You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
42563 lines
1.6 MiB
42563 lines
1.6 MiB
(function (root, factory) {
|
|
if (typeof define === 'function' && define.amd) {
|
|
// AMD. Register as an anonymous module.
|
|
define([], factory);
|
|
} else if (typeof module === 'object' && module.exports) {
|
|
// Node. Does not work with strict CommonJS, but
|
|
// only CommonJS-like environments that support module.exports,
|
|
// like Node.
|
|
module.exports = factory();
|
|
} else {
|
|
// Browser globals (root is window)
|
|
root.echarts = factory();
|
|
}
|
|
}(this, function () {var require, define;
|
|
(function () {
|
|
var mods = {};
|
|
|
|
define = function (id, deps, factory) {
|
|
mods[id] = {
|
|
id: id,
|
|
deps: deps,
|
|
factory: factory,
|
|
defined: 0,
|
|
exports: {},
|
|
require: createRequire(id)
|
|
};
|
|
};
|
|
|
|
require = createRequire('');
|
|
|
|
function normalize(id, baseId) {
|
|
if (!baseId) {
|
|
return id;
|
|
}
|
|
|
|
if (id.indexOf('.') === 0) {
|
|
var basePath = baseId.split('/');
|
|
var namePath = id.split('/');
|
|
var baseLen = basePath.length - 1;
|
|
var nameLen = namePath.length;
|
|
var cutBaseTerms = 0;
|
|
var cutNameTerms = 0;
|
|
|
|
pathLoop: for (var i = 0; i < nameLen; i++) {
|
|
switch (namePath[i]) {
|
|
case '..':
|
|
if (cutBaseTerms < baseLen) {
|
|
cutBaseTerms++;
|
|
cutNameTerms++;
|
|
}
|
|
else {
|
|
break pathLoop;
|
|
}
|
|
break;
|
|
case '.':
|
|
cutNameTerms++;
|
|
break;
|
|
default:
|
|
break pathLoop;
|
|
}
|
|
}
|
|
|
|
basePath.length = baseLen - cutBaseTerms;
|
|
namePath = namePath.slice(cutNameTerms);
|
|
|
|
return basePath.concat(namePath).join('/');
|
|
}
|
|
|
|
return id;
|
|
}
|
|
|
|
function createRequire(baseId) {
|
|
var cacheMods = {};
|
|
|
|
function localRequire(id, callback) {
|
|
if (typeof id === 'string') {
|
|
var exports = cacheMods[id];
|
|
if (!exports) {
|
|
exports = getModExports(normalize(id, baseId));
|
|
cacheMods[id] = exports;
|
|
}
|
|
|
|
return exports;
|
|
}
|
|
else if (id instanceof Array) {
|
|
callback = callback || function () {};
|
|
callback.apply(this, getModsExports(id, callback, baseId));
|
|
}
|
|
};
|
|
|
|
return localRequire;
|
|
}
|
|
|
|
function getModsExports(ids, factory, baseId) {
|
|
var es = [];
|
|
var mod = mods[baseId];
|
|
|
|
for (var i = 0, l = Math.min(ids.length, factory.length); i < l; i++) {
|
|
var id = normalize(ids[i], baseId);
|
|
var arg;
|
|
switch (id) {
|
|
case 'require':
|
|
arg = (mod && mod.require) || require;
|
|
break;
|
|
case 'exports':
|
|
arg = mod.exports;
|
|
break;
|
|
case 'module':
|
|
arg = mod;
|
|
break;
|
|
default:
|
|
arg = getModExports(id);
|
|
}
|
|
es.push(arg);
|
|
}
|
|
|
|
return es;
|
|
}
|
|
|
|
function getModExports(id) {
|
|
var mod = mods[id];
|
|
if (!mod) {
|
|
throw new Error('No ' + id);
|
|
}
|
|
|
|
if (!mod.defined) {
|
|
var factory = mod.factory;
|
|
var factoryReturn = factory.apply(
|
|
this,
|
|
getModsExports(mod.deps || [], factory, id)
|
|
);
|
|
if (typeof factoryReturn !== 'undefined') {
|
|
mod.exports = factoryReturn;
|
|
}
|
|
mod.defined = 1;
|
|
}
|
|
|
|
return mod.exports;
|
|
}
|
|
}());
|
|
define('echarts/chart/bar', ['require', 'zrender/core/util', '../coord/cartesian/Grid', './bar/BarSeries', './bar/BarView', '../layout/barGrid', '../echarts', '../component/gridSimple'], function (require) {
|
|
var zrUtil = require('zrender/core/util');
|
|
require('../coord/cartesian/Grid');
|
|
require('./bar/BarSeries');
|
|
require('./bar/BarView');
|
|
var barLayoutGrid = require('../layout/barGrid');
|
|
var echarts = require('../echarts');
|
|
echarts.registerLayout(zrUtil.curry(barLayoutGrid, 'bar'));
|
|
// Visual coding for legend
|
|
echarts.registerVisual(function (ecModel) {
|
|
ecModel.eachSeriesByType('bar', function (seriesModel) {
|
|
var data = seriesModel.getData();
|
|
data.setVisual('legendSymbol', 'roundRect');
|
|
});
|
|
});
|
|
// In case developer forget to include grid component
|
|
require('../component/gridSimple');
|
|
});
|
|
define('echarts/chart/line', ['require', 'zrender/core/util', '../echarts', './line/LineSeries', './line/LineView', '../visual/symbol', '../layout/points', '../processor/dataSample', '../component/gridSimple'], function (require) {
|
|
var zrUtil = require('zrender/core/util');
|
|
var echarts = require('../echarts');
|
|
var PRIORITY = echarts.PRIORITY;
|
|
require('./line/LineSeries');
|
|
require('./line/LineView');
|
|
echarts.registerVisual(zrUtil.curry(require('../visual/symbol'), 'line', 'circle', 'line'));
|
|
echarts.registerLayout(zrUtil.curry(require('../layout/points'), 'line'));
|
|
// Down sample after filter
|
|
echarts.registerProcessor(PRIORITY.PROCESSOR.STATISTIC, zrUtil.curry(require('../processor/dataSample'), 'line'));
|
|
// In case developer forget to include grid component
|
|
require('../component/gridSimple');
|
|
});
|
|
define('echarts/chart/pie', ['require', 'zrender/core/util', '../echarts', './pie/PieSeries', './pie/PieView', '../action/createDataSelectAction', '../visual/dataColor', './pie/pieLayout', '../processor/dataFilter'], function (require) {
|
|
var zrUtil = require('zrender/core/util');
|
|
var echarts = require('../echarts');
|
|
require('./pie/PieSeries');
|
|
require('./pie/PieView');
|
|
require('../action/createDataSelectAction')('pie', [
|
|
{
|
|
type: 'pieToggleSelect',
|
|
event: 'pieselectchanged',
|
|
method: 'toggleSelected'
|
|
},
|
|
{
|
|
type: 'pieSelect',
|
|
event: 'pieselected',
|
|
method: 'select'
|
|
},
|
|
{
|
|
type: 'pieUnSelect',
|
|
event: 'pieunselected',
|
|
method: 'unSelect'
|
|
}
|
|
]);
|
|
echarts.registerVisual(zrUtil.curry(require('../visual/dataColor'), 'pie'));
|
|
echarts.registerLayout(zrUtil.curry(require('./pie/pieLayout'), 'pie'));
|
|
echarts.registerProcessor(zrUtil.curry(require('../processor/dataFilter'), 'pie'));
|
|
});
|
|
define('echarts/chart/scatter', ['require', 'zrender/core/util', '../echarts', './scatter/ScatterSeries', './scatter/ScatterView', '../visual/symbol', '../layout/points', '../component/gridSimple'], function (require) {
|
|
var zrUtil = require('zrender/core/util');
|
|
var echarts = require('../echarts');
|
|
require('./scatter/ScatterSeries');
|
|
require('./scatter/ScatterView');
|
|
echarts.registerVisual(zrUtil.curry(require('../visual/symbol'), 'scatter', 'circle', null));
|
|
echarts.registerLayout(zrUtil.curry(require('../layout/points'), 'scatter'));
|
|
// In case developer forget to include grid component
|
|
require('../component/gridSimple');
|
|
});
|
|
define('echarts/chart/radar', ['require', 'zrender/core/util', '../echarts', '../component/radar', './radar/RadarSeries', './radar/RadarView', '../visual/dataColor', '../visual/symbol', './radar/radarLayout', '../processor/dataFilter', './radar/backwardCompat'], function (require) {
|
|
var zrUtil = require('zrender/core/util');
|
|
var echarts = require('../echarts');
|
|
// Must use radar component
|
|
require('../component/radar');
|
|
require('./radar/RadarSeries');
|
|
require('./radar/RadarView');
|
|
echarts.registerVisual(zrUtil.curry(require('../visual/dataColor'), 'radar'));
|
|
echarts.registerVisual(zrUtil.curry(require('../visual/symbol'), 'radar', 'circle', null));
|
|
echarts.registerLayout(require('./radar/radarLayout'));
|
|
echarts.registerProcessor(zrUtil.curry(require('../processor/dataFilter'), 'radar'));
|
|
echarts.registerPreprocessor(require('./radar/backwardCompat'));
|
|
});
|
|
define('echarts/chart/candlestick', ['require', '../echarts', './candlestick/CandlestickSeries', './candlestick/CandlestickView', './candlestick/preprocessor', './candlestick/candlestickVisual', './candlestick/candlestickLayout'], function (require) {
|
|
var echarts = require('../echarts');
|
|
require('./candlestick/CandlestickSeries');
|
|
require('./candlestick/CandlestickView');
|
|
echarts.registerPreprocessor(require('./candlestick/preprocessor'));
|
|
echarts.registerVisual(require('./candlestick/candlestickVisual'));
|
|
echarts.registerLayout(require('./candlestick/candlestickLayout'));
|
|
});
|
|
define('echarts/chart/heatmap', ['require', './heatmap/HeatmapSeries', './heatmap/HeatmapView'], function (require) {
|
|
require('./heatmap/HeatmapSeries');
|
|
require('./heatmap/HeatmapView');
|
|
});
|
|
define('echarts/echarts', ['require', 'zrender/core/env', './model/Global', './ExtensionAPI', './CoordinateSystem', './model/OptionManager', './preprocessor/backwardCompat', './model/Component', './model/Series', './view/Component', './view/Chart', './util/graphic', './util/model', './util/throttle', 'zrender/zrender', 'zrender/core/util', 'zrender/tool/color', 'zrender/mixin/Eventful', 'zrender/core/timsort', './visual/seriesColor', './loading/default', './data/List', './model/Model', './coord/Axis', './util/number', './util/format', 'zrender/core/matrix', 'zrender/core/vector', './helper'], function (require) {
|
|
var env = require('zrender/core/env');
|
|
var GlobalModel = require('./model/Global');
|
|
var ExtensionAPI = require('./ExtensionAPI');
|
|
var CoordinateSystemManager = require('./CoordinateSystem');
|
|
var OptionManager = require('./model/OptionManager');
|
|
var backwardCompat = require('./preprocessor/backwardCompat');
|
|
var ComponentModel = require('./model/Component');
|
|
var SeriesModel = require('./model/Series');
|
|
var ComponentView = require('./view/Component');
|
|
var ChartView = require('./view/Chart');
|
|
var graphic = require('./util/graphic');
|
|
var modelUtil = require('./util/model');
|
|
var throttle = require('./util/throttle');
|
|
var zrender = require('zrender/zrender');
|
|
var zrUtil = require('zrender/core/util');
|
|
var colorTool = require('zrender/tool/color');
|
|
var Eventful = require('zrender/mixin/Eventful');
|
|
var timsort = require('zrender/core/timsort');
|
|
var each = zrUtil.each;
|
|
var parseClassType = ComponentModel.parseClassType;
|
|
var PRIORITY_PROCESSOR_FILTER = 1000;
|
|
var PRIORITY_PROCESSOR_STATISTIC = 5000;
|
|
var PRIORITY_VISUAL_LAYOUT = 1000;
|
|
var PRIORITY_VISUAL_GLOBAL = 2000;
|
|
var PRIORITY_VISUAL_CHART = 3000;
|
|
var PRIORITY_VISUAL_COMPONENT = 4000;
|
|
// FIXME
|
|
// necessary?
|
|
var PRIORITY_VISUAL_BRUSH = 5000;
|
|
// 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 = '__flagInMainProcess';
|
|
var HAS_GRADIENT_OR_PATTERN_BG = '__hasGradientOrPatternBg';
|
|
var OPTION_UPDATED = '__optionUpdated';
|
|
var ACTION_REG = /^[a-zA-Z0-9_]+$/;
|
|
function createRegisterEventWithLowercaseName(method) {
|
|
return function (eventName, handler, context) {
|
|
// Event name is all lowercase
|
|
eventName = eventName && eventName.toLowerCase();
|
|
Eventful.prototype[method].call(this, eventName, handler, context);
|
|
};
|
|
}
|
|
/**
|
|
* @module echarts~MessageCenter
|
|
*/
|
|
function MessageCenter() {
|
|
Eventful.call(this);
|
|
}
|
|
MessageCenter.prototype.on = createRegisterEventWithLowercaseName('on');
|
|
MessageCenter.prototype.off = createRegisterEventWithLowercaseName('off');
|
|
MessageCenter.prototype.one = createRegisterEventWithLowercaseName('one');
|
|
zrUtil.mixin(MessageCenter, Eventful);
|
|
/**
|
|
* @module echarts~ECharts
|
|
*/
|
|
function ECharts(dom, theme, opts) {
|
|
opts = opts || {};
|
|
// Get theme by name
|
|
if (typeof theme === 'string') {
|
|
theme = themeStorage[theme];
|
|
}
|
|
/**
|
|
* @type {string}
|
|
*/
|
|
this.id;
|
|
/**
|
|
* Group id
|
|
* @type {string}
|
|
*/
|
|
this.group;
|
|
/**
|
|
* @type {HTMLElement}
|
|
* @private
|
|
*/
|
|
this._dom = dom;
|
|
/**
|
|
* @type {module:zrender/ZRender}
|
|
* @private
|
|
*/
|
|
var zr = this._zr = zrender.init(dom, {
|
|
renderer: opts.renderer || 'canvas',
|
|
devicePixelRatio: opts.devicePixelRatio,
|
|
width: opts.width,
|
|
height: opts.height
|
|
});
|
|
/**
|
|
* Expect 60 pfs.
|
|
* @type {Function}
|
|
* @private
|
|
*/
|
|
this._throttledZrFlush = throttle.throttle(zrUtil.bind(zr.flush, zr), 17);
|
|
var theme = zrUtil.clone(theme);
|
|
theme && backwardCompat(theme, true);
|
|
/**
|
|
* @type {Object}
|
|
* @private
|
|
*/
|
|
this._theme = theme;
|
|
/**
|
|
* @type {Array.<module:echarts/view/Chart>}
|
|
* @private
|
|
*/
|
|
this._chartsViews = [];
|
|
/**
|
|
* @type {Object.<string, module:echarts/view/Chart>}
|
|
* @private
|
|
*/
|
|
this._chartsMap = {};
|
|
/**
|
|
* @type {Array.<module:echarts/view/Component>}
|
|
* @private
|
|
*/
|
|
this._componentsViews = [];
|
|
/**
|
|
* @type {Object.<string, module:echarts/view/Component>}
|
|
* @private
|
|
*/
|
|
this._componentsMap = {};
|
|
/**
|
|
* @type {module:echarts/CoordinateSystem}
|
|
* @private
|
|
*/
|
|
this._coordSysMgr = new CoordinateSystemManager();
|
|
/**
|
|
* @type {module:echarts/ExtensionAPI}
|
|
* @private
|
|
*/
|
|
this._api = createExtensionAPI(this);
|
|
Eventful.call(this);
|
|
/**
|
|
* @type {module:echarts~MessageCenter}
|
|
* @private
|
|
*/
|
|
this._messageCenter = new MessageCenter();
|
|
// Init mouse events
|
|
this._initEvents();
|
|
// In case some people write `window.onresize = chart.resize`
|
|
this.resize = zrUtil.bind(this.resize, this);
|
|
// Can't dispatch action during rendering procedure
|
|
this._pendingActions = [];
|
|
// Sort on demand
|
|
function prioritySortFunc(a, b) {
|
|
return a.prio - b.prio;
|
|
}
|
|
timsort(visualFuncs, prioritySortFunc);
|
|
timsort(dataProcessorFuncs, prioritySortFunc);
|
|
zr.animation.on('frame', this._onframe, this);
|
|
// ECharts instance can be used as value.
|
|
zrUtil.setAsPrimitive(this);
|
|
}
|
|
var echartsProto = ECharts.prototype;
|
|
echartsProto._onframe = function () {
|
|
// Lazy update
|
|
if (this[OPTION_UPDATED]) {
|
|
var silent = this[OPTION_UPDATED].silent;
|
|
this[IN_MAIN_PROCESS] = true;
|
|
updateMethods.prepareAndUpdate.call(this);
|
|
this[IN_MAIN_PROCESS] = false;
|
|
this[OPTION_UPDATED] = false;
|
|
flushPendingActions.call(this, silent);
|
|
triggerUpdatedEvent.call(this, silent);
|
|
}
|
|
};
|
|
/**
|
|
* @return {HTMLElement}
|
|
*/
|
|
echartsProto.getDom = function () {
|
|
return this._dom;
|
|
};
|
|
/**
|
|
* @return {module:zrender~ZRender}
|
|
*/
|
|
echartsProto.getZr = function () {
|
|
return this._zr;
|
|
};
|
|
/**
|
|
* Usage:
|
|
* chart.setOption(option, notMerge, lazyUpdate);
|
|
* chart.setOption(option, {
|
|
* notMerge: ...,
|
|
* lazyUpdate: ...,
|
|
* silent: ...
|
|
* });
|
|
*
|
|
* @param {Object} option
|
|
* @param {Object|boolean} [opts] opts or notMerge.
|
|
* @param {boolean} [opts.notMerge=false]
|
|
* @param {boolean} [opts.lazyUpdate=false] Useful when setOption frequently.
|
|
*/
|
|
echartsProto.setOption = function (option, notMerge, lazyUpdate) {
|
|
if (true) {
|
|
zrUtil.assert(!this[IN_MAIN_PROCESS], '`setOption` should not be called during main process.');
|
|
}
|
|
var silent;
|
|
if (zrUtil.isObject(notMerge)) {
|
|
lazyUpdate = notMerge.lazyUpdate;
|
|
silent = notMerge.silent;
|
|
notMerge = notMerge.notMerge;
|
|
}
|
|
this[IN_MAIN_PROCESS] = true;
|
|
if (!this._model || notMerge) {
|
|
var optionManager = new OptionManager(this._api);
|
|
var theme = this._theme;
|
|
var ecModel = this._model = new GlobalModel(null, null, theme, optionManager);
|
|
ecModel.init(null, null, theme, optionManager);
|
|
}
|
|
this._model.setOption(option, optionPreprocessorFuncs);
|
|
if (lazyUpdate) {
|
|
this[OPTION_UPDATED] = { silent: silent };
|
|
this[IN_MAIN_PROCESS] = false;
|
|
} else {
|
|
updateMethods.prepareAndUpdate.call(this);
|
|
// Ensure zr refresh sychronously, and then pixel in canvas can be
|
|
// fetched after `setOption`.
|
|
this._zr.flush();
|
|
this[OPTION_UPDATED] = false;
|
|
this[IN_MAIN_PROCESS] = false;
|
|
flushPendingActions.call(this, silent);
|
|
triggerUpdatedEvent.call(this, silent);
|
|
}
|
|
};
|
|
/**
|
|
* @DEPRECATED
|
|
*/
|
|
echartsProto.setTheme = function () {
|
|
console.log('ECharts#setTheme() is DEPRECATED in ECharts 3.0');
|
|
};
|
|
/**
|
|
* @return {module:echarts/model/Global}
|
|
*/
|
|
echartsProto.getModel = function () {
|
|
return this._model;
|
|
};
|
|
/**
|
|
* @return {Object}
|
|
*/
|
|
echartsProto.getOption = function () {
|
|
return this._model && this._model.getOption();
|
|
};
|
|
/**
|
|
* @return {number}
|
|
*/
|
|
echartsProto.getWidth = function () {
|
|
return this._zr.getWidth();
|
|
};
|
|
/**
|
|
* @return {number}
|
|
*/
|
|
echartsProto.getHeight = function () {
|
|
return this._zr.getHeight();
|
|
};
|
|
/**
|
|
* @return {number}
|
|
*/
|
|
echartsProto.getDevicePixelRatio = function () {
|
|
return this._zr.painter.dpr || window.devicePixelRatio || 1;
|
|
};
|
|
/**
|
|
* Get canvas which has all thing rendered
|
|
* @param {Object} opts
|
|
* @param {string} [opts.backgroundColor]
|
|
*/
|
|
echartsProto.getRenderedCanvas = function (opts) {
|
|
if (!env.canvasSupported) {
|
|
return;
|
|
}
|
|
opts = opts || {};
|
|
opts.pixelRatio = opts.pixelRatio || 1;
|
|
opts.backgroundColor = opts.backgroundColor || this._model.get('backgroundColor');
|
|
var zr = this._zr;
|
|
var list = zr.storage.getDisplayList();
|
|
// Stop animations
|
|
zrUtil.each(list, function (el) {
|
|
el.stopAnimation(true);
|
|
});
|
|
return zr.painter.getRenderedCanvas(opts);
|
|
};
|
|
/**
|
|
* @return {string}
|
|
* @param {Object} opts
|
|
* @param {string} [opts.type='png']
|
|
* @param {string} [opts.pixelRatio=1]
|
|
* @param {string} [opts.backgroundColor]
|
|
* @param {string} [opts.excludeComponents]
|
|
*/
|
|
echartsProto.getDataURL = function (opts) {
|
|
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.getRenderedCanvas(opts).toDataURL('image/' + (opts && opts.type || 'png'));
|
|
each(excludesComponentViews, function (view) {
|
|
view.group.ignore = false;
|
|
});
|
|
return url;
|
|
};
|
|
/**
|
|
* @return {string}
|
|
* @param {Object} opts
|
|
* @param {string} [opts.type='png']
|
|
* @param {string} [opts.pixelRatio=1]
|
|
* @param {string} [opts.backgroundColor]
|
|
*/
|
|
echartsProto.getConnectedDataURL = function (opts) {
|
|
if (!env.canvasSupported) {
|
|
return;
|
|
}
|
|
var groupId = this.group;
|
|
var mathMin = Math.min;
|
|
var mathMax = Math.max;
|
|
var MAX_NUMBER = Infinity;
|
|
if (connectedGroups[groupId]) {
|
|
var left = MAX_NUMBER;
|
|
var top = MAX_NUMBER;
|
|
var right = -MAX_NUMBER;
|
|
var bottom = -MAX_NUMBER;
|
|
var canvasList = [];
|
|
var dpr = opts && opts.pixelRatio || 1;
|
|
zrUtil.each(instances, function (chart, id) {
|
|
if (chart.group === groupId) {
|
|
var canvas = chart.getRenderedCanvas(zrUtil.clone(opts));
|
|
var boundingRect = chart.getDom().getBoundingClientRect();
|
|
left = mathMin(boundingRect.left, left);
|
|
top = mathMin(boundingRect.top, top);
|
|
right = mathMax(boundingRect.right, right);
|
|
bottom = mathMax(boundingRect.bottom, bottom);
|
|
canvasList.push({
|
|
dom: canvas,
|
|
left: boundingRect.left,
|
|
top: boundingRect.top
|
|
});
|
|
}
|
|
});
|
|
left *= dpr;
|
|
top *= dpr;
|
|
right *= dpr;
|
|
bottom *= dpr;
|
|
var width = right - left;
|
|
var height = bottom - top;
|
|
var targetCanvas = zrUtil.createCanvas();
|
|
targetCanvas.width = width;
|
|
targetCanvas.height = height;
|
|
var zr = zrender.init(targetCanvas);
|
|
each(canvasList, function (item) {
|
|
var img = new graphic.Image({
|
|
style: {
|
|
x: item.left * dpr - left,
|
|
y: item.top * dpr - top,
|
|
image: item.dom
|
|
}
|
|
});
|
|
zr.add(img);
|
|
});
|
|
zr.refreshImmediately();
|
|
return targetCanvas.toDataURL('image/' + (opts && opts.type || 'png'));
|
|
} else {
|
|
return this.getDataURL(opts);
|
|
}
|
|
};
|
|
/**
|
|
* Convert from logical coordinate system to pixel coordinate system.
|
|
* See CoordinateSystem#convertToPixel.
|
|
* @param {string|Object} finder
|
|
* If string, e.g., 'geo', means {geoIndex: 0}.
|
|
* If Object, could contain some of these properties below:
|
|
* {
|
|
* seriesIndex / seriesId / seriesName,
|
|
* geoIndex / geoId, geoName,
|
|
* bmapIndex / bmapId / bmapName,
|
|
* xAxisIndex / xAxisId / xAxisName,
|
|
* yAxisIndex / yAxisId / yAxisName,
|
|
* gridIndex / gridId / gridName,
|
|
* ... (can be extended)
|
|
* }
|
|
* @param {Array|number} value
|
|
* @return {Array|number} result
|
|
*/
|
|
echartsProto.convertToPixel = zrUtil.curry(doConvertPixel, 'convertToPixel');
|
|
/**
|
|
* Convert from pixel coordinate system to logical coordinate system.
|
|
* See CoordinateSystem#convertFromPixel.
|
|
* @param {string|Object} finder
|
|
* If string, e.g., 'geo', means {geoIndex: 0}.
|
|
* If Object, could contain some of these properties below:
|
|
* {
|
|
* seriesIndex / seriesId / seriesName,
|
|
* geoIndex / geoId / geoName,
|
|
* bmapIndex / bmapId / bmapName,
|
|
* xAxisIndex / xAxisId / xAxisName,
|
|
* yAxisIndex / yAxisId / yAxisName
|
|
* gridIndex / gridId / gridName,
|
|
* ... (can be extended)
|
|
* }
|
|
* @param {Array|number} value
|
|
* @return {Array|number} result
|
|
*/
|
|
echartsProto.convertFromPixel = zrUtil.curry(doConvertPixel, 'convertFromPixel');
|
|
function doConvertPixel(methodName, finder, value) {
|
|
var ecModel = this._model;
|
|
var coordSysList = this._coordSysMgr.getCoordinateSystems();
|
|
var result;
|
|
finder = modelUtil.parseFinder(ecModel, finder);
|
|
for (var i = 0; i < coordSysList.length; i++) {
|
|
var coordSys = coordSysList[i];
|
|
if (coordSys[methodName] && (result = coordSys[methodName](ecModel, finder, value)) != null) {
|
|
return result;
|
|
}
|
|
}
|
|
if (true) {
|
|
console.warn('No coordinate system that supports ' + methodName + ' found by the given finder.');
|
|
}
|
|
}
|
|
/**
|
|
* Is the specified coordinate systems or components contain the given pixel point.
|
|
* @param {string|Object} finder
|
|
* If string, e.g., 'geo', means {geoIndex: 0}.
|
|
* If Object, could contain some of these properties below:
|
|
* {
|
|
* seriesIndex / seriesId / seriesName,
|
|
* geoIndex / geoId / geoName,
|
|
* bmapIndex / bmapId / bmapName,
|
|
* xAxisIndex / xAxisId / xAxisName,
|
|
* yAxisIndex / yAxisId / yAxisName,
|
|
* gridIndex / gridId / gridName,
|
|
* ... (can be extended)
|
|
* }
|
|
* @param {Array|number} value
|
|
* @return {boolean} result
|
|
*/
|
|
echartsProto.containPixel = function (finder, value) {
|
|
var ecModel = this._model;
|
|
var result;
|
|
finder = modelUtil.parseFinder(ecModel, finder);
|
|
zrUtil.each(finder, function (models, key) {
|
|
key.indexOf('Models') >= 0 && zrUtil.each(models, function (model) {
|
|
var coordSys = model.coordinateSystem;
|
|
if (coordSys && coordSys.containPoint) {
|
|
result |= !!coordSys.containPoint(value);
|
|
} else if (key === 'seriesModels') {
|
|
var view = this._chartsMap[model.__viewId];
|
|
if (view && view.containPoint) {
|
|
result |= view.containPoint(value, model);
|
|
} else {
|
|
if (true) {
|
|
console.warn(key + ': ' + (view ? 'The found component do not support containPoint.' : 'No view mapping to the found component.'));
|
|
}
|
|
}
|
|
} else {
|
|
if (true) {
|
|
console.warn(key + ': containPoint is not supported');
|
|
}
|
|
}
|
|
}, this);
|
|
}, this);
|
|
return !!result;
|
|
};
|
|
/**
|
|
* Get visual from series or data.
|
|
* @param {string|Object} 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 {string} visualType 'color', 'symbol', 'symbolSize'
|
|
*/
|
|
echartsProto.getVisual = function (finder, visualType) {
|
|
var ecModel = this._model;
|
|
finder = modelUtil.parseFinder(ecModel, finder, { defaultMainType: 'series' });
|
|
var seriesModel = finder.seriesModel;
|
|
if (true) {
|
|
if (!seriesModel) {
|
|
console.warn('There is no specified seires model');
|
|
}
|
|
}
|
|
var data = seriesModel.getData();
|
|
var dataIndexInside = finder.hasOwnProperty('dataIndexInside') ? finder.dataIndexInside : finder.hasOwnProperty('dataIndex') ? data.indexOfRawIndex(finder.dataIndex) : null;
|
|
return dataIndexInside != null ? data.getItemVisual(dataIndexInside, visualType) : data.getVisual(visualType);
|
|
};
|
|
/**
|
|
* Get view of corresponding component model
|
|
* @param {module:echarts/model/Component} componentModel
|
|
* @return {module:echarts/view/Component}
|
|
*/
|
|
echartsProto.getViewOfComponentModel = function (componentModel) {
|
|
return this._componentsMap[componentModel.__viewId];
|
|
};
|
|
/**
|
|
* Get view of corresponding series model
|
|
* @param {module:echarts/model/Series} seriesModel
|
|
* @return {module:echarts/view/Chart}
|
|
*/
|
|
echartsProto.getViewOfSeriesModel = function (seriesModel) {
|
|
return this._chartsMap[seriesModel.__viewId];
|
|
};
|
|
var updateMethods = {
|
|
update: function (payload) {
|
|
// console.profile && console.profile('update');
|
|
var ecModel = this._model;
|
|
var api = this._api;
|
|
var coordSysMgr = this._coordSysMgr;
|
|
var zr = this._zr;
|
|
// update before setOption
|
|
if (!ecModel) {
|
|
return;
|
|
}
|
|
// Fixme First time update ?
|
|
ecModel.restoreData();
|
|
// 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 orignal point
|
|
coordSysMgr.create(this._model, this._api);
|
|
processData.call(this, ecModel, api);
|
|
stackSeriesData.call(this, ecModel);
|
|
coordSysMgr.update(ecModel, api);
|
|
doVisualEncoding.call(this, ecModel, payload);
|
|
doRender.call(this, ecModel, payload);
|
|
// Set background
|
|
var backgroundColor = ecModel.get('backgroundColor') || 'transparent';
|
|
var painter = zr.painter;
|
|
// TODO all use clearColor ?
|
|
if (painter.isSingleCanvas && painter.isSingleCanvas()) {
|
|
zr.configLayer(0, { clearColor: backgroundColor });
|
|
} else {
|
|
// In IE8
|
|
if (!env.canvasSupported) {
|
|
var colorArr = colorTool.parse(backgroundColor);
|
|
backgroundColor = colorTool.stringify(colorArr, 'rgb');
|
|
if (colorArr[3] === 0) {
|
|
backgroundColor = 'transparent';
|
|
}
|
|
}
|
|
if (backgroundColor.colorStops || backgroundColor.image) {
|
|
// Gradient background
|
|
// FIXME Fixed layer?
|
|
zr.configLayer(0, { clearColor: backgroundColor });
|
|
this[HAS_GRADIENT_OR_PATTERN_BG] = true;
|
|
this._dom.style.background = 'transparent';
|
|
} else {
|
|
if (this[HAS_GRADIENT_OR_PATTERN_BG]) {
|
|
zr.configLayer(0, { clearColor: null });
|
|
}
|
|
this[HAS_GRADIENT_OR_PATTERN_BG] = false;
|
|
this._dom.style.background = backgroundColor;
|
|
}
|
|
}
|
|
each(postUpdateFuncs, function (func) {
|
|
func(ecModel, api);
|
|
}); // console.profile && console.profileEnd('update');
|
|
},
|
|
updateView: function (payload) {
|
|
var ecModel = this._model;
|
|
// update before setOption
|
|
if (!ecModel) {
|
|
return;
|
|
}
|
|
ecModel.eachSeries(function (seriesModel) {
|
|
seriesModel.getData().clearAllVisual();
|
|
});
|
|
doVisualEncoding.call(this, ecModel, payload);
|
|
invokeUpdateMethod.call(this, 'updateView', ecModel, payload);
|
|
},
|
|
updateVisual: function (payload) {
|
|
var ecModel = this._model;
|
|
// update before setOption
|
|
if (!ecModel) {
|
|
return;
|
|
}
|
|
ecModel.eachSeries(function (seriesModel) {
|
|
seriesModel.getData().clearAllVisual();
|
|
});
|
|
doVisualEncoding.call(this, ecModel, payload, true);
|
|
invokeUpdateMethod.call(this, 'updateVisual', ecModel, payload);
|
|
},
|
|
updateLayout: function (payload) {
|
|
var ecModel = this._model;
|
|
// update before setOption
|
|
if (!ecModel) {
|
|
return;
|
|
}
|
|
doLayout.call(this, ecModel, payload);
|
|
invokeUpdateMethod.call(this, 'updateLayout', ecModel, payload);
|
|
},
|
|
prepareAndUpdate: function (payload) {
|
|
var ecModel = this._model;
|
|
prepareView.call(this, 'component', ecModel);
|
|
prepareView.call(this, 'chart', ecModel);
|
|
updateMethods.update.call(this, payload);
|
|
}
|
|
};
|
|
/**
|
|
* @private
|
|
*/
|
|
function updateDirectly(ecIns, method, payload, mainType, subType) {
|
|
var ecModel = ecIns._model;
|
|
// broadcast
|
|
if (!mainType) {
|
|
each(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;
|
|
// If dispatchAction before setOption, do nothing.
|
|
ecModel && ecModel.eachComponent(condition, function (model, index) {
|
|
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);
|
|
}
|
|
}
|
|
/**
|
|
* Resize the chart
|
|
* @param {Object} opts
|
|
* @param {number} [opts.width] Can be 'auto' (the same as null/undefined)
|
|
* @param {number} [opts.height] Can be 'auto' (the same as null/undefined)
|
|
* @param {boolean} [opts.silent=false]
|
|
*/
|
|
echartsProto.resize = function (opts) {
|
|
if (true) {
|
|
zrUtil.assert(!this[IN_MAIN_PROCESS], '`resize` should not be called during main process.');
|
|
}
|
|
this[IN_MAIN_PROCESS] = true;
|
|
this._zr.resize(opts);
|
|
var optionChanged = this._model && this._model.resetOption('media');
|
|
var updateMethod = optionChanged ? 'prepareAndUpdate' : 'update';
|
|
updateMethods[updateMethod].call(this);
|
|
// Resize loading effect
|
|
this._loadingFX && this._loadingFX.resize();
|
|
this[IN_MAIN_PROCESS] = false;
|
|
var silent = opts && opts.silent;
|
|
flushPendingActions.call(this, silent);
|
|
triggerUpdatedEvent.call(this, silent);
|
|
};
|
|
/**
|
|
* Show loading effect
|
|
* @param {string} [name='default']
|
|
* @param {Object} [cfg]
|
|
*/
|
|
echartsProto.showLoading = function (name, cfg) {
|
|
if (zrUtil.isObject(name)) {
|
|
cfg = name;
|
|
name = '';
|
|
}
|
|
name = name || 'default';
|
|
this.hideLoading();
|
|
if (!loadingEffects[name]) {
|
|
if (true) {
|
|
console.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
|
|
*/
|
|
echartsProto.hideLoading = function () {
|
|
this._loadingFX && this._zr.remove(this._loadingFX);
|
|
this._loadingFX = null;
|
|
};
|
|
/**
|
|
* @param {Object} eventObj
|
|
* @return {Object}
|
|
*/
|
|
echartsProto.makeActionFromEvent = function (eventObj) {
|
|
var payload = zrUtil.extend({}, eventObj);
|
|
payload.type = eventActionMap[eventObj.type];
|
|
return payload;
|
|
};
|
|
/**
|
|
* @pubilc
|
|
* @param {Object} payload
|
|
* @param {string} [payload.type] Action type
|
|
* @param {Object|boolean} [opt] If pass boolean, means opt.silent
|
|
* @param {boolean} [opt.silent=false] Whether trigger events.
|
|
* @param {boolean} [opt.flush=undefined]
|
|
* true: Flush immediately, and then pixel in canvas can be fetched
|
|
* immediately. Caution: it might affect performance.
|
|
* false: Not not flush.
|
|
* undefined: Auto decide whether perform flush.
|
|
*/
|
|
echartsProto.dispatchAction = function (payload, opt) {
|
|
if (!zrUtil.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]) {
|
|
this._pendingActions.push(payload);
|
|
return;
|
|
}
|
|
doDispatchAction.call(this, payload, opt.silent);
|
|
if (opt.flush) {
|
|
this._zr.flush(true);
|
|
} else if (opt.flush !== false && env.browser.weChat) {
|
|
// In WeChat embeded browser, `requestAnimationFrame` and `setInterval`
|
|
// hang when sliding page (on touch event), which cause that zr does not
|
|
// refresh util 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, opt.silent);
|
|
triggerUpdatedEvent.call(this, opt.silent);
|
|
};
|
|
function doDispatchAction(payload, silent) {
|
|
var payloadType = payload.type;
|
|
var escapeConnect = payload.escapeConnect;
|
|
var actionWrap = actions[payloadType];
|
|
var actionInfo = actionWrap.actionInfo;
|
|
var cptType = (actionInfo.update || 'update').split(':');
|
|
var updateMethod = cptType.pop();
|
|
cptType = cptType[0] != null && parseClassType(cptType[0]);
|
|
this[IN_MAIN_PROCESS] = true;
|
|
var payloads = [payload];
|
|
var batched = false;
|
|
// Batch action
|
|
if (payload.batch) {
|
|
batched = true;
|
|
payloads = zrUtil.map(payload.batch, function (item) {
|
|
item = zrUtil.defaults(zrUtil.extend({}, item), payload);
|
|
item.batch = null;
|
|
return item;
|
|
});
|
|
}
|
|
var eventObjBatch = [];
|
|
var eventObj;
|
|
var isHighDown = payloadType === 'highlight' || payloadType === 'downplay';
|
|
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 || zrUtil.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) {
|
|
// method, payload, mainType, subType
|
|
updateDirectly(this, updateMethod, batchItem, 'series');
|
|
} else if (cptType) {
|
|
updateDirectly(this, updateMethod, batchItem, cptType.main, cptType.sub);
|
|
}
|
|
}, this);
|
|
if (updateMethod !== 'none' && !isHighDown && !cptType) {
|
|
// Still dirty
|
|
if (this[OPTION_UPDATED]) {
|
|
// FIXME Pass payload ?
|
|
updateMethods.prepareAndUpdate.call(this, payload);
|
|
this[OPTION_UPDATED] = false;
|
|
} else {
|
|
updateMethods[updateMethod].call(this, payload);
|
|
}
|
|
}
|
|
// 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] = false;
|
|
!silent && this._messageCenter.trigger(eventObj.type, eventObj);
|
|
}
|
|
function flushPendingActions(silent) {
|
|
var pendingActions = this._pendingActions;
|
|
while (pendingActions.length) {
|
|
var payload = pendingActions.shift();
|
|
doDispatchAction.call(this, payload, silent);
|
|
}
|
|
}
|
|
function triggerUpdatedEvent(silent) {
|
|
!silent && this.trigger('updated');
|
|
}
|
|
/**
|
|
* Register event
|
|
* @method
|
|
*/
|
|
echartsProto.on = createRegisterEventWithLowercaseName('on');
|
|
echartsProto.off = createRegisterEventWithLowercaseName('off');
|
|
echartsProto.one = createRegisterEventWithLowercaseName('one');
|
|
/**
|
|
* @param {string} methodName
|
|
* @private
|
|
*/
|
|
function invokeUpdateMethod(methodName, ecModel, payload) {
|
|
var api = this._api;
|
|
// Update all components
|
|
each(this._componentsViews, function (component) {
|
|
var componentModel = component.__model;
|
|
component[methodName](componentModel, ecModel, api, payload);
|
|
updateZ(componentModel, component);
|
|
}, this);
|
|
// Upate all charts
|
|
ecModel.eachSeries(function (seriesModel, idx) {
|
|
var chart = this._chartsMap[seriesModel.__viewId];
|
|
chart[methodName](seriesModel, ecModel, api, payload);
|
|
updateZ(seriesModel, chart);
|
|
updateProgressiveAndBlend(seriesModel, chart);
|
|
}, this);
|
|
// If use hover layer
|
|
updateHoverLayerStatus(this._zr, ecModel);
|
|
// Post render
|
|
each(postUpdateFuncs, function (func) {
|
|
func(ecModel, api);
|
|
});
|
|
}
|
|
/**
|
|
* Prepare view instances of charts and components
|
|
* @param {module:echarts/model/Global} ecModel
|
|
* @private
|
|
*/
|
|
function prepareView(type, ecModel) {
|
|
var isComponent = type === 'component';
|
|
var viewList = isComponent ? this._componentsViews : this._chartsViews;
|
|
var viewMap = isComponent ? this._componentsMap : this._chartsMap;
|
|
var zr = this._zr;
|
|
for (var i = 0; i < viewList.length; i++) {
|
|
viewList[i].__alive = false;
|
|
}
|
|
ecModel[isComponent ? 'eachComponent' : 'eachSeries'](function (componentType, model) {
|
|
if (isComponent) {
|
|
if (componentType === 'series') {
|
|
return;
|
|
}
|
|
} else {
|
|
model = componentType;
|
|
}
|
|
// Consider: id same and type changed.
|
|
var viewId = '_ec_' + model.id + '_' + model.type;
|
|
var view = viewMap[viewId];
|
|
if (!view) {
|
|
var classType = parseClassType(model.type);
|
|
var Clazz = isComponent ? ComponentView.getClass(classType.main, classType.sub) : ChartView.getClass(classType.sub);
|
|
if (Clazz) {
|
|
view = new Clazz();
|
|
view.init(ecModel, this._api);
|
|
viewMap[viewId] = view;
|
|
viewList.push(view);
|
|
zr.add(view.group);
|
|
} else {
|
|
// Error
|
|
return;
|
|
}
|
|
}
|
|
model.__viewId = view.__id = viewId;
|
|
view.__alive = true;
|
|
view.__model = model;
|
|
view.group.__ecComponentInfo = {
|
|
mainType: model.mainType,
|
|
index: model.componentIndex
|
|
};
|
|
}, this);
|
|
for (var i = 0; i < viewList.length;) {
|
|
var view = viewList[i];
|
|
if (!view.__alive) {
|
|
zr.remove(view.group);
|
|
view.dispose(ecModel, this._api);
|
|
viewList.splice(i, 1);
|
|
delete viewMap[view.__id];
|
|
view.__id = view.group.__ecComponentInfo = null;
|
|
} else {
|
|
i++;
|
|
}
|
|
}
|
|
}
|
|
/**
|
|
* Processor data in each series
|
|
*
|
|
* @param {module:echarts/model/Global} ecModel
|
|
* @private
|
|
*/
|
|
function processData(ecModel, api) {
|
|
each(dataProcessorFuncs, function (process) {
|
|
process.func(ecModel, api);
|
|
});
|
|
}
|
|
/**
|
|
* @private
|
|
*/
|
|
function stackSeriesData(ecModel) {
|
|
var stackedDataMap = {};
|
|
ecModel.eachSeries(function (series) {
|
|
var stack = series.get('stack');
|
|
var data = series.getData();
|
|
if (stack && data.type === 'list') {
|
|
var previousStack = stackedDataMap[stack];
|
|
// Avoid conflict with Object.prototype
|
|
if (stackedDataMap.hasOwnProperty(stack) && previousStack) {
|
|
data.stackedOn = previousStack;
|
|
}
|
|
stackedDataMap[stack] = data;
|
|
}
|
|
});
|
|
}
|
|
/**
|
|
* Layout before each chart render there series, special visual encoding stage
|
|
*
|
|
* @param {module:echarts/model/Global} ecModel
|
|
* @private
|
|
*/
|
|
function doLayout(ecModel, payload) {
|
|
var api = this._api;
|
|
each(visualFuncs, function (visual) {
|
|
if (visual.isLayout) {
|
|
visual.func(ecModel, api, payload);
|
|
}
|
|
});
|
|
}
|
|
/**
|
|
* Encode visual infomation from data after data processing
|
|
*
|
|
* @param {module:echarts/model/Global} ecModel
|
|
* @param {object} layout
|
|
* @param {boolean} [excludesLayout]
|
|
* @private
|
|
*/
|
|
function doVisualEncoding(ecModel, payload, excludesLayout) {
|
|
var api = this._api;
|
|
ecModel.clearColorPalette();
|
|
ecModel.eachSeries(function (seriesModel) {
|
|
seriesModel.clearColorPalette();
|
|
});
|
|
each(visualFuncs, function (visual) {
|
|
(!excludesLayout || !visual.isLayout) && visual.func(ecModel, api, payload);
|
|
});
|
|
}
|
|
/**
|
|
* Render each chart and component
|
|
* @private
|
|
*/
|
|
function doRender(ecModel, payload) {
|
|
var api = this._api;
|
|
// Render all components
|
|
each(this._componentsViews, function (componentView) {
|
|
var componentModel = componentView.__model;
|
|
componentView.render(componentModel, ecModel, api, payload);
|
|
updateZ(componentModel, componentView);
|
|
}, this);
|
|
each(this._chartsViews, function (chart) {
|
|
chart.__alive = false;
|
|
}, this);
|
|
// Render all charts
|
|
ecModel.eachSeries(function (seriesModel, idx) {
|
|
var chartView = this._chartsMap[seriesModel.__viewId];
|
|
chartView.__alive = true;
|
|
chartView.render(seriesModel, ecModel, api, payload);
|
|
chartView.group.silent = !!seriesModel.get('silent');
|
|
updateZ(seriesModel, chartView);
|
|
updateProgressiveAndBlend(seriesModel, chartView);
|
|
}, this);
|
|
// If use hover layer
|
|
updateHoverLayerStatus(this._zr, ecModel);
|
|
// Remove groups of unrendered charts
|
|
each(this._chartsViews, function (chart) {
|
|
if (!chart.__alive) {
|
|
chart.remove(ecModel, api);
|
|
}
|
|
}, this);
|
|
}
|
|
var MOUSE_EVENT_NAMES = [
|
|
'click',
|
|
'dblclick',
|
|
'mouseover',
|
|
'mouseout',
|
|
'mousemove',
|
|
'mousedown',
|
|
'mouseup',
|
|
'globalout',
|
|
'contextmenu'
|
|
];
|
|
/**
|
|
* @private
|
|
*/
|
|
echartsProto._initEvents = function () {
|
|
each(MOUSE_EVENT_NAMES, function (eveName) {
|
|
this._zr.on(eveName, function (e) {
|
|
var ecModel = this.getModel();
|
|
var el = e.target;
|
|
var params;
|
|
// no e.target when 'globalout'.
|
|
if (eveName === 'globalout') {
|
|
params = {};
|
|
} else if (el && el.dataIndex != null) {
|
|
var dataModel = el.dataModel || ecModel.getSeriesByIndex(el.seriesIndex);
|
|
params = dataModel && dataModel.getDataParams(el.dataIndex, el.dataType) || {};
|
|
} // If element has custom eventData of components
|
|
else if (el && el.eventData) {
|
|
params = zrUtil.extend({}, el.eventData);
|
|
}
|
|
if (params) {
|
|
params.event = e;
|
|
params.type = eveName;
|
|
this.trigger(eveName, params);
|
|
}
|
|
}, this);
|
|
}, this);
|
|
each(eventActionMap, function (actionType, eventType) {
|
|
this._messageCenter.on(eventType, function (event) {
|
|
this.trigger(eventType, event);
|
|
}, this);
|
|
}, this);
|
|
};
|
|
/**
|
|
* @return {boolean}
|
|
*/
|
|
echartsProto.isDisposed = function () {
|
|
return this._disposed;
|
|
};
|
|
/**
|
|
* Clear
|
|
*/
|
|
echartsProto.clear = function () {
|
|
this.setOption({ series: [] }, true);
|
|
};
|
|
/**
|
|
* Dispose instance
|
|
*/
|
|
echartsProto.dispose = function () {
|
|
if (this._disposed) {
|
|
if (true) {
|
|
console.warn('Instance ' + this.id + ' has been disposed');
|
|
}
|
|
return;
|
|
}
|
|
this._disposed = true;
|
|
var api = this._api;
|
|
var ecModel = this._model;
|
|
each(this._componentsViews, function (component) {
|
|
component.dispose(ecModel, api);
|
|
});
|
|
each(this._chartsViews, function (chart) {
|
|
chart.dispose(ecModel, api);
|
|
});
|
|
// Dispose after all views disposed
|
|
this._zr.dispose();
|
|
delete instances[this.id];
|
|
};
|
|
zrUtil.mixin(ECharts, Eventful);
|
|
function updateHoverLayerStatus(zr, ecModel) {
|
|
var storage = zr.storage;
|
|
var elCount = 0;
|
|
storage.traverse(function (el) {
|
|
if (!el.isGroup) {
|
|
elCount++;
|
|
}
|
|
});
|
|
if (elCount > ecModel.get('hoverLayerThreshold') && !env.node) {
|
|
storage.traverse(function (el) {
|
|
if (!el.isGroup) {
|
|
el.useHoverLayer = true;
|
|
}
|
|
});
|
|
}
|
|
}
|
|
/**
|
|
* Update chart progressive and blend.
|
|
* @param {module:echarts/model/Series|module:echarts/model/Component} model
|
|
* @param {module:echarts/view/Component|module:echarts/view/Chart} view
|
|
*/
|
|
function updateProgressiveAndBlend(seriesModel, chartView) {
|
|
// Progressive configuration
|
|
var elCount = 0;
|
|
chartView.group.traverse(function (el) {
|
|
if (el.type !== 'group' && !el.ignore) {
|
|
elCount++;
|
|
}
|
|
});
|
|
var frameDrawNum = +seriesModel.get('progressive');
|
|
var needProgressive = elCount > seriesModel.get('progressiveThreshold') && frameDrawNum && !env.node;
|
|
if (needProgressive) {
|
|
chartView.group.traverse(function (el) {
|
|
// FIXME marker and other components
|
|
if (!el.isGroup) {
|
|
el.progressive = needProgressive ? Math.floor(elCount++ / frameDrawNum) : -1;
|
|
if (needProgressive) {
|
|
el.stopAnimation(true);
|
|
}
|
|
}
|
|
});
|
|
}
|
|
// Blend configration
|
|
var blendMode = seriesModel.get('blendMode') || null;
|
|
if (true) {
|
|
if (!env.canvasSupported && blendMode && blendMode !== 'source-over') {
|
|
console.warn('Only canvas support blendMode');
|
|
}
|
|
}
|
|
chartView.group.traverse(function (el) {
|
|
// FIXME marker and other components
|
|
if (!el.isGroup) {
|
|
el.setStyle('blend', blendMode);
|
|
}
|
|
});
|
|
}
|
|
/**
|
|
* @param {module:echarts/model/Series|module:echarts/model/Component} model
|
|
* @param {module:echarts/view/Component|module:echarts/view/Chart} view
|
|
*/
|
|
function updateZ(model, view) {
|
|
var z = model.get('z');
|
|
var zlevel = model.get('zlevel');
|
|
// Set z and zlevel
|
|
view.group.traverse(function (el) {
|
|
if (el.type !== 'group') {
|
|
z != null && (el.z = z);
|
|
zlevel != null && (el.zlevel = zlevel);
|
|
}
|
|
});
|
|
}
|
|
function createExtensionAPI(ecInstance) {
|
|
var coordSysMgr = ecInstance._coordSysMgr;
|
|
return zrUtil.extend(new ExtensionAPI(ecInstance), {
|
|
getCoordinateSystems: zrUtil.bind(coordSysMgr.getCoordinateSystems, coordSysMgr),
|
|
getComponentByElement: function (el) {
|
|
while (el) {
|
|
var modelInfo = el.__ecComponentInfo;
|
|
if (modelInfo != null) {
|
|
return ecInstance._model.getComponent(modelInfo.mainType, modelInfo.index);
|
|
}
|
|
el = el.parent;
|
|
}
|
|
}
|
|
});
|
|
}
|
|
/**
|
|
* @type {Object} key: actionType.
|
|
* @inner
|
|
*/
|
|
var actions = {};
|
|
/**
|
|
* Map eventType to actionType
|
|
* @type {Object}
|
|
*/
|
|
var eventActionMap = {};
|
|
/**
|
|
* Data processor functions of each stage
|
|
* @type {Array.<Object.<string, Function>>}
|
|
* @inner
|
|
*/
|
|
var dataProcessorFuncs = [];
|
|
/**
|
|
* @type {Array.<Function>}
|
|
* @inner
|
|
*/
|
|
var optionPreprocessorFuncs = [];
|
|
/**
|
|
* @type {Array.<Function>}
|
|
* @inner
|
|
*/
|
|
var postUpdateFuncs = [];
|
|
/**
|
|
* Visual encoding functions of each stage
|
|
* @type {Array.<Object.<string, Function>>}
|
|
* @inner
|
|
*/
|
|
var visualFuncs = [];
|
|
/**
|
|
* Theme storage
|
|
* @type {Object.<key, Object>}
|
|
*/
|
|
var themeStorage = {};
|
|
/**
|
|
* Loading effects
|
|
*/
|
|
var loadingEffects = {};
|
|
var instances = {};
|
|
var connectedGroups = {};
|
|
var idBase = new Date() - 0;
|
|
var groupIdBase = new Date() - 0;
|
|
var DOM_ATTRIBUTE_KEY = '_echarts_instance_';
|
|
/**
|
|
* @alias module:echarts
|
|
*/
|
|
var echarts = {
|
|
version: '3.7.2',
|
|
dependencies: { zrender: '3.6.2' }
|
|
};
|
|
function enableConnect(chart) {
|
|
var STATUS_PENDING = 0;
|
|
var STATUS_UPDATING = 1;
|
|
var STATUS_UPDATED = 2;
|
|
var STATUS_KEY = '__connectUpdateStatus';
|
|
function updateConnectedChartsStatus(charts, status) {
|
|
for (var i = 0; i < charts.length; i++) {
|
|
var otherChart = charts[i];
|
|
otherChart[STATUS_KEY] = status;
|
|
}
|
|
}
|
|
zrUtil.each(eventActionMap, function (actionType, eventType) {
|
|
chart._messageCenter.on(eventType, function (event) {
|
|
if (connectedGroups[chart.group] && chart[STATUS_KEY] !== STATUS_PENDING) {
|
|
if (event && event.escapeConnect) {
|
|
return;
|
|
}
|
|
var action = chart.makeActionFromEvent(event);
|
|
var otherCharts = [];
|
|
zrUtil.each(instances, function (otherChart) {
|
|
if (otherChart !== chart && otherChart.group === chart.group) {
|
|
otherCharts.push(otherChart);
|
|
}
|
|
});
|
|
updateConnectedChartsStatus(otherCharts, STATUS_PENDING);
|
|
each(otherCharts, function (otherChart) {
|
|
if (otherChart[STATUS_KEY] !== STATUS_UPDATING) {
|
|
otherChart.dispatchAction(action);
|
|
}
|
|
});
|
|
updateConnectedChartsStatus(otherCharts, STATUS_UPDATED);
|
|
}
|
|
});
|
|
});
|
|
}
|
|
/**
|
|
* @param {HTMLElement} dom
|
|
* @param {Object} [theme]
|
|
* @param {Object} opts
|
|
* @param {number} [opts.devicePixelRatio] Use window.devicePixelRatio by default
|
|
* @param {string} [opts.renderer] Currently only 'canvas' is supported.
|
|
* @param {number} [opts.width] Use clientWidth of the input `dom` by default.
|
|
* Can be 'auto' (the same as null/undefined)
|
|
* @param {number} [opts.height] Use clientHeight of the input `dom` by default.
|
|
* Can be 'auto' (the same as null/undefined)
|
|
*/
|
|
echarts.init = function (dom, theme, opts) {
|
|
if (true) {
|
|
// Check version
|
|
if (zrender.version.replace('.', '') - 0 < echarts.dependencies.zrender.replace('.', '') - 0) {
|
|
throw new Error('ZRender ' + zrender.version + ' is too old for ECharts ' + echarts.version + '. Current version need ZRender ' + echarts.dependencies.zrender + '+');
|
|
}
|
|
if (!dom) {
|
|
throw new Error('Initialize failed: invalid dom.');
|
|
}
|
|
}
|
|
var existInstance = echarts.getInstanceByDom(dom);
|
|
if (existInstance) {
|
|
if (true) {
|
|
console.warn('There is a chart instance already initialized on the dom.');
|
|
}
|
|
return existInstance;
|
|
}
|
|
if (true) {
|
|
if (zrUtil.isDom(dom) && dom.nodeName.toUpperCase() !== 'CANVAS' && (!dom.clientWidth && (!opts || opts.width == null) || !dom.clientHeight && (!opts || opts.height == null))) {
|
|
console.warn('Can\'t get dom width or height');
|
|
}
|
|
}
|
|
var chart = new ECharts(dom, theme, opts);
|
|
chart.id = 'ec_' + idBase++;
|
|
instances[chart.id] = chart;
|
|
if (dom.setAttribute) {
|
|
dom.setAttribute(DOM_ATTRIBUTE_KEY, chart.id);
|
|
} else {
|
|
dom[DOM_ATTRIBUTE_KEY] = chart.id;
|
|
}
|
|
enableConnect(chart);
|
|
return chart;
|
|
};
|
|
/**
|
|
* @return {string|Array.<module:echarts~ECharts>} groupId
|
|
*/
|
|
echarts.connect = function (groupId) {
|
|
// Is array of charts
|
|
if (zrUtil.isArray(groupId)) {
|
|
var charts = groupId;
|
|
groupId = null;
|
|
// If any chart has group
|
|
zrUtil.each(charts, function (chart) {
|
|
if (chart.group != null) {
|
|
groupId = chart.group;
|
|
}
|
|
});
|
|
groupId = groupId || 'g_' + groupIdBase++;
|
|
zrUtil.each(charts, function (chart) {
|
|
chart.group = groupId;
|
|
});
|
|
}
|
|
connectedGroups[groupId] = true;
|
|
return groupId;
|
|
};
|
|
/**
|
|
* @DEPRECATED
|
|
* @return {string} groupId
|
|
*/
|
|
echarts.disConnect = function (groupId) {
|
|
connectedGroups[groupId] = false;
|
|
};
|
|
/**
|
|
* @return {string} groupId
|
|
*/
|
|
echarts.disconnect = echarts.disConnect;
|
|
/**
|
|
* Dispose a chart instance
|
|
* @param {module:echarts~ECharts|HTMLDomElement|string} chart
|
|
*/
|
|
echarts.dispose = function (chart) {
|
|
if (typeof chart === 'string') {
|
|
chart = instances[chart];
|
|
} else if (!(chart instanceof ECharts)) {
|
|
// Try to treat as dom
|
|
chart = echarts.getInstanceByDom(chart);
|
|
}
|
|
if (chart instanceof ECharts && !chart.isDisposed()) {
|
|
chart.dispose();
|
|
}
|
|
};
|
|
/**
|
|
* @param {HTMLElement} dom
|
|
* @return {echarts~ECharts}
|
|
*/
|
|
echarts.getInstanceByDom = function (dom) {
|
|
var key;
|
|
if (dom.getAttribute) {
|
|
key = dom.getAttribute(DOM_ATTRIBUTE_KEY);
|
|
} else {
|
|
key = dom[DOM_ATTRIBUTE_KEY];
|
|
}
|
|
return instances[key];
|
|
};
|
|
/**
|
|
* @param {string} key
|
|
* @return {echarts~ECharts}
|
|
*/
|
|
echarts.getInstanceById = function (key) {
|
|
return instances[key];
|
|
};
|
|
/**
|
|
* Register theme
|
|
*/
|
|
echarts.registerTheme = function (name, theme) {
|
|
themeStorage[name] = theme;
|
|
};
|
|
/**
|
|
* Register option preprocessor
|
|
* @param {Function} preprocessorFunc
|
|
*/
|
|
echarts.registerPreprocessor = function (preprocessorFunc) {
|
|
optionPreprocessorFuncs.push(preprocessorFunc);
|
|
};
|
|
/**
|
|
* @param {number} [priority=1000]
|
|
* @param {Function} processorFunc
|
|
*/
|
|
echarts.registerProcessor = function (priority, processorFunc) {
|
|
if (typeof priority === 'function') {
|
|
processorFunc = priority;
|
|
priority = PRIORITY_PROCESSOR_FILTER;
|
|
}
|
|
if (true) {
|
|
if (isNaN(priority)) {
|
|
throw new Error('Unkown processor priority');
|
|
}
|
|
}
|
|
dataProcessorFuncs.push({
|
|
prio: priority,
|
|
func: processorFunc
|
|
});
|
|
};
|
|
/**
|
|
* Register postUpdater
|
|
* @param {Function} postUpdateFunc
|
|
*/
|
|
echarts.registerPostUpdate = function (postUpdateFunc) {
|
|
postUpdateFuncs.push(postUpdateFunc);
|
|
};
|
|
/**
|
|
* Usage:
|
|
* registerAction('someAction', 'someEvent', function () { ... });
|
|
* registerAction('someAction', function () { ... });
|
|
* registerAction(
|
|
* {type: 'someAction', event: 'someEvent', update: 'updateView'},
|
|
* function () { ... }
|
|
* );
|
|
*
|
|
* @param {(string|Object)} actionInfo
|
|
* @param {string} actionInfo.type
|
|
* @param {string} [actionInfo.event]
|
|
* @param {string} [actionInfo.update]
|
|
* @param {string} [eventName]
|
|
* @param {Function} action
|
|
*/
|
|
echarts.registerAction = function (actionInfo, eventName, action) {
|
|
if (typeof eventName === 'function') {
|
|
action = eventName;
|
|
eventName = '';
|
|
}
|
|
var actionType = zrUtil.isObject(actionInfo) ? actionInfo.type : [
|
|
actionInfo,
|
|
actionInfo = { event: eventName }
|
|
][0];
|
|
// Event name is all lowercase
|
|
actionInfo.event = (actionInfo.event || actionType).toLowerCase();
|
|
eventName = actionInfo.event;
|
|
// Validate action type and event name.
|
|
zrUtil.assert(ACTION_REG.test(actionType) && ACTION_REG.test(eventName));
|
|
if (!actions[actionType]) {
|
|
actions[actionType] = {
|
|
action: action,
|
|
actionInfo: actionInfo
|
|
};
|
|
}
|
|
eventActionMap[eventName] = actionType;
|
|
};
|
|
/**
|
|
* @param {string} type
|
|
* @param {*} CoordinateSystem
|
|
*/
|
|
echarts.registerCoordinateSystem = function (type, CoordinateSystem) {
|
|
CoordinateSystemManager.register(type, CoordinateSystem);
|
|
};
|
|
/**
|
|
* Get dimensions of specified coordinate system.
|
|
* @param {string} type
|
|
* @return {Array.<string|Object>}
|
|
*/
|
|
echarts.getCoordinateSystemDimensions = function (type) {
|
|
var coordSysCreator = CoordinateSystemManager.get(type);
|
|
if (coordSysCreator) {
|
|
return coordSysCreator.getDimensionsInfo ? coordSysCreator.getDimensionsInfo() : coordSysCreator.dimensions.slice();
|
|
}
|
|
};
|
|
/**
|
|
* Layout is a special stage of visual encoding
|
|
* Most visual encoding like color are common for different chart
|
|
* But each chart has it's own layout algorithm
|
|
*
|
|
* @param {number} [priority=1000]
|
|
* @param {Function} layoutFunc
|
|
*/
|
|
echarts.registerLayout = function (priority, layoutFunc) {
|
|
if (typeof priority === 'function') {
|
|
layoutFunc = priority;
|
|
priority = PRIORITY_VISUAL_LAYOUT;
|
|
}
|
|
if (true) {
|
|
if (isNaN(priority)) {
|
|
throw new Error('Unkown layout priority');
|
|
}
|
|
}
|
|
visualFuncs.push({
|
|
prio: priority,
|
|
func: layoutFunc,
|
|
isLayout: true
|
|
});
|
|
};
|
|
/**
|
|
* @param {number} [priority=3000]
|
|
* @param {Function} visualFunc
|
|
*/
|
|
echarts.registerVisual = function (priority, visualFunc) {
|
|
if (typeof priority === 'function') {
|
|
visualFunc = priority;
|
|
priority = PRIORITY_VISUAL_CHART;
|
|
}
|
|
if (true) {
|
|
if (isNaN(priority)) {
|
|
throw new Error('Unkown visual priority');
|
|
}
|
|
}
|
|
visualFuncs.push({
|
|
prio: priority,
|
|
func: visualFunc
|
|
});
|
|
};
|
|
/**
|
|
* @param {string} name
|
|
*/
|
|
echarts.registerLoading = function (name, loadingFx) {
|
|
loadingEffects[name] = loadingFx;
|
|
};
|
|
/**
|
|
* @param {Object} opts
|
|
* @param {string} [superClass]
|
|
*/
|
|
echarts.extendComponentModel = function (opts) {
|
|
// var Clazz = ComponentModel;
|
|
// if (superClass) {
|
|
// var classType = parseClassType(superClass);
|
|
// Clazz = ComponentModel.getClass(classType.main, classType.sub, true);
|
|
// }
|
|
return ComponentModel.extend(opts);
|
|
};
|
|
/**
|
|
* @param {Object} opts
|
|
* @param {string} [superClass]
|
|
*/
|
|
echarts.extendComponentView = function (opts) {
|
|
// var Clazz = ComponentView;
|
|
// if (superClass) {
|
|
// var classType = parseClassType(superClass);
|
|
// Clazz = ComponentView.getClass(classType.main, classType.sub, true);
|
|
// }
|
|
return ComponentView.extend(opts);
|
|
};
|
|
/**
|
|
* @param {Object} opts
|
|
* @param {string} [superClass]
|
|
*/
|
|
echarts.extendSeriesModel = function (opts) {
|
|
// var Clazz = SeriesModel;
|
|
// if (superClass) {
|
|
// superClass = 'series.' + superClass.replace('series.', '');
|
|
// var classType = parseClassType(superClass);
|
|
// Clazz = ComponentModel.getClass(classType.main, classType.sub, true);
|
|
// }
|
|
return SeriesModel.extend(opts);
|
|
};
|
|
/**
|
|
* @param {Object} opts
|
|
* @param {string} [superClass]
|
|
*/
|
|
echarts.extendChartView = function (opts) {
|
|
// var Clazz = ChartView;
|
|
// if (superClass) {
|
|
// superClass = superClass.replace('series.', '');
|
|
// var classType = parseClassType(superClass);
|
|
// Clazz = ChartView.getClass(classType.main, true);
|
|
// }
|
|
return ChartView.extend(opts);
|
|
};
|
|
/**
|
|
* 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')
|
|
*
|
|
* Be careful of using it in the browser.
|
|
*
|
|
* @param {Function} creator
|
|
* @example
|
|
* var Canvas = require('canvas');
|
|
* var echarts = require('echarts');
|
|
* echarts.setCanvasCreator(function () {
|
|
* // Small size is enough.
|
|
* return new Canvas(32, 32);
|
|
* });
|
|
*/
|
|
echarts.setCanvasCreator = function (creator) {
|
|
zrUtil.createCanvas = creator;
|
|
};
|
|
echarts.registerVisual(PRIORITY_VISUAL_GLOBAL, require('./visual/seriesColor'));
|
|
echarts.registerPreprocessor(backwardCompat);
|
|
echarts.registerLoading('default', require('./loading/default'));
|
|
// Default action
|
|
echarts.registerAction({
|
|
type: 'highlight',
|
|
event: 'highlight',
|
|
update: 'highlight'
|
|
}, zrUtil.noop);
|
|
echarts.registerAction({
|
|
type: 'downplay',
|
|
event: 'downplay',
|
|
update: 'downplay'
|
|
}, zrUtil.noop);
|
|
// --------
|
|
// Exports
|
|
// --------
|
|
echarts.zrender = zrender;
|
|
echarts.List = require('./data/List');
|
|
echarts.Model = require('./model/Model');
|
|
echarts.Axis = require('./coord/Axis');
|
|
echarts.graphic = require('./util/graphic');
|
|
echarts.number = require('./util/number');
|
|
echarts.format = require('./util/format');
|
|
echarts.throttle = throttle.throttle;
|
|
echarts.matrix = require('zrender/core/matrix');
|
|
echarts.vector = require('zrender/core/vector');
|
|
echarts.color = require('zrender/tool/color');
|
|
echarts.util = {};
|
|
each([
|
|
'map',
|
|
'each',
|
|
'filter',
|
|
'indexOf',
|
|
'inherits',
|
|
'reduce',
|
|
'filter',
|
|
'bind',
|
|
'curry',
|
|
'isArray',
|
|
'isString',
|
|
'isObject',
|
|
'isFunction',
|
|
'extend',
|
|
'defaults',
|
|
'clone',
|
|
'merge'
|
|
], function (name) {
|
|
echarts.util[name] = zrUtil[name];
|
|
});
|
|
echarts.helper = require('./helper');
|
|
// PRIORITY
|
|
echarts.PRIORITY = {
|
|
PROCESSOR: {
|
|
FILTER: PRIORITY_PROCESSOR_FILTER,
|
|
STATISTIC: PRIORITY_PROCESSOR_STATISTIC
|
|
},
|
|
VISUAL: {
|
|
LAYOUT: PRIORITY_VISUAL_LAYOUT,
|
|
GLOBAL: PRIORITY_VISUAL_GLOBAL,
|
|
CHART: PRIORITY_VISUAL_CHART,
|
|
COMPONENT: PRIORITY_VISUAL_COMPONENT,
|
|
BRUSH: PRIORITY_VISUAL_BRUSH
|
|
}
|
|
};
|
|
return echarts;
|
|
});
|
|
define('echarts/chart/lines', ['require', './lines/LinesSeries', './lines/LinesView', '../echarts', './lines/linesLayout', './lines/linesVisual'], function (require) {
|
|
require('./lines/LinesSeries');
|
|
require('./lines/LinesView');
|
|
var echarts = require('../echarts');
|
|
echarts.registerLayout(require('./lines/linesLayout'));
|
|
echarts.registerVisual(require('./lines/linesVisual'));
|
|
});
|
|
define('echarts/chart/parallel', ['require', '../echarts', '../component/parallel', './parallel/ParallelSeries', './parallel/ParallelView', './parallel/parallelVisual'], function (require) {
|
|
var echarts = require('../echarts');
|
|
require('../component/parallel');
|
|
require('./parallel/ParallelSeries');
|
|
require('./parallel/ParallelView');
|
|
echarts.registerVisual(require('./parallel/parallelVisual'));
|
|
});
|
|
define('echarts/chart/map', ['require', '../echarts', './map/MapSeries', './map/MapView', '../action/geoRoam', '../coord/geo/geoCreator', './map/mapSymbolLayout', './map/mapVisual', './map/mapDataStatistic', './map/backwardCompat', '../action/createDataSelectAction'], function (require) {
|
|
var echarts = require('../echarts');
|
|
var PRIORITY = echarts.PRIORITY;
|
|
require('./map/MapSeries');
|
|
require('./map/MapView');
|
|
require('../action/geoRoam');
|
|
require('../coord/geo/geoCreator');
|
|
echarts.registerLayout(require('./map/mapSymbolLayout'));
|
|
echarts.registerVisual(require('./map/mapVisual'));
|
|
echarts.registerProcessor(PRIORITY.PROCESSOR.STATISTIC, require('./map/mapDataStatistic'));
|
|
echarts.registerPreprocessor(require('./map/backwardCompat'));
|
|
require('../action/createDataSelectAction')('map', [
|
|
{
|
|
type: 'mapToggleSelect',
|
|
event: 'mapselectchanged',
|
|
method: 'toggleSelected'
|
|
},
|
|
{
|
|
type: 'mapSelect',
|
|
event: 'mapselected',
|
|
method: 'select'
|
|
},
|
|
{
|
|
type: 'mapUnSelect',
|
|
event: 'mapunselected',
|
|
method: 'unSelect'
|
|
}
|
|
]);
|
|
});
|
|
define('echarts/chart/effectScatter', ['require', 'zrender/core/util', '../echarts', './effectScatter/EffectScatterSeries', './effectScatter/EffectScatterView', '../visual/symbol', '../layout/points'], function (require) {
|
|
var zrUtil = require('zrender/core/util');
|
|
var echarts = require('../echarts');
|
|
require('./effectScatter/EffectScatterSeries');
|
|
require('./effectScatter/EffectScatterView');
|
|
echarts.registerVisual(zrUtil.curry(require('../visual/symbol'), 'effectScatter', 'circle', null));
|
|
echarts.registerLayout(zrUtil.curry(require('../layout/points'), 'effectScatter'));
|
|
});
|
|
define('echarts/component/gridSimple', ['require', '../util/graphic', 'zrender/core/util', '../echarts', '../coord/cartesian/Grid', './axis'], function (require) {
|
|
'use strict';
|
|
var graphic = require('../util/graphic');
|
|
var zrUtil = require('zrender/core/util');
|
|
var echarts = require('../echarts');
|
|
require('../coord/cartesian/Grid');
|
|
require('./axis');
|
|
// Grid view
|
|
echarts.extendComponentView({
|
|
type: 'grid',
|
|
render: function (gridModel, ecModel) {
|
|
this.group.removeAll();
|
|
if (gridModel.get('show')) {
|
|
this.group.add(new graphic.Rect({
|
|
shape: gridModel.coordinateSystem.getRect(),
|
|
style: zrUtil.defaults({ fill: gridModel.get('backgroundColor') }, gridModel.getItemStyle()),
|
|
silent: true,
|
|
z2: -1
|
|
}));
|
|
}
|
|
}
|
|
});
|
|
echarts.registerPreprocessor(function (option) {
|
|
// Only create grid when need
|
|
if (option.xAxis && option.yAxis && !option.grid) {
|
|
option.grid = {};
|
|
}
|
|
});
|
|
});
|
|
define('echarts/component/title', ['require', '../echarts', '../util/graphic', '../util/layout'], function (require) {
|
|
'use strict';
|
|
var echarts = require('../echarts');
|
|
var graphic = require('../util/graphic');
|
|
var layout = require('../util/layout');
|
|
// Model
|
|
echarts.extendComponentModel({
|
|
type: 'title',
|
|
layoutMode: {
|
|
type: 'box',
|
|
ignoreSize: true
|
|
},
|
|
defaultOption: {
|
|
zlevel: 0,
|
|
z: 6,
|
|
show: true,
|
|
text: '',
|
|
target: 'blank',
|
|
subtext: '',
|
|
subtarget: 'blank',
|
|
left: 0,
|
|
top: 0,
|
|
backgroundColor: 'rgba(0,0,0,0)',
|
|
borderColor: '#ccc',
|
|
borderWidth: 0,
|
|
padding: 5,
|
|
itemGap: 10,
|
|
textStyle: {
|
|
fontSize: 18,
|
|
fontWeight: 'bolder',
|
|
color: '#333'
|
|
},
|
|
subtextStyle: { color: '#aaa' }
|
|
}
|
|
});
|
|
// View
|
|
echarts.extendComponentView({
|
|
type: 'title',
|
|
render: function (titleModel, ecModel, api) {
|
|
this.group.removeAll();
|
|
if (!titleModel.get('show')) {
|
|
return;
|
|
}
|
|
var group = this.group;
|
|
var textStyleModel = titleModel.getModel('textStyle');
|
|
var subtextStyleModel = titleModel.getModel('subtextStyle');
|
|
var textAlign = titleModel.get('textAlign');
|
|
var textBaseline = titleModel.get('textBaseline');
|
|
var textEl = new graphic.Text({
|
|
style: graphic.setTextStyle({}, textStyleModel, {
|
|
text: titleModel.get('text'),
|
|
textFill: textStyleModel.getTextColor()
|
|
}, { disableBox: true }),
|
|
z2: 10
|
|
});
|
|
var textRect = textEl.getBoundingRect();
|
|
var subText = titleModel.get('subtext');
|
|
var subTextEl = new graphic.Text({
|
|
style: graphic.setTextStyle({}, subtextStyleModel, {
|
|
text: subText,
|
|
textFill: subtextStyleModel.getTextColor(),
|
|
y: textRect.height + titleModel.get('itemGap'),
|
|
textVerticalAlign: 'top'
|
|
}, { disableBox: true }),
|
|
z2: 10
|
|
});
|
|
var link = titleModel.get('link');
|
|
var sublink = titleModel.get('sublink');
|
|
textEl.silent = !link;
|
|
subTextEl.silent = !sublink;
|
|
if (link) {
|
|
textEl.on('click', function () {
|
|
window.open(link, '_' + titleModel.get('target'));
|
|
});
|
|
}
|
|
if (sublink) {
|
|
subTextEl.on('click', function () {
|
|
window.open(sublink, '_' + titleModel.get('subtarget'));
|
|
});
|
|
}
|
|
group.add(textEl);
|
|
subText && group.add(subTextEl);
|
|
// If no subText, but add subTextEl, there will be an empty line.
|
|
var groupRect = group.getBoundingRect();
|
|
var layoutOption = titleModel.getBoxLayoutParams();
|
|
layoutOption.width = groupRect.width;
|
|
layoutOption.height = groupRect.height;
|
|
var layoutRect = layout.getLayoutRect(layoutOption, {
|
|
width: api.getWidth(),
|
|
height: api.getHeight()
|
|
}, titleModel.get('padding'));
|
|
// Adjust text align based on position
|
|
if (!textAlign) {
|
|
// Align left if title is on the left. center and right is same
|
|
textAlign = titleModel.get('left') || titleModel.get('right');
|
|
if (textAlign === 'middle') {
|
|
textAlign = 'center';
|
|
}
|
|
// Adjust layout by text align
|
|
if (textAlign === 'right') {
|
|
layoutRect.x += layoutRect.width;
|
|
} else if (textAlign === 'center') {
|
|
layoutRect.x += layoutRect.width / 2;
|
|
}
|
|
}
|
|
if (!textBaseline) {
|
|
textBaseline = titleModel.get('top') || titleModel.get('bottom');
|
|
if (textBaseline === 'center') {
|
|
textBaseline = 'middle';
|
|
}
|
|
if (textBaseline === 'bottom') {
|
|
layoutRect.y += layoutRect.height;
|
|
} else if (textBaseline === 'middle') {
|
|
layoutRect.y += layoutRect.height / 2;
|
|
}
|
|
textBaseline = textBaseline || 'top';
|
|
}
|
|
group.attr('position', [
|
|
layoutRect.x,
|
|
layoutRect.y
|
|
]);
|
|
var alignStyle = {
|
|
textAlign: textAlign,
|
|
textVerticalAlign: textBaseline
|
|
};
|
|
textEl.setStyle(alignStyle);
|
|
subTextEl.setStyle(alignStyle);
|
|
// Render background
|
|
// Get groupRect again because textAlign has been changed
|
|
groupRect = group.getBoundingRect();
|
|
var padding = layoutRect.margin;
|
|
var style = titleModel.getItemStyle([
|
|
'color',
|
|
'opacity'
|
|
]);
|
|
style.fill = titleModel.get('backgroundColor');
|
|
var rect = new graphic.Rect({
|
|
shape: {
|
|
x: groupRect.x - padding[3],
|
|
y: groupRect.y - padding[0],
|
|
width: groupRect.width + padding[1] + padding[3],
|
|
height: groupRect.height + padding[0] + padding[2],
|
|
r: titleModel.get('borderRadius')
|
|
},
|
|
style: style,
|
|
silent: true
|
|
});
|
|
graphic.subPixelOptimizeRect(rect);
|
|
group.add(rect);
|
|
}
|
|
});
|
|
});
|
|
define('echarts/component/legendScroll', ['require', './legend', './legend/ScrollableLegendModel', './legend/ScrollableLegendView', './legend/scrollableLegendAction'], function (require) {
|
|
require('./legend');
|
|
require('./legend/ScrollableLegendModel');
|
|
require('./legend/ScrollableLegendView');
|
|
require('./legend/scrollableLegendAction');
|
|
});
|
|
define('echarts/component/timeline', ['require', '../echarts', './timeline/preprocessor', './timeline/typeDefaulter', './timeline/timelineAction', './timeline/SliderTimelineModel', './timeline/SliderTimelineView'], function (require) {
|
|
var echarts = require('../echarts');
|
|
echarts.registerPreprocessor(require('./timeline/preprocessor'));
|
|
require('./timeline/typeDefaulter');
|
|
require('./timeline/timelineAction');
|
|
require('./timeline/SliderTimelineModel');
|
|
require('./timeline/SliderTimelineView');
|
|
});
|
|
define('echarts/component/tooltip', ['require', './axisPointer', './tooltip/TooltipModel', './tooltip/TooltipView', '../echarts'], function (require) {
|
|
require('./axisPointer');
|
|
require('./tooltip/TooltipModel');
|
|
require('./tooltip/TooltipView');
|
|
// Show tip action
|
|
/**
|
|
* @action
|
|
* @property {string} type
|
|
* @property {number} seriesIndex
|
|
* @property {number} dataIndex
|
|
* @property {number} [x]
|
|
* @property {number} [y]
|
|
*/
|
|
require('../echarts').registerAction({
|
|
type: 'showTip',
|
|
event: 'showTip',
|
|
update: 'tooltip:manuallyShowTip'
|
|
}, function () {
|
|
});
|
|
// Hide tip action
|
|
require('../echarts').registerAction({
|
|
type: 'hideTip',
|
|
event: 'hideTip',
|
|
update: 'tooltip:manuallyHideTip'
|
|
}, function () {
|
|
});
|
|
});
|
|
define('echarts/scale/Time', ['require', 'zrender/core/util', '../util/number', '../util/format', './helper', './Interval'], function (require) {
|
|
// [About UTC and local time zone]:
|
|
// In most cases, `number.parseDate` will treat input data string as local time
|
|
// (except time zone is specified in time string). And `format.formateTime` returns
|
|
// local time by default. option.useUTC is false by default. This design have
|
|
// concidered these common case:
|
|
// (1) Time that is persistent in server is in UTC, but it is needed to be diplayed
|
|
// in local time by default.
|
|
// (2) By default, the input data string (e.g., '2011-01-02') should be displayed
|
|
// as its original time, without any time difference.
|
|
var zrUtil = require('zrender/core/util');
|
|
var numberUtil = require('../util/number');
|
|
var formatUtil = require('../util/format');
|
|
var scaleHelper = require('./helper');
|
|
var IntervalScale = require('./Interval');
|
|
var intervalScaleProto = IntervalScale.prototype;
|
|
var mathCeil = Math.ceil;
|
|
var mathFloor = Math.floor;
|
|
var ONE_SECOND = 1000;
|
|
var ONE_MINUTE = ONE_SECOND * 60;
|
|
var ONE_HOUR = ONE_MINUTE * 60;
|
|
var ONE_DAY = ONE_HOUR * 24;
|
|
// FIXME 公用?
|
|
var bisect = function (a, x, lo, hi) {
|
|
while (lo < hi) {
|
|
var mid = lo + hi >>> 1;
|
|
if (a[mid][2] < x) {
|
|
lo = mid + 1;
|
|
} else {
|
|
hi = mid;
|
|
}
|
|
}
|
|
return lo;
|
|
};
|
|
/**
|
|
* @alias module:echarts/coord/scale/Time
|
|
* @constructor
|
|
*/
|
|
var TimeScale = IntervalScale.extend({
|
|
type: 'time',
|
|
getLabel: function (val) {
|
|
var stepLvl = this._stepLvl;
|
|
var date = new Date(val);
|
|
return formatUtil.formatTime(stepLvl[0], date, this.getSetting('useUTC'));
|
|
},
|
|
niceExtent: function (opt) {
|
|
var extent = this._extent;
|
|
// If extent start and end are same, expand them
|
|
if (extent[0] === extent[1]) {
|
|
// Expand extent
|
|
extent[0] -= ONE_DAY;
|
|
extent[1] += ONE_DAY;
|
|
}
|
|
// If there are no data and extent are [Infinity, -Infinity]
|
|
if (extent[1] === -Infinity && extent[0] === Infinity) {
|
|
var d = new Date();
|
|
extent[1] = +new Date(d.getFullYear(), d.getMonth(), d.getDate());
|
|
extent[0] = extent[1] - ONE_DAY;
|
|
}
|
|
this.niceTicks(opt.splitNumber, opt.minInterval, opt.maxInterval);
|
|
// var extent = this._extent;
|
|
var interval = this._interval;
|
|
if (!opt.fixMin) {
|
|
extent[0] = numberUtil.round(mathFloor(extent[0] / interval) * interval);
|
|
}
|
|
if (!opt.fixMax) {
|
|
extent[1] = numberUtil.round(mathCeil(extent[1] / interval) * interval);
|
|
}
|
|
},
|
|
niceTicks: function (approxTickNum, minInterval, maxInterval) {
|
|
approxTickNum = approxTickNum || 10;
|
|
var extent = this._extent;
|
|
var span = extent[1] - extent[0];
|
|
var approxInterval = span / approxTickNum;
|
|
if (minInterval != null && approxInterval < minInterval) {
|
|
approxInterval = minInterval;
|
|
}
|
|
if (maxInterval != null && approxInterval > maxInterval) {
|
|
approxInterval = maxInterval;
|
|
}
|
|
var scaleLevelsLen = scaleLevels.length;
|
|
var idx = bisect(scaleLevels, approxInterval, 0, scaleLevelsLen);
|
|
var level = scaleLevels[Math.min(idx, scaleLevelsLen - 1)];
|
|
var interval = level[2];
|
|
// Same with interval scale if span is much larger than 1 year
|
|
if (level[0] === 'year') {
|
|
var yearSpan = span / interval;
|
|
// From "Nice Numbers for Graph Labels" of Graphic Gems
|
|
// var niceYearSpan = numberUtil.nice(yearSpan, false);
|
|
var yearStep = numberUtil.nice(yearSpan / approxTickNum, true);
|
|
interval *= yearStep;
|
|
}
|
|
var timezoneOffset = this.getSetting('useUTC') ? 0 : new Date(+extent[0] || +extent[1]).getTimezoneOffset() * 60 * 1000;
|
|
var niceExtent = [
|
|
Math.round(mathCeil((extent[0] - timezoneOffset) / interval) * interval + timezoneOffset),
|
|
Math.round(mathFloor((extent[1] - timezoneOffset) / interval) * interval + timezoneOffset)
|
|
];
|
|
scaleHelper.fixExtent(niceExtent, extent);
|
|
this._stepLvl = level;
|
|
// Interval will be used in getTicks
|
|
this._interval = interval;
|
|
this._niceExtent = niceExtent;
|
|
},
|
|
parse: function (val) {
|
|
// val might be float.
|
|
return +numberUtil.parseDate(val);
|
|
}
|
|
});
|
|
zrUtil.each([
|
|
'contain',
|
|
'normalize'
|
|
], function (methodName) {
|
|
TimeScale.prototype[methodName] = function (val) {
|
|
return intervalScaleProto[methodName].call(this, this.parse(val));
|
|
};
|
|
});
|
|
// Steps from d3
|
|
var scaleLevels = [
|
|
[
|
|
'hh:mm:ss',
|
|
1,
|
|
ONE_SECOND
|
|
],
|
|
[
|
|
'hh:mm:ss',
|
|
5,
|
|
ONE_SECOND * 5
|
|
],
|
|
[
|
|
'hh:mm:ss',
|
|
10,
|
|
ONE_SECOND * 10
|
|
],
|
|
[
|
|
'hh:mm:ss',
|
|
15,
|
|
ONE_SECOND * 15
|
|
],
|
|
[
|
|
'hh:mm:ss',
|
|
30,
|
|
ONE_SECOND * 30
|
|
],
|
|
[
|
|
'hh:mm\nMM-dd',
|
|
1,
|
|
ONE_MINUTE
|
|
],
|
|
[
|
|
'hh:mm\nMM-dd',
|
|
5,
|
|
ONE_MINUTE * 5
|
|
],
|
|
[
|
|
'hh:mm\nMM-dd',
|
|
10,
|
|
ONE_MINUTE * 10
|
|
],
|
|
[
|
|
'hh:mm\nMM-dd',
|
|
15,
|
|
ONE_MINUTE * 15
|
|
],
|
|
[
|
|
'hh:mm\nMM-dd',
|
|
30,
|
|
ONE_MINUTE * 30
|
|
],
|
|
[
|
|
'hh:mm\nMM-dd',
|
|
1,
|
|
ONE_HOUR
|
|
],
|
|
[
|
|
'hh:mm\nMM-dd',
|
|
2,
|
|
ONE_HOUR * 2
|
|
],
|
|
[
|
|
'hh:mm\nMM-dd',
|
|
6,
|
|
ONE_HOUR * 6
|
|
],
|
|
[
|
|
'hh:mm\nMM-dd',
|
|
12,
|
|
ONE_HOUR * 12
|
|
],
|
|
[
|
|
'MM-dd\nyyyy',
|
|
1,
|
|
ONE_DAY
|
|
],
|
|
[
|
|
'week',
|
|
7,
|
|
ONE_DAY * 7
|
|
],
|
|
[
|
|
'month',
|
|
1,
|
|
ONE_DAY * 31
|
|
],
|
|
[
|
|
'quarter',
|
|
3,
|
|
ONE_DAY * 380 / 4
|
|
],
|
|
[
|
|
'half-year',
|
|
6,
|
|
ONE_DAY * 380 / 2
|
|
],
|
|
[
|
|
'year',
|
|
1,
|
|
ONE_DAY * 380
|
|
]
|
|
];
|
|
/**
|
|
* @param {module:echarts/model/Model}
|
|
* @return {module:echarts/scale/Time}
|
|
*/
|
|
TimeScale.create = function (model) {
|
|
return new TimeScale({ useUTC: model.ecModel.get('useUTC') });
|
|
};
|
|
return TimeScale;
|
|
});
|
|
define('echarts/component/toolbox', ['require', './toolbox/ToolboxModel', './toolbox/ToolboxView', './toolbox/feature/SaveAsImage', './toolbox/feature/MagicType', './toolbox/feature/DataView', './toolbox/feature/DataZoom', './toolbox/feature/Restore'], function (require) {
|
|
require('./toolbox/ToolboxModel');
|
|
require('./toolbox/ToolboxView');
|
|
require('./toolbox/feature/SaveAsImage');
|
|
require('./toolbox/feature/MagicType');
|
|
require('./toolbox/feature/DataView');
|
|
require('./toolbox/feature/DataZoom');
|
|
require('./toolbox/feature/Restore');
|
|
});
|
|
define('zrender/vml/vml', ['require', './graphic', '../zrender', './Painter'], function (require) {
|
|
require('./graphic');
|
|
require('../zrender').registerPainter('vml', require('./Painter'));
|
|
});
|
|
define('echarts/scale/Log', ['require', 'zrender/core/util', './Scale', '../util/number', './Interval'], function (require) {
|
|
var zrUtil = require('zrender/core/util');
|
|
var Scale = require('./Scale');
|
|
var numberUtil = require('../util/number');
|
|
// Use some method of IntervalScale
|
|
var IntervalScale = require('./Interval');
|
|
var scaleProto = Scale.prototype;
|
|
var intervalScaleProto = IntervalScale.prototype;
|
|
var getPrecisionSafe = numberUtil.getPrecisionSafe;
|
|
var roundingErrorFix = numberUtil.round;
|
|
var mathFloor = Math.floor;
|
|
var mathCeil = Math.ceil;
|
|
var mathPow = Math.pow;
|
|
var mathLog = Math.log;
|
|
var LogScale = Scale.extend({
|
|
type: 'log',
|
|
base: 10,
|
|
$constructor: function () {
|
|
Scale.apply(this, arguments);
|
|
this._originalScale = new IntervalScale();
|
|
},
|
|
getTicks: function () {
|
|
var originalScale = this._originalScale;
|
|
var extent = this._extent;
|
|
var originalExtent = originalScale.getExtent();
|
|
return zrUtil.map(intervalScaleProto.getTicks.call(this), function (val) {
|
|
var powVal = numberUtil.round(mathPow(this.base, val));
|
|
// Fix #4158
|
|
powVal = val === extent[0] && originalScale.__fixMin ? fixRoundingError(powVal, originalExtent[0]) : powVal;
|
|
powVal = val === extent[1] && originalScale.__fixMax ? fixRoundingError(powVal, originalExtent[1]) : powVal;
|
|
return powVal;
|
|
}, this);
|
|
},
|
|
getLabel: intervalScaleProto.getLabel,
|
|
scale: function (val) {
|
|
val = scaleProto.scale.call(this, val);
|
|
return mathPow(this.base, val);
|
|
},
|
|
setExtent: function (start, end) {
|
|
var base = this.base;
|
|
start = mathLog(start) / mathLog(base);
|
|
end = mathLog(end) / mathLog(base);
|
|
intervalScaleProto.setExtent.call(this, start, end);
|
|
},
|
|
getExtent: function () {
|
|
var base = this.base;
|
|
var extent = scaleProto.getExtent.call(this);
|
|
extent[0] = mathPow(base, extent[0]);
|
|
extent[1] = mathPow(base, extent[1]);
|
|
// Fix #4158
|
|
var originalScale = this._originalScale;
|
|
var originalExtent = originalScale.getExtent();
|
|
originalScale.__fixMin && (extent[0] = fixRoundingError(extent[0], originalExtent[0]));
|
|
originalScale.__fixMax && (extent[1] = fixRoundingError(extent[1], originalExtent[1]));
|
|
return extent;
|
|
},
|
|
unionExtent: function (extent) {
|
|
this._originalScale.unionExtent(extent);
|
|
var base = this.base;
|
|
extent[0] = mathLog(extent[0]) / mathLog(base);
|
|
extent[1] = mathLog(extent[1]) / mathLog(base);
|
|
scaleProto.unionExtent.call(this, extent);
|
|
},
|
|
unionExtentFromData: function (data, dim) {
|
|
this.unionExtent(data.getDataExtent(dim, true, function (val) {
|
|
return val > 0;
|
|
}));
|
|
},
|
|
niceTicks: function (approxTickNum) {
|
|
approxTickNum = approxTickNum || 10;
|
|
var extent = this._extent;
|
|
var span = extent[1] - extent[0];
|
|
if (span === Infinity || span <= 0) {
|
|
return;
|
|
}
|
|
var interval = numberUtil.quantity(span);
|
|
var err = approxTickNum / span * interval;
|
|
// Filter ticks to get closer to the desired count.
|
|
if (err <= 0.5) {
|
|
interval *= 10;
|
|
}
|
|
// Interval should be integer
|
|
while (!isNaN(interval) && Math.abs(interval) < 1 && Math.abs(interval) > 0) {
|
|
interval *= 10;
|
|
}
|
|
var niceExtent = [
|
|
numberUtil.round(mathCeil(extent[0] / interval) * interval),
|
|
numberUtil.round(mathFloor(extent[1] / interval) * interval)
|
|
];
|
|
this._interval = interval;
|
|
this._niceExtent = niceExtent;
|
|
},
|
|
niceExtent: function (opt) {
|
|
intervalScaleProto.niceExtent.call(this, opt);
|
|
var originalScale = this._originalScale;
|
|
originalScale.__fixMin = opt.fixMin;
|
|
originalScale.__fixMax = opt.fixMax;
|
|
}
|
|
});
|
|
zrUtil.each([
|
|
'contain',
|
|
'normalize'
|
|
], function (methodName) {
|
|
LogScale.prototype[methodName] = function (val) {
|
|
val = mathLog(val) / mathLog(this.base);
|
|
return scaleProto[methodName].call(this, val);
|
|
};
|
|
});
|
|
LogScale.create = function () {
|
|
return new LogScale();
|
|
};
|
|
function fixRoundingError(val, originalVal) {
|
|
return roundingErrorFix(val, getPrecisionSafe(originalVal));
|
|
}
|
|
return LogScale;
|
|
});
|
|
define('zrender/core/util', ['require'], function (require) {
|
|
// 用于处理merge时无法遍历Date等对象的问题
|
|
var BUILTIN_OBJECT = {
|
|
'[object Function]': 1,
|
|
'[object RegExp]': 1,
|
|
'[object Date]': 1,
|
|
'[object Error]': 1,
|
|
'[object CanvasGradient]': 1,
|
|
'[object CanvasPattern]': 1,
|
|
'[object Image]': 1,
|
|
'[object Canvas]': 1
|
|
};
|
|
var TYPED_ARRAY = {
|
|
'[object Int8Array]': 1,
|
|
'[object Uint8Array]': 1,
|
|
'[object Uint8ClampedArray]': 1,
|
|
'[object Int16Array]': 1,
|
|
'[object Uint16Array]': 1,
|
|
'[object Int32Array]': 1,
|
|
'[object Uint32Array]': 1,
|
|
'[object Float32Array]': 1,
|
|
'[object Float64Array]': 1
|
|
};
|
|
var objToString = Object.prototype.toString;
|
|
var arrayProto = Array.prototype;
|
|
var nativeForEach = arrayProto.forEach;
|
|
var nativeFilter = arrayProto.filter;
|
|
var nativeSlice = arrayProto.slice;
|
|
var nativeMap = arrayProto.map;
|
|
var nativeReduce = arrayProto.reduce;
|
|
/**
|
|
* Those data types can be cloned:
|
|
* Plain object, Array, TypedArray, number, string, null, undefined.
|
|
* Those data types will be assgined using the orginal data:
|
|
* BUILTIN_OBJECT
|
|
* Instance of user defined class will be cloned to a plain object, without
|
|
* properties in prototype.
|
|
* Other data types is not supported (not sure what will happen).
|
|
*
|
|
* Caution: do not support clone Date, for performance consideration.
|
|
* (There might be a large number of date in `series.data`).
|
|
* So date should not be modified in and out of echarts.
|
|
*
|
|
* @param {*} source
|
|
* @return {*} new
|
|
*/
|
|
function clone(source) {
|
|
if (source == null || typeof source != 'object') {
|
|
return source;
|
|
}
|
|
var result = source;
|
|
var typeStr = objToString.call(source);
|
|
if (typeStr === '[object Array]') {
|
|
result = [];
|
|
for (var i = 0, len = source.length; i < len; i++) {
|
|
result[i] = clone(source[i]);
|
|
}
|
|
} else if (TYPED_ARRAY[typeStr]) {
|
|
var Ctor = source.constructor;
|
|
if (source.constructor.from) {
|
|
result = Ctor.from(source);
|
|
} else {
|
|
result = new Ctor(source.length);
|
|
for (var i = 0, len = source.length; i < len; i++) {
|
|
result[i] = clone(source[i]);
|
|
}
|
|
}
|
|
} else if (!BUILTIN_OBJECT[typeStr] && !isPrimitive(source) && !isDom(source)) {
|
|
result = {};
|
|
for (var key in source) {
|
|
if (source.hasOwnProperty(key)) {
|
|
result[key] = clone(source[key]);
|
|
}
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
/**
|
|
* @memberOf module:zrender/core/util
|
|
* @param {*} target
|
|
* @param {*} source
|
|
* @param {boolean} [overwrite=false]
|
|
*/
|
|
function merge(target, source, overwrite) {
|
|
// We should escapse that source is string
|
|
// and enter for ... in ...
|
|
if (!isObject(source) || !isObject(target)) {
|
|
return overwrite ? clone(source) : target;
|
|
}
|
|
for (var key in source) {
|
|
if (source.hasOwnProperty(key)) {
|
|
var targetProp = target[key];
|
|
var sourceProp = source[key];
|
|
if (isObject(sourceProp) && isObject(targetProp) && !isArray(sourceProp) && !isArray(targetProp) && !isDom(sourceProp) && !isDom(targetProp) && !isBuiltInObject(sourceProp) && !isBuiltInObject(targetProp) && !isPrimitive(sourceProp) && !isPrimitive(targetProp)) {
|
|
// 如果需要递归覆盖,就递归调用merge
|
|
merge(targetProp, sourceProp, overwrite);
|
|
} else if (overwrite || !(key in target)) {
|
|
// 否则只处理overwrite为true,或者在目标对象中没有此属性的情况
|
|
// NOTE,在 target[key] 不存在的时候也是直接覆盖
|
|
target[key] = clone(source[key], true);
|
|
}
|
|
}
|
|
}
|
|
return target;
|
|
}
|
|
/**
|
|
* @param {Array} targetAndSources The first item is target, and the rests are source.
|
|
* @param {boolean} [overwrite=false]
|
|
* @return {*} target
|
|
*/
|
|
function mergeAll(targetAndSources, overwrite) {
|
|
var result = targetAndSources[0];
|
|
for (var i = 1, len = targetAndSources.length; i < len; i++) {
|
|
result = merge(result, targetAndSources[i], overwrite);
|
|
}
|
|
return result;
|
|
}
|
|
/**
|
|
* @param {*} target
|
|
* @param {*} source
|
|
* @memberOf module:zrender/core/util
|
|
*/
|
|
function extend(target, source) {
|
|
for (var key in source) {
|
|
if (source.hasOwnProperty(key)) {
|
|
target[key] = source[key];
|
|
}
|
|
}
|
|
return target;
|
|
}
|
|
/**
|
|
* @param {*} target
|
|
* @param {*} source
|
|
* @param {boolean} [overlay=false]
|
|
* @memberOf module:zrender/core/util
|
|
*/
|
|
function defaults(target, source, overlay) {
|
|
for (var key in source) {
|
|
if (source.hasOwnProperty(key) && (overlay ? source[key] != null : target[key] == null)) {
|
|
target[key] = source[key];
|
|
}
|
|
}
|
|
return target;
|
|
}
|
|
function createCanvas() {
|
|
return document.createElement('canvas');
|
|
}
|
|
// FIXME
|
|
var _ctx;
|
|
function getContext() {
|
|
if (!_ctx) {
|
|
// Use util.createCanvas instead of createCanvas
|
|
// because createCanvas may be overwritten in different environment
|
|
_ctx = util.createCanvas().getContext('2d');
|
|
}
|
|
return _ctx;
|
|
}
|
|
/**
|
|
* 查询数组中元素的index
|
|
* @memberOf module:zrender/core/util
|
|
*/
|
|
function indexOf(array, value) {
|
|
if (array) {
|
|
if (array.indexOf) {
|
|
return array.indexOf(value);
|
|
}
|
|
for (var i = 0, len = array.length; i < len; i++) {
|
|
if (array[i] === value) {
|
|
return i;
|
|
}
|
|
}
|
|
}
|
|
return -1;
|
|
}
|
|
/**
|
|
* 构造类继承关系
|
|
*
|
|
* @memberOf module:zrender/core/util
|
|
* @param {Function} clazz 源类
|
|
* @param {Function} baseClazz 基类
|
|
*/
|
|
function inherits(clazz, baseClazz) {
|
|
var clazzPrototype = clazz.prototype;
|
|
function F() {
|
|
}
|
|
F.prototype = baseClazz.prototype;
|
|
clazz.prototype = new F();
|
|
for (var prop in clazzPrototype) {
|
|
clazz.prototype[prop] = clazzPrototype[prop];
|
|
}
|
|
clazz.prototype.constructor = clazz;
|
|
clazz.superClass = baseClazz;
|
|
}
|
|
/**
|
|
* @memberOf module:zrender/core/util
|
|
* @param {Object|Function} target
|
|
* @param {Object|Function} sorce
|
|
* @param {boolean} overlay
|
|
*/
|
|
function mixin(target, source, overlay) {
|
|
target = 'prototype' in target ? target.prototype : target;
|
|
source = 'prototype' in source ? source.prototype : source;
|
|
defaults(target, source, overlay);
|
|
}
|
|
/**
|
|
* Consider typed array.
|
|
* @param {Array|TypedArray} data
|
|
*/
|
|
function isArrayLike(data) {
|
|
if (!data) {
|
|
return;
|
|
}
|
|
if (typeof data == 'string') {
|
|
return false;
|
|
}
|
|
return typeof data.length == 'number';
|
|
}
|
|
/**
|
|
* 数组或对象遍历
|
|
* @memberOf module:zrender/core/util
|
|
* @param {Object|Array} obj
|
|
* @param {Function} cb
|
|
* @param {*} [context]
|
|
*/
|
|
function each(obj, cb, context) {
|
|
if (!(obj && cb)) {
|
|
return;
|
|
}
|
|
if (obj.forEach && obj.forEach === nativeForEach) {
|
|
obj.forEach(cb, context);
|
|
} else if (obj.length === +obj.length) {
|
|
for (var i = 0, len = obj.length; i < len; i++) {
|
|
cb.call(context, obj[i], i, obj);
|
|
}
|
|
} else {
|
|
for (var key in obj) {
|
|
if (obj.hasOwnProperty(key)) {
|
|
cb.call(context, obj[key], key, obj);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
/**
|
|
* 数组映射
|
|
* @memberOf module:zrender/core/util
|
|
* @param {Array} obj
|
|
* @param {Function} cb
|
|
* @param {*} [context]
|
|
* @return {Array}
|
|
*/
|
|
function map(obj, cb, context) {
|
|
if (!(obj && cb)) {
|
|
return;
|
|
}
|
|
if (obj.map && obj.map === nativeMap) {
|
|
return obj.map(cb, context);
|
|
} else {
|
|
var result = [];
|
|
for (var i = 0, len = obj.length; i < len; i++) {
|
|
result.push(cb.call(context, obj[i], i, obj));
|
|
}
|
|
return result;
|
|
}
|
|
}
|
|
/**
|
|
* @memberOf module:zrender/core/util
|
|
* @param {Array} obj
|
|
* @param {Function} cb
|
|
* @param {Object} [memo]
|
|
* @param {*} [context]
|
|
* @return {Array}
|
|
*/
|
|
function reduce(obj, cb, memo, context) {
|
|
if (!(obj && cb)) {
|
|
return;
|
|
}
|
|
if (obj.reduce && obj.reduce === nativeReduce) {
|
|
return obj.reduce(cb, memo, context);
|
|
} else {
|
|
for (var i = 0, len = obj.length; i < len; i++) {
|
|
memo = cb.call(context, memo, obj[i], i, obj);
|
|
}
|
|
return memo;
|
|
}
|
|
}
|
|
/**
|
|
* 数组过滤
|
|
* @memberOf module:zrender/core/util
|
|
* @param {Array} obj
|
|
* @param {Function} cb
|
|
* @param {*} [context]
|
|
* @return {Array}
|
|
*/
|
|
function filter(obj, cb, context) {
|
|
if (!(obj && cb)) {
|
|
return;
|
|
}
|
|
if (obj.filter && obj.filter === nativeFilter) {
|
|
return obj.filter(cb, context);
|
|
} else {
|
|
var result = [];
|
|
for (var i = 0, len = obj.length; i < len; i++) {
|
|
if (cb.call(context, obj[i], i, obj)) {
|
|
result.push(obj[i]);
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
}
|
|
/**
|
|
* 数组项查找
|
|
* @memberOf module:zrender/core/util
|
|
* @param {Array} obj
|
|
* @param {Function} cb
|
|
* @param {*} [context]
|
|
* @return {Array}
|
|
*/
|
|
function find(obj, cb, context) {
|
|
if (!(obj && cb)) {
|
|
return;
|
|
}
|
|
for (var i = 0, len = obj.length; i < len; i++) {
|
|
if (cb.call(context, obj[i], i, obj)) {
|
|
return obj[i];
|
|
}
|
|
}
|
|
}
|
|
/**
|
|
* @memberOf module:zrender/core/util
|
|
* @param {Function} func
|
|
* @param {*} context
|
|
* @return {Function}
|
|
*/
|
|
function bind(func, context) {
|
|
var args = nativeSlice.call(arguments, 2);
|
|
return function () {
|
|
return func.apply(context, args.concat(nativeSlice.call(arguments)));
|
|
};
|
|
}
|
|
/**
|
|
* @memberOf module:zrender/core/util
|
|
* @param {Function} func
|
|
* @return {Function}
|
|
*/
|
|
function curry(func) {
|
|
var args = nativeSlice.call(arguments, 1);
|
|
return function () {
|
|
return func.apply(this, args.concat(nativeSlice.call(arguments)));
|
|
};
|
|
}
|
|
/**
|
|
* @memberOf module:zrender/core/util
|
|
* @param {*} value
|
|
* @return {boolean}
|
|
*/
|
|
function isArray(value) {
|
|
return objToString.call(value) === '[object Array]';
|
|
}
|
|
/**
|
|
* @memberOf module:zrender/core/util
|
|
* @param {*} value
|
|
* @return {boolean}
|
|
*/
|
|
function isFunction(value) {
|
|
return typeof value === 'function';
|
|
}
|
|
/**
|
|
* @memberOf module:zrender/core/util
|
|
* @param {*} value
|
|
* @return {boolean}
|
|
*/
|
|
function isString(value) {
|
|
return objToString.call(value) === '[object String]';
|
|
}
|
|
/**
|
|
* @memberOf module:zrender/core/util
|
|
* @param {*} value
|
|
* @return {boolean}
|
|
*/
|
|
function isObject(value) {
|
|
// Avoid a V8 JIT bug in Chrome 19-20.
|
|
// See https://code.google.com/p/v8/issues/detail?id=2291 for more details.
|
|
var type = typeof value;
|
|
return type === 'function' || !!value && type == 'object';
|
|
}
|
|
/**
|
|
* @memberOf module:zrender/core/util
|
|
* @param {*} value
|
|
* @return {boolean}
|
|
*/
|
|
function isBuiltInObject(value) {
|
|
return !!BUILTIN_OBJECT[objToString.call(value)];
|
|
}
|
|
/**
|
|
* @memberOf module:zrender/core/util
|
|
* @param {*} value
|
|
* @return {boolean}
|
|
*/
|
|
function isDom(value) {
|
|
return typeof value === 'object' && typeof value.nodeType === 'number' && typeof value.ownerDocument === 'object';
|
|
}
|
|
/**
|
|
* Whether is exactly NaN. Notice isNaN('a') returns true.
|
|
* @param {*} value
|
|
* @return {boolean}
|
|
*/
|
|
function eqNaN(value) {
|
|
return value !== value;
|
|
}
|
|
/**
|
|
* If value1 is not null, then return value1, otherwise judget rest of values.
|
|
* Low performance.
|
|
* @memberOf module:zrender/core/util
|
|
* @return {*} Final value
|
|
*/
|
|
function retrieve(values) {
|
|
for (var i = 0, len = arguments.length; i < len; i++) {
|
|
if (arguments[i] != null) {
|
|
return arguments[i];
|
|
}
|
|
}
|
|
}
|
|
function retrieve2(value0, value1) {
|
|
return value0 != null ? value0 : value1;
|
|
}
|
|
function retrieve3(value0, value1, value2) {
|
|
return value0 != null ? value0 : value1 != null ? value1 : value2;
|
|
}
|
|
/**
|
|
* @memberOf module:zrender/core/util
|
|
* @param {Array} arr
|
|
* @param {number} startIndex
|
|
* @param {number} endIndex
|
|
* @return {Array}
|
|
*/
|
|
function slice() {
|
|
return Function.call.apply(nativeSlice, arguments);
|
|
}
|
|
/**
|
|
* Normalize css liked array configuration
|
|
* e.g.
|
|
* 3 => [3, 3, 3, 3]
|
|
* [4, 2] => [4, 2, 4, 2]
|
|
* [4, 3, 2] => [4, 3, 2, 3]
|
|
* @param {number|Array.<number>} val
|
|
* @return {Array.<number>}
|
|
*/
|
|
function normalizeCssArray(val) {
|
|
if (typeof val === 'number') {
|
|
return [
|
|
val,
|
|
val,
|
|
val,
|
|
val
|
|
];
|
|
}
|
|
var len = val.length;
|
|
if (len === 2) {
|
|
// vertical | horizontal
|
|
return [
|
|
val[0],
|
|
val[1],
|
|
val[0],
|
|
val[1]
|
|
];
|
|
} else if (len === 3) {
|
|
// top | horizontal | bottom
|
|
return [
|
|
val[0],
|
|
val[1],
|
|
val[2],
|
|
val[1]
|
|
];
|
|
}
|
|
return val;
|
|
}
|
|
/**
|
|
* @memberOf module:zrender/core/util
|
|
* @param {boolean} condition
|
|
* @param {string} message
|
|
*/
|
|
function assert(condition, message) {
|
|
if (!condition) {
|
|
throw new Error(message);
|
|
}
|
|
}
|
|
var primitiveKey = '__ec_primitive__';
|
|
/**
|
|
* Set an object as primitive to be ignored traversing children in clone or merge
|
|
*/
|
|
function setAsPrimitive(obj) {
|
|
obj[primitiveKey] = true;
|
|
}
|
|
function isPrimitive(obj) {
|
|
return obj[primitiveKey];
|
|
}
|
|
/**
|
|
* @constructor
|
|
* @param {Object} obj Only apply `ownProperty`.
|
|
*/
|
|
function HashMap(obj) {
|
|
obj && each(obj, function (value, key) {
|
|
this.set(key, value);
|
|
}, this);
|
|
}
|
|
// Add prefix to avoid conflict with Object.prototype.
|
|
var HASH_MAP_PREFIX = '_ec_';
|
|
var HASH_MAP_PREFIX_LENGTH = 4;
|
|
HashMap.prototype = {
|
|
constructor: HashMap,
|
|
get: function (key) {
|
|
return this[HASH_MAP_PREFIX + key];
|
|
},
|
|
set: function (key, value) {
|
|
this[HASH_MAP_PREFIX + key] = value;
|
|
// Comparing with invocation chaining, `return value` is more commonly
|
|
// used in this case: `var someVal = map.set('a', genVal());`
|
|
return value;
|
|
},
|
|
each: function (cb, context) {
|
|
context !== void 0 && (cb = bind(cb, context));
|
|
for (var prefixedKey in this) {
|
|
this.hasOwnProperty(prefixedKey) && cb(this[prefixedKey], prefixedKey.slice(HASH_MAP_PREFIX_LENGTH));
|
|
}
|
|
},
|
|
removeKey: function (key) {
|
|
delete this[HASH_MAP_PREFIX + key];
|
|
}
|
|
};
|
|
function createHashMap(obj) {
|
|
return new HashMap(obj);
|
|
}
|
|
var util = {
|
|
inherits: inherits,
|
|
mixin: mixin,
|
|
clone: clone,
|
|
merge: merge,
|
|
mergeAll: mergeAll,
|
|
extend: extend,
|
|
defaults: defaults,
|
|
getContext: getContext,
|
|
createCanvas: createCanvas,
|
|
indexOf: indexOf,
|
|
slice: slice,
|
|
find: find,
|
|
isArrayLike: isArrayLike,
|
|
each: each,
|
|
map: map,
|
|
reduce: reduce,
|
|
filter: filter,
|
|
bind: bind,
|
|
curry: curry,
|
|
isArray: isArray,
|
|
isString: isString,
|
|
isObject: isObject,
|
|
isFunction: isFunction,
|
|
isBuiltInObject: isBuiltInObject,
|
|
isDom: isDom,
|
|
eqNaN: eqNaN,
|
|
retrieve: retrieve,
|
|
retrieve2: retrieve2,
|
|
retrieve3: retrieve3,
|
|
assert: assert,
|
|
setAsPrimitive: setAsPrimitive,
|
|
createHashMap: createHashMap,
|
|
normalizeCssArray: normalizeCssArray,
|
|
noop: function () {
|
|
}
|
|
};
|
|
return util;
|
|
});
|
|
define('echarts/chart/bar/BarSeries', ['require', './BaseBarSeries'], function (require) {
|
|
return require('./BaseBarSeries').extend({
|
|
type: 'series.bar',
|
|
dependencies: [
|
|
'grid',
|
|
'polar'
|
|
],
|
|
brushSelector: 'rect'
|
|
});
|
|
});
|
|
define('echarts/chart/bar/BarView', ['require', 'zrender/core/util', '../../util/graphic', './helper', '../../model/Model', './barItemStyle', '../../echarts'], function (require) {
|
|
'use strict';
|
|
var zrUtil = require('zrender/core/util');
|
|
var graphic = require('../../util/graphic');
|
|
var helper = require('./helper');
|
|
var BAR_BORDER_WIDTH_QUERY = [
|
|
'itemStyle',
|
|
'normal',
|
|
'barBorderWidth'
|
|
];
|
|
// FIXME
|
|
// Just for compatible with ec2.
|
|
zrUtil.extend(require('../../model/Model').prototype, require('./barItemStyle'));
|
|
var BarView = require('../../echarts').extendChartView({
|
|
type: 'bar',
|
|
render: function (seriesModel, ecModel, api) {
|
|
var coordinateSystemType = seriesModel.get('coordinateSystem');
|
|
if (coordinateSystemType === 'cartesian2d' || coordinateSystemType === 'polar') {
|
|
this._render(seriesModel, ecModel, api);
|
|
} else if (true) {
|
|
console.warn('Only cartesian2d and polar supported for bar.');
|
|
}
|
|
return this.group;
|
|
},
|
|
dispose: zrUtil.noop,
|
|
_render: function (seriesModel, ecModel, api) {
|
|
var group = this.group;
|
|
var data = seriesModel.getData();
|
|
var oldData = this._data;
|
|
var coord = seriesModel.coordinateSystem;
|
|
var baseAxis = coord.getBaseAxis();
|
|
var isHorizontalOrRadial;
|
|
if (coord.type === 'cartesian2d') {
|
|
isHorizontalOrRadial = baseAxis.isHorizontal();
|
|
} else if (coord.type === 'polar') {
|
|
isHorizontalOrRadial = baseAxis.dim === 'angle';
|
|
}
|
|
var animationModel = seriesModel.isAnimationEnabled() ? seriesModel : null;
|
|
data.diff(oldData).add(function (dataIndex) {
|
|
if (!data.hasValue(dataIndex)) {
|
|
return;
|
|
}
|
|
var itemModel = data.getItemModel(dataIndex);
|
|
var layout = getLayout[coord.type](data, dataIndex, itemModel);
|
|
var el = elementCreator[coord.type](data, dataIndex, itemModel, layout, isHorizontalOrRadial, animationModel);
|
|
data.setItemGraphicEl(dataIndex, el);
|
|
group.add(el);
|
|
updateStyle(el, data, dataIndex, itemModel, layout, seriesModel, isHorizontalOrRadial, coord.type === 'polar');
|
|
}).update(function (newIndex, oldIndex) {
|
|
var el = oldData.getItemGraphicEl(oldIndex);
|
|
if (!data.hasValue(newIndex)) {
|
|
group.remove(el);
|
|
return;
|
|
}
|
|
var itemModel = data.getItemModel(newIndex);
|
|
var layout = getLayout[coord.type](data, newIndex, itemModel);
|
|
if (el) {
|
|
graphic.updateProps(el, { shape: layout }, animationModel, newIndex);
|
|
} else {
|
|
el = elementCreator[coord.type](data, newIndex, itemModel, layout, isHorizontalOrRadial, animationModel, true);
|
|
}
|
|
data.setItemGraphicEl(newIndex, el);
|
|
// Add back
|
|
group.add(el);
|
|
updateStyle(el, data, newIndex, itemModel, layout, seriesModel, isHorizontalOrRadial, coord.type === 'polar');
|
|
}).remove(function (dataIndex) {
|
|
var el = oldData.getItemGraphicEl(dataIndex);
|
|
if (coord.type === 'cartesian2d') {
|
|
el && removeRect(dataIndex, animationModel, el);
|
|
} else {
|
|
el && removeSector(dataIndex, animationModel, el);
|
|
}
|
|
}).execute();
|
|
this._data = data;
|
|
},
|
|
remove: function (ecModel, api) {
|
|
var group = this.group;
|
|
var data = this._data;
|
|
if (ecModel.get('animation')) {
|
|
if (data) {
|
|
data.eachItemGraphicEl(function (el) {
|
|
if (el.type === 'sector') {
|
|
removeSector(el.dataIndex, ecModel, el);
|
|
} else {
|
|
removeRect(el.dataIndex, ecModel, el);
|
|
}
|
|
});
|
|
}
|
|
} else {
|
|
group.removeAll();
|
|
}
|
|
}
|
|
});
|
|
var elementCreator = {
|
|
cartesian2d: function (data, dataIndex, itemModel, layout, isHorizontal, animationModel, isUpdate) {
|
|
var rect = new graphic.Rect({ shape: zrUtil.extend({}, layout) });
|
|
// Animation
|
|
if (animationModel) {
|
|
var rectShape = rect.shape;
|
|
var animateProperty = isHorizontal ? 'height' : 'width';
|
|
var animateTarget = {};
|
|
rectShape[animateProperty] = 0;
|
|
animateTarget[animateProperty] = layout[animateProperty];
|
|
graphic[isUpdate ? 'updateProps' : 'initProps'](rect, { shape: animateTarget }, animationModel, dataIndex);
|
|
}
|
|
return rect;
|
|
},
|
|
polar: function (data, dataIndex, itemModel, layout, isRadial, animationModel, isUpdate) {
|
|
var sector = new graphic.Sector({ shape: zrUtil.extend({}, layout) });
|
|
// Animation
|
|
if (animationModel) {
|
|
var sectorShape = sector.shape;
|
|
var animateProperty = isRadial ? 'r' : 'endAngle';
|
|
var animateTarget = {};
|
|
sectorShape[animateProperty] = isRadial ? 0 : layout.startAngle;
|
|
animateTarget[animateProperty] = layout[animateProperty];
|
|
graphic[isUpdate ? 'updateProps' : 'initProps'](sector, { shape: animateTarget }, animationModel, dataIndex);
|
|
}
|
|
return sector;
|
|
}
|
|
};
|
|
function removeRect(dataIndex, animationModel, el) {
|
|
// Not show text when animating
|
|
el.style.text = null;
|
|
graphic.updateProps(el, { shape: { width: 0 } }, animationModel, dataIndex, function () {
|
|
el.parent && el.parent.remove(el);
|
|
});
|
|
}
|
|
function removeSector(dataIndex, animationModel, el) {
|
|
// Not show text when animating
|
|
el.style.text = null;
|
|
graphic.updateProps(el, { shape: { r: el.shape.r0 } }, animationModel, dataIndex, function () {
|
|
el.parent && el.parent.remove(el);
|
|
});
|
|
}
|
|
var getLayout = {
|
|
cartesian2d: function (data, dataIndex, itemModel) {
|
|
var layout = data.getItemLayout(dataIndex);
|
|
var fixedLineWidth = getLineWidth(itemModel, layout);
|
|
// fix layout with lineWidth
|
|
var signX = layout.width > 0 ? 1 : -1;
|
|
var signY = layout.height > 0 ? 1 : -1;
|
|
return {
|
|
x: layout.x + signX * fixedLineWidth / 2,
|
|
y: layout.y + signY * fixedLineWidth / 2,
|
|
width: layout.width - signX * fixedLineWidth,
|
|
height: layout.height - signY * fixedLineWidth
|
|
};
|
|
},
|
|
polar: function (data, dataIndex, itemModel) {
|
|
var layout = data.getItemLayout(dataIndex);
|
|
return {
|
|
cx: layout.cx,
|
|
cy: layout.cy,
|
|
r0: layout.r0,
|
|
r: layout.r,
|
|
startAngle: layout.startAngle,
|
|
endAngle: layout.endAngle
|
|
};
|
|
}
|
|
};
|
|
function updateStyle(el, data, dataIndex, itemModel, layout, seriesModel, isHorizontal, isPolar) {
|
|
var color = data.getItemVisual(dataIndex, 'color');
|
|
var opacity = data.getItemVisual(dataIndex, 'opacity');
|
|
var itemStyleModel = itemModel.getModel('itemStyle.normal');
|
|
var hoverStyle = itemModel.getModel('itemStyle.emphasis').getBarItemStyle();
|
|
if (!isPolar) {
|
|
el.setShape('r', itemStyleModel.get('barBorderRadius') || 0);
|
|
}
|
|
el.useStyle(zrUtil.defaults({
|
|
fill: color,
|
|
opacity: opacity
|
|
}, itemStyleModel.getBarItemStyle()));
|
|
var cursorStyle = itemModel.getShallow('cursor');
|
|
cursorStyle && el.attr('cursor', cursorStyle);
|
|
var labelPositionOutside = isHorizontal ? layout.height > 0 ? 'bottom' : 'top' : layout.width > 0 ? 'left' : 'right';
|
|
if (!isPolar) {
|
|
helper.setLabel(el.style, hoverStyle, itemModel, color, seriesModel, dataIndex, labelPositionOutside);
|
|
}
|
|
graphic.setHoverStyle(el, hoverStyle);
|
|
}
|
|
// In case width or height are too small.
|
|
function getLineWidth(itemModel, rawLayout) {
|
|
var lineWidth = itemModel.get(BAR_BORDER_WIDTH_QUERY) || 0;
|
|
return Math.min(lineWidth, Math.abs(rawLayout.width), Math.abs(rawLayout.height));
|
|
}
|
|
return BarView;
|
|
});
|
|
define('echarts/layout/barGrid', ['require', 'zrender/core/util', '../util/number'], function (require) {
|
|
'use strict';
|
|
var zrUtil = require('zrender/core/util');
|
|
var numberUtil = require('../util/number');
|
|
var parsePercent = numberUtil.parsePercent;
|
|
var STACK_PREFIX = '__ec_stack_';
|
|
function getSeriesStackId(seriesModel) {
|
|
return seriesModel.get('stack') || STACK_PREFIX + seriesModel.seriesIndex;
|
|
}
|
|
function getAxisKey(axis) {
|
|
return axis.dim + axis.index;
|
|
}
|
|
/**
|
|
* @param {Object} opt
|
|
* @param {module:echarts/coord/Axis} opt.axis Only support category axis currently.
|
|
* @param {number} opt.count Positive interger.
|
|
* @param {number} [opt.barWidth]
|
|
* @param {number} [opt.barMaxWidth]
|
|
* @param {number} [opt.barGap]
|
|
* @param {number} [opt.barCategoryGap]
|
|
* @return {Object} {width, offset, offsetCenter} If axis.type is not 'category', return undefined.
|
|
*/
|
|
function getLayoutOnAxis(opt, api) {
|
|
var params = [];
|
|
var baseAxis = opt.axis;
|
|
var axisKey = 'axis0';
|
|
if (baseAxis.type !== 'category') {
|
|
return;
|
|
}
|
|
var bandWidth = baseAxis.getBandWidth();
|
|
for (var i = 0; i < opt.count || 0; i++) {
|
|
params.push(zrUtil.defaults({
|
|
bandWidth: bandWidth,
|
|
axisKey: axisKey,
|
|
stackId: STACK_PREFIX + i
|
|
}, opt));
|
|
}
|
|
var widthAndOffsets = doCalBarWidthAndOffset(params, api);
|
|
var result = [];
|
|
for (var i = 0; i < opt.count; i++) {
|
|
var item = widthAndOffsets[axisKey][STACK_PREFIX + i];
|
|
item.offsetCenter = item.offset + item.width / 2;
|
|
result.push(item);
|
|
}
|
|
return result;
|
|
}
|
|
function calBarWidthAndOffset(barSeries, api) {
|
|
var seriesInfoList = zrUtil.map(barSeries, function (seriesModel) {
|
|
var data = seriesModel.getData();
|
|
var cartesian = seriesModel.coordinateSystem;
|
|
var baseAxis = cartesian.getBaseAxis();
|
|
var axisExtent = baseAxis.getExtent();
|
|
var bandWidth = baseAxis.type === 'category' ? baseAxis.getBandWidth() : Math.abs(axisExtent[1] - axisExtent[0]) / data.count();
|
|
var barWidth = parsePercent(seriesModel.get('barWidth'), bandWidth);
|
|
var barMaxWidth = parsePercent(seriesModel.get('barMaxWidth'), bandWidth);
|
|
var barGap = seriesModel.get('barGap');
|
|
var barCategoryGap = seriesModel.get('barCategoryGap');
|
|
return {
|
|
bandWidth: bandWidth,
|
|
barWidth: barWidth,
|
|
barMaxWidth: barMaxWidth,
|
|
barGap: barGap,
|
|
barCategoryGap: barCategoryGap,
|
|
axisKey: getAxisKey(baseAxis),
|
|
stackId: getSeriesStackId(seriesModel)
|
|
};
|
|
});
|
|
return doCalBarWidthAndOffset(seriesInfoList, api);
|
|
}
|
|
function doCalBarWidthAndOffset(seriesInfoList, api) {
|
|
// Columns info on each category axis. Key is cartesian name
|
|
var columnsMap = {};
|
|
zrUtil.each(seriesInfoList, function (seriesInfo, idx) {
|
|
var axisKey = seriesInfo.axisKey;
|
|
var bandWidth = seriesInfo.bandWidth;
|
|
var columnsOnAxis = columnsMap[axisKey] || {
|
|
bandWidth: bandWidth,
|
|
remainedWidth: bandWidth,
|
|
autoWidthCount: 0,
|
|
categoryGap: '20%',
|
|
gap: '30%',
|
|
stacks: {}
|
|
};
|
|
var stacks = columnsOnAxis.stacks;
|
|
columnsMap[axisKey] = columnsOnAxis;
|
|
var stackId = seriesInfo.stackId;
|
|
if (!stacks[stackId]) {
|
|
columnsOnAxis.autoWidthCount++;
|
|
}
|
|
stacks[stackId] = stacks[stackId] || {
|
|
width: 0,
|
|
maxWidth: 0
|
|
};
|
|
// Caution: In a single coordinate system, these barGrid attributes
|
|
// will be shared by series. Consider that they have default values,
|
|
// only the attributes set on the last series will work.
|
|
// Do not change this fact unless there will be a break change.
|
|
// TODO
|
|
var barWidth = seriesInfo.barWidth;
|
|
if (barWidth && !stacks[stackId].width) {
|
|
// See #6312, do not restrict width.
|
|
stacks[stackId].width = barWidth;
|
|
barWidth = Math.min(columnsOnAxis.remainedWidth, barWidth);
|
|
columnsOnAxis.remainedWidth -= barWidth;
|
|
}
|
|
var barMaxWidth = seriesInfo.barMaxWidth;
|
|
barMaxWidth && (stacks[stackId].maxWidth = barMaxWidth);
|
|
var barGap = seriesInfo.barGap;
|
|
barGap != null && (columnsOnAxis.gap = barGap);
|
|
var barCategoryGap = seriesInfo.barCategoryGap;
|
|
barCategoryGap != null && (columnsOnAxis.categoryGap = barCategoryGap);
|
|
});
|
|
var result = {};
|
|
zrUtil.each(columnsMap, function (columnsOnAxis, coordSysName) {
|
|
result[coordSysName] = {};
|
|
var stacks = columnsOnAxis.stacks;
|
|
var bandWidth = columnsOnAxis.bandWidth;
|
|
var categoryGap = parsePercent(columnsOnAxis.categoryGap, bandWidth);
|
|
var barGapPercent = parsePercent(columnsOnAxis.gap, 1);
|
|
var remainedWidth = columnsOnAxis.remainedWidth;
|
|
var autoWidthCount = columnsOnAxis.autoWidthCount;
|
|
var autoWidth = (remainedWidth - categoryGap) / (autoWidthCount + (autoWidthCount - 1) * barGapPercent);
|
|
autoWidth = Math.max(autoWidth, 0);
|
|
// Find if any auto calculated bar exceeded maxBarWidth
|
|
zrUtil.each(stacks, function (column, stack) {
|
|
var maxWidth = column.maxWidth;
|
|
if (maxWidth && maxWidth < autoWidth) {
|
|
maxWidth = Math.min(maxWidth, remainedWidth);
|
|
if (column.width) {
|
|
maxWidth = Math.min(maxWidth, column.width);
|
|
}
|
|
remainedWidth -= maxWidth;
|
|
column.width = maxWidth;
|
|
autoWidthCount--;
|
|
}
|
|
});
|
|
// Recalculate width again
|
|
autoWidth = (remainedWidth - categoryGap) / (autoWidthCount + (autoWidthCount - 1) * barGapPercent);
|
|
autoWidth = Math.max(autoWidth, 0);
|
|
var widthSum = 0;
|
|
var lastColumn;
|
|
zrUtil.each(stacks, function (column, idx) {
|
|
if (!column.width) {
|
|
column.width = autoWidth;
|
|
}
|
|
lastColumn = column;
|
|
widthSum += column.width * (1 + barGapPercent);
|
|
});
|
|
if (lastColumn) {
|
|
widthSum -= lastColumn.width * barGapPercent;
|
|
}
|
|
var offset = -widthSum / 2;
|
|
zrUtil.each(stacks, function (column, stackId) {
|
|
result[coordSysName][stackId] = result[coordSysName][stackId] || {
|
|
offset: offset,
|
|
width: column.width
|
|
};
|
|
offset += column.width * (1 + barGapPercent);
|
|
});
|
|
});
|
|
return result;
|
|
}
|
|
/**
|
|
* @param {string} seriesType
|
|
* @param {module:echarts/model/Global} ecModel
|
|
* @param {module:echarts/ExtensionAPI} api
|
|
*/
|
|
function barLayoutGrid(seriesType, ecModel, api) {
|
|
var barWidthAndOffset = calBarWidthAndOffset(zrUtil.filter(ecModel.getSeriesByType(seriesType), function (seriesModel) {
|
|
return !ecModel.isSeriesFiltered(seriesModel) && seriesModel.coordinateSystem && seriesModel.coordinateSystem.type === 'cartesian2d';
|
|
}));
|
|
var lastStackCoords = {};
|
|
var lastStackCoordsOrigin = {};
|
|
ecModel.eachSeriesByType(seriesType, function (seriesModel) {
|
|
// Check series coordinate, do layout for cartesian2d only
|
|
if (seriesModel.coordinateSystem.type !== 'cartesian2d') {
|
|
return;
|
|
}
|
|
var data = seriesModel.getData();
|
|
var cartesian = seriesModel.coordinateSystem;
|
|
var baseAxis = cartesian.getBaseAxis();
|
|
var stackId = getSeriesStackId(seriesModel);
|
|
var columnLayoutInfo = barWidthAndOffset[getAxisKey(baseAxis)][stackId];
|
|
var columnOffset = columnLayoutInfo.offset;
|
|
var columnWidth = columnLayoutInfo.width;
|
|
var valueAxis = cartesian.getOtherAxis(baseAxis);
|
|
var barMinHeight = seriesModel.get('barMinHeight') || 0;
|
|
var valueAxisStart = baseAxis.onZero ? valueAxis.toGlobalCoord(valueAxis.dataToCoord(0)) : valueAxis.getGlobalExtent()[0];
|
|
var coordDims = [
|
|
seriesModel.coordDimToDataDim('x')[0],
|
|
seriesModel.coordDimToDataDim('y')[0]
|
|
];
|
|
var coords = data.mapArray(coordDims, function (x, y) {
|
|
return cartesian.dataToPoint([
|
|
x,
|
|
y
|
|
]);
|
|
}, true);
|
|
lastStackCoords[stackId] = lastStackCoords[stackId] || [];
|
|
lastStackCoordsOrigin[stackId] = lastStackCoordsOrigin[stackId] || [];
|
|
// Fix #4243
|
|
data.setLayout({
|
|
offset: columnOffset,
|
|
size: columnWidth
|
|
});
|
|
data.each(seriesModel.coordDimToDataDim(valueAxis.dim)[0], function (value, idx) {
|
|
if (isNaN(value)) {
|
|
return;
|
|
}
|
|
if (!lastStackCoords[stackId][idx]) {
|
|
lastStackCoords[stackId][idx] = {
|
|
p: valueAxisStart,
|
|
n: valueAxisStart
|
|
};
|
|
lastStackCoordsOrigin[stackId][idx] = {
|
|
p: valueAxisStart,
|
|
n: valueAxisStart
|
|
};
|
|
}
|
|
var sign = value >= 0 ? 'p' : 'n';
|
|
var coord = coords[idx];
|
|
var lastCoord = lastStackCoords[stackId][idx][sign];
|
|
var lastCoordOrigin = lastStackCoordsOrigin[stackId][idx][sign];
|
|
var x;
|
|
var y;
|
|
var width;
|
|
var height;
|
|
if (valueAxis.isHorizontal()) {
|
|
x = lastCoord;
|
|
y = coord[1] + columnOffset;
|
|
width = coord[0] - lastCoordOrigin;
|
|
height = columnWidth;
|
|
lastStackCoordsOrigin[stackId][idx][sign] += width;
|
|
if (Math.abs(width) < barMinHeight) {
|
|
width = (width < 0 ? -1 : 1) * barMinHeight;
|
|
}
|
|
lastStackCoords[stackId][idx][sign] += width;
|
|
} else {
|
|
x = coord[0] + columnOffset;
|
|
y = lastCoord;
|
|
width = columnWidth;
|
|
height = coord[1] - lastCoordOrigin;
|
|
lastStackCoordsOrigin[stackId][idx][sign] += height;
|
|
if (Math.abs(height) < barMinHeight) {
|
|
// Include zero to has a positive bar
|
|
height = (height <= 0 ? -1 : 1) * barMinHeight;
|
|
}
|
|
lastStackCoords[stackId][idx][sign] += height;
|
|
}
|
|
data.setItemLayout(idx, {
|
|
x: x,
|
|
y: y,
|
|
width: width,
|
|
height: height
|
|
});
|
|
}, true);
|
|
}, this);
|
|
}
|
|
barLayoutGrid.getLayoutOnAxis = getLayoutOnAxis;
|
|
return barLayoutGrid;
|
|
});
|
|
define('echarts/chart/line/LineSeries', ['require', '../helper/createListFromArray', '../../model/Series'], function (require) {
|
|
'use strict';
|
|
var createListFromArray = require('../helper/createListFromArray');
|
|
var SeriesModel = require('../../model/Series');
|
|
return SeriesModel.extend({
|
|
type: 'series.line',
|
|
dependencies: [
|
|
'grid',
|
|
'polar'
|
|
],
|
|
getInitialData: function (option, ecModel) {
|
|
if (true) {
|
|
var coordSys = option.coordinateSystem;
|
|
if (coordSys !== 'polar' && coordSys !== 'cartesian2d') {
|
|
throw new Error('Line not support coordinateSystem besides cartesian and polar');
|
|
}
|
|
}
|
|
return createListFromArray(option.data, this, ecModel);
|
|
},
|
|
defaultOption: {
|
|
zlevel: 0,
|
|
z: 2,
|
|
coordinateSystem: 'cartesian2d',
|
|
legendHoverLink: true,
|
|
hoverAnimation: true,
|
|
clipOverflow: true,
|
|
label: { normal: { position: 'top' } },
|
|
lineStyle: {
|
|
normal: {
|
|
width: 2,
|
|
type: 'solid'
|
|
}
|
|
},
|
|
step: false,
|
|
smooth: false,
|
|
smoothMonotone: null,
|
|
symbol: 'emptyCircle',
|
|
symbolSize: 4,
|
|
symbolRotate: null,
|
|
showSymbol: true,
|
|
showAllSymbol: false,
|
|
connectNulls: false,
|
|
sampling: 'none',
|
|
animationEasing: 'linear',
|
|
progressive: 0,
|
|
hoverLayerThreshold: Infinity
|
|
}
|
|
});
|
|
});
|
|
define('echarts/visual/symbol', ['require'], function (require) {
|
|
return function (seriesType, defaultSymbolType, legendSymbol, ecModel, api) {
|
|
// Encoding visual for all series include which is filtered for legend drawing
|
|
ecModel.eachRawSeriesByType(seriesType, function (seriesModel) {
|
|
var data = seriesModel.getData();
|
|
var symbolType = seriesModel.get('symbol') || defaultSymbolType;
|
|
var symbolSize = seriesModel.get('symbolSize');
|
|
data.setVisual({
|
|
legendSymbol: legendSymbol || symbolType,
|
|
symbol: symbolType,
|
|
symbolSize: symbolSize
|
|
});
|
|
// Only visible series has each data be visual encoded
|
|
if (!ecModel.isSeriesFiltered(seriesModel)) {
|
|
if (typeof symbolSize === 'function') {
|
|
data.each(function (idx) {
|
|
var rawValue = seriesModel.getRawValue(idx);
|
|
// FIXME
|
|
var params = seriesModel.getDataParams(idx);
|
|
data.setItemVisual(idx, 'symbolSize', symbolSize(rawValue, params));
|
|
});
|
|
}
|
|
data.each(function (idx) {
|
|
var itemModel = data.getItemModel(idx);
|
|
var itemSymbolType = itemModel.getShallow('symbol', true);
|
|
var itemSymbolSize = itemModel.getShallow('symbolSize', true);
|
|
// If has item symbol
|
|
if (itemSymbolType != null) {
|
|
data.setItemVisual(idx, 'symbol', itemSymbolType);
|
|
}
|
|
if (itemSymbolSize != null) {
|
|
// PENDING Transform symbolSize ?
|
|
data.setItemVisual(idx, 'symbolSize', itemSymbolSize);
|
|
}
|
|
});
|
|
}
|
|
});
|
|
};
|
|
});
|
|
define('echarts/chart/line/LineView', ['require', 'zrender/core/util', '../helper/SymbolDraw', '../helper/Symbol', './lineAnimationDiff', '../../util/graphic', '../../util/model', './poly', '../../view/Chart'], function (require) {
|
|
'use strict';
|
|
var zrUtil = require('zrender/core/util');
|
|
var SymbolDraw = require('../helper/SymbolDraw');
|
|
var Symbol = require('../helper/Symbol');
|
|
var lineAnimationDiff = require('./lineAnimationDiff');
|
|
var graphic = require('../../util/graphic');
|
|
var modelUtil = require('../../util/model');
|
|
var polyHelper = require('./poly');
|
|
var ChartView = require('../../view/Chart');
|
|
function isPointsSame(points1, points2) {
|
|
if (points1.length !== points2.length) {
|
|
return;
|
|
}
|
|
for (var i = 0; i < points1.length; i++) {
|
|
var p1 = points1[i];
|
|
var p2 = points2[i];
|
|
if (p1[0] !== p2[0] || p1[1] !== p2[1]) {
|
|
return;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
function getSmooth(smooth) {
|
|
return typeof smooth === 'number' ? smooth : smooth ? 0.3 : 0;
|
|
}
|
|
function getAxisExtentWithGap(axis) {
|
|
var extent = axis.getGlobalExtent();
|
|
if (axis.onBand) {
|
|
// Remove extra 1px to avoid line miter in clipped edge
|
|
var halfBandWidth = axis.getBandWidth() / 2 - 1;
|
|
var dir = extent[1] > extent[0] ? 1 : -1;
|
|
extent[0] += dir * halfBandWidth;
|
|
extent[1] -= dir * halfBandWidth;
|
|
}
|
|
return extent;
|
|
}
|
|
function sign(val) {
|
|
return val >= 0 ? 1 : -1;
|
|
}
|
|
/**
|
|
* @param {module:echarts/coord/cartesian/Cartesian2D|module:echarts/coord/polar/Polar} coordSys
|
|
* @param {module:echarts/data/List} data
|
|
* @param {Array.<Array.<number>>} points
|
|
* @private
|
|
*/
|
|
function getStackedOnPoints(coordSys, data) {
|
|
var baseAxis = coordSys.getBaseAxis();
|
|
var valueAxis = coordSys.getOtherAxis(baseAxis);
|
|
var valueStart = 0;
|
|
if (!baseAxis.onZero) {
|
|
var extent = valueAxis.scale.getExtent();
|
|
if (extent[0] > 0) {
|
|
// Both positive
|
|
valueStart = extent[0];
|
|
} else if (extent[1] < 0) {
|
|
// Both negative
|
|
valueStart = extent[1];
|
|
} // If is one positive, and one negative, onZero shall be true
|
|
}
|
|
var valueDim = valueAxis.dim;
|
|
var baseDataOffset = valueDim === 'x' || valueDim === 'radius' ? 1 : 0;
|
|
return data.mapArray([valueDim], function (val, idx) {
|
|
var stackedOnSameSign;
|
|
var stackedOn = data.stackedOn;
|
|
// Find first stacked value with same sign
|
|
while (stackedOn && sign(stackedOn.get(valueDim, idx)) === sign(val)) {
|
|
stackedOnSameSign = stackedOn;
|
|
break;
|
|
}
|
|
var stackedData = [];
|
|
stackedData[baseDataOffset] = data.get(baseAxis.dim, idx);
|
|
stackedData[1 - baseDataOffset] = stackedOnSameSign ? stackedOnSameSign.get(valueDim, idx, true) : valueStart;
|
|
return coordSys.dataToPoint(stackedData);
|
|
}, true);
|
|
}
|
|
function createGridClipShape(cartesian, hasAnimation, seriesModel) {
|
|
var xExtent = getAxisExtentWithGap(cartesian.getAxis('x'));
|
|
var yExtent = getAxisExtentWithGap(cartesian.getAxis('y'));
|
|
var isHorizontal = cartesian.getBaseAxis().isHorizontal();
|
|
var x = Math.min(xExtent[0], xExtent[1]);
|
|
var y = Math.min(yExtent[0], yExtent[1]);
|
|
var width = Math.max(xExtent[0], xExtent[1]) - x;
|
|
var height = Math.max(yExtent[0], yExtent[1]) - y;
|
|
var lineWidth = seriesModel.get('lineStyle.normal.width') || 2;
|
|
// Expand clip shape to avoid clipping when line value exceeds axis
|
|
var expandSize = seriesModel.get('clipOverflow') ? lineWidth / 2 : Math.max(width, height);
|
|
if (isHorizontal) {
|
|
y -= expandSize;
|
|
height += expandSize * 2;
|
|
} else {
|
|
x -= expandSize;
|
|
width += expandSize * 2;
|
|
}
|
|
var clipPath = new graphic.Rect({
|
|
shape: {
|
|
x: x,
|
|
y: y,
|
|
width: width,
|
|
height: height
|
|
}
|
|
});
|
|
if (hasAnimation) {
|
|
clipPath.shape[isHorizontal ? 'width' : 'height'] = 0;
|
|
graphic.initProps(clipPath, {
|
|
shape: {
|
|
width: width,
|
|
height: height
|
|
}
|
|
}, seriesModel);
|
|
}
|
|
return clipPath;
|
|
}
|
|
function createPolarClipShape(polar, hasAnimation, seriesModel) {
|
|
var angleAxis = polar.getAngleAxis();
|
|
var radiusAxis = polar.getRadiusAxis();
|
|
var radiusExtent = radiusAxis.getExtent();
|
|
var angleExtent = angleAxis.getExtent();
|
|
var RADIAN = Math.PI / 180;
|
|
var clipPath = new graphic.Sector({
|
|
shape: {
|
|
cx: polar.cx,
|
|
cy: polar.cy,
|
|
r0: radiusExtent[0],
|
|
r: radiusExtent[1],
|
|
startAngle: -angleExtent[0] * RADIAN,
|
|
endAngle: -angleExtent[1] * RADIAN,
|
|
clockwise: angleAxis.inverse
|
|
}
|
|
});
|
|
if (hasAnimation) {
|
|
clipPath.shape.endAngle = -angleExtent[0] * RADIAN;
|
|
graphic.initProps(clipPath, { shape: { endAngle: -angleExtent[1] * RADIAN } }, seriesModel);
|
|
}
|
|
return clipPath;
|
|
}
|
|
function createClipShape(coordSys, hasAnimation, seriesModel) {
|
|
return coordSys.type === 'polar' ? createPolarClipShape(coordSys, hasAnimation, seriesModel) : createGridClipShape(coordSys, hasAnimation, seriesModel);
|
|
}
|
|
function turnPointsIntoStep(points, coordSys, stepTurnAt) {
|
|
var baseAxis = coordSys.getBaseAxis();
|
|
var baseIndex = baseAxis.dim === 'x' || baseAxis.dim === 'radius' ? 0 : 1;
|
|
var stepPoints = [];
|
|
for (var i = 0; i < points.length - 1; i++) {
|
|
var nextPt = points[i + 1];
|
|
var pt = points[i];
|
|
stepPoints.push(pt);
|
|
var stepPt = [];
|
|
switch (stepTurnAt) {
|
|
case 'end':
|
|
stepPt[baseIndex] = nextPt[baseIndex];
|
|
stepPt[1 - baseIndex] = pt[1 - baseIndex];
|
|
// default is start
|
|
stepPoints.push(stepPt);
|
|
break;
|
|
case 'middle':
|
|
// default is start
|
|
var middle = (pt[baseIndex] + nextPt[baseIndex]) / 2;
|
|
var stepPt2 = [];
|
|
stepPt[baseIndex] = stepPt2[baseIndex] = middle;
|
|
stepPt[1 - baseIndex] = pt[1 - baseIndex];
|
|
stepPt2[1 - baseIndex] = nextPt[1 - baseIndex];
|
|
stepPoints.push(stepPt);
|
|
stepPoints.push(stepPt2);
|
|
break;
|
|
default:
|
|
stepPt[baseIndex] = pt[baseIndex];
|
|
stepPt[1 - baseIndex] = nextPt[1 - baseIndex];
|
|
// default is start
|
|
stepPoints.push(stepPt);
|
|
}
|
|
}
|
|
// Last points
|
|
points[i] && stepPoints.push(points[i]);
|
|
return stepPoints;
|
|
}
|
|
function getVisualGradient(data, coordSys) {
|
|
var visualMetaList = data.getVisual('visualMeta');
|
|
if (!visualMetaList || !visualMetaList.length || !data.count()) {
|
|
// When data.count() is 0, gradient range can not be calculated.
|
|
return;
|
|
}
|
|
var visualMeta;
|
|
for (var i = visualMetaList.length - 1; i >= 0; i--) {
|
|
// Can only be x or y
|
|
if (visualMetaList[i].dimension < 2) {
|
|
visualMeta = visualMetaList[i];
|
|
break;
|
|
}
|
|
}
|
|
if (!visualMeta || coordSys.type !== 'cartesian2d') {
|
|
if (true) {
|
|
console.warn('Visual map on line style only support x or y dimension.');
|
|
}
|
|
return;
|
|
}
|
|
// If the area to be rendered is bigger than area defined by LinearGradient,
|
|
// the canvas spec prescribes that the color of the first stop and the last
|
|
// stop should be used. But if two stops are added at offset 0, in effect
|
|
// browsers use the color of the second stop to render area outside
|
|
// LinearGradient. So we can only infinitesimally extend area defined in
|
|
// LinearGradient to render `outerColors`.
|
|
var dimension = visualMeta.dimension;
|
|
var dimName = data.dimensions[dimension];
|
|
var axis = coordSys.getAxis(dimName);
|
|
// dataToCoor mapping may not be linear, but must be monotonic.
|
|
var colorStops = zrUtil.map(visualMeta.stops, function (stop) {
|
|
return {
|
|
coord: axis.toGlobalCoord(axis.dataToCoord(stop.value)),
|
|
color: stop.color
|
|
};
|
|
});
|
|
var stopLen = colorStops.length;
|
|
var outerColors = visualMeta.outerColors.slice();
|
|
if (stopLen && colorStops[0].coord > colorStops[stopLen - 1].coord) {
|
|
colorStops.reverse();
|
|
outerColors.reverse();
|
|
}
|
|
var tinyExtent = 10;
|
|
// Arbitrary value: 10px
|
|
var minCoord = colorStops[0].coord - tinyExtent;
|
|
var maxCoord = colorStops[stopLen - 1].coord + tinyExtent;
|
|
var coordSpan = maxCoord - minCoord;
|
|
if (coordSpan < 0.001) {
|
|
return 'transparent';
|
|
}
|
|
zrUtil.each(colorStops, function (stop) {
|
|
stop.offset = (stop.coord - minCoord) / coordSpan;
|
|
});
|
|
colorStops.push({
|
|
offset: stopLen ? colorStops[stopLen - 1].offset : 0.5,
|
|
color: outerColors[1] || 'transparent'
|
|
});
|
|
colorStops.unshift({
|
|
offset: stopLen ? colorStops[0].offset : 0.5,
|
|
color: outerColors[0] || 'transparent'
|
|
});
|
|
// zrUtil.each(colorStops, function (colorStop) {
|
|
// // Make sure each offset has rounded px to avoid not sharp edge
|
|
// colorStop.offset = (Math.round(colorStop.offset * (end - start) + start) - start) / (end - start);
|
|
// });
|
|
var gradient = new graphic.LinearGradient(0, 0, 0, 0, colorStops, true);
|
|
gradient[dimName] = minCoord;
|
|
gradient[dimName + '2'] = maxCoord;
|
|
return gradient;
|
|
}
|
|
return ChartView.extend({
|
|
type: 'line',
|
|
init: function () {
|
|
var lineGroup = new graphic.Group();
|
|
var symbolDraw = new SymbolDraw();
|
|
this.group.add(symbolDraw.group);
|
|
this._symbolDraw = symbolDraw;
|
|
this._lineGroup = lineGroup;
|
|
},
|
|
render: function (seriesModel, ecModel, api) {
|
|
var coordSys = seriesModel.coordinateSystem;
|
|
var group = this.group;
|
|
var data = seriesModel.getData();
|
|
var lineStyleModel = seriesModel.getModel('lineStyle.normal');
|
|
var areaStyleModel = seriesModel.getModel('areaStyle.normal');
|
|
var points = data.mapArray(data.getItemLayout, true);
|
|
var isCoordSysPolar = coordSys.type === 'polar';
|
|
var prevCoordSys = this._coordSys;
|
|
var symbolDraw = this._symbolDraw;
|
|
var polyline = this._polyline;
|
|
var polygon = this._polygon;
|
|
var lineGroup = this._lineGroup;
|
|
var hasAnimation = seriesModel.get('animation');
|
|
var isAreaChart = !areaStyleModel.isEmpty();
|
|
var stackedOnPoints = getStackedOnPoints(coordSys, data);
|
|
var showSymbol = seriesModel.get('showSymbol');
|
|
var isSymbolIgnore = showSymbol && !isCoordSysPolar && !seriesModel.get('showAllSymbol') && this._getSymbolIgnoreFunc(data, coordSys);
|
|
// Remove temporary symbols
|
|
var oldData = this._data;
|
|
oldData && oldData.eachItemGraphicEl(function (el, idx) {
|
|
if (el.__temp) {
|
|
group.remove(el);
|
|
oldData.setItemGraphicEl(idx, null);
|
|
}
|
|
});
|
|
// Remove previous created symbols if showSymbol changed to false
|
|
if (!showSymbol) {
|
|
symbolDraw.remove();
|
|
}
|
|
group.add(lineGroup);
|
|
// FIXME step not support polar
|
|
var step = !isCoordSysPolar && seriesModel.get('step');
|
|
// Initialization animation or coordinate system changed
|
|
if (!(polyline && prevCoordSys.type === coordSys.type && step === this._step)) {
|
|
showSymbol && symbolDraw.updateData(data, isSymbolIgnore);
|
|
if (step) {
|
|
// TODO If stacked series is not step
|
|
points = turnPointsIntoStep(points, coordSys, step);
|
|
stackedOnPoints = turnPointsIntoStep(stackedOnPoints, coordSys, step);
|
|
}
|
|
polyline = this._newPolyline(points, coordSys, hasAnimation);
|
|
if (isAreaChart) {
|
|
polygon = this._newPolygon(points, stackedOnPoints, coordSys, hasAnimation);
|
|
}
|
|
lineGroup.setClipPath(createClipShape(coordSys, true, seriesModel));
|
|
} else {
|
|
if (isAreaChart && !polygon) {
|
|
// If areaStyle is added
|
|
polygon = this._newPolygon(points, stackedOnPoints, coordSys, hasAnimation);
|
|
} else if (polygon && !isAreaChart) {
|
|
// If areaStyle is removed
|
|
lineGroup.remove(polygon);
|
|
polygon = this._polygon = null;
|
|
}
|
|
// Update clipPath
|
|
lineGroup.setClipPath(createClipShape(coordSys, false, seriesModel));
|
|
// Always update, or it is wrong in the case turning on legend
|
|
// because points are not changed
|
|
showSymbol && symbolDraw.updateData(data, isSymbolIgnore);
|
|
// Stop symbol animation and sync with line points
|
|
// FIXME performance?
|
|
data.eachItemGraphicEl(function (el) {
|
|
el.stopAnimation(true);
|
|
});
|
|
// In the case data zoom triggerred refreshing frequently
|
|
// Data may not change if line has a category axis. So it should animate nothing
|
|
if (!isPointsSame(this._stackedOnPoints, stackedOnPoints) || !isPointsSame(this._points, points)) {
|
|
if (hasAnimation) {
|
|
this._updateAnimation(data, stackedOnPoints, coordSys, api, step);
|
|
} else {
|
|
// Not do it in update with animation
|
|
if (step) {
|
|
// TODO If stacked series is not step
|
|
points = turnPointsIntoStep(points, coordSys, step);
|
|
stackedOnPoints = turnPointsIntoStep(stackedOnPoints, coordSys, step);
|
|
}
|
|
polyline.setShape({ points: points });
|
|
polygon && polygon.setShape({
|
|
points: points,
|
|
stackedOnPoints: stackedOnPoints
|
|
});
|
|
}
|
|
}
|
|
}
|
|
var visualColor = getVisualGradient(data, coordSys) || data.getVisual('color');
|
|
polyline.useStyle(zrUtil.defaults(lineStyleModel.getLineStyle(), {
|
|
fill: 'none',
|
|
stroke: visualColor,
|
|
lineJoin: 'bevel'
|
|
}));
|
|
var smooth = seriesModel.get('smooth');
|
|
smooth = getSmooth(seriesModel.get('smooth'));
|
|
polyline.setShape({
|
|
smooth: smooth,
|
|
smoothMonotone: seriesModel.get('smoothMonotone'),
|
|
connectNulls: seriesModel.get('connectNulls')
|
|
});
|
|
if (polygon) {
|
|
var stackedOn = data.stackedOn;
|
|
var stackedOnSmooth = 0;
|
|
polygon.useStyle(zrUtil.defaults(areaStyleModel.getAreaStyle(), {
|
|
fill: visualColor,
|
|
opacity: 0.7,
|
|
lineJoin: 'bevel'
|
|
}));
|
|
if (stackedOn) {
|
|
var stackedOnSeries = stackedOn.hostModel;
|
|
stackedOnSmooth = getSmooth(stackedOnSeries.get('smooth'));
|
|
}
|
|
polygon.setShape({
|
|
smooth: smooth,
|
|
stackedOnSmooth: stackedOnSmooth,
|
|
smoothMonotone: seriesModel.get('smoothMonotone'),
|
|
connectNulls: seriesModel.get('connectNulls')
|
|
});
|
|
}
|
|
this._data = data;
|
|
// Save the coordinate system for transition animation when data changed
|
|
this._coordSys = coordSys;
|
|
this._stackedOnPoints = stackedOnPoints;
|
|
this._points = points;
|
|
this._step = step;
|
|
},
|
|
dispose: function () {
|
|
},
|
|
highlight: function (seriesModel, ecModel, api, payload) {
|
|
var data = seriesModel.getData();
|
|
var dataIndex = modelUtil.queryDataIndex(data, payload);
|
|
if (!(dataIndex instanceof Array) && dataIndex != null && dataIndex >= 0) {
|
|
var symbol = data.getItemGraphicEl(dataIndex);
|
|
if (!symbol) {
|
|
// Create a temporary symbol if it is not exists
|
|
var pt = data.getItemLayout(dataIndex);
|
|
if (!pt) {
|
|
// Null data
|
|
return;
|
|
}
|
|
symbol = new Symbol(data, dataIndex);
|
|
symbol.position = pt;
|
|
symbol.setZ(seriesModel.get('zlevel'), seriesModel.get('z'));
|
|
symbol.ignore = isNaN(pt[0]) || isNaN(pt[1]);
|
|
symbol.__temp = true;
|
|
data.setItemGraphicEl(dataIndex, symbol);
|
|
// Stop scale animation
|
|
symbol.stopSymbolAnimation(true);
|
|
this.group.add(symbol);
|
|
}
|
|
symbol.highlight();
|
|
} else {
|
|
// Highlight whole series
|
|
ChartView.prototype.highlight.call(this, seriesModel, ecModel, api, payload);
|
|
}
|
|
},
|
|
downplay: function (seriesModel, ecModel, api, payload) {
|
|
var data = seriesModel.getData();
|
|
var dataIndex = modelUtil.queryDataIndex(data, payload);
|
|
if (dataIndex != null && dataIndex >= 0) {
|
|
var symbol = data.getItemGraphicEl(dataIndex);
|
|
if (symbol) {
|
|
if (symbol.__temp) {
|
|
data.setItemGraphicEl(dataIndex, null);
|
|
this.group.remove(symbol);
|
|
} else {
|
|
symbol.downplay();
|
|
}
|
|
}
|
|
} else {
|
|
// FIXME
|
|
// can not downplay completely.
|
|
// Downplay whole series
|
|
ChartView.prototype.downplay.call(this, seriesModel, ecModel, api, payload);
|
|
}
|
|
},
|
|
_newPolyline: function (points) {
|
|
var polyline = this._polyline;
|
|
// Remove previous created polyline
|
|
if (polyline) {
|
|
this._lineGroup.remove(polyline);
|
|
}
|
|
polyline = new polyHelper.Polyline({
|
|
shape: { points: points },
|
|
silent: true,
|
|
z2: 10
|
|
});
|
|
this._lineGroup.add(polyline);
|
|
this._polyline = polyline;
|
|
return polyline;
|
|
},
|
|
_newPolygon: function (points, stackedOnPoints) {
|
|
var polygon = this._polygon;
|
|
// Remove previous created polygon
|
|
if (polygon) {
|
|
this._lineGroup.remove(polygon);
|
|
}
|
|
polygon = new polyHelper.Polygon({
|
|
shape: {
|
|
points: points,
|
|
stackedOnPoints: stackedOnPoints
|
|
},
|
|
silent: true
|
|
});
|
|
this._lineGroup.add(polygon);
|
|
this._polygon = polygon;
|
|
return polygon;
|
|
},
|
|
_getSymbolIgnoreFunc: function (data, coordSys) {
|
|
var categoryAxis = coordSys.getAxesByScale('ordinal')[0];
|
|
// `getLabelInterval` is provided by echarts/component/axis
|
|
if (categoryAxis && categoryAxis.isLabelIgnored) {
|
|
return zrUtil.bind(categoryAxis.isLabelIgnored, categoryAxis);
|
|
}
|
|
},
|
|
_updateAnimation: function (data, stackedOnPoints, coordSys, api, step) {
|
|
var polyline = this._polyline;
|
|
var polygon = this._polygon;
|
|
var seriesModel = data.hostModel;
|
|
var diff = lineAnimationDiff(this._data, data, this._stackedOnPoints, stackedOnPoints, this._coordSys, coordSys);
|
|
var current = diff.current;
|
|
var stackedOnCurrent = diff.stackedOnCurrent;
|
|
var next = diff.next;
|
|
var stackedOnNext = diff.stackedOnNext;
|
|
if (step) {
|
|
// TODO If stacked series is not step
|
|
current = turnPointsIntoStep(diff.current, coordSys, step);
|
|
stackedOnCurrent = turnPointsIntoStep(diff.stackedOnCurrent, coordSys, step);
|
|
next = turnPointsIntoStep(diff.next, coordSys, step);
|
|
stackedOnNext = turnPointsIntoStep(diff.stackedOnNext, coordSys, step);
|
|
}
|
|
// `diff.current` is subset of `current` (which should be ensured by
|
|
// turnPointsIntoStep), so points in `__points` can be updated when
|
|
// points in `current` are update during animation.
|
|
polyline.shape.__points = diff.current;
|
|
polyline.shape.points = current;
|
|
graphic.updateProps(polyline, { shape: { points: next } }, seriesModel);
|
|
if (polygon) {
|
|
polygon.setShape({
|
|
points: current,
|
|
stackedOnPoints: stackedOnCurrent
|
|
});
|
|
graphic.updateProps(polygon, {
|
|
shape: {
|
|
points: next,
|
|
stackedOnPoints: stackedOnNext
|
|
}
|
|
}, seriesModel);
|
|
}
|
|
var updatedDataInfo = [];
|
|
var diffStatus = diff.status;
|
|
for (var i = 0; i < diffStatus.length; i++) {
|
|
var cmd = diffStatus[i].cmd;
|
|
if (cmd === '=') {
|
|
var el = data.getItemGraphicEl(diffStatus[i].idx1);
|
|
if (el) {
|
|
updatedDataInfo.push({
|
|
el: el,
|
|
ptIdx: i
|
|
});
|
|
}
|
|
}
|
|
}
|
|
if (polyline.animators && polyline.animators.length) {
|
|
polyline.animators[0].during(function () {
|
|
for (var i = 0; i < updatedDataInfo.length; i++) {
|
|
var el = updatedDataInfo[i].el;
|
|
el.attr('position', polyline.shape.__points[updatedDataInfo[i].ptIdx]);
|
|
}
|
|
});
|
|
}
|
|
},
|
|
remove: function (ecModel) {
|
|
var group = this.group;
|
|
var oldData = this._data;
|
|
this._lineGroup.removeAll();
|
|
this._symbolDraw.remove(true);
|
|
// Remove temporary created elements when highlighting
|
|
oldData && oldData.eachItemGraphicEl(function (el, idx) {
|
|
if (el.__temp) {
|
|
group.remove(el);
|
|
oldData.setItemGraphicEl(idx, null);
|
|
}
|
|
});
|
|
this._polyline = this._polygon = this._coordSys = this._points = this._stackedOnPoints = this._data = null;
|
|
}
|
|
});
|
|
});
|
|
define('echarts/layout/points', ['require'], function (require) {
|
|
return function (seriesType, ecModel) {
|
|
ecModel.eachSeriesByType(seriesType, function (seriesModel) {
|
|
var data = seriesModel.getData();
|
|
var coordSys = seriesModel.coordinateSystem;
|
|
if (!coordSys) {
|
|
return;
|
|
}
|
|
var dims = [];
|
|
var coordDims = coordSys.dimensions;
|
|
for (var i = 0; i < coordDims.length; i++) {
|
|
dims.push(seriesModel.coordDimToDataDim(coordSys.dimensions[i])[0]);
|
|
}
|
|
if (dims.length === 1) {
|
|
data.each(dims[0], function (x, idx) {
|
|
// Also {Array.<number>}, not undefined to avoid if...else... statement
|
|
data.setItemLayout(idx, isNaN(x) ? [
|
|
NaN,
|
|
NaN
|
|
] : coordSys.dataToPoint(x));
|
|
});
|
|
} else if (dims.length === 2) {
|
|
data.each(dims, function (x, y, idx) {
|
|
// Also {Array.<number>}, not undefined to avoid if...else... statement
|
|
data.setItemLayout(idx, isNaN(x) || isNaN(y) ? [
|
|
NaN,
|
|
NaN
|
|
] : coordSys.dataToPoint([
|
|
x,
|
|
y
|
|
]));
|
|
}, true);
|
|
}
|
|
});
|
|
};
|
|
});
|
|
define('echarts/processor/dataSample', [], function () {
|
|
var samplers = {
|
|
average: function (frame) {
|
|
var sum = 0;
|
|
var count = 0;
|
|
for (var i = 0; i < frame.length; i++) {
|
|
if (!isNaN(frame[i])) {
|
|
sum += frame[i];
|
|
count++;
|
|
}
|
|
}
|
|
// Return NaN if count is 0
|
|
return count === 0 ? NaN : sum / count;
|
|
},
|
|
sum: function (frame) {
|
|
var sum = 0;
|
|
for (var i = 0; i < frame.length; i++) {
|
|
// Ignore NaN
|
|
sum += frame[i] || 0;
|
|
}
|
|
return sum;
|
|
},
|
|
max: function (frame) {
|
|
var max = -Infinity;
|
|
for (var i = 0; i < frame.length; i++) {
|
|
frame[i] > max && (max = frame[i]);
|
|
}
|
|
return max;
|
|
},
|
|
min: function (frame) {
|
|
var min = Infinity;
|
|
for (var i = 0; i < frame.length; i++) {
|
|
frame[i] < min && (min = frame[i]);
|
|
}
|
|
return min;
|
|
},
|
|
nearest: function (frame) {
|
|
return frame[0];
|
|
}
|
|
};
|
|
var indexSampler = function (frame, value) {
|
|
return Math.round(frame.length / 2);
|
|
};
|
|
return function (seriesType, ecModel, api) {
|
|
ecModel.eachSeriesByType(seriesType, function (seriesModel) {
|
|
var data = seriesModel.getData();
|
|
var sampling = seriesModel.get('sampling');
|
|
var coordSys = seriesModel.coordinateSystem;
|
|
// Only cartesian2d support down sampling
|
|
if (coordSys.type === 'cartesian2d' && sampling) {
|
|
var baseAxis = coordSys.getBaseAxis();
|
|
var valueAxis = coordSys.getOtherAxis(baseAxis);
|
|
var extent = baseAxis.getExtent();
|
|
// Coordinste system has been resized
|
|
var size = extent[1] - extent[0];
|
|
var rate = Math.round(data.count() / size);
|
|
if (rate > 1) {
|
|
var sampler;
|
|
if (typeof sampling === 'string') {
|
|
sampler = samplers[sampling];
|
|
} else if (typeof sampling === 'function') {
|
|
sampler = sampling;
|
|
}
|
|
if (sampler) {
|
|
data = data.downSample(valueAxis.dim, 1 / rate, sampler, indexSampler);
|
|
seriesModel.setData(data);
|
|
}
|
|
}
|
|
}
|
|
}, this);
|
|
};
|
|
});
|
|
define('echarts/chart/pie/PieSeries', ['require', '../../data/List', 'zrender/core/util', '../../util/model', '../../util/number', '../../data/helper/completeDimensions', '../../component/helper/selectableMixin', '../../echarts'], function (require) {
|
|
'use strict';
|
|
var List = require('../../data/List');
|
|
var zrUtil = require('zrender/core/util');
|
|
var modelUtil = require('../../util/model');
|
|
var numberUtil = require('../../util/number');
|
|
var completeDimensions = require('../../data/helper/completeDimensions');
|
|
var dataSelectableMixin = require('../../component/helper/selectableMixin');
|
|
var PieSeries = require('../../echarts').extendSeriesModel({
|
|
type: 'series.pie',
|
|
init: function (option) {
|
|
PieSeries.superApply(this, 'init', arguments);
|
|
// Enable legend selection for each data item
|
|
// Use a function instead of direct access because data reference may changed
|
|
this.legendDataProvider = function () {
|
|
return this.getRawData();
|
|
};
|
|
this.updateSelectedMap(option.data);
|
|
this._defaultLabelLine(option);
|
|
},
|
|
mergeOption: function (newOption) {
|
|
PieSeries.superCall(this, 'mergeOption', newOption);
|
|
this.updateSelectedMap(this.option.data);
|
|
},
|
|
getInitialData: function (option, ecModel) {
|
|
var dimensions = completeDimensions(['value'], option.data);
|
|
var list = new List(dimensions, this);
|
|
list.initData(option.data);
|
|
return list;
|
|
},
|
|
getDataParams: function (dataIndex) {
|
|
var data = this.getData();
|
|
var params = PieSeries.superCall(this, 'getDataParams', dataIndex);
|
|
// FIXME toFixed?
|
|
var valueList = [];
|
|
data.each('value', function (value) {
|
|
valueList.push(value);
|
|
});
|
|
params.percent = numberUtil.getPercentWithPrecision(valueList, dataIndex, data.hostModel.get('percentPrecision'));
|
|
params.$vars.push('percent');
|
|
return params;
|
|
},
|
|
_defaultLabelLine: function (option) {
|
|
// Extend labelLine emphasis
|
|
modelUtil.defaultEmphasis(option.labelLine, ['show']);
|
|
var labelLineNormalOpt = option.labelLine.normal;
|
|
var labelLineEmphasisOpt = option.labelLine.emphasis;
|
|
// Not show label line if `label.normal.show = false`
|
|
labelLineNormalOpt.show = labelLineNormalOpt.show && option.label.normal.show;
|
|
labelLineEmphasisOpt.show = labelLineEmphasisOpt.show && option.label.emphasis.show;
|
|
},
|
|
defaultOption: {
|
|
zlevel: 0,
|
|
z: 2,
|
|
legendHoverLink: true,
|
|
hoverAnimation: true,
|
|
center: [
|
|
'50%',
|
|
'50%'
|
|
],
|
|
radius: [
|
|
0,
|
|
'75%'
|
|
],
|
|
clockwise: true,
|
|
startAngle: 90,
|
|
minAngle: 0,
|
|
selectedOffset: 10,
|
|
hoverOffset: 10,
|
|
avoidLabelOverlap: true,
|
|
percentPrecision: 2,
|
|
stillShowZeroSum: true,
|
|
label: {
|
|
normal: {
|
|
rotate: false,
|
|
show: true,
|
|
position: 'outer'
|
|
},
|
|
emphasis: {}
|
|
},
|
|
labelLine: {
|
|
normal: {
|
|
show: true,
|
|
length: 15,
|
|
length2: 15,
|
|
smooth: false,
|
|
lineStyle: {
|
|
width: 1,
|
|
type: 'solid'
|
|
}
|
|
}
|
|
},
|
|
itemStyle: {
|
|
normal: { borderWidth: 1 },
|
|
emphasis: {}
|
|
},
|
|
animationType: 'expansion',
|
|
animationEasing: 'cubicOut',
|
|
data: []
|
|
}
|
|
});
|
|
zrUtil.mixin(PieSeries, dataSelectableMixin);
|
|
return PieSeries;
|
|
});
|
|
define('echarts/chart/pie/PieView', ['require', '../../util/graphic', 'zrender/core/util', '../../view/Chart'], function (require) {
|
|
var graphic = require('../../util/graphic');
|
|
var zrUtil = require('zrender/core/util');
|
|
/**
|
|
* @param {module:echarts/model/Series} seriesModel
|
|
* @param {boolean} hasAnimation
|
|
* @inner
|
|
*/
|
|
function updateDataSelected(uid, seriesModel, hasAnimation, api) {
|
|
var data = seriesModel.getData();
|
|
var dataIndex = this.dataIndex;
|
|
var name = data.getName(dataIndex);
|
|
var selectedOffset = seriesModel.get('selectedOffset');
|
|
api.dispatchAction({
|
|
type: 'pieToggleSelect',
|
|
from: uid,
|
|
name: name,
|
|
seriesId: seriesModel.id
|
|
});
|
|
data.each(function (idx) {
|
|
toggleItemSelected(data.getItemGraphicEl(idx), data.getItemLayout(idx), seriesModel.isSelected(data.getName(idx)), selectedOffset, hasAnimation);
|
|
});
|
|
}
|
|
/**
|
|
* @param {module:zrender/graphic/Sector} el
|
|
* @param {Object} layout
|
|
* @param {boolean} isSelected
|
|
* @param {number} selectedOffset
|
|
* @param {boolean} hasAnimation
|
|
* @inner
|
|
*/
|
|
function toggleItemSelected(el, layout, isSelected, selectedOffset, hasAnimation) {
|
|
var midAngle = (layout.startAngle + layout.endAngle) / 2;
|
|
var dx = Math.cos(midAngle);
|
|
var dy = Math.sin(midAngle);
|
|
var offset = isSelected ? selectedOffset : 0;
|
|
var position = [
|
|
dx * offset,
|
|
dy * offset
|
|
];
|
|
hasAnimation ? el.animate().when(200, { position: position }).start('bounceOut') : el.attr('position', position);
|
|
}
|
|
/**
|
|
* Piece of pie including Sector, Label, LabelLine
|
|
* @constructor
|
|
* @extends {module:zrender/graphic/Group}
|
|
*/
|
|
function PiePiece(data, idx) {
|
|
graphic.Group.call(this);
|
|
var sector = new graphic.Sector({ z2: 2 });
|
|
var polyline = new graphic.Polyline();
|
|
var text = new graphic.Text();
|
|
this.add(sector);
|
|
this.add(polyline);
|
|
this.add(text);
|
|
this.updateData(data, idx, true);
|
|
// Hover to change label and labelLine
|
|
function onEmphasis() {
|
|
polyline.ignore = polyline.hoverIgnore;
|
|
text.ignore = text.hoverIgnore;
|
|
}
|
|
function onNormal() {
|
|
polyline.ignore = polyline.normalIgnore;
|
|
text.ignore = text.normalIgnore;
|
|
}
|
|
this.on('emphasis', onEmphasis).on('normal', onNormal).on('mouseover', onEmphasis).on('mouseout', onNormal);
|
|
}
|
|
var piePieceProto = PiePiece.prototype;
|
|
piePieceProto.updateData = function (data, idx, firstCreate) {
|
|
var sector = this.childAt(0);
|
|
var seriesModel = data.hostModel;
|
|
var itemModel = data.getItemModel(idx);
|
|
var layout = data.getItemLayout(idx);
|
|
var sectorShape = zrUtil.extend({}, layout);
|
|
sectorShape.label = null;
|
|
if (firstCreate) {
|
|
sector.setShape(sectorShape);
|
|
var animationType = seriesModel.getShallow('animationType');
|
|
if (animationType === 'scale') {
|
|
sector.shape.r = layout.r0;
|
|
graphic.initProps(sector, { shape: { r: layout.r } }, seriesModel, idx);
|
|
} // Expansion
|
|
else {
|
|
sector.shape.endAngle = layout.startAngle;
|
|
graphic.updateProps(sector, { shape: { endAngle: layout.endAngle } }, seriesModel, idx);
|
|
}
|
|
} else {
|
|
graphic.updateProps(sector, { shape: sectorShape }, seriesModel, idx);
|
|
}
|
|
// Update common style
|
|
var itemStyleModel = itemModel.getModel('itemStyle');
|
|
var visualColor = data.getItemVisual(idx, 'color');
|
|
sector.useStyle(zrUtil.defaults({
|
|
lineJoin: 'bevel',
|
|
fill: visualColor
|
|
}, itemStyleModel.getModel('normal').getItemStyle()));
|
|
sector.hoverStyle = itemStyleModel.getModel('emphasis').getItemStyle();
|
|
var cursorStyle = itemModel.getShallow('cursor');
|
|
cursorStyle && sector.attr('cursor', cursorStyle);
|
|
// Toggle selected
|
|
toggleItemSelected(this, data.getItemLayout(idx), itemModel.get('selected'), seriesModel.get('selectedOffset'), seriesModel.get('animation'));
|
|
function onEmphasis() {
|
|
// Sector may has animation of updating data. Force to move to the last frame
|
|
// Or it may stopped on the wrong shape
|
|
sector.stopAnimation(true);
|
|
sector.animateTo({ shape: { r: layout.r + seriesModel.get('hoverOffset') } }, 300, 'elasticOut');
|
|
}
|
|
function onNormal() {
|
|
sector.stopAnimation(true);
|
|
sector.animateTo({ shape: { r: layout.r } }, 300, 'elasticOut');
|
|
}
|
|
sector.off('mouseover').off('mouseout').off('emphasis').off('normal');
|
|
if (itemModel.get('hoverAnimation') && seriesModel.isAnimationEnabled()) {
|
|
sector.on('mouseover', onEmphasis).on('mouseout', onNormal).on('emphasis', onEmphasis).on('normal', onNormal);
|
|
}
|
|
this._updateLabel(data, idx);
|
|
graphic.setHoverStyle(this);
|
|
};
|
|
piePieceProto._updateLabel = function (data, idx) {
|
|
var labelLine = this.childAt(1);
|
|
var labelText = this.childAt(2);
|
|
var seriesModel = data.hostModel;
|
|
var itemModel = data.getItemModel(idx);
|
|
var layout = data.getItemLayout(idx);
|
|
var labelLayout = layout.label;
|
|
var visualColor = data.getItemVisual(idx, 'color');
|
|
graphic.updateProps(labelLine, {
|
|
shape: {
|
|
points: labelLayout.linePoints || [
|
|
[
|
|
labelLayout.x,
|
|
labelLayout.y
|
|
],
|
|
[
|
|
labelLayout.x,
|
|
labelLayout.y
|
|
],
|
|
[
|
|
labelLayout.x,
|
|
labelLayout.y
|
|
]
|
|
]
|
|
}
|
|
}, seriesModel, idx);
|
|
graphic.updateProps(labelText, {
|
|
style: {
|
|
x: labelLayout.x,
|
|
y: labelLayout.y
|
|
}
|
|
}, seriesModel, idx);
|
|
labelText.attr({
|
|
rotation: labelLayout.rotation,
|
|
origin: [
|
|
labelLayout.x,
|
|
labelLayout.y
|
|
],
|
|
z2: 10
|
|
});
|
|
var labelModel = itemModel.getModel('label.normal');
|
|
var labelHoverModel = itemModel.getModel('label.emphasis');
|
|
var labelLineModel = itemModel.getModel('labelLine.normal');
|
|
var labelLineHoverModel = itemModel.getModel('labelLine.emphasis');
|
|
var visualColor = data.getItemVisual(idx, 'color');
|
|
graphic.setLabelStyle(labelText.style, labelText.hoverStyle = {}, labelModel, labelHoverModel, {
|
|
labelFetcher: data.hostModel,
|
|
labelDataIndex: idx,
|
|
defaultText: data.getName(idx),
|
|
autoColor: visualColor,
|
|
useInsideStyle: !!labelLayout.inside
|
|
}, {
|
|
textAlign: labelLayout.textAlign,
|
|
textVerticalAlign: labelLayout.verticalAlign,
|
|
opacity: data.getItemVisual(idx, 'opacity')
|
|
});
|
|
labelText.ignore = labelText.normalIgnore = !labelModel.get('show');
|
|
labelText.hoverIgnore = !labelHoverModel.get('show');
|
|
labelLine.ignore = labelLine.normalIgnore = !labelLineModel.get('show');
|
|
labelLine.hoverIgnore = !labelLineHoverModel.get('show');
|
|
// Default use item visual color
|
|
labelLine.setStyle({
|
|
stroke: visualColor,
|
|
opacity: data.getItemVisual(idx, 'opacity')
|
|
});
|
|
labelLine.setStyle(labelLineModel.getModel('lineStyle').getLineStyle());
|
|
labelLine.hoverStyle = labelLineHoverModel.getModel('lineStyle').getLineStyle();
|
|
var smooth = labelLineModel.get('smooth');
|
|
if (smooth && smooth === true) {
|
|
smooth = 0.4;
|
|
}
|
|
labelLine.setShape({ smooth: smooth });
|
|
};
|
|
zrUtil.inherits(PiePiece, graphic.Group);
|
|
// Pie view
|
|
var Pie = require('../../view/Chart').extend({
|
|
type: 'pie',
|
|
init: function () {
|
|
var sectorGroup = new graphic.Group();
|
|
this._sectorGroup = sectorGroup;
|
|
},
|
|
render: function (seriesModel, ecModel, api, payload) {
|
|
if (payload && payload.from === this.uid) {
|
|
return;
|
|
}
|
|
var data = seriesModel.getData();
|
|
var oldData = this._data;
|
|
var group = this.group;
|
|
var hasAnimation = ecModel.get('animation');
|
|
var isFirstRender = !oldData;
|
|
var animationType = seriesModel.get('animationType');
|
|
var onSectorClick = zrUtil.curry(updateDataSelected, this.uid, seriesModel, hasAnimation, api);
|
|
var selectedMode = seriesModel.get('selectedMode');
|
|
data.diff(oldData).add(function (idx) {
|
|
var piePiece = new PiePiece(data, idx);
|
|
// Default expansion animation
|
|
if (isFirstRender && animationType !== 'scale') {
|
|
piePiece.eachChild(function (child) {
|
|
child.stopAnimation(true);
|
|
});
|
|
}
|
|
selectedMode && piePiece.on('click', onSectorClick);
|
|
data.setItemGraphicEl(idx, piePiece);
|
|
group.add(piePiece);
|
|
}).update(function (newIdx, oldIdx) {
|
|
var piePiece = oldData.getItemGraphicEl(oldIdx);
|
|
piePiece.updateData(data, newIdx);
|
|
piePiece.off('click');
|
|
selectedMode && piePiece.on('click', onSectorClick);
|
|
group.add(piePiece);
|
|
data.setItemGraphicEl(newIdx, piePiece);
|
|
}).remove(function (idx) {
|
|
var piePiece = oldData.getItemGraphicEl(idx);
|
|
group.remove(piePiece);
|
|
}).execute();
|
|
if (hasAnimation && isFirstRender && data.count() > 0 && animationType !== 'scale') {
|
|
var shape = data.getItemLayout(0);
|
|
var r = Math.max(api.getWidth(), api.getHeight()) / 2;
|
|
var removeClipPath = zrUtil.bind(group.removeClipPath, group);
|
|
group.setClipPath(this._createClipPath(shape.cx, shape.cy, r, shape.startAngle, shape.clockwise, removeClipPath, seriesModel));
|
|
}
|
|
this._data = data;
|
|
},
|
|
dispose: function () {
|
|
},
|
|
_createClipPath: function (cx, cy, r, startAngle, clockwise, cb, seriesModel) {
|
|
var clipPath = new graphic.Sector({
|
|
shape: {
|
|
cx: cx,
|
|
cy: cy,
|
|
r0: 0,
|
|
r: r,
|
|
startAngle: startAngle,
|
|
endAngle: startAngle,
|
|
clockwise: clockwise
|
|
}
|
|
});
|
|
graphic.initProps(clipPath, { shape: { endAngle: startAngle + (clockwise ? 1 : -1) * Math.PI * 2 } }, seriesModel, cb);
|
|
return clipPath;
|
|
},
|
|
containPoint: function (point, seriesModel) {
|
|
var data = seriesModel.getData();
|
|
var itemLayout = data.getItemLayout(0);
|
|
if (itemLayout) {
|
|
var dx = point[0] - itemLayout.cx;
|
|
var dy = point[1] - itemLayout.cy;
|
|
var radius = Math.sqrt(dx * dx + dy * dy);
|
|
return radius <= itemLayout.r && radius >= itemLayout.r0;
|
|
}
|
|
}
|
|
});
|
|
return Pie;
|
|
});
|
|
define('echarts/action/createDataSelectAction', ['require', '../echarts', 'zrender/core/util'], function (require) {
|
|
var echarts = require('../echarts');
|
|
var zrUtil = require('zrender/core/util');
|
|
return function (seriesType, actionInfos) {
|
|
zrUtil.each(actionInfos, function (actionInfo) {
|
|
actionInfo.update = 'updateView';
|
|
/**
|
|
* @payload
|
|
* @property {string} seriesName
|
|
* @property {string} name
|
|
*/
|
|
echarts.registerAction(actionInfo, function (payload, ecModel) {
|
|
var selected = {};
|
|
ecModel.eachComponent({
|
|
mainType: 'series',
|
|
subType: seriesType,
|
|
query: payload
|
|
}, function (seriesModel) {
|
|
if (seriesModel[actionInfo.method]) {
|
|
seriesModel[actionInfo.method](payload.name, payload.dataIndex);
|
|
}
|
|
var data = seriesModel.getData();
|
|
// Create selected map
|
|
data.each(function (idx) {
|
|
var name = data.getName(idx);
|
|
selected[name] = seriesModel.isSelected(name) || false;
|
|
});
|
|
});
|
|
return {
|
|
name: payload.name,
|
|
selected: selected
|
|
};
|
|
});
|
|
});
|
|
};
|
|
});
|
|
define('echarts/chart/custom', ['require', '../echarts', 'zrender/core/util', '../util/graphic', './helper/labelHelper', './helper/createListFromArray', '../layout/barGrid', '../data/DataDiffer', '../coord/cartesian/prepareCustom', '../coord/geo/prepareCustom', '../coord/single/prepareCustom', '../coord/polar/prepareCustom', '../coord/calendar/prepareCustom'], function (require) {
|
|
var echarts = require('../echarts');
|
|
var zrUtil = require('zrender/core/util');
|
|
var graphicUtil = require('../util/graphic');
|
|
var labelHelper = require('./helper/labelHelper');
|
|
var createListFromArray = require('./helper/createListFromArray');
|
|
var barGrid = require('../layout/barGrid');
|
|
var DataDiffer = require('../data/DataDiffer');
|
|
var ITEM_STYLE_NORMAL_PATH = [
|
|
'itemStyle',
|
|
'normal'
|
|
];
|
|
var ITEM_STYLE_EMPHASIS_PATH = [
|
|
'itemStyle',
|
|
'emphasis'
|
|
];
|
|
var LABEL_NORMAL = [
|
|
'label',
|
|
'normal'
|
|
];
|
|
var LABEL_EMPHASIS = [
|
|
'label',
|
|
'emphasis'
|
|
];
|
|
// Use prefix to avoid index to be the same as el.name,
|
|
// which will cause weird udpate animation.
|
|
var GROUP_DIFF_PREFIX = 'e ';
|
|
/**
|
|
* To reduce total package size of each coordinate systems, the modules `prepareCustom`
|
|
* of each coordinate systems are not required by each coordinate systems directly, but
|
|
* required by the module `custom`.
|
|
*
|
|
* prepareInfoForCustomSeries {Function}: optional
|
|
* @return {Object} {coordSys: {...}, api: {
|
|
* coord: function (data, clamp) {}, // return point in global.
|
|
* size: function (dataSize, dataItem) {} // return size of each axis in coordSys.
|
|
* }}
|
|
*/
|
|
var prepareCustoms = {
|
|
cartesian2d: require('../coord/cartesian/prepareCustom'),
|
|
geo: require('../coord/geo/prepareCustom'),
|
|
singleAxis: require('../coord/single/prepareCustom'),
|
|
polar: require('../coord/polar/prepareCustom'),
|
|
calendar: require('../coord/calendar/prepareCustom')
|
|
};
|
|
// ------
|
|
// Model
|
|
// ------
|
|
echarts.extendSeriesModel({
|
|
type: 'series.custom',
|
|
dependencies: [
|
|
'grid',
|
|
'polar',
|
|
'geo',
|
|
'singleAxis',
|
|
'calendar'
|
|
],
|
|
defaultOption: {
|
|
coordinateSystem: 'cartesian2d',
|
|
zlevel: 0,
|
|
z: 2,
|
|
legendHoverLink: true
|
|
},
|
|
getInitialData: function (option, ecModel) {
|
|
return createListFromArray(option.data, this, ecModel);
|
|
}
|
|
});
|
|
// -----
|
|
// View
|
|
// -----
|
|
echarts.extendChartView({
|
|
type: 'custom',
|
|
_data: null,
|
|
render: function (customSeries, ecModel, api) {
|
|
var oldData = this._data;
|
|
var data = customSeries.getData();
|
|
var group = this.group;
|
|
var renderItem = makeRenderItem(customSeries, data, ecModel, api);
|
|
data.diff(oldData).add(function (newIdx) {
|
|
data.hasValue(newIdx) && createOrUpdate(null, newIdx, renderItem(newIdx), customSeries, group, data);
|
|
}).update(function (newIdx, oldIdx) {
|
|
var el = oldData.getItemGraphicEl(oldIdx);
|
|
data.hasValue(newIdx) ? createOrUpdate(el, newIdx, renderItem(newIdx), customSeries, group, data) : el && group.remove(el);
|
|
}).remove(function (oldIdx) {
|
|
var el = oldData.getItemGraphicEl(oldIdx);
|
|
el && group.remove(el);
|
|
}).execute();
|
|
this._data = data;
|
|
},
|
|
dispose: zrUtil.noop
|
|
});
|
|
function createEl(elOption) {
|
|
var graphicType = elOption.type;
|
|
var el;
|
|
if (graphicType === 'path') {
|
|
var shape = elOption.shape;
|
|
el = graphicUtil.makePath(shape.pathData, null, {
|
|
x: shape.x || 0,
|
|
y: shape.y || 0,
|
|
width: shape.width || 0,
|
|
height: shape.height || 0
|
|
}, 'center');
|
|
el.__customPathData = elOption.pathData;
|
|
} else if (graphicType === 'image') {
|
|
el = new graphicUtil.Image({});
|
|
el.__customImagePath = elOption.style.image;
|
|
} else if (graphicType === 'text') {
|
|
el = new graphicUtil.Text({});
|
|
el.__customText = elOption.style.text;
|
|
} else {
|
|
var Clz = graphicUtil[graphicType.charAt(0).toUpperCase() + graphicType.slice(1)];
|
|
if (true) {
|
|
zrUtil.assert(Clz, 'graphic type "' + graphicType + '" can not be found.');
|
|
}
|
|
el = new Clz();
|
|
}
|
|
el.__customGraphicType = graphicType;
|
|
el.name = elOption.name;
|
|
return el;
|
|
}
|
|
function updateEl(el, dataIndex, elOption, animatableModel, data, isInit) {
|
|
var targetProps = {};
|
|
var elOptionStyle = elOption.style || {};
|
|
elOption.shape && (targetProps.shape = zrUtil.clone(elOption.shape));
|
|
elOption.position && (targetProps.position = elOption.position.slice());
|
|
elOption.scale && (targetProps.scale = elOption.scale.slice());
|
|
elOption.origin && (targetProps.origin = elOption.origin.slice());
|
|
elOption.rotation && (targetProps.rotation = elOption.rotation);
|
|
if (el.type === 'image' && elOption.style) {
|
|
var targetStyle = targetProps.style = {};
|
|
zrUtil.each([
|
|
'x',
|
|
'y',
|
|
'width',
|
|
'height'
|
|
], function (prop) {
|
|
prepareStyleTransition(prop, targetStyle, elOptionStyle, el.style, isInit);
|
|
});
|
|
}
|
|
if (el.type === 'text' && elOption.style) {
|
|
var targetStyle = targetProps.style = {};
|
|
zrUtil.each([
|
|
'x',
|
|
'y'
|
|
], function (prop) {
|
|
prepareStyleTransition(prop, targetStyle, elOptionStyle, el.style, isInit);
|
|
});
|
|
// Compatible with previous: both support
|
|
// textFill and fill, textStroke and stroke in 'text' element.
|
|
!elOptionStyle.hasOwnProperty('textFill') && elOptionStyle.fill && (elOptionStyle.textFill = elOptionStyle.fill);
|
|
!elOptionStyle.hasOwnProperty('textStroke') && elOptionStyle.stroke && (elOptionStyle.textStroke = elOptionStyle.stroke);
|
|
}
|
|
if (el.type !== 'group') {
|
|
el.useStyle(elOptionStyle);
|
|
// Init animation.
|
|
if (isInit) {
|
|
el.style.opacity = 0;
|
|
var targetOpacity = elOptionStyle.opacity;
|
|
targetOpacity == null && (targetOpacity = 1);
|
|
graphicUtil.initProps(el, { style: { opacity: targetOpacity } }, animatableModel, dataIndex);
|
|
}
|
|
}
|
|
if (isInit) {
|
|
el.attr(targetProps);
|
|
} else {
|
|
graphicUtil.updateProps(el, targetProps, animatableModel, dataIndex);
|
|
}
|
|
// z2 must not be null/undefined, otherwise sort error may occur.
|
|
el.attr({
|
|
z2: elOption.z2 || 0,
|
|
silent: elOption.silent
|
|
});
|
|
elOption.styleEmphasis !== false && graphicUtil.setHoverStyle(el, elOption.styleEmphasis);
|
|
}
|
|
function prepareStyleTransition(prop, targetStyle, elOptionStyle, oldElStyle, isInit) {
|
|
if (elOptionStyle[prop] != null && !isInit) {
|
|
targetStyle[prop] = elOptionStyle[prop];
|
|
elOptionStyle[prop] = oldElStyle[prop];
|
|
}
|
|
}
|
|
function makeRenderItem(customSeries, data, ecModel, api) {
|
|
var renderItem = customSeries.get('renderItem');
|
|
var coordSys = customSeries.coordinateSystem;
|
|
var prepareResult = {};
|
|
if (coordSys) {
|
|
if (true) {
|
|
zrUtil.assert(renderItem, 'series.render is required.');
|
|
zrUtil.assert(coordSys.prepareCustoms || prepareCustoms[coordSys.type], 'This coordSys does not support custom series.');
|
|
}
|
|
prepareResult = coordSys.prepareCustoms ? coordSys.prepareCustoms() : prepareCustoms[coordSys.type](coordSys);
|
|
}
|
|
var userAPI = zrUtil.defaults({
|
|
getWidth: api.getWidth,
|
|
getHeight: api.getHeight,
|
|
getZr: api.getZr,
|
|
getDevicePixelRatio: api.getDevicePixelRatio,
|
|
value: value,
|
|
style: style,
|
|
styleEmphasis: styleEmphasis,
|
|
visual: visual,
|
|
barLayout: barLayout,
|
|
currentSeriesIndices: currentSeriesIndices,
|
|
font: font
|
|
}, prepareResult.api || {});
|
|
var userParams = {
|
|
context: {},
|
|
seriesId: customSeries.id,
|
|
seriesName: customSeries.name,
|
|
seriesIndex: customSeries.seriesIndex,
|
|
coordSys: prepareResult.coordSys,
|
|
dataInsideLength: data.count(),
|
|
encode: wrapEncodeDef(customSeries.getData())
|
|
};
|
|
// Do not support call `api` asynchronously without dataIndexInside input.
|
|
var currDataIndexInside;
|
|
var currDirty = true;
|
|
var currItemModel;
|
|
var currLabelNormalModel;
|
|
var currLabelEmphasisModel;
|
|
var currLabelValueDim;
|
|
var currVisualColor;
|
|
return function (dataIndexInside) {
|
|
currDataIndexInside = dataIndexInside;
|
|
currDirty = true;
|
|
return renderItem && renderItem(zrUtil.defaults({
|
|
dataIndexInside: dataIndexInside,
|
|
dataIndex: data.getRawIndex(dataIndexInside)
|
|
}, userParams), userAPI) || {};
|
|
};
|
|
// Do not update cache until api called.
|
|
function updateCache(dataIndexInside) {
|
|
dataIndexInside == null && (dataIndexInside = currDataIndexInside);
|
|
if (currDirty) {
|
|
currItemModel = data.getItemModel(dataIndexInside);
|
|
currLabelNormalModel = currItemModel.getModel(LABEL_NORMAL);
|
|
currLabelEmphasisModel = currItemModel.getModel(LABEL_EMPHASIS);
|
|
currLabelValueDim = labelHelper.findLabelValueDim(data);
|
|
currVisualColor = data.getItemVisual(dataIndexInside, 'color');
|
|
currDirty = false;
|
|
}
|
|
}
|
|
/**
|
|
* @public
|
|
* @param {number|string} dim
|
|
* @param {number} [dataIndexInside=currDataIndexInside]
|
|
* @return {number|string} value
|
|
*/
|
|
function value(dim, dataIndexInside) {
|
|
dataIndexInside == null && (dataIndexInside = currDataIndexInside);
|
|
return data.get(data.getDimension(dim || 0), dataIndexInside);
|
|
}
|
|
/**
|
|
* By default, `visual` is applied to style (to support visualMap).
|
|
* `visual.color` is applied at `fill`. If user want apply visual.color on `stroke`,
|
|
* it can be implemented as:
|
|
* `api.style({stroke: api.visual('color'), fill: null})`;
|
|
* @public
|
|
* @param {Object} [extra]
|
|
* @param {number} [dataIndexInside=currDataIndexInside]
|
|
*/
|
|
function style(extra, dataIndexInside) {
|
|
dataIndexInside == null && (dataIndexInside = currDataIndexInside);
|
|
updateCache(dataIndexInside);
|
|
var itemStyle = currItemModel.getModel(ITEM_STYLE_NORMAL_PATH).getItemStyle();
|
|
currVisualColor != null && (itemStyle.fill = currVisualColor);
|
|
var opacity = data.getItemVisual(dataIndexInside, 'opacity');
|
|
opacity != null && (itemStyle.opacity = opacity);
|
|
if (currLabelValueDim != null) {
|
|
graphicUtil.setTextStyle(itemStyle, currLabelNormalModel, null, {
|
|
autoColor: currVisualColor,
|
|
isRectText: true
|
|
});
|
|
itemStyle.text = currLabelNormalModel.getShallow('show') ? zrUtil.retrieve2(customSeries.getFormattedLabel(dataIndexInside, 'normal'), data.get(currLabelValueDim, dataIndexInside)) : null;
|
|
}
|
|
extra && zrUtil.extend(itemStyle, extra);
|
|
return itemStyle;
|
|
}
|
|
/**
|
|
* @public
|
|
* @param {Object} [extra]
|
|
* @param {number} [dataIndexInside=currDataIndexInside]
|
|
*/
|
|
function styleEmphasis(extra, dataIndexInside) {
|
|
dataIndexInside == null && (dataIndexInside = currDataIndexInside);
|
|
updateCache(dataIndexInside);
|
|
var itemStyle = currItemModel.getModel(ITEM_STYLE_EMPHASIS_PATH).getItemStyle();
|
|
if (currLabelValueDim != null) {
|
|
graphicUtil.setTextStyle(itemStyle, currLabelEmphasisModel, null, { isRectText: true }, true);
|
|
itemStyle.text = currLabelEmphasisModel.getShallow('show') ? zrUtil.retrieve3(customSeries.getFormattedLabel(dataIndexInside, 'emphasis'), customSeries.getFormattedLabel(dataIndexInside, 'normal'), data.get(currLabelValueDim, dataIndexInside)) : null;
|
|
}
|
|
extra && zrUtil.extend(itemStyle, extra);
|
|
return itemStyle;
|
|
}
|
|
/**
|
|
* @public
|
|
* @param {string} visualType
|
|
* @param {number} [dataIndexInside=currDataIndexInside]
|
|
*/
|
|
function visual(visualType, dataIndexInside) {
|
|
dataIndexInside == null && (dataIndexInside = currDataIndexInside);
|
|
return data.getItemVisual(dataIndexInside, visualType);
|
|
}
|
|
/**
|
|
* @public
|
|
* @param {number} opt.count Positive interger.
|
|
* @param {number} [opt.barWidth]
|
|
* @param {number} [opt.barMaxWidth]
|
|
* @param {number} [opt.barGap]
|
|
* @param {number} [opt.barCategoryGap]
|
|
* @return {Object} {width, offset, offsetCenter} is not support, return undefined.
|
|
*/
|
|
function barLayout(opt) {
|
|
if (coordSys.getBaseAxis) {
|
|
var baseAxis = coordSys.getBaseAxis();
|
|
return barGrid.getLayoutOnAxis(zrUtil.defaults({ axis: baseAxis }, opt), api);
|
|
}
|
|
}
|
|
/**
|
|
* @public
|
|
* @return {Array.<number>}
|
|
*/
|
|
function currentSeriesIndices() {
|
|
return ecModel.getCurrentSeriesIndices();
|
|
}
|
|
/**
|
|
* @public
|
|
* @param {Object} opt
|
|
* @param {string} [opt.fontStyle]
|
|
* @param {number} [opt.fontWeight]
|
|
* @param {number} [opt.fontSize]
|
|
* @param {string} [opt.fontFamily]
|
|
* @return {string} font string
|
|
*/
|
|
function font(opt) {
|
|
return graphicUtil.getFont(opt, ecModel);
|
|
}
|
|
}
|
|
function wrapEncodeDef(data) {
|
|
var encodeDef = {};
|
|
zrUtil.each(data.dimensions, function (dimName, dataDimIndex) {
|
|
var dimInfo = data.getDimensionInfo(dimName);
|
|
if (!dimInfo.isExtraCoord) {
|
|
var coordDim = dimInfo.coordDim;
|
|
var dataDims = encodeDef[coordDim] = encodeDef[coordDim] || [];
|
|
dataDims[dimInfo.coordDimIndex] = dataDimIndex;
|
|
}
|
|
});
|
|
return encodeDef;
|
|
}
|
|
function createOrUpdate(el, dataIndex, elOption, animatableModel, group, data) {
|
|
el = doCreateOrUpdate(el, dataIndex, elOption, animatableModel, group, data);
|
|
el && data.setItemGraphicEl(dataIndex, el);
|
|
}
|
|
function doCreateOrUpdate(el, dataIndex, elOption, animatableModel, group, data) {
|
|
var elOptionType = elOption.type;
|
|
if (el && elOptionType !== el.__customGraphicType && (elOptionType !== 'path' || elOption.pathData !== el.__customPathData) && (elOptionType !== 'image' || elOption.style.image !== el.__customImagePath) && (elOptionType !== 'text' || elOption.style.text !== el.__customText)) {
|
|
group.remove(el);
|
|
el = null;
|
|
}
|
|
// `elOption.type` is undefined when `renderItem` returns nothing.
|
|
if (elOptionType == null) {
|
|
return;
|
|
}
|
|
var isInit = !el;
|
|
!el && (el = createEl(elOption));
|
|
updateEl(el, dataIndex, elOption, animatableModel, data, isInit);
|
|
if (elOptionType === 'group') {
|
|
var oldChildren = el.children() || [];
|
|
var newChildren = elOption.children || [];
|
|
if (elOption.diffChildrenByName) {
|
|
// lower performance.
|
|
diffGroupChildren({
|
|
oldChildren: oldChildren,
|
|
newChildren: newChildren,
|
|
dataIndex: dataIndex,
|
|
animatableModel: animatableModel,
|
|
group: el,
|
|
data: data
|
|
});
|
|
} else {
|
|
// better performance.
|
|
var index = 0;
|
|
for (; index < newChildren.length; index++) {
|
|
doCreateOrUpdate(el.childAt(index), dataIndex, newChildren[index], animatableModel, el, data);
|
|
}
|
|
for (; index < oldChildren.length; index++) {
|
|
oldChildren[index] && el.remove(oldChildren[index]);
|
|
}
|
|
}
|
|
}
|
|
group.add(el);
|
|
return el;
|
|
}
|
|
function diffGroupChildren(context) {
|
|
new DataDiffer(context.oldChildren, context.newChildren, getKey, getKey, context).add(processAddUpdate).update(processAddUpdate).remove(processRemove).execute();
|
|
}
|
|
function getKey(item, idx) {
|
|
var name = item && item.name;
|
|
return name != null ? name : GROUP_DIFF_PREFIX + idx;
|
|
}
|
|
function processAddUpdate(newIndex, oldIndex) {
|
|
var context = this.context;
|
|
var childOption = newIndex != null ? context.newChildren[newIndex] : null;
|
|
var child = oldIndex != null ? context.oldChildren[oldIndex] : null;
|
|
doCreateOrUpdate(child, context.dataIndex, childOption, context.animatableModel, context.group, context.data);
|
|
}
|
|
function processRemove(oldIndex) {
|
|
var context = this.context;
|
|
var child = context.oldChildren[oldIndex];
|
|
child && context.group.remove(child);
|
|
}
|
|
});
|
|
define('echarts/visual/dataColor', ['require'], function (require) {
|
|
return function (seriesType, ecModel) {
|
|
// Pie and funnel may use diferrent scope
|
|
var paletteScope = {};
|
|
ecModel.eachRawSeriesByType(seriesType, function (seriesModel) {
|
|
var dataAll = seriesModel.getRawData();
|
|
var idxMap = {};
|
|
if (!ecModel.isSeriesFiltered(seriesModel)) {
|
|
var data = seriesModel.getData();
|
|
data.each(function (idx) {
|
|
var rawIdx = data.getRawIndex(idx);
|
|
idxMap[rawIdx] = idx;
|
|
});
|
|
dataAll.each(function (rawIdx) {
|
|
var filteredIdx = idxMap[rawIdx];
|
|
// If series.itemStyle.normal.color is a function. itemVisual may be encoded
|
|
var singleDataColor = filteredIdx != null && data.getItemVisual(filteredIdx, 'color', true);
|
|
if (!singleDataColor) {
|
|
// FIXME Performance
|
|
var itemModel = dataAll.getItemModel(rawIdx);
|
|
var color = itemModel.get('itemStyle.normal.color') || seriesModel.getColorFromPalette(dataAll.getName(rawIdx), paletteScope);
|
|
// Legend may use the visual info in data before processed
|
|
dataAll.setItemVisual(rawIdx, 'color', color);
|
|
// Data is not filtered
|
|
if (filteredIdx != null) {
|
|
data.setItemVisual(filteredIdx, 'color', color);
|
|
}
|
|
} else {
|
|
// Set data all color for legend
|
|
dataAll.setItemVisual(rawIdx, 'color', singleDataColor);
|
|
}
|
|
});
|
|
}
|
|
});
|
|
};
|
|
});
|
|
define('echarts/chart/pie/pieLayout', ['require', '../../util/number', './labelLayout', 'zrender/core/util'], function (require) {
|
|
var numberUtil = require('../../util/number');
|
|
var parsePercent = numberUtil.parsePercent;
|
|
var labelLayout = require('./labelLayout');
|
|
var zrUtil = require('zrender/core/util');
|
|
var PI2 = Math.PI * 2;
|
|
var RADIAN = Math.PI / 180;
|
|
return function (seriesType, ecModel, api, payload) {
|
|
ecModel.eachSeriesByType(seriesType, function (seriesModel) {
|
|
var center = seriesModel.get('center');
|
|
var radius = seriesModel.get('radius');
|
|
if (!zrUtil.isArray(radius)) {
|
|
radius = [
|
|
0,
|
|
radius
|
|
];
|
|
}
|
|
if (!zrUtil.isArray(center)) {
|
|
center = [
|
|
center,
|
|
center
|
|
];
|
|
}
|
|
var width = api.getWidth();
|
|
var height = api.getHeight();
|
|
var size = Math.min(width, height);
|
|
var cx = parsePercent(center[0], width);
|
|
var cy = parsePercent(center[1], height);
|
|
var r0 = parsePercent(radius[0], size / 2);
|
|
var r = parsePercent(radius[1], size / 2);
|
|
var data = seriesModel.getData();
|
|
var startAngle = -seriesModel.get('startAngle') * RADIAN;
|
|
var minAngle = seriesModel.get('minAngle') * RADIAN;
|
|
var validDataCount = 0;
|
|
data.each('value', function (value) {
|
|
!isNaN(value) && validDataCount++;
|
|
});
|
|
var sum = data.getSum('value');
|
|
// Sum may be 0
|
|
var unitRadian = Math.PI / (sum || validDataCount) * 2;
|
|
var clockwise = seriesModel.get('clockwise');
|
|
var roseType = seriesModel.get('roseType');
|
|
var stillShowZeroSum = seriesModel.get('stillShowZeroSum');
|
|
// [0...max]
|
|
var extent = data.getDataExtent('value');
|
|
extent[0] = 0;
|
|
// In the case some sector angle is smaller than minAngle
|
|
var restAngle = PI2;
|
|
var valueSumLargerThanMinAngle = 0;
|
|
var currentAngle = startAngle;
|
|
var dir = clockwise ? 1 : -1;
|
|
data.each('value', function (value, idx) {
|
|
var angle;
|
|
if (isNaN(value)) {
|
|
data.setItemLayout(idx, {
|
|
angle: NaN,
|
|
startAngle: NaN,
|
|
endAngle: NaN,
|
|
clockwise: clockwise,
|
|
cx: cx,
|
|
cy: cy,
|
|
r0: r0,
|
|
r: roseType ? NaN : r
|
|
});
|
|
return;
|
|
}
|
|
// FIXME 兼容 2.0 但是 roseType 是 area 的时候才是这样?
|
|
if (roseType !== 'area') {
|
|
angle = sum === 0 && stillShowZeroSum ? unitRadian : value * unitRadian;
|
|
} else {
|
|
angle = PI2 / validDataCount;
|
|
}
|
|
if (angle < minAngle) {
|
|
angle = minAngle;
|
|
restAngle -= minAngle;
|
|
} else {
|
|
valueSumLargerThanMinAngle += value;
|
|
}
|
|
var endAngle = currentAngle + dir * angle;
|
|
data.setItemLayout(idx, {
|
|
angle: angle,
|
|
startAngle: currentAngle,
|
|
endAngle: endAngle,
|
|
clockwise: clockwise,
|
|
cx: cx,
|
|
cy: cy,
|
|
r0: r0,
|
|
r: roseType ? numberUtil.linearMap(value, extent, [
|
|
r0,
|
|
r
|
|
]) : r
|
|
});
|
|
currentAngle = endAngle;
|
|
}, true);
|
|
// Some sector is constrained by minAngle
|
|
// Rest sectors needs recalculate angle
|
|
if (restAngle < PI2 && validDataCount) {
|
|
// Average the angle if rest angle is not enough after all angles is
|
|
// Constrained by minAngle
|
|
if (restAngle <= 0.001) {
|
|
var angle = PI2 / validDataCount;
|
|
data.each('value', function (value, idx) {
|
|
if (!isNaN(value)) {
|
|
var layout = data.getItemLayout(idx);
|
|
layout.angle = angle;
|
|
layout.startAngle = startAngle + dir * idx * angle;
|
|
layout.endAngle = startAngle + dir * (idx + 1) * angle;
|
|
}
|
|
});
|
|
} else {
|
|
unitRadian = restAngle / valueSumLargerThanMinAngle;
|
|
currentAngle = startAngle;
|
|
data.each('value', function (value, idx) {
|
|
if (!isNaN(value)) {
|
|
var layout = data.getItemLayout(idx);
|
|
var angle = layout.angle === minAngle ? minAngle : value * unitRadian;
|
|
layout.startAngle = currentAngle;
|
|
layout.endAngle = currentAngle + dir * angle;
|
|
currentAngle += dir * angle;
|
|
}
|
|
});
|
|
}
|
|
}
|
|
labelLayout(seriesModel, r, width, height);
|
|
});
|
|
};
|
|
});
|
|
define('echarts/chart/scatter/ScatterSeries', ['require', '../helper/createListFromArray', '../../model/Series'], function (require) {
|
|
'use strict';
|
|
var createListFromArray = require('../helper/createListFromArray');
|
|
var SeriesModel = require('../../model/Series');
|
|
return SeriesModel.extend({
|
|
type: 'series.scatter',
|
|
dependencies: [
|
|
'grid',
|
|
'polar',
|
|
'geo',
|
|
'singleAxis',
|
|
'calendar'
|
|
],
|
|
getInitialData: function (option, ecModel) {
|
|
return createListFromArray(option.data, this, ecModel);
|
|
},
|
|
brushSelector: 'point',
|
|
defaultOption: {
|
|
coordinateSystem: 'cartesian2d',
|
|
zlevel: 0,
|
|
z: 2,
|
|
legendHoverLink: true,
|
|
hoverAnimation: true,
|
|
symbolSize: 10,
|
|
large: false,
|
|
largeThreshold: 2000,
|
|
itemStyle: { normal: { opacity: 0.8 } }
|
|
}
|
|
});
|
|
});
|
|
define('echarts/chart/scatter/ScatterView', ['require', '../helper/SymbolDraw', '../helper/LargeSymbolDraw', '../../echarts'], function (require) {
|
|
var SymbolDraw = require('../helper/SymbolDraw');
|
|
var LargeSymbolDraw = require('../helper/LargeSymbolDraw');
|
|
require('../../echarts').extendChartView({
|
|
type: 'scatter',
|
|
init: function () {
|
|
this._normalSymbolDraw = new SymbolDraw();
|
|
this._largeSymbolDraw = new LargeSymbolDraw();
|
|
},
|
|
render: function (seriesModel, ecModel, api) {
|
|
var data = seriesModel.getData();
|
|
var largeSymbolDraw = this._largeSymbolDraw;
|
|
var normalSymbolDraw = this._normalSymbolDraw;
|
|
var group = this.group;
|
|
var symbolDraw = seriesModel.get('large') && data.count() > seriesModel.get('largeThreshold') ? largeSymbolDraw : normalSymbolDraw;
|
|
this._symbolDraw = symbolDraw;
|
|
symbolDraw.updateData(data);
|
|
group.add(symbolDraw.group);
|
|
group.remove(symbolDraw === largeSymbolDraw ? normalSymbolDraw.group : largeSymbolDraw.group);
|
|
},
|
|
updateLayout: function (seriesModel) {
|
|
this._symbolDraw.updateLayout(seriesModel);
|
|
},
|
|
remove: function (ecModel, api) {
|
|
this._symbolDraw && this._symbolDraw.remove(api, true);
|
|
},
|
|
dispose: function () {
|
|
}
|
|
});
|
|
});
|
|
define('echarts/component/radar', ['require', '../coord/radar/Radar', '../coord/radar/RadarModel', './radar/RadarView'], function (require) {
|
|
require('../coord/radar/Radar');
|
|
require('../coord/radar/RadarModel');
|
|
require('./radar/RadarView');
|
|
});
|
|
define('echarts/processor/dataFilter', [], function () {
|
|
return function (seriesType, ecModel) {
|
|
var legendModels = ecModel.findComponents({ mainType: 'legend' });
|
|
if (!legendModels || !legendModels.length) {
|
|
return;
|
|
}
|
|
ecModel.eachSeriesByType(seriesType, function (series) {
|
|
var data = series.getData();
|
|
data.filterSelf(function (idx) {
|
|
var name = data.getName(idx);
|
|
// If in any legend component the status is not selected.
|
|
for (var i = 0; i < legendModels.length; i++) {
|
|
if (!legendModels[i].isSelected(name)) {
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}, this);
|
|
}, this);
|
|
};
|
|
});
|
|
define('echarts/chart/radar/RadarSeries', ['require', '../../model/Series', '../../data/List', '../../data/helper/completeDimensions', 'zrender/core/util', '../../util/format'], function (require) {
|
|
'use strict';
|
|
var SeriesModel = require('../../model/Series');
|
|
var List = require('../../data/List');
|
|
var completeDimensions = require('../../data/helper/completeDimensions');
|
|
var zrUtil = require('zrender/core/util');
|
|
var encodeHTML = require('../../util/format').encodeHTML;
|
|
var RadarSeries = SeriesModel.extend({
|
|
type: 'series.radar',
|
|
dependencies: ['radar'],
|
|
init: function (option) {
|
|
RadarSeries.superApply(this, 'init', arguments);
|
|
// Enable legend selection for each data item
|
|
// Use a function instead of direct access because data reference may changed
|
|
this.legendDataProvider = function () {
|
|
return this.getRawData();
|
|
};
|
|
},
|
|
getInitialData: function (option, ecModel) {
|
|
var data = option.data || [];
|
|
var dimensions = completeDimensions([], data, {
|
|
extraPrefix: 'indicator_',
|
|
extraFromZero: true
|
|
});
|
|
var list = new List(dimensions, this);
|
|
list.initData(data);
|
|
return list;
|
|
},
|
|
formatTooltip: function (dataIndex) {
|
|
var value = this.getRawValue(dataIndex);
|
|
var coordSys = this.coordinateSystem;
|
|
var indicatorAxes = coordSys.getIndicatorAxes();
|
|
var name = this.getData().getName(dataIndex);
|
|
return encodeHTML(name === '' ? this.name : name) + '<br/>' + zrUtil.map(indicatorAxes, function (axis, idx) {
|
|
return encodeHTML(axis.name + ' : ' + value[idx]);
|
|
}).join('<br />');
|
|
},
|
|
defaultOption: {
|
|
zlevel: 0,
|
|
z: 2,
|
|
coordinateSystem: 'radar',
|
|
legendHoverLink: true,
|
|
radarIndex: 0,
|
|
lineStyle: {
|
|
normal: {
|
|
width: 2,
|
|
type: 'solid'
|
|
}
|
|
},
|
|
label: { normal: { position: 'top' } },
|
|
symbol: 'emptyCircle',
|
|
symbolSize: 4
|
|
}
|
|
});
|
|
return RadarSeries;
|
|
});
|
|
define('echarts/chart/radar/RadarView', ['require', '../../util/graphic', 'zrender/core/util', '../../util/symbol', '../../echarts'], function (require) {
|
|
var graphic = require('../../util/graphic');
|
|
var zrUtil = require('zrender/core/util');
|
|
var symbolUtil = require('../../util/symbol');
|
|
function normalizeSymbolSize(symbolSize) {
|
|
if (!zrUtil.isArray(symbolSize)) {
|
|
symbolSize = [
|
|
+symbolSize,
|
|
+symbolSize
|
|
];
|
|
}
|
|
return symbolSize;
|
|
}
|
|
return require('../../echarts').extendChartView({
|
|
type: 'radar',
|
|
render: function (seriesModel, ecModel, api) {
|
|
var polar = seriesModel.coordinateSystem;
|
|
var group = this.group;
|
|
var data = seriesModel.getData();
|
|
var oldData = this._data;
|
|
function createSymbol(data, idx) {
|
|
var symbolType = data.getItemVisual(idx, 'symbol') || 'circle';
|
|
var color = data.getItemVisual(idx, 'color');
|
|
if (symbolType === 'none') {
|
|
return;
|
|
}
|
|
var symbolSize = normalizeSymbolSize(data.getItemVisual(idx, 'symbolSize'));
|
|
var symbolPath = symbolUtil.createSymbol(symbolType, -1, -1, 2, 2, color);
|
|
symbolPath.attr({
|
|
style: { strokeNoScale: true },
|
|
z2: 100,
|
|
scale: [
|
|
symbolSize[0] / 2,
|
|
symbolSize[1] / 2
|
|
]
|
|
});
|
|
return symbolPath;
|
|
}
|
|
function updateSymbols(oldPoints, newPoints, symbolGroup, data, idx, isInit) {
|
|
// Simply rerender all
|
|
symbolGroup.removeAll();
|
|
for (var i = 0; i < newPoints.length - 1; i++) {
|
|
var symbolPath = createSymbol(data, idx);
|
|
if (symbolPath) {
|
|
symbolPath.__dimIdx = i;
|
|
if (oldPoints[i]) {
|
|
symbolPath.attr('position', oldPoints[i]);
|
|
graphic[isInit ? 'initProps' : 'updateProps'](symbolPath, { position: newPoints[i] }, seriesModel, idx);
|
|
} else {
|
|
symbolPath.attr('position', newPoints[i]);
|
|
}
|
|
symbolGroup.add(symbolPath);
|
|
}
|
|
}
|
|
}
|
|
function getInitialPoints(points) {
|
|
return zrUtil.map(points, function (pt) {
|
|
return [
|
|
polar.cx,
|
|
polar.cy
|
|
];
|
|
});
|
|
}
|
|
data.diff(oldData).add(function (idx) {
|
|
var points = data.getItemLayout(idx);
|
|
if (!points) {
|
|
return;
|
|
}
|
|
var polygon = new graphic.Polygon();
|
|
var polyline = new graphic.Polyline();
|
|
var target = { shape: { points: points } };
|
|
polygon.shape.points = getInitialPoints(points);
|
|
polyline.shape.points = getInitialPoints(points);
|
|
graphic.initProps(polygon, target, seriesModel, idx);
|
|
graphic.initProps(polyline, target, seriesModel, idx);
|
|
var itemGroup = new graphic.Group();
|
|
var symbolGroup = new graphic.Group();
|
|
itemGroup.add(polyline);
|
|
itemGroup.add(polygon);
|
|
itemGroup.add(symbolGroup);
|
|
updateSymbols(polyline.shape.points, points, symbolGroup, data, idx, true);
|
|
data.setItemGraphicEl(idx, itemGroup);
|
|
}).update(function (newIdx, oldIdx) {
|
|
var itemGroup = oldData.getItemGraphicEl(oldIdx);
|
|
var polyline = itemGroup.childAt(0);
|
|
var polygon = itemGroup.childAt(1);
|
|
var symbolGroup = itemGroup.childAt(2);
|
|
var target = { shape: { points: data.getItemLayout(newIdx) } };
|
|
if (!target.shape.points) {
|
|
return;
|
|
}
|
|
updateSymbols(polyline.shape.points, target.shape.points, symbolGroup, data, newIdx, false);
|
|
graphic.updateProps(polyline, target, seriesModel);
|
|
graphic.updateProps(polygon, target, seriesModel);
|
|
data.setItemGraphicEl(newIdx, itemGroup);
|
|
}).remove(function (idx) {
|
|
group.remove(oldData.getItemGraphicEl(idx));
|
|
}).execute();
|
|
data.eachItemGraphicEl(function (itemGroup, idx) {
|
|
var itemModel = data.getItemModel(idx);
|
|
var polyline = itemGroup.childAt(0);
|
|
var polygon = itemGroup.childAt(1);
|
|
var symbolGroup = itemGroup.childAt(2);
|
|
var color = data.getItemVisual(idx, 'color');
|
|
group.add(itemGroup);
|
|
polyline.useStyle(zrUtil.defaults(itemModel.getModel('lineStyle.normal').getLineStyle(), {
|
|
fill: 'none',
|
|
stroke: color
|
|
}));
|
|
polyline.hoverStyle = itemModel.getModel('lineStyle.emphasis').getLineStyle();
|
|
var areaStyleModel = itemModel.getModel('areaStyle.normal');
|
|
var hoverAreaStyleModel = itemModel.getModel('areaStyle.emphasis');
|
|
var polygonIgnore = areaStyleModel.isEmpty() && areaStyleModel.parentModel.isEmpty();
|
|
var hoverPolygonIgnore = hoverAreaStyleModel.isEmpty() && hoverAreaStyleModel.parentModel.isEmpty();
|
|
hoverPolygonIgnore = hoverPolygonIgnore && polygonIgnore;
|
|
polygon.ignore = polygonIgnore;
|
|
polygon.useStyle(zrUtil.defaults(areaStyleModel.getAreaStyle(), {
|
|
fill: color,
|
|
opacity: 0.7
|
|
}));
|
|
polygon.hoverStyle = hoverAreaStyleModel.getAreaStyle();
|
|
var itemStyle = itemModel.getModel('itemStyle.normal').getItemStyle(['color']);
|
|
var itemHoverStyle = itemModel.getModel('itemStyle.emphasis').getItemStyle();
|
|
var labelModel = itemModel.getModel('label.normal');
|
|
var labelHoverModel = itemModel.getModel('label.emphasis');
|
|
symbolGroup.eachChild(function (symbolPath) {
|
|
symbolPath.setStyle(itemStyle);
|
|
symbolPath.hoverStyle = zrUtil.clone(itemHoverStyle);
|
|
graphic.setLabelStyle(symbolPath.style, symbolPath.hoverStyle, labelModel, labelHoverModel, {
|
|
labelFetcher: data.hostModel,
|
|
labelDataIndex: idx,
|
|
labelDimIndex: symbolPath.__dimIdx,
|
|
defaultText: data.get(data.dimensions[symbolPath.__dimIdx], idx),
|
|
autoColor: color,
|
|
isRectText: true
|
|
});
|
|
});
|
|
function onEmphasis() {
|
|
polygon.attr('ignore', hoverPolygonIgnore);
|
|
}
|
|
function onNormal() {
|
|
polygon.attr('ignore', polygonIgnore);
|
|
}
|
|
itemGroup.off('mouseover').off('mouseout').off('normal').off('emphasis');
|
|
itemGroup.on('emphasis', onEmphasis).on('mouseover', onEmphasis).on('normal', onNormal).on('mouseout', onNormal);
|
|
graphic.setHoverStyle(itemGroup);
|
|
});
|
|
this._data = data;
|
|
},
|
|
remove: function () {
|
|
this.group.removeAll();
|
|
this._data = null;
|
|
},
|
|
dispose: function () {
|
|
}
|
|
});
|
|
});
|
|
define('echarts/chart/radar/radarLayout', ['require'], function (require) {
|
|
return function (ecModel) {
|
|
ecModel.eachSeriesByType('radar', function (seriesModel) {
|
|
var data = seriesModel.getData();
|
|
var points = [];
|
|
var coordSys = seriesModel.coordinateSystem;
|
|
if (!coordSys) {
|
|
return;
|
|
}
|
|
function pointsConverter(val, idx) {
|
|
points[idx] = points[idx] || [];
|
|
points[idx][i] = coordSys.dataToPoint(val, i);
|
|
}
|
|
for (var i = 0; i < coordSys.getIndicatorAxes().length; i++) {
|
|
var dim = data.dimensions[i];
|
|
data.each(dim, pointsConverter);
|
|
}
|
|
data.each(function (idx) {
|
|
// Close polygon
|
|
points[idx][0] && points[idx].push(points[idx][0].slice());
|
|
data.setItemLayout(idx, points[idx]);
|
|
});
|
|
});
|
|
};
|
|
});
|
|
define('echarts/chart/radar/backwardCompat', ['require', 'zrender/core/util'], function (require) {
|
|
var zrUtil = require('zrender/core/util');
|
|
return function (option) {
|
|
var polarOptArr = option.polar;
|
|
if (polarOptArr) {
|
|
if (!zrUtil.isArray(polarOptArr)) {
|
|
polarOptArr = [polarOptArr];
|
|
}
|
|
var polarNotRadar = [];
|
|
zrUtil.each(polarOptArr, function (polarOpt, idx) {
|
|
if (polarOpt.indicator) {
|
|
if (polarOpt.type && !polarOpt.shape) {
|
|
polarOpt.shape = polarOpt.type;
|
|
}
|
|
option.radar = option.radar || [];
|
|
if (!zrUtil.isArray(option.radar)) {
|
|
option.radar = [option.radar];
|
|
}
|
|
option.radar.push(polarOpt);
|
|
} else {
|
|
polarNotRadar.push(polarOpt);
|
|
}
|
|
});
|
|
option.polar = polarNotRadar;
|
|
}
|
|
zrUtil.each(option.series, function (seriesOpt) {
|
|
if (seriesOpt.type === 'radar' && seriesOpt.polarIndex) {
|
|
seriesOpt.radarIndex = seriesOpt.polarIndex;
|
|
}
|
|
});
|
|
};
|
|
});
|
|
define('echarts/chart/candlestick/CandlestickSeries', ['require', 'zrender/core/util', '../../model/Series', '../helper/whiskerBoxCommon'], function (require) {
|
|
'use strict';
|
|
var zrUtil = require('zrender/core/util');
|
|
var SeriesModel = require('../../model/Series');
|
|
var whiskerBoxCommon = require('../helper/whiskerBoxCommon');
|
|
var CandlestickSeries = SeriesModel.extend({
|
|
type: 'series.candlestick',
|
|
dependencies: [
|
|
'xAxis',
|
|
'yAxis',
|
|
'grid'
|
|
],
|
|
defaultValueDimensions: [
|
|
'open',
|
|
'close',
|
|
'lowest',
|
|
'highest'
|
|
],
|
|
dimensions: null,
|
|
defaultOption: {
|
|
zlevel: 0,
|
|
z: 2,
|
|
coordinateSystem: 'cartesian2d',
|
|
legendHoverLink: true,
|
|
hoverAnimation: true,
|
|
layout: null,
|
|
itemStyle: {
|
|
normal: {
|
|
color: '#c23531',
|
|
color0: '#314656',
|
|
borderWidth: 1,
|
|
borderColor: '#c23531',
|
|
borderColor0: '#314656'
|
|
},
|
|
emphasis: { borderWidth: 2 }
|
|
},
|
|
barMaxWidth: null,
|
|
barMinWidth: null,
|
|
barWidth: null,
|
|
animationUpdate: false,
|
|
animationEasing: 'linear',
|
|
animationDuration: 300
|
|
},
|
|
getShadowDim: function () {
|
|
return 'open';
|
|
},
|
|
brushSelector: function (dataIndex, data, selectors) {
|
|
var itemLayout = data.getItemLayout(dataIndex);
|
|
return selectors.rect(itemLayout.brushRect);
|
|
}
|
|
});
|
|
zrUtil.mixin(CandlestickSeries, whiskerBoxCommon.seriesModelMixin, true);
|
|
return CandlestickSeries;
|
|
});
|
|
define('echarts/chart/candlestick/CandlestickView', ['require', 'zrender/core/util', '../../view/Chart', '../../util/graphic', '../helper/whiskerBoxCommon'], function (require) {
|
|
'use strict';
|
|
var zrUtil = require('zrender/core/util');
|
|
var ChartView = require('../../view/Chart');
|
|
var graphic = require('../../util/graphic');
|
|
var whiskerBoxCommon = require('../helper/whiskerBoxCommon');
|
|
var CandlestickView = ChartView.extend({
|
|
type: 'candlestick',
|
|
getStyleUpdater: function () {
|
|
return updateStyle;
|
|
},
|
|
dispose: zrUtil.noop
|
|
});
|
|
zrUtil.mixin(CandlestickView, whiskerBoxCommon.viewMixin, true);
|
|
// Update common properties
|
|
var normalStyleAccessPath = [
|
|
'itemStyle',
|
|
'normal'
|
|
];
|
|
var emphasisStyleAccessPath = [
|
|
'itemStyle',
|
|
'emphasis'
|
|
];
|
|
function updateStyle(itemGroup, data, idx) {
|
|
var itemModel = data.getItemModel(idx);
|
|
var normalItemStyleModel = itemModel.getModel(normalStyleAccessPath);
|
|
var color = data.getItemVisual(idx, 'color');
|
|
var borderColor = data.getItemVisual(idx, 'borderColor') || color;
|
|
// Color must be excluded.
|
|
// Because symbol provide setColor individually to set fill and stroke
|
|
var itemStyle = normalItemStyleModel.getItemStyle([
|
|
'color',
|
|
'color0',
|
|
'borderColor',
|
|
'borderColor0'
|
|
]);
|
|
var whiskerEl = itemGroup.childAt(itemGroup.whiskerIndex);
|
|
whiskerEl.useStyle(itemStyle);
|
|
whiskerEl.style.stroke = borderColor;
|
|
var bodyEl = itemGroup.childAt(itemGroup.bodyIndex);
|
|
bodyEl.useStyle(itemStyle);
|
|
bodyEl.style.fill = color;
|
|
bodyEl.style.stroke = borderColor;
|
|
var hoverStyle = itemModel.getModel(emphasisStyleAccessPath).getItemStyle();
|
|
graphic.setHoverStyle(itemGroup, hoverStyle);
|
|
}
|
|
return CandlestickView;
|
|
});
|
|
define('echarts/coord/cartesian/Grid', ['require', 'exports', '../../util/layout', '../../coord/axisHelper', 'zrender/core/util', './Cartesian2D', './Axis2D', './GridModel', '../../CoordinateSystem'], function (require, factory) {
|
|
var layout = require('../../util/layout');
|
|
var axisHelper = require('../../coord/axisHelper');
|
|
var zrUtil = require('zrender/core/util');
|
|
var Cartesian2D = require('./Cartesian2D');
|
|
var Axis2D = require('./Axis2D');
|
|
var each = zrUtil.each;
|
|
var ifAxisCrossZero = axisHelper.ifAxisCrossZero;
|
|
var niceScaleExtent = axisHelper.niceScaleExtent;
|
|
// 依赖 GridModel, AxisModel 做预处理
|
|
require('./GridModel');
|
|
/**
|
|
* Check if the axis is used in the specified grid
|
|
* @inner
|
|
*/
|
|
function isAxisUsedInTheGrid(axisModel, gridModel, ecModel) {
|
|
return axisModel.getCoordSysModel() === gridModel;
|
|
}
|
|
function getLabelUnionRect(axis) {
|
|
var axisModel = axis.model;
|
|
var labels = axisModel.getFormattedLabels();
|
|
var axisLabelModel = axisModel.getModel('axisLabel');
|
|
var rect;
|
|
var step = 1;
|
|
var labelCount = labels.length;
|
|
if (labelCount > 40) {
|
|
// Simple optimization for large amount of labels
|
|
step = Math.ceil(labelCount / 40);
|
|
}
|
|
for (var i = 0; i < labelCount; i += step) {
|
|
if (!axis.isLabelIgnored(i)) {
|
|
var singleRect = axisLabelModel.getTextRect(labels[i]);
|
|
// FIXME consider label rotate
|
|
rect ? rect.union(singleRect) : rect = singleRect;
|
|
}
|
|
}
|
|
return rect;
|
|
}
|
|
function Grid(gridModel, ecModel, api) {
|
|
/**
|
|
* @type {Object.<string, module:echarts/coord/cartesian/Cartesian2D>}
|
|
* @private
|
|
*/
|
|
this._coordsMap = {};
|
|
/**
|
|
* @type {Array.<module:echarts/coord/cartesian/Cartesian>}
|
|
* @private
|
|
*/
|
|
this._coordsList = [];
|
|
/**
|
|
* @type {Object.<string, module:echarts/coord/cartesian/Axis2D>}
|
|
* @private
|
|
*/
|
|
this._axesMap = {};
|
|
/**
|
|
* @type {Array.<module:echarts/coord/cartesian/Axis2D>}
|
|
* @private
|
|
*/
|
|
this._axesList = [];
|
|
this._initCartesian(gridModel, ecModel, api);
|
|
this.model = gridModel;
|
|
}
|
|
var gridProto = Grid.prototype;
|
|
gridProto.type = 'grid';
|
|
gridProto.axisPointerEnabled = true;
|
|
gridProto.getRect = function () {
|
|
return this._rect;
|
|
};
|
|
gridProto.update = function (ecModel, api) {
|
|
var axesMap = this._axesMap;
|
|
this._updateScale(ecModel, this.model);
|
|
each(axesMap.x, function (xAxis) {
|
|
niceScaleExtent(xAxis.scale, xAxis.model);
|
|
});
|
|
each(axesMap.y, function (yAxis) {
|
|
niceScaleExtent(yAxis.scale, yAxis.model);
|
|
});
|
|
each(axesMap.x, function (xAxis) {
|
|
fixAxisOnZero(axesMap, 'y', xAxis);
|
|
});
|
|
each(axesMap.y, function (yAxis) {
|
|
fixAxisOnZero(axesMap, 'x', yAxis);
|
|
});
|
|
// Resize again if containLabel is enabled
|
|
// FIXME It may cause getting wrong grid size in data processing stage
|
|
this.resize(this.model, api);
|
|
};
|
|
function fixAxisOnZero(axesMap, otherAxisDim, axis) {
|
|
// onZero can not be enabled in these two situations:
|
|
// 1. When any other axis is a category axis.
|
|
// 2. When no axis is cross 0 point.
|
|
var axes = axesMap[otherAxisDim];
|
|
if (!axis.onZero) {
|
|
return;
|
|
}
|
|
var onZeroAxisIndex = axis.onZeroAxisIndex;
|
|
// If target axis is specified.
|
|
if (onZeroAxisIndex != null) {
|
|
var otherAxis = axes[onZeroAxisIndex];
|
|
if (otherAxis && canNotOnZeroToAxis(otherAxis)) {
|
|
axis.onZero = false;
|
|
}
|
|
return;
|
|
}
|
|
for (var idx in axes) {
|
|
if (axes.hasOwnProperty(idx)) {
|
|
var otherAxis = axes[idx];
|
|
if (otherAxis && !canNotOnZeroToAxis(otherAxis)) {
|
|
onZeroAxisIndex = +idx;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if (onZeroAxisIndex == null) {
|
|
axis.onZero = false;
|
|
}
|
|
axis.onZeroAxisIndex = onZeroAxisIndex;
|
|
}
|
|
function canNotOnZeroToAxis(axis) {
|
|
return axis.type === 'category' || axis.type === 'time' || !ifAxisCrossZero(axis);
|
|
}
|
|
/**
|
|
* Resize the grid
|
|
* @param {module:echarts/coord/cartesian/GridModel} gridModel
|
|
* @param {module:echarts/ExtensionAPI} api
|
|
*/
|
|
gridProto.resize = function (gridModel, api, ignoreContainLabel) {
|
|
var gridRect = layout.getLayoutRect(gridModel.getBoxLayoutParams(), {
|
|
width: api.getWidth(),
|
|
height: api.getHeight()
|
|
});
|
|
this._rect = gridRect;
|
|
var axesList = this._axesList;
|
|
adjustAxes();
|
|
// Minus label size
|
|
if (!ignoreContainLabel && gridModel.get('containLabel')) {
|
|
each(axesList, function (axis) {
|
|
if (!axis.model.get('axisLabel.inside')) {
|
|
var labelUnionRect = getLabelUnionRect(axis);
|
|
if (labelUnionRect) {
|
|
var dim = axis.isHorizontal() ? 'height' : 'width';
|
|
var margin = axis.model.get('axisLabel.margin');
|
|
gridRect[dim] -= labelUnionRect[dim] + margin;
|
|
if (axis.position === 'top') {
|
|
gridRect.y += labelUnionRect.height + margin;
|
|
} else if (axis.position === 'left') {
|
|
gridRect.x += labelUnionRect.width + margin;
|
|
}
|
|
}
|
|
}
|
|
});
|
|
adjustAxes();
|
|
}
|
|
function adjustAxes() {
|
|
each(axesList, function (axis) {
|
|
var isHorizontal = axis.isHorizontal();
|
|
var extent = isHorizontal ? [
|
|
0,
|
|
gridRect.width
|
|
] : [
|
|
0,
|
|
gridRect.height
|
|
];
|
|
var idx = axis.inverse ? 1 : 0;
|
|
axis.setExtent(extent[idx], extent[1 - idx]);
|
|
updateAxisTransfrom(axis, isHorizontal ? gridRect.x : gridRect.y);
|
|
});
|
|
}
|
|
};
|
|
/**
|
|
* @param {string} axisType
|
|
* @param {number} [axisIndex]
|
|
*/
|
|
gridProto.getAxis = function (axisType, axisIndex) {
|
|
var axesMapOnDim = this._axesMap[axisType];
|
|
if (axesMapOnDim != null) {
|
|
if (axisIndex == null) {
|
|
// Find first axis
|
|
for (var name in axesMapOnDim) {
|
|
if (axesMapOnDim.hasOwnProperty(name)) {
|
|
return axesMapOnDim[name];
|
|
}
|
|
}
|
|
}
|
|
return axesMapOnDim[axisIndex];
|
|
}
|
|
};
|
|
/**
|
|
* @return {Array.<module:echarts/coord/Axis>}
|
|
*/
|
|
gridProto.getAxes = function () {
|
|
return this._axesList.slice();
|
|
};
|
|
/**
|
|
* Usage:
|
|
* grid.getCartesian(xAxisIndex, yAxisIndex);
|
|
* grid.getCartesian(xAxisIndex);
|
|
* grid.getCartesian(null, yAxisIndex);
|
|
* grid.getCartesian({xAxisIndex: ..., yAxisIndex: ...});
|
|
*
|
|
* @param {number|Object} [xAxisIndex]
|
|
* @param {number} [yAxisIndex]
|
|
*/
|
|
gridProto.getCartesian = function (xAxisIndex, yAxisIndex) {
|
|
if (xAxisIndex != null && yAxisIndex != null) {
|
|
var key = 'x' + xAxisIndex + 'y' + yAxisIndex;
|
|
return this._coordsMap[key];
|
|
}
|
|
if (zrUtil.isObject(xAxisIndex)) {
|
|
yAxisIndex = xAxisIndex.yAxisIndex;
|
|
xAxisIndex = xAxisIndex.xAxisIndex;
|
|
}
|
|
// When only xAxisIndex or yAxisIndex given, find its first cartesian.
|
|
for (var i = 0, coordList = this._coordsList; i < coordList.length; i++) {
|
|
if (coordList[i].getAxis('x').index === xAxisIndex || coordList[i].getAxis('y').index === yAxisIndex) {
|
|
return coordList[i];
|
|
}
|
|
}
|
|
};
|
|
gridProto.getCartesians = function () {
|
|
return this._coordsList.slice();
|
|
};
|
|
/**
|
|
* @implements
|
|
* see {module:echarts/CoodinateSystem}
|
|
*/
|
|
gridProto.convertToPixel = function (ecModel, finder, value) {
|
|
var target = this._findConvertTarget(ecModel, finder);
|
|
return target.cartesian ? target.cartesian.dataToPoint(value) : target.axis ? target.axis.toGlobalCoord(target.axis.dataToCoord(value)) : null;
|
|
};
|
|
/**
|
|
* @implements
|
|
* see {module:echarts/CoodinateSystem}
|
|
*/
|
|
gridProto.convertFromPixel = function (ecModel, finder, value) {
|
|
var target = this._findConvertTarget(ecModel, finder);
|
|
return target.cartesian ? target.cartesian.pointToData(value) : target.axis ? target.axis.coordToData(target.axis.toLocalCoord(value)) : null;
|
|
};
|
|
/**
|
|
* @inner
|
|
*/
|
|
gridProto._findConvertTarget = function (ecModel, finder) {
|
|
var seriesModel = finder.seriesModel;
|
|
var xAxisModel = finder.xAxisModel || seriesModel && seriesModel.getReferringComponents('xAxis')[0];
|
|
var yAxisModel = finder.yAxisModel || seriesModel && seriesModel.getReferringComponents('yAxis')[0];
|
|
var gridModel = finder.gridModel;
|
|
var coordsList = this._coordsList;
|
|
var cartesian;
|
|
var axis;
|
|
if (seriesModel) {
|
|
cartesian = seriesModel.coordinateSystem;
|
|
zrUtil.indexOf(coordsList, cartesian) < 0 && (cartesian = null);
|
|
} else if (xAxisModel && yAxisModel) {
|
|
cartesian = this.getCartesian(xAxisModel.componentIndex, yAxisModel.componentIndex);
|
|
} else if (xAxisModel) {
|
|
axis = this.getAxis('x', xAxisModel.componentIndex);
|
|
} else if (yAxisModel) {
|
|
axis = this.getAxis('y', yAxisModel.componentIndex);
|
|
} // Lowest priority.
|
|
else if (gridModel) {
|
|
var grid = gridModel.coordinateSystem;
|
|
if (grid === this) {
|
|
cartesian = this._coordsList[0];
|
|
}
|
|
}
|
|
return {
|
|
cartesian: cartesian,
|
|
axis: axis
|
|
};
|
|
};
|
|
/**
|
|
* @implements
|
|
* see {module:echarts/CoodinateSystem}
|
|
*/
|
|
gridProto.containPoint = function (point) {
|
|
var coord = this._coordsList[0];
|
|
if (coord) {
|
|
return coord.containPoint(point);
|
|
}
|
|
};
|
|
/**
|
|
* Initialize cartesian coordinate systems
|
|
* @private
|
|
*/
|
|
gridProto._initCartesian = function (gridModel, ecModel, api) {
|
|
var axisPositionUsed = {
|
|
left: false,
|
|
right: false,
|
|
top: false,
|
|
bottom: false
|
|
};
|
|
var axesMap = {
|
|
x: {},
|
|
y: {}
|
|
};
|
|
var axesCount = {
|
|
x: 0,
|
|
y: 0
|
|
};
|
|
/// Create axis
|
|
ecModel.eachComponent('xAxis', createAxisCreator('x'), this);
|
|
ecModel.eachComponent('yAxis', createAxisCreator('y'), this);
|
|
if (!axesCount.x || !axesCount.y) {
|
|
// Roll back when there no either x or y axis
|
|
this._axesMap = {};
|
|
this._axesList = [];
|
|
return;
|
|
}
|
|
this._axesMap = axesMap;
|
|
/// Create cartesian2d
|
|
each(axesMap.x, function (xAxis, xAxisIndex) {
|
|
each(axesMap.y, function (yAxis, yAxisIndex) {
|
|
var key = 'x' + xAxisIndex + 'y' + yAxisIndex;
|
|
var cartesian = new Cartesian2D(key);
|
|
cartesian.grid = this;
|
|
cartesian.model = gridModel;
|
|
this._coordsMap[key] = cartesian;
|
|
this._coordsList.push(cartesian);
|
|
cartesian.addAxis(xAxis);
|
|
cartesian.addAxis(yAxis);
|
|
}, this);
|
|
}, this);
|
|
function createAxisCreator(axisType) {
|
|
return function (axisModel, idx) {
|
|
if (!isAxisUsedInTheGrid(axisModel, gridModel, ecModel)) {
|
|
return;
|
|
}
|
|
var axisPosition = axisModel.get('position');
|
|
if (axisType === 'x') {
|
|
// Fix position
|
|
if (axisPosition !== 'top' && axisPosition !== 'bottom') {
|
|
// Default bottom of X
|
|
axisPosition = 'bottom';
|
|
if (axisPositionUsed[axisPosition]) {
|
|
axisPosition = axisPosition === 'top' ? 'bottom' : 'top';
|
|
}
|
|
}
|
|
} else {
|
|
// Fix position
|
|
if (axisPosition !== 'left' && axisPosition !== 'right') {
|
|
// Default left of Y
|
|
axisPosition = 'left';
|
|
if (axisPositionUsed[axisPosition]) {
|
|
axisPosition = axisPosition === 'left' ? 'right' : 'left';
|
|
}
|
|
}
|
|
}
|
|
axisPositionUsed[axisPosition] = true;
|
|
var axis = new Axis2D(axisType, axisHelper.createScaleByModel(axisModel), [
|
|
0,
|
|
0
|
|
], axisModel.get('type'), axisPosition);
|
|
var isCategory = axis.type === 'category';
|
|
axis.onBand = isCategory && axisModel.get('boundaryGap');
|
|
axis.inverse = axisModel.get('inverse');
|
|
axis.onZero = axisModel.get('axisLine.onZero');
|
|
axis.onZeroAxisIndex = axisModel.get('axisLine.onZeroAxisIndex');
|
|
// Inject axis into axisModel
|
|
axisModel.axis = axis;
|
|
// Inject axisModel into axis
|
|
axis.model = axisModel;
|
|
// Inject grid info axis
|
|
axis.grid = this;
|
|
// Index of axis, can be used as key
|
|
axis.index = idx;
|
|
this._axesList.push(axis);
|
|
axesMap[axisType][idx] = axis;
|
|
axesCount[axisType]++;
|
|
};
|
|
}
|
|
};
|
|
/**
|
|
* Update cartesian properties from series
|
|
* @param {module:echarts/model/Option} option
|
|
* @private
|
|
*/
|
|
gridProto._updateScale = function (ecModel, gridModel) {
|
|
// Reset scale
|
|
zrUtil.each(this._axesList, function (axis) {
|
|
axis.scale.setExtent(Infinity, -Infinity);
|
|
});
|
|
ecModel.eachSeries(function (seriesModel) {
|
|
if (isCartesian2D(seriesModel)) {
|
|
var axesModels = findAxesModels(seriesModel, ecModel);
|
|
var xAxisModel = axesModels[0];
|
|
var yAxisModel = axesModels[1];
|
|
if (!isAxisUsedInTheGrid(xAxisModel, gridModel, ecModel) || !isAxisUsedInTheGrid(yAxisModel, gridModel, ecModel)) {
|
|
return;
|
|
}
|
|
var cartesian = this.getCartesian(xAxisModel.componentIndex, yAxisModel.componentIndex);
|
|
var data = seriesModel.getData();
|
|
var xAxis = cartesian.getAxis('x');
|
|
var yAxis = cartesian.getAxis('y');
|
|
if (data.type === 'list') {
|
|
unionExtent(data, xAxis, seriesModel);
|
|
unionExtent(data, yAxis, seriesModel);
|
|
}
|
|
}
|
|
}, this);
|
|
function unionExtent(data, axis, seriesModel) {
|
|
each(seriesModel.coordDimToDataDim(axis.dim), function (dim) {
|
|
axis.scale.unionExtentFromData(data, dim);
|
|
});
|
|
}
|
|
};
|
|
/**
|
|
* @param {string} [dim] 'x' or 'y' or 'auto' or null/undefined
|
|
* @return {Object} {baseAxes: [], otherAxes: []}
|
|
*/
|
|
gridProto.getTooltipAxes = function (dim) {
|
|
var baseAxes = [];
|
|
var otherAxes = [];
|
|
each(this.getCartesians(), function (cartesian) {
|
|
var baseAxis = dim != null && dim !== 'auto' ? cartesian.getAxis(dim) : cartesian.getBaseAxis();
|
|
var otherAxis = cartesian.getOtherAxis(baseAxis);
|
|
zrUtil.indexOf(baseAxes, baseAxis) < 0 && baseAxes.push(baseAxis);
|
|
zrUtil.indexOf(otherAxes, otherAxis) < 0 && otherAxes.push(otherAxis);
|
|
});
|
|
return {
|
|
baseAxes: baseAxes,
|
|
otherAxes: otherAxes
|
|
};
|
|
};
|
|
/**
|
|
* @inner
|
|
*/
|
|
function updateAxisTransfrom(axis, coordBase) {
|
|
var axisExtent = axis.getExtent();
|
|
var axisExtentSum = axisExtent[0] + axisExtent[1];
|
|
// Fast transform
|
|
axis.toGlobalCoord = axis.dim === 'x' ? function (coord) {
|
|
return coord + coordBase;
|
|
} : function (coord) {
|
|
return axisExtentSum - coord + coordBase;
|
|
};
|
|
axis.toLocalCoord = axis.dim === 'x' ? function (coord) {
|
|
return coord - coordBase;
|
|
} : function (coord) {
|
|
return axisExtentSum - coord + coordBase;
|
|
};
|
|
}
|
|
var axesTypes = [
|
|
'xAxis',
|
|
'yAxis'
|
|
];
|
|
/**
|
|
* @inner
|
|
*/
|
|
function findAxesModels(seriesModel, ecModel) {
|
|
return zrUtil.map(axesTypes, function (axisType) {
|
|
var axisModel = seriesModel.getReferringComponents(axisType)[0];
|
|
if (true) {
|
|
if (!axisModel) {
|
|
throw new Error(axisType + ' "' + zrUtil.retrieve(seriesModel.get(axisType + 'Index'), seriesModel.get(axisType + 'Id'), 0) + '" not found');
|
|
}
|
|
}
|
|
return axisModel;
|
|
});
|
|
}
|
|
/**
|
|
* @inner
|
|
*/
|
|
function isCartesian2D(seriesModel) {
|
|
return seriesModel.get('coordinateSystem') === 'cartesian2d';
|
|
}
|
|
Grid.create = function (ecModel, api) {
|
|
var grids = [];
|
|
ecModel.eachComponent('grid', function (gridModel, idx) {
|
|
var grid = new Grid(gridModel, ecModel, api);
|
|
grid.name = 'grid_' + idx;
|
|
// dataSampling requires axis extent, so resize
|
|
// should be performed in create stage.
|
|
grid.resize(gridModel, api, true);
|
|
gridModel.coordinateSystem = grid;
|
|
grids.push(grid);
|
|
});
|
|
// Inject the coordinateSystems into seriesModel
|
|
ecModel.eachSeries(function (seriesModel) {
|
|
if (!isCartesian2D(seriesModel)) {
|
|
return;
|
|
}
|
|
var axesModels = findAxesModels(seriesModel, ecModel);
|
|
var xAxisModel = axesModels[0];
|
|
var yAxisModel = axesModels[1];
|
|
var gridModel = xAxisModel.getCoordSysModel();
|
|
if (true) {
|
|
if (!gridModel) {
|
|
throw new Error('Grid "' + zrUtil.retrieve(xAxisModel.get('gridIndex'), xAxisModel.get('gridId'), 0) + '" not found');
|
|
}
|
|
if (xAxisModel.getCoordSysModel() !== yAxisModel.getCoordSysModel()) {
|
|
throw new Error('xAxis and yAxis must use the same grid');
|
|
}
|
|
}
|
|
var grid = gridModel.coordinateSystem;
|
|
seriesModel.coordinateSystem = grid.getCartesian(xAxisModel.componentIndex, yAxisModel.componentIndex);
|
|
});
|
|
return grids;
|
|
};
|
|
// For deciding which dimensions to use when creating list data
|
|
Grid.dimensions = Grid.prototype.dimensions = Cartesian2D.prototype.dimensions;
|
|
require('../../CoordinateSystem').register('cartesian2d', Grid);
|
|
return Grid;
|
|
});
|
|
define('echarts/chart/candlestick/preprocessor', ['require', 'zrender/core/util'], function (require) {
|
|
var zrUtil = require('zrender/core/util');
|
|
return function (option) {
|
|
if (!option || !zrUtil.isArray(option.series)) {
|
|
return;
|
|
}
|
|
// Translate 'k' to 'candlestick'.
|
|
zrUtil.each(option.series, function (seriesItem) {
|
|
if (zrUtil.isObject(seriesItem) && seriesItem.type === 'k') {
|
|
seriesItem.type = 'candlestick';
|
|
}
|
|
});
|
|
};
|
|
});
|
|
define('echarts/chart/candlestick/candlestickVisual', ['require'], function (require) {
|
|
var positiveBorderColorQuery = [
|
|
'itemStyle',
|
|
'normal',
|
|
'borderColor'
|
|
];
|
|
var negativeBorderColorQuery = [
|
|
'itemStyle',
|
|
'normal',
|
|
'borderColor0'
|
|
];
|
|
var positiveColorQuery = [
|
|
'itemStyle',
|
|
'normal',
|
|
'color'
|
|
];
|
|
var negativeColorQuery = [
|
|
'itemStyle',
|
|
'normal',
|
|
'color0'
|
|
];
|
|
return function (ecModel, api) {
|
|
ecModel.eachRawSeriesByType('candlestick', function (seriesModel) {
|
|
var data = seriesModel.getData();
|
|
data.setVisual({ legendSymbol: 'roundRect' });
|
|
// Only visible series has each data be visual encoded
|
|
if (!ecModel.isSeriesFiltered(seriesModel)) {
|
|
data.each(function (idx) {
|
|
var itemModel = data.getItemModel(idx);
|
|
var sign = data.getItemLayout(idx).sign;
|
|
data.setItemVisual(idx, {
|
|
color: itemModel.get(sign > 0 ? positiveColorQuery : negativeColorQuery),
|
|
borderColor: itemModel.get(sign > 0 ? positiveBorderColorQuery : negativeBorderColorQuery)
|
|
});
|
|
});
|
|
}
|
|
});
|
|
};
|
|
});
|
|
define('echarts/chart/candlestick/candlestickLayout', ['require', 'zrender/core/util', '../../util/number', '../../util/graphic'], function (require) {
|
|
var zrUtil = require('zrender/core/util');
|
|
var retrieve = require('zrender/core/util').retrieve;
|
|
var parsePercent = require('../../util/number').parsePercent;
|
|
var graphic = require('../../util/graphic');
|
|
return function (ecModel) {
|
|
ecModel.eachSeriesByType('candlestick', function (seriesModel) {
|
|
var coordSys = seriesModel.coordinateSystem;
|
|
var data = seriesModel.getData();
|
|
var candleWidth = calculateCandleWidth(seriesModel, data);
|
|
var chartLayout = seriesModel.get('layout');
|
|
var variableDim = chartLayout === 'horizontal' ? 0 : 1;
|
|
var constDim = 1 - variableDim;
|
|
var coordDims = [
|
|
'x',
|
|
'y'
|
|
];
|
|
var vDims = [];
|
|
var cDim;
|
|
zrUtil.each(data.dimensions, function (dimName) {
|
|
var dimInfo = data.getDimensionInfo(dimName);
|
|
var coordDim = dimInfo.coordDim;
|
|
if (coordDim === coordDims[constDim]) {
|
|
vDims.push(dimName);
|
|
} else if (coordDim === coordDims[variableDim]) {
|
|
cDim = dimName;
|
|
}
|
|
});
|
|
if (cDim == null || vDims.length < 4) {
|
|
return;
|
|
}
|
|
var dataIndex = 0;
|
|
data.each([cDim].concat(vDims), function () {
|
|
var args = arguments;
|
|
var axisDimVal = args[0];
|
|
var idx = args[vDims.length + 1];
|
|
var openVal = args[1];
|
|
var closeVal = args[2];
|
|
var lowestVal = args[3];
|
|
var highestVal = args[4];
|
|
var ocLow = Math.min(openVal, closeVal);
|
|
var ocHigh = Math.max(openVal, closeVal);
|
|
var ocLowPoint = getPoint(ocLow);
|
|
var ocHighPoint = getPoint(ocHigh);
|
|
var lowestPoint = getPoint(lowestVal);
|
|
var highestPoint = getPoint(highestVal);
|
|
var whiskerEnds = [
|
|
[
|
|
subPixelOptimizePoint(highestPoint),
|
|
subPixelOptimizePoint(ocHighPoint)
|
|
],
|
|
[
|
|
subPixelOptimizePoint(lowestPoint),
|
|
subPixelOptimizePoint(ocLowPoint)
|
|
]
|
|
];
|
|
var bodyEnds = [];
|
|
addBodyEnd(ocHighPoint, 0);
|
|
addBodyEnd(ocLowPoint, 1);
|
|
var sign;
|
|
if (openVal > closeVal) {
|
|
sign = -1;
|
|
} else if (openVal < closeVal) {
|
|
sign = 1;
|
|
} else {
|
|
// If close === open, compare with close of last record
|
|
if (dataIndex > 0) {
|
|
sign = data.getItemModel(dataIndex - 1).get()[2] <= closeVal ? 1 : -1;
|
|
} else {
|
|
// No record of previous, set to be positive
|
|
sign = 1;
|
|
}
|
|
}
|
|
data.setItemLayout(idx, {
|
|
chartLayout: chartLayout,
|
|
sign: sign,
|
|
initBaseline: openVal > closeVal ? ocHighPoint[constDim] : ocLowPoint[constDim],
|
|
bodyEnds: bodyEnds,
|
|
whiskerEnds: whiskerEnds,
|
|
brushRect: makeBrushRect()
|
|
});
|
|
++dataIndex;
|
|
function getPoint(val) {
|
|
var p = [];
|
|
p[variableDim] = axisDimVal;
|
|
p[constDim] = val;
|
|
return isNaN(axisDimVal) || isNaN(val) ? [
|
|
NaN,
|
|
NaN
|
|
] : coordSys.dataToPoint(p);
|
|
}
|
|
function addBodyEnd(point, start) {
|
|
var point1 = point.slice();
|
|
var point2 = point.slice();
|
|
point1[variableDim] = graphic.subPixelOptimize(point1[variableDim] + candleWidth / 2, 1, false);
|
|
point2[variableDim] = graphic.subPixelOptimize(point2[variableDim] - candleWidth / 2, 1, true);
|
|
start ? bodyEnds.push(point1, point2) : bodyEnds.push(point2, point1);
|
|
}
|
|
function makeBrushRect() {
|
|
var pmin = getPoint(Math.min(openVal, closeVal, lowestVal, highestVal));
|
|
var pmax = getPoint(Math.max(openVal, closeVal, lowestVal, highestVal));
|
|
pmin[variableDim] -= candleWidth / 2;
|
|
pmax[variableDim] -= candleWidth / 2;
|
|
return {
|
|
x: pmin[0],
|
|
y: pmin[1],
|
|
width: constDim ? candleWidth : pmax[0] - pmin[0],
|
|
height: constDim ? pmax[1] - pmin[1] : candleWidth
|
|
};
|
|
}
|
|
function subPixelOptimizePoint(point) {
|
|
point[variableDim] = graphic.subPixelOptimize(point[variableDim], 1);
|
|
return point;
|
|
}
|
|
}, true);
|
|
});
|
|
};
|
|
function calculateCandleWidth(seriesModel, data) {
|
|
var baseAxis = seriesModel.getBaseAxis();
|
|
var extent;
|
|
var bandWidth = baseAxis.type === 'category' ? baseAxis.getBandWidth() : (extent = baseAxis.getExtent(), Math.abs(extent[1] - extent[0]) / data.count());
|
|
var barMaxWidth = parsePercent(retrieve(seriesModel.get('barMaxWidth'), bandWidth), bandWidth);
|
|
var barMinWidth = parsePercent(retrieve(seriesModel.get('barMinWidth'), 1), bandWidth);
|
|
var barWidth = seriesModel.get('barWidth');
|
|
return barWidth != null ? parsePercent(barWidth, bandWidth) : Math.max(Math.min(bandWidth / 2, barMaxWidth), barMinWidth);
|
|
}
|
|
});
|
|
define('echarts/chart/heatmap/HeatmapSeries', ['require', '../../model/Series', '../helper/createListFromArray'], function (require) {
|
|
var SeriesModel = require('../../model/Series');
|
|
var createListFromArray = require('../helper/createListFromArray');
|
|
return SeriesModel.extend({
|
|
type: 'series.heatmap',
|
|
getInitialData: function (option, ecModel) {
|
|
return createListFromArray(option.data, this, ecModel);
|
|
},
|
|
defaultOption: {
|
|
coordinateSystem: 'cartesian2d',
|
|
zlevel: 0,
|
|
z: 2,
|
|
geoIndex: 0,
|
|
blurSize: 30,
|
|
pointSize: 20,
|
|
maxOpacity: 1,
|
|
minOpacity: 0
|
|
}
|
|
});
|
|
});
|
|
define('echarts/chart/heatmap/HeatmapView', ['require', '../../util/graphic', './HeatmapLayer', 'zrender/core/util', '../../echarts'], function (require) {
|
|
var graphic = require('../../util/graphic');
|
|
var HeatmapLayer = require('./HeatmapLayer');
|
|
var zrUtil = require('zrender/core/util');
|
|
function getIsInPiecewiseRange(dataExtent, pieceList, selected) {
|
|
var dataSpan = dataExtent[1] - dataExtent[0];
|
|
pieceList = zrUtil.map(pieceList, function (piece) {
|
|
return {
|
|
interval: [
|
|
(piece.interval[0] - dataExtent[0]) / dataSpan,
|
|
(piece.interval[1] - dataExtent[0]) / dataSpan
|
|
]
|
|
};
|
|
});
|
|
var len = pieceList.length;
|
|
var lastIndex = 0;
|
|
return function (val) {
|
|
// Try to find in the location of the last found
|
|
for (var i = lastIndex; i < len; i++) {
|
|
var interval = pieceList[i].interval;
|
|
if (interval[0] <= val && val <= interval[1]) {
|
|
lastIndex = i;
|
|
break;
|
|
}
|
|
}
|
|
if (i === len) {
|
|
// Not found, back interation
|
|
for (var i = lastIndex - 1; i >= 0; i--) {
|
|
var interval = pieceList[i].interval;
|
|
if (interval[0] <= val && val <= interval[1]) {
|
|
lastIndex = i;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
return i >= 0 && i < len && selected[i];
|
|
};
|
|
}
|
|
function getIsInContinuousRange(dataExtent, range) {
|
|
var dataSpan = dataExtent[1] - dataExtent[0];
|
|
range = [
|
|
(range[0] - dataExtent[0]) / dataSpan,
|
|
(range[1] - dataExtent[0]) / dataSpan
|
|
];
|
|
return function (val) {
|
|
return val >= range[0] && val <= range[1];
|
|
};
|
|
}
|
|
function isGeoCoordSys(coordSys) {
|
|
var dimensions = coordSys.dimensions;
|
|
// Not use coorSys.type === 'geo' because coordSys maybe extended
|
|
return dimensions[0] === 'lng' && dimensions[1] === 'lat';
|
|
}
|
|
return require('../../echarts').extendChartView({
|
|
type: 'heatmap',
|
|
render: function (seriesModel, ecModel, api) {
|
|
var visualMapOfThisSeries;
|
|
ecModel.eachComponent('visualMap', function (visualMap) {
|
|
visualMap.eachTargetSeries(function (targetSeries) {
|
|
if (targetSeries === seriesModel) {
|
|
visualMapOfThisSeries = visualMap;
|
|
}
|
|
});
|
|
});
|
|
if (true) {
|
|
if (!visualMapOfThisSeries) {
|
|
throw new Error('Heatmap must use with visualMap');
|
|
}
|
|
}
|
|
this.group.removeAll();
|
|
var coordSys = seriesModel.coordinateSystem;
|
|
if (coordSys.type === 'cartesian2d' || coordSys.type === 'calendar') {
|
|
this._renderOnCartesianAndCalendar(coordSys, seriesModel, api);
|
|
} else if (isGeoCoordSys(coordSys)) {
|
|
this._renderOnGeo(coordSys, seriesModel, visualMapOfThisSeries, api);
|
|
}
|
|
},
|
|
dispose: function () {
|
|
},
|
|
_renderOnCartesianAndCalendar: function (coordSys, seriesModel, api) {
|
|
if (coordSys.type === 'cartesian2d') {
|
|
var xAxis = coordSys.getAxis('x');
|
|
var yAxis = coordSys.getAxis('y');
|
|
if (true) {
|
|
if (!(xAxis.type === 'category' && yAxis.type === 'category')) {
|
|
throw new Error('Heatmap on cartesian must have two category axes');
|
|
}
|
|
if (!(xAxis.onBand && yAxis.onBand)) {
|
|
throw new Error('Heatmap on cartesian must have two axes with boundaryGap true');
|
|
}
|
|
}
|
|
var width = xAxis.getBandWidth();
|
|
var height = yAxis.getBandWidth();
|
|
}
|
|
var group = this.group;
|
|
var data = seriesModel.getData();
|
|
var itemStyleQuery = 'itemStyle.normal';
|
|
var hoverItemStyleQuery = 'itemStyle.emphasis';
|
|
var labelQuery = 'label.normal';
|
|
var hoverLabelQuery = 'label.emphasis';
|
|
var style = seriesModel.getModel(itemStyleQuery).getItemStyle(['color']);
|
|
var hoverStl = seriesModel.getModel(hoverItemStyleQuery).getItemStyle();
|
|
var labelModel = seriesModel.getModel('label.normal');
|
|
var hoverLabelModel = seriesModel.getModel('label.emphasis');
|
|
var coordSysType = coordSys.type;
|
|
var dataDims = coordSysType === 'cartesian2d' ? [
|
|
seriesModel.coordDimToDataDim('x')[0],
|
|
seriesModel.coordDimToDataDim('y')[0],
|
|
seriesModel.coordDimToDataDim('value')[0]
|
|
] : [
|
|
seriesModel.coordDimToDataDim('time')[0],
|
|
seriesModel.coordDimToDataDim('value')[0]
|
|
];
|
|
data.each(function (idx) {
|
|
var rect;
|
|
if (coordSysType === 'cartesian2d') {
|
|
// Ignore empty data
|
|
if (isNaN(data.get(dataDims[2], idx))) {
|
|
return;
|
|
}
|
|
var point = coordSys.dataToPoint([
|
|
data.get(dataDims[0], idx),
|
|
data.get(dataDims[1], idx)
|
|
]);
|
|
rect = new graphic.Rect({
|
|
shape: {
|
|
x: point[0] - width / 2,
|
|
y: point[1] - height / 2,
|
|
width: width,
|
|
height: height
|
|
},
|
|
style: {
|
|
fill: data.getItemVisual(idx, 'color'),
|
|
opacity: data.getItemVisual(idx, 'opacity')
|
|
}
|
|
});
|
|
} else {
|
|
// Ignore empty data
|
|
if (isNaN(data.get(dataDims[1], idx))) {
|
|
return;
|
|
}
|
|
rect = new graphic.Rect({
|
|
z2: 1,
|
|
shape: coordSys.dataToRect([data.get(dataDims[0], idx)]).contentShape,
|
|
style: {
|
|
fill: data.getItemVisual(idx, 'color'),
|
|
opacity: data.getItemVisual(idx, 'opacity')
|
|
}
|
|
});
|
|
}
|
|
var itemModel = data.getItemModel(idx);
|
|
// Optimization for large datset
|
|
if (data.hasItemOption) {
|
|
style = itemModel.getModel(itemStyleQuery).getItemStyle(['color']);
|
|
hoverStl = itemModel.getModel(hoverItemStyleQuery).getItemStyle();
|
|
labelModel = itemModel.getModel(labelQuery);
|
|
hoverLabelModel = itemModel.getModel(hoverLabelQuery);
|
|
}
|
|
var rawValue = seriesModel.getRawValue(idx);
|
|
var defaultText = '-';
|
|
if (rawValue && rawValue[2] != null) {
|
|
defaultText = rawValue[2];
|
|
}
|
|
graphic.setLabelStyle(style, hoverStl, labelModel, hoverLabelModel, {
|
|
labelFetcher: seriesModel,
|
|
labelDataIndex: idx,
|
|
defaultText: defaultText,
|
|
isRectText: true
|
|
});
|
|
rect.setStyle(style);
|
|
graphic.setHoverStyle(rect, data.hasItemOption ? hoverStl : zrUtil.extend({}, hoverStl));
|
|
group.add(rect);
|
|
data.setItemGraphicEl(idx, rect);
|
|
});
|
|
},
|
|
_renderOnGeo: function (geo, seriesModel, visualMapModel, api) {
|
|
var inRangeVisuals = visualMapModel.targetVisuals.inRange;
|
|
var outOfRangeVisuals = visualMapModel.targetVisuals.outOfRange;
|
|
// if (!visualMapping) {
|
|
// throw new Error('Data range must have color visuals');
|
|
// }
|
|
var data = seriesModel.getData();
|
|
var hmLayer = this._hmLayer || (this._hmLayer || new HeatmapLayer());
|
|
hmLayer.blurSize = seriesModel.get('blurSize');
|
|
hmLayer.pointSize = seriesModel.get('pointSize');
|
|
hmLayer.minOpacity = seriesModel.get('minOpacity');
|
|
hmLayer.maxOpacity = seriesModel.get('maxOpacity');
|
|
var rect = geo.getViewRect().clone();
|
|
var roamTransform = geo.getRoamTransform().transform;
|
|
rect.applyTransform(roamTransform);
|
|
// Clamp on viewport
|
|
var x = Math.max(rect.x, 0);
|
|
var y = Math.max(rect.y, 0);
|
|
var x2 = Math.min(rect.width + rect.x, api.getWidth());
|
|
var y2 = Math.min(rect.height + rect.y, api.getHeight());
|
|
var width = x2 - x;
|
|
var height = y2 - y;
|
|
var points = data.mapArray([
|
|
'lng',
|
|
'lat',
|
|
'value'
|
|
], function (lng, lat, value) {
|
|
var pt = geo.dataToPoint([
|
|
lng,
|
|
lat
|
|
]);
|
|
pt[0] -= x;
|
|
pt[1] -= y;
|
|
pt.push(value);
|
|
return pt;
|
|
});
|
|
var dataExtent = visualMapModel.getExtent();
|
|
var isInRange = visualMapModel.type === 'visualMap.continuous' ? getIsInContinuousRange(dataExtent, visualMapModel.option.range) : getIsInPiecewiseRange(dataExtent, visualMapModel.getPieceList(), visualMapModel.option.selected);
|
|
hmLayer.update(points, width, height, inRangeVisuals.color.getNormalizer(), {
|
|
inRange: inRangeVisuals.color.getColorMapper(),
|
|
outOfRange: outOfRangeVisuals.color.getColorMapper()
|
|
}, isInRange);
|
|
var img = new graphic.Image({
|
|
style: {
|
|
width: width,
|
|
height: height,
|
|
x: x,
|
|
y: y,
|
|
image: hmLayer.canvas
|
|
},
|
|
silent: true
|
|
});
|
|
this.group.add(img);
|
|
}
|
|
});
|
|
});
|
|
define('echarts/model/Global', ['require', 'zrender/core/util', '../util/model', './Model', './Component', './globalDefault', './mixin/colorPalette'], function (require) {
|
|
/**
|
|
* Caution: If the mechanism should be changed some day, these cases
|
|
* should be considered:
|
|
*
|
|
* (1) In `merge option` mode, if using the same option to call `setOption`
|
|
* many times, the result should be the same (try our best to ensure that).
|
|
* (2) In `merge option` mode, if a component has no id/name specified, it
|
|
* will be merged by index, and the result sequence of the components is
|
|
* consistent to the original sequence.
|
|
* (3) `reset` feature (in toolbox). Find detailed info in comments about
|
|
* `mergeOption` in module:echarts/model/OptionManager.
|
|
*/
|
|
var zrUtil = require('zrender/core/util');
|
|
var modelUtil = require('../util/model');
|
|
var Model = require('./Model');
|
|
var each = zrUtil.each;
|
|
var filter = zrUtil.filter;
|
|
var map = zrUtil.map;
|
|
var isArray = zrUtil.isArray;
|
|
var indexOf = zrUtil.indexOf;
|
|
var isObject = zrUtil.isObject;
|
|
var ComponentModel = require('./Component');
|
|
var globalDefault = require('./globalDefault');
|
|
var OPTION_INNER_KEY = ' |