project/node_modules/echarts/lib/core/echarts.js

2273 lines
82 KiB
JavaScript
Raw Permalink Normal View History

2024-07-14 15:48:34 +08:00
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
/**
* AUTO-GENERATED FILE. DO NOT MODIFY.
*/
import { __extends } from "tslib";
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import * as zrender from 'zrender/lib/zrender.js';
import { assert, each, isFunction, isObject, indexOf, bind, clone, setAsPrimitive, extend, createHashMap, map, defaults, isDom, isArray, noop, isString, retrieve2 } from 'zrender/lib/core/util.js';
import env from 'zrender/lib/core/env.js';
import timsort from 'zrender/lib/core/timsort.js';
import Eventful from 'zrender/lib/core/Eventful.js';
import GlobalModel from '../model/Global.js';
import ExtensionAPI from './ExtensionAPI.js';
import CoordinateSystemManager from './CoordinateSystem.js';
import OptionManager from '../model/OptionManager.js';
import backwardCompat from '../preprocessor/backwardCompat.js';
import dataStack from '../processor/dataStack.js';
import SeriesModel from '../model/Series.js';
import ComponentView from '../view/Component.js';
import ChartView from '../view/Chart.js';
import * as graphic from '../util/graphic.js';
import { getECData } from '../util/innerStore.js';
import { isHighDownDispatcher, HOVER_STATE_EMPHASIS, HOVER_STATE_BLUR, blurSeriesFromHighlightPayload, toggleSelectionFromPayload, updateSeriesElementSelection, getAllSelectedIndices, isSelectChangePayload, isHighDownPayload, HIGHLIGHT_ACTION_TYPE, DOWNPLAY_ACTION_TYPE, SELECT_ACTION_TYPE, UNSELECT_ACTION_TYPE, TOGGLE_SELECT_ACTION_TYPE, savePathStates, enterEmphasis, leaveEmphasis, leaveBlur, enterSelect, leaveSelect, enterBlur, allLeaveBlur, findComponentHighDownDispatchers, blurComponent, handleGlobalMouseOverForHighDown, handleGlobalMouseOutForHighDown } from '../util/states.js';
import * as modelUtil from '../util/model.js';
import { throttle } from '../util/throttle.js';
import { seriesStyleTask, dataStyleTask, dataColorPaletteTask } from '../visual/style.js';
import loadingDefault from '../loading/default.js';
import Scheduler from './Scheduler.js';
import lightTheme from '../theme/light.js';
import darkTheme from '../theme/dark.js';
import { parseClassType } from '../util/clazz.js';
import { ECEventProcessor } from '../util/ECEventProcessor.js';
import { seriesSymbolTask, dataSymbolTask } from '../visual/symbol.js';
import { getVisualFromData, getItemVisualFromData } from '../visual/helper.js';
import { deprecateLog, deprecateReplaceLog, error, warn } from '../util/log.js';
import { handleLegacySelectEvents } from '../legacy/dataSelectAction.js';
import { registerExternalTransform } from '../data/helper/transform.js';
import { createLocaleObject, SYSTEM_LANG } from './locale.js';
import { findEventDispatcher } from '../util/event.js';
import decal from '../visual/decal.js';
import lifecycle from './lifecycle.js';
import { platformApi, setPlatformAPI } from 'zrender/lib/core/platform.js';
import { getImpl } from './impl.js';
export var version = '5.5.0';
export var dependencies = {
zrender: '5.5.0'
};
var TEST_FRAME_REMAIN_TIME = 1;
var PRIORITY_PROCESSOR_SERIES_FILTER = 800;
// Some data processors depends on the stack result dimension (to calculate data extent).
// So data stack stage should be in front of data processing stage.
var PRIORITY_PROCESSOR_DATASTACK = 900;
// "Data filter" will block the stream, so it should be
// put at the beginning of data processing.
var PRIORITY_PROCESSOR_FILTER = 1000;
var PRIORITY_PROCESSOR_DEFAULT = 2000;
var PRIORITY_PROCESSOR_STATISTIC = 5000;
var PRIORITY_VISUAL_LAYOUT = 1000;
var PRIORITY_VISUAL_PROGRESSIVE_LAYOUT = 1100;
var PRIORITY_VISUAL_GLOBAL = 2000;
var PRIORITY_VISUAL_CHART = 3000;
var PRIORITY_VISUAL_COMPONENT = 4000;
// Visual property in data. Greater than `PRIORITY_VISUAL_COMPONENT` to enable to
// overwrite the viusal result of component (like `visualMap`)
// using data item specific setting (like itemStyle.xxx on data item)
var PRIORITY_VISUAL_CHART_DATA_CUSTOM = 4500;
// Greater than `PRIORITY_VISUAL_CHART_DATA_CUSTOM` to enable to layout based on
// visual result like `symbolSize`.
var PRIORITY_VISUAL_POST_CHART_LAYOUT = 4600;
var PRIORITY_VISUAL_BRUSH = 5000;
var PRIORITY_VISUAL_ARIA = 6000;
var PRIORITY_VISUAL_DECAL = 7000;
export var PRIORITY = {
PROCESSOR: {
FILTER: PRIORITY_PROCESSOR_FILTER,
SERIES_FILTER: PRIORITY_PROCESSOR_SERIES_FILTER,
STATISTIC: PRIORITY_PROCESSOR_STATISTIC
},
VISUAL: {
LAYOUT: PRIORITY_VISUAL_LAYOUT,
PROGRESSIVE_LAYOUT: PRIORITY_VISUAL_PROGRESSIVE_LAYOUT,
GLOBAL: PRIORITY_VISUAL_GLOBAL,
CHART: PRIORITY_VISUAL_CHART,
POST_CHART_LAYOUT: PRIORITY_VISUAL_POST_CHART_LAYOUT,
COMPONENT: PRIORITY_VISUAL_COMPONENT,
BRUSH: PRIORITY_VISUAL_BRUSH,
CHART_ITEM: PRIORITY_VISUAL_CHART_DATA_CUSTOM,
ARIA: PRIORITY_VISUAL_ARIA,
DECAL: PRIORITY_VISUAL_DECAL
}
};
// Main process have three entries: `setOption`, `dispatchAction` and `resize`,
// where they must not be invoked nestedly, except the only case: invoke
// dispatchAction with updateMethod "none" in main process.
// This flag is used to carry out this rule.
// All events will be triggered out side main process (i.e. when !this[IN_MAIN_PROCESS]).
var IN_MAIN_PROCESS_KEY = '__flagInMainProcess';
var PENDING_UPDATE = '__pendingUpdate';
var STATUS_NEEDS_UPDATE_KEY = '__needsUpdateStatus';
var ACTION_REG = /^[a-zA-Z0-9_]+$/;
var CONNECT_STATUS_KEY = '__connectUpdateStatus';
var CONNECT_STATUS_PENDING = 0;
var CONNECT_STATUS_UPDATING = 1;
var CONNECT_STATUS_UPDATED = 2;
;
;
function createRegisterEventWithLowercaseECharts(method) {
return function () {
var args = [];
for (var _i = 0; _i < arguments.length; _i++) {
args[_i] = arguments[_i];
}
if (this.isDisposed()) {
disposedWarning(this.id);
return;
}
return toLowercaseNameAndCallEventful(this, method, args);
};
}
function createRegisterEventWithLowercaseMessageCenter(method) {
return function () {
var args = [];
for (var _i = 0; _i < arguments.length; _i++) {
args[_i] = arguments[_i];
}
return toLowercaseNameAndCallEventful(this, method, args);
};
}
function toLowercaseNameAndCallEventful(host, method, args) {
// `args[0]` is event name. Event name is all lowercase.
args[0] = args[0] && args[0].toLowerCase();
return Eventful.prototype[method].apply(host, args);
}
var MessageCenter = /** @class */function (_super) {
__extends(MessageCenter, _super);
function MessageCenter() {
return _super !== null && _super.apply(this, arguments) || this;
}
return MessageCenter;
}(Eventful);
var messageCenterProto = MessageCenter.prototype;
messageCenterProto.on = createRegisterEventWithLowercaseMessageCenter('on');
messageCenterProto.off = createRegisterEventWithLowercaseMessageCenter('off');
// ---------------------------------------
// Internal method names for class ECharts
// ---------------------------------------
var prepare;
var prepareView;
var updateDirectly;
var updateMethods;
var doConvertPixel;
var updateStreamModes;
var doDispatchAction;
var flushPendingActions;
var triggerUpdatedEvent;
var bindRenderedEvent;
var bindMouseEvent;
var render;
var renderComponents;
var renderSeries;
var createExtensionAPI;
var enableConnect;
var markStatusToUpdate;
var applyChangedStates;
var ECharts = /** @class */function (_super) {
__extends(ECharts, _super);
function ECharts(dom,
// Theme name or themeOption.
theme, opts) {
var _this = _super.call(this, new ECEventProcessor()) || this;
_this._chartsViews = [];
_this._chartsMap = {};
_this._componentsViews = [];
_this._componentsMap = {};
// Can't dispatch action during rendering procedure
_this._pendingActions = [];
opts = opts || {};
// Get theme by name
if (isString(theme)) {
theme = themeStorage[theme];
}
_this._dom = dom;
var defaultRenderer = 'canvas';
var defaultCoarsePointer = 'auto';
var defaultUseDirtyRect = false;
if (process.env.NODE_ENV !== 'production') {
var root = /* eslint-disable-next-line */
env.hasGlobalWindow ? window : global;
if (root) {
defaultRenderer = retrieve2(root.__ECHARTS__DEFAULT__RENDERER__, defaultRenderer);
defaultCoarsePointer = retrieve2(root.__ECHARTS__DEFAULT__COARSE_POINTER, defaultCoarsePointer);
defaultUseDirtyRect = retrieve2(root.__ECHARTS__DEFAULT__USE_DIRTY_RECT__, defaultUseDirtyRect);
}
}
if (opts.ssr) {
zrender.registerSSRDataGetter(function (el) {
var ecData = getECData(el);
var dataIndex = ecData.dataIndex;
if (dataIndex == null) {
return;
}
var hashMap = createHashMap();
hashMap.set('series_index', ecData.seriesIndex);
hashMap.set('data_index', dataIndex);
ecData.ssrType && hashMap.set('ssr_type', ecData.ssrType);
return hashMap;
});
}
var zr = _this._zr = zrender.init(dom, {
renderer: opts.renderer || defaultRenderer,
devicePixelRatio: opts.devicePixelRatio,
width: opts.width,
height: opts.height,
ssr: opts.ssr,
useDirtyRect: retrieve2(opts.useDirtyRect, defaultUseDirtyRect),
useCoarsePointer: retrieve2(opts.useCoarsePointer, defaultCoarsePointer),
pointerSize: opts.pointerSize
});
_this._ssr = opts.ssr;
// Expect 60 fps.
_this._throttledZrFlush = throttle(bind(zr.flush, zr), 17);
theme = clone(theme);
theme && backwardCompat(theme, true);
_this._theme = theme;
_this._locale = createLocaleObject(opts.locale || SYSTEM_LANG);
_this._coordSysMgr = new CoordinateSystemManager();
var api = _this._api = createExtensionAPI(_this);
// Sort on demand
function prioritySortFunc(a, b) {
return a.__prio - b.__prio;
}
timsort(visualFuncs, prioritySortFunc);
timsort(dataProcessorFuncs, prioritySortFunc);
_this._scheduler = new Scheduler(_this, api, dataProcessorFuncs, visualFuncs);
_this._messageCenter = new MessageCenter();
// Init mouse events
_this._initEvents();
// In case some people write `window.onresize = chart.resize`
_this.resize = bind(_this.resize, _this);
zr.animation.on('frame', _this._onframe, _this);
bindRenderedEvent(zr, _this);
bindMouseEvent(zr, _this);
// ECharts instance can be used as value.
setAsPrimitive(_this);
return _this;
}
ECharts.prototype._onframe = function () {
if (this._disposed) {
return;
}
applyChangedStates(this);
var scheduler = this._scheduler;
// Lazy update
if (this[PENDING_UPDATE]) {
var silent = this[PENDING_UPDATE].silent;
this[IN_MAIN_PROCESS_KEY] = true;
try {
prepare(this);
updateMethods.update.call(this, null, this[PENDING_UPDATE].updateParams);
} catch (e) {
this[IN_MAIN_PROCESS_KEY] = false;
this[PENDING_UPDATE] = null;
throw e;
}
// At present, in each frame, zrender performs:
// (1) animation step forward.
// (2) trigger('frame') (where this `_onframe` is called)
// (3) zrender flush (render).
// If we do nothing here, since we use `setToFinal: true`, the step (3) above
// will render the final state of the elements before the real animation started.
this._zr.flush();
this[IN_MAIN_PROCESS_KEY] = false;
this[PENDING_UPDATE] = null;
flushPendingActions.call(this, silent);
triggerUpdatedEvent.call(this, silent);
}
// Avoid do both lazy update and progress in one frame.
else if (scheduler.unfinished) {
// Stream progress.
var remainTime = TEST_FRAME_REMAIN_TIME;
var ecModel = this._model;
var api = this._api;
scheduler.unfinished = false;
do {
var startTime = +new Date();
scheduler.performSeriesTasks(ecModel);
// Currently dataProcessorFuncs do not check threshold.
scheduler.performDataProcessorTasks(ecModel);
updateStreamModes(this, ecModel);
// Do not update coordinate system here. Because that coord system update in
// each frame is not a good user experience. So we follow the rule that
// the extent of the coordinate system is determined in the first frame (the
// frame is executed immediately after task reset.
// this._coordSysMgr.update(ecModel, api);
// console.log('--- ec frame visual ---', remainTime);
scheduler.performVisualTasks(ecModel);
renderSeries(this, this._model, api, 'remain', {});
remainTime -= +new Date() - startTime;
} while (remainTime > 0 && scheduler.unfinished);
// Call flush explicitly for trigger finished event.
if (!scheduler.unfinished) {
this._zr.flush();
}
// Else, zr flushing be ensue within the same frame,
// because zr flushing is after onframe event.
}
};
ECharts.prototype.getDom = function () {
return this._dom;
};
ECharts.prototype.getId = function () {
return this.id;
};
ECharts.prototype.getZr = function () {
return this._zr;
};
ECharts.prototype.isSSR = function () {
return this._ssr;
};
/* eslint-disable-next-line */
ECharts.prototype.setOption = function (option, notMerge, lazyUpdate) {
if (this[IN_MAIN_PROCESS_KEY]) {
if (process.env.NODE_ENV !== 'production') {
error('`setOption` should not be called during main process.');
}
return;
}
if (this._disposed) {
disposedWarning(this.id);
return;
}
var silent;
var replaceMerge;
var transitionOpt;
if (isObject(notMerge)) {
lazyUpdate = notMerge.lazyUpdate;
silent = notMerge.silent;
replaceMerge = notMerge.replaceMerge;
transitionOpt = notMerge.transition;
notMerge = notMerge.notMerge;
}
this[IN_MAIN_PROCESS_KEY] = true;
if (!this._model || notMerge) {
var optionManager = new OptionManager(this._api);
var theme = this._theme;
var ecModel = this._model = new GlobalModel();
ecModel.scheduler = this._scheduler;
ecModel.ssr = this._ssr;
ecModel.init(null, null, null, theme, this._locale, optionManager);
}
this._model.setOption(option, {
replaceMerge: replaceMerge
}, optionPreprocessorFuncs);
var updateParams = {
seriesTransition: transitionOpt,
optionChanged: true
};
if (lazyUpdate) {
this[PENDING_UPDATE] = {
silent: silent,
updateParams: updateParams
};
this[IN_MAIN_PROCESS_KEY] = false;
// `setOption(option, {lazyMode: true})` may be called when zrender has been slept.
// It should wake it up to make sure zrender start to render at the next frame.
this.getZr().wakeUp();
} else {
try {
prepare(this);
updateMethods.update.call(this, null, updateParams);
} catch (e) {
this[PENDING_UPDATE] = null;
this[IN_MAIN_PROCESS_KEY] = false;
throw e;
}
// Ensure zr refresh sychronously, and then pixel in canvas can be
// fetched after `setOption`.
if (!this._ssr) {
// not use flush when using ssr mode.
this._zr.flush();
}
this[PENDING_UPDATE] = null;
this[IN_MAIN_PROCESS_KEY] = false;
flushPendingActions.call(this, silent);
triggerUpdatedEvent.call(this, silent);
}
};
/**
* @deprecated
*/
ECharts.prototype.setTheme = function () {
deprecateLog('ECharts#setTheme() is DEPRECATED in ECharts 3.0');
};
// We don't want developers to use getModel directly.
ECharts.prototype.getModel = function () {
return this._model;
};
ECharts.prototype.getOption = function () {
return this._model && this._model.getOption();
};
ECharts.prototype.getWidth = function () {
return this._zr.getWidth();
};
ECharts.prototype.getHeight = function () {
return this._zr.getHeight();
};
ECharts.prototype.getDevicePixelRatio = function () {
return this._zr.painter.dpr
/* eslint-disable-next-line */ || env.hasGlobalWindow && window.devicePixelRatio || 1;
};
/**
* Get canvas which has all thing rendered
* @deprecated Use renderToCanvas instead.
*/
ECharts.prototype.getRenderedCanvas = function (opts) {
if (process.env.NODE_ENV !== 'production') {
deprecateReplaceLog('getRenderedCanvas', 'renderToCanvas');
}
return this.renderToCanvas(opts);
};
ECharts.prototype.renderToCanvas = function (opts) {
opts = opts || {};
var painter = this._zr.painter;
if (process.env.NODE_ENV !== 'production') {
if (painter.type !== 'canvas') {
throw new Error('renderToCanvas can only be used in the canvas renderer.');
}
}
return painter.getRenderedCanvas({
backgroundColor: opts.backgroundColor || this._model.get('backgroundColor'),
pixelRatio: opts.pixelRatio || this.getDevicePixelRatio()
});
};
ECharts.prototype.renderToSVGString = function (opts) {
opts = opts || {};
var painter = this._zr.painter;
if (process.env.NODE_ENV !== 'production') {
if (painter.type !== 'svg') {
throw new Error('renderToSVGString can only be used in the svg renderer.');
}
}
return painter.renderToString({
useViewBox: opts.useViewBox
});
};
/**
* Get svg data url
*/
ECharts.prototype.getSvgDataURL = function () {
if (!env.svgSupported) {
return;
}
var zr = this._zr;
var list = zr.storage.getDisplayList();
// Stop animations
each(list, function (el) {
el.stopAnimation(null, true);
});
return zr.painter.toDataURL();
};
ECharts.prototype.getDataURL = function (opts) {
if (this._disposed) {
disposedWarning(this.id);
return;
}
opts = opts || {};
var excludeComponents = opts.excludeComponents;
var ecModel = this._model;
var excludesComponentViews = [];
var self = this;
each(excludeComponents, function (componentType) {
ecModel.eachComponent({
mainType: componentType
}, function (component) {
var view = self._componentsMap[component.__viewId];
if (!view.group.ignore) {
excludesComponentViews.push(view);
view.group.ignore = true;
}
});
});
var url = this._zr.painter.getType() === 'svg' ? this.getSvgDataURL() : this.renderToCanvas(opts).toDataURL('image/' + (opts && opts.type || 'png'));
each(excludesComponentViews, function (view) {
view.group.ignore = false;
});
return url;
};
ECharts.prototype.getConnectedDataURL = function (opts) {
if (this._disposed) {
disposedWarning(this.id);
return;
}
var isSvg = opts.type === 'svg';
var groupId = this.group;
var mathMin = Math.min;
var mathMax = Math.max;
var MAX_NUMBER = Infinity;
if (connectedGroups[groupId]) {
var left_1 = MAX_NUMBER;
var top_1 = MAX_NUMBER;
var right_1 = -MAX_NUMBER;
var bottom_1 = -MAX_NUMBER;
var canvasList_1 = [];
var dpr_1 = opts && opts.pixelRatio || this.getDevicePixelRatio();
each(instances, function (chart, id) {
if (chart.group === groupId) {
var canvas = isSvg ? chart.getZr().painter.getSvgDom().innerHTML : chart.renderToCanvas(clone(opts));
var boundingRect = chart.getDom().getBoundingClientRect();
left_1 = mathMin(boundingRect.left, left_1);
top_1 = mathMin(boundingRect.top, top_1);
right_1 = mathMax(boundingRect.right, right_1);
bottom_1 = mathMax(boundingRect.bottom, bottom_1);
canvasList_1.push({
dom: canvas,
left: boundingRect.left,
top: boundingRect.top
});
}
});
left_1 *= dpr_1;
top_1 *= dpr_1;
right_1 *= dpr_1;
bottom_1 *= dpr_1;
var width = right_1 - left_1;
var height = bottom_1 - top_1;
var targetCanvas = platformApi.createCanvas();
var zr_1 = zrender.init(targetCanvas, {
renderer: isSvg ? 'svg' : 'canvas'
});
zr_1.resize({
width: width,
height: height
});
if (isSvg) {
var content_1 = '';
each(canvasList_1, function (item) {
var x = item.left - left_1;
var y = item.top - top_1;
content_1 += '<g transform="translate(' + x + ',' + y + ')">' + item.dom + '</g>';
});
zr_1.painter.getSvgRoot().innerHTML = content_1;
if (opts.connectedBackgroundColor) {
zr_1.painter.setBackgroundColor(opts.connectedBackgroundColor);
}
zr_1.refreshImmediately();
return zr_1.painter.toDataURL();
} else {
// Background between the charts
if (opts.connectedBackgroundColor) {
zr_1.add(new graphic.Rect({
shape: {
x: 0,
y: 0,
width: width,
height: height
},
style: {
fill: opts.connectedBackgroundColor
}
}));
}
each(canvasList_1, function (item) {
var img = new graphic.Image({
style: {
x: item.left * dpr_1 - left_1,
y: item.top * dpr_1 - top_1,
image: item.dom
}
});
zr_1.add(img);
});
zr_1.refreshImmediately();
return targetCanvas.toDataURL('image/' + (opts && opts.type || 'png'));
}
} else {
return this.getDataURL(opts);
}
};
ECharts.prototype.convertToPixel = function (finder, value) {
return doConvertPixel(this, 'convertToPixel', finder, value);
};
ECharts.prototype.convertFromPixel = function (finder, value) {
return doConvertPixel(this, 'convertFromPixel', finder, value);
};
/**
* Is the specified coordinate systems or components contain the given pixel point.
* @param {Array|number} value
* @return {boolean} result
*/
ECharts.prototype.containPixel = function (finder, value) {
if (this._disposed) {
disposedWarning(this.id);
return;
}
var ecModel = this._model;
var result;
var findResult = modelUtil.parseFinder(ecModel, finder);
each(findResult, function (models, key) {
key.indexOf('Models') >= 0 && each(models, function (model) {
var coordSys = model.coordinateSystem;
if (coordSys && coordSys.containPoint) {
result = result || !!coordSys.containPoint(value);
} else if (key === 'seriesModels') {
var view = this._chartsMap[model.__viewId];
if (view && view.containPoint) {
result = result || view.containPoint(value, model);
} else {
if (process.env.NODE_ENV !== 'production') {
warn(key + ': ' + (view ? 'The found component do not support containPoint.' : 'No view mapping to the found component.'));
}
}
} else {
if (process.env.NODE_ENV !== 'production') {
warn(key + ': containPoint is not supported');
}
}
}, this);
}, this);
return !!result;
};
/**
* Get visual from series or data.
* @param finder
* If string, e.g., 'series', means {seriesIndex: 0}.
* If Object, could contain some of these properties below:
* {
* seriesIndex / seriesId / seriesName,
* dataIndex / dataIndexInside
* }
* If dataIndex is not specified, series visual will be fetched,
* but not data item visual.
* If all of seriesIndex, seriesId, seriesName are not specified,
* visual will be fetched from first series.
* @param visualType 'color', 'symbol', 'symbolSize'
*/
ECharts.prototype.getVisual = function (finder, visualType) {
var ecModel = this._model;
var parsedFinder = modelUtil.parseFinder(ecModel, finder, {
defaultMainType: 'series'
});
var seriesModel = parsedFinder.seriesModel;
if (process.env.NODE_ENV !== 'production') {
if (!seriesModel) {
warn('There is no specified series model');
}
}
var data = seriesModel.getData();
var dataIndexInside = parsedFinder.hasOwnProperty('dataIndexInside') ? parsedFinder.dataIndexInside : parsedFinder.hasOwnProperty('dataIndex') ? data.indexOfRawIndex(parsedFinder.dataIndex) : null;
return dataIndexInside != null ? getItemVisualFromData(data, dataIndexInside, visualType) : getVisualFromData(data, visualType);
};
/**
* Get view of corresponding component model
*/
ECharts.prototype.getViewOfComponentModel = function (componentModel) {
return this._componentsMap[componentModel.__viewId];
};
/**
* Get view of corresponding series model
*/
ECharts.prototype.getViewOfSeriesModel = function (seriesModel) {
return this._chartsMap[seriesModel.__viewId];
};
ECharts.prototype._initEvents = function () {
var _this = this;
each(MOUSE_EVENT_NAMES, function (eveName) {
var handler = function (e) {
var ecModel = _this.getModel();
var el = e.target;
var params;
var isGlobalOut = eveName === 'globalout';
// no e.target when 'globalout'.
if (isGlobalOut) {
params = {};
} else {
el && findEventDispatcher(el, function (parent) {
var ecData = getECData(parent);
if (ecData && ecData.dataIndex != null) {
var dataModel = ecData.dataModel || ecModel.getSeriesByIndex(ecData.seriesIndex);
params = dataModel && dataModel.getDataParams(ecData.dataIndex, ecData.dataType, el) || {};
return true;
}
// If element has custom eventData of components
else if (ecData.eventData) {
params = extend({}, ecData.eventData);
return true;
}
}, true);
}
// Contract: if params prepared in mouse event,
// these properties must be specified:
// {
// componentType: string (component main type)
// componentIndex: number
// }
// Otherwise event query can not work.
if (params) {
var componentType = params.componentType;
var componentIndex = params.componentIndex;
// Special handling for historic reason: when trigger by
// markLine/markPoint/markArea, the componentType is
// 'markLine'/'markPoint'/'markArea', but we should better
// enable them to be queried by seriesIndex, since their
// option is set in each series.
if (componentType === 'markLine' || componentType === 'markPoint' || componentType === 'markArea') {
componentType = 'series';
componentIndex = params.seriesIndex;
}
var model = componentType && componentIndex != null && ecModel.getComponent(componentType, componentIndex);
var view = model && _this[model.mainType === 'series' ? '_chartsMap' : '_componentsMap'][model.__viewId];
if (process.env.NODE_ENV !== 'production') {
// `event.componentType` and `event[componentTpype + 'Index']` must not
// be missed, otherwise there is no way to distinguish source component.
// See `dataFormat.getDataParams`.
if (!isGlobalOut && !(model && view)) {
warn('model or view can not be found by params');
}
}
params.event = e;
params.type = eveName;
_this._$eventProcessor.eventInfo = {
targetEl: el,
packedEvent: params,
model: model,
view: view
};
_this.trigger(eveName, params);
}
};
// Consider that some component (like tooltip, brush, ...)
// register zr event handler, but user event handler might
// do anything, such as call `setOption` or `dispatchAction`,
// which probably update any of the content and probably
// cause problem if it is called previous other inner handlers.
handler.zrEventfulCallAtLast = true;
_this._zr.on(eveName, handler, _this);
});
each(eventActionMap, function (actionType, eventType) {
_this._messageCenter.on(eventType, function (event) {
this.trigger(eventType, event);
}, _this);
});
// Extra events
// TODO register?
each(['selectchanged'], function (eventType) {
_this._messageCenter.on(eventType, function (event) {
this.trigger(eventType, event);
}, _this);
});
handleLegacySelectEvents(this._messageCenter, this, this._api);
};
ECharts.prototype.isDisposed = function () {
return this._disposed;
};
ECharts.prototype.clear = function () {
if (this._disposed) {
disposedWarning(this.id);
return;
}
this.setOption({
series: []
}, true);
};
ECharts.prototype.dispose = function () {
if (this._disposed) {
disposedWarning(this.id);
return;
}
this._disposed = true;
var dom = this.getDom();
if (dom) {
modelUtil.setAttribute(this.getDom(), DOM_ATTRIBUTE_KEY, '');
}
var chart = this;
var api = chart._api;
var ecModel = chart._model;
each(chart._componentsViews, function (component) {
component.dispose(ecModel, api);
});
each(chart._chartsViews, function (chart) {
chart.dispose(ecModel, api);
});
// Dispose after all views disposed
chart._zr.dispose();
// Set properties to null.
// To reduce the memory cost in case the top code still holds this instance unexpectedly.
chart._dom = chart._model = chart._chartsMap = chart._componentsMap = chart._chartsViews = chart._componentsViews = chart._scheduler = chart._api = chart._zr = chart._throttledZrFlush = chart._theme = chart._coordSysMgr = chart._messageCenter = null;
delete instances[chart.id];
};
/**
* Resize the chart
*/
ECharts.prototype.resize = function (opts) {
if (this[IN_MAIN_PROCESS_KEY]) {
if (process.env.NODE_ENV !== 'production') {
error('`resize` should not be called during main process.');
}
return;
}
if (this._disposed) {
disposedWarning(this.id);
return;
}
this._zr.resize(opts);
var ecModel = this._model;
// Resize loading effect
this._loadingFX && this._loadingFX.resize();
if (!ecModel) {
return;
}
var needPrepare = ecModel.resetOption('media');
var silent = opts && opts.silent;
// There is some real cases that:
// chart.setOption(option, { lazyUpdate: true });
// chart.resize();
if (this[PENDING_UPDATE]) {
if (silent == null) {
silent = this[PENDING_UPDATE].silent;
}
needPrepare = true;
this[PENDING_UPDATE] = null;
}
this[IN_MAIN_PROCESS_KEY] = true;
try {
needPrepare && prepare(this);
updateMethods.update.call(this, {
type: 'resize',
animation: extend({
// Disable animation
duration: 0
}, opts && opts.animation)
});
} catch (e) {
this[IN_MAIN_PROCESS_KEY] = false;
throw e;
}
this[IN_MAIN_PROCESS_KEY] = false;
flushPendingActions.call(this, silent);
triggerUpdatedEvent.call(this, silent);
};
ECharts.prototype.showLoading = function (name, cfg) {
if (this._disposed) {
disposedWarning(this.id);
return;
}
if (isObject(name)) {
cfg = name;
name = '';
}
name = name || 'default';
this.hideLoading();
if (!loadingEffects[name]) {
if (process.env.NODE_ENV !== 'production') {
warn('Loading effects ' + name + ' not exists.');
}
return;
}
var el = loadingEffects[name](this._api, cfg);
var zr = this._zr;
this._loadingFX = el;
zr.add(el);
};
/**
* Hide loading effect
*/
ECharts.prototype.hideLoading = function () {
if (this._disposed) {
disposedWarning(this.id);
return;
}
this._loadingFX && this._zr.remove(this._loadingFX);
this._loadingFX = null;
};
ECharts.prototype.makeActionFromEvent = function (eventObj) {
var payload = extend({}, eventObj);
payload.type = eventActionMap[eventObj.type];
return payload;
};
/**
* @param opt If pass boolean, means opt.silent
* @param opt.silent Default `false`. Whether trigger events.
* @param opt.flush Default `undefined`.
* true: Flush immediately, and then pixel in canvas can be fetched
* immediately. Caution: it might affect performance.
* false: Not flush.
* undefined: Auto decide whether perform flush.
*/
ECharts.prototype.dispatchAction = function (payload, opt) {
if (this._disposed) {
disposedWarning(this.id);
return;
}
if (!isObject(opt)) {
opt = {
silent: !!opt
};
}
if (!actions[payload.type]) {
return;
}
// Avoid dispatch action before setOption. Especially in `connect`.
if (!this._model) {
return;
}
// May dispatchAction in rendering procedure
if (this[IN_MAIN_PROCESS_KEY]) {
this._pendingActions.push(payload);
return;
}
var silent = opt.silent;
doDispatchAction.call(this, payload, silent);
var flush = opt.flush;
if (flush) {
this._zr.flush();
} else if (flush !== false && env.browser.weChat) {
// In WeChat embedded browser, `requestAnimationFrame` and `setInterval`
// hang when sliding page (on touch event), which cause that zr does not
// refresh until user interaction finished, which is not expected.
// But `dispatchAction` may be called too frequently when pan on touch
// screen, which impacts performance if do not throttle them.
this._throttledZrFlush();
}
flushPendingActions.call(this, silent);
triggerUpdatedEvent.call(this, silent);
};
ECharts.prototype.updateLabelLayout = function () {
lifecycle.trigger('series:layoutlabels', this._model, this._api, {
// Not adding series labels.
// TODO
updatedSeries: []
});
};
ECharts.prototype.appendData = function (params) {
if (this._disposed) {
disposedWarning(this.id);
return;
}
var seriesIndex = params.seriesIndex;
var ecModel = this.getModel();
var seriesModel = ecModel.getSeriesByIndex(seriesIndex);
if (process.env.NODE_ENV !== 'production') {
assert(params.data && seriesModel);
}
seriesModel.appendData(params);
// Note: `appendData` does not support that update extent of coordinate
// system, util some scenario require that. In the expected usage of
// `appendData`, the initial extent of coordinate system should better
// be fixed by axis `min`/`max` setting or initial data, otherwise if
// the extent changed while `appendData`, the location of the painted
// graphic elements have to be changed, which make the usage of
// `appendData` meaningless.
this._scheduler.unfinished = true;
this.getZr().wakeUp();
};
// A work around for no `internal` modifier in ts yet but
// need to strictly hide private methods to JS users.
ECharts.internalField = function () {
prepare = function (ecIns) {
var scheduler = ecIns._scheduler;
scheduler.restorePipelines(ecIns._model);
scheduler.prepareStageTasks();
prepareView(ecIns, true);
prepareView(ecIns, false);
scheduler.plan();
};
/**
* Prepare view instances of charts and components
*/
prepareView = function (ecIns, isComponent) {
var ecModel = ecIns._model;
var scheduler = ecIns._scheduler;
var viewList = isComponent ? ecIns._componentsViews : ecIns._chartsViews;
var viewMap = isComponent ? ecIns._componentsMap : ecIns._chartsMap;
var zr = ecIns._zr;
var api = ecIns._api;
for (var i = 0; i < viewList.length; i++) {
viewList[i].__alive = false;
}
isComponent ? ecModel.eachComponent(function (componentType, model) {
componentType !== 'series' && doPrepare(model);
}) : ecModel.eachSeries(doPrepare);
function doPrepare(model) {
// By default view will be reused if possible for the case that `setOption` with "notMerge"
// mode and need to enable transition animation. (Usually, when they have the same id, or
// especially no id but have the same type & name & index. See the `model.id` generation
// rule in `makeIdAndName` and `viewId` generation rule here).
// But in `replaceMerge` mode, this feature should be able to disabled when it is clear that
// the new model has nothing to do with the old model.
var requireNewView = model.__requireNewView;
// This command should not work twice.
model.__requireNewView = false;
// Consider: id same and type changed.
var viewId = '_ec_' + model.id + '_' + model.type;
var view = !requireNewView && viewMap[viewId];
if (!view) {
var classType = parseClassType(model.type);
var Clazz = isComponent ? ComponentView.getClass(classType.main, classType.sub) :
// FIXME:TS
// (ChartView as ChartViewConstructor).getClass('series', classType.sub)
// For backward compat, still support a chart type declared as only subType
// like "liquidfill", but recommend "series.liquidfill"
// But need a base class to make a type series.
ChartView.getClass(classType.sub);
if (process.env.NODE_ENV !== 'production') {
assert(Clazz, classType.sub + ' does not exist.');
}
view = new Clazz();
view.init(ecModel, api);
viewMap[viewId] = view;
viewList.push(view);
zr.add(view.group);
}
model.__viewId = view.__id = viewId;
view.__alive = true;
view.__model = model;
view.group.__ecComponentInfo = {
mainType: model.mainType,
index: model.componentIndex
};
!isComponent && scheduler.prepareView(view, model, ecModel, api);
}
for (var i = 0; i < viewList.length;) {
var view = viewList[i];
if (!view.__alive) {
!isComponent && view.renderTask.dispose();
zr.remove(view.group);
view.dispose(ecModel, api);
viewList.splice(i, 1);
if (viewMap[view.__id] === view) {
delete viewMap[view.__id];
}
view.__id = view.group.__ecComponentInfo = null;
} else {
i++;
}
}
};
updateDirectly = function (ecIns, method, payload, mainType, subType) {
var ecModel = ecIns._model;
ecModel.setUpdatePayload(payload);
// broadcast
if (!mainType) {
// FIXME
// Chart will not be update directly here, except set dirty.
// But there is no such scenario now.
each([].concat(ecIns._componentsViews).concat(ecIns._chartsViews), callView);
return;
}
var query = {};
query[mainType + 'Id'] = payload[mainType + 'Id'];
query[mainType + 'Index'] = payload[mainType + 'Index'];
query[mainType + 'Name'] = payload[mainType + 'Name'];
var condition = {
mainType: mainType,
query: query
};
subType && (condition.subType = subType); // subType may be '' by parseClassType;
var excludeSeriesId = payload.excludeSeriesId;
var excludeSeriesIdMap;
if (excludeSeriesId != null) {
excludeSeriesIdMap = createHashMap();
each(modelUtil.normalizeToArray(excludeSeriesId), function (id) {
var modelId = modelUtil.convertOptionIdName(id, null);
if (modelId != null) {
excludeSeriesIdMap.set(modelId, true);
}
});
}
// If dispatchAction before setOption, do nothing.
ecModel && ecModel.eachComponent(condition, function (model) {
var isExcluded = excludeSeriesIdMap && excludeSeriesIdMap.get(model.id) != null;
if (isExcluded) {
return;
}
;
if (isHighDownPayload(payload)) {
if (model instanceof SeriesModel) {
if (payload.type === HIGHLIGHT_ACTION_TYPE && !payload.notBlur && !model.get(['emphasis', 'disabled'])) {
blurSeriesFromHighlightPayload(model, payload, ecIns._api);
}
} else {
var _a = findComponentHighDownDispatchers(model.mainType, model.componentIndex, payload.name, ecIns._api),
focusSelf = _a.focusSelf,
dispatchers = _a.dispatchers;
if (payload.type === HIGHLIGHT_ACTION_TYPE && focusSelf && !payload.notBlur) {
blurComponent(model.mainType, model.componentIndex, ecIns._api);
}
// PENDING:
// Whether to put this "enter emphasis" code in `ComponentView`,
// which will be the same as `ChartView` but might be not necessary
// and will be far from this logic.
if (dispatchers) {
each(dispatchers, function (dispatcher) {
payload.type === HIGHLIGHT_ACTION_TYPE ? enterEmphasis(dispatcher) : leaveEmphasis(dispatcher);
});
}
}
} else if (isSelectChangePayload(payload)) {
// TODO geo
if (model instanceof SeriesModel) {
toggleSelectionFromPayload(model, payload, ecIns._api);
updateSeriesElementSelection(model);
markStatusToUpdate(ecIns);
}
}
}, ecIns);
ecModel && ecModel.eachComponent(condition, function (model) {
var isExcluded = excludeSeriesIdMap && excludeSeriesIdMap.get(model.id) != null;
if (isExcluded) {
return;
}
;
callView(ecIns[mainType === 'series' ? '_chartsMap' : '_componentsMap'][model.__viewId]);
}, ecIns);
function callView(view) {
view && view.__alive && view[method] && view[method](view.__model, ecModel, ecIns._api, payload);
}
};
updateMethods = {
prepareAndUpdate: function (payload) {
prepare(this);
updateMethods.update.call(this, payload, {
// Needs to mark option changed if newOption is given.
// It's from MagicType.
// TODO If use a separate flag optionChanged in payload?
optionChanged: payload.newOption != null
});
},
update: function (payload, updateParams) {
var ecModel = this._model;
var api = this._api;
var zr = this._zr;
var coordSysMgr = this._coordSysMgr;
var scheduler = this._scheduler;
// update before setOption
if (!ecModel) {
return;
}
ecModel.setUpdatePayload(payload);
scheduler.restoreData(ecModel, payload);
scheduler.performSeriesTasks(ecModel);
// TODO
// Save total ecModel here for undo/redo (after restoring data and before processing data).
// Undo (restoration of total ecModel) can be carried out in 'action' or outside API call.
// Create new coordinate system each update
// In LineView may save the old coordinate system and use it to get the original point.
coordSysMgr.create(ecModel, api);
scheduler.performDataProcessorTasks(ecModel, payload);
// Current stream render is not supported in data process. So we can update
// stream modes after data processing, where the filtered data is used to
// determine whether to use progressive rendering.
updateStreamModes(this, ecModel);
// We update stream modes before coordinate system updated, then the modes info
// can be fetched when coord sys updating (consider the barGrid extent fix). But
// the drawback is the full coord info can not be fetched. Fortunately this full
// coord is not required in stream mode updater currently.
coordSysMgr.update(ecModel, api);
clearColorPalette(ecModel);
scheduler.performVisualTasks(ecModel, payload);
render(this, ecModel, api, payload, updateParams);
// Set background
var backgroundColor = ecModel.get('backgroundColor') || 'transparent';
var darkMode = ecModel.get('darkMode');
zr.setBackgroundColor(backgroundColor);
// Force set dark mode.
if (darkMode != null && darkMode !== 'auto') {
zr.setDarkMode(darkMode);
}
lifecycle.trigger('afterupdate', ecModel, api);
},
updateTransform: function (payload) {
var _this = this;
var ecModel = this._model;
var api = this._api;
// update before setOption
if (!ecModel) {
return;
}
ecModel.setUpdatePayload(payload);
// ChartView.markUpdateMethod(payload, 'updateTransform');
var componentDirtyList = [];
ecModel.eachComponent(function (componentType, componentModel) {
if (componentType === 'series') {
return;
}
var componentView = _this.getViewOfComponentModel(componentModel);
if (componentView && componentView.__alive) {
if (componentView.updateTransform) {
var result = componentView.updateTransform(componentModel, ecModel, api, payload);
result && result.update && componentDirtyList.push(componentView);
} else {
componentDirtyList.push(componentView);
}
}
});
var seriesDirtyMap = createHashMap();
ecModel.eachSeries(function (seriesModel) {
var chartView = _this._chartsMap[seriesModel.__viewId];
if (chartView.updateTransform) {
var result = chartView.updateTransform(seriesModel, ecModel, api, payload);
result && result.update && seriesDirtyMap.set(seriesModel.uid, 1);
} else {
seriesDirtyMap.set(seriesModel.uid, 1);
}
});
clearColorPalette(ecModel);
// Keep pipe to the exist pipeline because it depends on the render task of the full pipeline.
// this._scheduler.performVisualTasks(ecModel, payload, 'layout', true);
this._scheduler.performVisualTasks(ecModel, payload, {
setDirty: true,
dirtyMap: seriesDirtyMap
});
// Currently, not call render of components. Geo render cost a lot.
// renderComponents(ecIns, ecModel, api, payload, componentDirtyList);
renderSeries(this, ecModel, api, payload, {}, seriesDirtyMap);
lifecycle.trigger('afterupdate', ecModel, api);
},
updateView: function (payload) {
var ecModel = this._model;
// update before setOption
if (!ecModel) {
return;
}
ecModel.setUpdatePayload(payload);
ChartView.markUpdateMethod(payload, 'updateView');
clearColorPalette(ecModel);
// Keep pipe to the exist pipeline because it depends on the render task of the full pipeline.
this._scheduler.performVisualTasks(ecModel, payload, {
setDirty: true
});
render(this, ecModel, this._api, payload, {});
lifecycle.trigger('afterupdate', ecModel, this._api);
},
updateVisual: function (payload) {
// updateMethods.update.call(this, payload);
var _this = this;
var ecModel = this._model;
// update before setOption
if (!ecModel) {
return;
}
ecModel.setUpdatePayload(payload);
// clear all visual
ecModel.eachSeries(function (seriesModel) {
seriesModel.getData().clearAllVisual();
});
// Perform visual
ChartView.markUpdateMethod(payload, 'updateVisual');
clearColorPalette(ecModel);
// Keep pipe to the exist pipeline because it depends on the render task of the full pipeline.
this._scheduler.performVisualTasks(ecModel, payload, {
visualType: 'visual',
setDirty: true
});
ecModel.eachComponent(function (componentType, componentModel) {
if (componentType !== 'series') {
var componentView = _this.getViewOfComponentModel(componentModel);
componentView && componentView.__alive && componentView.updateVisual(componentModel, ecModel, _this._api, payload);
}
});
ecModel.eachSeries(function (seriesModel) {
var chartView = _this._chartsMap[seriesModel.__viewId];
chartView.updateVisual(seriesModel, ecModel, _this._api, payload);
});
lifecycle.trigger('afterupdate', ecModel, this._api);
},
updateLayout: function (payload) {
updateMethods.update.call(this, payload);
}
};
doConvertPixel = function (ecIns, methodName, finder, value) {
if (ecIns._disposed) {
disposedWarning(ecIns.id);
return;
}
var ecModel = ecIns._model;
var coordSysList = ecIns._coordSysMgr.getCoordinateSystems();
var result;
var parsedFinder = modelUtil.parseFinder(ecModel, finder);
for (var i = 0; i < coordSysList.length; i++) {
var coordSys = coordSysList[i];
if (coordSys[methodName] && (result = coordSys[methodName](ecModel, parsedFinder, value)) != null) {
return result;
}
}
if (process.env.NODE_ENV !== 'production') {
warn('No coordinate system that supports ' + methodName + ' found by the given finder.');
}
};
updateStreamModes = function (ecIns, ecModel) {
var chartsMap = ecIns._chartsMap;
var scheduler = ecIns._scheduler;
ecModel.eachSeries(function (seriesModel) {
scheduler.updateStreamModes(seriesModel, chartsMap[seriesModel.__viewId]);
});
};
doDispatchAction = function (payload, silent) {
var _this = this;
var ecModel = this.getModel();
var payloadType = payload.type;
var escapeConnect = payload.escapeConnect;
var actionWrap = actions[payloadType];
var actionInfo = actionWrap.actionInfo;
var cptTypeTmp = (actionInfo.update || 'update').split(':');
var updateMethod = cptTypeTmp.pop();
var cptType = cptTypeTmp[0] != null && parseClassType(cptTypeTmp[0]);
this[IN_MAIN_PROCESS_KEY] = true;
var payloads = [payload];
var batched = false;
// Batch action
if (payload.batch) {
batched = true;
payloads = map(payload.batch, function (item) {
item = defaults(extend({}, item), payload);
item.batch = null;
return item;
});
}
var eventObjBatch = [];
var eventObj;
var isSelectChange = isSelectChangePayload(payload);
var isHighDown = isHighDownPayload(payload);
// Only leave blur once if there are multiple batches.
if (isHighDown) {
allLeaveBlur(this._api);
}
each(payloads, function (batchItem) {
// Action can specify the event by return it.
eventObj = actionWrap.action(batchItem, _this._model, _this._api);
// Emit event outside
eventObj = eventObj || extend({}, batchItem);
// Convert type to eventType
eventObj.type = actionInfo.event || eventObj.type;
eventObjBatch.push(eventObj);
// light update does not perform data process, layout and visual.
if (isHighDown) {
var _a = modelUtil.preParseFinder(payload),
queryOptionMap = _a.queryOptionMap,
mainTypeSpecified = _a.mainTypeSpecified;
var componentMainType = mainTypeSpecified ? queryOptionMap.keys()[0] : 'series';
updateDirectly(_this, updateMethod, batchItem, componentMainType);
markStatusToUpdate(_this);
} else if (isSelectChange) {
// At present `dispatchAction({ type: 'select', ... })` is not supported on components.
// geo still use 'geoselect'.
updateDirectly(_this, updateMethod, batchItem, 'series');
markStatusToUpdate(_this);
} else if (cptType) {
updateDirectly(_this, updateMethod, batchItem, cptType.main, cptType.sub);
}
});
if (updateMethod !== 'none' && !isHighDown && !isSelectChange && !cptType) {
try {
// Still dirty
if (this[PENDING_UPDATE]) {
prepare(this);
updateMethods.update.call(this, payload);
this[PENDING_UPDATE] = null;
} else {
updateMethods[updateMethod].call(this, payload);
}
} catch (e) {
this[IN_MAIN_PROCESS_KEY] = false;
throw e;
}
}
// Follow the rule of action batch
if (batched) {
eventObj = {
type: actionInfo.event || payloadType,
escapeConnect: escapeConnect,
batch: eventObjBatch
};
} else {
eventObj = eventObjBatch[0];
}
this[IN_MAIN_PROCESS_KEY] = false;
if (!silent) {
var messageCenter = this._messageCenter;
messageCenter.trigger(eventObj.type, eventObj);
// Extra triggered 'selectchanged' event
if (isSelectChange) {
var newObj = {
type: 'selectchanged',
escapeConnect: escapeConnect,
selected: getAllSelectedIndices(ecModel),
isFromClick: payload.isFromClick || false,
fromAction: payload.type,
fromActionPayload: payload
};
messageCenter.trigger(newObj.type, newObj);
}
}
};
flushPendingActions = function (silent) {
var pendingActions = this._pendingActions;
while (pendingActions.length) {
var payload = pendingActions.shift();
doDispatchAction.call(this, payload, silent);
}
};
triggerUpdatedEvent = function (silent) {
!silent && this.trigger('updated');
};
/**
* Event `rendered` is triggered when zr
* rendered. It is useful for realtime
* snapshot (reflect animation).
*
* Event `finished` is triggered when:
* (1) zrender rendering finished.
* (2) initial animation finished.
* (3) progressive rendering finished.
* (4) no pending action.
* (5) no delayed setOption needs to be processed.
*/
bindRenderedEvent = function (zr, ecIns) {
zr.on('rendered', function (params) {
ecIns.trigger('rendered', params);
// The `finished` event should not be triggered repeatedly,
// so it should only be triggered when rendering indeed happens
// in zrender. (Consider the case that dipatchAction is keep
// triggering when mouse move).
if (
// Although zr is dirty if initial animation is not finished
// and this checking is called on frame, we also check
// animation finished for robustness.
zr.animation.isFinished() && !ecIns[PENDING_UPDATE] && !ecIns._scheduler.unfinished && !ecIns._pendingActions.length) {
ecIns.trigger('finished');
}
});
};
bindMouseEvent = function (zr, ecIns) {
zr.on('mouseover', function (e) {
var el = e.target;
var dispatcher = findEventDispatcher(el, isHighDownDispatcher);
if (dispatcher) {
handleGlobalMouseOverForHighDown(dispatcher, e, ecIns._api);
markStatusToUpdate(ecIns);
}
}).on('mouseout', function (e) {
var el = e.target;
var dispatcher = findEventDispatcher(el, isHighDownDispatcher);
if (dispatcher) {
handleGlobalMouseOutForHighDown(dispatcher, e, ecIns._api);
markStatusToUpdate(ecIns);
}
}).on('click', function (e) {
var el = e.target;
var dispatcher = findEventDispatcher(el, function (target) {
return getECData(target).dataIndex != null;
}, true);
if (dispatcher) {
var actionType = dispatcher.selected ? 'unselect' : 'select';
var ecData = getECData(dispatcher);
ecIns._api.dispatchAction({
type: actionType,
dataType: ecData.dataType,
dataIndexInside: ecData.dataIndex,
seriesIndex: ecData.seriesIndex,
isFromClick: true
});
}
});
};
function clearColorPalette(ecModel) {
ecModel.clearColorPalette();
ecModel.eachSeries(function (seriesModel) {
seriesModel.clearColorPalette();
});
}
;
// Allocate zlevels for series and components
function allocateZlevels(ecModel) {
;
var componentZLevels = [];
var seriesZLevels = [];
var hasSeparateZLevel = false;
ecModel.eachComponent(function (componentType, componentModel) {
var zlevel = componentModel.get('zlevel') || 0;
var z = componentModel.get('z') || 0;
var zlevelKey = componentModel.getZLevelKey();
hasSeparateZLevel = hasSeparateZLevel || !!zlevelKey;
(componentType === 'series' ? seriesZLevels : componentZLevels).push({
zlevel: zlevel,
z: z,
idx: componentModel.componentIndex,
type: componentType,
key: zlevelKey
});
});
if (hasSeparateZLevel) {
// Series after component
var zLevels = componentZLevels.concat(seriesZLevels);
var lastSeriesZLevel_1;
var lastSeriesKey_1;
timsort(zLevels, function (a, b) {
if (a.zlevel === b.zlevel) {
return a.z - b.z;
}
return a.zlevel - b.zlevel;
});
each(zLevels, function (item) {
var componentModel = ecModel.getComponent(item.type, item.idx);
var zlevel = item.zlevel;
var key = item.key;
if (lastSeriesZLevel_1 != null) {
zlevel = Math.max(lastSeriesZLevel_1, zlevel);
}
if (key) {
if (zlevel === lastSeriesZLevel_1 && key !== lastSeriesKey_1) {
zlevel++;
}
lastSeriesKey_1 = key;
} else if (lastSeriesKey_1) {
if (zlevel === lastSeriesZLevel_1) {
zlevel++;
}
lastSeriesKey_1 = '';
}
lastSeriesZLevel_1 = zlevel;
componentModel.setZLevel(zlevel);
});
}
}
render = function (ecIns, ecModel, api, payload, updateParams) {
allocateZlevels(ecModel);
renderComponents(ecIns, ecModel, api, payload, updateParams);
each(ecIns._chartsViews, function (chart) {
chart.__alive = false;
});
renderSeries(ecIns, ecModel, api, payload, updateParams);
// Remove groups of unrendered charts
each(ecIns._chartsViews, function (chart) {
if (!chart.__alive) {
chart.remove(ecModel, api);
}
});
};
renderComponents = function (ecIns, ecModel, api, payload, updateParams, dirtyList) {
each(dirtyList || ecIns._componentsViews, function (componentView) {
var componentModel = componentView.__model;
clearStates(componentModel, componentView);
componentView.render(componentModel, ecModel, api, payload);
updateZ(componentModel, componentView);
updateStates(componentModel, componentView);
});
};
/**
* Render each chart and component
*/
renderSeries = function (ecIns, ecModel, api, payload, updateParams, dirtyMap) {
// Render all charts
var scheduler = ecIns._scheduler;
updateParams = extend(updateParams || {}, {
updatedSeries: ecModel.getSeries()
});
// TODO progressive?
lifecycle.trigger('series:beforeupdate', ecModel, api, updateParams);
var unfinished = false;
ecModel.eachSeries(function (seriesModel) {
var chartView = ecIns._chartsMap[seriesModel.__viewId];
chartView.__alive = true;
var renderTask = chartView.renderTask;
scheduler.updatePayload(renderTask, payload);
// TODO states on marker.
clearStates(seriesModel, chartView);
if (dirtyMap && dirtyMap.get(seriesModel.uid)) {
renderTask.dirty();
}
if (renderTask.perform(scheduler.getPerformArgs(renderTask))) {
unfinished = true;
}
chartView.group.silent = !!seriesModel.get('silent');
// Should not call markRedraw on group, because it will disable zrender
// incremental render (always render from the __startIndex each frame)
// chartView.group.markRedraw();
updateBlend(seriesModel, chartView);
updateSeriesElementSelection(seriesModel);
});
scheduler.unfinished = unfinished || scheduler.unfinished;
lifecycle.trigger('series:layoutlabels', ecModel, api, updateParams);
// transition after label is layouted.
lifecycle.trigger('series:transition', ecModel, api, updateParams);
ecModel.eachSeries(function (seriesModel) {
var chartView = ecIns._chartsMap[seriesModel.__viewId];
// Update Z after labels updated. Before applying states.
updateZ(seriesModel, chartView);
// NOTE: Update states after label is updated.
// label should be in normal status when layouting.
updateStates(seriesModel, chartView);
});
// If use hover layer
updateHoverLayerStatus(ecIns, ecModel);
lifecycle.trigger('series:afterupdate', ecModel, api, updateParams);
};
markStatusToUpdate = function (ecIns) {
ecIns[STATUS_NEEDS_UPDATE_KEY] = true;
// Wake up zrender if it's sleep. Let it update states in the next frame.
ecIns.getZr().wakeUp();
};
applyChangedStates = function (ecIns) {
if (!ecIns[STATUS_NEEDS_UPDATE_KEY]) {
return;
}
ecIns.getZr().storage.traverse(function (el) {
// Not applied on removed elements, it may still in fading.
if (graphic.isElementRemoved(el)) {
return;
}
applyElementStates(el);
});
ecIns[STATUS_NEEDS_UPDATE_KEY] = false;
};
function applyElementStates(el) {
var newStates = [];
var oldStates = el.currentStates;
// Keep other states.
for (var i = 0; i < oldStates.length; i++) {
var stateName = oldStates[i];
if (!(stateName === 'emphasis' || stateName === 'blur' || stateName === 'select')) {
newStates.push(stateName);
}
}
// Only use states when it's exists.
if (el.selected && el.states.select) {
newStates.push('select');
}
if (el.hoverState === HOVER_STATE_EMPHASIS && el.states.emphasis) {
newStates.push('emphasis');
} else if (el.hoverState === HOVER_STATE_BLUR && el.states.blur) {
newStates.push('blur');
}
el.useStates(newStates);
}
function updateHoverLayerStatus(ecIns, ecModel) {
var zr = ecIns._zr;
var storage = zr.storage;
var elCount = 0;
storage.traverse(function (el) {
if (!el.isGroup) {
elCount++;
}
});
if (elCount > ecModel.get('hoverLayerThreshold') && !env.node && !env.worker) {
ecModel.eachSeries(function (seriesModel) {
if (seriesModel.preventUsingHoverLayer) {
return;
}
var chartView = ecIns._chartsMap[seriesModel.__viewId];
if (chartView.__alive) {
chartView.eachRendered(function (el) {
if (el.states.emphasis) {
el.states.emphasis.hoverLayer = true;
}
});
}
});
}
}
;
/**
* Update chart and blend.
*/
function updateBlend(seriesModel, chartView) {
var blendMode = seriesModel.get('blendMode') || null;
chartView.eachRendered(function (el) {
// FIXME marker and other components
if (!el.isGroup) {
// DON'T mark the element dirty. In case element is incremental and don't want to rerender.
el.style.blend = blendMode;
}
});
}
;
function updateZ(model, view) {
if (model.preventAutoZ) {
return;
}
var z = model.get('z') || 0;
var zlevel = model.get('zlevel') || 0;
// Set z and zlevel
view.eachRendered(function (el) {
doUpdateZ(el, z, zlevel, -Infinity);
// Don't traverse the children because it has been traversed in _updateZ.
return true;
});
}
;
function doUpdateZ(el, z, zlevel, maxZ2) {
// Group may also have textContent
var label = el.getTextContent();
var labelLine = el.getTextGuideLine();
var isGroup = el.isGroup;
if (isGroup) {
// set z & zlevel of children elements of Group
var children = el.childrenRef();
for (var i = 0; i < children.length; i++) {
maxZ2 = Math.max(doUpdateZ(children[i], z, zlevel, maxZ2), maxZ2);
}
} else {
// not Group
el.z = z;
el.zlevel = zlevel;
maxZ2 = Math.max(el.z2, maxZ2);
}
// always set z and zlevel if label/labelLine exists
if (label) {
label.z = z;
label.zlevel = zlevel;
// lift z2 of text content
// TODO if el.emphasis.z2 is spcefied, what about textContent.
isFinite(maxZ2) && (label.z2 = maxZ2 + 2);
}
if (labelLine) {
var textGuideLineConfig = el.textGuideLineConfig;
labelLine.z = z;
labelLine.zlevel = zlevel;
isFinite(maxZ2) && (labelLine.z2 = maxZ2 + (textGuideLineConfig && textGuideLineConfig.showAbove ? 1 : -1));
}
return maxZ2;
}
// Clear states without animation.
// TODO States on component.
function clearStates(model, view) {
view.eachRendered(function (el) {
// Not applied on removed elements, it may still in fading.
if (graphic.isElementRemoved(el)) {
return;
}
var textContent = el.getTextContent();
var textGuide = el.getTextGuideLine();
if (el.stateTransition) {
el.stateTransition = null;
}
if (textContent && textContent.stateTransition) {
textContent.stateTransition = null;
}
if (textGuide && textGuide.stateTransition) {
textGuide.stateTransition = null;
}
// TODO If el is incremental.
if (el.hasState()) {
el.prevStates = el.currentStates;
el.clearStates();
} else if (el.prevStates) {
el.prevStates = null;
}
});
}
function updateStates(model, view) {
var stateAnimationModel = model.getModel('stateAnimation');
var enableAnimation = model.isAnimationEnabled();
var duration = stateAnimationModel.get('duration');
var stateTransition = duration > 0 ? {
duration: duration,
delay: stateAnimationModel.get('delay'),
easing: stateAnimationModel.get('easing')
// additive: stateAnimationModel.get('additive')
} : null;
view.eachRendered(function (el) {
if (el.states && el.states.emphasis) {
// Not applied on removed elements, it may still in fading.
if (graphic.isElementRemoved(el)) {
return;
}
if (el instanceof graphic.Path) {
savePathStates(el);
}
// Only updated on changed element. In case element is incremental and don't want to rerender.
// TODO, a more proper way?
if (el.__dirty) {
var prevStates = el.prevStates;
// Restore states without animation
if (prevStates) {
el.useStates(prevStates);
}
}
// Update state transition and enable animation again.
if (enableAnimation) {
el.stateTransition = stateTransition;
var textContent = el.getTextContent();
var textGuide = el.getTextGuideLine();
// TODO Is it necessary to animate label?
if (textContent) {
textContent.stateTransition = stateTransition;
}
if (textGuide) {
textGuide.stateTransition = stateTransition;
}
}
// Use highlighted and selected flag to toggle states.
if (el.__dirty) {
applyElementStates(el);
}
}
});
}
;
createExtensionAPI = function (ecIns) {
return new ( /** @class */function (_super) {
__extends(class_1, _super);
function class_1() {
return _super !== null && _super.apply(this, arguments) || this;
}
class_1.prototype.getCoordinateSystems = function () {
return ecIns._coordSysMgr.getCoordinateSystems();
};
class_1.prototype.getComponentByElement = function (el) {
while (el) {
var modelInfo = el.__ecComponentInfo;
if (modelInfo != null) {
return ecIns._model.getComponent(modelInfo.mainType, modelInfo.index);
}
el = el.parent;
}
};
class_1.prototype.enterEmphasis = function (el, highlightDigit) {
enterEmphasis(el, highlightDigit);
markStatusToUpdate(ecIns);
};
class_1.prototype.leaveEmphasis = function (el, highlightDigit) {
leaveEmphasis(el, highlightDigit);
markStatusToUpdate(ecIns);
};
class_1.prototype.enterBlur = function (el) {
enterBlur(el);
markStatusToUpdate(ecIns);
};
class_1.prototype.leaveBlur = function (el) {
leaveBlur(el);
markStatusToUpdate(ecIns);
};
class_1.prototype.enterSelect = function (el) {
enterSelect(el);
markStatusToUpdate(ecIns);
};
class_1.prototype.leaveSelect = function (el) {
leaveSelect(el);
markStatusToUpdate(ecIns);
};
class_1.prototype.getModel = function () {
return ecIns.getModel();
};
class_1.prototype.getViewOfComponentModel = function (componentModel) {
return ecIns.getViewOfComponentModel(componentModel);
};
class_1.prototype.getViewOfSeriesModel = function (seriesModel) {
return ecIns.getViewOfSeriesModel(seriesModel);
};
return class_1;
}(ExtensionAPI))(ecIns);
};
enableConnect = function (chart) {
function updateConnectedChartsStatus(charts, status) {
for (var i = 0; i < charts.length; i++) {
var otherChart = charts[i];
otherChart[CONNECT_STATUS_KEY] = status;
}
}
each(eventActionMap, function (actionType, eventType) {
chart._messageCenter.on(eventType, function (event) {
if (connectedGroups[chart.group] && chart[CONNECT_STATUS_KEY] !== CONNECT_STATUS_PENDING) {
if (event && event.escapeConnect) {
return;
}
var action_1 = chart.makeActionFromEvent(event);
var otherCharts_1 = [];
each(instances, function (otherChart) {
if (otherChart !== chart && otherChart.group === chart.group) {
otherCharts_1.push(otherChart);
}
});
updateConnectedChartsStatus(otherCharts_1, CONNECT_STATUS_PENDING);
each(otherCharts_1, function (otherChart) {
if (otherChart[CONNECT_STATUS_KEY] !== CONNECT_STATUS_UPDATING) {
otherChart.dispatchAction(action_1);
}
});
updateConnectedChartsStatus(otherCharts_1, CONNECT_STATUS_UPDATED);
}
});
});
};
}();
return ECharts;
}(Eventful);
var echartsProto = ECharts.prototype;
echartsProto.on = createRegisterEventWithLowercaseECharts('on');
echartsProto.off = createRegisterEventWithLowercaseECharts('off');
/**
* @deprecated
*/
// @ts-ignore
echartsProto.one = function (eventName, cb, ctx) {
var self = this;
deprecateLog('ECharts#one is deprecated.');
function wrapped() {
var args2 = [];
for (var _i = 0; _i < arguments.length; _i++) {
args2[_i] = arguments[_i];
}
cb && cb.apply && cb.apply(this, args2);
// @ts-ignore
self.off(eventName, wrapped);
}
;
// @ts-ignore
this.on.call(this, eventName, wrapped, ctx);
};
var MOUSE_EVENT_NAMES = ['click', 'dblclick', 'mouseover', 'mouseout', 'mousemove', 'mousedown', 'mouseup', 'globalout', 'contextmenu'];
function disposedWarning(id) {
if (process.env.NODE_ENV !== 'production') {
warn('Instance ' + id + ' has been disposed');
}
}
var actions = {};
/**
* Map eventType to actionType
*/
var eventActionMap = {};
var dataProcessorFuncs = [];
var optionPreprocessorFuncs = [];
var visualFuncs = [];
var themeStorage = {};
var loadingEffects = {};
var instances = {};
var connectedGroups = {};
var idBase = +new Date() - 0;
var groupIdBase = +new Date() - 0;
var DOM_ATTRIBUTE_KEY = '_echarts_instance_';
/**
* @param opts.devicePixelRatio Use window.devicePixelRatio by default
* @param opts.renderer Can choose 'canvas' or 'svg' to render the chart.
* @param opts.width Use clientWidth of the input `dom` by default.
* Can be 'auto' (the same as null/undefined)
* @param opts.height Use clientHeight of the input `dom` by default.
* Can be 'auto' (the same as null/undefined)
* @param opts.locale Specify the locale.
* @param opts.useDirtyRect Enable dirty rectangle rendering or not.
*/
export function init(dom, theme, opts) {
var isClient = !(opts && opts.ssr);
if (isClient) {
if (process.env.NODE_ENV !== 'production') {
if (!dom) {
throw new Error('Initialize failed: invalid dom.');
}
}
var existInstance = getInstanceByDom(dom);
if (existInstance) {
if (process.env.NODE_ENV !== 'production') {
warn('There is a chart instance already initialized on the dom.');
}
return existInstance;
}
if (process.env.NODE_ENV !== 'production') {
if (isDom(dom) && dom.nodeName.toUpperCase() !== 'CANVAS' && (!dom.clientWidth && (!opts || opts.width == null) || !dom.clientHeight && (!opts || opts.height == null))) {
warn('Can\'t get DOM width or height. Please check ' + 'dom.clientWidth and dom.clientHeight. They should not be 0.' + 'For example, you may need to call this in the callback ' + 'of window.onload.');
}
}
}
var chart = new ECharts(dom, theme, opts);
chart.id = 'ec_' + idBase++;
instances[chart.id] = chart;
isClient && modelUtil.setAttribute(dom, DOM_ATTRIBUTE_KEY, chart.id);
enableConnect(chart);
lifecycle.trigger('afterinit', chart);
return chart;
}
/**
* @usage
* (A)
* ```js
* let chart1 = echarts.init(dom1);
* let chart2 = echarts.init(dom2);
* chart1.group = 'xxx';
* chart2.group = 'xxx';
* echarts.connect('xxx');
* ```
* (B)
* ```js
* let chart1 = echarts.init(dom1);
* let chart2 = echarts.init(dom2);
* echarts.connect('xxx', [chart1, chart2]);
* ```
*/
export function connect(groupId) {
// Is array of charts
if (isArray(groupId)) {
var charts = groupId;
groupId = null;
// If any chart has group
each(charts, function (chart) {
if (chart.group != null) {
groupId = chart.group;
}
});
groupId = groupId || 'g_' + groupIdBase++;
each(charts, function (chart) {
chart.group = groupId;
});
}
connectedGroups[groupId] = true;
return groupId;
}
export function disconnect(groupId) {
connectedGroups[groupId] = false;
}
/**
* Alias and backward compatibility
* @deprecated
*/
export var disConnect = disconnect;
/**
* Dispose a chart instance
*/
export function dispose(chart) {
if (isString(chart)) {
chart = instances[chart];
} else if (!(chart instanceof ECharts)) {
// Try to treat as dom
chart = getInstanceByDom(chart);
}
if (chart instanceof ECharts && !chart.isDisposed()) {
chart.dispose();
}
}
export function getInstanceByDom(dom) {
return instances[modelUtil.getAttribute(dom, DOM_ATTRIBUTE_KEY)];
}
export function getInstanceById(key) {
return instances[key];
}
/**
* Register theme
*/
export function registerTheme(name, theme) {
themeStorage[name] = theme;
}
/**
* Register option preprocessor
*/
export function registerPreprocessor(preprocessorFunc) {
if (indexOf(optionPreprocessorFuncs, preprocessorFunc) < 0) {
optionPreprocessorFuncs.push(preprocessorFunc);
}
}
export function registerProcessor(priority, processor) {
normalizeRegister(dataProcessorFuncs, priority, processor, PRIORITY_PROCESSOR_DEFAULT);
}
/**
* Register postIniter
* @param {Function} postInitFunc
*/
export function registerPostInit(postInitFunc) {
registerUpdateLifecycle('afterinit', postInitFunc);
}
/**
* Register postUpdater
* @param {Function} postUpdateFunc
*/
export function registerPostUpdate(postUpdateFunc) {
registerUpdateLifecycle('afterupdate', postUpdateFunc);
}
export function registerUpdateLifecycle(name, cb) {
lifecycle.on(name, cb);
}
export function registerAction(actionInfo, eventName, action) {
if (isFunction(eventName)) {
action = eventName;
eventName = '';
}
var actionType = isObject(actionInfo) ? actionInfo.type : [actionInfo, actionInfo = {
event: eventName
}][0];
// Event name is all lowercase
actionInfo.event = (actionInfo.event || actionType).toLowerCase();
eventName = actionInfo.event;
if (eventActionMap[eventName]) {
// Already registered.
return;
}
// Validate action type and event name.
assert(ACTION_REG.test(actionType) && ACTION_REG.test(eventName));
if (!actions[actionType]) {
actions[actionType] = {
action: action,
actionInfo: actionInfo
};
}
eventActionMap[eventName] = actionType;
}
export function registerCoordinateSystem(type, coordSysCreator) {
CoordinateSystemManager.register(type, coordSysCreator);
}
/**
* Get dimensions of specified coordinate system.
* @param {string} type
* @return {Array.<string|Object>}
*/
export function getCoordinateSystemDimensions(type) {
var coordSysCreator = CoordinateSystemManager.get(type);
if (coordSysCreator) {
return coordSysCreator.getDimensionsInfo ? coordSysCreator.getDimensionsInfo() : coordSysCreator.dimensions.slice();
}
}
export { registerLocale } from './locale.js';
function registerLayout(priority, layoutTask) {
normalizeRegister(visualFuncs, priority, layoutTask, PRIORITY_VISUAL_LAYOUT, 'layout');
}
function registerVisual(priority, visualTask) {
normalizeRegister(visualFuncs, priority, visualTask, PRIORITY_VISUAL_CHART, 'visual');
}
export { registerLayout, registerVisual };
var registeredTasks = [];
function normalizeRegister(targetList, priority, fn, defaultPriority, visualType) {
if (isFunction(priority) || isObject(priority)) {
fn = priority;
priority = defaultPriority;
}
if (process.env.NODE_ENV !== 'production') {
if (isNaN(priority) || priority == null) {
throw new Error('Illegal priority');
}
// Check duplicate
each(targetList, function (wrap) {
assert(wrap.__raw !== fn);
});
}
// Already registered
if (indexOf(registeredTasks, fn) >= 0) {
return;
}
registeredTasks.push(fn);
var stageHandler = Scheduler.wrapStageHandler(fn, visualType);
stageHandler.__prio = priority;
stageHandler.__raw = fn;
targetList.push(stageHandler);
}
export function registerLoading(name, loadingFx) {
loadingEffects[name] = loadingFx;
}
/**
* ZRender need a canvas context to do measureText.
* But in node environment canvas may be created by node-canvas.
* So we need to specify how to create a canvas instead of using document.createElement('canvas')
*
*
* @deprecated use setPlatformAPI({ createCanvas }) instead.
*
* @example
* let Canvas = require('canvas');
* let echarts = require('echarts');
* echarts.setCanvasCreator(function () {
* // Small size is enough.
* return new Canvas(32, 32);
* });
*/
export function setCanvasCreator(creator) {
if (process.env.NODE_ENV !== 'production') {
deprecateLog('setCanvasCreator is deprecated. Use setPlatformAPI({ createCanvas }) instead.');
}
setPlatformAPI({
createCanvas: creator
});
}
/**
* The parameters and usage: see `geoSourceManager.registerMap`.
* Compatible with previous `echarts.registerMap`.
*/
export function registerMap(mapName, geoJson, specialAreas) {
var registerMap = getImpl('registerMap');
registerMap && registerMap(mapName, geoJson, specialAreas);
}
export function getMap(mapName) {
var getMap = getImpl('getMap');
return getMap && getMap(mapName);
}
export var registerTransform = registerExternalTransform;
/**
* Globa dispatchAction to a specified chart instance.
*/
// export function dispatchAction(payload: { chartId: string } & Payload, opt?: Parameters<ECharts['dispatchAction']>[1]) {
// if (!payload || !payload.chartId) {
// // Must have chartId to find chart
// return;
// }
// const chart = instances[payload.chartId];
// if (chart) {
// chart.dispatchAction(payload, opt);
// }
// }
// Builtin global visual
registerVisual(PRIORITY_VISUAL_GLOBAL, seriesStyleTask);
registerVisual(PRIORITY_VISUAL_CHART_DATA_CUSTOM, dataStyleTask);
registerVisual(PRIORITY_VISUAL_CHART_DATA_CUSTOM, dataColorPaletteTask);
registerVisual(PRIORITY_VISUAL_GLOBAL, seriesSymbolTask);
registerVisual(PRIORITY_VISUAL_CHART_DATA_CUSTOM, dataSymbolTask);
registerVisual(PRIORITY_VISUAL_DECAL, decal);
registerPreprocessor(backwardCompat);
registerProcessor(PRIORITY_PROCESSOR_DATASTACK, dataStack);
registerLoading('default', loadingDefault);
// Default actions
registerAction({
type: HIGHLIGHT_ACTION_TYPE,
event: HIGHLIGHT_ACTION_TYPE,
update: HIGHLIGHT_ACTION_TYPE
}, noop);
registerAction({
type: DOWNPLAY_ACTION_TYPE,
event: DOWNPLAY_ACTION_TYPE,
update: DOWNPLAY_ACTION_TYPE
}, noop);
registerAction({
type: SELECT_ACTION_TYPE,
event: SELECT_ACTION_TYPE,
update: SELECT_ACTION_TYPE
}, noop);
registerAction({
type: UNSELECT_ACTION_TYPE,
event: UNSELECT_ACTION_TYPE,
update: UNSELECT_ACTION_TYPE
}, noop);
registerAction({
type: TOGGLE_SELECT_ACTION_TYPE,
event: TOGGLE_SELECT_ACTION_TYPE,
update: TOGGLE_SELECT_ACTION_TYPE
}, noop);
// Default theme
registerTheme('light', lightTheme);
registerTheme('dark', darkTheme);
// For backward compatibility, where the namespace `dataTool` will
// be mounted on `echarts` is the extension `dataTool` is imported.
export var dataTool = {};