UNPKG

@eclipse-scout/chart

Version:
214 lines (184 loc) 6.03 kB
/* * Copyright (c) 2010, 2025 BSI Business Systems Integration AG * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 */ import {Chart} from '../index'; import {arrays, PropertyChangeEvent, PropertyEventEmitter, PropertyEventMap, Session} from '@eclipse-scout/core'; import {UpdateChartOptions} from './Chart'; export class AbstractChartRenderer extends PropertyEventEmitter { declare eventMap: AbstractChartRendererEventMap; chart: Chart; session: Session; /** true while this.render() is executing */ rendering: boolean; rendered: boolean; /** set by render() and remove(), makes it unnecessary to carry an argument through all method calls */ animationDuration: number; firstOpaqueBackgroundColor: string; constructor(chart: Chart) { super(); this.chart = chart; this.session = chart.session; this.rendering = false; this.rendered = false; this.animationDuration = 0; this.firstOpaqueBackgroundColor = ''; } validate(): boolean { if (!this._validateChartData()) { return false; } return this._validate(); } protected _validateChartData(): boolean { let chartData = this.chart && this.chart.data; if (!chartData || !chartData.chartValueGroups || chartData.chartValueGroups.length === 0) { return false; } // check lengths let i, length = 0; for (i = 0; i < chartData.chartValueGroups.length; i++) { let chartValueGroup = chartData.chartValueGroups[i]; if (!chartValueGroup.values) { return false; } // Length of all "values" arrays have to be equal if (i === 0) { length = chartValueGroup.values.length; } else { if (chartValueGroup.values.length !== length) { return false; } } // color should have been set. if (!this.chart.config.options.autoColor && !arrays.ensure(chartValueGroup.colorHexValue).length && !chartValueGroup.cssClass) { return false; } } for (i = 0; i < chartData.axes.length; i++) { if (chartData.axes[i].length !== length) { return false; } } return true; } protected _validate(): boolean { // Override in subclasses return true; } /** * @param requestAnimation * Whether animations should be used while rendering the chart. Note that his * property is ignored when chart.config.options.animation.duration is <code>0</code>! */ render(requestAnimation: boolean) { if (!this.validate() || !this.chart.rendered) { return; } const configAnimationDuration = this.chart.config.options.animation.duration; this.setAnimationDuration(requestAnimation ? configAnimationDuration : 0); this.rendering = true; this._render(); this.rendering = false; this.rendered = true; this.setAnimationDuration(configAnimationDuration); } protected _render() { // Override in subclasses } renderCheckedItems() { if (this.rendered) { this._renderCheckedItems(); } } protected _renderCheckedItems() { // nop } /** * @param requestAnimation * Whether animations should be used while updating the chart. Note that his * property is ignored when chart.config.options.animation.duration is <code>0</code>! */ updateData(requestAnimation: boolean) { if (!this.rendered) { this.render(requestAnimation); return; } if (!this.validate() || !this.isDataUpdatable()) { return; } const configAnimationDuration = this.chart.config.options.animation.duration; this.setAnimationDuration(requestAnimation ? configAnimationDuration : 0); this._updateData(); this.setAnimationDuration(configAnimationDuration); } protected _updateData() { // Override in subclasses } isDataUpdatable(): boolean { return false; } isDetachSupported(): boolean { return true; } refresh() { if (this.rendering) { return; } if (this.rendered) { this.remove(false); } this.render(false); } setAnimationDuration(animationDuration: number) { if (!this.setProperty('animationDuration', animationDuration)) { return; } if (this.rendered) { this._renderAnimationDuration(); } } protected _setAnimationDuration(animationDuration: number) { this._setProperty('animationDuration', animationDuration); } protected _renderAnimationDuration() { // nop } /** * @param requestAnimation * Whether animations should be used while removing the chart. Note that his * property is ignored when chart.config.options.animation.duration is <code>0</code>! */ remove(requestAnimation = false, afterRemoveFunc?: (chartAnimationStopping?: boolean) => void) { const configAnimationDuration = this.chart.config.options.animation.duration; this.setAnimationDuration(requestAnimation && configAnimationDuration); if (this.animationDuration && this.rendered) { this._removeAnimated(afterRemoveFunc); } else { this._remove(afterRemoveFunc); } this.setAnimationDuration(configAnimationDuration); } protected _remove(afterRemoveFunc: (chartAnimationStopping?: boolean) => void) { this.rendered = false; afterRemoveFunc && afterRemoveFunc(); } protected _removeAnimated(afterRemoveFunc: (chartAnimationStopping?: boolean) => void) { // Override in subclasses this._remove(afterRemoveFunc); } /** * Controls if the animation of the chart is shown when chart data has been updated. */ shouldAnimateRemoveOnUpdate(opts: UpdateChartOptions): boolean { return opts.requestAnimation; } } export interface AbstractChartRendererEventMap extends PropertyEventMap { 'propertyChange:animationDuration': PropertyChangeEvent<number>; }