UNPKG

zz-chart

Version:

Alauda Chart components by Alauda Frontend Team

314 lines 9.17 kB
import { isBoolean, isObject, merge, set, cloneDeep } from 'lodash-es'; import { Coordinate } from '../components/coordinate.js'; import { getInteraction } from '../interaction/index.js'; import Interaction from '../interaction/interaction.js'; import { reactive } from '../reactivity/index.js'; import { UPlotViewStrategy, ViewStrategyManager, InternalViewStrategy, } from '../strategy/index.js'; import { getTheme } from '../theme/index.js'; import { ChartEvent, } from '../types/index.js'; import { getChartColor } from '../utils/index.js'; import EventEmitter from './event-emitter.js'; export class View extends EventEmitter { constructor(props) { super(); /** 所有的组件 */ this.components = new Map(); /** 图形组件 */ this.shapeComponents = new Map(); // 配置信息存储 this.options = {}; this.interactions = new Map(); this.systemThemeType = 'light'; this.size = { width: 0, height: 0 }; this.fixedSize = { width: 0, height: 0, }; this.shapeCache = new Map(); this.systemChangeTheme = (e) => { const theme = e.matches ? 'dark' : 'light'; this.theme(theme); }; const { width, height, chartEle, ele, options, data, theme, chartOption, padding, defaultInteractions, } = props; this.reactivity = reactive(chartOption, this); this.chartContainer = chartEle; this.container = ele; if (options) { this.options = { ...options, padding }; } data && this.data(data); this.defaultInteractions = defaultInteractions; this.size = { ...this.size, width, height }; this.fixedSize = { width, height, }; this.initTheme(theme); this.init(); } // 判断是否是 element active [point] get isElementAction() { return !!this.shapeComponents.get('point'); } get hideTooltip() { return this.options.tooltip === false; } init() { this.initViewStrategy(); this.initComponent(); } reactive() { return this.reactivity.reactiveObject; } render(size) { if (size) { this.size = size; } [...this.components.values()].forEach(c => c.render()); this.strategy.forEach(item => { item.render(); }); // TODO: 去除依赖 shape 判断 is point this.initDefaultInteractions(this.defaultInteractions); } interaction(name, steps) { const interactionStep = getInteraction(name); if ((steps || interactionStep) && !this.interactions.get(name)) { const step = steps && interactionStep ? merge(interactionStep, steps) : steps || interactionStep; const interaction = new Interaction(this, cloneDeep(step)); interaction.init(); this.interactions.set(name, interaction); } } initDefaultInteractions(interactions) { for (const name of interactions) { if (name) { this.interaction(name); } } } /** * 基于注册组件初始化 */ initComponent() { this.createCoordinate(); this.strategyManage.getComponent().forEach(c => { this.components.set(c.name, c); }); } /** * 初始化策略 uPlot internal */ initViewStrategy() { this.strategyManage = new ViewStrategyManager(); const internal = new InternalViewStrategy(this); this.strategyManage.add(internal); const uPlot = new UPlotViewStrategy(this); this.strategyManage.add(uPlot); this.strategy = this.strategyManage.getAllStrategy(); } /** * * @param theme 主题 * 不设置默认根据系统切换 light dark */ initTheme(theme) { this.mediaQuery = window.matchMedia('(prefers-color-scheme: dark)'); this.systemThemeType = this.mediaQuery.matches ? 'dark' : 'light'; if (!theme || theme?.type === 'system') { this.bindThemeListener(); } this.theme(theme || this.systemThemeType); } bindThemeListener() { this.mediaQuery.addEventListener('change', this.systemChangeTheme); } unbindThemeListener() { this.mediaQuery.removeEventListener('change', this.systemChangeTheme); } /** * 设置主题。 * @param theme 主题名或者主题配置 * @returns View */ theme(theme) { this.themeObject = isObject(theme) ? getTheme(theme.type, theme) : getTheme(theme); this.emit(ChartEvent.THEME_CHANGE); return this; } /** * 获取主题配置。 * @returns themeObject */ getTheme() { return this.themeObject; } /** * 获取 view options 配置 */ getOption() { return this.options; } /** * 装载数据源。 * * ```ts * chart.data(); * ``` * * @param data 数据源。 * @returns View */ data(data) { data.forEach((d, index) => { if (!d.color) { d.color = getChartColor(index); } }); set(this.options, 'data', data); this.emit(ChartEvent.DATA_CHANGE, data); return this; } getData() { return this.options.data || []; } // -------------- Component ---------------// title(titleOption) { set(this.options, 'title', titleOption); return this; } legend(legendOption) { set(this.options, 'legend', legendOption); return this.components.get('legend'); } axis(field, axisOption) { if (isBoolean(field)) { set(this.options, ['axis'], field); } else { set(this.options, ['axis', field], axisOption); } return this; } /** * 对x y 度量进行配置。 * ``` * @param field 度量 x y * @param scaleOption 度量配置 */ scale(field, axisOption) { if (isBoolean(field)) { set(this.options, ['scale'], field); } else { set(this.options, ['scale', field], axisOption); } return this.components.get('scale'); } setScale(field, limits) { const scale = this.components.get('scale'); scale.setScale(field, limits); } /** * 创建坐标系 * @private */ createCoordinate() { this.coordinateInstance = new Coordinate(this); } /** * 坐标系配置。 * * ```ts * // 直角坐标系,并进行转置变换 * chart.coordinate().transpose(); * ``` * @returns */ coordinate(option) { set(this.options, 'coordinate', option); // 更新 coordinate 配置 // this.coordinateInstance.update(option); return this.coordinateInstance; } getCoordinate() { return this.coordinateInstance; } tooltip(tooltipOption) { set(this.options, 'tooltip', tooltipOption); return this; } /** * 辅助标记配置 */ annotation() { return this.components.get('annotation'); } // 命令式设置 option setOption(name, option) { set(this.options, name, option); return this; } redraw() { this.emit(ChartEvent.HOOKS_REDRAW); } setShape(name, shape) { const shapeValue = this.shapeCache.get(name); if (shapeValue) { this.shapeCache.set(name, [...shapeValue, shape]); return; } this.shapeCache.set(name, [shape]); } getShapeList() { const keys = Array.from(this.shapeCache.keys()); return keys .map(key => { return this.shapeCache.get(key).flat(); }) .flat(); } getShapeDataName() { return this.getShapeList() .map((shape) => { return shape.getSeries(); }) .flat() .map(s => s.label); } /** * 生命周期:销毁,完全无法使用。 */ destroy() { // ... this.chartContainer.innerHTML = ''; this.options = {}; this.shapeCache.clear(); this.reactivity.unsubscribe(); [...this.components.values()].forEach(c => c.destroy()); [...this.shapeComponents.values()].forEach(c => c.destroy()); this.strategyManage.getStrategy('uPlot')?.destroy(); this.unbindThemeListener(); this.off(); } } /** * 注册 geometry 组件 * @param name * @param Ctor * @returns Geometry */ export function registerShape(name, Ctor) { const key = name.toLowerCase(); // 语法糖,在 view API 上增加原型方法 View.prototype[key] = function (options) { const shape = new Ctor(this, options); this.shapeComponents.set(key, shape); return shape; }; } //# sourceMappingURL=view.js.map