import * as ChartJS from 'chart.js';
import _ from 'lodash';
import Input from './input';
import Treemap from './_treemap';
import Map from './_map';
import {
colors, settingDefualtChartOption, defineType, nonChartJsType,
} from './variable';
import Timeline from './timelime';
/**
* GamifyJS에서 차트를 생성하는 클래스입니다.
* <p>해당 클래스를 통해 차트를 생성하고, 제어할 수 있습니다.
* @class
* @alias Chart
*/
export default class Chart {
/**
* @description DOM의 크기를 계산해서 DOM의 크기에 딱 맞게 Gamify를 생성해준다.
* @param { object } option - Gamify를 통해 생설할 차트의 데이터
* @param { Gamify } parent - Gamify 클래스 ( 부모 클래스 ) 링크
*/
constructor(option, parent) {
// eslint-disable-next-line consistent-return
return this.gamifyOptionToChartJsOption(option).then((objects) => {
const value = objects.chartJsOption;
if (_.includes(nonChartJsType, option.type)) {
switch (option.type) {
case 'treemap':
new Treemap(option, value.data.datasets);
document.addEventListener('contextmenu', event => event.preventDefault());
break;
case 'map':
new Map(option, value.data.datasets);
break;
default:
break;
}
} else {
const chartDOM = document.createElement('canvas');
chartDOM.width = option.rootSize.width;
chartDOM.height = option.rootSize.height;
chartDOM.style.position = 'absolute';
chartDOM.style.zIndex = 1;
document.getElementById(option.domId).appendChild(chartDOM);
const context = chartDOM.getContext('2d');
let _ChartJS;
if (option.type === 'scatter') {
_ChartJS = ChartJS.Scatter(context, value);
} else {
_ChartJS = new ChartJS(context, value);
}
// const
/**
* @description ChartJS 오브젝트
* @type { ChartJS }
*/
this.chartJsObject = _ChartJS;
if (!_.isUndefined(objects.originalDatasets)) {
parent.timeline = new Timeline({ chart: this.chartJsObject, parent, option }, objects.originalDatasets);
}
if (option.data.importType === 'api' && option.data.interval) {
let start = new Date().getTime();
setInterval(() => {
let elapsed = Math.abs(new Date().getTime() - start);
if (elapsed >= option.data.interval * 1000) {
start = new Date().getTime();
elapsed = 0;
}
this.chartJsObject.updateElapsedTime = elapsed;
}, 1);
setInterval(() => {
Input.getDataFromAPI(option.data.url, option.data.params).then((result) => {
const chartDataByUser = option.data.fn(result);
if (option.data.colorMode === 'auto') { this.makeBackgroundColor(chartDataByUser); }
for (let i = 0; i < this.chartJsObject.config.data.datasets.length; i++) {
this.chartJsObject.config.data.datasets[i].data = chartDataByUser.datasets[i].data;
}
this.chartJsObject.update();
});
}, 1000 * option.data.interval);
}
return this.chartJsObject;
}
});
}
/**
* Gamify의 일부차트는 ChartJS를 통해 생성하기 때문에 Gamify의 옵션을 Chartjs에 맞게 변형시켜주는 함수
* <p><b> async 키워드를 사용한 Synchronous (동기) 함수</b>
* @param {object} option Gamify 생성 시 입력한 옵션
* @memberof Chart
* @returns {object}
* @instance
*/
async gamifyOptionToChartJsOption(option) {
const chartJsOption = {};
let originalDatasets;
chartJsOption.type = option.type;
if (_.includes(Object.keys(defineType), chartJsOption.type)) {
chartJsOption.type = defineType[chartJsOption.type];
}
if (option.data.timeline) {
originalDatasets = _.cloneDeep(option.data.datasets);
option.data.datasets = option.data.datasets.splice(0, 1);
}
chartJsOption.data = {};
switch (option.data.importType) {
case 'plane':
chartJsOption.data.labels = option.data.labels;
chartJsOption.data.datasets = option.data.datasets;
break;
case 'spreadsheet':
await Input.getDataFromSpreadSheet(option.data).then((result) => {
chartJsOption.data = { ...chartJsOption.data, ...result };
});
break;
case 'api':
await Input.getDataFromAPI(option.data.url, option.data.params).then((result) => {
const chartDataByUser = option.data.fn(result);
chartJsOption.data = { ...chartJsOption.data, ...chartDataByUser };
});
break;
default:
break;
}
chartJsOption.options = {
responsive: true,
scales: {
yAxes: [{
ticks: {
beginAtZero: true,
},
}],
xAxes: [{
ticks: {
beginAtZero: true,
},
}],
},
};
chartJsOption.options = { ...chartJsOption.options, ...option.options };
if (option.data.colorMode === 'auto') {
this.makeBackgroundColor(chartJsOption.data);
}
if (settingDefualtChartOption[option.type] !== undefined) {
settingDefualtChartOption[option.type](chartJsOption);
}
return { chartJsOption, originalDatasets };
}
/**
* 차트의 배경색을 auto로 지정했을 때 자동으로 색을 선택해줌
* @param {object} data 차트의 데이터
* @memberof Chart
* @instance
*/
makeBackgroundColor(data) {
let colorIndex = 0;
const backgroundColorArray = [];
const borderColorArray = [];
if (data.datasets.length === 1) {
for (let i = 0; i < data.labels.length; i++) {
const backgroundColor = `rgba(${colors[colorIndex][0]},${colors[colorIndex][1]},${colors[colorIndex][2]},1)`;
const borderColor = `rgba(${colors[colorIndex][0]},${colors[colorIndex][1]},${colors[colorIndex][2]},1)`;
backgroundColorArray.push(backgroundColor);
borderColorArray.push(borderColor);
colorIndex += 6;
if (colorIndex >= colors.length) {
colorIndex -= colors.length;
}
}
data.datasets[0].backgroundColor = backgroundColorArray;
data.datasets[0].borderColor = borderColorArray;
data.datasets[0].borderWidth = 1;
} else {
for (let i = 0; i < data.datasets.length; i++) {
const backgroundColor = `rgba(${colors[colorIndex][0]},${colors[colorIndex][1]},${colors[colorIndex][2]},0.3)`;
const borderColor = `rgba(${colors[colorIndex][0]},${colors[colorIndex][1]},${colors[colorIndex][2]},1)`;
data.datasets[i].backgroundColor = backgroundColor;
data.datasets[i].borderColor = borderColor;
data.datasets[i].borderWidth = 1;
colorIndex += 6;
if (colorIndex >= colors.length) {
colorIndex -= colors.length;
}
}
}
}
}