import _ from 'lodash';
import BarEffect from './bar';
import PieEffect from './pie';
import Utility from '../utility';
import LineEffect from './line';
import ScatterEffect from './scatter';
/**
* GamifyJS에서 효과를 생성하는 클래스입니다.
* <p>해당 클래스를 통해 효과를 생성하고, 제어할 수 있습니다.
* @class
* @alias Effect
*/
export default class Effect {
/**
* @description DOM의 크기를 계산해서 DOM의 크기에 딱 맞게 Gamify를 생성해준다.
* @param { object } option - Gamify를 통해 생설할 차트의 데이터
* @param { ChartJS } chartJsObject - 생성된 ChartJS 오브젝트
*/
constructor(option, chartJsObject) {
/**
* @description Gamify를 통해 생설할 차트의 데이터
* @type { object }
*/
this.option = option;
/**
* @description 차트의 타입
* @type { string }
*/
this.chartType = option.type;
/**
* @description 생성된 ChartJS 오브젝트
* @type { ChartJS }
*/
this.chartJsObject = chartJsObject;
/**
* @description 효과를 생성할 PIXI 오브젝트
* @type { PIXI }
*/
this.pixiJsObject = Utility.makePixi(option);
/**
* @description 각 타입의 효과 정보
* @type { object }
* @property { string } bar bar 타입에 대한 효과 정보
* @property { array } bar.enableEffectList bar 타입에서 사용가능한 효과 리스트
* @property { string } bar.enableEffectList.upperLimit 기준치 초과에 대한 효과
* @property { string } bar.enableEffectList.lowerLimit 기준치 미만에 대한 효과
* @property { BarEffect } bar.Effect BarEffect 오브젝트
* @property { string } pie pie 타입에 대한 효과 정보
* @property { array } pie.enableEffectList pie 타입에서 사용가능한 효과 리스트
* @property { string } pie.enableEffectList.extrude 마우스 상호작용 효과
* @property { PieEffect } pie.Effect PieEffect 오브젝트
* @property { string } scatter scatter 타입에 대한 효과 정보
* @property { array } scatter.enableEffectList scatter 타입에서 사용가능한 효과 리스트
* @property { string } scatter.enableEffectList.missile scatter 차트의 좌표가 변경될 때효과
* @property { ScatterEffect } scatter.Effect scatterEffect 오브젝트
*/
this.information = {
bar: {
enableEffectList: ['lowerLimit', 'upperLimit'],
enableEffectAgain: [],
Effect: BarEffect,
},
line: {
enableEffectList: ['lineTracer', 'lowerLimit', 'upperLimit'],
enableEffectAgain: ['lineTracer'],
Effect: LineEffect,
},
pie: {
enableEffectList: ['extrude'],
enableEffectAgain: [],
Effect: PieEffect,
},
scatter: {
enableEffectList: ['missile'],
enableEffectAgain: [],
Effect: ScatterEffect,
},
};
/**
* @description 생성된 효과의 리스트
* @type { object }
*/
this.list = {};
/**
* @description ChartJS 애니메이션 onProgress 이벤트 발생 시 실행되는 함수 리스트
* @type { object }
*/
this.chartOnProgressFunctionList = {};
/**
* @description ChartJS 애니메이션 onComplete 이벤트 발생 시 실행되는 함수 리스트
* @type { object }
*/
this.chartOnCompleteFunctionList = {};
this.chartJsObject.options.animation.onProgress = () => {
for (let i = 0; i < Object.keys(this.chartOnProgressFunctionList).length; i++) {
const key = Object.keys(this.chartOnProgressFunctionList)[i];
this.chartOnProgressFunctionList[key]();
}
};
this.chartJsObject.options.animation.onComplete = () => {
for (let i = 0; i < Object.keys(this.chartOnCompleteFunctionList).length; i++) {
const key = Object.keys(this.chartOnCompleteFunctionList)[i];
this.chartOnCompleteFunctionList[key]();
}
};
const standardResolution = {
width: 1280,
height: 720,
};
const { width, height } = this.option.rootSize;
this.widthRatio = width / standardResolution.width;
this.heightRatio = height / standardResolution.height;
this.ratio = {
min: Math.min(this.widthRatio, this.heightRatio),
mid: Math.min(this.widthRatio, this.heightRatio) + Math.abs(this.widthRatio - this.heightRatio) / 2,
max: Math.max(this.widthRatio, this.heightRatio),
};
/**
* @description 효과 리스트 인덱스
* @type { number }
*/
this.effectListIndex = 0;
/**
* @description ChartJS onProgress 추가 인덱스
* @type { number }
*/
this.chartAnimationProgressIndex = 0;
/**
* @description ChartJS onComplete 추가 인덱스
* @type { number }
*/
this.chartAnimationCompleteIndex = 0;
}
/**
* 효과를 추가하는 함수
* <p>사용하고자 하는 효과를 알맞은 차트에 적용해야함
* @param {effectName} option 효과 이름
* @param {object} option 효과 옵션
* @memberof Effect
* @returns {number} 인덱스 반환
* @instance
*/
add(effectName, option) {
option = option || {};
if (_.includes(this.information[this.chartType].enableEffectList, effectName)) {
if (!_.isUndefined(this.information[this.chartType].enableEffectAgain) && !_.includes(this.information[this.chartType].enableEffectAgain, effectName)) {
for (let i = 0; i < Object.keys(this.list).length; i++) {
if (_.isEqual(effectName, this.list[Object.keys(this.list)[i]].name)) {
console.warn(`${effectName} 는 중복적용을 지원하지 않습니다.`);
return undefined;
}
}
}
const effect = new this.information[this.chartType].Effect({ chart: this.chartJsObject, pixi: this.pixiJsObject, effect: this }, option);
effect[effectName]();
this.list[this.effectListIndex++] = { object: effect, name: effectName };
return this.effectListIndex - 1;
}
console.warn('지원하지 않는 효과입니다.');
return undefined;
}
/**
* 효과를 제거하는 함수
* @param {number} index 효과 생성할 때 얻은 인덱스
* @memberof Effect
* @instance
*/
destroy(index) {
this.list[index].object.destroy();
delete this.list[index];
}
/**
* <b>내부 함수</b>
* <p>ChartJS 애니메이션 onProgress 이벤트 발생할 때 실행할 함수를 추가하는 함수
* @param {function} fn 실행할 함수
* @memberof Effect
* @returns {number} 인덱스
* @instance
*/
_addOnProgressFunction(fn) {
this.chartOnProgressFunctionList[this.chartAnimationProgressIndex++] = fn;
return this.chartAnimationProgressIndex - 1;
}
/**
* <b>내부 함수</b>
* <p>ChartJS 애니메이션 onComplete 이벤트 발생할 때 실행할 함수를 추가하는 함수
* @param {function} fn 실행할 함수
* @memberof Effect
* @returns {number} 인덱스
* @instance
*/
_addOnCompleteFunction(fn) {
this.chartOnCompleteFunctionList[this.chartAnimationCompleteIndex++] = fn;
return this.chartAnimationCompleteIndex - 1;
}
/**
* <b>내부 함수</b>
* <p>ChartJS 애니메이션 onProgress 이벤트 발생할 때 실행할 함수를 제거하는 함수
* @param {number} index _addOnProgressFunction를 통해 받은 인덱스
* @memberof Effect
* @instance
*/
_removeOnProgressFunction(index) {
delete this.chartOnProgressFunctionList[index];
}
/**
* <b>내부 함수</b>
* <p>ChartJS 애니메이션 onComplete 이벤트 발생할 때 실행할 함수를 제거하는 함수
* @param {number} index _addOnCompleteFunction 통해 받은 인덱스
* @memberof Effect
* @instance
*/
_removeOnCompleteFunction(index) {
delete this.chartOnCompleteFunctionList[index];
}
}