UNPKG

@toast-ui/chart

Version:

TOAST UI Application: Chart

273 lines (272 loc) 11.7 kB
import { deepCopy, getFirstValidValue, includes, isBoolean, isNumber, isUndefined, range, } from "../helpers/utils"; import { makeRawCategories } from "./category"; import { getCoordinateXValue, isCoordinateSeries } from "../helpers/coordinate"; import { isZooming } from "../helpers/range"; import { message } from "../message"; import { hasNestedPieSeries } from "../helpers/pieSeries"; import { extend } from "./store"; function initRange(series, categories) { let rawCategoriesLength; if (categories) { rawCategoriesLength = Array.isArray(categories) ? categories.length : categories.x.length; } else { rawCategoriesLength = Object.keys(makeRawCategories(series, categories)).length; } return [0, rawCategoriesLength - 1]; } function initZoomRange(series, options, categories) { var _a; if (!(series.line || series.area) || !((_a = options.series) === null || _a === void 0 ? void 0 : _a.zoomable)) { return; } return initRange(series, categories); } function initShiftRange(series, options, categories) { var _a; if (!(series.line || series.area || series.column || series.heatmap) || !((_a = options.series) === null || _a === void 0 ? void 0 : _a.shift)) { return; } return initRange(series, categories); } function getCoordinateDataRange(data, rawCategories, zoomRange) { const [zoomStart, zoomEnd] = zoomRange; let start, end; range(zoomStart, zoomEnd + 1).forEach((i) => { const idx = data.findIndex((datum) => getCoordinateXValue(datum).toString() === rawCategories[i]); if (idx !== -1) { if (isUndefined(start)) { start = idx; } if (!isUndefined(start)) { end = Math.max(idx, (end !== null && end !== void 0 ? end : 0)); } } }); return [start, end]; } function getSeriesDataInRange(data, rawCategories, chartType, zoomRange) { if (!zoomRange) { return data; } let [startIdx, endIdx] = zoomRange; const isCoordinateChart = chartType !== 'area' && !isNumber(getFirstValidValue(data)); if (isCoordinateChart) { [startIdx, endIdx] = getCoordinateDataRange(data, rawCategories, zoomRange); } else { startIdx = startIdx > 1 ? startIdx - 1 : startIdx; endIdx = endIdx < rawCategories.length - 1 ? endIdx + 1 : endIdx; } return data.slice(startIdx, endIdx + 1); } function isCoordinateTypeSeries(series, chartType) { return (isCoordinateSeries(series) && (isUndefined(chartType) || chartType === 'line' || chartType === 'scatter')); } function isSeriesAlreadyExist(series, seriesName, data) { return series[seriesName].some(({ label }) => label === data.name); } function isTreemapSeriesAlreadyExist(series, data) { return series.treemap.some(({ label }) => label === data.label); } function isHeatmapSeriesAlreadyExist(categories, category) { return includes(categories.y, category); } function initDisabledSeries(series) { const nestedPieChart = hasNestedPieSeries(series); const disabledSeries = []; if (nestedPieChart) { series.pie.forEach(({ data }) => { data.forEach((datum) => { if (isBoolean(datum.visible) && !datum.visible) { disabledSeries.push(datum.name); } }); }); } else { Object.keys(series).forEach((type) => { series[type].forEach(({ name, visible }) => { if (isBoolean(visible) && !visible) { disabledSeries.push(name); } }); }); } return disabledSeries; } const seriesData = { name: 'seriesData', state: ({ series, categories, options }) => ({ rawCategories: makeRawCategories(series, categories), series: Object.assign({}, series), zoomRange: initZoomRange(series, options, categories), shiftRange: initShiftRange(series, options, categories), disabledSeries: initDisabledSeries(series), }), action: { setSeriesData({ state, initStoreState }) { const rawSeries = deepCopy(initStoreState.series); const { disabledSeries, theme, zoomRange, rawCategories } = state; const newSeriesData = {}; Object.keys(rawSeries).forEach((seriesName) => { var _a, _b, _c; const { colors, iconTypes } = theme.series[seriesName]; let originSeriesData = rawSeries[seriesName].map((m, idx) => (Object.assign(Object.assign({}, m), { rawData: m.data, data: getSeriesDataInRange(m.data, rawCategories, seriesName, zoomRange), color: colors ? colors[idx % colors.length] : '' }))); if (seriesName === 'scatter') { originSeriesData = originSeriesData.map((m, idx) => (Object.assign(Object.assign({}, m), { iconType: iconTypes ? iconTypes[idx] : 'circle' }))); } const seriesCount = originSeriesData.length; const seriesGroupCount = (_c = (_b = (_a = originSeriesData[0]) === null || _a === void 0 ? void 0 : _a.data) === null || _b === void 0 ? void 0 : _b.length, (_c !== null && _c !== void 0 ? _c : 0)); const data = originSeriesData.filter(({ name }) => !disabledSeries.includes(name)); newSeriesData[seriesName] = { seriesCount, seriesGroupCount, data, colors, }; }); extend(state.series, newSeriesData); }, disableSeries({ state }, name) { state.disabledSeries.push(name); this.notify(state, 'disabledSeries'); if (state.series.bullet) { this.dispatch('removeCategoryByName', name); } }, enableSeries({ state }, name) { const index = state.disabledSeries.findIndex((disabled) => disabled === name); state.disabledSeries.splice(index, 1); this.notify(state, 'disabledSeries'); if (state.series.bullet) { state.categories = state.series.bullet.data.map(({ name: seriesName }) => seriesName); this.notify(state, 'axes'); } }, zoom({ state }, rangeCategories) { const rawCategories = state.rawCategories; state.zoomRange = rangeCategories.map((rangeCategory) => rawCategories.findIndex((category) => category === rangeCategory)); this.notify(state, 'zoomRange'); }, resetZoom({ state, initStoreState }) { const { series, options } = initStoreState; const rawCategories = state.rawCategories; state.zoomRange = initZoomRange(series, options, rawCategories); this.notify(state, 'zoomRange'); }, addData({ state, initStoreState }, { data, category, chartType }) { const { series } = initStoreState; const coordinateChart = isCoordinateTypeSeries(state.series, chartType); let { categories } = initStoreState; categories = series.heatmap ? categories.x : categories; if (category && Array.isArray(categories)) { const isExist = categories.some((c) => c === category); if (!isExist) { categories.push(category); if (Array.isArray(state.shiftRange)) { const [start, end] = state.shiftRange; state.shiftRange = [start + 1, end + 1]; } } } if (chartType) { series[chartType].forEach((datum, idx) => { datum.data.push(data[idx]); }); } else { const [seriesName] = Object.keys(initStoreState.series); series[seriesName].forEach((datum, idx) => { datum.data.push(data[idx]); }); } this.notify(state, 'series'); this.notify(state, 'rawCategories'); if (Array.isArray(state.zoomRange)) { this.dispatch('resetZoom'); } if (coordinateChart) { this.dispatch('initCategory'); } }, addSeries({ state, initStoreState }, { data, chartType, category, }) { const { series, categories } = initStoreState; const coordinateChart = isCoordinateTypeSeries(state.series, chartType); const seriesName = chartType || Object.keys(series)[0]; const isExist = isSeriesAlreadyExist(series, seriesName, data); if (!isExist) { series[seriesName].push(data); if (Array.isArray(categories) && category) { categories.push(category); } } this.dispatch('initThemeState'); this.dispatch('initLegendState'); this.notify(state, 'series'); if (coordinateChart || seriesName === 'bullet') { this.dispatch('initCategory'); } }, addHeatmapSeries({ state, initStoreState }, { data, category }) { const { series, categories } = initStoreState; const isExist = isHeatmapSeriesAlreadyExist(categories, category); if (!isExist) { series.heatmap.push({ data, yCategory: category }); } if (!isExist && category) { categories.y.push(category); this.notify(state, 'rawCategories'); } this.notify(state, 'series'); this.dispatch('initThemeState'); this.dispatch('initLegendState'); }, addTreemapSeries({ state, initStoreState }, { data }) { const { series } = initStoreState; const isExist = isTreemapSeriesAlreadyExist(series, data); if (!isExist) { series.treemap.push(data); } this.notify(state, 'series'); this.notify(state, 'treemapSeries'); this.dispatch('initThemeState'); this.dispatch('initLegendState'); }, setData({ state, initStoreState }, { series, categories }) { initStoreState.series = series; const isNestedPieChart = hasNestedPieSeries(series); if (!isNestedPieChart) { state.rawCategories = makeRawCategories(series, categories); } this.dispatch('initThemeState'); this.dispatch('initLegendState'); }, addOutlier({ state, initStoreState }, { seriesIndex, outliers }) { var _a; const { series } = initStoreState; const seriesRawData = series.boxPlot[seriesIndex]; if (!seriesRawData) { throw new Error(message.SERIES_INDEX_ERROR); } seriesRawData.outliers = [...(_a = seriesRawData.outliers, (_a !== null && _a !== void 0 ? _a : [])), ...outliers]; this.notify(state, 'series'); }, }, observe: { updateSeriesData() { this.dispatch('setSeriesData'); }, }, computed: { isLineTypeSeriesZooming: ({ zoomRange, rawCategories }) => { return isZooming(rawCategories, zoomRange); }, viewRange: ({ zoomRange, shiftRange }) => { return zoomRange || shiftRange; }, }, }; export default seriesData;