1 (function webpackUniversalModuleDefinition(root, factory) {
\r
2 if(typeof exports === 'object' && typeof module === 'object')
\r
3 module.exports = factory();
\r
4 else if(typeof define === 'function' && define.amd)
\r
6 else if(typeof exports === 'object')
\r
7 exports["echarts"] = factory();
\r
9 root["echarts"] = factory();
\r
10 })(this, function() {
\r
11 return /******/ (function(modules) { // webpackBootstrap
\r
12 /******/ // The module cache
\r
13 /******/ var installedModules = {};
\r
15 /******/ // The require function
\r
16 /******/ function __webpack_require__(moduleId) {
\r
18 /******/ // Check if module is in cache
\r
19 /******/ if(installedModules[moduleId])
\r
20 /******/ return installedModules[moduleId].exports;
\r
22 /******/ // Create a new module (and put it into the cache)
\r
23 /******/ var module = installedModules[moduleId] = {
\r
24 /******/ exports: {},
\r
25 /******/ id: moduleId,
\r
26 /******/ loaded: false
\r
29 /******/ // Execute the module function
\r
30 /******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
\r
32 /******/ // Flag the module as loaded
\r
33 /******/ module.loaded = true;
\r
35 /******/ // Return the exports of the module
\r
36 /******/ return module.exports;
\r
40 /******/ // expose the modules object (__webpack_modules__)
\r
41 /******/ __webpack_require__.m = modules;
\r
43 /******/ // expose the module cache
\r
44 /******/ __webpack_require__.c = installedModules;
\r
46 /******/ // __webpack_public_path__
\r
47 /******/ __webpack_require__.p = "";
\r
49 /******/ // Load entry module and return exports
\r
50 /******/ return __webpack_require__(0);
\r
52 /************************************************************************/
\r
55 /***/ function(module, exports, __webpack_require__) {
\r
58 * Export echarts as CommonJS module
\r
60 module.exports = __webpack_require__(1);
\r
62 // Import all charts and components
\r
63 __webpack_require__(91);
\r
64 __webpack_require__(127);
\r
65 __webpack_require__(132);
\r
66 __webpack_require__(141);
\r
67 __webpack_require__(145);
\r
69 __webpack_require__(155);
\r
70 __webpack_require__(177);
\r
71 __webpack_require__(189);
\r
72 __webpack_require__(207);
\r
73 __webpack_require__(211);
\r
74 __webpack_require__(215);
\r
75 __webpack_require__(230);
\r
76 __webpack_require__(236);
\r
77 __webpack_require__(243);
\r
78 __webpack_require__(249);
\r
79 __webpack_require__(253);
\r
80 __webpack_require__(258);
\r
82 __webpack_require__(106);
\r
83 __webpack_require__(262);
\r
84 __webpack_require__(268);
\r
85 __webpack_require__(272);
\r
86 __webpack_require__(283);
\r
87 __webpack_require__(216);
\r
89 __webpack_require__(285);
\r
91 __webpack_require__(286);
\r
92 __webpack_require__(300);
\r
94 __webpack_require__(315);
\r
95 __webpack_require__(319);
\r
97 __webpack_require__(322);
\r
98 __webpack_require__(331);
\r
100 __webpack_require__(345);
\r
105 /***/ function(module, exports, __webpack_require__) {
\r
108 * ECharts, a javascript interactive chart library.
\r
110 * Copyright (c) 2015, Baidu Inc.
\r
111 * All rights reserved.
\r
114 * https://github.com/ecomfe/echarts/blob/master/LICENSE.txt
\r
122 var GlobalModel = __webpack_require__(2);
\r
123 var ExtensionAPI = __webpack_require__(24);
\r
124 var CoordinateSystemManager = __webpack_require__(25);
\r
125 var OptionManager = __webpack_require__(26);
\r
127 var ComponentModel = __webpack_require__(19);
\r
128 var SeriesModel = __webpack_require__(27);
\r
130 var ComponentView = __webpack_require__(28);
\r
131 var ChartView = __webpack_require__(41);
\r
132 var graphic = __webpack_require__(42);
\r
134 var zrender = __webpack_require__(77);
\r
135 var zrUtil = __webpack_require__(3);
\r
136 var colorTool = __webpack_require__(38);
\r
137 var env = __webpack_require__(78);
\r
138 var Eventful = __webpack_require__(32);
\r
140 var each = zrUtil.each;
\r
142 var VISUAL_CODING_STAGES = ['echarts', 'chart', 'component'];
\r
144 // TODO Transform first or filter first
\r
145 var PROCESSOR_STAGES = ['transform', 'filter', 'statistic'];
\r
147 function createRegisterEventWithLowercaseName(method) {
\r
148 return function (eventName, handler, context) {
\r
149 // Event name is all lowercase
\r
150 eventName = eventName && eventName.toLowerCase();
\r
151 Eventful.prototype[method].call(this, eventName, handler, context);
\r
155 * @module echarts~MessageCenter
\r
157 function MessageCenter() {
\r
158 Eventful.call(this);
\r
160 MessageCenter.prototype.on = createRegisterEventWithLowercaseName('on');
\r
161 MessageCenter.prototype.off = createRegisterEventWithLowercaseName('off');
\r
162 MessageCenter.prototype.one = createRegisterEventWithLowercaseName('one');
\r
163 zrUtil.mixin(MessageCenter, Eventful);
\r
165 * @module echarts~ECharts
\r
167 function ECharts (dom, theme, opts) {
\r
170 // Get theme by name
\r
171 if (typeof theme === 'string') {
\r
172 theme = themeStorage[theme];
\r
176 each(optionPreprocessorFuncs, function (preProcess) {
\r
190 * @type {HTMLDomElement}
\r
195 * @type {module:zrender/ZRender}
\r
198 this._zr = zrender.init(dom, {
\r
199 renderer: opts.renderer || 'canvas',
\r
200 devicePixelRatio: opts.devicePixelRatio
\r
207 this._theme = zrUtil.clone(theme);
\r
210 * @type {Array.<module:echarts/view/Chart>}
\r
213 this._chartsViews = [];
\r
216 * @type {Object.<string, module:echarts/view/Chart>}
\r
219 this._chartsMap = {};
\r
222 * @type {Array.<module:echarts/view/Component>}
\r
225 this._componentsViews = [];
\r
228 * @type {Object.<string, module:echarts/view/Component>}
\r
231 this._componentsMap = {};
\r
234 * @type {module:echarts/ExtensionAPI}
\r
237 this._api = new ExtensionAPI(this);
\r
240 * @type {module:echarts/CoordinateSystem}
\r
243 this._coordSysMgr = new CoordinateSystemManager();
\r
245 Eventful.call(this);
\r
248 * @type {module:echarts~MessageCenter}
\r
251 this._messageCenter = new MessageCenter();
\r
253 // Init mouse events
\r
254 this._initEvents();
\r
256 // In case some people write `window.onresize = chart.resize`
\r
257 this.resize = zrUtil.bind(this.resize, this);
\r
260 var echartsProto = ECharts.prototype;
\r
263 * @return {HTMLDomElement}
\r
265 echartsProto.getDom = function () {
\r
270 * @return {module:zrender~ZRender}
\r
272 echartsProto.getZr = function () {
\r
277 * @param {Object} option
\r
278 * @param {boolean} notMerge
\r
279 * @param {boolean} [notRefreshImmediately=false] Useful when setOption frequently.
\r
281 echartsProto.setOption = function (option, notMerge, notRefreshImmediately) {
\r
282 if (!this._model || notMerge) {
\r
283 this._model = new GlobalModel(
\r
284 null, null, this._theme, new OptionManager(this._api)
\r
288 this._model.setOption(option, optionPreprocessorFuncs);
\r
290 updateMethods.prepareAndUpdate.call(this);
\r
292 !notRefreshImmediately && this._zr.refreshImmediately();
\r
298 echartsProto.setTheme = function () {
\r
299 console.log('ECharts#setTheme() is DEPRECATED in ECharts 3.0');
\r
303 * @return {module:echarts/model/Global}
\r
305 echartsProto.getModel = function () {
\r
306 return this._model;
\r
312 echartsProto.getOption = function () {
\r
313 return this._model.getOption();
\r
319 echartsProto.getWidth = function () {
\r
320 return this._zr.getWidth();
\r
326 echartsProto.getHeight = function () {
\r
327 return this._zr.getHeight();
\r
331 * Get canvas which has all thing rendered
\r
332 * @param {Object} opts
\r
333 * @param {string} [opts.backgroundColor]
\r
335 echartsProto.getRenderedCanvas = function (opts) {
\r
336 if (!env.canvasSupported) {
\r
340 opts.pixelRatio = opts.pixelRatio || 1;
\r
341 opts.backgroundColor = opts.backgroundColor
\r
342 || this._model.get('backgroundColor');
\r
344 var list = zr.storage.getDisplayList();
\r
346 zrUtil.each(list, function (el) {
\r
347 el.stopAnimation(true);
\r
349 return zr.painter.getRenderedCanvas(opts);
\r
353 * @param {Object} opts
\r
354 * @param {string} [opts.type='png']
\r
355 * @param {string} [opts.pixelRatio=1]
\r
356 * @param {string} [opts.backgroundColor]
\r
358 echartsProto.getDataURL = function (opts) {
\r
360 var excludeComponents = opts.excludeComponents;
\r
361 var ecModel = this._model;
\r
362 var excludesComponentViews = [];
\r
365 each(excludeComponents, function (componentType) {
\r
366 ecModel.eachComponent({
\r
367 mainType: componentType
\r
368 }, function (component) {
\r
369 var view = self._componentsMap[component.__viewId];
\r
370 if (!view.group.ignore) {
\r
371 excludesComponentViews.push(view);
\r
372 view.group.ignore = true;
\r
377 var url = this.getRenderedCanvas(opts).toDataURL(
\r
378 'image/' + (opts && opts.type || 'png')
\r
381 each(excludesComponentViews, function (view) {
\r
382 view.group.ignore = false;
\r
390 * @param {Object} opts
\r
391 * @param {string} [opts.type='png']
\r
392 * @param {string} [opts.pixelRatio=1]
\r
393 * @param {string} [opts.backgroundColor]
\r
395 echartsProto.getConnectedDataURL = function (opts) {
\r
396 if (!env.canvasSupported) {
\r
399 var groupId = this.group;
\r
400 var mathMin = Math.min;
\r
401 var mathMax = Math.max;
\r
402 var MAX_NUMBER = Infinity;
\r
403 if (connectedGroups[groupId]) {
\r
404 var left = MAX_NUMBER;
\r
405 var top = MAX_NUMBER;
\r
406 var right = -MAX_NUMBER;
\r
407 var bottom = -MAX_NUMBER;
\r
408 var canvasList = [];
\r
409 var dpr = (opts && opts.pixelRatio) || 1;
\r
410 for (var id in instances) {
\r
411 var chart = instances[id];
\r
412 if (chart.group === groupId) {
\r
413 var canvas = chart.getRenderedCanvas(
\r
416 var boundingRect = chart.getDom().getBoundingClientRect();
\r
417 left = mathMin(boundingRect.left, left);
\r
418 top = mathMin(boundingRect.top, top);
\r
419 right = mathMax(boundingRect.right, right);
\r
420 bottom = mathMax(boundingRect.bottom, bottom);
\r
423 left: boundingRect.left,
\r
424 top: boundingRect.top
\r
433 var width = right - left;
\r
434 var height = bottom - top;
\r
435 var targetCanvas = zrUtil.createCanvas();
\r
436 targetCanvas.width = width;
\r
437 targetCanvas.height = height;
\r
438 var zr = zrender.init(targetCanvas);
\r
440 each(canvasList, function (item) {
\r
441 var img = new graphic.Image({
\r
443 x: item.left * dpr - left,
\r
444 y: item.top * dpr - top,
\r
450 zr.refreshImmediately();
\r
452 return targetCanvas.toDataURL('image/' + (opts && opts.type || 'png'));
\r
455 return this.getDataURL(opts);
\r
459 var updateMethods = {
\r
462 * @param {Object} payload
\r
465 update: function (payload) {
\r
466 // console.time && console.time('update');
\r
468 var ecModel = this._model;
\r
469 var api = this._api;
\r
470 var coordSysMgr = this._coordSysMgr;
\r
471 // update before setOption
\r
476 ecModel.restoreData();
\r
479 // Save total ecModel here for undo/redo (after restoring data and before processing data).
\r
480 // Undo (restoration of total ecModel) can be carried out in 'action' or outside API call.
\r
482 // Create new coordinate system each update
\r
483 // In LineView may save the old coordinate system and use it to get the orignal point
\r
484 coordSysMgr.create(this._model, this._api);
\r
486 processData.call(this, ecModel, api);
\r
488 stackSeriesData.call(this, ecModel);
\r
490 coordSysMgr.update(ecModel, api);
\r
492 doLayout.call(this, ecModel, payload);
\r
494 doVisualCoding.call(this, ecModel, payload);
\r
496 doRender.call(this, ecModel, payload);
\r
499 var backgroundColor = ecModel.get('backgroundColor') || 'transparent';
\r
501 var painter = this._zr.painter;
\r
502 // TODO all use clearColor ?
\r
503 if (painter.isSingleCanvas && painter.isSingleCanvas()) {
\r
504 this._zr.configLayer(0, {
\r
505 clearColor: backgroundColor
\r
510 if (!env.canvasSupported) {
\r
511 var colorArr = colorTool.parse(backgroundColor);
\r
512 backgroundColor = colorTool.stringify(colorArr, 'rgb');
\r
513 if (colorArr[3] === 0) {
\r
514 backgroundColor = 'transparent';
\r
517 backgroundColor = backgroundColor;
\r
518 this._dom.style.backgroundColor = backgroundColor;
\r
521 // console.time && console.timeEnd('update');
\r
526 * @param {Object} payload
\r
529 updateView: function (payload) {
\r
530 var ecModel = this._model;
\r
532 // update before setOption
\r
537 doLayout.call(this, ecModel, payload);
\r
539 doVisualCoding.call(this, ecModel, payload);
\r
541 invokeUpdateMethod.call(this, 'updateView', ecModel, payload);
\r
545 * @param {Object} payload
\r
548 updateVisual: function (payload) {
\r
549 var ecModel = this._model;
\r
551 // update before setOption
\r
556 doVisualCoding.call(this, ecModel, payload);
\r
558 invokeUpdateMethod.call(this, 'updateVisual', ecModel, payload);
\r
562 * @param {Object} payload
\r
565 updateLayout: function (payload) {
\r
566 var ecModel = this._model;
\r
568 // update before setOption
\r
573 doLayout.call(this, ecModel, payload);
\r
575 invokeUpdateMethod.call(this, 'updateLayout', ecModel, payload);
\r
579 * @param {Object} payload
\r
582 highlight: function (payload) {
\r
583 toggleHighlight.call(this, 'highlight', payload);
\r
587 * @param {Object} payload
\r
590 downplay: function (payload) {
\r
591 toggleHighlight.call(this, 'downplay', payload);
\r
595 * @param {Object} payload
\r
598 prepareAndUpdate: function (payload) {
\r
599 var ecModel = this._model;
\r
601 prepareView.call(this, 'component', ecModel);
\r
603 prepareView.call(this, 'chart', ecModel);
\r
605 updateMethods.update.call(this, payload);
\r
610 * @param {Object} payload
\r
613 function toggleHighlight(method, payload) {
\r
614 var ecModel = this._model;
\r
616 // dispatchAction before setOption
\r
621 ecModel.eachComponent(
\r
622 {mainType: 'series', query: payload},
\r
623 function (seriesModel, index) {
\r
624 var chartView = this._chartsMap[seriesModel.__viewId];
\r
625 if (chartView && chartView.__alive) {
\r
627 seriesModel, ecModel, this._api, payload
\r
638 echartsProto.resize = function () {
\r
641 var optionChanged = this._model && this._model.resetOption('media');
\r
642 updateMethods[optionChanged ? 'prepareAndUpdate' : 'update'].call(this);
\r
644 // Resize loading effect
\r
645 this._loadingFX && this._loadingFX.resize();
\r
648 var defaultLoadingEffect = __webpack_require__(87);
\r
650 * Show loading effect
\r
651 * @param {string} [name='default']
\r
652 * @param {Object} [cfg]
\r
654 echartsProto.showLoading = function (name, cfg) {
\r
655 if (zrUtil.isObject(name)) {
\r
659 this.hideLoading();
\r
660 var el = defaultLoadingEffect(this._api, cfg);
\r
662 this._loadingFX = el;
\r
668 * Hide loading effect
\r
670 echartsProto.hideLoading = function () {
\r
671 this._loadingFX && this._zr.remove(this._loadingFX);
\r
672 this._loadingFX = null;
\r
676 * @param {Object} eventObj
\r
679 echartsProto.makeActionFromEvent = function (eventObj) {
\r
680 var payload = zrUtil.extend({}, eventObj);
\r
681 payload.type = eventActionMap[eventObj.type];
\r
687 * @param {Object} payload
\r
688 * @param {string} [payload.type] Action type
\r
689 * @param {boolean} [silent=false] Whether trigger event.
\r
691 echartsProto.dispatchAction = function (payload, silent) {
\r
692 var actionWrap = actions[payload.type];
\r
694 var actionInfo = actionWrap.actionInfo;
\r
695 var updateMethod = actionInfo.update || 'update';
\r
697 var payloads = [payload];
\r
698 var batched = false;
\r
700 if (payload.batch) {
\r
702 payloads = zrUtil.map(payload.batch, function (item) {
\r
703 item = zrUtil.defaults(zrUtil.extend({}, item), payload);
\r
709 var eventObjBatch = [];
\r
711 var isHighlightOrDownplay = payload.type === 'highlight' || payload.type === 'downplay';
\r
712 for (var i = 0; i < payloads.length; i++) {
\r
713 var batchItem = payloads[i];
\r
714 // Action can specify the event by return it.
\r
715 eventObj = actionWrap.action(batchItem, this._model);
\r
716 // Emit event outside
\r
717 eventObj = eventObj || zrUtil.extend({}, batchItem);
\r
718 // Convert type to eventType
\r
719 eventObj.type = actionInfo.event || eventObj.type;
\r
720 eventObjBatch.push(eventObj);
\r
722 // Highlight and downplay are special.
\r
723 isHighlightOrDownplay && updateMethods[updateMethod].call(this, batchItem);
\r
726 (updateMethod !== 'none' && !isHighlightOrDownplay)
\r
727 && updateMethods[updateMethod].call(this, payload);
\r
730 // Follow the rule of action batch
\r
733 type: actionInfo.event || payload.type,
\r
734 batch: eventObjBatch
\r
738 eventObj = eventObjBatch[0];
\r
740 this._messageCenter.trigger(eventObj.type, eventObj);
\r
749 echartsProto.on = createRegisterEventWithLowercaseName('on');
\r
750 echartsProto.off = createRegisterEventWithLowercaseName('off');
\r
751 echartsProto.one = createRegisterEventWithLowercaseName('one');
\r
754 * @param {string} methodName
\r
757 function invokeUpdateMethod(methodName, ecModel, payload) {
\r
758 var api = this._api;
\r
760 // Update all components
\r
761 each(this._componentsViews, function (component) {
\r
762 var componentModel = component.__model;
\r
763 component[methodName](componentModel, ecModel, api, payload);
\r
765 updateZ(componentModel, component);
\r
768 // Upate all charts
\r
769 ecModel.eachSeries(function (seriesModel, idx) {
\r
770 var chart = this._chartsMap[seriesModel.__viewId];
\r
771 chart[methodName](seriesModel, ecModel, api, payload);
\r
773 updateZ(seriesModel, chart);
\r
779 * Prepare view instances of charts and components
\r
780 * @param {module:echarts/model/Global} ecModel
\r
783 function prepareView(type, ecModel) {
\r
784 var isComponent = type === 'component';
\r
785 var viewList = isComponent ? this._componentsViews : this._chartsViews;
\r
786 var viewMap = isComponent ? this._componentsMap : this._chartsMap;
\r
789 for (var i = 0; i < viewList.length; i++) {
\r
790 viewList[i].__alive = false;
\r
793 ecModel[isComponent ? 'eachComponent' : 'eachSeries'](function (componentType, model) {
\r
795 if (componentType === 'series') {
\r
800 model = componentType;
\r
803 // Consider: id same and type changed.
\r
804 var viewId = model.id + '_' + model.type;
\r
805 var view = viewMap[viewId];
\r
807 var classType = ComponentModel.parseClassType(model.type);
\r
808 var Clazz = isComponent
\r
809 ? ComponentView.getClass(classType.main, classType.sub)
\r
810 : ChartView.getClass(classType.sub);
\r
812 view = new Clazz();
\r
813 view.init(ecModel, this._api);
\r
814 viewMap[viewId] = view;
\r
815 viewList.push(view);
\r
816 zr.add(view.group);
\r
824 model.__viewId = viewId;
\r
825 view.__alive = true;
\r
826 view.__id = viewId;
\r
827 view.__model = model;
\r
830 for (var i = 0; i < viewList.length;) {
\r
831 var view = viewList[i];
\r
832 if (!view.__alive) {
\r
833 zr.remove(view.group);
\r
834 view.dispose(ecModel, this._api);
\r
835 viewList.splice(i, 1);
\r
836 delete viewMap[view.__id];
\r
845 * Processor data in each series
\r
847 * @param {module:echarts/model/Global} ecModel
\r
850 function processData(ecModel, api) {
\r
851 each(PROCESSOR_STAGES, function (stage) {
\r
852 each(dataProcessorFuncs[stage] || [], function (process) {
\r
853 process(ecModel, api);
\r
861 function stackSeriesData(ecModel) {
\r
862 var stackedDataMap = {};
\r
863 ecModel.eachSeries(function (series) {
\r
864 var stack = series.get('stack');
\r
865 var data = series.getData();
\r
866 if (stack && data.type === 'list') {
\r
867 var previousStack = stackedDataMap[stack];
\r
868 if (previousStack) {
\r
869 data.stackedOn = previousStack;
\r
871 stackedDataMap[stack] = data;
\r
877 * Layout before each chart render there series, after visual coding and data processing
\r
879 * @param {module:echarts/model/Global} ecModel
\r
882 function doLayout(ecModel, payload) {
\r
883 var api = this._api;
\r
884 each(layoutFuncs, function (layout) {
\r
885 layout(ecModel, api, payload);
\r
890 * Code visual infomation from data after data processing
\r
892 * @param {module:echarts/model/Global} ecModel
\r
895 function doVisualCoding(ecModel, payload) {
\r
896 each(VISUAL_CODING_STAGES, function (stage) {
\r
897 each(visualCodingFuncs[stage] || [], function (visualCoding) {
\r
898 visualCoding(ecModel, payload);
\r
904 * Render each chart and component
\r
907 function doRender(ecModel, payload) {
\r
908 var api = this._api;
\r
909 // Render all components
\r
910 each(this._componentsViews, function (componentView) {
\r
911 var componentModel = componentView.__model;
\r
912 componentView.render(componentModel, ecModel, api, payload);
\r
914 updateZ(componentModel, componentView);
\r
917 each(this._chartsViews, function (chart) {
\r
918 chart.__alive = false;
\r
921 // Render all charts
\r
922 ecModel.eachSeries(function (seriesModel, idx) {
\r
923 var chartView = this._chartsMap[seriesModel.__viewId];
\r
924 chartView.__alive = true;
\r
925 chartView.render(seriesModel, ecModel, api, payload);
\r
927 updateZ(seriesModel, chartView);
\r
930 // Remove groups of unrendered charts
\r
931 each(this._chartsViews, function (chart) {
\r
932 if (!chart.__alive) {
\r
933 chart.remove(ecModel, api);
\r
938 var MOUSE_EVENT_NAMES = [
\r
939 'click', 'dblclick', 'mouseover', 'mouseout', 'mousedown', 'mouseup', 'globalout'
\r
944 echartsProto._initEvents = function () {
\r
946 each(MOUSE_EVENT_NAMES, function (eveName) {
\r
947 zr.on(eveName, function (e) {
\r
948 var ecModel = this.getModel();
\r
950 if (el && el.dataIndex != null) {
\r
951 var dataModel = el.dataModel || ecModel.getSeriesByIndex(el.seriesIndex);
\r
952 var params = dataModel && dataModel.getDataParams(el.dataIndex) || {};
\r
954 params.type = eveName;
\r
955 this.trigger(eveName, params);
\r
960 each(eventActionMap, function (actionType, eventType) {
\r
961 this._messageCenter.on(eventType, function (event) {
\r
962 this.trigger(eventType, event);
\r
968 * @return {boolean}
\r
970 echartsProto.isDisposed = function () {
\r
971 return this._disposed;
\r
977 echartsProto.clear = function () {
\r
978 this.setOption({}, true);
\r
983 echartsProto.dispose = function () {
\r
984 this._disposed = true;
\r
985 var api = this._api;
\r
986 var ecModel = this._model;
\r
988 each(this._componentsViews, function (component) {
\r
989 component.dispose(ecModel, api);
\r
991 each(this._chartsViews, function (chart) {
\r
992 chart.dispose(ecModel, api);
\r
995 this._zr.dispose();
\r
997 delete instances[this.id];
\r
1000 zrUtil.mixin(ECharts, Eventful);
\r
1003 * @param {module:echarts/model/Series|module:echarts/model/Component} model
\r
1004 * @param {module:echarts/view/Component|module:echarts/view/Chart} view
\r
1005 * @return {string}
\r
1007 function updateZ(model, view) {
\r
1008 var z = model.get('z');
\r
1009 var zlevel = model.get('zlevel');
\r
1010 // Set z and zlevel
\r
1011 view.group.traverse(function (el) {
\r
1012 z != null && (el.z = z);
\r
1013 zlevel != null && (el.zlevel = zlevel);
\r
1017 * @type {Array.<Function>}
\r
1023 * Map eventType to actionType
\r
1026 var eventActionMap = {};
\r
1029 * @type {Array.<Function>}
\r
1032 var layoutFuncs = [];
\r
1035 * Data processor functions of each stage
\r
1036 * @type {Array.<Object.<string, Function>>}
\r
1039 var dataProcessorFuncs = {};
\r
1042 * @type {Array.<Function>}
\r
1045 var optionPreprocessorFuncs = [];
\r
1048 * Visual coding functions of each stage
\r
1049 * @type {Array.<Object.<string, Function>>}
\r
1052 var visualCodingFuncs = {};
\r
1055 * @type {Object.<key, Object>}
\r
1057 var themeStorage = {};
\r
1060 var instances = {};
\r
1061 var connectedGroups = {};
\r
1063 var idBase = new Date() - 0;
\r
1064 var groupIdBase = new Date() - 0;
\r
1065 var DOM_ATTRIBUTE_KEY = '_echarts_instance_';
\r
1067 * @alias module:echarts
\r
1079 function enableConnect(chart) {
\r
1081 var STATUS_PENDING = 0;
\r
1082 var STATUS_UPDATING = 1;
\r
1083 var STATUS_UPDATED = 2;
\r
1084 var STATUS_KEY = '__connectUpdateStatus';
\r
1085 function updateConnectedChartsStatus(charts, status) {
\r
1086 for (var i = 0; i < charts.length; i++) {
\r
1087 var otherChart = charts[i];
\r
1088 otherChart[STATUS_KEY] = status;
\r
1091 zrUtil.each(eventActionMap, function (actionType, eventType) {
\r
1092 chart._messageCenter.on(eventType, function (event) {
\r
1093 if (connectedGroups[chart.group] && chart[STATUS_KEY] !== STATUS_PENDING) {
\r
1094 var action = chart.makeActionFromEvent(event);
\r
1095 var otherCharts = [];
\r
1096 for (var id in instances) {
\r
1097 var otherChart = instances[id];
\r
1098 if (otherChart !== chart && otherChart.group === chart.group) {
\r
1099 otherCharts.push(otherChart);
\r
1102 updateConnectedChartsStatus(otherCharts, STATUS_PENDING);
\r
1103 each(otherCharts, function (otherChart) {
\r
1104 if (otherChart[STATUS_KEY] !== STATUS_UPDATING) {
\r
1105 otherChart.dispatchAction(action);
\r
1108 updateConnectedChartsStatus(otherCharts, STATUS_UPDATED);
\r
1115 * @param {HTMLDomElement} dom
\r
1116 * @param {Object} [theme]
\r
1117 * @param {Object} opts
\r
1119 echarts.init = function (dom, theme, opts) {
\r
1121 if ((zrender.version.replace('.', '') - 0) < (echarts.dependencies.zrender.replace('.', '') - 0)) {
\r
1123 'ZRender ' + zrender.version
\r
1124 + ' is too old for ECharts ' + echarts.version
\r
1125 + '. Current version need ZRender '
\r
1126 + echarts.dependencies.zrender + '+'
\r
1130 throw new Error('Initialize failed: invalid dom.');
\r
1133 var chart = new ECharts(dom, theme, opts);
\r
1134 chart.id = 'ec_' + idBase++;
\r
1135 instances[chart.id] = chart;
\r
1137 dom.setAttribute &&
\r
1138 dom.setAttribute(DOM_ATTRIBUTE_KEY, chart.id);
\r
1140 enableConnect(chart);
\r
1146 * @return {string|Array.<module:echarts~ECharts>} groupId
\r
1148 echarts.connect = function (groupId) {
\r
1149 // Is array of charts
\r
1150 if (zrUtil.isArray(groupId)) {
\r
1151 var charts = groupId;
\r
1153 // If any chart has group
\r
1154 zrUtil.each(charts, function (chart) {
\r
1155 if (chart.group != null) {
\r
1156 groupId = chart.group;
\r
1159 groupId = groupId || ('g_' + groupIdBase++);
\r
1160 zrUtil.each(charts, function (chart) {
\r
1161 chart.group = groupId;
\r
1164 connectedGroups[groupId] = true;
\r
1169 * @return {string} groupId
\r
1171 echarts.disConnect = function (groupId) {
\r
1172 connectedGroups[groupId] = false;
\r
1176 * Dispose a chart instance
\r
1177 * @param {module:echarts~ECharts|HTMLDomElement|string} chart
\r
1179 echarts.dispose = function (chart) {
\r
1180 if (zrUtil.isDom(chart)) {
\r
1181 chart = echarts.getInstanceByDom(chart);
\r
1183 else if (typeof chart === 'string') {
\r
1184 chart = instances[chart];
\r
1186 if ((chart instanceof ECharts) && !chart.isDisposed()) {
\r
1192 * @param {HTMLDomElement} dom
\r
1193 * @return {echarts~ECharts}
\r
1195 echarts.getInstanceByDom = function (dom) {
\r
1196 var key = dom.getAttribute(DOM_ATTRIBUTE_KEY);
\r
1197 return instances[key];
\r
1200 * @param {string} key
\r
1201 * @return {echarts~ECharts}
\r
1203 echarts.getInstanceById = function (key) {
\r
1204 return instances[key];
\r
1210 echarts.registerTheme = function (name, theme) {
\r
1211 themeStorage[name] = theme;
\r
1215 * Register option preprocessor
\r
1216 * @param {Function} preprocessorFunc
\r
1218 echarts.registerPreprocessor = function (preprocessorFunc) {
\r
1219 optionPreprocessorFuncs.push(preprocessorFunc);
\r
1223 * @param {string} stage
\r
1224 * @param {Function} processorFunc
\r
1226 echarts.registerProcessor = function (stage, processorFunc) {
\r
1227 if (zrUtil.indexOf(PROCESSOR_STAGES, stage) < 0) {
\r
1228 throw new Error('stage should be one of ' + PROCESSOR_STAGES);
\r
1230 var funcs = dataProcessorFuncs[stage] || (dataProcessorFuncs[stage] = []);
\r
1231 funcs.push(processorFunc);
\r
1236 * registerAction('someAction', 'someEvent', function () { ... });
\r
1237 * registerAction('someAction', function () { ... });
\r
1239 * {type: 'someAction', event: 'someEvent', update: 'updateView'},
\r
1240 * function () { ... }
\r
1243 * @param {(string|Object)} actionInfo
\r
1244 * @param {string} actionInfo.type
\r
1245 * @param {string} [actionInfo.event]
\r
1246 * @param {string} [actionInfo.update]
\r
1247 * @param {string} [eventName]
\r
1248 * @param {Function} action
\r
1250 echarts.registerAction = function (actionInfo, eventName, action) {
\r
1251 if (typeof eventName === 'function') {
\r
1252 action = eventName;
\r
1255 var actionType = zrUtil.isObject(actionInfo)
\r
1257 : ([actionInfo, actionInfo = {
\r
1261 // Event name is all lowercase
\r
1262 actionInfo.event = (actionInfo.event || actionType).toLowerCase();
\r
1263 eventName = actionInfo.event;
\r
1265 if (!actions[actionType]) {
\r
1266 actions[actionType] = {action: action, actionInfo: actionInfo};
\r
1268 eventActionMap[eventName] = actionType;
\r
1272 * @param {string} type
\r
1273 * @param {*} CoordinateSystem
\r
1275 echarts.registerCoordinateSystem = function (type, CoordinateSystem) {
\r
1276 CoordinateSystemManager.register(type, CoordinateSystem);
\r
1280 * @param {*} layout
\r
1282 echarts.registerLayout = function (layout) {
\r
1283 // PENDING All functions ?
\r
1284 if (zrUtil.indexOf(layoutFuncs, layout) < 0) {
\r
1285 layoutFuncs.push(layout);
\r
1290 * @param {string} stage
\r
1291 * @param {Function} visualCodingFunc
\r
1293 echarts.registerVisualCoding = function (stage, visualCodingFunc) {
\r
1294 if (zrUtil.indexOf(VISUAL_CODING_STAGES, stage) < 0) {
\r
1295 throw new Error('stage should be one of ' + VISUAL_CODING_STAGES);
\r
1297 var funcs = visualCodingFuncs[stage] || (visualCodingFuncs[stage] = []);
\r
1298 funcs.push(visualCodingFunc);
\r
1302 * @param {Object} opts
\r
1304 echarts.extendChartView = function (opts) {
\r
1305 return ChartView.extend(opts);
\r
1309 * @param {Object} opts
\r
1311 echarts.extendComponentModel = function (opts) {
\r
1312 return ComponentModel.extend(opts);
\r
1316 * @param {Object} opts
\r
1318 echarts.extendSeriesModel = function (opts) {
\r
1319 return SeriesModel.extend(opts);
\r
1323 * @param {Object} opts
\r
1325 echarts.extendComponentView = function (opts) {
\r
1326 return ComponentView.extend(opts);
\r
1330 * ZRender need a canvas context to do measureText.
\r
1331 * But in node environment canvas may be created by node-canvas.
\r
1332 * So we need to specify how to create a canvas instead of using document.createElement('canvas')
\r
1334 * Be careful of using it in the browser.
\r
1336 * @param {Function} creator
\r
1338 * var Canvas = require('canvas');
\r
1339 * var echarts = require('echarts');
\r
1340 * echarts.setCanvasCreator(function () {
\r
1341 * // Small size is enough.
\r
1342 * return new Canvas(32, 32);
\r
1345 echarts.setCanvasCreator = function (creator) {
\r
1346 zrUtil.createCanvas = creator;
\r
1349 echarts.registerVisualCoding('echarts', zrUtil.curry(
\r
1350 __webpack_require__(88), '', 'itemStyle'
\r
1352 echarts.registerPreprocessor(__webpack_require__(89));
\r
1355 echarts.registerAction({
\r
1356 type: 'highlight',
\r
1357 event: 'highlight',
\r
1358 update: 'highlight'
\r
1360 echarts.registerAction({
\r
1362 event: 'downplay',
\r
1363 update: 'downplay'
\r
1371 echarts.graphic = __webpack_require__(42);
\r
1372 echarts.number = __webpack_require__(7);
\r
1373 echarts.format = __webpack_require__(6);
\r
1374 echarts.matrix = __webpack_require__(17);
\r
1375 echarts.vector = __webpack_require__(16);
\r
1377 echarts.util = {};
\r
1379 'map', 'each', 'filter', 'indexOf', 'inherits',
\r
1380 'reduce', 'filter', 'bind', 'curry', 'isArray',
\r
1381 'isString', 'isObject', 'isFunction', 'extend'
\r
1384 echarts.util[name] = zrUtil[name];
\r
1388 module.exports = echarts;
\r
1393 /***/ function(module, exports, __webpack_require__) {
\r
1396 * ECharts global model
\r
1398 * @module {echarts/model/Global}
\r
1404 var zrUtil = __webpack_require__(3);
\r
1405 var modelUtil = __webpack_require__(5);
\r
1406 var Model = __webpack_require__(8);
\r
1407 var each = zrUtil.each;
\r
1408 var filter = zrUtil.filter;
\r
1409 var map = zrUtil.map;
\r
1410 var isArray = zrUtil.isArray;
\r
1411 var indexOf = zrUtil.indexOf;
\r
1412 var isObject = zrUtil.isObject;
\r
1414 var ComponentModel = __webpack_require__(19);
\r
1416 var globalDefault = __webpack_require__(23);
\r
1418 var OPTION_INNER_KEY = '\0_ec_inner';
\r
1421 * @alias module:echarts/model/Global
\r
1423 * @param {Object} option
\r
1424 * @param {module:echarts/model/Model} parentModel
\r
1425 * @param {Object} theme
\r
1427 var GlobalModel = Model.extend({
\r
1429 constructor: GlobalModel,
\r
1431 init: function (option, parentModel, theme, optionManager) {
\r
1432 theme = theme || {};
\r
1434 this.option = null; // Mark as not initialized.
\r
1437 * @type {module:echarts/model/Model}
\r
1440 this._theme = new Model(theme);
\r
1443 * @type {module:echarts/model/OptionManager}
\r
1445 this._optionManager = optionManager;
\r
1448 setOption: function (option, optionPreprocessorFuncs) {
\r
1450 !(OPTION_INNER_KEY in option),
\r
1451 'please use chart.getOption()'
\r
1454 this._optionManager.setOption(option, optionPreprocessorFuncs);
\r
1456 this.resetOption();
\r
1460 * @param {string} type null/undefined: reset all.
\r
1461 * 'recreate': force recreate all.
\r
1462 * 'timeline': only reset timeline option
\r
1463 * 'media': only reset media query option
\r
1464 * @return {boolean} Whether option changed.
\r
1466 resetOption: function (type) {
\r
1467 var optionChanged = false;
\r
1468 var optionManager = this._optionManager;
\r
1470 if (!type || type === 'recreate') {
\r
1471 var baseOption = optionManager.mountOption(type === 'recreate');
\r
1473 if (!this.option || type === 'recreate') {
\r
1474 initBase.call(this, baseOption);
\r
1477 this.restoreData();
\r
1478 this.mergeOption(baseOption);
\r
1480 optionChanged = true;
\r
1483 if (type === 'timeline' || type === 'media') {
\r
1484 this.restoreData();
\r
1487 if (!type || type === 'recreate' || type === 'timeline') {
\r
1488 var timelineOption = optionManager.getTimelineOption(this);
\r
1489 timelineOption && (this.mergeOption(timelineOption), optionChanged = true);
\r
1492 if (!type || type === 'recreate' || type === 'media') {
\r
1493 var mediaOptions = optionManager.getMediaOption(this, this._api);
\r
1494 if (mediaOptions.length) {
\r
1495 each(mediaOptions, function (mediaOption) {
\r
1496 this.mergeOption(mediaOption, optionChanged = true);
\r
1501 return optionChanged;
\r
1507 mergeOption: function (newOption) {
\r
1508 var option = this.option;
\r
1509 var componentsMap = this._componentsMap;
\r
1510 var newCptTypes = [];
\r
1512 // 如果不存在对应的 component model 则直接 merge
\r
1513 each(newOption, function (componentOption, mainType) {
\r
1514 if (componentOption == null) {
\r
1518 if (!ComponentModel.hasClass(mainType)) {
\r
1519 option[mainType] = option[mainType] == null
\r
1520 ? zrUtil.clone(componentOption)
\r
1521 : zrUtil.merge(option[mainType], componentOption, true);
\r
1524 newCptTypes.push(mainType);
\r
1528 // FIXME OPTION 同步是否要改回原来的
\r
1529 ComponentModel.topologicalTravel(
\r
1530 newCptTypes, ComponentModel.getAllClassMainTypes(), visitComponent, this
\r
1533 function visitComponent(mainType, dependencies) {
\r
1534 var newCptOptionList = modelUtil.normalizeToArray(newOption[mainType]);
\r
1536 var mapResult = modelUtil.mappingToExists(
\r
1537 componentsMap[mainType], newCptOptionList
\r
1540 makeKeyInfo(mainType, mapResult);
\r
1542 var dependentModels = getComponentsByTypes(
\r
1543 componentsMap, dependencies
\r
1546 option[mainType] = [];
\r
1547 componentsMap[mainType] = [];
\r
1549 each(mapResult, function (resultItem, index) {
\r
1550 var componentModel = resultItem.exist;
\r
1551 var newCptOption = resultItem.option;
\r
1554 isObject(newCptOption) || componentModel,
\r
1555 'Empty component definition'
\r
1558 // Consider where is no new option and should be merged using {},
\r
1559 // see removeEdgeAndAdd in topologicalTravel and
\r
1560 // ComponentModel.getAllClassMainTypes.
\r
1561 if (!newCptOption) {
\r
1562 componentModel.mergeOption({}, this);
\r
1563 componentModel.optionUpdated(this);
\r
1566 var ComponentModelClass = ComponentModel.getClass(
\r
1567 mainType, resultItem.keyInfo.subType, true
\r
1570 if (componentModel && componentModel instanceof ComponentModelClass) {
\r
1571 componentModel.mergeOption(newCptOption, this);
\r
1572 componentModel.optionUpdated(this);
\r
1575 // PENDING Global as parent ?
\r
1576 componentModel = new ComponentModelClass(
\r
1577 newCptOption, this, this,
\r
1580 dependentModels: dependentModels,
\r
1581 componentIndex: index
\r
1583 resultItem.keyInfo
\r
1586 // Call optionUpdated after init
\r
1587 componentModel.optionUpdated(this);
\r
1591 componentsMap[mainType][index] = componentModel;
\r
1592 option[mainType][index] = componentModel.option;
\r
1595 // Backup series for filtering.
\r
1596 if (mainType === 'series') {
\r
1597 this._seriesIndices = createSeriesIndices(componentsMap.series);
\r
1603 * Get option for output (cloned option and inner info removed)
\r
1605 * @return {Object}
\r
1607 getOption: function () {
\r
1608 var option = zrUtil.clone(this.option);
\r
1610 each(option, function (opts, mainType) {
\r
1611 if (ComponentModel.hasClass(mainType)) {
\r
1612 var opts = modelUtil.normalizeToArray(opts);
\r
1613 for (var i = opts.length - 1; i >= 0; i--) {
\r
1614 // Remove options with inner id.
\r
1615 if (modelUtil.isIdInner(opts[i])) {
\r
1616 opts.splice(i, 1);
\r
1619 option[mainType] = opts;
\r
1623 delete option[OPTION_INNER_KEY];
\r
1629 * @return {module:echarts/model/Model}
\r
1631 getTheme: function () {
\r
1632 return this._theme;
\r
1636 * @param {string} mainType
\r
1637 * @param {number} [idx=0]
\r
1638 * @return {module:echarts/model/Component}
\r
1640 getComponent: function (mainType, idx) {
\r
1641 var list = this._componentsMap[mainType];
\r
1643 return list[idx || 0];
\r
1648 * @param {Object} condition
\r
1649 * @param {string} condition.mainType
\r
1650 * @param {string} [condition.subType] If ignore, only query by mainType
\r
1651 * @param {number} [condition.index] Either input index or id or name.
\r
1652 * @param {string} [condition.id] Either input index or id or name.
\r
1653 * @param {string} [condition.name] Either input index or id or name.
\r
1654 * @return {Array.<module:echarts/model/Component>}
\r
1656 queryComponents: function (condition) {
\r
1657 var mainType = condition.mainType;
\r
1662 var index = condition.index;
\r
1663 var id = condition.id;
\r
1664 var name = condition.name;
\r
1666 var cpts = this._componentsMap[mainType];
\r
1668 if (!cpts || !cpts.length) {
\r
1674 if (index != null) {
\r
1675 if (!isArray(index)) {
\r
1678 result = filter(map(index, function (idx) {
\r
1680 }), function (val) {
\r
1684 else if (id != null) {
\r
1685 var isIdArray = isArray(id);
\r
1686 result = filter(cpts, function (cpt) {
\r
1687 return (isIdArray && indexOf(id, cpt.id) >= 0)
\r
1688 || (!isIdArray && cpt.id === id);
\r
1691 else if (name != null) {
\r
1692 var isNameArray = isArray(name);
\r
1693 result = filter(cpts, function (cpt) {
\r
1694 return (isNameArray && indexOf(name, cpt.name) >= 0)
\r
1695 || (!isNameArray && cpt.name === name);
\r
1699 return filterBySubType(result, condition);
\r
1703 * The interface is different from queryComponents,
\r
1704 * which is convenient for inner usage.
\r
1708 * {mainType: 'dataZoom', query: {dataZoomId: 'abc'}},
\r
1709 * function (model, index) {...}
\r
1713 * {mainType: 'series', subType: 'pie', query: {seriesName: 'uio'}},
\r
1714 * function (model, index) {...}
\r
1717 * var result = findComponents(
\r
1718 * {mainType: 'series'},
\r
1719 * function (model, index) {...}
\r
1721 * // result like [component0, componnet1, ...]
\r
1723 * @param {Object} condition
\r
1724 * @param {string} condition.mainType Mandatory.
\r
1725 * @param {string} [condition.subType] Optional.
\r
1726 * @param {Object} [condition.query] like {xxxIndex, xxxId, xxxName},
\r
1727 * where xxx is mainType.
\r
1728 * If query attribute is null/undefined or has no index/id/name,
\r
1729 * do not filtering by query conditions, which is convenient for
\r
1730 * no-payload situations or when target of action is global.
\r
1731 * @param {Function} [condition.filter] parameter: component, return boolean.
\r
1732 * @return {Array.<module:echarts/model/Component>}
\r
1734 findComponents: function (condition) {
\r
1735 var query = condition.query;
\r
1736 var mainType = condition.mainType;
\r
1738 var queryCond = getQueryCond(query);
\r
1739 var result = queryCond
\r
1740 ? this.queryComponents(queryCond)
\r
1741 : this._componentsMap[mainType];
\r
1743 return doFilter(filterBySubType(result, condition));
\r
1745 function getQueryCond(q) {
\r
1746 var indexAttr = mainType + 'Index';
\r
1747 var idAttr = mainType + 'Id';
\r
1748 var nameAttr = mainType + 'Name';
\r
1750 q.hasOwnProperty(indexAttr)
\r
1751 || q.hasOwnProperty(idAttr)
\r
1752 || q.hasOwnProperty(nameAttr)
\r
1755 mainType: mainType,
\r
1756 // subType will be filtered finally.
\r
1757 index: q[indexAttr],
\r
1764 function doFilter(res) {
\r
1765 return condition.filter
\r
1766 ? filter(res, condition.filter)
\r
1773 * eachComponent('legend', function (legendModel, index) {
\r
1776 * eachComponent(function (componentType, model, index) {
\r
1777 * // componentType does not include subType
\r
1778 * // (componentType is 'xxx' but not 'xxx.aa')
\r
1781 * {mainType: 'dataZoom', query: {dataZoomId: 'abc'}},
\r
1782 * function (model, index) {...}
\r
1785 * {mainType: 'series', subType: 'pie', query: {seriesName: 'uio'}},
\r
1786 * function (model, index) {...}
\r
1789 * @param {string|Object=} mainType When mainType is object, the definition
\r
1790 * is the same as the method 'findComponents'.
\r
1791 * @param {Function} cb
\r
1792 * @param {*} context
\r
1794 eachComponent: function (mainType, cb, context) {
\r
1795 var componentsMap = this._componentsMap;
\r
1797 if (typeof mainType === 'function') {
\r
1800 each(componentsMap, function (components, componentType) {
\r
1801 each(components, function (component, index) {
\r
1802 cb.call(context, componentType, component, index);
\r
1806 else if (zrUtil.isString(mainType)) {
\r
1807 each(componentsMap[mainType], cb, context);
\r
1809 else if (isObject(mainType)) {
\r
1810 var queryResult = this.findComponents(mainType);
\r
1811 each(queryResult, cb, context);
\r
1816 * @param {string} name
\r
1817 * @return {Array.<module:echarts/model/Series>}
\r
1819 getSeriesByName: function (name) {
\r
1820 var series = this._componentsMap.series;
\r
1821 return filter(series, function (oneSeries) {
\r
1822 return oneSeries.name === name;
\r
1827 * @param {number} seriesIndex
\r
1828 * @return {module:echarts/model/Series}
\r
1830 getSeriesByIndex: function (seriesIndex) {
\r
1831 return this._componentsMap.series[seriesIndex];
\r
1835 * @param {string} subType
\r
1836 * @return {Array.<module:echarts/model/Series>}
\r
1838 getSeriesByType: function (subType) {
\r
1839 var series = this._componentsMap.series;
\r
1840 return filter(series, function (oneSeries) {
\r
1841 return oneSeries.subType === subType;
\r
1846 * @return {Array.<module:echarts/model/Series>}
\r
1848 getSeries: function () {
\r
1849 return this._componentsMap.series.slice();
\r
1853 * After filtering, series may be different
\r
1854 * frome raw series.
\r
1856 * @param {Function} cb
\r
1857 * @param {*} context
\r
1859 eachSeries: function (cb, context) {
\r
1860 assertSeriesInitialized(this);
\r
1861 each(this._seriesIndices, function (rawSeriesIndex) {
\r
1862 var series = this._componentsMap.series[rawSeriesIndex];
\r
1863 cb.call(context, series, rawSeriesIndex);
\r
1868 * Iterate raw series before filtered.
\r
1870 * @param {Function} cb
\r
1871 * @param {*} context
\r
1873 eachRawSeries: function (cb, context) {
\r
1874 each(this._componentsMap.series, cb, context);
\r
1878 * After filtering, series may be different.
\r
1879 * frome raw series.
\r
1881 * @parma {string} subType
\r
1882 * @param {Function} cb
\r
1883 * @param {*} context
\r
1885 eachSeriesByType: function (subType, cb, context) {
\r
1886 assertSeriesInitialized(this);
\r
1887 each(this._seriesIndices, function (rawSeriesIndex) {
\r
1888 var series = this._componentsMap.series[rawSeriesIndex];
\r
1889 if (series.subType === subType) {
\r
1890 cb.call(context, series, rawSeriesIndex);
\r
1896 * Iterate raw series before filtered of given type.
\r
1898 * @parma {string} subType
\r
1899 * @param {Function} cb
\r
1900 * @param {*} context
\r
1902 eachRawSeriesByType: function (subType, cb, context) {
\r
1903 return each(this.getSeriesByType(subType), cb, context);
\r
1907 * @param {module:echarts/model/Series} seriesModel
\r
1909 isSeriesFiltered: function (seriesModel) {
\r
1910 assertSeriesInitialized(this);
\r
1911 return zrUtil.indexOf(this._seriesIndices, seriesModel.componentIndex) < 0;
\r
1915 * @param {Function} cb
\r
1916 * @param {*} context
\r
1918 filterSeries: function (cb, context) {
\r
1919 assertSeriesInitialized(this);
\r
1920 var filteredSeries = filter(
\r
1921 this._componentsMap.series, cb, context
\r
1923 this._seriesIndices = createSeriesIndices(filteredSeries);
\r
1926 restoreData: function () {
\r
1927 var componentsMap = this._componentsMap;
\r
1929 this._seriesIndices = createSeriesIndices(componentsMap.series);
\r
1931 var componentTypes = [];
\r
1932 each(componentsMap, function (components, componentType) {
\r
1933 componentTypes.push(componentType);
\r
1936 ComponentModel.topologicalTravel(
\r
1938 ComponentModel.getAllClassMainTypes(),
\r
1939 function (componentType, dependencies) {
\r
1940 each(componentsMap[componentType], function (component) {
\r
1941 component.restoreData();
\r
1952 function mergeTheme(option, theme) {
\r
1953 for (var name in theme) {
\r
1954 // 如果有 component model 则把具体的 merge 逻辑交给该 model 处理
\r
1955 if (!ComponentModel.hasClass(name)) {
\r
1956 if (typeof theme[name] === 'object') {
\r
1957 option[name] = !option[name]
\r
1958 ? zrUtil.clone(theme[name])
\r
1959 : zrUtil.merge(option[name], theme[name], false);
\r
1962 if (option[name] == null) {
\r
1963 option[name] = theme[name];
\r
1970 function initBase(baseOption) {
\r
1971 baseOption = baseOption;
\r
1973 // Using OPTION_INNER_KEY to mark that this option can not be used outside,
\r
1974 // i.e. `chart.setOption(chart.getModel().option);` is forbiden.
\r
1976 this.option[OPTION_INNER_KEY] = 1;
\r
1979 * @type {Object.<string, Array.<module:echarts/model/Model>>}
\r
1982 this._componentsMap = {};
\r
1985 * Mapping between filtered series list and raw series list.
\r
1986 * key: filtered series indices, value: raw series indices.
\r
1987 * @type {Array.<nubmer>}
\r
1990 this._seriesIndices = null;
\r
1992 mergeTheme(baseOption, this._theme.option);
\r
1994 // TODO Needs clone when merging to the unexisted property
\r
1995 zrUtil.merge(baseOption, globalDefault, false);
\r
1997 this.mergeOption(baseOption);
\r
2002 * @param {Array.<string>|string} types model types
\r
2003 * @return {Object} key: {string} type, value: {Array.<Object>} models
\r
2005 function getComponentsByTypes(componentsMap, types) {
\r
2006 if (!zrUtil.isArray(types)) {
\r
2007 types = types ? [types] : [];
\r
2011 each(types, function (type) {
\r
2012 ret[type] = (componentsMap[type] || []).slice();
\r
2021 function makeKeyInfo(mainType, mapResult) {
\r
2022 // We use this id to hash component models and view instances
\r
2023 // in echarts. id can be specified by user, or auto generated.
\r
2025 // The id generation rule ensures new view instance are able
\r
2026 // to mapped to old instance when setOption are called in
\r
2027 // no-merge mode. So we generate model id by name and plus
\r
2028 // type in view id.
\r
2030 // name can be duplicated among components, which is convenient
\r
2031 // to specify multi components (like series) by one name.
\r
2033 // Ensure that each id is distinct.
\r
2036 each(mapResult, function (item, index) {
\r
2037 var existCpt = item.exist;
\r
2038 existCpt && (idMap[existCpt.id] = item);
\r
2041 each(mapResult, function (item, index) {
\r
2042 var opt = item.option;
\r
2045 !opt || opt.id == null || !idMap[opt.id] || idMap[opt.id] === item,
\r
2046 'id duplicates: ' + (opt && opt.id)
\r
2049 opt && opt.id != null && (idMap[opt.id] = item);
\r
2051 // Complete subType
\r
2052 if (isObject(opt)) {
\r
2053 var subType = determineSubType(mainType, opt, item.exist);
\r
2054 item.keyInfo = {mainType: mainType, subType: subType};
\r
2058 // Make name and id.
\r
2059 each(mapResult, function (item, index) {
\r
2060 var existCpt = item.exist;
\r
2061 var opt = item.option;
\r
2062 var keyInfo = item.keyInfo;
\r
2064 if (!isObject(opt)) {
\r
2068 // name can be overwitten. Consider case: axis.name = '20km'.
\r
2069 // But id generated by name will not be changed, which affect
\r
2070 // only in that case: setOption with 'not merge mode' and view
\r
2071 // instance will be recreated, which can be accepted.
\r
2072 keyInfo.name = opt.name != null
\r
2079 keyInfo.id = existCpt.id;
\r
2081 else if (opt.id != null) {
\r
2082 keyInfo.id = opt.id + '';
\r
2085 // Consider this situatoin:
\r
2086 // optionA: [{name: 'a'}, {name: 'a'}, {..}]
\r
2087 // optionB [{..}, {name: 'a'}, {name: 'a'}]
\r
2088 // Series with the same name between optionA and optionB
\r
2089 // should be mapped.
\r
2092 keyInfo.id = '\0' + keyInfo.name + '\0' + idNum++;
\r
2094 while (idMap[keyInfo.id]);
\r
2097 idMap[keyInfo.id] = item;
\r
2104 function determineSubType(mainType, newCptOption, existComponent) {
\r
2105 var subType = newCptOption.type
\r
2106 ? newCptOption.type
\r
2108 ? existComponent.subType
\r
2109 // Use determineSubType only when there is no existComponent.
\r
2110 : ComponentModel.determineSubType(mainType, newCptOption);
\r
2112 // tooltip, markline, markpoint may always has no subType
\r
2119 function createSeriesIndices(seriesModels) {
\r
2120 return map(seriesModels, function (series) {
\r
2121 return series.componentIndex;
\r
2128 function filterBySubType(components, condition) {
\r
2129 // Using hasOwnProperty for restrict. Consider
\r
2130 // subType is undefined in user payload.
\r
2131 return condition.hasOwnProperty('subType')
\r
2132 ? filter(components, function (cpt) {
\r
2133 return cpt.subType === condition.subType;
\r
2141 function assertSeriesInitialized(ecModel) {
\r
2142 // Components that use _seriesIndices should depends on series component,
\r
2143 // which make sure that their initialization is after series.
\r
2144 if (!ecModel._seriesIndices) {
\r
2145 throw new Error('Series has not been initialized yet.');
\r
2149 module.exports = GlobalModel;
\r
2154 /***/ function(module, exports, __webpack_require__) {
\r
2159 var Gradient = __webpack_require__(4);
\r
2160 // 用于处理merge时无法遍历Date等对象的问题
\r
2161 var BUILTIN_OBJECT = {
\r
2162 '[object Function]': 1,
\r
2163 '[object RegExp]': 1,
\r
2164 '[object Date]': 1,
\r
2165 '[object Error]': 1,
\r
2166 '[object CanvasGradient]': 1
\r
2169 var objToString = Object.prototype.toString;
\r
2171 var arrayProto = Array.prototype;
\r
2172 var nativeForEach = arrayProto.forEach;
\r
2173 var nativeFilter = arrayProto.filter;
\r
2174 var nativeSlice = arrayProto.slice;
\r
2175 var nativeMap = arrayProto.map;
\r
2176 var nativeReduce = arrayProto.reduce;
\r
2179 * @param {*} source
\r
2180 * @return {*} 拷贝后的新对象
\r
2182 function clone(source) {
\r
2183 if (typeof source == 'object' && source !== null) {
\r
2184 var result = source;
\r
2185 if (source instanceof Array) {
\r
2187 for (var i = 0, len = source.length; i < len; i++) {
\r
2188 result[i] = clone(source[i]);
\r
2192 !isBuildInObject(source)
\r
2197 for (var key in source) {
\r
2198 if (source.hasOwnProperty(key)) {
\r
2199 result[key] = clone(source[key]);
\r
2211 * @param {*} target
\r
2212 * @param {*} source
\r
2213 * @param {boolean} [overwrite=false]
\r
2215 function merge(target, source, overwrite) {
\r
2216 // We should escapse that source is string
\r
2217 // and enter for ... in ...
\r
2218 if (!isObject(source) || !isObject(target)) {
\r
2219 return overwrite ? clone(source) : target;
\r
2222 for (var key in source) {
\r
2223 if (source.hasOwnProperty(key)) {
\r
2224 var targetProp = target[key];
\r
2225 var sourceProp = source[key];
\r
2227 if (isObject(sourceProp)
\r
2228 && isObject(targetProp)
\r
2229 && !isArray(sourceProp)
\r
2230 && !isArray(targetProp)
\r
2231 && !isDom(sourceProp)
\r
2232 && !isDom(targetProp)
\r
2233 && !isBuildInObject(sourceProp)
\r
2234 && !isBuildInObject(targetProp)
\r
2236 // 如果需要递归覆盖,就递归调用merge
\r
2237 merge(targetProp, sourceProp, overwrite);
\r
2239 else if (overwrite || !(key in target)) {
\r
2240 // 否则只处理overwrite为true,或者在目标对象中没有此属性的情况
\r
2241 // NOTE,在 target[key] 不存在的时候也是直接覆盖
\r
2242 target[key] = clone(source[key], true);
\r
2251 * @param {Array} targetAndSources The first item is target, and the rests are source.
\r
2252 * @param {boolean} [overwrite=false]
\r
2253 * @return {*} target
\r
2255 function mergeAll(targetAndSources, overwrite) {
\r
2256 var result = targetAndSources[0];
\r
2257 for (var i = 1, len = targetAndSources.length; i < len; i++) {
\r
2258 result = merge(result, targetAndSources[i], overwrite);
\r
2264 * @param {*} target
\r
2265 * @param {*} source
\r
2267 function extend(target, source) {
\r
2268 for (var key in source) {
\r
2269 if (source.hasOwnProperty(key)) {
\r
2270 target[key] = source[key];
\r
2277 * @param {*} target
\r
2278 * @param {*} source
\r
2279 * @param {boolen} [overlay=false]
\r
2281 function defaults(target, source, overlay) {
\r
2282 for (var key in source) {
\r
2283 if (source.hasOwnProperty(key)
\r
2284 && (overlay ? source[key] != null : target[key] == null)
\r
2286 target[key] = source[key];
\r
2292 function createCanvas() {
\r
2293 return document.createElement('canvas');
\r
2297 function getContext() {
\r
2299 // Use util.createCanvas instead of createCanvas
\r
2300 // because createCanvas may be overwritten in different environment
\r
2301 _ctx = util.createCanvas().getContext('2d');
\r
2309 function indexOf(array, value) {
\r
2311 if (array.indexOf) {
\r
2312 return array.indexOf(value);
\r
2314 for (var i = 0, len = array.length; i < len; i++) {
\r
2315 if (array[i] === value) {
\r
2326 * @param {Function} clazz 源类
\r
2327 * @param {Function} baseClazz 基类
\r
2329 function inherits(clazz, baseClazz) {
\r
2330 var clazzPrototype = clazz.prototype;
\r
2332 F.prototype = baseClazz.prototype;
\r
2333 clazz.prototype = new F();
\r
2335 for (var prop in clazzPrototype) {
\r
2336 clazz.prototype[prop] = clazzPrototype[prop];
\r
2338 clazz.prototype.constructor = clazz;
\r
2339 clazz.superClass = baseClazz;
\r
2343 * @param {Object|Function} target
\r
2344 * @param {Object|Function} sorce
\r
2345 * @param {boolean} overlay
\r
2347 function mixin(target, source, overlay) {
\r
2348 target = 'prototype' in target ? target.prototype : target;
\r
2349 source = 'prototype' in source ? source.prototype : source;
\r
2351 defaults(target, source, overlay);
\r
2355 * @param {Array|TypedArray} data
\r
2357 function isArrayLike(data) {
\r
2361 if (typeof data == 'string') {
\r
2364 return typeof data.length == 'number';
\r
2369 * @memberOf module:zrender/tool/util
\r
2370 * @param {Object|Array} obj
\r
2371 * @param {Function} cb
\r
2372 * @param {*} [context]
\r
2374 function each(obj, cb, context) {
\r
2375 if (!(obj && cb)) {
\r
2378 if (obj.forEach && obj.forEach === nativeForEach) {
\r
2379 obj.forEach(cb, context);
\r
2381 else if (obj.length === +obj.length) {
\r
2382 for (var i = 0, len = obj.length; i < len; i++) {
\r
2383 cb.call(context, obj[i], i, obj);
\r
2387 for (var key in obj) {
\r
2388 if (obj.hasOwnProperty(key)) {
\r
2389 cb.call(context, obj[key], key, obj);
\r
2397 * @memberOf module:zrender/tool/util
\r
2398 * @param {Array} obj
\r
2399 * @param {Function} cb
\r
2400 * @param {*} [context]
\r
2403 function map(obj, cb, context) {
\r
2404 if (!(obj && cb)) {
\r
2407 if (obj.map && obj.map === nativeMap) {
\r
2408 return obj.map(cb, context);
\r
2412 for (var i = 0, len = obj.length; i < len; i++) {
\r
2413 result.push(cb.call(context, obj[i], i, obj));
\r
2420 * @memberOf module:zrender/tool/util
\r
2421 * @param {Array} obj
\r
2422 * @param {Function} cb
\r
2423 * @param {Object} [memo]
\r
2424 * @param {*} [context]
\r
2427 function reduce(obj, cb, memo, context) {
\r
2428 if (!(obj && cb)) {
\r
2431 if (obj.reduce && obj.reduce === nativeReduce) {
\r
2432 return obj.reduce(cb, memo, context);
\r
2435 for (var i = 0, len = obj.length; i < len; i++) {
\r
2436 memo = cb.call(context, memo, obj[i], i, obj);
\r
2444 * @memberOf module:zrender/tool/util
\r
2445 * @param {Array} obj
\r
2446 * @param {Function} cb
\r
2447 * @param {*} [context]
\r
2450 function filter(obj, cb, context) {
\r
2451 if (!(obj && cb)) {
\r
2454 if (obj.filter && obj.filter === nativeFilter) {
\r
2455 return obj.filter(cb, context);
\r
2459 for (var i = 0, len = obj.length; i < len; i++) {
\r
2460 if (cb.call(context, obj[i], i, obj)) {
\r
2461 result.push(obj[i]);
\r
2470 * @memberOf module:zrender/tool/util
\r
2471 * @param {Array} obj
\r
2472 * @param {Function} cb
\r
2473 * @param {*} [context]
\r
2476 function find(obj, cb, context) {
\r
2477 if (!(obj && cb)) {
\r
2480 for (var i = 0, len = obj.length; i < len; i++) {
\r
2481 if (cb.call(context, obj[i], i, obj)) {
\r
2488 * @memberOf module:zrender/tool/util
\r
2489 * @param {Function} func
\r
2490 * @param {*} context
\r
2491 * @return {Function}
\r
2493 function bind(func, context) {
\r
2494 var args = nativeSlice.call(arguments, 2);
\r
2495 return function () {
\r
2496 return func.apply(context, args.concat(nativeSlice.call(arguments)));
\r
2501 * @memberOf module:zrender/tool/util
\r
2502 * @param {Function} func
\r
2504 * @return {Function}
\r
2506 function curry(func) {
\r
2507 var args = nativeSlice.call(arguments, 1);
\r
2508 return function () {
\r
2509 return func.apply(this, args.concat(nativeSlice.call(arguments)));
\r
2514 * @memberOf module:zrender/tool/util
\r
2515 * @param {*} value
\r
2516 * @return {boolean}
\r
2518 function isArray(value) {
\r
2519 return objToString.call(value) === '[object Array]';
\r
2523 * @memberOf module:zrender/tool/util
\r
2524 * @param {*} value
\r
2525 * @return {boolean}
\r
2527 function isFunction(value) {
\r
2528 return typeof value === 'function';
\r
2532 * @memberOf module:zrender/tool/util
\r
2533 * @param {*} value
\r
2534 * @return {boolean}
\r
2536 function isString(value) {
\r
2537 return objToString.call(value) === '[object String]';
\r
2541 * @memberOf module:zrender/tool/util
\r
2542 * @param {*} value
\r
2543 * @return {boolean}
\r
2545 function isObject(value) {
\r
2546 // Avoid a V8 JIT bug in Chrome 19-20.
\r
2547 // See https://code.google.com/p/v8/issues/detail?id=2291 for more details.
\r
2548 var type = typeof value;
\r
2549 return type === 'function' || (!!value && type == 'object');
\r
2553 * @memberOf module:zrender/tool/util
\r
2554 * @param {*} value
\r
2555 * @return {boolean}
\r
2557 function isBuildInObject(value) {
\r
2558 return !!BUILTIN_OBJECT[objToString.call(value)]
\r
2559 || (value instanceof Gradient);
\r
2563 * @memberOf module:zrender/tool/util
\r
2564 * @param {*} value
\r
2565 * @return {boolean}
\r
2567 function isDom(value) {
\r
2568 return value && value.nodeType === 1
\r
2569 && typeof(value.nodeName) == 'string';
\r
2573 * If value1 is not null, then return value1, otherwise judget rest of values.
\r
2574 * @param {*...} values
\r
2575 * @return {*} Final value
\r
2577 function retrieve(values) {
\r
2578 for (var i = 0, len = arguments.length; i < len; i++) {
\r
2579 if (arguments[i] != null) {
\r
2580 return arguments[i];
\r
2586 * @memberOf module:zrender/tool/util
\r
2587 * @param {Array} arr
\r
2588 * @param {number} startIndex
\r
2589 * @param {number} endIndex
\r
2592 function slice() {
\r
2593 return Function.call.apply(nativeSlice, arguments);
\r
2597 * @param {boolean} condition
\r
2598 * @param {string} message
\r
2600 function assert(condition, message) {
\r
2602 throw new Error(message);
\r
2607 inherits: inherits,
\r
2611 mergeAll: mergeAll,
\r
2613 defaults: defaults,
\r
2614 getContext: getContext,
\r
2615 createCanvas: createCanvas,
\r
2619 isArrayLike: isArrayLike,
\r
2627 isString: isString,
\r
2628 isObject: isObject,
\r
2629 isFunction: isFunction,
\r
2630 isBuildInObject: isBuildInObject,
\r
2632 retrieve: retrieve,
\r
2634 noop: function () {}
\r
2636 module.exports = util;
\r
2642 /***/ function(module, exports) {
\r
2647 * @param {Array.<Object>} colorStops
\r
2649 var Gradient = function (colorStops) {
\r
2651 this.colorStops = colorStops || [];
\r
2654 Gradient.prototype = {
\r
2656 constructor: Gradient,
\r
2658 addColorStop: function (offset, color) {
\r
2659 this.colorStops.push({
\r
2668 module.exports = Gradient;
\r
2673 /***/ function(module, exports, __webpack_require__) {
\r
2677 var formatUtil = __webpack_require__(6);
\r
2678 var nubmerUtil = __webpack_require__(7);
\r
2679 var zrUtil = __webpack_require__(3);
\r
2681 var Model = __webpack_require__(8);
\r
2683 var AXIS_DIMS = ['x', 'y', 'z', 'radius', 'angle'];
\r
2685 var modelUtil = {};
\r
2688 * Create "each" method to iterate names.
\r
2691 * @param {Array.<string>} names
\r
2692 * @param {Array.<string>=} attrs
\r
2693 * @return {Function}
\r
2695 modelUtil.createNameEach = function (names, attrs) {
\r
2696 names = names.slice();
\r
2697 var capitalNames = zrUtil.map(names, modelUtil.capitalFirst);
\r
2698 attrs = (attrs || []).slice();
\r
2699 var capitalAttrs = zrUtil.map(attrs, modelUtil.capitalFirst);
\r
2701 return function (callback, context) {
\r
2702 zrUtil.each(names, function (name, index) {
\r
2703 var nameObj = {name: name, capital: capitalNames[index]};
\r
2705 for (var j = 0; j < attrs.length; j++) {
\r
2706 nameObj[attrs[j]] = name + capitalAttrs[j];
\r
2709 callback.call(context, nameObj);
\r
2717 modelUtil.capitalFirst = function (str) {
\r
2718 return str ? str.charAt(0).toUpperCase() + str.substr(1) : str;
\r
2722 * Iterate each dimension name.
\r
2725 * @param {Function} callback The parameter is like:
\r
2728 * capital: 'Angle',
\r
2729 * axis: 'angleAxis',
\r
2730 * axisIndex: 'angleAixs',
\r
2731 * index: 'angleIndex'
\r
2733 * @param {Object} context
\r
2735 modelUtil.eachAxisDim = modelUtil.createNameEach(AXIS_DIMS, ['axisIndex', 'axis', 'index']);
\r
2738 * If value is not array, then translate it to array.
\r
2739 * @param {*} value
\r
2740 * @return {Array} [value] or value
\r
2742 modelUtil.normalizeToArray = function (value) {
\r
2743 return zrUtil.isArray(value)
\r
2751 * If tow dataZoomModels has the same axis controlled, we say that they are 'linked'.
\r
2752 * dataZoomModels and 'links' make up one or more graphics.
\r
2753 * This function finds the graphic where the source dataZoomModel is in.
\r
2756 * @param {Function} forEachNode Node iterator.
\r
2757 * @param {Function} forEachEdgeType edgeType iterator
\r
2758 * @param {Function} edgeIdGetter Giving node and edgeType, return an array of edge id.
\r
2759 * @return {Function} Input: sourceNode, Output: Like {nodes: [], dims: {}}
\r
2761 modelUtil.createLinkedNodesFinder = function (forEachNode, forEachEdgeType, edgeIdGetter) {
\r
2763 return function (sourceNode) {
\r
2766 records: {} // key: edgeType.name, value: Object (key: edge id, value: boolean).
\r
2769 forEachEdgeType(function (edgeType) {
\r
2770 result.records[edgeType.name] = {};
\r
2773 if (!sourceNode) {
\r
2777 absorb(sourceNode, result);
\r
2781 existsLink = false;
\r
2782 forEachNode(processSingleNode);
\r
2784 while (existsLink);
\r
2786 function processSingleNode(node) {
\r
2787 if (!isNodeAbsorded(node, result) && isLinked(node, result)) {
\r
2788 absorb(node, result);
\r
2789 existsLink = true;
\r
2796 function isNodeAbsorded(node, result) {
\r
2797 return zrUtil.indexOf(result.nodes, node) >= 0;
\r
2800 function isLinked(node, result) {
\r
2801 var hasLink = false;
\r
2802 forEachEdgeType(function (edgeType) {
\r
2803 zrUtil.each(edgeIdGetter(node, edgeType) || [], function (edgeId) {
\r
2804 result.records[edgeType.name][edgeId] && (hasLink = true);
\r
2810 function absorb(node, result) {
\r
2811 result.nodes.push(node);
\r
2812 forEachEdgeType(function (edgeType) {
\r
2813 zrUtil.each(edgeIdGetter(node, edgeType) || [], function (edgeId) {
\r
2814 result.records[edgeType.name][edgeId] = true;
\r
2821 * Sync default option between normal and emphasis like `position` and `show`
\r
2822 * In case some one will write code like
\r
2826 * position: 'outside',
\r
2835 * @param {Object} opt
\r
2836 * @param {Array.<string>} subOpts
\r
2838 modelUtil.defaultEmphasis = function (opt, subOpts) {
\r
2840 var emphasisOpt = opt.emphasis = opt.emphasis || {};
\r
2841 var normalOpt = opt.normal = opt.normal || {};
\r
2843 // Default emphasis option from normal
\r
2844 zrUtil.each(subOpts, function (subOptName) {
\r
2845 var val = zrUtil.retrieve(emphasisOpt[subOptName], normalOpt[subOptName]);
\r
2846 if (val != null) {
\r
2847 emphasisOpt[subOptName] = val;
\r
2854 * Create a model proxy to be used in tooltip for edge data, markLine data, markPoint data.
\r
2855 * @param {Object} opt
\r
2856 * @param {string} [opt.seriesIndex]
\r
2857 * @param {Object} [opt.name]
\r
2858 * @param {module:echarts/data/List} data
\r
2859 * @param {Array.<Object>} rawData
\r
2861 modelUtil.createDataFormatModel = function (opt, data, rawData) {
\r
2862 var model = new Model();
\r
2863 zrUtil.mixin(model, modelUtil.dataFormatMixin);
\r
2864 model.seriesIndex = opt.seriesIndex;
\r
2865 model.name = opt.name || '';
\r
2867 model.getData = function () {
\r
2870 model.getRawDataArray = function () {
\r
2877 * data could be [12, 2323, {value: 223}, [1221, 23], {value: [2, 23]}]
\r
2878 * This helper method retieves value from data.
\r
2879 * @param {string|number|Date|Array|Object} dataItem
\r
2880 * @return {number|string|Date|Array.<number|string|Date>}
\r
2882 modelUtil.getDataItemValue = function (dataItem) {
\r
2883 // Performance sensitive.
\r
2884 return dataItem && (dataItem.value == null ? dataItem : dataItem.value);
\r
2888 * This helper method convert value in data.
\r
2889 * @param {string|number|Date} value
\r
2890 * @param {Object|string} [dimInfo] If string (like 'x'), dimType defaults 'number'.
\r
2892 modelUtil.converDataValue = function (value, dimInfo) {
\r
2893 // Performance sensitive.
\r
2894 var dimType = dimInfo && dimInfo.type;
\r
2895 if (dimType === 'ordinal') {
\r
2899 if (dimType === 'time' && !isFinite(value) && value != null && value !== '-') {
\r
2900 value = +nubmerUtil.parseDate(value);
\r
2903 // dimType defaults 'number'.
\r
2904 // If dimType is not ordinal and value is null or undefined or NaN or '-',
\r
2906 return (value == null || value === '')
\r
2907 ? NaN : +value; // If string (like '-'), using '+' parse to NaN
\r
2910 modelUtil.dataFormatMixin = {
\r
2912 * Get params for formatter
\r
2913 * @param {number} dataIndex
\r
2914 * @return {Object}
\r
2916 getDataParams: function (dataIndex) {
\r
2917 var data = this.getData();
\r
2919 var seriesIndex = this.seriesIndex;
\r
2920 var seriesName = this.name;
\r
2922 var rawValue = this.getRawValue(dataIndex);
\r
2923 var rawDataIndex = data.getRawIndex(dataIndex);
\r
2924 var name = data.getName(dataIndex, true);
\r
2926 // Data may not exists in the option given by user
\r
2927 var rawDataArray = this.getRawDataArray();
\r
2928 var itemOpt = rawDataArray && rawDataArray[rawDataIndex];
\r
2931 seriesIndex: seriesIndex,
\r
2932 seriesName: seriesName,
\r
2934 dataIndex: rawDataIndex,
\r
2937 color: data.getItemVisual(dataIndex, 'color'),
\r
2939 // Param name list for mapping `a`, `b`, `c`, `d`, `e`
\r
2940 $vars: ['seriesName', 'name', 'value']
\r
2946 * @param {number} dataIndex
\r
2947 * @param {string} [status='normal'] 'normal' or 'emphasis'
\r
2948 * @param {Function|string} [formatter] Default use the `itemStyle[status].label.formatter`
\r
2949 * @return {string}
\r
2951 getFormattedLabel: function (dataIndex, status, formatter) {
\r
2952 status = status || 'normal';
\r
2953 var data = this.getData();
\r
2954 var itemModel = data.getItemModel(dataIndex);
\r
2956 var params = this.getDataParams(dataIndex);
\r
2957 if (formatter == null) {
\r
2958 formatter = itemModel.get(['label', status, 'formatter']);
\r
2961 if (typeof formatter === 'function') {
\r
2962 params.status = status;
\r
2963 return formatter(params);
\r
2965 else if (typeof formatter === 'string') {
\r
2966 return formatUtil.formatTpl(formatter, params);
\r
2971 * Get raw value in option
\r
2972 * @param {number} idx
\r
2973 * @return {Object}
\r
2975 getRawValue: function (idx) {
\r
2976 var itemModel = this.getData().getItemModel(idx);
\r
2977 if (itemModel && itemModel.option != null) {
\r
2978 var dataItem = itemModel.option;
\r
2979 return (zrUtil.isObject(dataItem) && !zrUtil.isArray(dataItem))
\r
2980 ? dataItem.value : dataItem;
\r
2986 * Mapping to exists for merge.
\r
2989 * @param {Array.<Object>|Array.<module:echarts/model/Component>} exists
\r
2990 * @param {Object|Array.<Object>} newCptOptions
\r
2991 * @return {Array.<Object>} Result, like [{exist: ..., option: ...}, {}],
\r
2992 * which order is the same as exists.
\r
2994 modelUtil.mappingToExists = function (exists, newCptOptions) {
\r
2995 // Mapping by the order by original option (but not order of
\r
2996 // new option) in merge mode. Because we should ensure
\r
2997 // some specified index (like xAxisIndex) is consistent with
\r
2998 // original option, which is easy to understand, espatially in
\r
2999 // media query. And in most case, merge option is used to
\r
3000 // update partial option but not be expected to change order.
\r
3001 newCptOptions = (newCptOptions || []).slice();
\r
3003 var result = zrUtil.map(exists || [], function (obj, index) {
\r
3004 return {exist: obj};
\r
3007 // Mapping by id or name if specified.
\r
3008 zrUtil.each(newCptOptions, function (cptOption, index) {
\r
3009 if (!zrUtil.isObject(cptOption)) {
\r
3013 for (var i = 0; i < result.length; i++) {
\r
3014 var exist = result[i].exist;
\r
3015 if (!result[i].option // Consider name: two map to one.
\r
3017 // id has highest priority.
\r
3018 (cptOption.id != null && exist.id === cptOption.id + '')
\r
3019 || (cptOption.name != null
\r
3020 && !modelUtil.isIdInner(cptOption)
\r
3021 && !modelUtil.isIdInner(exist)
\r
3022 && exist.name === cptOption.name + ''
\r
3026 result[i].option = cptOption;
\r
3027 newCptOptions[index] = null;
\r
3033 // Otherwise mapping by index.
\r
3034 zrUtil.each(newCptOptions, function (cptOption, index) {
\r
3035 if (!zrUtil.isObject(cptOption)) {
\r
3040 for (; i < result.length; i++) {
\r
3041 var exist = result[i].exist;
\r
3042 if (!result[i].option
\r
3043 && !modelUtil.isIdInner(exist)
\r
3045 // Do not overwrite id. But name can be overwritten,
\r
3046 // because axis use name as 'show label text'.
\r
3047 // 'exist' always has id and name and we dont
\r
3048 // need to check it.
\r
3049 && cptOption.id == null
\r
3051 result[i].option = cptOption;
\r
3056 if (i >= result.length) {
\r
3057 result.push({option: cptOption});
\r
3066 * @param {Object} cptOption
\r
3067 * @return {boolean}
\r
3069 modelUtil.isIdInner = function (cptOption) {
\r
3070 return zrUtil.isObject(cptOption)
\r
3072 && (cptOption.id + '').indexOf('\0_ec_\0') === 0;
\r
3075 module.exports = modelUtil;
\r
3080 /***/ function(module, exports, __webpack_require__) {
\r
3084 var zrUtil = __webpack_require__(3);
\r
3085 var numberUtil = __webpack_require__(7);
\r
3089 * @type {string|number} x
\r
3091 function addCommas(x) {
\r
3095 x = (x + '').split('.');
\r
3096 return x[0].replace(/(\d{1,3})(?=(?:\d{3})+(?!\d))/g,'$1,')
\r
3097 + (x.length > 1 ? ('.' + x[1]) : '');
\r
3101 * @param {string} str
\r
3102 * @return {string} str
\r
3104 function toCamelCase(str) {
\r
3105 return str.toLowerCase().replace(/-(.)/g, function(match, group1) {
\r
3106 return group1.toUpperCase();
\r
3111 * Normalize css liked array configuration
\r
3113 * 3 => [3, 3, 3, 3]
\r
3114 * [4, 2] => [4, 2, 4, 2]
\r
3115 * [4, 3, 2] => [4, 3, 2, 3]
\r
3116 * @param {number|Array.<number>} val
\r
3118 function normalizeCssArray(val) {
\r
3119 var len = val.length;
\r
3120 if (typeof (val) === 'number') {
\r
3121 return [val, val, val, val];
\r
3123 else if (len === 2) {
\r
3124 // vertical | horizontal
\r
3125 return [val[0], val[1], val[0], val[1]];
\r
3127 else if (len === 3) {
\r
3128 // top | horizontal | bottom
\r
3129 return [val[0], val[1], val[2], val[1]];
\r
3134 function encodeHTML(source) {
\r
3135 return String(source)
\r
3136 .replace(/&/g, '&')
\r
3137 .replace(/</g, '<')
\r
3138 .replace(/>/g, '>')
\r
3139 .replace(/"/g, '"')
\r
3140 .replace(/'/g, ''');
\r
3143 var TPL_VAR_ALIAS = ['a', 'b', 'c', 'd', 'e', 'f', 'g'];
\r
3145 function wrapVar(varName, seriesIdx) {
\r
3146 return '{' + varName + (seriesIdx == null ? '' : seriesIdx) + '}';
\r
3149 * Template formatter
\r
3150 * @param {string} tpl
\r
3151 * @param {Array.<Object>|Object} paramsList
\r
3152 * @return {string}
\r
3154 function formatTpl(tpl, paramsList) {
\r
3155 if (!zrUtil.isArray(paramsList)) {
\r
3156 paramsList = [paramsList];
\r
3158 var seriesLen = paramsList.length;
\r
3163 var $vars = paramsList[0].$vars;
\r
3164 for (var i = 0; i < $vars.length; i++) {
\r
3165 var alias = TPL_VAR_ALIAS[i];
\r
3166 tpl = tpl.replace(wrapVar(alias), wrapVar(alias, 0));
\r
3168 for (var seriesIdx = 0; seriesIdx < seriesLen; seriesIdx++) {
\r
3169 for (var k = 0; k < $vars.length; k++) {
\r
3170 tpl = tpl.replace(
\r
3171 wrapVar(TPL_VAR_ALIAS[k], seriesIdx),
\r
3172 paramsList[seriesIdx][$vars[k]]
\r
3182 * @param {string} tpl
\r
3183 * @param {number} value
\r
3186 function formatTime(tpl, value) {
\r
3187 if (tpl === 'week'
\r
3188 || tpl === 'month'
\r
3189 || tpl === 'quarter'
\r
3190 || tpl === 'half-year'
\r
3193 tpl = 'MM-dd\nyyyy';
\r
3196 var date = numberUtil.parseDate(value);
\r
3197 var y = date.getFullYear();
\r
3198 var M = date.getMonth() + 1;
\r
3199 var d = date.getDate();
\r
3200 var h = date.getHours();
\r
3201 var m = date.getMinutes();
\r
3202 var s = date.getSeconds();
\r
3204 tpl = tpl.replace('MM', s2d(M))
\r
3206 .replace('yyyy', y)
\r
3207 .replace('yy', y % 100)
\r
3208 .replace('dd', s2d(d))
\r
3210 .replace('hh', s2d(h))
\r
3212 .replace('mm', s2d(m))
\r
3214 .replace('ss', s2d(s))
\r
3221 * @param {string} str
\r
3222 * @return {string}
\r
3225 function s2d(str) {
\r
3226 return str < 10 ? ('0' + str) : str;
\r
3229 module.exports = {
\r
3231 normalizeCssArray: normalizeCssArray,
\r
3233 addCommas: addCommas,
\r
3235 toCamelCase: toCamelCase,
\r
3237 encodeHTML: encodeHTML,
\r
3239 formatTpl: formatTpl,
\r
3241 formatTime: formatTime
\r
3247 /***/ function(module, exports) {
\r
3251 * @module echarts/util/number
\r
3258 var RADIAN_EPSILON = 1e-4;
\r
3260 function _trim(str) {
\r
3261 return str.replace(/^\s+/, '').replace(/\s+$/, '');
\r
3265 * Linear mapping a value from domain to range
\r
3266 * @memberOf module:echarts/util/number
\r
3267 * @param {(number|Array.<number>)} val
\r
3268 * @param {Array.<number>} domain Domain extent domain[0] can be bigger than domain[1]
\r
3269 * @param {Array.<number>} range Range extent range[0] can be bigger than range[1]
\r
3270 * @param {boolean} clamp
\r
3271 * @return {(number|Array.<number>}
\r
3273 number.linearMap = function (val, domain, range, clamp) {
\r
3275 var sub = domain[1] - domain[0];
\r
3278 return (range[0] + range[1]) / 2;
\r
3280 var t = (val - domain[0]) / sub;
\r
3283 t = Math.min(Math.max(t, 0), 1);
\r
3286 return t * (range[1] - range[0]) + range[0];
\r
3290 * Convert a percent string to absolute number.
\r
3291 * Returns NaN if percent is not a valid string or number
\r
3292 * @memberOf module:echarts/util/number
\r
3293 * @param {string|number} percent
\r
3294 * @param {number} all
\r
3295 * @return {number}
\r
3297 number.parsePercent = function(percent, all) {
\r
3298 switch (percent) {
\r
3312 if (typeof percent === 'string') {
\r
3313 if (_trim(percent).match(/%$/)) {
\r
3314 return parseFloat(percent) / 100 * all;
\r
3317 return parseFloat(percent);
\r
3320 return percent == null ? NaN : +percent;
\r
3324 * Fix rounding error of float numbers
\r
3325 * @param {number} x
\r
3326 * @return {number}
\r
3328 number.round = function (x) {
\r
3330 return +(+x).toFixed(12);
\r
3333 number.asc = function (arr) {
\r
3334 arr.sort(function (a, b) {
\r
3342 * @param {number} val
\r
3344 number.getPrecision = function (val) {
\r
3348 // It is much faster than methods converting number to string as follows
\r
3349 // var tmp = val.toString();
\r
3350 // return tmp.length - 1 - tmp.indexOf('.');
\r
3351 // especially when precision is low
\r
3354 while (Math.round(val * e) / e !== val) {
\r
3362 * @param {Array.<number>} dataExtent
\r
3363 * @param {Array.<number>} pixelExtent
\r
3364 * @return {number} precision
\r
3366 number.getPixelPrecision = function (dataExtent, pixelExtent) {
\r
3367 var log = Math.log;
\r
3368 var LN10 = Math.LN10;
\r
3369 var dataQuantity = Math.floor(log(dataExtent[1] - dataExtent[0]) / LN10);
\r
3370 var sizeQuantity = Math.round(log(Math.abs(pixelExtent[1] - pixelExtent[0])) / LN10);
\r
3372 -dataQuantity + sizeQuantity,
\r
3377 // Number.MAX_SAFE_INTEGER, ie do not support.
\r
3378 number.MAX_SAFE_INTEGER = 9007199254740991;
\r
3381 * To 0 - 2 * PI, considering negative radian.
\r
3382 * @param {number} radian
\r
3383 * @return {number}
\r
3385 number.remRadian = function (radian) {
\r
3386 var pi2 = Math.PI * 2;
\r
3387 return (radian % pi2 + pi2) % pi2;
\r
3391 * @param {type} radian
\r
3392 * @return {boolean}
\r
3394 number.isRadianAroundZero = function (val) {
\r
3395 return val > -RADIAN_EPSILON && val < RADIAN_EPSILON;
\r
3399 * @param {string|Date|number} value
\r
3400 * @return {number} timestamp
\r
3402 number.parseDate = function (value) {
\r
3403 return value instanceof Date
\r
3406 typeof value === 'string'
\r
3407 ? value.replace(/-/g, '/')
\r
3408 : Math.round(value)
\r
3412 // "Nice Numbers for Graph Labels" of Graphic Gems
\r
3414 * find a “nice” number approximately equal to x. Round the number if round = true, take ceiling if round = false
\r
3415 * The primary observation is that the “nicest” numbers in decimal are 1, 2, and 5, and all power-of-ten multiples of these numbers.
\r
3416 * @param {number} val
\r
3417 * @param {boolean} round
\r
3418 * @return {number}
\r
3420 number.nice = function (val, round) {
\r
3421 var exp = Math.floor(Math.log(val) / Math.LN10);
\r
3422 var exp10 = Math.pow(10, exp);
\r
3423 var f = val / exp10; // between 1 and 10
\r
3426 if (f < 1.5) { nf = 1; }
\r
3427 else if (f < 2.5) { nf = 2; }
\r
3428 else if (f < 4) { nf = 3; }
\r
3429 else if (f < 7) { nf = 5; }
\r
3433 if (f < 1) { nf = 1; }
\r
3434 else if (f < 2) { nf = 2; }
\r
3435 else if (f < 3) { nf = 3; }
\r
3436 else if (f < 5) { nf = 5; }
\r
3439 return nf * exp10;
\r
3442 module.exports = number;
\r
3447 /***/ function(module, exports, __webpack_require__) {
\r
3450 * @module echarts/model/Model
\r
3454 var zrUtil = __webpack_require__(3);
\r
3455 var clazzUtil = __webpack_require__(9);
\r
3458 * @alias module:echarts/model/Model
\r
3460 * @param {Object} option
\r
3461 * @param {module:echarts/model/Model} parentModel
\r
3462 * @param {module:echarts/model/Global} ecModel
\r
3463 * @param {Object} extraOpt
\r
3465 function Model(option, parentModel, ecModel, extraOpt) {
\r
3467 * @type {module:echarts/model/Model}
\r
3470 this.parentModel = parentModel;
\r
3473 * @type {module:echarts/model/Global}
\r
3476 this.ecModel = ecModel;
\r
3482 this.option = option;
\r
3484 // Simple optimization
\r
3486 if (arguments.length <= 4) {
\r
3487 this.init(option, parentModel, ecModel, extraOpt);
\r
3490 this.init.apply(this, arguments);
\r
3495 Model.prototype = {
\r
3497 constructor: Model,
\r
3501 * @param {Object} option
\r
3506 * 从新的 Option merge
\r
3508 mergeOption: function (option) {
\r
3509 zrUtil.merge(this.option, option, true);
\r
3513 * @param {string} path
\r
3514 * @param {boolean} [ignoreParent=false]
\r
3517 get: function (path, ignoreParent) {
\r
3519 return this.option;
\r
3522 if (typeof path === 'string') {
\r
3523 path = path.split('.');
\r
3526 var obj = this.option;
\r
3527 var parentModel = this.parentModel;
\r
3528 for (var i = 0; i < path.length; i++) {
\r
3529 // obj could be number/string/... (like 0)
\r
3530 obj = (obj && typeof obj === 'object') ? obj[path[i]] : null;
\r
3531 if (obj == null) {
\r
3535 if (obj == null && parentModel && !ignoreParent) {
\r
3536 obj = parentModel.get(path);
\r
3542 * @param {string} key
\r
3543 * @param {boolean} [ignoreParent=false]
\r
3546 getShallow: function (key, ignoreParent) {
\r
3547 var option = this.option;
\r
3548 var val = option && option[key];
\r
3549 var parentModel = this.parentModel;
\r
3550 if (val == null && parentModel && !ignoreParent) {
\r
3551 val = parentModel.getShallow(key);
\r
3557 * @param {string} path
\r
3558 * @param {module:echarts/model/Model} [parentModel]
\r
3559 * @return {module:echarts/model/Model}
\r
3561 getModel: function (path, parentModel) {
\r
3562 var obj = this.get(path, true);
\r
3563 var thisParentModel = this.parentModel;
\r
3564 var model = new Model(
\r
3565 obj, parentModel || (thisParentModel && thisParentModel.getModel(path)),
\r
3572 * If model has option
\r
3574 isEmpty: function () {
\r
3575 return this.option == null;
\r
3578 restoreData: function () {},
\r
3581 clone: function () {
\r
3582 var Ctor = this.constructor;
\r
3583 return new Ctor(zrUtil.clone(this.option));
\r
3586 setReadOnly: function (properties) {
\r
3587 clazzUtil.setReadOnly(this, properties);
\r
3591 // Enable Model.extend.
\r
3592 clazzUtil.enableClassExtend(Model);
\r
3594 var mixin = zrUtil.mixin;
\r
3595 mixin(Model, __webpack_require__(10));
\r
3596 mixin(Model, __webpack_require__(12));
\r
3597 mixin(Model, __webpack_require__(13));
\r
3598 mixin(Model, __webpack_require__(18));
\r
3600 module.exports = Model;
\r
3605 /***/ function(module, exports, __webpack_require__) {
\r
3609 var zrUtil = __webpack_require__(3);
\r
3613 var TYPE_DELIMITER = '.';
\r
3614 var IS_CONTAINER = '___EC__COMPONENT__CONTAINER___';
\r
3618 var parseClassType = clazz.parseClassType = function (componentType) {
\r
3619 var ret = {main: '', sub: ''};
\r
3620 if (componentType) {
\r
3621 componentType = componentType.split(TYPE_DELIMITER);
\r
3622 ret.main = componentType[0] || '';
\r
3623 ret.sub = componentType[1] || '';
\r
3630 clazz.enableClassExtend = function (RootClass, preConstruct) {
\r
3631 RootClass.extend = function (proto) {
\r
3632 var ExtendedClass = function () {
\r
3633 preConstruct && preConstruct.apply(this, arguments);
\r
3634 RootClass.apply(this, arguments);
\r
3637 zrUtil.extend(ExtendedClass.prototype, proto);
\r
3639 ExtendedClass.extend = this.extend;
\r
3640 ExtendedClass.superCall = superCall;
\r
3641 ExtendedClass.superApply = superApply;
\r
3642 zrUtil.inherits(ExtendedClass, this);
\r
3643 ExtendedClass.superClass = this;
\r
3645 return ExtendedClass;
\r
3649 // superCall should have class info, which can not be fetch from 'this'.
\r
3650 // Consider this case:
\r
3651 // class A has method f,
\r
3652 // class B inherits class A, overrides method f, f call superApply('f'),
\r
3653 // class C inherits class B, do not overrides method f,
\r
3654 // then when method of class C is called, dead loop occured.
\r
3655 function superCall(context, methodName) {
\r
3656 var args = zrUtil.slice(arguments, 2);
\r
3657 return this.superClass.prototype[methodName].apply(context, args);
\r
3660 function superApply(context, methodName, args) {
\r
3661 return this.superClass.prototype[methodName].apply(context, args);
\r
3665 * @param {Object} entity
\r
3666 * @param {Object} options
\r
3667 * @param {boolean} [options.registerWhenExtend]
\r
3670 clazz.enableClassManagement = function (entity, options) {
\r
3671 options = options || {};
\r
3674 * Component model classes
\r
3675 * key: componentType,
\r
3677 * componentClass, when componentType is 'xxx'
\r
3678 * or Object.<subKey, componentClass>, when componentType is 'xxx.yy'
\r
3683 entity.registerClass = function (Clazz, componentType) {
\r
3684 if (componentType) {
\r
3685 componentType = parseClassType(componentType);
\r
3687 if (!componentType.sub) {
\r
3688 if (storage[componentType.main]) {
\r
3689 throw new Error(componentType.main + 'exists.');
\r
3691 storage[componentType.main] = Clazz;
\r
3693 else if (componentType.sub !== IS_CONTAINER) {
\r
3694 var container = makeContainer(componentType);
\r
3695 container[componentType.sub] = Clazz;
\r
3701 entity.getClass = function (componentTypeMain, subType, throwWhenNotFound) {
\r
3702 var Clazz = storage[componentTypeMain];
\r
3704 if (Clazz && Clazz[IS_CONTAINER]) {
\r
3705 Clazz = subType ? Clazz[subType] : null;
\r
3708 if (throwWhenNotFound && !Clazz) {
\r
3710 'Component ' + componentTypeMain + '.' + (subType || '') + ' not exists. Load it first.'
\r
3717 entity.getClassesByMainType = function (componentType) {
\r
3718 componentType = parseClassType(componentType);
\r
3721 var obj = storage[componentType.main];
\r
3723 if (obj && obj[IS_CONTAINER]) {
\r
3724 zrUtil.each(obj, function (o, type) {
\r
3725 type !== IS_CONTAINER && result.push(o);
\r
3735 entity.hasClass = function (componentType) {
\r
3736 // Just consider componentType.main.
\r
3737 componentType = parseClassType(componentType);
\r
3738 return !!storage[componentType.main];
\r
3742 * @return {Array.<string>} Like ['aa', 'bb'], but can not be ['aa.xx']
\r
3744 entity.getAllClassMainTypes = function () {
\r
3746 zrUtil.each(storage, function (obj, type) {
\r
3753 * If a main type is container and has sub types
\r
3754 * @param {string} mainType
\r
3755 * @return {boolean}
\r
3757 entity.hasSubTypes = function (componentType) {
\r
3758 componentType = parseClassType(componentType);
\r
3759 var obj = storage[componentType.main];
\r
3760 return obj && obj[IS_CONTAINER];
\r
3763 entity.parseClassType = parseClassType;
\r
3765 function makeContainer(componentType) {
\r
3766 var container = storage[componentType.main];
\r
3767 if (!container || !container[IS_CONTAINER]) {
\r
3768 container = storage[componentType.main] = {};
\r
3769 container[IS_CONTAINER] = true;
\r
3774 if (options.registerWhenExtend) {
\r
3775 var originalExtend = entity.extend;
\r
3776 if (originalExtend) {
\r
3777 entity.extend = function (proto) {
\r
3778 var ExtendedClass = originalExtend.call(this, proto);
\r
3779 return entity.registerClass(ExtendedClass, proto.type);
\r
3788 * @param {string|Array.<string>} properties
\r
3790 clazz.setReadOnly = function (obj, properties) {
\r
3791 // FIXME It seems broken in IE8 simulation of IE11
\r
3792 // if (!zrUtil.isArray(properties)) {
\r
3793 // properties = properties != null ? [properties] : [];
\r
3795 // zrUtil.each(properties, function (prop) {
\r
3796 // var value = obj[prop];
\r
3798 // Object.defineProperty
\r
3799 // && Object.defineProperty(obj, prop, {
\r
3800 // value: value, writable: false
\r
3802 // zrUtil.isArray(obj[prop])
\r
3803 // && Object.freeze
\r
3804 // && Object.freeze(obj[prop]);
\r
3808 module.exports = clazz;
\r
3813 /***/ function(module, exports, __webpack_require__) {
\r
3816 var getLineStyle = __webpack_require__(11)(
\r
3818 ['lineWidth', 'width'],
\r
3819 ['stroke', 'color'],
\r
3822 ['shadowOffsetX'],
\r
3823 ['shadowOffsetY'],
\r
3827 module.exports = {
\r
3828 getLineStyle: function (excludes) {
\r
3829 var style = getLineStyle.call(this, excludes);
\r
3830 var lineDash = this.getLineDash();
\r
3831 lineDash && (style.lineDash = lineDash);
\r
3835 getLineDash: function () {
\r
3836 var lineType = this.get('type');
\r
3837 return (lineType === 'solid' || lineType == null) ? null
\r
3838 : (lineType === 'dashed' ? [5, 5] : [1, 1]);
\r
3845 /***/ function(module, exports, __webpack_require__) {
\r
3847 // TODO Parse shadow style
\r
3848 // TODO Only shallow path support
\r
3850 var zrUtil = __webpack_require__(3);
\r
3852 module.exports = function (properties) {
\r
3854 for (var i = 0; i < properties.length; i++) {
\r
3855 if (!properties[i][1]) {
\r
3856 properties[i][1] = properties[i][0];
\r
3859 return function (excludes) {
\r
3861 for (var i = 0; i < properties.length; i++) {
\r
3862 var propName = properties[i][1];
\r
3863 if (excludes && zrUtil.indexOf(excludes, propName) >= 0) {
\r
3866 var val = this.getShallow(propName);
\r
3867 if (val != null) {
\r
3868 style[properties[i][0]] = val;
\r
3878 /***/ function(module, exports, __webpack_require__) {
\r
3881 module.exports = {
\r
3882 getAreaStyle: __webpack_require__(11)(
\r
3884 ['fill', 'color'],
\r
3886 ['shadowOffsetX'],
\r
3887 ['shadowOffsetY'],
\r
3897 /***/ function(module, exports, __webpack_require__) {
\r
3901 var textContain = __webpack_require__(14);
\r
3903 function getShallow(model, path) {
\r
3904 return model && model.getShallow(path);
\r
3907 module.exports = {
\r
3909 * Get color property or get color from option.textStyle.color
\r
3910 * @return {string}
\r
3912 getTextColor: function () {
\r
3913 var ecModel = this.ecModel;
\r
3914 return this.getShallow('color')
\r
3915 || (ecModel && ecModel.get('textStyle.color'));
\r
3919 * Create font string from fontStyle, fontWeight, fontSize, fontFamily
\r
3920 * @return {string}
\r
3922 getFont: function () {
\r
3923 var ecModel = this.ecModel;
\r
3924 var gTextStyleModel = ecModel && ecModel.getModel('textStyle');
\r
3926 // FIXME in node-canvas fontWeight is before fontStyle
\r
3927 this.getShallow('fontStyle') || getShallow(gTextStyleModel, 'fontStyle'),
\r
3928 this.getShallow('fontWeight') || getShallow(gTextStyleModel, 'fontWeight'),
\r
3929 (this.getShallow('fontSize') || getShallow(gTextStyleModel, 'fontSize') || 12) + 'px',
\r
3930 this.getShallow('fontFamily') || getShallow(gTextStyleModel, 'fontFamily') || 'sans-serif'
\r
3934 getTextRect: function (text) {
\r
3935 var textStyle = this.get('textStyle') || {};
\r
3936 return textContain.getBoundingRect(
\r
3940 textStyle.baseline
\r
3944 ellipsis: function (text, containerWidth, options) {
\r
3945 return textContain.ellipsis(
\r
3946 text, this.getFont(), containerWidth, options
\r
3954 /***/ function(module, exports, __webpack_require__) {
\r
3958 var textWidthCache = {};
\r
3959 var textWidthCacheCounter = 0;
\r
3960 var TEXT_CACHE_MAX = 5000;
\r
3962 var util = __webpack_require__(3);
\r
3963 var BoundingRect = __webpack_require__(15);
\r
3965 function getTextWidth(text, textFont) {
\r
3966 var key = text + ':' + textFont;
\r
3967 if (textWidthCache[key]) {
\r
3968 return textWidthCache[key];
\r
3971 var textLines = (text + '').split('\n');
\r
3974 for (var i = 0, l = textLines.length; i < l; i++) {
\r
3975 // measureText 可以被覆盖以兼容不支持 Canvas 的环境
\r
3976 width = Math.max(textContain.measureText(textLines[i], textFont).width, width);
\r
3979 if (textWidthCacheCounter > TEXT_CACHE_MAX) {
\r
3980 textWidthCacheCounter = 0;
\r
3981 textWidthCache = {};
\r
3983 textWidthCacheCounter++;
\r
3984 textWidthCache[key] = width;
\r
3989 function getTextRect(text, textFont, textAlign, textBaseline) {
\r
3990 var textLineLen = ((text || '') + '').split('\n').length;
\r
3992 var width = getTextWidth(text, textFont);
\r
3994 var lineHeight = getTextWidth('国', textFont);
\r
3995 var height = textLineLen * lineHeight;
\r
3997 var rect = new BoundingRect(0, 0, width, height);
\r
3998 // Text has a special line height property
\r
3999 rect.lineHeight = lineHeight;
\r
4001 switch (textBaseline) {
\r
4003 case 'alphabetic':
\r
4004 rect.y -= lineHeight;
\r
4007 rect.y -= lineHeight / 2;
\r
4009 // case 'hanging':
\r
4013 // FIXME Right to left language
\r
4014 switch (textAlign) {
\r
4017 rect.x -= rect.width;
\r
4020 rect.x -= rect.width / 2;
\r
4029 function adjustTextPositionOnRect(textPosition, rect, textRect, distance) {
\r
4034 var height = rect.height;
\r
4035 var width = rect.width;
\r
4037 var textHeight = textRect.height;
\r
4039 var halfHeight = height / 2 - textHeight / 2;
\r
4041 var textAlign = 'left';
\r
4043 switch (textPosition) {
\r
4047 textAlign = 'right';
\r
4050 x += distance + width;
\r
4052 textAlign = 'left';
\r
4056 y -= distance + textHeight;
\r
4057 textAlign = 'center';
\r
4061 y += height + distance;
\r
4062 textAlign = 'center';
\r
4067 textAlign = 'center';
\r
4069 case 'insideLeft':
\r
4072 textAlign = 'left';
\r
4074 case 'insideRight':
\r
4075 x += width - distance;
\r
4077 textAlign = 'right';
\r
4082 textAlign = 'center';
\r
4084 case 'insideBottom':
\r
4086 y += height - textHeight - distance;
\r
4087 textAlign = 'center';
\r
4089 case 'insideTopLeft':
\r
4092 textAlign = 'left';
\r
4094 case 'insideTopRight':
\r
4095 x += width - distance;
\r
4097 textAlign = 'right';
\r
4099 case 'insideBottomLeft':
\r
4101 y += height - textHeight - distance;
\r
4103 case 'insideBottomRight':
\r
4104 x += width - distance;
\r
4105 y += height - textHeight - distance;
\r
4106 textAlign = 'right';
\r
4113 textAlign: textAlign,
\r
4114 textBaseline: 'top'
\r
4119 * Show ellipsis if overflow.
\r
4121 * @param {string} text
\r
4122 * @param {string} textFont
\r
4123 * @param {string} containerWidth
\r
4124 * @param {Object} [options]
\r
4125 * @param {number} [options.ellipsis='...']
\r
4126 * @param {number} [options.maxIterations=3]
\r
4127 * @param {number} [options.minCharacters=3]
\r
4128 * @return {string}
\r
4130 function textEllipsis(text, textFont, containerWidth, options) {
\r
4131 if (!containerWidth) {
\r
4135 options = util.defaults({
\r
4139 cnCharWidth: getTextWidth('国', textFont),
\r
4142 ascCharWidth: getTextWidth('a', textFont)
\r
4143 }, options, true);
\r
4145 containerWidth -= getTextWidth(options.ellipsis);
\r
4147 var textLines = (text + '').split('\n');
\r
4149 for (var i = 0, len = textLines.length; i < len; i++) {
\r
4150 textLines[i] = textLineTruncate(
\r
4151 textLines[i], textFont, containerWidth, options
\r
4155 return textLines.join('\n');
\r
4158 function textLineTruncate(text, textFont, containerWidth, options) {
\r
4160 // 粗糙得写的,尚未考虑性能和各种语言、字体的效果。
\r
4161 for (var i = 0;; i++) {
\r
4162 var lineWidth = getTextWidth(text, textFont);
\r
4164 if (lineWidth < containerWidth || i >= options.maxIterations) {
\r
4165 text += options.ellipsis;
\r
4169 var subLength = i === 0
\r
4170 ? estimateLength(text, containerWidth, options)
\r
4171 : Math.floor(text.length * containerWidth / lineWidth);
\r
4173 if (subLength < options.minCharacters) {
\r
4178 text = text.substr(0, subLength);
\r
4184 function estimateLength(text, containerWidth, options) {
\r
4187 for (var len = text.length; i < len && width < containerWidth; i++) {
\r
4188 var charCode = text.charCodeAt(i);
\r
4189 width += (0 <= charCode && charCode <= 127)
\r
4190 ? options.ascCharWidth : options.cnCharWidth;
\r
4195 var textContain = {
\r
4197 getWidth: getTextWidth,
\r
4199 getBoundingRect: getTextRect,
\r
4201 adjustTextPositionOnRect: adjustTextPositionOnRect,
\r
4203 ellipsis: textEllipsis,
\r
4205 measureText: function (text, textFont) {
\r
4206 var ctx = util.getContext();
\r
4207 ctx.font = textFont;
\r
4208 return ctx.measureText(text);
\r
4212 module.exports = textContain;
\r
4217 /***/ function(module, exports, __webpack_require__) {
\r
4221 * @module echarts/core/BoundingRect
\r
4225 var vec2 = __webpack_require__(16);
\r
4226 var matrix = __webpack_require__(17);
\r
4228 var v2ApplyTransform = vec2.applyTransform;
\r
4229 var mathMin = Math.min;
\r
4230 var mathAbs = Math.abs;
\r
4231 var mathMax = Math.max;
\r
4233 * @alias module:echarts/core/BoundingRect
\r
4235 function BoundingRect(x, y, width, height) {
\r
4247 this.width = width;
\r
4251 this.height = height;
\r
4254 BoundingRect.prototype = {
\r
4256 constructor: BoundingRect,
\r
4259 * @param {module:echarts/core/BoundingRect} other
\r
4261 union: function (other) {
\r
4262 var x = mathMin(other.x, this.x);
\r
4263 var y = mathMin(other.y, this.y);
\r
4265 this.width = mathMax(
\r
4266 other.x + other.width,
\r
4267 this.x + this.width
\r
4269 this.height = mathMax(
\r
4270 other.y + other.height,
\r
4271 this.y + this.height
\r
4278 * @param {Array.<number>} m
\r
4281 applyTransform: (function () {
\r
4284 return function (m) {
\r
4285 // In case usage like this
\r
4286 // el.getBoundingRect().applyTransform(el.transform)
\r
4287 // And element has no transform
\r
4293 max[0] = this.x + this.width;
\r
4294 max[1] = this.y + this.height;
\r
4296 v2ApplyTransform(min, min, m);
\r
4297 v2ApplyTransform(max, max, m);
\r
4299 this.x = mathMin(min[0], max[0]);
\r
4300 this.y = mathMin(min[1], max[1]);
\r
4301 this.width = mathAbs(max[0] - min[0]);
\r
4302 this.height = mathAbs(max[1] - min[1]);
\r
4307 * Calculate matrix of transforming from self to target rect
\r
4308 * @param {module:zrender/core/BoundingRect} b
\r
4309 * @return {Array.<number>}
\r
4311 calculateTransform: function (b) {
\r
4313 var sx = b.width / a.width;
\r
4314 var sy = b.height / a.height;
\r
4316 var m = matrix.create();
\r
4319 matrix.translate(m, m, [-a.x, -a.y]);
\r
4320 matrix.scale(m, m, [sx, sy]);
\r
4321 matrix.translate(m, m, [b.x, b.y]);
\r
4327 * @param {(module:echarts/core/BoundingRect|Object)} b
\r
4328 * @return {boolean}
\r
4330 intersect: function (b) {
\r
4333 var ax1 = a.x + a.width;
\r
4335 var ay1 = a.y + a.height;
\r
4338 var bx1 = b.x + b.width;
\r
4340 var by1 = b.y + b.height;
\r
4342 return ! (ax1 < bx0 || bx1 < ax0 || ay1 < by0 || by1 < ay0);
\r
4345 contain: function (x, y) {
\r
4347 return x >= rect.x
\r
4348 && x <= (rect.x + rect.width)
\r
4350 && y <= (rect.y + rect.height);
\r
4354 * @return {module:echarts/core/BoundingRect}
\r
4356 clone: function () {
\r
4357 return new BoundingRect(this.x, this.y, this.width, this.height);
\r
4361 * Copy from another rect
\r
4363 copy: function (other) {
\r
4366 this.width = other.width;
\r
4367 this.height = other.height;
\r
4371 module.exports = BoundingRect;
\r
4376 /***/ function(module, exports) {
\r
4379 var ArrayCtor = typeof Float32Array === 'undefined'
\r
4384 * @typedef {Float32Array|Array.<number>} Vector2
\r
4388 * @exports zrender/tool/vector
\r
4393 * @param {number} [x=0]
\r
4394 * @param {number} [y=0]
\r
4395 * @return {Vector2}
\r
4397 create: function (x, y) {
\r
4398 var out = new ArrayCtor(2);
\r
4406 * @param {Vector2} out
\r
4407 * @param {Vector2} v
\r
4408 * @return {Vector2}
\r
4410 copy: function (out, v) {
\r
4418 * @param {Vector2} v
\r
4419 * @return {Vector2}
\r
4421 clone: function (v) {
\r
4422 var out = new ArrayCtor(2);
\r
4430 * @param {Vector2} out
\r
4431 * @param {number} a
\r
4432 * @param {number} b
\r
4433 * @return {Vector2} 结果
\r
4435 set: function (out, a, b) {
\r
4443 * @param {Vector2} out
\r
4444 * @param {Vector2} v1
\r
4445 * @param {Vector2} v2
\r
4447 add: function (out, v1, v2) {
\r
4448 out[0] = v1[0] + v2[0];
\r
4449 out[1] = v1[1] + v2[1];
\r
4455 * @param {Vector2} out
\r
4456 * @param {Vector2} v1
\r
4457 * @param {Vector2} v2
\r
4458 * @param {number} a
\r
4460 scaleAndAdd: function (out, v1, v2, a) {
\r
4461 out[0] = v1[0] + v2[0] * a;
\r
4462 out[1] = v1[1] + v2[1] * a;
\r
4468 * @param {Vector2} out
\r
4469 * @param {Vector2} v1
\r
4470 * @param {Vector2} v2
\r
4472 sub: function (out, v1, v2) {
\r
4473 out[0] = v1[0] - v2[0];
\r
4474 out[1] = v1[1] - v2[1];
\r
4480 * @param {Vector2} v
\r
4481 * @return {number}
\r
4483 len: function (v) {
\r
4484 return Math.sqrt(this.lenSquare(v));
\r
4489 * @param {Vector2} v
\r
4490 * @return {number}
\r
4492 lenSquare: function (v) {
\r
4493 return v[0] * v[0] + v[1] * v[1];
\r
4498 * @param {Vector2} out
\r
4499 * @param {Vector2} v1
\r
4500 * @param {Vector2} v2
\r
4502 mul: function (out, v1, v2) {
\r
4503 out[0] = v1[0] * v2[0];
\r
4504 out[1] = v1[1] * v2[1];
\r
4510 * @param {Vector2} out
\r
4511 * @param {Vector2} v1
\r
4512 * @param {Vector2} v2
\r
4514 div: function (out, v1, v2) {
\r
4515 out[0] = v1[0] / v2[0];
\r
4516 out[1] = v1[1] / v2[1];
\r
4522 * @param {Vector2} v1
\r
4523 * @param {Vector2} v2
\r
4524 * @return {number}
\r
4526 dot: function (v1, v2) {
\r
4527 return v1[0] * v2[0] + v1[1] * v2[1];
\r
4532 * @param {Vector2} out
\r
4533 * @param {Vector2} v
\r
4534 * @param {number} s
\r
4536 scale: function (out, v, s) {
\r
4537 out[0] = v[0] * s;
\r
4538 out[1] = v[1] * s;
\r
4544 * @param {Vector2} out
\r
4545 * @param {Vector2} v
\r
4547 normalize: function (out, v) {
\r
4548 var d = vector.len(v);
\r
4554 out[0] = v[0] / d;
\r
4555 out[1] = v[1] / d;
\r
4562 * @param {Vector2} v1
\r
4563 * @param {Vector2} v2
\r
4564 * @return {number}
\r
4566 distance: function (v1, v2) {
\r
4568 (v1[0] - v2[0]) * (v1[0] - v2[0])
\r
4569 + (v1[1] - v2[1]) * (v1[1] - v2[1])
\r
4575 * @param {Vector2} v1
\r
4576 * @param {Vector2} v2
\r
4577 * @return {number}
\r
4579 distanceSquare: function (v1, v2) {
\r
4580 return (v1[0] - v2[0]) * (v1[0] - v2[0])
\r
4581 + (v1[1] - v2[1]) * (v1[1] - v2[1]);
\r
4586 * @param {Vector2} out
\r
4587 * @param {Vector2} v
\r
4589 negate: function (out, v) {
\r
4597 * @param {Vector2} out
\r
4598 * @param {Vector2} v1
\r
4599 * @param {Vector2} v2
\r
4600 * @param {number} t
\r
4602 lerp: function (out, v1, v2, t) {
\r
4603 out[0] = v1[0] + t * (v2[0] - v1[0]);
\r
4604 out[1] = v1[1] + t * (v2[1] - v1[1]);
\r
4610 * @param {Vector2} out
\r
4611 * @param {Vector2} v
\r
4612 * @param {Vector2} m
\r
4614 applyTransform: function (out, v, m) {
\r
4617 out[0] = m[0] * x + m[2] * y + m[4];
\r
4618 out[1] = m[1] * x + m[3] * y + m[5];
\r
4623 * @param {Vector2} out
\r
4624 * @param {Vector2} v1
\r
4625 * @param {Vector2} v2
\r
4627 min: function (out, v1, v2) {
\r
4628 out[0] = Math.min(v1[0], v2[0]);
\r
4629 out[1] = Math.min(v1[1], v2[1]);
\r
4634 * @param {Vector2} out
\r
4635 * @param {Vector2} v1
\r
4636 * @param {Vector2} v2
\r
4638 max: function (out, v1, v2) {
\r
4639 out[0] = Math.max(v1[0], v2[0]);
\r
4640 out[1] = Math.max(v1[1], v2[1]);
\r
4645 vector.length = vector.len;
\r
4646 vector.lengthSquare = vector.lenSquare;
\r
4647 vector.dist = vector.distance;
\r
4648 vector.distSquare = vector.distanceSquare;
\r
4650 module.exports = vector;
\r
4656 /***/ function(module, exports) {
\r
4659 var ArrayCtor = typeof Float32Array === 'undefined'
\r
4664 * @exports zrender/tool/matrix
\r
4669 * @return {Float32Array|Array.<number>}
\r
4671 create : function() {
\r
4672 var out = new ArrayCtor(6);
\r
4673 matrix.identity(out);
\r
4679 * @param {Float32Array|Array.<number>} out
\r
4681 identity : function(out) {
\r
4692 * @param {Float32Array|Array.<number>} out
\r
4693 * @param {Float32Array|Array.<number>} m
\r
4695 copy: function(out, m) {
\r
4706 * @param {Float32Array|Array.<number>} out
\r
4707 * @param {Float32Array|Array.<number>} m1
\r
4708 * @param {Float32Array|Array.<number>} m2
\r
4710 mul : function (out, m1, m2) {
\r
4711 // Consider matrix.mul(m, m2, m);
\r
4712 // where out is the same as m2.
\r
4713 // So use temp variable to escape error.
\r
4714 var out0 = m1[0] * m2[0] + m1[2] * m2[1];
\r
4715 var out1 = m1[1] * m2[0] + m1[3] * m2[1];
\r
4716 var out2 = m1[0] * m2[2] + m1[2] * m2[3];
\r
4717 var out3 = m1[1] * m2[2] + m1[3] * m2[3];
\r
4718 var out4 = m1[0] * m2[4] + m1[2] * m2[5] + m1[4];
\r
4719 var out5 = m1[1] * m2[4] + m1[3] * m2[5] + m1[5];
\r
4730 * @param {Float32Array|Array.<number>} out
\r
4731 * @param {Float32Array|Array.<number>} a
\r
4732 * @param {Float32Array|Array.<number>} v
\r
4734 translate : function(out, a, v) {
\r
4739 out[4] = a[4] + v[0];
\r
4740 out[5] = a[5] + v[1];
\r
4745 * @param {Float32Array|Array.<number>} out
\r
4746 * @param {Float32Array|Array.<number>} a
\r
4747 * @param {number} rad
\r
4749 rotate : function(out, a, rad) {
\r
4756 var st = Math.sin(rad);
\r
4757 var ct = Math.cos(rad);
\r
4759 out[0] = aa * ct + ab * st;
\r
4760 out[1] = -aa * st + ab * ct;
\r
4761 out[2] = ac * ct + ad * st;
\r
4762 out[3] = -ac * st + ct * ad;
\r
4763 out[4] = ct * atx + st * aty;
\r
4764 out[5] = ct * aty - st * atx;
\r
4769 * @param {Float32Array|Array.<number>} out
\r
4770 * @param {Float32Array|Array.<number>} a
\r
4771 * @param {Float32Array|Array.<number>} v
\r
4773 scale : function(out, a, v) {
\r
4776 out[0] = a[0] * vx;
\r
4777 out[1] = a[1] * vy;
\r
4778 out[2] = a[2] * vx;
\r
4779 out[3] = a[3] * vy;
\r
4780 out[4] = a[4] * vx;
\r
4781 out[5] = a[5] * vy;
\r
4786 * @param {Float32Array|Array.<number>} out
\r
4787 * @param {Float32Array|Array.<number>} a
\r
4789 invert : function(out, a) {
\r
4798 var det = aa * ad - ab * ac;
\r
4804 out[0] = ad * det;
\r
4805 out[1] = -ab * det;
\r
4806 out[2] = -ac * det;
\r
4807 out[3] = aa * det;
\r
4808 out[4] = (ac * aty - ad * atx) * det;
\r
4809 out[5] = (ab * atx - aa * aty) * det;
\r
4814 module.exports = matrix;
\r
4820 /***/ function(module, exports, __webpack_require__) {
\r
4823 module.exports = {
\r
4824 getItemStyle: __webpack_require__(11)(
\r
4826 ['fill', 'color'],
\r
4827 ['stroke', 'borderColor'],
\r
4828 ['lineWidth', 'borderWidth'],
\r
4831 ['shadowOffsetX'],
\r
4832 ['shadowOffsetY'],
\r
4841 /***/ function(module, exports, __webpack_require__) {
\r
4846 * @module echarts/model/Component
\r
4850 var Model = __webpack_require__(8);
\r
4851 var zrUtil = __webpack_require__(3);
\r
4852 var arrayPush = Array.prototype.push;
\r
4853 var componentUtil = __webpack_require__(20);
\r
4854 var clazzUtil = __webpack_require__(9);
\r
4855 var layout = __webpack_require__(21);
\r
4858 * @alias module:echarts/model/Component
\r
4860 * @param {Object} option
\r
4861 * @param {module:echarts/model/Model} parentModel
\r
4862 * @param {module:echarts/model/Model} ecModel
\r
4864 var ComponentModel = Model.extend({
\r
4866 type: 'component',
\r
4895 componentIndex: 0,
\r
4901 defaultOption: null,
\r
4904 * @type {module:echarts/model/Global}
\r
4910 * key: componentType
\r
4911 * value: Component model list, can not be null.
\r
4912 * @type {Object.<string, Array.<module:echarts/model/Model>>}
\r
4915 dependentModels: [],
\r
4924 * Support merge layout params.
\r
4925 * Only support 'box' now (left/right/top/bottom/width/height).
\r
4926 * @type {string|Object} Object can be {ignoreSize: true}
\r
4932 init: function (option, parentModel, ecModel, extraOpt) {
\r
4933 this.mergeDefaultAndTheme(this.option, this.ecModel);
\r
4936 mergeDefaultAndTheme: function (option, ecModel) {
\r
4937 var layoutMode = this.layoutMode;
\r
4938 var inputPositionParams = layoutMode
\r
4939 ? layout.getLayoutParams(option) : {};
\r
4941 var themeModel = ecModel.getTheme();
\r
4942 zrUtil.merge(option, themeModel.get(this.mainType));
\r
4943 zrUtil.merge(option, this.getDefaultOption());
\r
4946 layout.mergeLayoutParam(option, inputPositionParams, layoutMode);
\r
4950 mergeOption: function (option) {
\r
4951 zrUtil.merge(this.option, option, true);
\r
4953 var layoutMode = this.layoutMode;
\r
4955 layout.mergeLayoutParam(this.option, option, layoutMode);
\r
4959 // Hooker after init or mergeOption
\r
4960 optionUpdated: function (ecModel) {},
\r
4962 getDefaultOption: function () {
\r
4963 if (!this.hasOwnProperty('__defaultOption')) {
\r
4965 var Class = this.constructor;
\r
4967 var opt = Class.prototype.defaultOption;
\r
4968 opt && optList.push(opt);
\r
4969 Class = Class.superClass;
\r
4972 var defaultOption = {};
\r
4973 for (var i = optList.length - 1; i >= 0; i--) {
\r
4974 defaultOption = zrUtil.merge(defaultOption, optList[i], true);
\r
4976 this.__defaultOption = defaultOption;
\r
4978 return this.__defaultOption;
\r
4983 // Reset ComponentModel.extend, add preConstruct.
\r
4984 clazzUtil.enableClassExtend(
\r
4986 function (option, parentModel, ecModel, extraOpt) {
\r
4987 // Set dependentModels, componentIndex, name, id, mainType, subType.
\r
4988 zrUtil.extend(this, extraOpt);
\r
4990 this.uid = componentUtil.getUID('componentModel');
\r
4992 // this.setReadOnly([
\r
4993 // 'type', 'id', 'uid', 'name', 'mainType', 'subType',
\r
4994 // 'dependentModels', 'componentIndex'
\r
4999 // Add capability of registerClass, getClass, hasClass, registerSubTypeDefaulter and so on.
\r
5000 clazzUtil.enableClassManagement(
\r
5001 ComponentModel, {registerWhenExtend: true}
\r
5003 componentUtil.enableSubTypeDefaulter(ComponentModel);
\r
5005 // Add capability of ComponentModel.topologicalTravel.
\r
5006 componentUtil.enableTopologicalTravel(ComponentModel, getDependencies);
\r
5008 function getDependencies(componentType) {
\r
5010 zrUtil.each(ComponentModel.getClassesByMainType(componentType), function (Clazz) {
\r
5011 arrayPush.apply(deps, Clazz.prototype.dependencies || []);
\r
5013 // Ensure main type
\r
5014 return zrUtil.map(deps, function (type) {
\r
5015 return clazzUtil.parseClassType(type).main;
\r
5019 zrUtil.mixin(ComponentModel, __webpack_require__(22));
\r
5021 module.exports = ComponentModel;
\r
5026 /***/ function(module, exports, __webpack_require__) {
\r
5030 var zrUtil = __webpack_require__(3);
\r
5031 var clazz = __webpack_require__(9);
\r
5033 var parseClassType = clazz.parseClassType;
\r
5037 var componentUtil = {};
\r
5039 var DELIMITER = '_';
\r
5043 * @param {string} type
\r
5044 * @return {string}
\r
5046 componentUtil.getUID = function (type) {
\r
5047 // Considering the case of crossing js context,
\r
5048 // use Math.random to make id as unique as possible.
\r
5049 return [(type || ''), base++, Math.random()].join(DELIMITER);
\r
5055 componentUtil.enableSubTypeDefaulter = function (entity) {
\r
5057 var subTypeDefaulters = {};
\r
5059 entity.registerSubTypeDefaulter = function (componentType, defaulter) {
\r
5060 componentType = parseClassType(componentType);
\r
5061 subTypeDefaulters[componentType.main] = defaulter;
\r
5064 entity.determineSubType = function (componentType, option) {
\r
5065 var type = option.type;
\r
5067 var componentTypeMain = parseClassType(componentType).main;
\r
5068 if (entity.hasSubTypes(componentType) && subTypeDefaulters[componentTypeMain]) {
\r
5069 type = subTypeDefaulters[componentTypeMain](option);
\r
5079 * Topological travel on Activity Network (Activity On Vertices).
\r
5080 * Dependencies is defined in Model.prototype.dependencies, like ['xAxis', 'yAxis'].
\r
5082 * If 'xAxis' or 'yAxis' is absent in componentTypeList, just ignore it in topology.
\r
5084 * If there is circle dependencey, Error will be thrown.
\r
5087 componentUtil.enableTopologicalTravel = function (entity, dependencyGetter) {
\r
5091 * @param {Array.<string>} targetNameList Target Component type list.
\r
5092 * Can be ['aa', 'bb', 'aa.xx']
\r
5093 * @param {Array.<string>} fullNameList By which we can build dependency graph.
\r
5094 * @param {Function} callback Params: componentType, dependencies.
\r
5095 * @param {Object} context Scope of callback.
\r
5097 entity.topologicalTravel = function (targetNameList, fullNameList, callback, context) {
\r
5098 if (!targetNameList.length) {
\r
5102 var result = makeDepndencyGraph(fullNameList);
\r
5103 var graph = result.graph;
\r
5104 var stack = result.noEntryList;
\r
5106 var targetNameSet = {};
\r
5107 zrUtil.each(targetNameList, function (name) {
\r
5108 targetNameSet[name] = true;
\r
5111 while (stack.length) {
\r
5112 var currComponentType = stack.pop();
\r
5113 var currVertex = graph[currComponentType];
\r
5114 var isInTargetNameSet = !!targetNameSet[currComponentType];
\r
5115 if (isInTargetNameSet) {
\r
5116 callback.call(context, currComponentType, currVertex.originalDeps.slice());
\r
5117 delete targetNameSet[currComponentType];
\r
5120 currVertex.successor,
\r
5121 isInTargetNameSet ? removeEdgeAndAdd : removeEdge
\r
5125 zrUtil.each(targetNameSet, function () {
\r
5126 throw new Error('Circle dependency may exists');
\r
5129 function removeEdge(succComponentType) {
\r
5130 graph[succComponentType].entryCount--;
\r
5131 if (graph[succComponentType].entryCount === 0) {
\r
5132 stack.push(succComponentType);
\r
5136 // Consider this case: legend depends on series, and we call
\r
5137 // chart.setOption({series: [...]}), where only series is in option.
\r
5138 // If we do not have 'removeEdgeAndAdd', legendModel.mergeOption will
\r
5139 // not be called, but only sereis.mergeOption is called. Thus legend
\r
5140 // have no chance to update its local record about series (like which
\r
5141 // name of series is available in legend).
\r
5142 function removeEdgeAndAdd(succComponentType) {
\r
5143 targetNameSet[succComponentType] = true;
\r
5144 removeEdge(succComponentType);
\r
5149 * DepndencyGraph: {Object}
\r
5150 * key: conponentType,
\r
5152 * successor: [conponentTypes...],
\r
5153 * originalDeps: [conponentTypes...],
\r
5154 * entryCount: {number}
\r
5157 function makeDepndencyGraph(fullNameList) {
\r
5159 var noEntryList = [];
\r
5161 zrUtil.each(fullNameList, function (name) {
\r
5163 var thisItem = createDependencyGraphItem(graph, name);
\r
5164 var originalDeps = thisItem.originalDeps = dependencyGetter(name);
\r
5166 var availableDeps = getAvailableDependencies(originalDeps, fullNameList);
\r
5167 thisItem.entryCount = availableDeps.length;
\r
5168 if (thisItem.entryCount === 0) {
\r
5169 noEntryList.push(name);
\r
5172 zrUtil.each(availableDeps, function (dependentName) {
\r
5173 if (zrUtil.indexOf(thisItem.predecessor, dependentName) < 0) {
\r
5174 thisItem.predecessor.push(dependentName);
\r
5176 var thatItem = createDependencyGraphItem(graph, dependentName);
\r
5177 if (zrUtil.indexOf(thatItem.successor, dependentName) < 0) {
\r
5178 thatItem.successor.push(name);
\r
5183 return {graph: graph, noEntryList: noEntryList};
\r
5186 function createDependencyGraphItem(graph, name) {
\r
5187 if (!graph[name]) {
\r
5188 graph[name] = {predecessor: [], successor: []};
\r
5190 return graph[name];
\r
5193 function getAvailableDependencies(originalDeps, fullNameList) {
\r
5194 var availableDeps = [];
\r
5195 zrUtil.each(originalDeps, function (dep) {
\r
5196 zrUtil.indexOf(fullNameList, dep) >= 0 && availableDeps.push(dep);
\r
5198 return availableDeps;
\r
5202 module.exports = componentUtil;
\r
5207 /***/ function(module, exports, __webpack_require__) {
\r
5210 // Layout helpers for each component positioning
\r
5213 var zrUtil = __webpack_require__(3);
\r
5214 var BoundingRect = __webpack_require__(15);
\r
5215 var numberUtil = __webpack_require__(7);
\r
5216 var formatUtil = __webpack_require__(6);
\r
5217 var parsePercent = numberUtil.parsePercent;
\r
5218 var each = zrUtil.each;
\r
5222 var LOCATION_PARAMS = ['left', 'right', 'top', 'bottom', 'width', 'height'];
\r
5224 function boxLayout(orient, group, gap, maxWidth, maxHeight) {
\r
5227 if (maxWidth == null) {
\r
5228 maxWidth = Infinity;
\r
5230 if (maxHeight == null) {
\r
5231 maxHeight = Infinity;
\r
5233 var currentLineMaxSize = 0;
\r
5234 group.eachChild(function (child, idx) {
\r
5235 var position = child.position;
\r
5236 var rect = child.getBoundingRect();
\r
5237 var nextChild = group.childAt(idx + 1);
\r
5238 var nextChildRect = nextChild && nextChild.getBoundingRect();
\r
5241 if (orient === 'horizontal') {
\r
5242 var moveX = rect.width + (nextChildRect ? (-nextChildRect.x + rect.x) : 0);
\r
5243 nextX = x + moveX;
\r
5244 // Wrap when width exceeds maxWidth or meet a `newline` group
\r
5245 if (nextX > maxWidth || child.newline) {
\r
5248 y += currentLineMaxSize + gap;
\r
5249 currentLineMaxSize = rect.height;
\r
5252 currentLineMaxSize = Math.max(currentLineMaxSize, rect.height);
\r
5256 var moveY = rect.height + (nextChildRect ? (-nextChildRect.y + rect.y) : 0);
\r
5257 nextY = y + moveY;
\r
5258 // Wrap when width exceeds maxHeight or meet a `newline` group
\r
5259 if (nextY > maxHeight || child.newline) {
\r
5260 x += currentLineMaxSize + gap;
\r
5263 currentLineMaxSize = rect.width;
\r
5266 currentLineMaxSize = Math.max(currentLineMaxSize, rect.width);
\r
5270 if (child.newline) {
\r
5277 orient === 'horizontal'
\r
5278 ? (x = nextX + gap)
\r
5279 : (y = nextY + gap);
\r
5284 * VBox or HBox layouting
\r
5285 * @param {string} orient
\r
5286 * @param {module:zrender/container/Group} group
\r
5287 * @param {number} gap
\r
5288 * @param {number} [width=Infinity]
\r
5289 * @param {number} [height=Infinity]
\r
5291 layout.box = boxLayout;
\r
5295 * @param {module:zrender/container/Group} group
\r
5296 * @param {number} gap
\r
5297 * @param {number} [width=Infinity]
\r
5298 * @param {number} [height=Infinity]
\r
5300 layout.vbox = zrUtil.curry(boxLayout, 'vertical');
\r
5304 * @param {module:zrender/container/Group} group
\r
5305 * @param {number} gap
\r
5306 * @param {number} [width=Infinity]
\r
5307 * @param {number} [height=Infinity]
\r
5309 layout.hbox = zrUtil.curry(boxLayout, 'horizontal');
\r
5312 * If x or x2 is not specified or 'center' 'left' 'right',
\r
5313 * the width would be as long as possible.
\r
5314 * If y or y2 is not specified or 'middle' 'top' 'bottom',
\r
5315 * the height would be as long as possible.
\r
5317 * @param {Object} positionInfo
\r
5318 * @param {number|string} [positionInfo.x]
\r
5319 * @param {number|string} [positionInfo.y]
\r
5320 * @param {number|string} [positionInfo.x2]
\r
5321 * @param {number|string} [positionInfo.y2]
\r
5322 * @param {Object} containerRect
\r
5323 * @param {string|number} margin
\r
5324 * @return {Object} {width, height}
\r
5326 layout.getAvailableSize = function (positionInfo, containerRect, margin) {
\r
5327 var containerWidth = containerRect.width;
\r
5328 var containerHeight = containerRect.height;
\r
5330 var x = parsePercent(positionInfo.x, containerWidth);
\r
5331 var y = parsePercent(positionInfo.y, containerHeight);
\r
5332 var x2 = parsePercent(positionInfo.x2, containerWidth);
\r
5333 var y2 = parsePercent(positionInfo.y2, containerHeight);
\r
5335 (isNaN(x) || isNaN(parseFloat(positionInfo.x))) && (x = 0);
\r
5336 (isNaN(x2) || isNaN(parseFloat(positionInfo.x2))) && (x2 = containerWidth);
\r
5337 (isNaN(y) || isNaN(parseFloat(positionInfo.y))) && (y = 0);
\r
5338 (isNaN(y2) || isNaN(parseFloat(positionInfo.y2))) && (y2 = containerHeight);
\r
5340 margin = formatUtil.normalizeCssArray(margin || 0);
\r
5343 width: Math.max(x2 - x - margin[1] - margin[3], 0),
\r
5344 height: Math.max(y2 - y - margin[0] - margin[2], 0)
\r
5349 * Parse position info.
\r
5351 * @param {Object} positionInfo
\r
5352 * @param {number|string} [positionInfo.left]
\r
5353 * @param {number|string} [positionInfo.top]
\r
5354 * @param {number|string} [positionInfo.right]
\r
5355 * @param {number|string} [positionInfo.bottom]
\r
5356 * @param {number|string} [positionInfo.width]
\r
5357 * @param {number|string} [positionInfo.height]
\r
5358 * @param {number|string} [positionInfo.aspect] Aspect is width / height
\r
5359 * @param {Object} containerRect
\r
5360 * @param {string|number} [margin]
\r
5362 * @return {module:zrender/core/BoundingRect}
\r
5364 layout.getLayoutRect = function (
\r
5365 positionInfo, containerRect, margin
\r
5367 margin = formatUtil.normalizeCssArray(margin || 0);
\r
5369 var containerWidth = containerRect.width;
\r
5370 var containerHeight = containerRect.height;
\r
5372 var left = parsePercent(positionInfo.left, containerWidth);
\r
5373 var top = parsePercent(positionInfo.top, containerHeight);
\r
5374 var right = parsePercent(positionInfo.right, containerWidth);
\r
5375 var bottom = parsePercent(positionInfo.bottom, containerHeight);
\r
5376 var width = parsePercent(positionInfo.width, containerWidth);
\r
5377 var height = parsePercent(positionInfo.height, containerHeight);
\r
5379 var verticalMargin = margin[2] + margin[0];
\r
5380 var horizontalMargin = margin[1] + margin[3];
\r
5381 var aspect = positionInfo.aspect;
\r
5383 // If width is not specified, calculate width from left and right
\r
5384 if (isNaN(width)) {
\r
5385 width = containerWidth - right - horizontalMargin - left;
\r
5387 if (isNaN(height)) {
\r
5388 height = containerHeight - bottom - verticalMargin - top;
\r
5391 // If width and height are not given
\r
5392 // 1. Graph should not exceeds the container
\r
5393 // 2. Aspect must be keeped
\r
5394 // 3. Graph should take the space as more as possible
\r
5395 if (isNaN(width) && isNaN(height)) {
\r
5396 if (aspect > containerWidth / containerHeight) {
\r
5397 width = containerWidth * 0.8;
\r
5400 height = containerHeight * 0.8;
\r
5404 if (aspect != null) {
\r
5405 // Calculate width or height with given aspect
\r
5406 if (isNaN(width)) {
\r
5407 width = aspect * height;
\r
5409 if (isNaN(height)) {
\r
5410 height = width / aspect;
\r
5414 // If left is not specified, calculate left from right and width
\r
5415 if (isNaN(left)) {
\r
5416 left = containerWidth - right - width - horizontalMargin;
\r
5419 top = containerHeight - bottom - height - verticalMargin;
\r
5422 // Align left and top
\r
5423 switch (positionInfo.left || positionInfo.right) {
\r
5425 left = containerWidth / 2 - width / 2 - margin[3];
\r
5428 left = containerWidth - width - horizontalMargin;
\r
5431 switch (positionInfo.top || positionInfo.bottom) {
\r
5434 top = containerHeight / 2 - height / 2 - margin[0];
\r
5437 top = containerHeight - height - verticalMargin;
\r
5440 // If something is wrong and left, top, width, height are calculated as NaN
\r
5443 if (isNaN(width)) {
\r
5444 // Width may be NaN if only one value is given except width
\r
5445 width = containerWidth - left - (right || 0);
\r
5447 if (isNaN(height)) {
\r
5448 // Height may be NaN if only one value is given except height
\r
5449 height = containerHeight - top - (bottom || 0);
\r
5452 var rect = new BoundingRect(left + margin[3], top + margin[0], width, height);
\r
5453 rect.margin = margin;
\r
5458 * Position group of component in viewport
\r
5459 * Group position is specified by either
\r
5460 * {left, top}, {right, bottom}
\r
5461 * If all properties exists, right and bottom will be igonred.
\r
5463 * @param {module:zrender/container/Group} group
\r
5464 * @param {Object} positionInfo
\r
5465 * @param {number|string} [positionInfo.left]
\r
5466 * @param {number|string} [positionInfo.top]
\r
5467 * @param {number|string} [positionInfo.right]
\r
5468 * @param {number|string} [positionInfo.bottom]
\r
5469 * @param {Object} containerRect
\r
5470 * @param {string|number} margin
\r
5472 layout.positionGroup = function (
\r
5473 group, positionInfo, containerRect, margin
\r
5475 var groupRect = group.getBoundingRect();
\r
5477 positionInfo = zrUtil.extend(zrUtil.clone(positionInfo), {
\r
5478 width: groupRect.width,
\r
5479 height: groupRect.height
\r
5482 positionInfo = layout.getLayoutRect(
\r
5483 positionInfo, containerRect, margin
\r
5486 group.position = [
\r
5487 positionInfo.x - groupRect.x,
\r
5488 positionInfo.y - groupRect.y
\r
5494 * When defulat option has {left: 0, width: 100}, and we set {right: 0}
\r
5495 * through setOption or media query, using normal zrUtil.merge will cause
\r
5496 * {right: 0} does not take effect.
\r
5499 * ComponentModel.extend({
\r
5500 * init: function () {
\r
5502 * var inputPositionParams = layout.getLayoutParams(option);
\r
5503 * this.mergeOption(inputPositionParams);
\r
5505 * mergeOption: function (newOption) {
\r
5506 * newOption && zrUtil.merge(thisOption, newOption, true);
\r
5507 * layout.mergeLayoutParam(thisOption, newOption);
\r
5511 * @param {Object} targetOption
\r
5512 * @param {Object} newOption
\r
5513 * @param {Object|string} [opt]
\r
5514 * @param {boolean} [opt.ignoreSize=false] Some component must has width and height.
\r
5516 layout.mergeLayoutParam = function (targetOption, newOption, opt) {
\r
5517 !zrUtil.isObject(opt) && (opt = {});
\r
5518 var hNames = ['width', 'left', 'right']; // Order by priority.
\r
5519 var vNames = ['height', 'top', 'bottom']; // Order by priority.
\r
5520 var hResult = merge(hNames);
\r
5521 var vResult = merge(vNames);
\r
5523 copy(hNames, targetOption, hResult);
\r
5524 copy(vNames, targetOption, vResult);
\r
5526 function merge(names) {
\r
5527 var newParams = {};
\r
5528 var newValueCount = 0;
\r
5530 var mergedValueCount = 0;
\r
5531 var enoughParamNumber = opt.ignoreSize ? 1 : 2;
\r
5533 each(names, function (name) {
\r
5534 merged[name] = targetOption[name];
\r
5536 each(names, function (name) {
\r
5537 // Consider case: newOption.width is null, which is
\r
5538 // set by user for removing width setting.
\r
5539 hasProp(newOption, name) && (newParams[name] = merged[name] = newOption[name]);
\r
5540 hasValue(newParams, name) && newValueCount++;
\r
5541 hasValue(merged, name) && mergedValueCount++;
\r
5544 // Case: newOption: {width: ..., right: ...},
\r
5545 // or targetOption: {right: ...} and newOption: {width: ...},
\r
5546 // There is no conflict when merged only has params count
\r
5547 // little than enoughParamNumber.
\r
5548 if (mergedValueCount === enoughParamNumber || !newValueCount) {
\r
5551 // Case: newOption: {width: ..., right: ...},
\r
5552 // Than we can make sure user only want those two, and ignore
\r
5553 // all origin params in targetOption.
\r
5554 else if (newValueCount >= enoughParamNumber) {
\r
5558 // Chose another param from targetOption by priority.
\r
5559 // When 'ignoreSize', enoughParamNumber is 1 and those will not happen.
\r
5560 for (var i = 0; i < names.length; i++) {
\r
5561 var name = names[i];
\r
5562 if (!hasProp(newParams, name) && hasProp(targetOption, name)) {
\r
5563 newParams[name] = targetOption[name];
\r
5571 function hasProp(obj, name) {
\r
5572 return obj.hasOwnProperty(name);
\r
5575 function hasValue(obj, name) {
\r
5576 return obj[name] != null && obj[name] !== 'auto';
\r
5579 function copy(names, target, source) {
\r
5580 each(names, function (name) {
\r
5581 target[name] = source[name];
\r
5587 * Retrieve 'left', 'right', 'top', 'bottom', 'width', 'height' from object.
\r
5588 * @param {Object} source
\r
5589 * @return {Object} Result contains those props.
\r
5591 layout.getLayoutParams = function (source) {
\r
5592 return layout.copyLayoutParams({}, source);
\r
5596 * Retrieve 'left', 'right', 'top', 'bottom', 'width', 'height' from object.
\r
5597 * @param {Object} source
\r
5598 * @return {Object} Result contains those props.
\r
5600 layout.copyLayoutParams = function (target, source) {
\r
5601 source && target && each(LOCATION_PARAMS, function (name) {
\r
5602 source.hasOwnProperty(name) && (target[name] = source[name]);
\r
5607 module.exports = layout;
\r
5612 /***/ function(module, exports) {
\r
5616 module.exports = {
\r
5617 getBoxLayoutParams: function () {
\r
5619 left: this.get('left'),
\r
5620 top: this.get('top'),
\r
5621 right: this.get('right'),
\r
5622 bottom: this.get('bottom'),
\r
5623 width: this.get('width'),
\r
5624 height: this.get('height')
\r
5632 /***/ function(module, exports) {
\r
5635 var platform = '';
\r
5636 // Navigator not exists in node
\r
5637 if (typeof navigator !== 'undefined') {
\r
5638 platform = navigator.platform || '';
\r
5640 module.exports = {
\r
5642 // backgroundColor: 'rgba(0,0,0,0)',
\r
5644 // https://dribbble.com/shots/1065960-Infographic-Pie-chart-visualization
\r
5645 // color: ['#5793f3', '#d14a61', '#fd9c35', '#675bba', '#fec42c', '#dd4444', '#d4df5a', '#cd4870'],
\r
5647 // color: ['#bcd3bb', '#e88f70', '#edc1a5', '#9dc5c8', '#e1e8c8', '#7b7c68', '#e5b5b5', '#f0b489', '#928ea8', '#bda29a'],
\r
5648 // color: ['#cc5664', '#9bd6ec', '#ea946e', '#8acaaa', '#f1ec64', '#ee8686', '#a48dc1', '#5da6bc', '#b9dcae'],
\r
5650 color: ['#c23531','#2f4554', '#61a0a8', '#d48265', '#91c7ae','#749f83', '#ca8622', '#bda29a','#6e7074', '#546570', '#c4ccd3'],
\r
5657 // decoration: 'none',
\r
5659 fontFamily: platform.match(/^Win/) ? 'Microsoft YaHei' : 'sans-serif',
\r
5660 // fontFamily: 'Arial, Verdana, sans-serif',
\r
5662 fontStyle: 'normal',
\r
5663 fontWeight: 'normal'
\r
5667 // 'circle', 'rectangle', 'triangle', 'diamond',
\r
5668 // 'emptyCircle', 'emptyRectangle', 'emptyTriangle', 'emptyDiamond'
\r
5670 animation: true, // 过渡动画是否开启
\r
5671 animationThreshold: 2000, // 动画元素阀值,产生的图形原素超过2000不出动画
\r
5672 animationDuration: 1000, // 过渡动画参数:进入
\r
5673 animationDurationUpdate: 300, // 过渡动画参数:更新
\r
5674 animationEasing: 'exponentialOut', //BounceOut
\r
5675 animationEasingUpdate: 'cubicOut'
\r
5681 /***/ function(module, exports, __webpack_require__) {
\r
5686 var zrUtil = __webpack_require__(3);
\r
5688 var echartsAPIList = [
\r
5689 'getDom', 'getZr', 'getWidth', 'getHeight', 'dispatchAction',
\r
5690 'on', 'off', 'getDataURL', 'getConnectedDataURL', 'getModel', 'getOption'
\r
5693 function ExtensionAPI(chartInstance) {
\r
5694 zrUtil.each(echartsAPIList, function (name) {
\r
5695 this[name] = zrUtil.bind(chartInstance[name], chartInstance);
\r
5699 module.exports = ExtensionAPI;
\r
5704 /***/ function(module, exports) {
\r
5709 // var zrUtil = require('zrender/lib/core/util');
\r
5710 var coordinateSystemCreators = {};
\r
5712 function CoordinateSystemManager() {
\r
5714 this._coordinateSystems = [];
\r
5717 CoordinateSystemManager.prototype = {
\r
5719 constructor: CoordinateSystemManager,
\r
5721 create: function (ecModel, api) {
\r
5722 var coordinateSystems = [];
\r
5723 for (var type in coordinateSystemCreators) {
\r
5724 var list = coordinateSystemCreators[type].create(ecModel, api);
\r
5725 list && (coordinateSystems = coordinateSystems.concat(list));
\r
5728 this._coordinateSystems = coordinateSystems;
\r
5731 update: function (ecModel, api) {
\r
5732 var coordinateSystems = this._coordinateSystems;
\r
5733 for (var i = 0; i < coordinateSystems.length; i++) {
\r
5734 // FIXME MUST have
\r
5735 coordinateSystems[i].update && coordinateSystems[i].update(ecModel, api);
\r
5740 CoordinateSystemManager.register = function (type, coordinateSystemCreator) {
\r
5741 coordinateSystemCreators[type] = coordinateSystemCreator;
\r
5744 CoordinateSystemManager.get = function (type) {
\r
5745 return coordinateSystemCreators[type];
\r
5748 module.exports = CoordinateSystemManager;
\r
5753 /***/ function(module, exports, __webpack_require__) {
\r
5756 * ECharts option manager
\r
5758 * @module {echarts/model/OptionManager}
\r
5763 var zrUtil = __webpack_require__(3);
\r
5764 var modelUtil = __webpack_require__(5);
\r
5765 var ComponentModel = __webpack_require__(19);
\r
5766 var each = zrUtil.each;
\r
5767 var clone = zrUtil.clone;
\r
5768 var map = zrUtil.map;
\r
5769 var merge = zrUtil.merge;
\r
5771 var QUERY_REG = /^(min|max)?(.+)$/;
\r
5774 * TERM EXPLANATIONS:
\r
5778 * An object that contains definitions of components. For example:
\r
5782 * visualMap: {...},
\r
5792 * An object input to echarts.setOption. 'rawOption' may be an
\r
5793 * 'option', or may be an object contains multi-options. For example:
\r
5804 * timeline: {...},
\r
5806 * {title: {...}, series: {data: [...]}},
\r
5807 * {title: {...}, series: {data: [...]}},
\r
5812 * query: {maxWidth: 320},
\r
5813 * option: {series: {x: 20}, visualMap: {show: false}}
\r
5816 * query: {minWidth: 320, maxWidth: 720},
\r
5817 * option: {series: {x: 500}, visualMap: {show: true}}
\r
5820 * option: {series: {x: 1200}, visualMap: {show: true}}
\r
5825 * @alias module:echarts/model/OptionManager
\r
5826 * @param {module:echarts/ExtensionAPI} api
\r
5828 function OptionManager(api) {
\r
5832 * @type {module:echarts/ExtensionAPI}
\r
5838 * @type {Array.<number>}
\r
5840 this._timelineOptions = [];
\r
5844 * @type {Array.<Object>}
\r
5846 this._mediaList = [];
\r
5852 this._mediaDefault;
\r
5855 * -1, means default.
\r
5856 * empty means no media.
\r
5858 * @type {Array.<number>}
\r
5860 this._currentMediaIndices = [];
\r
5866 this._optionBackup;
\r
5872 this._newOptionBackup;
\r
5875 // timeline.notMerge is not supported in ec3. Firstly there is rearly
\r
5876 // case that notMerge is needed. Secondly supporting 'notMerge' requires
\r
5877 // rawOption cloned and backuped when timeline changed, which does no
\r
5878 // good to performance. What's more, that both timeline and setOption
\r
5879 // method supply 'notMerge' brings complex and some problems.
\r
5880 // Consider this case:
\r
5881 // (step1) chart.setOption({timeline: {notMerge: false}, ...}, false);
\r
5882 // (step2) chart.setOption({timeline: {notMerge: true}, ...}, false);
\r
5884 OptionManager.prototype = {
\r
5886 constructor: OptionManager,
\r
5890 * @param {Object} rawOption Raw option.
\r
5891 * @param {module:echarts/model/Global} ecModel
\r
5892 * @param {Array.<Function>} optionPreprocessorFuncs
\r
5893 * @return {Object} Init option
\r
5895 setOption: function (rawOption, optionPreprocessorFuncs) {
\r
5896 rawOption = clone(rawOption, true);
\r
5899 // 如果 timeline options 或者 media 中设置了某个属性,而baseOption中没有设置,则进行警告。
\r
5901 var oldOptionBackup = this._optionBackup;
\r
5902 var newOptionBackup = this._newOptionBackup = parseRawOption.call(
\r
5903 this, rawOption, optionPreprocessorFuncs
\r
5906 // For setOption at second time (using merge mode);
\r
5907 if (oldOptionBackup) {
\r
5908 // Only baseOption can be merged.
\r
5909 mergeOption(oldOptionBackup.baseOption, newOptionBackup.baseOption);
\r
5911 if (newOptionBackup.timelineOptions.length) {
\r
5912 oldOptionBackup.timelineOptions = newOptionBackup.timelineOptions;
\r
5914 if (newOptionBackup.mediaList.length) {
\r
5915 oldOptionBackup.mediaList = newOptionBackup.mediaList;
\r
5917 if (newOptionBackup.mediaDefault) {
\r
5918 oldOptionBackup.mediaDefault = newOptionBackup.mediaDefault;
\r
5922 this._optionBackup = newOptionBackup;
\r
5927 * @param {boolean} isRecreate
\r
5928 * @return {Object}
\r
5930 mountOption: function (isRecreate) {
\r
5931 var optionBackup = isRecreate
\r
5932 // this._optionBackup can be only used when recreate.
\r
5933 // In other cases we use model.mergeOption to handle merge.
\r
5934 ? this._optionBackup : this._newOptionBackup;
\r
5937 // 如果没有reset功能则不clone。
\r
5939 this._timelineOptions = map(optionBackup.timelineOptions, clone);
\r
5940 this._mediaList = map(optionBackup.mediaList, clone);
\r
5941 this._mediaDefault = clone(optionBackup.mediaDefault);
\r
5942 this._currentMediaIndices = [];
\r
5944 return clone(optionBackup.baseOption);
\r
5948 * @param {module:echarts/model/Global} ecModel
\r
5949 * @return {Object}
\r
5951 getTimelineOption: function (ecModel) {
\r
5953 var timelineOptions = this._timelineOptions;
\r
5955 if (timelineOptions.length) {
\r
5956 // getTimelineOption can only be called after ecModel inited,
\r
5957 // so we can get currentIndex from timelineModel.
\r
5958 var timelineModel = ecModel.getComponent('timeline');
\r
5959 if (timelineModel) {
\r
5961 timelineOptions[timelineModel.getCurrentIndex()],
\r
5971 * @param {module:echarts/model/Global} ecModel
\r
5972 * @return {Array.<Object>}
\r
5974 getMediaOption: function (ecModel) {
\r
5975 var ecWidth = this._api.getWidth();
\r
5976 var ecHeight = this._api.getHeight();
\r
5977 var mediaList = this._mediaList;
\r
5978 var mediaDefault = this._mediaDefault;
\r
5982 // No media defined.
\r
5983 if (!mediaList.length && !mediaDefault) {
\r
5987 // Multi media may be applied, the latter defined media has higher priority.
\r
5988 for (var i = 0, len = mediaList.length; i < len; i++) {
\r
5989 if (applyMediaQuery(mediaList[i].query, ecWidth, ecHeight)) {
\r
5995 // 是否mediaDefault应该强制用户设置,否则可能修改不能回归。
\r
5996 if (!indices.length && mediaDefault) {
\r
6000 if (indices.length && !indicesEquals(indices, this._currentMediaIndices)) {
\r
6001 result = map(indices, function (index) {
\r
6003 index === -1 ? mediaDefault.option : mediaList[index].option
\r
6007 // Otherwise return nothing.
\r
6009 this._currentMediaIndices = indices;
\r
6015 function parseRawOption(rawOption, optionPreprocessorFuncs) {
\r
6016 var timelineOptions = [];
\r
6017 var mediaList = [];
\r
6021 // Compatible with ec2.
\r
6022 var timelineOpt = rawOption.timeline;
\r
6024 if (rawOption.baseOption) {
\r
6025 baseOption = rawOption.baseOption;
\r
6029 if (timelineOpt || rawOption.options) {
\r
6030 baseOption = baseOption || {};
\r
6031 timelineOptions = (rawOption.options || []).slice();
\r
6033 // For media query
\r
6034 if (rawOption.media) {
\r
6035 baseOption = baseOption || {};
\r
6036 var media = rawOption.media;
\r
6037 each(media, function (singleMedia) {
\r
6038 if (singleMedia && singleMedia.option) {
\r
6039 if (singleMedia.query) {
\r
6040 mediaList.push(singleMedia);
\r
6042 else if (!mediaDefault) {
\r
6043 // Use the first media default.
\r
6044 mediaDefault = singleMedia;
\r
6050 // For normal option
\r
6051 if (!baseOption) {
\r
6052 baseOption = rawOption;
\r
6055 // Set timelineOpt to baseOption in ec3,
\r
6056 // which is convenient for merge option.
\r
6057 if (!baseOption.timeline) {
\r
6058 baseOption.timeline = timelineOpt;
\r
6062 each([baseOption].concat(timelineOptions)
\r
6063 .concat(zrUtil.map(mediaList, function (media) {
\r
6064 return media.option;
\r
6066 function (option) {
\r
6067 each(optionPreprocessorFuncs, function (preProcess) {
\r
6068 preProcess(option);
\r
6074 baseOption: baseOption,
\r
6075 timelineOptions: timelineOptions,
\r
6076 mediaDefault: mediaDefault,
\r
6077 mediaList: mediaList
\r
6082 * @see <http://www.w3.org/TR/css3-mediaqueries/#media1>
\r
6083 * Support: width, height, aspectRatio
\r
6084 * Can use max or min as prefix.
\r
6086 function applyMediaQuery(query, ecWidth, ecHeight) {
\r
6090 aspectratio: ecWidth / ecHeight // lowser case for convenientce.
\r
6093 var applicatable = true;
\r
6095 zrUtil.each(query, function (value, attr) {
\r
6096 var matched = attr.match(QUERY_REG);
\r
6098 if (!matched || !matched[1] || !matched[2]) {
\r
6102 var operator = matched[1];
\r
6103 var realAttr = matched[2].toLowerCase();
\r
6105 if (!compare(realMap[realAttr], value, operator)) {
\r
6106 applicatable = false;
\r
6110 return applicatable;
\r
6113 function compare(real, expect, operator) {
\r
6114 if (operator === 'min') {
\r
6115 return real >= expect;
\r
6117 else if (operator === 'max') {
\r
6118 return real <= expect;
\r
6121 return real === expect;
\r
6125 function indicesEquals(indices1, indices2) {
\r
6126 // indices is always order by asc and has only finite number.
\r
6127 return indices1.join(',') === indices2.join(',');
\r
6132 * `chart.setOption(opt1);`
\r
6133 * Then user do some interaction like dataZoom, dataView changing.
\r
6134 * `chart.setOption(opt2);`
\r
6135 * Then user press 'reset button' in toolbox.
\r
6137 * After doing that all of the interaction effects should be reset, the
\r
6138 * chart should be the same as the result of invoke
\r
6139 * `chart.setOption(opt1); chart.setOption(opt2);`.
\r
6141 * Although it is not able ensure that
\r
6142 * `chart.setOption(opt1); chart.setOption(opt2);` is equivalents to
\r
6143 * `chart.setOption(merge(opt1, opt2));` exactly,
\r
6144 * this might be the only simple way to implement that feature.
\r
6146 * MEMO: We've considered some other approaches:
\r
6147 * 1. Each model handle its self restoration but not uniform treatment.
\r
6148 * (Too complex in logic and error-prone)
\r
6149 * 2. Use a shadow ecModel. (Performace expensive)
\r
6151 function mergeOption(oldOption, newOption) {
\r
6152 newOption = newOption || {};
\r
6154 each(newOption, function (newCptOpt, mainType) {
\r
6155 if (newCptOpt == null) {
\r
6159 var oldCptOpt = oldOption[mainType];
\r
6161 if (!ComponentModel.hasClass(mainType)) {
\r
6162 oldOption[mainType] = merge(oldCptOpt, newCptOpt, true);
\r
6165 newCptOpt = modelUtil.normalizeToArray(newCptOpt);
\r
6166 oldCptOpt = modelUtil.normalizeToArray(oldCptOpt);
\r
6168 var mapResult = modelUtil.mappingToExists(oldCptOpt, newCptOpt);
\r
6170 oldOption[mainType] = map(mapResult, function (item) {
\r
6171 return (item.option && item.exist)
\r
6172 ? merge(item.exist, item.option, true)
\r
6173 : (item.exist || item.option);
\r
6179 module.exports = OptionManager;
\r
6184 /***/ function(module, exports, __webpack_require__) {
\r
6189 var zrUtil = __webpack_require__(3);
\r
6190 var formatUtil = __webpack_require__(6);
\r
6191 var modelUtil = __webpack_require__(5);
\r
6192 var ComponentModel = __webpack_require__(19);
\r
6194 var encodeHTML = formatUtil.encodeHTML;
\r
6195 var addCommas = formatUtil.addCommas;
\r
6197 var SeriesModel = ComponentModel.extend({
\r
6199 type: 'series.__base__',
\r
6206 // coodinateSystem will be injected in the echarts/CoordinateSystem
\r
6207 coordinateSystem: null,
\r
6213 defaultOption: null,
\r
6216 * Data provided for legend
\r
6217 * @type {Function}
\r
6220 legendDataProvider: null,
\r
6222 init: function (option, parentModel, ecModel, extraOpt) {
\r
6228 this.seriesIndex = this.componentIndex;
\r
6230 this.mergeDefaultAndTheme(option, ecModel);
\r
6233 * @type {module:echarts/data/List|module:echarts/data/Tree|module:echarts/data/Graph}
\r
6236 this._dataBeforeProcessed = this.getInitialData(option, ecModel);
\r
6238 // When using module:echarts/data/Tree or module:echarts/data/Graph,
\r
6239 // cloneShallow will cause this._data.graph.data pointing to new data list.
\r
6240 // Wo we make this._dataBeforeProcessed first, and then make this._data.
\r
6241 this._data = this._dataBeforeProcessed.cloneShallow();
\r
6245 * Util for merge default and theme to option
\r
6246 * @param {Object} option
\r
6247 * @param {module:echarts/model/Global} ecModel
\r
6249 mergeDefaultAndTheme: function (option, ecModel) {
\r
6252 ecModel.getTheme().get(this.subType)
\r
6254 zrUtil.merge(option, this.getDefaultOption());
\r
6256 // Default label emphasis `position` and `show`
\r
6257 modelUtil.defaultEmphasis(
\r
6258 option.label, ['position', 'show', 'textStyle', 'distance', 'formatter']
\r
6261 // Default data label emphasis `position` and `show`
\r
6262 // FIXME Tree structure data ?
\r
6263 var data = option.data || [];
\r
6264 for (var i = 0; i < data.length; i++) {
\r
6265 if (data[i] && data[i].label) {
\r
6266 modelUtil.defaultEmphasis(
\r
6267 data[i].label, ['position', 'show', 'textStyle', 'distance', 'formatter']
\r
6273 mergeOption: function (newSeriesOption, ecModel) {
\r
6274 newSeriesOption = zrUtil.merge(this.option, newSeriesOption, true);
\r
6276 var data = this.getInitialData(newSeriesOption, ecModel);
\r
6277 // TODO Merge data?
\r
6279 this._data = data;
\r
6280 this._dataBeforeProcessed = data.cloneShallow();
\r
6285 * Init a data structure from data related option in series
\r
6286 * Must be overwritten
\r
6288 getInitialData: function () {},
\r
6291 * @return {module:echarts/data/List}
\r
6293 getData: function () {
\r
6294 return this._data;
\r
6298 * @param {module:echarts/data/List} data
\r
6300 setData: function (data) {
\r
6301 this._data = data;
\r
6305 * Get data before processed
\r
6306 * @return {module:echarts/data/List}
\r
6308 getRawData: function () {
\r
6309 return this._dataBeforeProcessed;
\r
6313 * Get raw data array given by user
\r
6314 * @return {Array.<Object>}
\r
6316 getRawDataArray: function () {
\r
6317 return this.option.data;
\r
6321 * Coord dimension to data dimension.
\r
6323 * By default the result is the same as dimensions of series data.
\r
6324 * But some series dimensions are different from coord dimensions (i.e.
\r
6325 * candlestick and boxplot). Override this method to handle those cases.
\r
6327 * Coord dimension to data dimension can be one-to-many
\r
6329 * @param {string} coordDim
\r
6330 * @return {Array.<string>} dimensions on the axis.
\r
6332 coordDimToDataDim: function (coordDim) {
\r
6333 return [coordDim];
\r
6337 * Convert data dimension to coord dimension.
\r
6339 * @param {string|number} dataDim
\r
6340 * @return {string}
\r
6342 dataDimToCoordDim: function (dataDim) {
\r
6347 * Get base axis if has coordinate system and has axis.
\r
6348 * By default use coordSys.getBaseAxis();
\r
6349 * Can be overrided for some chart.
\r
6350 * @return {type} description
\r
6352 getBaseAxis: function () {
\r
6353 var coordSys = this.coordinateSystem;
\r
6354 return coordSys && coordSys.getBaseAxis && coordSys.getBaseAxis();
\r
6359 * Default tooltip formatter
\r
6361 * @param {number} dataIndex
\r
6362 * @param {boolean} [multipleSeries=false]
\r
6364 formatTooltip: function (dataIndex, multipleSeries) {
\r
6365 var data = this._data;
\r
6366 var value = this.getRawValue(dataIndex);
\r
6367 var formattedValue = zrUtil.isArray(value)
\r
6368 ? zrUtil.map(value, addCommas).join(', ') : addCommas(value);
\r
6369 var name = data.getName(dataIndex);
\r
6370 var color = data.getItemVisual(dataIndex, 'color');
\r
6371 var colorEl = '<span style="display:inline-block;margin-right:5px;'
\r
6372 + 'border-radius:10px;width:9px;height:9px;background-color:' + color + '"></span>';
\r
6374 return !multipleSeries
\r
6375 ? (encodeHTML(this.name) + '<br />' + colorEl
\r
6377 ? encodeHTML(name) + ' : ' + formattedValue
\r
6380 : (colorEl + encodeHTML(this.name) + ' : ' + formattedValue);
\r
6383 restoreData: function () {
\r
6384 this._data = this._dataBeforeProcessed.cloneShallow();
\r
6388 zrUtil.mixin(SeriesModel, modelUtil.dataFormatMixin);
\r
6390 module.exports = SeriesModel;
\r
6395 /***/ function(module, exports, __webpack_require__) {
\r
6399 var Group = __webpack_require__(29);
\r
6400 var componentUtil = __webpack_require__(20);
\r
6401 var clazzUtil = __webpack_require__(9);
\r
6403 var Component = function () {
\r
6405 * @type {module:zrender/container/Group}
\r
6408 this.group = new Group();
\r
6414 this.uid = componentUtil.getUID('viewComponent');
\r
6417 Component.prototype = {
\r
6419 constructor: Component,
\r
6421 init: function (ecModel, api) {},
\r
6423 render: function (componentModel, ecModel, api, payload) {},
\r
6425 dispose: function () {}
\r
6428 var componentProto = Component.prototype;
\r
6429 componentProto.updateView
\r
6430 = componentProto.updateLayout
\r
6431 = componentProto.updateVisual
\r
6432 = function (seriesModel, ecModel, api, payload) {
\r
6435 // Enable Component.extend.
\r
6436 clazzUtil.enableClassExtend(Component);
\r
6438 // Enable capability of registerClass, getClass, hasClass, registerSubTypeDefaulter and so on.
\r
6439 clazzUtil.enableClassManagement(Component, {registerWhenExtend: true});
\r
6441 module.exports = Component;
\r
6446 /***/ function(module, exports, __webpack_require__) {
\r
6449 * Group是一个容器,可以插入子节点,Group的变换也会被应用到子节点上
\r
6450 * @module zrender/graphic/Group
\r
6452 * var Group = require('zrender/lib/container/Group');
\r
6453 * var Circle = require('zrender/lib/graphic/shape/Circle');
\r
6454 * var g = new Group();
\r
6455 * g.position[0] = 100;
\r
6456 * g.position[1] = 100;
\r
6457 * g.add(new Circle({
\r
6468 var zrUtil = __webpack_require__(3);
\r
6469 var Element = __webpack_require__(30);
\r
6470 var BoundingRect = __webpack_require__(15);
\r
6473 * @alias module:zrender/graphic/Group
\r
6475 * @extends module:zrender/mixin/Transformable
\r
6476 * @extends module:zrender/mixin/Eventful
\r
6478 var Group = function (opts) {
\r
6480 opts = opts || {};
\r
6482 Element.call(this, opts);
\r
6484 for (var key in opts) {
\r
6485 this[key] = opts[key];
\r
6488 this._children = [];
\r
6490 this.__storage = null;
\r
6492 this.__dirty = true;
\r
6495 Group.prototype = {
\r
6497 constructor: Group,
\r
6505 * @return {Array.<module:zrender/Element>}
\r
6507 children: function () {
\r
6508 return this._children.slice();
\r
6512 * 获取指定 index 的儿子节点
\r
6513 * @param {number} idx
\r
6514 * @return {module:zrender/Element}
\r
6516 childAt: function (idx) {
\r
6517 return this._children[idx];
\r
6522 * @param {string} name
\r
6523 * @return {module:zrender/Element}
\r
6525 childOfName: function (name) {
\r
6526 var children = this._children;
\r
6527 for (var i = 0; i < children.length; i++) {
\r
6528 if (children[i].name === name) {
\r
6529 return children[i];
\r
6535 * @return {number}
\r
6537 childCount: function () {
\r
6538 return this._children.length;
\r
6543 * @param {module:zrender/Element} child
\r
6545 add: function (child) {
\r
6546 if (child && child !== this && child.parent !== this) {
\r
6548 this._children.push(child);
\r
6550 this._doAdd(child);
\r
6557 * 添加子节点在 nextSibling 之前
\r
6558 * @param {module:zrender/Element} child
\r
6559 * @param {module:zrender/Element} nextSibling
\r
6561 addBefore: function (child, nextSibling) {
\r
6562 if (child && child !== this && child.parent !== this
\r
6563 && nextSibling && nextSibling.parent === this) {
\r
6565 var children = this._children;
\r
6566 var idx = children.indexOf(nextSibling);
\r
6569 children.splice(idx, 0, child);
\r
6570 this._doAdd(child);
\r
6577 _doAdd: function (child) {
\r
6578 if (child.parent) {
\r
6579 child.parent.remove(child);
\r
6582 child.parent = this;
\r
6584 var storage = this.__storage;
\r
6585 var zr = this.__zr;
\r
6586 if (storage && storage !== child.__storage) {
\r
6588 storage.addToMap(child);
\r
6590 if (child instanceof Group) {
\r
6591 child.addChildrenToStorage(storage);
\r
6595 zr && zr.refresh();
\r
6600 * @param {module:zrender/Element} child
\r
6602 remove: function (child) {
\r
6603 var zr = this.__zr;
\r
6604 var storage = this.__storage;
\r
6605 var children = this._children;
\r
6607 var idx = zrUtil.indexOf(children, child);
\r
6611 children.splice(idx, 1);
\r
6613 child.parent = null;
\r
6617 storage.delFromMap(child.id);
\r
6619 if (child instanceof Group) {
\r
6620 child.delChildrenFromStorage(storage);
\r
6624 zr && zr.refresh();
\r
6632 removeAll: function () {
\r
6633 var children = this._children;
\r
6634 var storage = this.__storage;
\r
6637 for (i = 0; i < children.length; i++) {
\r
6638 child = children[i];
\r
6640 storage.delFromMap(child.id);
\r
6641 if (child instanceof Group) {
\r
6642 child.delChildrenFromStorage(storage);
\r
6645 child.parent = null;
\r
6647 children.length = 0;
\r
6654 * @param {Function} cb
\r
6655 * @param {} context
\r
6657 eachChild: function (cb, context) {
\r
6658 var children = this._children;
\r
6659 for (var i = 0; i < children.length; i++) {
\r
6660 var child = children[i];
\r
6661 cb.call(context, child, i);
\r
6668 * @param {Function} cb
\r
6669 * @param {} context
\r
6671 traverse: function (cb, context) {
\r
6672 for (var i = 0; i < this._children.length; i++) {
\r
6673 var child = this._children[i];
\r
6674 cb.call(context, child);
\r
6676 if (child.type === 'group') {
\r
6677 child.traverse(cb, context);
\r
6683 addChildrenToStorage: function (storage) {
\r
6684 for (var i = 0; i < this._children.length; i++) {
\r
6685 var child = this._children[i];
\r
6686 storage.addToMap(child);
\r
6687 if (child instanceof Group) {
\r
6688 child.addChildrenToStorage(storage);
\r
6693 delChildrenFromStorage: function (storage) {
\r
6694 for (var i = 0; i < this._children.length; i++) {
\r
6695 var child = this._children[i];
\r
6696 storage.delFromMap(child.id);
\r
6697 if (child instanceof Group) {
\r
6698 child.delChildrenFromStorage(storage);
\r
6703 dirty: function () {
\r
6704 this.__dirty = true;
\r
6705 this.__zr && this.__zr.refresh();
\r
6710 * @return {module:zrender/core/BoundingRect}
\r
6712 getBoundingRect: function (includeChildren) {
\r
6716 var tmpRect = new BoundingRect(0, 0, 0, 0);
\r
6717 var children = includeChildren || this._children;
\r
6720 for (var i = 0; i < children.length; i++) {
\r
6721 var child = children[i];
\r
6722 if (child.ignore || child.invisible) {
\r
6726 var childRect = child.getBoundingRect();
\r
6727 var transform = child.getLocalTransform(tmpMat);
\r
6729 tmpRect.copy(childRect);
\r
6730 tmpRect.applyTransform(transform);
\r
6731 rect = rect || tmpRect.clone();
\r
6732 rect.union(tmpRect);
\r
6735 rect = rect || childRect.clone();
\r
6736 rect.union(childRect);
\r
6739 return rect || tmpRect;
\r
6743 zrUtil.inherits(Group, Element);
\r
6745 module.exports = Group;
\r
6750 /***/ function(module, exports, __webpack_require__) {
\r
6754 * @module zrender/Element
\r
6758 var guid = __webpack_require__(31);
\r
6759 var Eventful = __webpack_require__(32);
\r
6760 var Transformable = __webpack_require__(33);
\r
6761 var Animatable = __webpack_require__(34);
\r
6762 var zrUtil = __webpack_require__(3);
\r
6765 * @alias module:zrender/Element
\r
6767 * @extends {module:zrender/mixin/Animatable}
\r
6768 * @extends {module:zrender/mixin/Transformable}
\r
6769 * @extends {module:zrender/mixin/Eventful}
\r
6771 var Element = function (opts) {
\r
6773 Transformable.call(this, opts);
\r
6774 Eventful.call(this, opts);
\r
6775 Animatable.call(this, opts);
\r
6781 this.id = opts.id || guid();
\r
6784 Element.prototype = {
\r
6801 * ZRender 实例对象,会在 element 添加到 zrender 实例中后自动赋值
\r
6802 * ZRender instance will be assigned when element is associated with zrender
\r
6803 * @name module:/zrender/Element#__zr
\r
6804 * @type {module:zrender/ZRender}
\r
6809 * 图形是否忽略,为true时忽略图形的绘制以及事件触发
\r
6810 * If ignore drawing and events of the element object
\r
6811 * @name module:/zrender/Element#ignore
\r
6818 * 用于裁剪的路径(shape),所有 Group 内的路径在绘制时都会被这个路径裁剪
\r
6820 * @type {module:zrender/graphic/Path}
\r
6821 * @see http://www.w3.org/TR/2dcontext/#clipping-region
\r
6828 * @param {number} dx dx on the global space
\r
6829 * @param {number} dy dy on the global space
\r
6831 drift: function (dx, dy) {
\r
6832 switch (this.draggable) {
\r
6833 case 'horizontal':
\r
6841 var m = this.transform;
\r
6843 m = this.transform = [1, 0, 0, 1, 0, 0];
\r
6848 this.decomposeTransform();
\r
6853 * Hook before update
\r
6855 beforeUpdate: function () {},
\r
6857 * Hook after update
\r
6859 afterUpdate: function () {},
\r
6861 * Update each frame
\r
6863 update: function () {
\r
6864 this.updateTransform();
\r
6868 * @param {Function} cb
\r
6869 * @param {} context
\r
6871 traverse: function (cb, context) {},
\r
6876 attrKV: function (key, value) {
\r
6877 if (key === 'position' || key === 'scale' || key === 'origin') {
\r
6880 var target = this[key];
\r
6882 target = this[key] = [];
\r
6884 target[0] = value[0];
\r
6885 target[1] = value[1];
\r
6889 this[key] = value;
\r
6894 * Hide the element
\r
6896 hide: function () {
\r
6897 this.ignore = true;
\r
6898 this.__zr && this.__zr.refresh();
\r
6902 * Show the element
\r
6904 show: function () {
\r
6905 this.ignore = false;
\r
6906 this.__zr && this.__zr.refresh();
\r
6910 * @param {string|Object} key
\r
6911 * @param {*} value
\r
6913 attr: function (key, value) {
\r
6914 if (typeof key === 'string') {
\r
6915 this.attrKV(key, value);
\r
6917 else if (zrUtil.isObject(key)) {
\r
6918 for (var name in key) {
\r
6919 if (key.hasOwnProperty(name)) {
\r
6920 this.attrKV(name, key[name]);
\r
6930 * @param {module:zrender/graphic/Path} clipPath
\r
6932 setClipPath: function (clipPath) {
\r
6933 var zr = this.__zr;
\r
6935 clipPath.addSelfToZr(zr);
\r
6938 // Remove previous clip path
\r
6939 if (this.clipPath && this.clipPath !== clipPath) {
\r
6940 this.removeClipPath();
\r
6943 this.clipPath = clipPath;
\r
6944 clipPath.__zr = zr;
\r
6945 clipPath.__clipTarget = this;
\r
6952 removeClipPath: function () {
\r
6953 var clipPath = this.clipPath;
\r
6955 if (clipPath.__zr) {
\r
6956 clipPath.removeSelfFromZr(clipPath.__zr);
\r
6959 clipPath.__zr = null;
\r
6960 clipPath.__clipTarget = null;
\r
6961 this.clipPath = null;
\r
6968 * Add self from zrender instance.
\r
6969 * Not recursively because it will be invoked when element added to storage.
\r
6970 * @param {module:zrender/ZRender} zr
\r
6972 addSelfToZr: function (zr) {
\r
6975 var animators = this.animators;
\r
6977 for (var i = 0; i < animators.length; i++) {
\r
6978 zr.animation.addAnimator(animators[i]);
\r
6982 if (this.clipPath) {
\r
6983 this.clipPath.addSelfToZr(zr);
\r
6988 * Remove self from zrender instance.
\r
6989 * Not recursively because it will be invoked when element added to storage.
\r
6990 * @param {module:zrender/ZRender} zr
\r
6992 removeSelfFromZr: function (zr) {
\r
6995 var animators = this.animators;
\r
6997 for (var i = 0; i < animators.length; i++) {
\r
6998 zr.animation.removeAnimator(animators[i]);
\r
7002 if (this.clipPath) {
\r
7003 this.clipPath.removeSelfFromZr(zr);
\r
7008 zrUtil.mixin(Element, Animatable);
\r
7009 zrUtil.mixin(Element, Transformable);
\r
7010 zrUtil.mixin(Element, Eventful);
\r
7012 module.exports = Element;
\r
7017 /***/ function(module, exports) {
\r
7022 * @author errorrik (errorrik@gmail.com)
\r
7026 var idStart = 0x0907;
\r
7028 module.exports = function () {
\r
7029 return 'zr_' + (idStart++);
\r
7036 /***/ function(module, exports, __webpack_require__) {
\r
7040 * @module zrender/mixin/Eventful
\r
7041 * @author Kener (@Kener-林峰, kener.linfeng@gmail.com)
\r
7042 * pissang (https://www.github.com/pissang)
\r
7046 var arrySlice = Array.prototype.slice;
\r
7047 var zrUtil = __webpack_require__(3);
\r
7048 var indexOf = zrUtil.indexOf;
\r
7052 * @alias module:zrender/mixin/Eventful
\r
7055 var Eventful = function () {
\r
7056 this._$handlers = {};
\r
7059 Eventful.prototype = {
\r
7061 constructor: Eventful,
\r
7064 * 单次触发绑定,trigger后销毁
\r
7066 * @param {string} event 事件名
\r
7067 * @param {Function} handler 响应函数
\r
7068 * @param {Object} context
\r
7070 one: function (event, handler, context) {
\r
7071 var _h = this._$handlers;
\r
7073 if (!handler || !event) {
\r
7081 if (indexOf(_h[event], event) >= 0) {
\r
7088 ctx: context || this
\r
7096 * @param {string} event 事件名
\r
7097 * @param {Function} handler 事件处理函数
\r
7098 * @param {Object} [context]
\r
7100 on: function (event, handler, context) {
\r
7101 var _h = this._$handlers;
\r
7103 if (!handler || !event) {
\r
7114 ctx: context || this
\r
7122 * @param {string} event
\r
7123 * @return {boolean}
\r
7125 isSilent: function (event) {
\r
7126 var _h = this._$handlers;
\r
7127 return _h[event] && _h[event].length;
\r
7132 * @param {string} event 事件名
\r
7133 * @param {Function} [handler] 事件处理函数
\r
7135 off: function (event, handler) {
\r
7136 var _h = this._$handlers;
\r
7139 this._$handlers = {};
\r
7146 for (var i = 0, l = _h[event].length; i < l; i++) {
\r
7147 if (_h[event][i]['h'] != handler) {
\r
7148 newList.push(_h[event][i]);
\r
7151 _h[event] = newList;
\r
7154 if (_h[event] && _h[event].length === 0) {
\r
7168 * @param {string} type 事件类型
\r
7170 trigger: function (type) {
\r
7171 if (this._$handlers[type]) {
\r
7172 var args = arguments;
\r
7173 var argLen = args.length;
\r
7176 args = arrySlice.call(args, 1);
\r
7179 var _h = this._$handlers[type];
\r
7180 var len = _h.length;
\r
7181 for (var i = 0; i < len;) {
\r
7182 // Optimize advise from backbone
\r
7185 _h[i]['h'].call(_h[i]['ctx']);
\r
7188 _h[i]['h'].call(_h[i]['ctx'], args[1]);
\r
7191 _h[i]['h'].call(_h[i]['ctx'], args[1], args[2]);
\r
7194 // have more than 2 given arguments
\r
7195 _h[i]['h'].apply(_h[i]['ctx'], args);
\r
7199 if (_h[i]['one']) {
\r
7213 * 带有context的事件分发, 最后一个参数是事件回调的context
\r
7214 * @param {string} type 事件类型
\r
7216 triggerWithContext: function (type) {
\r
7217 if (this._$handlers[type]) {
\r
7218 var args = arguments;
\r
7219 var argLen = args.length;
\r
7222 args = arrySlice.call(args, 1, args.length - 1);
\r
7224 var ctx = args[args.length - 1];
\r
7226 var _h = this._$handlers[type];
\r
7227 var len = _h.length;
\r
7228 for (var i = 0; i < len;) {
\r
7229 // Optimize advise from backbone
\r
7232 _h[i]['h'].call(ctx);
\r
7235 _h[i]['h'].call(ctx, args[1]);
\r
7238 _h[i]['h'].call(ctx, args[1], args[2]);
\r
7241 // have more than 2 given arguments
\r
7242 _h[i]['h'].apply(ctx, args);
\r
7246 if (_h[i]['one']) {
\r
7260 // 对象可以通过 onxxxx 绑定事件
\r
7262 * @event module:zrender/mixin/Eventful#onclick
\r
7263 * @type {Function}
\r
7267 * @event module:zrender/mixin/Eventful#onmouseover
\r
7268 * @type {Function}
\r
7272 * @event module:zrender/mixin/Eventful#onmouseout
\r
7273 * @type {Function}
\r
7277 * @event module:zrender/mixin/Eventful#onmousemove
\r
7278 * @type {Function}
\r
7282 * @event module:zrender/mixin/Eventful#onmousewheel
\r
7283 * @type {Function}
\r
7287 * @event module:zrender/mixin/Eventful#onmousedown
\r
7288 * @type {Function}
\r
7292 * @event module:zrender/mixin/Eventful#onmouseup
\r
7293 * @type {Function}
\r
7297 * @event module:zrender/mixin/Eventful#ondragstart
\r
7298 * @type {Function}
\r
7302 * @event module:zrender/mixin/Eventful#ondragend
\r
7303 * @type {Function}
\r
7307 * @event module:zrender/mixin/Eventful#ondragenter
\r
7308 * @type {Function}
\r
7312 * @event module:zrender/mixin/Eventful#ondragleave
\r
7313 * @type {Function}
\r
7317 * @event module:zrender/mixin/Eventful#ondragover
\r
7318 * @type {Function}
\r
7322 * @event module:zrender/mixin/Eventful#ondrop
\r
7323 * @type {Function}
\r
7327 module.exports = Eventful;
\r
7333 /***/ function(module, exports, __webpack_require__) {
\r
7338 * @module zrender/mixin/Transformable
\r
7339 * @author pissang (https://www.github.com/pissang)
\r
7343 var matrix = __webpack_require__(17);
\r
7344 var vector = __webpack_require__(16);
\r
7345 var mIdentity = matrix.identity;
\r
7347 var EPSILON = 5e-5;
\r
7349 function isNotAroundZero(val) {
\r
7350 return val > EPSILON || val < -EPSILON;
\r
7354 * @alias module:zrender/mixin/Transformable
\r
7357 var Transformable = function (opts) {
\r
7358 opts = opts || {};
\r
7359 // If there are no given position, rotation, scale
\r
7360 if (!opts.position) {
\r
7363 * @type {Array.<number>}
\r
7366 this.position = [0, 0];
\r
7368 if (opts.rotation == null) {
\r
7371 * @type {Array.<number>}
\r
7374 this.rotation = 0;
\r
7376 if (!opts.scale) {
\r
7379 * @type {Array.<number>}
\r
7382 this.scale = [1, 1];
\r
7386 * @type {Array.<number>}
\r
7389 this.origin = this.origin || null;
\r
7392 var transformableProto = Transformable.prototype;
\r
7393 transformableProto.transform = null;
\r
7397 * 如果有坐标变换, 则从position, rotation, scale以及父节点的transform计算出自身的transform矩阵
\r
7399 transformableProto.needLocalTransform = function () {
\r
7400 return isNotAroundZero(this.rotation)
\r
7401 || isNotAroundZero(this.position[0])
\r
7402 || isNotAroundZero(this.position[1])
\r
7403 || isNotAroundZero(this.scale[0] - 1)
\r
7404 || isNotAroundZero(this.scale[1] - 1);
\r
7407 transformableProto.updateTransform = function () {
\r
7408 var parent = this.parent;
\r
7409 var parentHasTransform = parent && parent.transform;
\r
7410 var needLocalTransform = this.needLocalTransform();
\r
7412 var m = this.transform;
\r
7413 if (!(needLocalTransform || parentHasTransform)) {
\r
7414 m && mIdentity(m);
\r
7418 m = m || matrix.create();
\r
7420 if (needLocalTransform) {
\r
7421 this.getLocalTransform(m);
\r
7428 if (parentHasTransform) {
\r
7429 if (needLocalTransform) {
\r
7430 matrix.mul(m, parent.transform, m);
\r
7433 matrix.copy(m, parent.transform);
\r
7437 this.transform = m;
\r
7439 this.invTransform = this.invTransform || matrix.create();
\r
7440 matrix.invert(this.invTransform, m);
\r
7443 transformableProto.getLocalTransform = function (m) {
\r
7447 var origin = this.origin;
\r
7449 var scale = this.scale;
\r
7450 var rotation = this.rotation;
\r
7451 var position = this.position;
\r
7453 // Translate to origin
\r
7454 m[4] -= origin[0];
\r
7455 m[5] -= origin[1];
\r
7457 matrix.scale(m, m, scale);
\r
7459 matrix.rotate(m, m, rotation);
\r
7462 // Translate back from origin
\r
7463 m[4] += origin[0];
\r
7464 m[5] += origin[1];
\r
7467 m[4] += position[0];
\r
7468 m[5] += position[1];
\r
7473 * 将自己的transform应用到context上
\r
7474 * @param {Context2D} ctx
\r
7476 transformableProto.setTransform = function (ctx) {
\r
7477 var m = this.transform;
\r
7479 ctx.transform(m[0], m[1], m[2], m[3], m[4], m[5]);
\r
7483 var tmpTransform = [];
\r
7486 * 分解`transform`矩阵到`position`, `rotation`, `scale`
\r
7488 transformableProto.decomposeTransform = function () {
\r
7489 if (!this.transform) {
\r
7492 var parent = this.parent;
\r
7493 var m = this.transform;
\r
7494 if (parent && parent.transform) {
\r
7495 // Get local transform and decompose them to position, scale, rotation
\r
7496 matrix.mul(tmpTransform, parent.invTransform, m);
\r
7499 var sx = m[0] * m[0] + m[1] * m[1];
\r
7500 var sy = m[2] * m[2] + m[3] * m[3];
\r
7501 var position = this.position;
\r
7502 var scale = this.scale;
\r
7503 if (isNotAroundZero(sx - 1)) {
\r
7504 sx = Math.sqrt(sx);
\r
7506 if (isNotAroundZero(sy - 1)) {
\r
7507 sy = Math.sqrt(sy);
\r
7515 position[0] = m[4];
\r
7516 position[1] = m[5];
\r
7519 this.rotation = Math.atan2(-m[1] / sy, m[0] / sx);
\r
7523 * 变换坐标位置到 shape 的局部坐标空间
\r
7525 * @param {number} x
\r
7526 * @param {number} y
\r
7527 * @return {Array.<number>}
\r
7529 transformableProto.transformCoordToLocal = function (x, y) {
\r
7531 var invTransform = this.invTransform;
\r
7532 if (invTransform) {
\r
7533 vector.applyTransform(v2, v2, invTransform);
\r
7541 * @param {number} x
\r
7542 * @param {number} y
\r
7543 * @return {Array.<number>}
\r
7545 transformableProto.transformCoordToGlobal = function (x, y) {
\r
7547 var transform = this.transform;
\r
7549 vector.applyTransform(v2, v2, transform);
\r
7554 module.exports = Transformable;
\r
7560 /***/ function(module, exports, __webpack_require__) {
\r
7564 * @module zrender/mixin/Animatable
\r
7568 var Animator = __webpack_require__(35);
\r
7569 var util = __webpack_require__(3);
\r
7570 var isString = util.isString;
\r
7571 var isFunction = util.isFunction;
\r
7572 var isObject = util.isObject;
\r
7573 var log = __webpack_require__(39);
\r
7576 * @alias modue:zrender/mixin/Animatable
\r
7579 var Animatable = function () {
\r
7582 * @type {Array.<module:zrender/animation/Animator>}
\r
7585 this.animators = [];
\r
7588 Animatable.prototype = {
\r
7590 constructor: Animatable,
\r
7595 * @param {string} path 需要添加动画的属性获取路径,可以通过a.b.c来获取深层的属性
\r
7596 * @param {boolean} [loop] 动画是否循环
\r
7597 * @return {module:zrender/animation/Animator}
\r
7599 * el.animate('style', false)
\r
7600 * .when(1000, {x: 10} )
\r
7601 * .done(function(){ // Animation done })
\r
7604 animate: function (path, loop) {
\r
7606 var animatingShape = false;
\r
7608 var zr = this.__zr;
\r
7610 var pathSplitted = path.split('.');
\r
7612 // If animating shape
\r
7613 animatingShape = pathSplitted[0] === 'shape';
\r
7614 for (var i = 0, l = pathSplitted.length; i < l; i++) {
\r
7618 prop = prop[pathSplitted[i]];
\r
7632 + '" is not existed in element '
\r
7638 var animators = el.animators;
\r
7640 var animator = new Animator(target, loop);
\r
7642 animator.during(function (target) {
\r
7643 el.dirty(animatingShape);
\r
7645 .done(function () {
\r
7646 // FIXME Animator will not be removed if use `Animator#stop` to stop animation
\r
7647 animators.splice(util.indexOf(animators, animator), 1);
\r
7650 animators.push(animator);
\r
7652 // If animate after added to the zrender
\r
7654 zr.animation.addAnimator(animator);
\r
7662 * @param {boolean} forwardToLast If move to last frame before stop
\r
7664 stopAnimation: function (forwardToLast) {
\r
7665 var animators = this.animators;
\r
7666 var len = animators.length;
\r
7667 for (var i = 0; i < len; i++) {
\r
7668 animators[i].stop(forwardToLast);
\r
7670 animators.length = 0;
\r
7676 * @param {Object} target
\r
7677 * @param {number} [time=500] Time in ms
\r
7678 * @param {string} [easing='linear']
\r
7679 * @param {number} [delay=0]
\r
7680 * @param {Function} [callback]
\r
7683 * // Animate position
\r
7685 * position: [10, 10]
\r
7686 * }, function () { // done })
\r
7688 * // Animate shape, style and position in 100ms, delayed 100ms, with cubicOut easing
\r
7696 * position: [10, 10]
\r
7697 * }, 100, 100, 'cubicOut', function () { // done })
\r
7699 // TODO Return animation key
\r
7700 animateTo: function (target, time, delay, easing, callback) {
\r
7701 // animateTo(target, time, easing, callback);
\r
7702 if (isString(delay)) {
\r
7703 callback = easing;
\r
7707 // animateTo(target, time, delay, callback);
\r
7708 else if (isFunction(easing)) {
\r
7709 callback = easing;
\r
7710 easing = 'linear';
\r
7713 // animateTo(target, time, callback);
\r
7714 else if (isFunction(delay)) {
\r
7718 // animateTo(target, callback)
\r
7719 else if (isFunction(time)) {
\r
7723 // animateTo(target)
\r
7727 // Stop all previous animations
\r
7728 this.stopAnimation();
\r
7729 this._animateToShallow('', this, target, time, delay, easing, callback);
\r
7731 // Animators may be removed immediately after start
\r
7732 // if there is nothing to animate
\r
7733 var animators = this.animators.slice();
\r
7734 var count = animators.length;
\r
7738 callback && callback();
\r
7742 // No animators. This should be checked before animators[i].start(),
\r
7743 // because 'done' may be executed immediately if no need to animate.
\r
7745 callback && callback();
\r
7747 // Start after all animators created
\r
7748 // Incase any animator is done immediately when all animation properties are not changed
\r
7749 for (var i = 0; i < animators.length; i++) {
\r
7758 * @param {string} path=''
\r
7759 * @param {Object} source=this
\r
7760 * @param {Object} target
\r
7761 * @param {number} [time=500]
\r
7762 * @param {number} [delay=0]
\r
7765 * // Animate position
\r
7766 * el._animateToShallow({
\r
7767 * position: [10, 10]
\r
7770 * // Animate shape, style and position in 100ms, delayed 100ms
\r
7771 * el._animateToShallow({
\r
7778 * position: [10, 10]
\r
7781 _animateToShallow: function (path, source, target, time, delay) {
\r
7782 var objShallow = {};
\r
7783 var propertyCount = 0;
\r
7784 for (var name in target) {
\r
7785 if (source[name] != null) {
\r
7786 if (isObject(target[name]) && !util.isArrayLike(target[name])) {
\r
7787 this._animateToShallow(
\r
7788 path ? path + '.' + name : name,
\r
7796 objShallow[name] = target[name];
\r
7800 else if (target[name] != null) {
\r
7801 // Attr directly if not has property
\r
7802 // FIXME, if some property not needed for element ?
\r
7804 this.attr(name, target[name]);
\r
7806 else { // Shape or style
\r
7809 props[path][name] = target[name];
\r
7815 if (propertyCount > 0) {
\r
7816 this.animate(path, false)
\r
7817 .when(time == null ? 500 : time, objShallow)
\r
7818 .delay(delay || 0);
\r
7825 module.exports = Animatable;
\r
7830 /***/ function(module, exports, __webpack_require__) {
\r
7833 * @module echarts/animation/Animator
\r
7837 var Clip = __webpack_require__(36);
\r
7838 var color = __webpack_require__(38);
\r
7839 var util = __webpack_require__(3);
\r
7840 var isArrayLike = util.isArrayLike;
\r
7842 var arraySlice = Array.prototype.slice;
\r
7844 function defaultGetter(target, key) {
\r
7845 return target[key];
\r
7848 function defaultSetter(target, key, value) {
\r
7849 target[key] = value;
\r
7853 * @param {number} p0
\r
7854 * @param {number} p1
\r
7855 * @param {number} percent
\r
7856 * @return {number}
\r
7858 function interpolateNumber(p0, p1, percent) {
\r
7859 return (p1 - p0) * percent + p0;
\r
7863 * @param {string} p0
\r
7864 * @param {string} p1
\r
7865 * @param {number} percent
\r
7866 * @return {string}
\r
7868 function interpolateString(p0, p1, percent) {
\r
7869 return percent > 0.5 ? p1 : p0;
\r
7873 * @param {Array} p0
\r
7874 * @param {Array} p1
\r
7875 * @param {number} percent
\r
7876 * @param {Array} out
\r
7877 * @param {number} arrDim
\r
7879 function interpolateArray(p0, p1, percent, out, arrDim) {
\r
7880 var len = p0.length;
\r
7881 if (arrDim == 1) {
\r
7882 for (var i = 0; i < len; i++) {
\r
7883 out[i] = interpolateNumber(p0[i], p1[i], percent);
\r
7887 var len2 = p0[0].length;
\r
7888 for (var i = 0; i < len; i++) {
\r
7889 for (var j = 0; j < len2; j++) {
\r
7890 out[i][j] = interpolateNumber(
\r
7891 p0[i][j], p1[i][j], percent
\r
7898 function fillArr(arr0, arr1, arrDim) {
\r
7899 var arr0Len = arr0.length;
\r
7900 var arr1Len = arr1.length;
\r
7901 if (arr0Len === arr1Len) {
\r
7904 // FIXME Not work for TypedArray
\r
7905 var isPreviousLarger = arr0Len > arr1Len;
\r
7906 if (isPreviousLarger) {
\r
7907 // Cut the previous
\r
7908 arr0.length = arr1Len;
\r
7911 // Fill the previous
\r
7912 for (var i = arr0Len; i < arr1Len; i++) {
\r
7914 arrDim === 1 ? arr1[i] : arraySlice.call(arr1[i])
\r
7921 * @param {Array} arr0
\r
7922 * @param {Array} arr1
\r
7923 * @param {number} arrDim
\r
7924 * @return {boolean}
\r
7926 function isArraySame(arr0, arr1, arrDim) {
\r
7927 if (arr0 === arr1) {
\r
7930 var len = arr0.length;
\r
7931 if (len !== arr1.length) {
\r
7934 if (arrDim === 1) {
\r
7935 for (var i = 0; i < len; i++) {
\r
7936 if (arr0[i] !== arr1[i]) {
\r
7942 var len2 = arr0[0].length;
\r
7943 for (var i = 0; i < len; i++) {
\r
7944 for (var j = 0; j < len2; j++) {
\r
7945 if (arr0[i][j] !== arr1[i][j]) {
\r
7955 * Catmull Rom interpolate array
\r
7956 * @param {Array} p0
\r
7957 * @param {Array} p1
\r
7958 * @param {Array} p2
\r
7959 * @param {Array} p3
\r
7960 * @param {number} t
\r
7961 * @param {number} t2
\r
7962 * @param {number} t3
\r
7963 * @param {Array} out
\r
7964 * @param {number} arrDim
\r
7966 function catmullRomInterpolateArray(
\r
7967 p0, p1, p2, p3, t, t2, t3, out, arrDim
\r
7969 var len = p0.length;
\r
7970 if (arrDim == 1) {
\r
7971 for (var i = 0; i < len; i++) {
\r
7972 out[i] = catmullRomInterpolate(
\r
7973 p0[i], p1[i], p2[i], p3[i], t, t2, t3
\r
7978 var len2 = p0[0].length;
\r
7979 for (var i = 0; i < len; i++) {
\r
7980 for (var j = 0; j < len2; j++) {
\r
7981 out[i][j] = catmullRomInterpolate(
\r
7982 p0[i][j], p1[i][j], p2[i][j], p3[i][j],
\r
7991 * Catmull Rom interpolate number
\r
7992 * @param {number} p0
\r
7993 * @param {number} p1
\r
7994 * @param {number} p2
\r
7995 * @param {number} p3
\r
7996 * @param {number} t
\r
7997 * @param {number} t2
\r
7998 * @param {number} t3
\r
7999 * @return {number}
\r
8001 function catmullRomInterpolate(p0, p1, p2, p3, t, t2, t3) {
\r
8002 var v0 = (p2 - p0) * 0.5;
\r
8003 var v1 = (p3 - p1) * 0.5;
\r
8004 return (2 * (p1 - p2) + v0 + v1) * t3
\r
8005 + (-3 * (p1 - p2) - 2 * v0 - v1) * t2
\r
8009 function cloneValue(value) {
\r
8010 if (isArrayLike(value)) {
\r
8011 var len = value.length;
\r
8012 if (isArrayLike(value[0])) {
\r
8014 for (var i = 0; i < len; i++) {
\r
8015 ret.push(arraySlice.call(value[i]));
\r
8020 return arraySlice.call(value);
\r
8026 function rgba2String(rgba) {
\r
8027 rgba[0] = Math.floor(rgba[0]);
\r
8028 rgba[1] = Math.floor(rgba[1]);
\r
8029 rgba[2] = Math.floor(rgba[2]);
\r
8031 return 'rgba(' + rgba.join(',') + ')';
\r
8034 function createTrackClip (animator, easing, oneTrackDone, keyframes, propName) {
\r
8035 var getter = animator._getter;
\r
8036 var setter = animator._setter;
\r
8037 var useSpline = easing === 'spline';
\r
8039 var trackLen = keyframes.length;
\r
8043 // Guess data type
\r
8044 var firstVal = keyframes[0].value;
\r
8045 var isValueArray = isArrayLike(firstVal);
\r
8046 var isValueColor = false;
\r
8047 var isValueString = false;
\r
8049 // For vertices morphing
\r
8052 && isArrayLike(firstVal[0])
\r
8056 // Sort keyframe as ascending
\r
8057 keyframes.sort(function(a, b) {
\r
8058 return a.time - b.time;
\r
8061 trackMaxTime = keyframes[trackLen - 1].time;
\r
8062 // Percents of each keyframe
\r
8063 var kfPercents = [];
\r
8064 // Value of each keyframe
\r
8065 var kfValues = [];
\r
8066 var prevValue = keyframes[0].value;
\r
8067 var isAllValueEqual = true;
\r
8068 for (var i = 0; i < trackLen; i++) {
\r
8069 kfPercents.push(keyframes[i].time / trackMaxTime);
\r
8070 // Assume value is a color when it is a string
\r
8071 var value = keyframes[i].value;
\r
8073 // Check if value is equal, deep check if value is array
\r
8074 if (!((isValueArray && isArraySame(value, prevValue, arrDim))
\r
8075 || (!isValueArray && value === prevValue))) {
\r
8076 isAllValueEqual = false;
\r
8078 prevValue = value;
\r
8080 // Try converting a string to a color array
\r
8081 if (typeof value == 'string') {
\r
8082 var colorArray = color.parse(value);
\r
8084 value = colorArray;
\r
8085 isValueColor = true;
\r
8088 isValueString = true;
\r
8091 kfValues.push(value);
\r
8093 if (isAllValueEqual) {
\r
8097 if (isValueArray) {
\r
8098 var lastValue = kfValues[trackLen - 1];
\r
8100 for (var i = 0; i < trackLen - 1; i++) {
\r
8101 fillArr(kfValues[i], lastValue, arrDim);
\r
8103 fillArr(getter(animator._target, propName), lastValue, arrDim);
\r
8106 // Cache the key of last frame to speed up when
\r
8107 // animation playback is sequency
\r
8108 var lastFrame = 0;
\r
8109 var lastFramePercent = 0;
\r
8117 if (isValueColor) {
\r
8118 var rgba = [0, 0, 0, 0];
\r
8121 var onframe = function (target, percent) {
\r
8122 // Find the range keyframes
\r
8123 // kf1-----kf2---------current--------kf3
\r
8124 // find kf2 and kf3 and do interpolation
\r
8126 if (percent < lastFramePercent) {
\r
8127 // Start from next key
\r
8128 start = Math.min(lastFrame + 1, trackLen - 1);
\r
8129 for (frame = start; frame >= 0; frame--) {
\r
8130 if (kfPercents[frame] <= percent) {
\r
8134 frame = Math.min(frame, trackLen - 2);
\r
8137 for (frame = lastFrame; frame < trackLen; frame++) {
\r
8138 if (kfPercents[frame] > percent) {
\r
8142 frame = Math.min(frame - 1, trackLen - 2);
\r
8144 lastFrame = frame;
\r
8145 lastFramePercent = percent;
\r
8147 var range = (kfPercents[frame + 1] - kfPercents[frame]);
\r
8148 if (range === 0) {
\r
8152 w = (percent - kfPercents[frame]) / range;
\r
8155 p1 = kfValues[frame];
\r
8156 p0 = kfValues[frame === 0 ? frame : frame - 1];
\r
8157 p2 = kfValues[frame > trackLen - 2 ? trackLen - 1 : frame + 1];
\r
8158 p3 = kfValues[frame > trackLen - 3 ? trackLen - 1 : frame + 2];
\r
8159 if (isValueArray) {
\r
8160 catmullRomInterpolateArray(
\r
8161 p0, p1, p2, p3, w, w * w, w * w * w,
\r
8162 getter(target, propName),
\r
8168 if (isValueColor) {
\r
8169 value = catmullRomInterpolateArray(
\r
8170 p0, p1, p2, p3, w, w * w, w * w * w,
\r
8173 value = rgba2String(rgba);
\r
8175 else if (isValueString) {
\r
8176 // String is step(0.5)
\r
8177 return interpolateString(p1, p2, w);
\r
8180 value = catmullRomInterpolate(
\r
8181 p0, p1, p2, p3, w, w * w, w * w * w
\r
8192 if (isValueArray) {
\r
8194 kfValues[frame], kfValues[frame + 1], w,
\r
8195 getter(target, propName),
\r
8201 if (isValueColor) {
\r
8203 kfValues[frame], kfValues[frame + 1], w,
\r
8206 value = rgba2String(rgba);
\r
8208 else if (isValueString) {
\r
8209 // String is step(0.5)
\r
8210 return interpolateString(kfValues[frame], kfValues[frame + 1], w);
\r
8213 value = interpolateNumber(kfValues[frame], kfValues[frame + 1], w);
\r
8224 var clip = new Clip({
\r
8225 target: animator._target,
\r
8226 life: trackMaxTime,
\r
8227 loop: animator._loop,
\r
8228 delay: animator._delay,
\r
8230 ondestroy: oneTrackDone
\r
8233 if (easing && easing !== 'spline') {
\r
8234 clip.easing = easing;
\r
8241 * @alias module:zrender/animation/Animator
\r
8243 * @param {Object} target
\r
8244 * @param {boolean} loop
\r
8245 * @param {Function} getter
\r
8246 * @param {Function} setter
\r
8248 var Animator = function(target, loop, getter, setter) {
\r
8249 this._tracks = {};
\r
8250 this._target = target;
\r
8252 this._loop = loop || false;
\r
8254 this._getter = getter || defaultGetter;
\r
8255 this._setter = setter || defaultSetter;
\r
8257 this._clipCount = 0;
\r
8261 this._doneList = [];
\r
8263 this._onframeList = [];
\r
8265 this._clipList = [];
\r
8268 Animator.prototype = {
\r
8271 * @param {number} time 关键帧时间,单位是ms
\r
8272 * @param {Object} props 关键帧的属性值,key-value表示
\r
8273 * @return {module:zrender/animation/Animator}
\r
8275 when: function(time /* ms */, props) {
\r
8276 var tracks = this._tracks;
\r
8277 for (var propName in props) {
\r
8278 if (!tracks[propName]) {
\r
8279 tracks[propName] = [];
\r
8281 var value = this._getter(this._target, propName);
\r
8282 if (value == null) {
\r
8283 // zrLog('Invalid property ' + propName);
\r
8287 // Then props is given initialize value
\r
8289 // Initialize value from current prop value
\r
8291 tracks[propName].push({
\r
8293 value: cloneValue(value)
\r
8297 tracks[propName].push({
\r
8299 value: props[propName]
\r
8306 * @param {Function} callback
\r
8307 * @return {module:zrender/animation/Animator}
\r
8309 during: function (callback) {
\r
8310 this._onframeList.push(callback);
\r
8314 _doneCallback: function () {
\r
8315 // Clear all tracks
\r
8316 this._tracks = {};
\r
8317 // Clear all clips
\r
8318 this._clipList.length = 0;
\r
8320 var doneList = this._doneList;
\r
8321 var len = doneList.length;
\r
8322 for (var i = 0; i < len; i++) {
\r
8323 doneList[i].call(this);
\r
8328 * @param {string|Function} easing
\r
8329 * 动画缓动函数,详见{@link module:zrender/animation/easing}
\r
8330 * @return {module:zrender/animation/Animator}
\r
8332 start: function (easing) {
\r
8335 var clipCount = 0;
\r
8337 var oneTrackDone = function() {
\r
8340 self._doneCallback();
\r
8345 for (var propName in this._tracks) {
\r
8346 var clip = createTrackClip(
\r
8347 this, easing, oneTrackDone,
\r
8348 this._tracks[propName], propName
\r
8351 this._clipList.push(clip);
\r
8354 // If start after added to animation
\r
8355 if (this.animation) {
\r
8356 this.animation.addClip(clip);
\r
8363 // Add during callback on the last clip
\r
8365 var oldOnFrame = lastClip.onframe;
\r
8366 lastClip.onframe = function (target, percent) {
\r
8367 oldOnFrame(target, percent);
\r
8369 for (var i = 0; i < self._onframeList.length; i++) {
\r
8370 self._onframeList[i](target, percent);
\r
8376 this._doneCallback();
\r
8382 * @param {boolean} forwardToLast If move to last frame before stop
\r
8384 stop: function (forwardToLast) {
\r
8385 var clipList = this._clipList;
\r
8386 var animation = this.animation;
\r
8387 for (var i = 0; i < clipList.length; i++) {
\r
8388 var clip = clipList[i];
\r
8389 if (forwardToLast) {
\r
8390 // Move to last frame before stop
\r
8391 clip.onframe(this._target, 1);
\r
8393 animation && animation.removeClip(clip);
\r
8395 clipList.length = 0;
\r
8399 * @param {number} time 单位ms
\r
8400 * @return {module:zrender/animation/Animator}
\r
8402 delay: function (time) {
\r
8403 this._delay = time;
\r
8408 * @param {Function} cb
\r
8409 * @return {module:zrender/animation/Animator}
\r
8411 done: function(cb) {
\r
8413 this._doneList.push(cb);
\r
8419 * @return {Array.<module:zrender/animation/Clip>}
\r
8421 getClips: function () {
\r
8422 return this._clipList;
\r
8426 module.exports = Animator;
\r
8431 /***/ function(module, exports, __webpack_require__) {
\r
8435 * @config target 动画对象,可以是数组,如果是数组的话会批量分发onframe等事件
\r
8436 * @config life(1000) 动画时长
\r
8437 * @config delay(0) 动画延迟时间
\r
8438 * @config loop(true)
\r
8439 * @config gap(0) 循环的间隔时间
\r
8441 * @config easing(optional)
\r
8442 * @config ondestroy(optional)
\r
8443 * @config onrestart(optional)
\r
8449 var easingFuncs = __webpack_require__(37);
\r
8451 function Clip(options) {
\r
8453 this._target = options.target;
\r
8456 this._life = options.life || 1000;
\r
8458 this._delay = options.delay || 0;
\r
8460 // this._startTime = new Date().getTime() + this._delay;// 单位毫秒
\r
8461 this._initialized = false;
\r
8464 this.loop = options.loop == null ? false : options.loop;
\r
8466 this.gap = options.gap || 0;
\r
8468 this.easing = options.easing || 'Linear';
\r
8470 this.onframe = options.onframe;
\r
8471 this.ondestroy = options.ondestroy;
\r
8472 this.onrestart = options.onrestart;
\r
8475 Clip.prototype = {
\r
8477 constructor: Clip,
\r
8479 step: function (time) {
\r
8480 // Set startTime on first step, or _startTime may has milleseconds different between clips
\r
8482 if (!this._initialized) {
\r
8483 this._startTime = new Date().getTime() + this._delay;
\r
8484 this._initialized = true;
\r
8487 var percent = (time - this._startTime) / this._life;
\r
8490 if (percent < 0) {
\r
8494 percent = Math.min(percent, 1);
\r
8496 var easing = this.easing;
\r
8497 var easingFunc = typeof easing == 'string' ? easingFuncs[easing] : easing;
\r
8498 var schedule = typeof easingFunc === 'function'
\r
8499 ? easingFunc(percent)
\r
8502 this.fire('frame', schedule);
\r
8505 if (percent == 1) {
\r
8509 // 抛出而不是直接调用事件直到 stage.update 后再统一调用这些事件
\r
8513 // 动画完成将这个控制器标识为待删除
\r
8514 // 在Animation.update中进行批量删除
\r
8515 this._needsRemove = true;
\r
8522 restart: function() {
\r
8523 var time = new Date().getTime();
\r
8524 var remainder = (time - this._startTime) % this._life;
\r
8525 this._startTime = new Date().getTime() - remainder + this.gap;
\r
8527 this._needsRemove = false;
\r
8530 fire: function(eventType, arg) {
\r
8531 eventType = 'on' + eventType;
\r
8532 if (this[eventType]) {
\r
8533 this[eventType](this._target, arg);
\r
8538 module.exports = Clip;
\r
8544 /***/ function(module, exports) {
\r
8547 * 缓动代码来自 https://github.com/sole/tween.js/blob/master/src/Tween.js
\r
8548 * @see http://sole.github.io/tween.js/examples/03_graphs.html
\r
8549 * @exports zrender/animation/easing
\r
8554 * @param {number} k
\r
8555 * @return {number}
\r
8557 linear: function (k) {
\r
8562 * @param {number} k
\r
8563 * @return {number}
\r
8565 quadraticIn: function (k) {
\r
8569 * @param {number} k
\r
8570 * @return {number}
\r
8572 quadraticOut: function (k) {
\r
8573 return k * (2 - k);
\r
8576 * @param {number} k
\r
8577 * @return {number}
\r
8579 quadraticInOut: function (k) {
\r
8580 if ((k *= 2) < 1) {
\r
8581 return 0.5 * k * k;
\r
8583 return -0.5 * (--k * (k - 2) - 1);
\r
8588 * @param {number} k
\r
8589 * @return {number}
\r
8591 cubicIn: function (k) {
\r
8595 * @param {number} k
\r
8596 * @return {number}
\r
8598 cubicOut: function (k) {
\r
8599 return --k * k * k + 1;
\r
8602 * @param {number} k
\r
8603 * @return {number}
\r
8605 cubicInOut: function (k) {
\r
8606 if ((k *= 2) < 1) {
\r
8607 return 0.5 * k * k * k;
\r
8609 return 0.5 * ((k -= 2) * k * k + 2);
\r
8614 * @param {number} k
\r
8615 * @return {number}
\r
8617 quarticIn: function (k) {
\r
8618 return k * k * k * k;
\r
8621 * @param {number} k
\r
8622 * @return {number}
\r
8624 quarticOut: function (k) {
\r
8625 return 1 - (--k * k * k * k);
\r
8628 * @param {number} k
\r
8629 * @return {number}
\r
8631 quarticInOut: function (k) {
\r
8632 if ((k *= 2) < 1) {
\r
8633 return 0.5 * k * k * k * k;
\r
8635 return -0.5 * ((k -= 2) * k * k * k - 2);
\r
8640 * @param {number} k
\r
8641 * @return {number}
\r
8643 quinticIn: function (k) {
\r
8644 return k * k * k * k * k;
\r
8647 * @param {number} k
\r
8648 * @return {number}
\r
8650 quinticOut: function (k) {
\r
8651 return --k * k * k * k * k + 1;
\r
8654 * @param {number} k
\r
8655 * @return {number}
\r
8657 quinticInOut: function (k) {
\r
8658 if ((k *= 2) < 1) {
\r
8659 return 0.5 * k * k * k * k * k;
\r
8661 return 0.5 * ((k -= 2) * k * k * k * k + 2);
\r
8664 // 正弦曲线的缓动(sin(t))
\r
8666 * @param {number} k
\r
8667 * @return {number}
\r
8669 sinusoidalIn: function (k) {
\r
8670 return 1 - Math.cos(k * Math.PI / 2);
\r
8673 * @param {number} k
\r
8674 * @return {number}
\r
8676 sinusoidalOut: function (k) {
\r
8677 return Math.sin(k * Math.PI / 2);
\r
8680 * @param {number} k
\r
8681 * @return {number}
\r
8683 sinusoidalInOut: function (k) {
\r
8684 return 0.5 * (1 - Math.cos(Math.PI * k));
\r
8689 * @param {number} k
\r
8690 * @return {number}
\r
8692 exponentialIn: function (k) {
\r
8693 return k === 0 ? 0 : Math.pow(1024, k - 1);
\r
8696 * @param {number} k
\r
8697 * @return {number}
\r
8699 exponentialOut: function (k) {
\r
8700 return k === 1 ? 1 : 1 - Math.pow(2, -10 * k);
\r
8703 * @param {number} k
\r
8704 * @return {number}
\r
8706 exponentialInOut: function (k) {
\r
8713 if ((k *= 2) < 1) {
\r
8714 return 0.5 * Math.pow(1024, k - 1);
\r
8716 return 0.5 * (-Math.pow(2, -10 * (k - 1)) + 2);
\r
8719 // 圆形曲线的缓动(sqrt(1-t^2))
\r
8721 * @param {number} k
\r
8722 * @return {number}
\r
8724 circularIn: function (k) {
\r
8725 return 1 - Math.sqrt(1 - k * k);
\r
8728 * @param {number} k
\r
8729 * @return {number}
\r
8731 circularOut: function (k) {
\r
8732 return Math.sqrt(1 - (--k * k));
\r
8735 * @param {number} k
\r
8736 * @return {number}
\r
8738 circularInOut: function (k) {
\r
8739 if ((k *= 2) < 1) {
\r
8740 return -0.5 * (Math.sqrt(1 - k * k) - 1);
\r
8742 return 0.5 * (Math.sqrt(1 - (k -= 2) * k) + 1);
\r
8745 // 创建类似于弹簧在停止前来回振荡的动画
\r
8747 * @param {number} k
\r
8748 * @return {number}
\r
8750 elasticIn: function (k) {
\r
8760 if (!a || a < 1) {
\r
8764 s = p * Math.asin(1 / a) / (2 * Math.PI);
\r
8766 return -(a * Math.pow(2, 10 * (k -= 1)) *
\r
8767 Math.sin((k - s) * (2 * Math.PI) / p));
\r
8770 * @param {number} k
\r
8771 * @return {number}
\r
8773 elasticOut: function (k) {
\r
8783 if (!a || a < 1) {
\r
8787 s = p * Math.asin(1 / a) / (2 * Math.PI);
\r
8789 return (a * Math.pow(2, -10 * k) *
\r
8790 Math.sin((k - s) * (2 * Math.PI) / p) + 1);
\r
8793 * @param {number} k
\r
8794 * @return {number}
\r
8796 elasticInOut: function (k) {
\r
8806 if (!a || a < 1) {
\r
8810 s = p * Math.asin(1 / a) / (2 * Math.PI);
\r
8812 if ((k *= 2) < 1) {
\r
8813 return -0.5 * (a * Math.pow(2, 10 * (k -= 1))
\r
8814 * Math.sin((k - s) * (2 * Math.PI) / p));
\r
8816 return a * Math.pow(2, -10 * (k -= 1))
\r
8817 * Math.sin((k - s) * (2 * Math.PI) / p) * 0.5 + 1;
\r
8821 // 在某一动画开始沿指示的路径进行动画处理前稍稍收回该动画的移动
\r
8823 * @param {number} k
\r
8824 * @return {number}
\r
8826 backIn: function (k) {
\r
8828 return k * k * ((s + 1) * k - s);
\r
8831 * @param {number} k
\r
8832 * @return {number}
\r
8834 backOut: function (k) {
\r
8836 return --k * k * ((s + 1) * k + s) + 1;
\r
8839 * @param {number} k
\r
8840 * @return {number}
\r
8842 backInOut: function (k) {
\r
8843 var s = 1.70158 * 1.525;
\r
8844 if ((k *= 2) < 1) {
\r
8845 return 0.5 * (k * k * ((s + 1) * k - s));
\r
8847 return 0.5 * ((k -= 2) * k * ((s + 1) * k + s) + 2);
\r
8852 * @param {number} k
\r
8853 * @return {number}
\r
8855 bounceIn: function (k) {
\r
8856 return 1 - easing.bounceOut(1 - k);
\r
8859 * @param {number} k
\r
8860 * @return {number}
\r
8862 bounceOut: function (k) {
\r
8863 if (k < (1 / 2.75)) {
\r
8864 return 7.5625 * k * k;
\r
8866 else if (k < (2 / 2.75)) {
\r
8867 return 7.5625 * (k -= (1.5 / 2.75)) * k + 0.75;
\r
8869 else if (k < (2.5 / 2.75)) {
\r
8870 return 7.5625 * (k -= (2.25 / 2.75)) * k + 0.9375;
\r
8873 return 7.5625 * (k -= (2.625 / 2.75)) * k + 0.984375;
\r
8877 * @param {number} k
\r
8878 * @return {number}
\r
8880 bounceInOut: function (k) {
\r
8882 return easing.bounceIn(k * 2) * 0.5;
\r
8884 return easing.bounceOut(k * 2 - 1) * 0.5 + 0.5;
\r
8888 module.exports = easing;
\r
8895 /***/ function(module, exports) {
\r
8898 * @module zrender/tool/color
\r
8902 var kCSSColorTable = {
\r
8903 'transparent': [0,0,0,0], 'aliceblue': [240,248,255,1],
\r
8904 'antiquewhite': [250,235,215,1], 'aqua': [0,255,255,1],
\r
8905 'aquamarine': [127,255,212,1], 'azure': [240,255,255,1],
\r
8906 'beige': [245,245,220,1], 'bisque': [255,228,196,1],
\r
8907 'black': [0,0,0,1], 'blanchedalmond': [255,235,205,1],
\r
8908 'blue': [0,0,255,1], 'blueviolet': [138,43,226,1],
\r
8909 'brown': [165,42,42,1], 'burlywood': [222,184,135,1],
\r
8910 'cadetblue': [95,158,160,1], 'chartreuse': [127,255,0,1],
\r
8911 'chocolate': [210,105,30,1], 'coral': [255,127,80,1],
\r
8912 'cornflowerblue': [100,149,237,1], 'cornsilk': [255,248,220,1],
\r
8913 'crimson': [220,20,60,1], 'cyan': [0,255,255,1],
\r
8914 'darkblue': [0,0,139,1], 'darkcyan': [0,139,139,1],
\r
8915 'darkgoldenrod': [184,134,11,1], 'darkgray': [169,169,169,1],
\r
8916 'darkgreen': [0,100,0,1], 'darkgrey': [169,169,169,1],
\r
8917 'darkkhaki': [189,183,107,1], 'darkmagenta': [139,0,139,1],
\r
8918 'darkolivegreen': [85,107,47,1], 'darkorange': [255,140,0,1],
\r
8919 'darkorchid': [153,50,204,1], 'darkred': [139,0,0,1],
\r
8920 'darksalmon': [233,150,122,1], 'darkseagreen': [143,188,143,1],
\r
8921 'darkslateblue': [72,61,139,1], 'darkslategray': [47,79,79,1],
\r
8922 'darkslategrey': [47,79,79,1], 'darkturquoise': [0,206,209,1],
\r
8923 'darkviolet': [148,0,211,1], 'deeppink': [255,20,147,1],
\r
8924 'deepskyblue': [0,191,255,1], 'dimgray': [105,105,105,1],
\r
8925 'dimgrey': [105,105,105,1], 'dodgerblue': [30,144,255,1],
\r
8926 'firebrick': [178,34,34,1], 'floralwhite': [255,250,240,1],
\r
8927 'forestgreen': [34,139,34,1], 'fuchsia': [255,0,255,1],
\r
8928 'gainsboro': [220,220,220,1], 'ghostwhite': [248,248,255,1],
\r
8929 'gold': [255,215,0,1], 'goldenrod': [218,165,32,1],
\r
8930 'gray': [128,128,128,1], 'green': [0,128,0,1],
\r
8931 'greenyellow': [173,255,47,1], 'grey': [128,128,128,1],
\r
8932 'honeydew': [240,255,240,1], 'hotpink': [255,105,180,1],
\r
8933 'indianred': [205,92,92,1], 'indigo': [75,0,130,1],
\r
8934 'ivory': [255,255,240,1], 'khaki': [240,230,140,1],
\r
8935 'lavender': [230,230,250,1], 'lavenderblush': [255,240,245,1],
\r
8936 'lawngreen': [124,252,0,1], 'lemonchiffon': [255,250,205,1],
\r
8937 'lightblue': [173,216,230,1], 'lightcoral': [240,128,128,1],
\r
8938 'lightcyan': [224,255,255,1], 'lightgoldenrodyellow': [250,250,210,1],
\r
8939 'lightgray': [211,211,211,1], 'lightgreen': [144,238,144,1],
\r
8940 'lightgrey': [211,211,211,1], 'lightpink': [255,182,193,1],
\r
8941 'lightsalmon': [255,160,122,1], 'lightseagreen': [32,178,170,1],
\r
8942 'lightskyblue': [135,206,250,1], 'lightslategray': [119,136,153,1],
\r
8943 'lightslategrey': [119,136,153,1], 'lightsteelblue': [176,196,222,1],
\r
8944 'lightyellow': [255,255,224,1], 'lime': [0,255,0,1],
\r
8945 'limegreen': [50,205,50,1], 'linen': [250,240,230,1],
\r
8946 'magenta': [255,0,255,1], 'maroon': [128,0,0,1],
\r
8947 'mediumaquamarine': [102,205,170,1], 'mediumblue': [0,0,205,1],
\r
8948 'mediumorchid': [186,85,211,1], 'mediumpurple': [147,112,219,1],
\r
8949 'mediumseagreen': [60,179,113,1], 'mediumslateblue': [123,104,238,1],
\r
8950 'mediumspringgreen': [0,250,154,1], 'mediumturquoise': [72,209,204,1],
\r
8951 'mediumvioletred': [199,21,133,1], 'midnightblue': [25,25,112,1],
\r
8952 'mintcream': [245,255,250,1], 'mistyrose': [255,228,225,1],
\r
8953 'moccasin': [255,228,181,1], 'navajowhite': [255,222,173,1],
\r
8954 'navy': [0,0,128,1], 'oldlace': [253,245,230,1],
\r
8955 'olive': [128,128,0,1], 'olivedrab': [107,142,35,1],
\r
8956 'orange': [255,165,0,1], 'orangered': [255,69,0,1],
\r
8957 'orchid': [218,112,214,1], 'palegoldenrod': [238,232,170,1],
\r
8958 'palegreen': [152,251,152,1], 'paleturquoise': [175,238,238,1],
\r
8959 'palevioletred': [219,112,147,1], 'papayawhip': [255,239,213,1],
\r
8960 'peachpuff': [255,218,185,1], 'peru': [205,133,63,1],
\r
8961 'pink': [255,192,203,1], 'plum': [221,160,221,1],
\r
8962 'powderblue': [176,224,230,1], 'purple': [128,0,128,1],
\r
8963 'red': [255,0,0,1], 'rosybrown': [188,143,143,1],
\r
8964 'royalblue': [65,105,225,1], 'saddlebrown': [139,69,19,1],
\r
8965 'salmon': [250,128,114,1], 'sandybrown': [244,164,96,1],
\r
8966 'seagreen': [46,139,87,1], 'seashell': [255,245,238,1],
\r
8967 'sienna': [160,82,45,1], 'silver': [192,192,192,1],
\r
8968 'skyblue': [135,206,235,1], 'slateblue': [106,90,205,1],
\r
8969 'slategray': [112,128,144,1], 'slategrey': [112,128,144,1],
\r
8970 'snow': [255,250,250,1], 'springgreen': [0,255,127,1],
\r
8971 'steelblue': [70,130,180,1], 'tan': [210,180,140,1],
\r
8972 'teal': [0,128,128,1], 'thistle': [216,191,216,1],
\r
8973 'tomato': [255,99,71,1], 'turquoise': [64,224,208,1],
\r
8974 'violet': [238,130,238,1], 'wheat': [245,222,179,1],
\r
8975 'white': [255,255,255,1], 'whitesmoke': [245,245,245,1],
\r
8976 'yellow': [255,255,0,1], 'yellowgreen': [154,205,50,1]
\r
8979 function clampCssByte(i) { // Clamp to integer 0 .. 255.
\r
8980 i = Math.round(i); // Seems to be what Chrome does (vs truncation).
\r
8981 return i < 0 ? 0 : i > 255 ? 255 : i;
\r
8984 function clampCssAngle(i) { // Clamp to integer 0 .. 360.
\r
8985 i = Math.round(i); // Seems to be what Chrome does (vs truncation).
\r
8986 return i < 0 ? 0 : i > 360 ? 360 : i;
\r
8989 function clampCssFloat(f) { // Clamp to float 0.0 .. 1.0.
\r
8990 return f < 0 ? 0 : f > 1 ? 1 : f;
\r
8993 function parseCssInt(str) { // int or percentage.
\r
8994 if (str.length && str.charAt(str.length - 1) === '%') {
\r
8995 return clampCssByte(parseFloat(str) / 100 * 255);
\r
8997 return clampCssByte(parseInt(str, 10));
\r
9000 function parseCssFloat(str) { // float or percentage.
\r
9001 if (str.length && str.charAt(str.length - 1) === '%') {
\r
9002 return clampCssFloat(parseFloat(str) / 100);
\r
9004 return clampCssFloat(parseFloat(str));
\r
9007 function cssHueToRgb(m1, m2, h) {
\r
9016 return m1 + (m2 - m1) * h * 6;
\r
9022 return m1 + (m2 - m1) * (2/3 - h) * 6;
\r
9027 function lerp(a, b, p) {
\r
9028 return a + (b - a) * p;
\r
9032 * @param {string} colorStr
\r
9033 * @return {Array.<number>}
\r
9034 * @memberOf module:zrender/util/color
\r
9036 function parse(colorStr) {
\r
9040 // colorStr may be not string
\r
9041 colorStr = colorStr + '';
\r
9042 // Remove all whitespace, not compliant, but should just be more accepting.
\r
9043 var str = colorStr.replace(/ /g, '').toLowerCase();
\r
9045 // Color keywords (and transparent) lookup.
\r
9046 if (str in kCSSColorTable) {
\r
9047 return kCSSColorTable[str].slice(); // dup.
\r
9050 // #abc and #abc123 syntax.
\r
9051 if (str.charAt(0) === '#') {
\r
9052 if (str.length === 4) {
\r
9053 var iv = parseInt(str.substr(1), 16); // TODO(deanm): Stricter parsing.
\r
9054 if (!(iv >= 0 && iv <= 0xfff)) {
\r
9055 return; // Covers NaN.
\r
9058 ((iv & 0xf00) >> 4) | ((iv & 0xf00) >> 8),
\r
9059 (iv & 0xf0) | ((iv & 0xf0) >> 4),
\r
9060 (iv & 0xf) | ((iv & 0xf) << 4),
\r
9064 else if (str.length === 7) {
\r
9065 var iv = parseInt(str.substr(1), 16); // TODO(deanm): Stricter parsing.
\r
9066 if (!(iv >= 0 && iv <= 0xffffff)) {
\r
9067 return; // Covers NaN.
\r
9070 (iv & 0xff0000) >> 16,
\r
9071 (iv & 0xff00) >> 8,
\r
9079 var op = str.indexOf('('), ep = str.indexOf(')');
\r
9080 if (op !== -1 && ep + 1 === str.length) {
\r
9081 var fname = str.substr(0, op);
\r
9082 var params = str.substr(op + 1, ep - (op + 1)).split(',');
\r
9083 var alpha = 1; // To allow case fallthrough.
\r
9086 if (params.length !== 4) {
\r
9089 alpha = parseCssFloat(params.pop()); // jshint ignore:line
\r
9092 if (params.length !== 3) {
\r
9096 parseCssInt(params[0]),
\r
9097 parseCssInt(params[1]),
\r
9098 parseCssInt(params[2]),
\r
9102 if (params.length !== 4) {
\r
9105 params[3] = parseCssFloat(params[3]);
\r
9106 return hsla2rgba(params);
\r
9108 if (params.length !== 3) {
\r
9111 return hsla2rgba(params);
\r
9121 * @param {Array.<number>} hsla
\r
9122 * @return {Array.<number>} rgba
\r
9124 function hsla2rgba(hsla) {
\r
9125 var h = (((parseFloat(hsla[0]) % 360) + 360) % 360) / 360; // 0 .. 1
\r
9126 // NOTE(deanm): According to the CSS spec s/l should only be
\r
9127 // percentages, but we don't bother and let float or percentage.
\r
9128 var s = parseCssFloat(hsla[1]);
\r
9129 var l = parseCssFloat(hsla[2]);
\r
9130 var m2 = l <= 0.5 ? l * (s + 1) : l + s - l * s;
\r
9131 var m1 = l * 2 - m2;
\r
9134 clampCssByte(cssHueToRgb(m1, m2, h + 1 / 3) * 255),
\r
9135 clampCssByte(cssHueToRgb(m1, m2, h) * 255),
\r
9136 clampCssByte(cssHueToRgb(m1, m2, h - 1 / 3) * 255)
\r
9139 if (hsla.length === 4) {
\r
9140 rgba[3] = hsla[3];
\r
9147 * @param {Array.<number>} rgba
\r
9148 * @return {Array.<number>} hsla
\r
9150 function rgba2hsla(rgba) {
\r
9155 // RGB from 0 to 255
\r
9156 var R = rgba[0] / 255;
\r
9157 var G = rgba[1] / 255;
\r
9158 var B = rgba[2] / 255;
\r
9160 var vMin = Math.min(R, G, B); // Min. value of RGB
\r
9161 var vMax = Math.max(R, G, B); // Max. value of RGB
\r
9162 var delta = vMax - vMin; // Delta RGB value
\r
9164 var L = (vMax + vMin) / 2;
\r
9167 // HSL results from 0 to 1
\r
9168 if (delta === 0) {
\r
9174 S = delta / (vMax + vMin);
\r
9177 S = delta / (2 - vMax - vMin);
\r
9180 var deltaR = (((vMax - R) / 6) + (delta / 2)) / delta;
\r
9181 var deltaG = (((vMax - G) / 6) + (delta / 2)) / delta;
\r
9182 var deltaB = (((vMax - B) / 6) + (delta / 2)) / delta;
\r
9185 H = deltaB - deltaG;
\r
9187 else if (G === vMax) {
\r
9188 H = (1 / 3) + deltaR - deltaB;
\r
9190 else if (B === vMax) {
\r
9191 H = (2 / 3) + deltaG - deltaR;
\r
9203 var hsla = [H * 360, S, L];
\r
9205 if (rgba[3] != null) {
\r
9206 hsla.push(rgba[3]);
\r
9213 * @param {string} color
\r
9214 * @param {number} level
\r
9215 * @return {string}
\r
9216 * @memberOf module:zrender/util/color
\r
9218 function lift(color, level) {
\r
9219 var colorArr = parse(color);
\r
9221 for (var i = 0; i < 3; i++) {
\r
9223 colorArr[i] = colorArr[i] * (1 - level) | 0;
\r
9226 colorArr[i] = ((255 - colorArr[i]) * level + colorArr[i]) | 0;
\r
9229 return stringify(colorArr, colorArr.length === 4 ? 'rgba' : 'rgb');
\r
9234 * @param {string} color
\r
9235 * @return {string}
\r
9236 * @memberOf module:zrender/util/color
\r
9238 function toHex(color, level) {
\r
9239 var colorArr = parse(color);
\r
9241 return ((1 << 24) + (colorArr[0] << 16) + (colorArr[1] << 8) + (+colorArr[2])).toString(16).slice(1);
\r
9246 * Map value to color. Faster than mapToColor methods because color is represented by rgba array
\r
9247 * @param {number} normalizedValue A float between 0 and 1.
\r
9248 * @param {Array.<Array.<number>>} colors List of rgba color array
\r
9249 * @param {Array.<number>} [out] Mapped gba color array
\r
9250 * @return {Array.<number>}
\r
9252 function fastMapToColor(normalizedValue, colors, out) {
\r
9253 if (!(colors && colors.length)
\r
9254 || !(normalizedValue >= 0 && normalizedValue <= 1)
\r
9258 out = out || [0, 0, 0, 0];
\r
9259 var value = normalizedValue * (colors.length - 1);
\r
9260 var leftIndex = Math.floor(value);
\r
9261 var rightIndex = Math.ceil(value);
\r
9262 var leftColor = colors[leftIndex];
\r
9263 var rightColor = colors[rightIndex];
\r
9264 var dv = value - leftIndex;
\r
9265 out[0] = clampCssByte(lerp(leftColor[0], rightColor[0], dv));
\r
9266 out[1] = clampCssByte(lerp(leftColor[1], rightColor[1], dv));
\r
9267 out[2] = clampCssByte(lerp(leftColor[2], rightColor[2], dv));
\r
9268 out[3] = clampCssByte(lerp(leftColor[3], rightColor[3], dv));
\r
9272 * @param {number} normalizedValue A float between 0 and 1.
\r
9273 * @param {Array.<string>} colors Color list.
\r
9274 * @param {boolean=} fullOutput Default false.
\r
9275 * @return {(string|Object)} Result color. If fullOutput,
\r
9276 * return {color: ..., leftIndex: ..., rightIndex: ..., value: ...},
\r
9277 * @memberOf module:zrender/util/color
\r
9279 function mapToColor(normalizedValue, colors, fullOutput) {
\r
9280 if (!(colors && colors.length)
\r
9281 || !(normalizedValue >= 0 && normalizedValue <= 1)
\r
9286 var value = normalizedValue * (colors.length - 1);
\r
9287 var leftIndex = Math.floor(value);
\r
9288 var rightIndex = Math.ceil(value);
\r
9289 var leftColor = parse(colors[leftIndex]);
\r
9290 var rightColor = parse(colors[rightIndex]);
\r
9291 var dv = value - leftIndex;
\r
9293 var color = stringify(
\r
9295 clampCssByte(lerp(leftColor[0], rightColor[0], dv)),
\r
9296 clampCssByte(lerp(leftColor[1], rightColor[1], dv)),
\r
9297 clampCssByte(lerp(leftColor[2], rightColor[2], dv)),
\r
9298 clampCssFloat(lerp(leftColor[3], rightColor[3], dv))
\r
9306 leftIndex: leftIndex,
\r
9307 rightIndex: rightIndex,
\r
9314 * @param {Array<number>} interval Array length === 2,
\r
9315 * each item is normalized value ([0, 1]).
\r
9316 * @param {Array.<string>} colors Color list.
\r
9317 * @return {Array.<Object>} colors corresponding to the interval,
\r
9318 * each item is {color: 'xxx', offset: ...}
\r
9319 * where offset is between 0 and 1.
\r
9320 * @memberOf module:zrender/util/color
\r
9322 function mapIntervalToColor(interval, colors) {
\r
9323 if (interval.length !== 2 || interval[1] < interval[0]) {
\r
9327 var info0 = mapToColor(interval[0], colors, true);
\r
9328 var info1 = mapToColor(interval[1], colors, true);
\r
9330 var result = [{color: info0.color, offset: 0}];
\r
9332 var during = info1.value - info0.value;
\r
9333 var start = Math.max(info0.value, info0.rightIndex);
\r
9334 var end = Math.min(info1.value, info1.leftIndex);
\r
9336 for (var i = start; during > 0 && i <= end; i++) {
\r
9339 offset: (i - info0.value) / during
\r
9342 result.push({color: info1.color, offset: 1});
\r
9348 * @param {string} color
\r
9349 * @param {number=} h 0 ~ 360, ignore when null.
\r
9350 * @param {number=} s 0 ~ 1, ignore when null.
\r
9351 * @param {number=} l 0 ~ 1, ignore when null.
\r
9352 * @return {string} Color string in rgba format.
\r
9353 * @memberOf module:zrender/util/color
\r
9355 function modifyHSL(color, h, s, l) {
\r
9356 color = parse(color);
\r
9359 color = rgba2hsla(color);
\r
9360 h != null && (color[0] = clampCssAngle(h));
\r
9361 s != null && (color[1] = parseCssFloat(s));
\r
9362 l != null && (color[2] = parseCssFloat(l));
\r
9364 return stringify(hsla2rgba(color), 'rgba');
\r
9369 * @param {string} color
\r
9370 * @param {number=} alpha 0 ~ 1
\r
9371 * @return {string} Color string in rgba format.
\r
9372 * @memberOf module:zrender/util/color
\r
9374 function modifyAlpha(color, alpha) {
\r
9375 color = parse(color);
\r
9377 if (color && alpha != null) {
\r
9378 color[3] = clampCssFloat(alpha);
\r
9379 return stringify(color, 'rgba');
\r
9384 * @param {Array.<string>} colors Color list.
\r
9385 * @param {string} type 'rgba', 'hsva', ...
\r
9386 * @return {string} Result color.
\r
9388 function stringify(arrColor, type) {
\r
9389 if (type === 'rgb' || type === 'hsv' || type === 'hsl') {
\r
9390 arrColor = arrColor.slice(0, 3);
\r
9392 return type + '(' + arrColor.join(',') + ')';
\r
9395 module.exports = {
\r
9399 fastMapToColor: fastMapToColor,
\r
9400 mapToColor: mapToColor,
\r
9401 mapIntervalToColor: mapIntervalToColor,
\r
9402 modifyHSL: modifyHSL,
\r
9403 modifyAlpha: modifyAlpha,
\r
9404 stringify: stringify
\r
9412 /***/ function(module, exports, __webpack_require__) {
\r
9415 var config = __webpack_require__(40);
\r
9418 * @exports zrender/tool/log
\r
9419 * @author Kener (@Kener-林峰, kener.linfeng@gmail.com)
\r
9421 module.exports = function() {
\r
9422 if (config.debugMode === 0) {
\r
9425 else if (config.debugMode == 1) {
\r
9426 for (var k in arguments) {
\r
9427 throw new Error(arguments[k]);
\r
9430 else if (config.debugMode > 1) {
\r
9431 for (var k in arguments) {
\r
9432 console.log(arguments[k]);
\r
9438 return function(mes) {
\r
9439 document.getElementById('wrong-message').innerHTML =
\r
9440 mes + ' ' + (new Date() - 0)
\r
9442 + document.getElementById('wrong-message').innerHTML;
\r
9450 /***/ function(module, exports) {
\r
9454 // If in browser environment
\r
9455 if (typeof window !== 'undefined') {
\r
9456 dpr = Math.max(window.devicePixelRatio || 1, 1);
\r
9460 * @exports zrender/config
\r
9461 * @author Kener (@Kener-林峰, kener.linfeng@gmail.com)
\r
9465 * debug日志选项:catchBrushException为true下有效
\r
9466 * 0 : 不生成debug数据,发布用
\r
9473 devicePixelRatio: dpr
\r
9475 module.exports = config;
\r
9482 /***/ function(module, exports, __webpack_require__) {
\r
9486 var Group = __webpack_require__(29);
\r
9487 var componentUtil = __webpack_require__(20);
\r
9488 var clazzUtil = __webpack_require__(9);
\r
9490 function Chart() {
\r
9493 * @type {module:zrender/container/Group}
\r
9496 this.group = new Group();
\r
9502 this.uid = componentUtil.getUID('viewChart');
\r
9505 Chart.prototype = {
\r
9511 * @param {module:echarts/model/Global} ecModel
\r
9512 * @param {module:echarts/ExtensionAPI} api
\r
9514 init: function (ecModel, api) {},
\r
9517 * Render the chart
\r
9518 * @param {module:echarts/model/Series} seriesModel
\r
9519 * @param {module:echarts/model/Global} ecModel
\r
9520 * @param {module:echarts/ExtensionAPI} api
\r
9521 * @param {Object} payload
\r
9523 render: function (seriesModel, ecModel, api, payload) {},
\r
9526 * Highlight series or specified data item
\r
9527 * @param {module:echarts/model/Series} seriesModel
\r
9528 * @param {module:echarts/model/Global} ecModel
\r
9529 * @param {module:echarts/ExtensionAPI} api
\r
9530 * @param {Object} payload
\r
9532 highlight: function (seriesModel, ecModel, api, payload) {
\r
9533 toggleHighlight(seriesModel.getData(), payload, 'emphasis');
\r
9537 * Downplay series or specified data item
\r
9538 * @param {module:echarts/model/Series} seriesModel
\r
9539 * @param {module:echarts/model/Global} ecModel
\r
9540 * @param {module:echarts/ExtensionAPI} api
\r
9541 * @param {Object} payload
\r
9543 downplay: function (seriesModel, ecModel, api, payload) {
\r
9544 toggleHighlight(seriesModel.getData(), payload, 'normal');
\r
9549 * @param {module:echarts/model/Global} ecModel
\r
9550 * @param {module:echarts/ExtensionAPI} api
\r
9552 remove: function (ecModel, api) {
\r
9553 this.group.removeAll();
\r
9558 * @param {module:echarts/model/Global} ecModel
\r
9559 * @param {module:echarts/ExtensionAPI} api
\r
9561 dispose: function () {}
\r
9564 var chartProto = Chart.prototype;
\r
9565 chartProto.updateView
\r
9566 = chartProto.updateLayout
\r
9567 = chartProto.updateVisual
\r
9568 = function (seriesModel, ecModel, api, payload) {
\r
9569 this.render(seriesModel, ecModel, api, payload);
\r
9573 * Set state of single element
\r
9574 * @param {module:zrender/Element} el
\r
9575 * @param {string} state
\r
9577 function elSetState(el, state) {
\r
9579 el.trigger(state);
\r
9580 if (el.type === 'group') {
\r
9581 for (var i = 0; i < el.childCount(); i++) {
\r
9582 elSetState(el.childAt(i), state);
\r
9588 * @param {module:echarts/data/List} data
\r
9589 * @param {Object} payload
\r
9590 * @param {string} state 'normal'|'emphasis'
\r
9593 function toggleHighlight(data, payload, state) {
\r
9594 if (payload.dataIndex != null) {
\r
9595 var el = data.getItemGraphicEl(payload.dataIndex);
\r
9596 elSetState(el, state);
\r
9598 else if (payload.name) {
\r
9599 var dataIndex = data.indexOfName(payload.name);
\r
9600 var el = data.getItemGraphicEl(dataIndex);
\r
9601 elSetState(el, state);
\r
9604 data.eachItemGraphicEl(function (el) {
\r
9605 elSetState(el, state);
\r
9610 // Enable Chart.extend.
\r
9611 clazzUtil.enableClassExtend(Chart);
\r
9613 // Add capability of registerClass, getClass, hasClass, registerSubTypeDefaulter and so on.
\r
9614 clazzUtil.enableClassManagement(Chart, {registerWhenExtend: true});
\r
9616 module.exports = Chart;
\r
9621 /***/ function(module, exports, __webpack_require__) {
\r
9626 var zrUtil = __webpack_require__(3);
\r
9628 var pathTool = __webpack_require__(43);
\r
9629 var round = Math.round;
\r
9630 var Path = __webpack_require__(44);
\r
9631 var colorTool = __webpack_require__(38);
\r
9632 var matrix = __webpack_require__(17);
\r
9633 var vector = __webpack_require__(16);
\r
9634 var Gradient = __webpack_require__(4);
\r
9638 graphic.Group = __webpack_require__(29);
\r
9640 graphic.Image = __webpack_require__(59);
\r
9642 graphic.Text = __webpack_require__(62);
\r
9644 graphic.Circle = __webpack_require__(63);
\r
9646 graphic.Sector = __webpack_require__(64);
\r
9648 graphic.Ring = __webpack_require__(65);
\r
9650 graphic.Polygon = __webpack_require__(66);
\r
9652 graphic.Polyline = __webpack_require__(70);
\r
9654 graphic.Rect = __webpack_require__(71);
\r
9656 graphic.Line = __webpack_require__(72);
\r
9658 graphic.BezierCurve = __webpack_require__(73);
\r
9660 graphic.Arc = __webpack_require__(74);
\r
9662 graphic.LinearGradient = __webpack_require__(75);
\r
9664 graphic.RadialGradient = __webpack_require__(76);
\r
9666 graphic.BoundingRect = __webpack_require__(15);
\r
9669 * Extend shape with parameters
\r
9671 graphic.extendShape = function (opts) {
\r
9672 return Path.extend(opts);
\r
9678 graphic.extendPath = function (pathData, opts) {
\r
9679 return pathTool.extendFromString(pathData, opts);
\r
9683 * Create a path element from path data string
\r
9684 * @param {string} pathData
\r
9685 * @param {Object} opts
\r
9686 * @param {module:zrender/core/BoundingRect} rect
\r
9687 * @param {string} [layout=cover] 'center' or 'cover'
\r
9689 graphic.makePath = function (pathData, opts, rect, layout) {
\r
9690 var path = pathTool.createFromString(pathData, opts);
\r
9691 var boundingRect = path.getBoundingRect();
\r
9693 var aspect = boundingRect.width / boundingRect.height;
\r
9695 if (layout === 'center') {
\r
9696 // Set rect to center, keep width / height ratio.
\r
9697 var width = rect.height * aspect;
\r
9699 if (width <= rect.width) {
\r
9700 height = rect.height;
\r
9703 width = rect.width;
\r
9704 height = width / aspect;
\r
9706 var cx = rect.x + rect.width / 2;
\r
9707 var cy = rect.y + rect.height / 2;
\r
9709 rect.x = cx - width / 2;
\r
9710 rect.y = cy - height / 2;
\r
9711 rect.width = width;
\r
9712 rect.height = height;
\r
9715 this.resizePath(path, rect);
\r
9720 graphic.mergePath = pathTool.mergePath,
\r
9723 * Resize a path to fit the rect
\r
9724 * @param {module:zrender/graphic/Path} path
\r
9725 * @param {Object} rect
\r
9727 graphic.resizePath = function (path, rect) {
\r
9728 if (!path.applyTransform) {
\r
9732 var pathRect = path.getBoundingRect();
\r
9734 var m = pathRect.calculateTransform(rect);
\r
9736 path.applyTransform(m);
\r
9740 * Sub pixel optimize line for canvas
\r
9742 * @param {Object} param
\r
9743 * @param {Object} [param.shape]
\r
9744 * @param {number} [param.shape.x1]
\r
9745 * @param {number} [param.shape.y1]
\r
9746 * @param {number} [param.shape.x2]
\r
9747 * @param {number} [param.shape.y2]
\r
9748 * @param {Object} [param.style]
\r
9749 * @param {number} [param.style.lineWidth]
\r
9750 * @return {Object} Modified param
\r
9752 graphic.subPixelOptimizeLine = function (param) {
\r
9753 var subPixelOptimize = graphic.subPixelOptimize;
\r
9754 var shape = param.shape;
\r
9755 var lineWidth = param.style.lineWidth;
\r
9757 if (round(shape.x1 * 2) === round(shape.x2 * 2)) {
\r
9758 shape.x1 = shape.x2 = subPixelOptimize(shape.x1, lineWidth, true);
\r
9760 if (round(shape.y1 * 2) === round(shape.y2 * 2)) {
\r
9761 shape.y1 = shape.y2 = subPixelOptimize(shape.y1, lineWidth, true);
\r
9767 * Sub pixel optimize rect for canvas
\r
9769 * @param {Object} param
\r
9770 * @param {Object} [param.shape]
\r
9771 * @param {number} [param.shape.x]
\r
9772 * @param {number} [param.shape.y]
\r
9773 * @param {number} [param.shape.width]
\r
9774 * @param {number} [param.shape.height]
\r
9775 * @param {Object} [param.style]
\r
9776 * @param {number} [param.style.lineWidth]
\r
9777 * @return {Object} Modified param
\r
9779 graphic.subPixelOptimizeRect = function (param) {
\r
9780 var subPixelOptimize = graphic.subPixelOptimize;
\r
9781 var shape = param.shape;
\r
9782 var lineWidth = param.style.lineWidth;
\r
9783 var originX = shape.x;
\r
9784 var originY = shape.y;
\r
9785 var originWidth = shape.width;
\r
9786 var originHeight = shape.height;
\r
9787 shape.x = subPixelOptimize(shape.x, lineWidth, true);
\r
9788 shape.y = subPixelOptimize(shape.y, lineWidth, true);
\r
9789 shape.width = Math.max(
\r
9790 subPixelOptimize(originX + originWidth, lineWidth, false) - shape.x,
\r
9791 originWidth === 0 ? 0 : 1
\r
9793 shape.height = Math.max(
\r
9794 subPixelOptimize(originY + originHeight, lineWidth, false) - shape.y,
\r
9795 originHeight === 0 ? 0 : 1
\r
9801 * Sub pixel optimize for canvas
\r
9803 * @param {number} position Coordinate, such as x, y
\r
9804 * @param {number} lineWidth Should be nonnegative integer.
\r
9805 * @param {boolean=} positiveOrNegative Default false (negative).
\r
9806 * @return {number} Optimized position.
\r
9808 graphic.subPixelOptimize = function (position, lineWidth, positiveOrNegative) {
\r
9809 // Assure that (position + lineWidth / 2) is near integer edge,
\r
9810 // otherwise line will be fuzzy in canvas.
\r
9811 var doubledPosition = round(position * 2);
\r
9812 return (doubledPosition + round(lineWidth)) % 2 === 0
\r
9813 ? doubledPosition / 2
\r
9814 : (doubledPosition + (positiveOrNegative ? 1 : -1)) / 2;
\r
9820 function doSingleEnterHover(el) {
\r
9821 if (el.__isHover) {
\r
9824 if (el.__hoverStlDirty) {
\r
9825 var stroke = el.style.stroke;
\r
9826 var fill = el.style.fill;
\r
9828 // Create hoverStyle on mouseover
\r
9829 var hoverStyle = el.__hoverStl;
\r
9830 var lift = colorTool.lift;
\r
9831 hoverStyle.fill = hoverStyle.fill
\r
9832 || (fill && (fill instanceof Gradient ? fill : lift(fill, -0.1)));
\r
9833 hoverStyle.stroke = hoverStyle.stroke
\r
9834 || (stroke && (stroke instanceof Gradient ? stroke : lift(stroke, -0.1)));
\r
9836 var normalStyle = {};
\r
9837 for (var name in hoverStyle) {
\r
9838 if (hoverStyle.hasOwnProperty(name)) {
\r
9839 normalStyle[name] = el.style[name];
\r
9843 el.__normalStl = normalStyle;
\r
9845 el.__hoverStlDirty = false;
\r
9847 el.setStyle(el.__hoverStl);
\r
9850 el.__isHover = true;
\r
9856 function doSingleLeaveHover(el) {
\r
9857 if (!el.__isHover) {
\r
9861 var normalStl = el.__normalStl;
\r
9862 normalStl && el.setStyle(normalStl);
\r
9865 el.__isHover = false;
\r
9871 function doEnterHover(el) {
\r
9872 el.type === 'group'
\r
9873 ? el.traverse(function (child) {
\r
9874 if (child.type !== 'group') {
\r
9875 doSingleEnterHover(child);
\r
9878 : doSingleEnterHover(el);
\r
9881 function doLeaveHover(el) {
\r
9882 el.type === 'group'
\r
9883 ? el.traverse(function (child) {
\r
9884 if (child.type !== 'group') {
\r
9885 doSingleLeaveHover(child);
\r
9888 : doSingleLeaveHover(el);
\r
9894 function setElementHoverStl(el, hoverStl) {
\r
9895 // If element has sepcified hoverStyle, then use it instead of given hoverStyle
\r
9896 // Often used when item group has a label element and it's hoverStyle is different
\r
9897 el.__hoverStl = el.hoverStyle || hoverStl || {};
\r
9898 el.__hoverStlDirty = true;
\r
9904 function onElementMouseOver() {
\r
9905 // Only if element is not in emphasis status
\r
9906 !this.__isEmphasis && doEnterHover(this);
\r
9912 function onElementMouseOut() {
\r
9913 // Only if element is not in emphasis status
\r
9914 !this.__isEmphasis && doLeaveHover(this);
\r
9920 function enterEmphasis() {
\r
9921 this.__isEmphasis = true;
\r
9922 doEnterHover(this);
\r
9928 function leaveEmphasis() {
\r
9929 this.__isEmphasis = false;
\r
9930 doLeaveHover(this);
\r
9934 * Set hover style of element
\r
9935 * @param {module:zrender/Element} el
\r
9936 * @param {Object} [hoverStyle]
\r
9938 graphic.setHoverStyle = function (el, hoverStyle) {
\r
9939 el.type === 'group'
\r
9940 ? el.traverse(function (child) {
\r
9941 if (child.type !== 'group') {
\r
9942 setElementHoverStl(child, hoverStyle);
\r
9945 : setElementHoverStl(el, hoverStyle);
\r
9946 // Remove previous bound handlers
\r
9947 el.on('mouseover', onElementMouseOver)
\r
9948 .on('mouseout', onElementMouseOut);
\r
9950 // Emphasis, normal can be triggered manually
\r
9951 el.on('emphasis', enterEmphasis)
\r
9952 .on('normal', leaveEmphasis);
\r
9956 * Set text option in the style
\r
9957 * @param {Object} textStyle
\r
9958 * @param {module:echarts/model/Model} labelModel
\r
9959 * @param {string} color
\r
9961 graphic.setText = function (textStyle, labelModel, color) {
\r
9962 var labelPosition = labelModel.getShallow('position') || 'inside';
\r
9963 var labelColor = labelPosition.indexOf('inside') >= 0 ? 'white' : color;
\r
9964 var textStyleModel = labelModel.getModel('textStyle');
\r
9965 zrUtil.extend(textStyle, {
\r
9966 textDistance: labelModel.getShallow('distance') || 5,
\r
9967 textFont: textStyleModel.getFont(),
\r
9968 textPosition: labelPosition,
\r
9969 textFill: textStyleModel.getTextColor() || labelColor
\r
9973 function animateOrSetProps(isUpdate, el, props, animatableModel, cb) {
\r
9974 var postfix = isUpdate ? 'Update' : '';
\r
9975 var duration = animatableModel
\r
9976 && animatableModel.getShallow('animationDuration' + postfix);
\r
9977 var animationEasing = animatableModel
\r
9978 && animatableModel.getShallow('animationEasing' + postfix);
\r
9980 animatableModel && animatableModel.getShallow('animation')
\r
9981 ? el.animateTo(props, duration, animationEasing, cb)
\r
9982 : (el.attr(props), cb && cb());
\r
9985 * Update graphic element properties with or without animation according to the configuration in series
\r
9986 * @param {module:zrender/Element} el
\r
9987 * @param {Object} props
\r
9988 * @param {module:echarts/model/Model} [animatableModel]
\r
9989 * @param {Function} cb
\r
9991 graphic.updateProps = zrUtil.curry(animateOrSetProps, true);
\r
9994 * Init graphic element properties with or without animation according to the configuration in series
\r
9995 * @param {module:zrender/Element} el
\r
9996 * @param {Object} props
\r
9997 * @param {module:echarts/model/Model} [animatableModel]
\r
9998 * @param {Function} cb
\r
10000 graphic.initProps = zrUtil.curry(animateOrSetProps, false);
\r
10003 * Get transform matrix of target (param target),
\r
10004 * in coordinate of its ancestor (param ancestor)
\r
10006 * @param {module:zrender/mixin/Transformable} target
\r
10007 * @param {module:zrender/mixin/Transformable} ancestor
\r
10009 graphic.getTransform = function (target, ancestor) {
\r
10010 var mat = matrix.identity([]);
\r
10012 while (target && target !== ancestor) {
\r
10013 matrix.mul(mat, target.getLocalTransform(), mat);
\r
10014 target = target.parent;
\r
10021 * Apply transform to an vertex.
\r
10022 * @param {Array.<number>} vertex [x, y]
\r
10023 * @param {Array.<number>} transform Transform matrix: like [1, 0, 0, 1, 0, 0]
\r
10024 * @param {boolean=} invert Whether use invert matrix.
\r
10025 * @return {Array.<number>} [x, y]
\r
10027 graphic.applyTransform = function (vertex, transform, invert) {
\r
10029 transform = matrix.invert([], transform);
\r
10031 return vector.applyTransform([], vertex, transform);
\r
10035 * @param {string} direction 'left' 'right' 'top' 'bottom'
\r
10036 * @param {Array.<number>} transform Transform matrix: like [1, 0, 0, 1, 0, 0]
\r
10037 * @param {boolean=} invert Whether use invert matrix.
\r
10038 * @return {string} Transformed direction. 'left' 'right' 'top' 'bottom'
\r
10040 graphic.transformDirection = function (direction, transform, invert) {
\r
10042 // Pick a base, ensure that transform result will not be (0, 0).
\r
10043 var hBase = (transform[4] === 0 || transform[5] === 0 || transform[0] === 0)
\r
10044 ? 1 : Math.abs(2 * transform[4] / transform[0]);
\r
10045 var vBase = (transform[4] === 0 || transform[5] === 0 || transform[2] === 0)
\r
10046 ? 1 : Math.abs(2 * transform[4] / transform[2]);
\r
10049 direction === 'left' ? -hBase : direction === 'right' ? hBase : 0,
\r
10050 direction === 'top' ? -vBase : direction === 'bottom' ? vBase : 0
\r
10053 vertex = graphic.applyTransform(vertex, transform, invert);
\r
10055 return Math.abs(vertex[0]) > Math.abs(vertex[1])
\r
10056 ? (vertex[0] > 0 ? 'right' : 'left')
\r
10057 : (vertex[1] > 0 ? 'bottom' : 'top');
\r
10060 module.exports = graphic;
\r
10065 /***/ function(module, exports, __webpack_require__) {
\r
10069 var Path = __webpack_require__(44);
\r
10070 var PathProxy = __webpack_require__(48);
\r
10071 var transformPath = __webpack_require__(58);
\r
10072 var matrix = __webpack_require__(17);
\r
10076 'm', 'M', 'l', 'L', 'v', 'V', 'h', 'H', 'z', 'Z',
\r
10077 'c', 'C', 'q', 'Q', 't', 'T', 's', 'S', 'a', 'A'
\r
10080 var mathSqrt = Math.sqrt;
\r
10081 var mathSin = Math.sin;
\r
10082 var mathCos = Math.cos;
\r
10083 var PI = Math.PI;
\r
10085 var vMag = function(v) {
\r
10086 return Math.sqrt(v[0] * v[0] + v[1] * v[1]);
\r
10088 var vRatio = function(u, v) {
\r
10089 return (u[0] * v[0] + u[1] * v[1]) / (vMag(u) * vMag(v));
\r
10091 var vAngle = function(u, v) {
\r
10092 return (u[0] * v[1] < u[1] * v[0] ? -1 : 1)
\r
10093 * Math.acos(vRatio(u, v));
\r
10096 function processArc(x1, y1, x2, y2, fa, fs, rx, ry, psiDeg, cmd, path) {
\r
10097 var psi = psiDeg * (PI / 180.0);
\r
10098 var xp = mathCos(psi) * (x1 - x2) / 2.0
\r
10099 + mathSin(psi) * (y1 - y2) / 2.0;
\r
10100 var yp = -1 * mathSin(psi) * (x1 - x2) / 2.0
\r
10101 + mathCos(psi) * (y1 - y2) / 2.0;
\r
10103 var lambda = (xp * xp) / (rx * rx) + (yp * yp) / (ry * ry);
\r
10105 if (lambda > 1) {
\r
10106 rx *= mathSqrt(lambda);
\r
10107 ry *= mathSqrt(lambda);
\r
10110 var f = (fa === fs ? -1 : 1)
\r
10111 * mathSqrt((((rx * rx) * (ry * ry))
\r
10112 - ((rx * rx) * (yp * yp))
\r
10113 - ((ry * ry) * (xp * xp))) / ((rx * rx) * (yp * yp)
\r
10114 + (ry * ry) * (xp * xp))
\r
10117 var cxp = f * rx * yp / ry;
\r
10118 var cyp = f * -ry * xp / rx;
\r
10120 var cx = (x1 + x2) / 2.0
\r
10121 + mathCos(psi) * cxp
\r
10122 - mathSin(psi) * cyp;
\r
10123 var cy = (y1 + y2) / 2.0
\r
10124 + mathSin(psi) * cxp
\r
10125 + mathCos(psi) * cyp;
\r
10127 var theta = vAngle([ 1, 0 ], [ (xp - cxp) / rx, (yp - cyp) / ry ]);
\r
10128 var u = [ (xp - cxp) / rx, (yp - cyp) / ry ];
\r
10129 var v = [ (-1 * xp - cxp) / rx, (-1 * yp - cyp) / ry ];
\r
10130 var dTheta = vAngle(u, v);
\r
10132 if (vRatio(u, v) <= -1) {
\r
10135 if (vRatio(u, v) >= 1) {
\r
10138 if (fs === 0 && dTheta > 0) {
\r
10139 dTheta = dTheta - 2 * PI;
\r
10141 if (fs === 1 && dTheta < 0) {
\r
10142 dTheta = dTheta + 2 * PI;
\r
10145 path.addData(cmd, cx, cy, rx, ry, theta, dTheta, psi, fs);
\r
10148 function createPathProxyFromString(data) {
\r
10153 // command string
\r
10154 var cs = data.replace(/-/g, ' -')
\r
10155 .replace(/ /g, ' ')
\r
10156 .replace(/ /g, ',')
\r
10157 .replace(/,,/g, ',');
\r
10160 // create pipes so that we can split the data
\r
10161 for (n = 0; n < cc.length; n++) {
\r
10162 cs = cs.replace(new RegExp(cc[n], 'g'), '|' + cc[n]);
\r
10166 var arr = cs.split('|');
\r
10167 // init context point
\r
10171 var path = new PathProxy();
\r
10172 var CMD = PathProxy.CMD;
\r
10175 for (n = 1; n < arr.length; n++) {
\r
10176 var str = arr[n];
\r
10177 var c = str.charAt(0);
\r
10179 var p = str.slice(1).replace(/e,-/g, 'e-').split(',');
\r
10182 if (p.length > 0 && p[0] === '') {
\r
10186 for (var i = 0; i < p.length; i++) {
\r
10187 p[i] = parseFloat(p[i]);
\r
10189 while (off < p.length && !isNaN(p[off])) {
\r
10190 if (isNaN(p[0])) {
\r
10205 // convert l, H, h, V, and v to L
\r
10211 path.addData(cmd, cpx, cpy);
\r
10217 path.addData(cmd, cpx, cpy);
\r
10223 path.addData(cmd, cpx, cpy);
\r
10230 path.addData(cmd, cpx, cpy);
\r
10236 path.addData(cmd, cpx, cpy);
\r
10241 path.addData(cmd, cpx, cpy);
\r
10246 path.addData(cmd, cpx, cpy);
\r
10251 path.addData(cmd, cpx, cpy);
\r
10256 cmd, p[off++], p[off++], p[off++], p[off++], p[off++], p[off++]
\r
10258 cpx = p[off - 2];
\r
10259 cpy = p[off - 1];
\r
10265 p[off++] + cpx, p[off++] + cpy,
\r
10266 p[off++] + cpx, p[off++] + cpy,
\r
10267 p[off++] + cpx, p[off++] + cpy
\r
10269 cpx += p[off - 2];
\r
10270 cpy += p[off - 1];
\r
10275 var len = path.len();
\r
10276 var pathData = path.data;
\r
10277 if (prevCmd === CMD.C) {
\r
10278 ctlPtx += cpx - pathData[len - 4];
\r
10279 ctlPty += cpy - pathData[len - 3];
\r
10286 path.addData(cmd, ctlPtx, ctlPty, x1, y1, cpx, cpy);
\r
10291 var len = path.len();
\r
10292 var pathData = path.data;
\r
10293 if (prevCmd === CMD.C) {
\r
10294 ctlPtx += cpx - pathData[len - 4];
\r
10295 ctlPty += cpy - pathData[len - 3];
\r
10298 x1 = cpx + p[off++];
\r
10299 y1 = cpy + p[off++];
\r
10302 path.addData(cmd, ctlPtx, ctlPty, x1, y1, cpx, cpy);
\r
10310 path.addData(cmd, x1, y1, cpx, cpy);
\r
10313 x1 = p[off++] + cpx;
\r
10314 y1 = p[off++] + cpy;
\r
10318 path.addData(cmd, x1, y1, cpx, cpy);
\r
10323 var len = path.len();
\r
10324 var pathData = path.data;
\r
10325 if (prevCmd === CMD.Q) {
\r
10326 ctlPtx += cpx - pathData[len - 4];
\r
10327 ctlPty += cpy - pathData[len - 3];
\r
10332 path.addData(cmd, ctlPtx, ctlPty, cpx, cpy);
\r
10337 var len = path.len();
\r
10338 var pathData = path.data;
\r
10339 if (prevCmd === CMD.Q) {
\r
10340 ctlPtx += cpx - pathData[len - 4];
\r
10341 ctlPty += cpy - pathData[len - 3];
\r
10346 path.addData(cmd, ctlPtx, ctlPty, cpx, cpy);
\r
10355 x1 = cpx, y1 = cpy;
\r
10360 x1, y1, cpx, cpy, fa, fs, rx, ry, psi, cmd, path
\r
10370 x1 = cpx, y1 = cpy;
\r
10375 x1, y1, cpx, cpy, fa, fs, rx, ry, psi, cmd, path
\r
10381 if (c === 'z' || c === 'Z') {
\r
10383 path.addData(cmd);
\r
10394 // TODO Optimize double memory cost problem
\r
10395 function createPathOptions(str, opts) {
\r
10396 var pathProxy = createPathProxyFromString(str);
\r
10398 opts = opts || {};
\r
10399 opts.buildPath = function (path) {
\r
10400 path.setData(pathProxy.data);
\r
10401 transform && transformPath(path, transform);
\r
10402 // Svg and vml renderer don't have context
\r
10403 var ctx = path.getContext();
\r
10405 path.rebuildPath(ctx);
\r
10409 opts.applyTransform = function (m) {
\r
10410 if (!transform) {
\r
10411 transform = matrix.create();
\r
10413 matrix.mul(transform, m, transform);
\r
10419 module.exports = {
\r
10421 * Create a Path object from path string data
\r
10422 * http://www.w3.org/TR/SVG/paths.html#PathData
\r
10423 * @param {Object} opts Other options
\r
10425 createFromString: function (str, opts) {
\r
10426 return new Path(createPathOptions(str, opts));
\r
10430 * Create a Path class from path string data
\r
10431 * @param {string} str
\r
10432 * @param {Object} opts Other options
\r
10434 extendFromString: function (str, opts) {
\r
10435 return Path.extend(createPathOptions(str, opts));
\r
10439 * Merge multiple paths
\r
10441 // TODO Apply transform
\r
10442 // TODO stroke dash
\r
10443 // TODO Optimize double memory cost problem
\r
10444 mergePath: function (pathEls, opts) {
\r
10445 var pathList = [];
\r
10446 var len = pathEls.length;
\r
10449 for (i = 0; i < len; i++) {
\r
10450 pathEl = pathEls[i];
\r
10451 if (pathEl.__dirty) {
\r
10452 pathEl.buildPath(pathEl.path, pathEl.shape);
\r
10454 pathList.push(pathEl.path);
\r
10457 var pathBundle = new Path(opts);
\r
10458 pathBundle.buildPath = function (path) {
\r
10459 path.appendPath(pathList);
\r
10460 // Svg and vml renderer don't have context
\r
10461 var ctx = path.getContext();
\r
10463 path.rebuildPath(ctx);
\r
10467 return pathBundle;
\r
10474 /***/ function(module, exports, __webpack_require__) {
\r
10478 * @module zrender/graphic/Path
\r
10483 var Displayable = __webpack_require__(45);
\r
10484 var zrUtil = __webpack_require__(3);
\r
10485 var PathProxy = __webpack_require__(48);
\r
10486 var pathContain = __webpack_require__(51);
\r
10488 var Gradient = __webpack_require__(4);
\r
10490 function pathHasFill(style) {
\r
10491 var fill = style.fill;
\r
10492 return fill != null && fill !== 'none';
\r
10495 function pathHasStroke(style) {
\r
10496 var stroke = style.stroke;
\r
10497 return stroke != null && stroke !== 'none' && style.lineWidth > 0;
\r
10500 var abs = Math.abs;
\r
10503 * @alias module:zrender/graphic/Path
\r
10504 * @extends module:zrender/graphic/Displayable
\r
10506 * @param {Object} opts
\r
10508 function Path(opts) {
\r
10509 Displayable.call(this, opts);
\r
10512 * @type {module:zrender/core/PathProxy}
\r
10515 this.path = new PathProxy();
\r
10518 Path.prototype = {
\r
10520 constructor: Path,
\r
10524 __dirtyPath: true,
\r
10526 strokeContainThreshold: 5,
\r
10528 brush: function (ctx) {
\r
10531 var style = this.style;
\r
10532 var path = this.path;
\r
10533 var hasStroke = pathHasStroke(style);
\r
10534 var hasFill = pathHasFill(style);
\r
10536 if (this.__dirtyPath) {
\r
10537 // Update gradient because bounding rect may changed
\r
10538 if (hasFill && (style.fill instanceof Gradient)) {
\r
10539 style.fill.updateCanvasGradient(this, ctx);
\r
10541 if (hasStroke && (style.stroke instanceof Gradient)) {
\r
10542 style.stroke.updateCanvasGradient(this, ctx);
\r
10546 style.bind(ctx, this);
\r
10547 this.setTransform(ctx);
\r
10549 var lineDash = style.lineDash;
\r
10550 var lineDashOffset = style.lineDashOffset;
\r
10552 var ctxLineDash = !!ctx.setLineDash;
\r
10555 // Rebuild path in following 2 cases
\r
10556 // 1. Path is dirty
\r
10557 // 2. Path needs javascript implemented lineDash stroking.
\r
10558 // In this case, lineDash information will not be saved in PathProxy
\r
10559 if (this.__dirtyPath || (
\r
10560 lineDash && !ctxLineDash && hasStroke
\r
10562 path = this.path.beginPath(ctx);
\r
10564 // Setting line dash before build path
\r
10565 if (lineDash && !ctxLineDash) {
\r
10566 path.setLineDash(lineDash);
\r
10567 path.setLineDashOffset(lineDashOffset);
\r
10570 this.buildPath(path, this.shape);
\r
10572 // Clear path dirty flag
\r
10573 this.__dirtyPath = false;
\r
10576 // Replay path building
\r
10578 this.path.rebuildPath(ctx);
\r
10581 hasFill && path.fill(ctx);
\r
10583 if (lineDash && ctxLineDash) {
\r
10584 ctx.setLineDash(lineDash);
\r
10585 ctx.lineDashOffset = lineDashOffset;
\r
10588 hasStroke && path.stroke(ctx);
\r
10590 // Draw rect text
\r
10591 if (style.text != null) {
\r
10592 // var rect = this.getBoundingRect();
\r
10593 this.drawRectText(ctx, this.getBoundingRect());
\r
10599 buildPath: function (ctx, shapeCfg) {},
\r
10601 getBoundingRect: function () {
\r
10602 var rect = this._rect;
\r
10603 var style = this.style;
\r
10604 var needsUpdateRect = !rect;
\r
10605 if (needsUpdateRect) {
\r
10606 var path = this.path;
\r
10607 if (this.__dirtyPath) {
\r
10608 path.beginPath();
\r
10609 this.buildPath(path, this.shape);
\r
10611 rect = path.getBoundingRect();
\r
10613 this._rect = rect;
\r
10615 if (pathHasStroke(style)) {
\r
10616 // Needs update rect with stroke lineWidth when
\r
10617 // 1. Element changes scale or lineWidth
\r
10618 // 2. Shape is changed
\r
10619 var rectWithStroke = this._rectWithStroke;
\r
10620 if (this.__dirty || needsUpdateRect) {
\r
10621 var rectWithStroke = this._rectWithStroke
\r
10622 || (this._rectWithStroke = rect.clone());
\r
10623 rectWithStroke.copy(rect);
\r
10624 // FIXME Must after updateTransform
\r
10625 var w = style.lineWidth;
\r
10626 // PENDING, Min line width is needed when line is horizontal or vertical
\r
10627 var lineScale = style.strokeNoScale ? this.getLineScale() : 1;
\r
10629 // Only add extra hover lineWidth when there are no fill
\r
10630 if (!pathHasFill(style)) {
\r
10631 w = Math.max(w, this.strokeContainThreshold);
\r
10633 // Consider line width
\r
10634 // Line scale can't be 0;
\r
10635 if (lineScale > 1e-10) {
\r
10636 rectWithStroke.width += w / lineScale;
\r
10637 rectWithStroke.height += w / lineScale;
\r
10638 rectWithStroke.x -= w / lineScale / 2;
\r
10639 rectWithStroke.y -= w / lineScale / 2;
\r
10643 // Return rect with stroke
\r
10644 return rectWithStroke;
\r
10650 contain: function (x, y) {
\r
10651 var localPos = this.transformCoordToLocal(x, y);
\r
10652 var rect = this.getBoundingRect();
\r
10653 var style = this.style;
\r
10657 if (rect.contain(x, y)) {
\r
10658 var pathData = this.path.data;
\r
10659 if (pathHasStroke(style)) {
\r
10660 var lineWidth = style.lineWidth;
\r
10661 var lineScale = style.strokeNoScale ? this.getLineScale() : 1;
\r
10662 // Line scale can't be 0;
\r
10663 if (lineScale > 1e-10) {
\r
10664 // Only add extra hover lineWidth when there are no fill
\r
10665 if (!pathHasFill(style)) {
\r
10666 lineWidth = Math.max(lineWidth, this.strokeContainThreshold);
\r
10668 if (pathContain.containStroke(
\r
10669 pathData, lineWidth / lineScale, x, y
\r
10675 if (pathHasFill(style)) {
\r
10676 return pathContain.contain(pathData, x, y);
\r
10683 * @param {boolean} dirtyPath
\r
10685 dirty: function (dirtyPath) {
\r
10686 if (arguments.length ===0) {
\r
10687 dirtyPath = true;
\r
10689 // Only mark dirty, not mark clean
\r
10691 this.__dirtyPath = dirtyPath;
\r
10692 this._rect = null;
\r
10695 this.__dirty = true;
\r
10697 this.__zr && this.__zr.refresh();
\r
10699 // Used as a clipping path
\r
10700 if (this.__clipTarget) {
\r
10701 this.__clipTarget.dirty();
\r
10706 * Alias for animate('shape')
\r
10707 * @param {boolean} loop
\r
10709 animateShape: function (loop) {
\r
10710 return this.animate('shape', loop);
\r
10713 // Overwrite attrKV
\r
10714 attrKV: function (key, value) {
\r
10716 if (key === 'shape') {
\r
10717 this.setShape(value);
\r
10720 Displayable.prototype.attrKV.call(this, key, value);
\r
10725 * @param {Object|string} key
\r
10726 * @param {*} value
\r
10728 setShape: function (key, value) {
\r
10729 var shape = this.shape;
\r
10730 // Path from string may not have shape
\r
10732 if (zrUtil.isObject(key)) {
\r
10733 for (var name in key) {
\r
10734 shape[name] = key[name];
\r
10738 shape[key] = value;
\r
10740 this.dirty(true);
\r
10745 getLineScale: function () {
\r
10746 var m = this.transform;
\r
10747 // Get the line scale.
\r
10748 // Determinant of `m` means how much the area is enlarged by the
\r
10749 // transformation. So its square root can be used as a scale factor
\r
10751 return m && abs(m[0] - 1) > 1e-10 && abs(m[3] - 1) > 1e-10
\r
10752 ? Math.sqrt(abs(m[0] * m[3] - m[2] * m[1]))
\r
10758 * 扩展一个 Path element, 比如星形,圆等。
\r
10759 * Extend a path element
\r
10760 * @param {Object} props
\r
10761 * @param {string} props.type Path type
\r
10762 * @param {Function} props.init Initialize
\r
10763 * @param {Function} props.buildPath Overwrite buildPath method
\r
10764 * @param {Object} [props.style] Extended default style config
\r
10765 * @param {Object} [props.shape] Extended default shape config
\r
10767 Path.extend = function (defaults) {
\r
10768 var Sub = function (opts) {
\r
10769 Path.call(this, opts);
\r
10771 if (defaults.style) {
\r
10772 // Extend default style
\r
10773 this.style.extendFrom(defaults.style, false);
\r
10776 // Extend default shape
\r
10777 var defaultShape = defaults.shape;
\r
10778 if (defaultShape) {
\r
10779 this.shape = this.shape || {};
\r
10780 var thisShape = this.shape;
\r
10781 for (var name in defaultShape) {
\r
10783 ! thisShape.hasOwnProperty(name)
\r
10784 && defaultShape.hasOwnProperty(name)
\r
10786 thisShape[name] = defaultShape[name];
\r
10791 defaults.init && defaults.init.call(this, opts);
\r
10794 zrUtil.inherits(Sub, Path);
\r
10796 // FIXME 不能 extend position, rotation 等引用对象
\r
10797 for (var name in defaults) {
\r
10798 // Extending prototype values and methods
\r
10799 if (name !== 'style' && name !== 'shape') {
\r
10800 Sub.prototype[name] = defaults[name];
\r
10807 zrUtil.inherits(Path, Displayable);
\r
10809 module.exports = Path;
\r
10814 /***/ function(module, exports, __webpack_require__) {
\r
10818 * Base class of all displayable graphic objects
\r
10819 * @module zrender/graphic/Displayable
\r
10824 var zrUtil = __webpack_require__(3);
\r
10826 var Style = __webpack_require__(46);
\r
10828 var Element = __webpack_require__(30);
\r
10829 var RectText = __webpack_require__(47);
\r
10830 // var Stateful = require('./mixin/Stateful');
\r
10833 * @alias module:zrender/graphic/Displayable
\r
10834 * @extends module:zrender/Element
\r
10835 * @extends module:zrender/graphic/mixin/RectText
\r
10837 function Displayable(opts) {
\r
10839 opts = opts || {};
\r
10841 Element.call(this, opts);
\r
10843 // Extend properties
\r
10844 for (var name in opts) {
\r
10846 opts.hasOwnProperty(name) &&
\r
10849 this[name] = opts[name];
\r
10854 * @type {module:zrender/graphic/Style}
\r
10856 this.style = new Style(opts.style);
\r
10858 this._rect = null;
\r
10859 // Shapes for cascade clipping.
\r
10860 this.__clipPaths = [];
\r
10862 // FIXME Stateful must be mixined after style is setted
\r
10863 // Stateful.call(this, opts);
\r
10866 Displayable.prototype = {
\r
10868 constructor: Displayable,
\r
10870 type: 'displayable',
\r
10873 * Displayable 是否为脏,Painter 中会根据该标记判断是否需要是否需要重新绘制
\r
10874 * Dirty flag. From which painter will determine if this displayable object needs brush
\r
10875 * @name module:zrender/graphic/Displayable#__dirty
\r
10876 * @type {boolean}
\r
10881 * 图形是否可见,为true时不绘制图形,但是仍能触发鼠标事件
\r
10882 * If ignore drawing of the displayable object. Mouse event will still be triggered
\r
10883 * @name module:/zrender/graphic/Displayable#invisible
\r
10884 * @type {boolean}
\r
10887 invisible: false,
\r
10890 * @name module:/zrender/graphic/Displayable#z
\r
10897 * @name module:/zrender/graphic/Displayable#z
\r
10904 * z层level,决定绘画在哪层canvas中
\r
10905 * @name module:/zrender/graphic/Displayable#zlevel
\r
10913 * @name module:/zrender/graphic/Displayable#draggable
\r
10914 * @type {boolean}
\r
10917 draggable: false,
\r
10921 * @name module:/zrender/graphic/Displayable#draggable
\r
10922 * @type {boolean}
\r
10929 * @name module:/zrender/graphic/Displayable#silent
\r
10930 * @type {boolean}
\r
10936 * If enable culling
\r
10937 * @type {boolean}
\r
10943 * Mouse cursor when hovered
\r
10944 * @name module:/zrender/graphic/Displayable#cursor
\r
10947 cursor: 'pointer',
\r
10950 * If hover area is bounding rect
\r
10951 * @name module:/zrender/graphic/Displayable#rectHover
\r
10954 rectHover: false,
\r
10956 beforeBrush: function (ctx) {},
\r
10958 afterBrush: function (ctx) {},
\r
10962 * @param {Canvas2DRenderingContext} ctx
\r
10965 brush: function (ctx) {},
\r
10969 * @return {module:zrender/core/BoundingRect}
\r
10972 getBoundingRect: function () {},
\r
10975 * 判断坐标 x, y 是否在图形上
\r
10976 * If displayable element contain coord x, y
\r
10977 * @param {number} x
\r
10978 * @param {number} y
\r
10979 * @return {boolean}
\r
10981 contain: function (x, y) {
\r
10982 return this.rectContain(x, y);
\r
10986 * @param {Function} cb
\r
10987 * @param {} context
\r
10989 traverse: function (cb, context) {
\r
10990 cb.call(context, this);
\r
10994 * 判断坐标 x, y 是否在图形的包围盒上
\r
10995 * If bounding rect of element contain coord x, y
\r
10996 * @param {number} x
\r
10997 * @param {number} y
\r
10998 * @return {boolean}
\r
11000 rectContain: function (x, y) {
\r
11001 var coord = this.transformCoordToLocal(x, y);
\r
11002 var rect = this.getBoundingRect();
\r
11003 return rect.contain(coord[0], coord[1]);
\r
11007 * 标记图形元素为脏,并且在下一帧重绘
\r
11008 * Mark displayable element dirty and refresh next frame
\r
11010 dirty: function () {
\r
11011 this.__dirty = true;
\r
11013 this._rect = null;
\r
11015 this.__zr && this.__zr.refresh();
\r
11020 * If displayable object binded any event
\r
11021 * @return {boolean}
\r
11023 // TODO, 通过 bind 绑定的事件
\r
11024 // isSilent: function () {
\r
11026 // this.hoverable || this.draggable
\r
11027 // || this.onmousemove || this.onmouseover || this.onmouseout
\r
11028 // || this.onmousedown || this.onmouseup || this.onclick
\r
11029 // || this.ondragenter || this.ondragover || this.ondragleave
\r
11030 // || this.ondrop
\r
11034 * Alias for animate('style')
\r
11035 * @param {boolean} loop
\r
11037 animateStyle: function (loop) {
\r
11038 return this.animate('style', loop);
\r
11041 attrKV: function (key, value) {
\r
11042 if (key !== 'style') {
\r
11043 Element.prototype.attrKV.call(this, key, value);
\r
11046 this.style.set(value);
\r
11051 * @param {Object|string} key
\r
11052 * @param {*} value
\r
11054 setStyle: function (key, value) {
\r
11055 this.style.set(key, value);
\r
11056 this.dirty(false);
\r
11061 zrUtil.inherits(Displayable, Element);
\r
11063 zrUtil.mixin(Displayable, RectText);
\r
11064 // zrUtil.mixin(Displayable, Stateful);
\r
11066 module.exports = Displayable;
\r
11071 /***/ function(module, exports) {
\r
11074 * @module zrender/graphic/Style
\r
11079 var STYLE_LIST_COMMON = [
\r
11080 'lineCap', 'lineJoin', 'miterLimit',
\r
11081 'shadowBlur', 'shadowOffsetX', 'shadowOffsetY', 'shadowColor'
\r
11084 var Style = function (opts) {
\r
11085 this.extendFrom(opts);
\r
11088 Style.prototype = {
\r
11090 constructor: Style,
\r
11108 * @type {Array.<number>}
\r
11115 lineDashOffset: 0,
\r
11125 shadowOffsetX: 0,
\r
11130 shadowOffsetY: 0,
\r
11138 * If stroke ignore scale
\r
11139 * @type {Boolean}
\r
11141 strokeNoScale: false,
\r
11143 // Bounding rect text configuration
\r
11144 // Not affected by element transform
\r
11153 textFill: '#000',
\r
11158 textStroke: null,
\r
11161 * 'inside', 'left', 'right', 'top', 'bottom'
\r
11163 * @type {string|Array.<number>}
\r
11164 * @default 'inside'
\r
11166 textPosition: 'inside',
\r
11171 textBaseline: null,
\r
11181 textVerticalAlign: null,
\r
11191 textShadowBlur: 0,
\r
11196 textShadowOffsetX: 0,
\r
11201 textShadowOffsetY: 0,
\r
11204 * @param {CanvasRenderingContext2D} ctx
\r
11206 bind: function (ctx, el) {
\r
11207 var fill = this.fill;
\r
11208 var stroke = this.stroke;
\r
11209 for (var i = 0; i < STYLE_LIST_COMMON.length; i++) {
\r
11210 var styleName = STYLE_LIST_COMMON[i];
\r
11212 if (this[styleName] != null) {
\r
11213 ctx[styleName] = this[styleName];
\r
11216 if (stroke != null) {
\r
11217 var lineWidth = this.lineWidth;
\r
11218 ctx.lineWidth = lineWidth / (
\r
11219 (this.strokeNoScale && el && el.getLineScale) ? el.getLineScale() : 1
\r
11222 if (fill != null) {
\r
11223 // Use canvas gradient if has
\r
11224 ctx.fillStyle = fill.canvasGradient ? fill.canvasGradient : fill;
\r
11226 if (stroke != null) {
\r
11227 // Use canvas gradient if has
\r
11228 ctx.strokeStyle = stroke.canvasGradient ? stroke.canvasGradient : stroke;
\r
11230 this.opacity != null && (ctx.globalAlpha = this.opacity);
\r
11234 * Extend from other style
\r
11235 * @param {zrender/graphic/Style} otherStyle
\r
11236 * @param {boolean} overwrite
\r
11238 extendFrom: function (otherStyle, overwrite) {
\r
11239 if (otherStyle) {
\r
11240 var target = this;
\r
11241 for (var name in otherStyle) {
\r
11242 if (otherStyle.hasOwnProperty(name)
\r
11243 && (overwrite || ! target.hasOwnProperty(name))
\r
11245 target[name] = otherStyle[name];
\r
11252 * Batch setting style with a given object
\r
11253 * @param {Object|string} obj
\r
11254 * @param {*} [obj]
\r
11256 set: function (obj, value) {
\r
11257 if (typeof obj === 'string') {
\r
11258 this[obj] = value;
\r
11261 this.extendFrom(obj, true);
\r
11267 * @return {zrender/graphic/Style} [description]
\r
11269 clone: function () {
\r
11270 var newStyle = new this.constructor();
\r
11271 newStyle.extendFrom(this, true);
\r
11276 var styleProto = Style.prototype;
\r
11279 for (i = 0; i < STYLE_LIST_COMMON.length; i++) {
\r
11280 name = STYLE_LIST_COMMON[i];
\r
11281 if (!(name in styleProto)) {
\r
11282 styleProto[name] = null;
\r
11286 module.exports = Style;
\r
11291 /***/ function(module, exports, __webpack_require__) {
\r
11294 * Mixin for drawing text in a element bounding rect
\r
11295 * @module zrender/mixin/RectText
\r
11300 var textContain = __webpack_require__(14);
\r
11301 var BoundingRect = __webpack_require__(15);
\r
11303 var tmpRect = new BoundingRect();
\r
11305 var RectText = function () {};
\r
11307 function parsePercent(value, maxValue) {
\r
11308 if (typeof value === 'string') {
\r
11309 if (value.lastIndexOf('%') >= 0) {
\r
11310 return parseFloat(value) / 100 * maxValue;
\r
11312 return parseFloat(value);
\r
11317 function setTransform(ctx, m) {
\r
11318 ctx.transform(m[0], m[1], m[2], m[3], m[4], m[5]);
\r
11321 RectText.prototype = {
\r
11323 constructor: RectText,
\r
11326 * Draw text in a rect with specified position.
\r
11327 * @param {CanvasRenderingContext} ctx
\r
11328 * @param {Object} rect Displayable rect
\r
11329 * @return {Object} textRect Alternative precalculated text bounding rect
\r
11331 drawRectText: function (ctx, rect, textRect) {
\r
11332 var style = this.style;
\r
11333 var text = style.text;
\r
11334 // Convert to string
\r
11335 text != null && (text += '');
\r
11341 var textPosition = style.textPosition;
\r
11342 var distance = style.textDistance;
\r
11343 var align = style.textAlign;
\r
11344 var font = style.textFont || style.font;
\r
11345 var baseline = style.textBaseline;
\r
11346 var verticalAlign = style.textVerticalAlign;
\r
11348 textRect = textRect || textContain.getBoundingRect(text, font, align, baseline);
\r
11350 // Transform rect to view space
\r
11351 var transform = this.transform;
\r
11352 var invTransform = this.invTransform;
\r
11354 tmpRect.copy(rect);
\r
11355 tmpRect.applyTransform(transform);
\r
11357 // Transform back
\r
11358 setTransform(ctx, invTransform);
\r
11361 // Text position represented by coord
\r
11362 if (textPosition instanceof Array) {
\r
11364 x = rect.x + parsePercent(textPosition[0], rect.width);
\r
11365 y = rect.y + parsePercent(textPosition[1], rect.height);
\r
11366 align = align || 'left';
\r
11367 baseline = baseline || 'top';
\r
11370 var res = textContain.adjustTextPositionOnRect(
\r
11371 textPosition, rect, textRect, distance
\r
11375 // Default align and baseline when has textPosition
\r
11376 align = align || res.textAlign;
\r
11377 baseline = baseline || res.textBaseline;
\r
11380 ctx.textAlign = align;
\r
11381 if (verticalAlign) {
\r
11382 switch (verticalAlign) {
\r
11384 y -= textRect.height / 2;
\r
11387 y -= textRect.height;
\r
11391 // Ignore baseline
\r
11392 ctx.textBaseline = 'top';
\r
11395 ctx.textBaseline = baseline;
\r
11398 var textFill = style.textFill;
\r
11399 var textStroke = style.textStroke;
\r
11400 textFill && (ctx.fillStyle = textFill);
\r
11401 textStroke && (ctx.strokeStyle = textStroke);
\r
11405 ctx.shadowColor = style.textShadowColor;
\r
11406 ctx.shadowBlur = style.textShadowBlur;
\r
11407 ctx.shadowOffsetX = style.textShadowOffsetX;
\r
11408 ctx.shadowOffsetY = style.textShadowOffsetY;
\r
11410 var textLines = text.split('\n');
\r
11411 for (var i = 0; i < textLines.length; i++) {
\r
11412 textFill && ctx.fillText(textLines[i], x, y);
\r
11413 textStroke && ctx.strokeText(textLines[i], x, y);
\r
11414 y += textRect.lineHeight;
\r
11417 // Transform again
\r
11418 transform && setTransform(ctx, transform);
\r
11422 module.exports = RectText;
\r
11427 /***/ function(module, exports, __webpack_require__) {
\r
11431 * Path 代理,可以在`buildPath`中用于替代`ctx`, 会保存每个path操作的命令到pathCommands属性中
\r
11432 * 可以用于 isInsidePath 判断以及获取boundingRect
\r
11434 * @module zrender/core/PathProxy
\r
11435 * @author Yi Shen (http://www.github.com/pissang)
\r
11438 // TODO getTotalLength, getPointAtLength
\r
11441 var curve = __webpack_require__(49);
\r
11442 var vec2 = __webpack_require__(16);
\r
11443 var bbox = __webpack_require__(50);
\r
11444 var BoundingRect = __webpack_require__(15);
\r
11461 var mathMin = Math.min;
\r
11462 var mathMax = Math.max;
\r
11463 var mathCos = Math.cos;
\r
11464 var mathSin = Math.sin;
\r
11465 var mathSqrt = Math.sqrt;
\r
11467 var hasTypedArray = typeof Float32Array != 'undefined';
\r
11470 * @alias module:zrender/core/PathProxy
\r
11473 var PathProxy = function () {
\r
11476 * Path data. Stored as flat array
\r
11477 * @type {Array.<Object>}
\r
11483 this._ctx = null;
\r
11493 * 快速计算Path包围盒(并不是最小包围盒)
\r
11494 * @return {Object}
\r
11496 PathProxy.prototype = {
\r
11498 constructor: PathProxy,
\r
11508 getContext: function () {
\r
11509 return this._ctx;
\r
11513 * @param {CanvasRenderingContext2D} ctx
\r
11514 * @return {module:zrender/core/PathProxy}
\r
11516 beginPath: function (ctx) {
\r
11519 ctx && ctx.beginPath();
\r
11524 if (this._lineDash) {
\r
11525 this._lineDash = null;
\r
11527 this._dashOffset = 0;
\r
11534 * @param {number} x
\r
11535 * @param {number} y
\r
11536 * @return {module:zrender/core/PathProxy}
\r
11538 moveTo: function (x, y) {
\r
11539 this.addData(CMD.M, x, y);
\r
11540 this._ctx && this._ctx.moveTo(x, y);
\r
11542 // x0, y0, xi, yi 是记录在 _dashedXXXXTo 方法中使用
\r
11543 // xi, yi 记录当前点, x0, y0 在 closePath 的时候回到起始点。
\r
11544 // 有可能在 beginPath 之后直接调用 lineTo,这时候 x0, y0 需要
\r
11545 // 在 lineTo 方法中记录,这里先不考虑这种情况,dashed line 也只在 IE10- 中不支持
\r
11556 * @param {number} x
\r
11557 * @param {number} y
\r
11558 * @return {module:zrender/core/PathProxy}
\r
11560 lineTo: function (x, y) {
\r
11561 this.addData(CMD.L, x, y);
\r
11563 this._needsDash() ? this._dashedLineTo(x, y)
\r
11564 : this._ctx.lineTo(x, y);
\r
11572 * @param {number} x1
\r
11573 * @param {number} y1
\r
11574 * @param {number} x2
\r
11575 * @param {number} y2
\r
11576 * @param {number} x3
\r
11577 * @param {number} y3
\r
11578 * @return {module:zrender/core/PathProxy}
\r
11580 bezierCurveTo: function (x1, y1, x2, y2, x3, y3) {
\r
11581 this.addData(CMD.C, x1, y1, x2, y2, x3, y3);
\r
11583 this._needsDash() ? this._dashedBezierTo(x1, y1, x2, y2, x3, y3)
\r
11584 : this._ctx.bezierCurveTo(x1, y1, x2, y2, x3, y3);
\r
11592 * @param {number} x1
\r
11593 * @param {number} y1
\r
11594 * @param {number} x2
\r
11595 * @param {number} y2
\r
11596 * @return {module:zrender/core/PathProxy}
\r
11598 quadraticCurveTo: function (x1, y1, x2, y2) {
\r
11599 this.addData(CMD.Q, x1, y1, x2, y2);
\r
11601 this._needsDash() ? this._dashedQuadraticTo(x1, y1, x2, y2)
\r
11602 : this._ctx.quadraticCurveTo(x1, y1, x2, y2);
\r
11610 * @param {number} cx
\r
11611 * @param {number} cy
\r
11612 * @param {number} r
\r
11613 * @param {number} startAngle
\r
11614 * @param {number} endAngle
\r
11615 * @param {boolean} anticlockwise
\r
11616 * @return {module:zrender/core/PathProxy}
\r
11618 arc: function (cx, cy, r, startAngle, endAngle, anticlockwise) {
\r
11620 CMD.A, cx, cy, r, r, startAngle, endAngle - startAngle, 0, anticlockwise ? 0 : 1
\r
11622 this._ctx && this._ctx.arc(cx, cy, r, startAngle, endAngle, anticlockwise);
\r
11624 this._xi = mathCos(endAngle) * r + cx;
\r
11625 this._xi = mathSin(endAngle) * r + cx;
\r
11630 arcTo: function (x1, y1, x2, y2, radius) {
\r
11632 this._ctx.arcTo(x1, y1, x2, y2, radius);
\r
11638 rect: function (x, y, w, h) {
\r
11639 this._ctx && this._ctx.rect(x, y, w, h);
\r
11640 this.addData(CMD.R, x, y, w, h);
\r
11645 * @return {module:zrender/core/PathProxy}
\r
11647 closePath: function () {
\r
11648 this.addData(CMD.Z);
\r
11650 var ctx = this._ctx;
\r
11651 var x0 = this._x0;
\r
11652 var y0 = this._y0;
\r
11654 this._needsDash() && this._dashedLineTo(x0, y0);
\r
11664 * Context 从外部传入,因为有可能是 rebuildPath 完之后再 fill。
\r
11666 * @param {CanvasRenderingContext2D} ctx
\r
11667 * @return {module:zrender/core/PathProxy}
\r
11669 fill: function (ctx) {
\r
11670 ctx && ctx.fill();
\r
11675 * @param {CanvasRenderingContext2D} ctx
\r
11676 * @return {module:zrender/core/PathProxy}
\r
11678 stroke: function (ctx) {
\r
11679 ctx && ctx.stroke();
\r
11685 * Must be invoked before all other path drawing methods
\r
11686 * @return {module:zrender/core/PathProxy}
\r
11688 setLineDash: function (lineDash) {
\r
11689 if (lineDash instanceof Array) {
\r
11690 this._lineDash = lineDash;
\r
11692 this._dashIdx = 0;
\r
11694 var lineDashSum = 0;
\r
11695 for (var i = 0; i < lineDash.length; i++) {
\r
11696 lineDashSum += lineDash[i];
\r
11698 this._dashSum = lineDashSum;
\r
11705 * Must be invoked before all other path drawing methods
\r
11706 * @return {module:zrender/core/PathProxy}
\r
11708 setLineDashOffset: function (offset) {
\r
11709 this._dashOffset = offset;
\r
11715 * @return {boolean}
\r
11717 len: function () {
\r
11718 return this._len;
\r
11724 setData: function (data) {
\r
11726 var len = data.length;
\r
11728 if (! (this.data && this.data.length == len) && hasTypedArray) {
\r
11729 this.data = new Float32Array(len);
\r
11732 for (var i = 0; i < len; i++) {
\r
11733 this.data[i] = data[i];
\r
11741 * @param {module:zrender/core/PathProxy|Array.<module:zrender/core/PathProxy>} path
\r
11743 appendPath: function (path) {
\r
11744 if (!(path instanceof Array)) {
\r
11747 var len = path.length;
\r
11748 var appendSize = 0;
\r
11749 var offset = this._len;
\r
11750 for (var i = 0; i < len; i++) {
\r
11751 appendSize += path[i].len();
\r
11753 if (hasTypedArray && (this.data instanceof Float32Array)) {
\r
11754 this.data = new Float32Array(offset + appendSize);
\r
11756 for (var i = 0; i < len; i++) {
\r
11757 var appendPathData = path[i].data;
\r
11758 for (var k = 0; k < appendPathData.length; k++) {
\r
11759 this.data[offset++] = appendPathData[k];
\r
11762 this._len = offset;
\r
11767 * 尽量复用而不申明新的数组。大部分图形重绘的指令数据长度都是不变的。
\r
11769 addData: function (cmd) {
\r
11770 var data = this.data;
\r
11771 if (this._len + arguments.length > data.length) {
\r
11772 // 因为之前的数组已经转换成静态的 Float32Array
\r
11773 // 所以不够用时需要扩展一个新的动态数组
\r
11774 this._expandData();
\r
11775 data = this.data;
\r
11777 for (var i = 0; i < arguments.length; i++) {
\r
11778 data[this._len++] = arguments[i];
\r
11781 this._prevCmd = cmd;
\r
11784 _expandData: function () {
\r
11785 // Only if data is Float32Array
\r
11786 if (!(this.data instanceof Array)) {
\r
11787 var newData = [];
\r
11788 for (var i = 0; i < this._len; i++) {
\r
11789 newData[i] = this.data[i];
\r
11791 this.data = newData;
\r
11796 * If needs js implemented dashed line
\r
11797 * @return {boolean}
\r
11800 _needsDash: function () {
\r
11801 return this._lineDash;
\r
11804 _dashedLineTo: function (x1, y1) {
\r
11805 var dashSum = this._dashSum;
\r
11806 var offset = this._dashOffset;
\r
11807 var lineDash = this._lineDash;
\r
11808 var ctx = this._ctx;
\r
11810 var x0 = this._xi;
\r
11811 var y0 = this._yi;
\r
11812 var dx = x1 - x0;
\r
11813 var dy = y1 - y0;
\r
11814 var dist = mathSqrt(dx * dx + dy * dy);
\r
11818 var nDash = lineDash.length;
\r
11823 if (offset < 0) {
\r
11824 // Convert to positive offset
\r
11825 offset = dashSum + offset;
\r
11827 offset %= dashSum;
\r
11828 x -= offset * dx;
\r
11829 y -= offset * dy;
\r
11831 while ((dx >= 0 && x <= x1) || (dx < 0 && x > x1)) {
\r
11832 idx = this._dashIdx;
\r
11833 dash = lineDash[idx];
\r
11836 this._dashIdx = (idx + 1) % nDash;
\r
11837 // Skip positive offset
\r
11838 if ((dx > 0 && x < x0) || (dx < 0 && x > x0)) {
\r
11841 ctx[idx % 2 ? 'moveTo' : 'lineTo'](
\r
11842 dx >= 0 ? mathMin(x, x1) : mathMax(x, x1),
\r
11843 dy >= 0 ? mathMin(y, y1) : mathMax(y, y1)
\r
11846 // Offset for next lineTo
\r
11849 this._dashOffset = -mathSqrt(dx * dx + dy * dy);
\r
11852 // Not accurate dashed line to
\r
11853 _dashedBezierTo: function (x1, y1, x2, y2, x3, y3) {
\r
11854 var dashSum = this._dashSum;
\r
11855 var offset = this._dashOffset;
\r
11856 var lineDash = this._lineDash;
\r
11857 var ctx = this._ctx;
\r
11859 var x0 = this._xi;
\r
11860 var y0 = this._yi;
\r
11864 var cubicAt = curve.cubicAt;
\r
11865 var bezierLen = 0;
\r
11866 var idx = this._dashIdx;
\r
11867 var nDash = lineDash.length;
\r
11874 if (offset < 0) {
\r
11875 // Convert to positive offset
\r
11876 offset = dashSum + offset;
\r
11878 offset %= dashSum;
\r
11879 // Bezier approx length
\r
11880 for (t = 0; t < 1; t += 0.1) {
\r
11881 dx = cubicAt(x0, x1, x2, x3, t + 0.1)
\r
11882 - cubicAt(x0, x1, x2, x3, t);
\r
11883 dy = cubicAt(y0, y1, y2, y3, t + 0.1)
\r
11884 - cubicAt(y0, y1, y2, y3, t);
\r
11885 bezierLen += mathSqrt(dx * dx + dy * dy);
\r
11888 // Find idx after add offset
\r
11889 for (; idx < nDash; idx++) {
\r
11890 tmpLen += lineDash[idx];
\r
11891 if (tmpLen > offset) {
\r
11895 t = (tmpLen - offset) / bezierLen;
\r
11899 x = cubicAt(x0, x1, x2, x3, t);
\r
11900 y = cubicAt(y0, y1, y2, y3, t);
\r
11902 // Use line to approximate dashed bezier
\r
11903 // Bad result if dash is long
\r
11904 idx % 2 ? ctx.moveTo(x, y)
\r
11905 : ctx.lineTo(x, y);
\r
11907 t += lineDash[idx] / bezierLen;
\r
11909 idx = (idx + 1) % nDash;
\r
11912 // Finish the last segment and calculate the new offset
\r
11913 (idx % 2 !== 0) && ctx.lineTo(x3, y3);
\r
11916 this._dashOffset = -mathSqrt(dx * dx + dy * dy);
\r
11919 _dashedQuadraticTo: function (x1, y1, x2, y2) {
\r
11920 // Convert quadratic to cubic using degree elevation
\r
11923 x2 = (x2 + 2 * x1) / 3;
\r
11924 y2 = (y2 + 2 * y1) / 3;
\r
11925 x1 = (this._xi + 2 * x1) / 3;
\r
11926 y1 = (this._yi + 2 * y1) / 3;
\r
11928 this._dashedBezierTo(x1, y1, x2, y2, x3, y3);
\r
11932 * 转成静态的 Float32Array 减少堆内存占用
\r
11933 * Convert dynamic array to static Float32Array
\r
11935 toStatic: function () {
\r
11936 var data = this.data;
\r
11937 if (data instanceof Array) {
\r
11938 data.length = this._len;
\r
11939 if (hasTypedArray) {
\r
11940 this.data = new Float32Array(data);
\r
11946 * @return {module:zrender/core/BoundingRect}
\r
11948 getBoundingRect: function () {
\r
11949 min[0] = min[1] = min2[0] = min2[1] = Number.MAX_VALUE;
\r
11950 max[0] = max[1] = max2[0] = max2[1] = -Number.MAX_VALUE;
\r
11952 var data = this.data;
\r
11958 for (var i = 0; i < data.length;) {
\r
11959 var cmd = data[i++];
\r
11962 // 如果第一个命令是 L, C, Q
\r
11963 // 则 previous point 同绘制命令的第一个 point
\r
11965 // 第一个命令为 Arc 的情况下会在后面特殊处理
\r
11967 yi = data[i + 1];
\r
11975 // moveTo 命令重新创建一个新的 subpath, 并且更新新的起点
\r
11976 // 在 closePath 的时候使用
\r
11987 bbox.fromLine(xi, yi, data[i], data[i + 1], min2, max2);
\r
11993 xi, yi, data[i++], data[i++], data[i++], data[i++], data[i], data[i + 1],
\r
12000 bbox.fromQuadratic(
\r
12001 xi, yi, data[i++], data[i++], data[i], data[i + 1],
\r
12008 // TODO Arc 判断的开销比较大
\r
12009 var cx = data[i++];
\r
12010 var cy = data[i++];
\r
12011 var rx = data[i++];
\r
12012 var ry = data[i++];
\r
12013 var startAngle = data[i++];
\r
12014 var endAngle = data[i++] + startAngle;
\r
12016 var psi = data[i++];
\r
12017 var anticlockwise = 1 - data[i++];
\r
12022 x0 = mathCos(startAngle) * rx + cx;
\r
12023 y0 = mathSin(startAngle) * ry + cy;
\r
12027 cx, cy, rx, ry, startAngle, endAngle,
\r
12028 anticlockwise, min2, max2
\r
12031 xi = mathCos(endAngle) * rx + cx;
\r
12032 yi = mathSin(endAngle) * ry + cy;
\r
12035 x0 = xi = data[i++];
\r
12036 y0 = yi = data[i++];
\r
12037 var width = data[i++];
\r
12038 var height = data[i++];
\r
12040 bbox.fromLine(x0, y0, x0 + width, y0 + height, min2, max2);
\r
12049 vec2.min(min, min, min2);
\r
12050 vec2.max(max, max, max2);
\r
12055 min[0] = min[1] = max[0] = max[1] = 0;
\r
12058 return new BoundingRect(
\r
12059 min[0], min[1], max[0] - min[0], max[1] - min[1]
\r
12064 * Rebuild path from current data
\r
12065 * Rebuild path will not consider javascript implemented line dash.
\r
12066 * @param {CanvasRenderingContext} ctx
\r
12068 rebuildPath: function (ctx) {
\r
12069 var d = this.data;
\r
12070 for (var i = 0; i < this._len;) {
\r
12071 var cmd = d[i++];
\r
12074 ctx.moveTo(d[i++], d[i++]);
\r
12077 ctx.lineTo(d[i++], d[i++]);
\r
12080 ctx.bezierCurveTo(
\r
12081 d[i++], d[i++], d[i++], d[i++], d[i++], d[i++]
\r
12085 ctx.quadraticCurveTo(d[i++], d[i++], d[i++], d[i++]);
\r
12092 var theta = d[i++];
\r
12093 var dTheta = d[i++];
\r
12094 var psi = d[i++];
\r
12096 var r = (rx > ry) ? rx : ry;
\r
12097 var scaleX = (rx > ry) ? 1 : rx / ry;
\r
12098 var scaleY = (rx > ry) ? ry / rx : 1;
\r
12099 var isEllipse = Math.abs(rx - ry) > 1e-3;
\r
12101 ctx.translate(cx, cy);
\r
12103 ctx.scale(scaleX, scaleY);
\r
12104 ctx.arc(0, 0, r, theta, theta + dTheta, 1 - fs);
\r
12105 ctx.scale(1 / scaleX, 1 / scaleY);
\r
12106 ctx.rotate(-psi);
\r
12107 ctx.translate(-cx, -cy);
\r
12110 ctx.arc(cx, cy, r, theta, theta + dTheta, 1 - fs);
\r
12114 ctx.rect(d[i++], d[i++], d[i++], d[i++]);
\r
12123 PathProxy.CMD = CMD;
\r
12125 module.exports = PathProxy;
\r
12130 /***/ function(module, exports, __webpack_require__) {
\r
12135 * @module zrender/core/curve
\r
12136 * @author pissang(https://www.github.com/pissang)
\r
12140 var vec2 = __webpack_require__(16);
\r
12141 var v2Create = vec2.create;
\r
12142 var v2DistSquare = vec2.distSquare;
\r
12143 var mathPow = Math.pow;
\r
12144 var mathSqrt = Math.sqrt;
\r
12146 var EPSILON = 1e-8;
\r
12147 var EPSILON_NUMERIC = 1e-4;
\r
12149 var THREE_SQRT = mathSqrt(3);
\r
12150 var ONE_THIRD = 1 / 3;
\r
12153 var _v0 = v2Create();
\r
12154 var _v1 = v2Create();
\r
12155 var _v2 = v2Create();
\r
12156 // var _v3 = vec2.create();
\r
12158 function isAroundZero(val) {
\r
12159 return val > -EPSILON && val < EPSILON;
\r
12161 function isNotAroundZero(val) {
\r
12162 return val > EPSILON || val < -EPSILON;
\r
12166 * @memberOf module:zrender/core/curve
\r
12167 * @param {number} p0
\r
12168 * @param {number} p1
\r
12169 * @param {number} p2
\r
12170 * @param {number} p3
\r
12171 * @param {number} t
\r
12172 * @return {number}
\r
12174 function cubicAt(p0, p1, p2, p3, t) {
\r
12175 var onet = 1 - t;
\r
12176 return onet * onet * (onet * p0 + 3 * t * p1)
\r
12177 + t * t * (t * p3 + 3 * onet * p2);
\r
12182 * @memberOf module:zrender/core/curve
\r
12183 * @param {number} p0
\r
12184 * @param {number} p1
\r
12185 * @param {number} p2
\r
12186 * @param {number} p3
\r
12187 * @param {number} t
\r
12188 * @return {number}
\r
12190 function cubicDerivativeAt(p0, p1, p2, p3, t) {
\r
12191 var onet = 1 - t;
\r
12193 ((p1 - p0) * onet + 2 * (p2 - p1) * t) * onet
\r
12194 + (p3 - p2) * t * t
\r
12199 * 计算三次贝塞尔方程根,使用盛金公式
\r
12200 * @memberOf module:zrender/core/curve
\r
12201 * @param {number} p0
\r
12202 * @param {number} p1
\r
12203 * @param {number} p2
\r
12204 * @param {number} p3
\r
12205 * @param {number} val
\r
12206 * @param {Array.<number>} roots
\r
12207 * @return {number} 有效根数目
\r
12209 function cubicRootAt(p0, p1, p2, p3, val, roots) {
\r
12210 // Evaluate roots of cubic functions
\r
12211 var a = p3 + 3 * (p1 - p2) - p0;
\r
12212 var b = 3 * (p2 - p1 * 2 + p0);
\r
12213 var c = 3 * (p1 - p0);
\r
12214 var d = p0 - val;
\r
12216 var A = b * b - 3 * a * c;
\r
12217 var B = b * c - 9 * a * d;
\r
12218 var C = c * c - 3 * b * d;
\r
12222 if (isAroundZero(A) && isAroundZero(B)) {
\r
12223 if (isAroundZero(b)) {
\r
12227 var t1 = -c / b; //t1, t2, t3, b is not zero
\r
12228 if (t1 >= 0 && t1 <= 1) {
\r
12234 var disc = B * B - 4 * A * C;
\r
12236 if (isAroundZero(disc)) {
\r
12238 var t1 = -b / a + K; // t1, a is not zero
\r
12239 var t2 = -K / 2; // t2, t3
\r
12240 if (t1 >= 0 && t1 <= 1) {
\r
12243 if (t2 >= 0 && t2 <= 1) {
\r
12247 else if (disc > 0) {
\r
12248 var discSqrt = mathSqrt(disc);
\r
12249 var Y1 = A * b + 1.5 * a * (-B + discSqrt);
\r
12250 var Y2 = A * b + 1.5 * a * (-B - discSqrt);
\r
12252 Y1 = -mathPow(-Y1, ONE_THIRD);
\r
12255 Y1 = mathPow(Y1, ONE_THIRD);
\r
12258 Y2 = -mathPow(-Y2, ONE_THIRD);
\r
12261 Y2 = mathPow(Y2, ONE_THIRD);
\r
12263 var t1 = (-b - (Y1 + Y2)) / (3 * a);
\r
12264 if (t1 >= 0 && t1 <= 1) {
\r
12269 var T = (2 * A * b - 3 * a * B) / (2 * mathSqrt(A * A * A));
\r
12270 var theta = Math.acos(T) / 3;
\r
12271 var ASqrt = mathSqrt(A);
\r
12272 var tmp = Math.cos(theta);
\r
12274 var t1 = (-b - 2 * ASqrt * tmp) / (3 * a);
\r
12275 var t2 = (-b + ASqrt * (tmp + THREE_SQRT * Math.sin(theta))) / (3 * a);
\r
12276 var t3 = (-b + ASqrt * (tmp - THREE_SQRT * Math.sin(theta))) / (3 * a);
\r
12277 if (t1 >= 0 && t1 <= 1) {
\r
12280 if (t2 >= 0 && t2 <= 1) {
\r
12283 if (t3 >= 0 && t3 <= 1) {
\r
12292 * 计算三次贝塞尔方程极限值的位置
\r
12293 * @memberOf module:zrender/core/curve
\r
12294 * @param {number} p0
\r
12295 * @param {number} p1
\r
12296 * @param {number} p2
\r
12297 * @param {number} p3
\r
12298 * @param {Array.<number>} extrema
\r
12299 * @return {number} 有效数目
\r
12301 function cubicExtrema(p0, p1, p2, p3, extrema) {
\r
12302 var b = 6 * p2 - 12 * p1 + 6 * p0;
\r
12303 var a = 9 * p1 + 3 * p3 - 3 * p0 - 9 * p2;
\r
12304 var c = 3 * p1 - 3 * p0;
\r
12307 if (isAroundZero(a)) {
\r
12308 if (isNotAroundZero(b)) {
\r
12310 if (t1 >= 0 && t1 <=1) {
\r
12311 extrema[n++] = t1;
\r
12316 var disc = b * b - 4 * a * c;
\r
12317 if (isAroundZero(disc)) {
\r
12318 extrema[0] = -b / (2 * a);
\r
12320 else if (disc > 0) {
\r
12321 var discSqrt = mathSqrt(disc);
\r
12322 var t1 = (-b + discSqrt) / (2 * a);
\r
12323 var t2 = (-b - discSqrt) / (2 * a);
\r
12324 if (t1 >= 0 && t1 <= 1) {
\r
12325 extrema[n++] = t1;
\r
12327 if (t2 >= 0 && t2 <= 1) {
\r
12328 extrema[n++] = t2;
\r
12337 * @memberOf module:zrender/core/curve
\r
12338 * @param {number} p0
\r
12339 * @param {number} p1
\r
12340 * @param {number} p2
\r
12341 * @param {number} p3
\r
12342 * @param {number} t
\r
12343 * @param {Array.<number>} out
\r
12345 function cubicSubdivide(p0, p1, p2, p3, t, out) {
\r
12346 var p01 = (p1 - p0) * t + p0;
\r
12347 var p12 = (p2 - p1) * t + p1;
\r
12348 var p23 = (p3 - p2) * t + p2;
\r
12350 var p012 = (p12 - p01) * t + p01;
\r
12351 var p123 = (p23 - p12) * t + p12;
\r
12353 var p0123 = (p123 - p012) * t + p012;
\r
12367 * 投射点到三次贝塞尔曲线上,返回投射距离。
\r
12368 * 投射点有可能会有一个或者多个,这里只返回其中距离最短的一个。
\r
12369 * @param {number} x0
\r
12370 * @param {number} y0
\r
12371 * @param {number} x1
\r
12372 * @param {number} y1
\r
12373 * @param {number} x2
\r
12374 * @param {number} y2
\r
12375 * @param {number} x3
\r
12376 * @param {number} y3
\r
12377 * @param {number} x
\r
12378 * @param {number} y
\r
12379 * @param {Array.<number>} [out] 投射点
\r
12380 * @return {number}
\r
12382 function cubicProjectPoint(
\r
12383 x0, y0, x1, y1, x2, y2, x3, y3,
\r
12386 // http://pomax.github.io/bezierinfo/#projections
\r
12388 var interval = 0.005;
\r
12389 var d = Infinity;
\r
12398 // 先粗略估计一下可能的最小距离的 t 值
\r
12400 for (var _t = 0; _t < 1; _t += 0.05) {
\r
12401 _v1[0] = cubicAt(x0, x1, x2, x3, _t);
\r
12402 _v1[1] = cubicAt(y0, y1, y2, y3, _t);
\r
12403 d1 = v2DistSquare(_v0, _v1);
\r
12411 // At most 32 iteration
\r
12412 for (var i = 0; i < 32; i++) {
\r
12413 if (interval < EPSILON_NUMERIC) {
\r
12416 prev = t - interval;
\r
12417 next = t + interval;
\r
12419 _v1[0] = cubicAt(x0, x1, x2, x3, prev);
\r
12420 _v1[1] = cubicAt(y0, y1, y2, y3, prev);
\r
12422 d1 = v2DistSquare(_v1, _v0);
\r
12424 if (prev >= 0 && d1 < d) {
\r
12430 _v2[0] = cubicAt(x0, x1, x2, x3, next);
\r
12431 _v2[1] = cubicAt(y0, y1, y2, y3, next);
\r
12432 d2 = v2DistSquare(_v2, _v0);
\r
12434 if (next <= 1 && d2 < d) {
\r
12445 out[0] = cubicAt(x0, x1, x2, x3, t);
\r
12446 out[1] = cubicAt(y0, y1, y2, y3, t);
\r
12448 // console.log(interval, i);
\r
12449 return mathSqrt(d);
\r
12454 * @param {number} p0
\r
12455 * @param {number} p1
\r
12456 * @param {number} p2
\r
12457 * @param {number} t
\r
12458 * @return {number}
\r
12460 function quadraticAt(p0, p1, p2, t) {
\r
12461 var onet = 1 - t;
\r
12462 return onet * (onet * p0 + 2 * t * p1) + t * t * p2;
\r
12467 * @param {number} p0
\r
12468 * @param {number} p1
\r
12469 * @param {number} p2
\r
12470 * @param {number} t
\r
12471 * @return {number}
\r
12473 function quadraticDerivativeAt(p0, p1, p2, t) {
\r
12474 return 2 * ((1 - t) * (p1 - p0) + t * (p2 - p1));
\r
12479 * @param {number} p0
\r
12480 * @param {number} p1
\r
12481 * @param {number} p2
\r
12482 * @param {number} t
\r
12483 * @param {Array.<number>} roots
\r
12484 * @return {number} 有效根数目
\r
12486 function quadraticRootAt(p0, p1, p2, val, roots) {
\r
12487 var a = p0 - 2 * p1 + p2;
\r
12488 var b = 2 * (p1 - p0);
\r
12489 var c = p0 - val;
\r
12492 if (isAroundZero(a)) {
\r
12493 if (isNotAroundZero(b)) {
\r
12495 if (t1 >= 0 && t1 <= 1) {
\r
12501 var disc = b * b - 4 * a * c;
\r
12502 if (isAroundZero(disc)) {
\r
12503 var t1 = -b / (2 * a);
\r
12504 if (t1 >= 0 && t1 <= 1) {
\r
12508 else if (disc > 0) {
\r
12509 var discSqrt = mathSqrt(disc);
\r
12510 var t1 = (-b + discSqrt) / (2 * a);
\r
12511 var t2 = (-b - discSqrt) / (2 * a);
\r
12512 if (t1 >= 0 && t1 <= 1) {
\r
12515 if (t2 >= 0 && t2 <= 1) {
\r
12525 * @memberOf module:zrender/core/curve
\r
12526 * @param {number} p0
\r
12527 * @param {number} p1
\r
12528 * @param {number} p2
\r
12529 * @return {number}
\r
12531 function quadraticExtremum(p0, p1, p2) {
\r
12532 var divider = p0 + p2 - 2 * p1;
\r
12533 if (divider === 0) {
\r
12534 // p1 is center of p0 and p2
\r
12538 return (p0 - p1) / divider;
\r
12544 * @memberOf module:zrender/core/curve
\r
12545 * @param {number} p0
\r
12546 * @param {number} p1
\r
12547 * @param {number} p2
\r
12548 * @param {number} t
\r
12549 * @param {Array.<number>} out
\r
12551 function quadraticSubdivide(p0, p1, p2, t, out) {
\r
12552 var p01 = (p1 - p0) * t + p0;
\r
12553 var p12 = (p2 - p1) * t + p1;
\r
12554 var p012 = (p12 - p01) * t + p01;
\r
12568 * 投射点到二次贝塞尔曲线上,返回投射距离。
\r
12569 * 投射点有可能会有一个或者多个,这里只返回其中距离最短的一个。
\r
12570 * @param {number} x0
\r
12571 * @param {number} y0
\r
12572 * @param {number} x1
\r
12573 * @param {number} y1
\r
12574 * @param {number} x2
\r
12575 * @param {number} y2
\r
12576 * @param {number} x
\r
12577 * @param {number} y
\r
12578 * @param {Array.<number>} out 投射点
\r
12579 * @return {number}
\r
12581 function quadraticProjectPoint(
\r
12582 x0, y0, x1, y1, x2, y2,
\r
12585 // http://pomax.github.io/bezierinfo/#projections
\r
12587 var interval = 0.005;
\r
12588 var d = Infinity;
\r
12593 // 先粗略估计一下可能的最小距离的 t 值
\r
12595 for (var _t = 0; _t < 1; _t += 0.05) {
\r
12596 _v1[0] = quadraticAt(x0, x1, x2, _t);
\r
12597 _v1[1] = quadraticAt(y0, y1, y2, _t);
\r
12598 var d1 = v2DistSquare(_v0, _v1);
\r
12606 // At most 32 iteration
\r
12607 for (var i = 0; i < 32; i++) {
\r
12608 if (interval < EPSILON_NUMERIC) {
\r
12611 var prev = t - interval;
\r
12612 var next = t + interval;
\r
12614 _v1[0] = quadraticAt(x0, x1, x2, prev);
\r
12615 _v1[1] = quadraticAt(y0, y1, y2, prev);
\r
12617 var d1 = v2DistSquare(_v1, _v0);
\r
12619 if (prev >= 0 && d1 < d) {
\r
12625 _v2[0] = quadraticAt(x0, x1, x2, next);
\r
12626 _v2[1] = quadraticAt(y0, y1, y2, next);
\r
12627 var d2 = v2DistSquare(_v2, _v0);
\r
12628 if (next <= 1 && d2 < d) {
\r
12639 out[0] = quadraticAt(x0, x1, x2, t);
\r
12640 out[1] = quadraticAt(y0, y1, y2, t);
\r
12642 // console.log(interval, i);
\r
12643 return mathSqrt(d);
\r
12646 module.exports = {
\r
12648 cubicAt: cubicAt,
\r
12650 cubicDerivativeAt: cubicDerivativeAt,
\r
12652 cubicRootAt: cubicRootAt,
\r
12654 cubicExtrema: cubicExtrema,
\r
12656 cubicSubdivide: cubicSubdivide,
\r
12658 cubicProjectPoint: cubicProjectPoint,
\r
12660 quadraticAt: quadraticAt,
\r
12662 quadraticDerivativeAt: quadraticDerivativeAt,
\r
12664 quadraticRootAt: quadraticRootAt,
\r
12666 quadraticExtremum: quadraticExtremum,
\r
12668 quadraticSubdivide: quadraticSubdivide,
\r
12670 quadraticProjectPoint: quadraticProjectPoint
\r
12676 /***/ function(module, exports, __webpack_require__) {
\r
12679 * @author Yi Shen(https://github.com/pissang)
\r
12683 var vec2 = __webpack_require__(16);
\r
12684 var curve = __webpack_require__(49);
\r
12687 var mathMin = Math.min;
\r
12688 var mathMax = Math.max;
\r
12689 var mathSin = Math.sin;
\r
12690 var mathCos = Math.cos;
\r
12692 var start = vec2.create();
\r
12693 var end = vec2.create();
\r
12694 var extremity = vec2.create();
\r
12696 var PI2 = Math.PI * 2;
\r
12698 * 从顶点数组中计算出最小包围盒,写入`min`和`max`中
\r
12699 * @module zrender/core/bbox
\r
12700 * @param {Array<Object>} points 顶点数组
\r
12701 * @param {number} min
\r
12702 * @param {number} max
\r
12704 bbox.fromPoints = function(points, min, max) {
\r
12705 if (points.length === 0) {
\r
12708 var p = points[0];
\r
12710 var right = p[0];
\r
12712 var bottom = p[1];
\r
12715 for (i = 1; i < points.length; i++) {
\r
12717 left = mathMin(left, p[0]);
\r
12718 right = mathMax(right, p[0]);
\r
12719 top = mathMin(top, p[1]);
\r
12720 bottom = mathMax(bottom, p[1]);
\r
12730 * @memberOf module:zrender/core/bbox
\r
12731 * @param {number} x0
\r
12732 * @param {number} y0
\r
12733 * @param {number} x1
\r
12734 * @param {number} y1
\r
12735 * @param {Array.<number>} min
\r
12736 * @param {Array.<number>} max
\r
12738 bbox.fromLine = function (x0, y0, x1, y1, min, max) {
\r
12739 min[0] = mathMin(x0, x1);
\r
12740 min[1] = mathMin(y0, y1);
\r
12741 max[0] = mathMax(x0, x1);
\r
12742 max[1] = mathMax(y0, y1);
\r
12748 * 从三阶贝塞尔曲线(p0, p1, p2, p3)中计算出最小包围盒,写入`min`和`max`中
\r
12749 * @memberOf module:zrender/core/bbox
\r
12750 * @param {number} x0
\r
12751 * @param {number} y0
\r
12752 * @param {number} x1
\r
12753 * @param {number} y1
\r
12754 * @param {number} x2
\r
12755 * @param {number} y2
\r
12756 * @param {number} x3
\r
12757 * @param {number} y3
\r
12758 * @param {Array.<number>} min
\r
12759 * @param {Array.<number>} max
\r
12761 bbox.fromCubic = function(
\r
12762 x0, y0, x1, y1, x2, y2, x3, y3, min, max
\r
12764 var cubicExtrema = curve.cubicExtrema;
\r
12765 var cubicAt = curve.cubicAt;
\r
12767 var n = cubicExtrema(x0, x1, x2, x3, xDim);
\r
12768 min[0] = Infinity;
\r
12769 min[1] = Infinity;
\r
12770 max[0] = -Infinity;
\r
12771 max[1] = -Infinity;
\r
12773 for (i = 0; i < n; i++) {
\r
12774 var x = cubicAt(x0, x1, x2, x3, xDim[i]);
\r
12775 min[0] = mathMin(x, min[0]);
\r
12776 max[0] = mathMax(x, max[0]);
\r
12778 n = cubicExtrema(y0, y1, y2, y3, yDim);
\r
12779 for (i = 0; i < n; i++) {
\r
12780 var y = cubicAt(y0, y1, y2, y3, yDim[i]);
\r
12781 min[1] = mathMin(y, min[1]);
\r
12782 max[1] = mathMax(y, max[1]);
\r
12785 min[0] = mathMin(x0, min[0]);
\r
12786 max[0] = mathMax(x0, max[0]);
\r
12787 min[0] = mathMin(x3, min[0]);
\r
12788 max[0] = mathMax(x3, max[0]);
\r
12790 min[1] = mathMin(y0, min[1]);
\r
12791 max[1] = mathMax(y0, max[1]);
\r
12792 min[1] = mathMin(y3, min[1]);
\r
12793 max[1] = mathMax(y3, max[1]);
\r
12797 * 从二阶贝塞尔曲线(p0, p1, p2)中计算出最小包围盒,写入`min`和`max`中
\r
12798 * @memberOf module:zrender/core/bbox
\r
12799 * @param {number} x0
\r
12800 * @param {number} y0
\r
12801 * @param {number} x1
\r
12802 * @param {number} y1
\r
12803 * @param {number} x2
\r
12804 * @param {number} y2
\r
12805 * @param {Array.<number>} min
\r
12806 * @param {Array.<number>} max
\r
12808 bbox.fromQuadratic = function(x0, y0, x1, y1, x2, y2, min, max) {
\r
12809 var quadraticExtremum = curve.quadraticExtremum;
\r
12810 var quadraticAt = curve.quadraticAt;
\r
12811 // Find extremities, where derivative in x dim or y dim is zero
\r
12814 mathMin(quadraticExtremum(x0, x1, x2), 1), 0
\r
12818 mathMin(quadraticExtremum(y0, y1, y2), 1), 0
\r
12821 var x = quadraticAt(x0, x1, x2, tx);
\r
12822 var y = quadraticAt(y0, y1, y2, ty);
\r
12824 min[0] = mathMin(x0, x2, x);
\r
12825 min[1] = mathMin(y0, y2, y);
\r
12826 max[0] = mathMax(x0, x2, x);
\r
12827 max[1] = mathMax(y0, y2, y);
\r
12831 * 从圆弧中计算出最小包围盒,写入`min`和`max`中
\r
12833 * @memberOf module:zrender/core/bbox
\r
12834 * @param {number} x
\r
12835 * @param {number} y
\r
12836 * @param {number} rx
\r
12837 * @param {number} ry
\r
12838 * @param {number} startAngle
\r
12839 * @param {number} endAngle
\r
12840 * @param {number} anticlockwise
\r
12841 * @param {Array.<number>} min
\r
12842 * @param {Array.<number>} max
\r
12844 bbox.fromArc = function (
\r
12845 x, y, rx, ry, startAngle, endAngle, anticlockwise, min, max
\r
12847 var vec2Min = vec2.min;
\r
12848 var vec2Max = vec2.max;
\r
12850 var diff = Math.abs(startAngle - endAngle);
\r
12853 if (diff % PI2 < 1e-4 && diff > 1e-4) {
\r
12862 start[0] = mathCos(startAngle) * rx + x;
\r
12863 start[1] = mathSin(startAngle) * ry + y;
\r
12865 end[0] = mathCos(endAngle) * rx + x;
\r
12866 end[1] = mathSin(endAngle) * ry + y;
\r
12868 vec2Min(min, start, end);
\r
12869 vec2Max(max, start, end);
\r
12871 // Thresh to [0, Math.PI * 2]
\r
12872 startAngle = startAngle % (PI2);
\r
12873 if (startAngle < 0) {
\r
12874 startAngle = startAngle + PI2;
\r
12876 endAngle = endAngle % (PI2);
\r
12877 if (endAngle < 0) {
\r
12878 endAngle = endAngle + PI2;
\r
12881 if (startAngle > endAngle && !anticlockwise) {
\r
12884 else if (startAngle < endAngle && anticlockwise) {
\r
12885 startAngle += PI2;
\r
12887 if (anticlockwise) {
\r
12888 var tmp = endAngle;
\r
12889 endAngle = startAngle;
\r
12890 startAngle = tmp;
\r
12893 // var number = 0;
\r
12894 // var step = (anticlockwise ? -Math.PI : Math.PI) / 2;
\r
12895 for (var angle = 0; angle < endAngle; angle += Math.PI / 2) {
\r
12896 if (angle > startAngle) {
\r
12897 extremity[0] = mathCos(angle) * rx + x;
\r
12898 extremity[1] = mathSin(angle) * ry + y;
\r
12900 vec2Min(min, extremity, min);
\r
12901 vec2Max(max, extremity, max);
\r
12906 module.exports = bbox;
\r
12912 /***/ function(module, exports, __webpack_require__) {
\r
12917 var CMD = __webpack_require__(48).CMD;
\r
12918 var line = __webpack_require__(52);
\r
12919 var cubic = __webpack_require__(53);
\r
12920 var quadratic = __webpack_require__(54);
\r
12921 var arc = __webpack_require__(55);
\r
12922 var normalizeRadian = __webpack_require__(56).normalizeRadian;
\r
12923 var curve = __webpack_require__(49);
\r
12925 var windingLine = __webpack_require__(57);
\r
12927 var containStroke = line.containStroke;
\r
12929 var PI2 = Math.PI * 2;
\r
12931 var EPSILON = 1e-4;
\r
12933 function isAroundEqual(a, b) {
\r
12934 return Math.abs(a - b) < EPSILON;
\r
12938 var roots = [-1, -1, -1];
\r
12939 var extrema = [-1, -1];
\r
12941 function swapExtrema() {
\r
12942 var tmp = extrema[0];
\r
12943 extrema[0] = extrema[1];
\r
12944 extrema[1] = tmp;
\r
12947 function windingCubic(x0, y0, x1, y1, x2, y2, x3, y3, x, y) {
\r
12950 (y > y0 && y > y1 && y > y2 && y > y3)
\r
12951 || (y < y0 && y < y1 && y < y2 && y < y3)
\r
12955 var nRoots = curve.cubicRootAt(y0, y1, y2, y3, y, roots);
\r
12956 if (nRoots === 0) {
\r
12961 var nExtrema = -1;
\r
12963 for (var i = 0; i < nRoots; i++) {
\r
12964 var t = roots[i];
\r
12965 var x_ = curve.cubicAt(x0, x1, x2, x3, t);
\r
12966 if (x_ < x) { // Quick reject
\r
12969 if (nExtrema < 0) {
\r
12970 nExtrema = curve.cubicExtrema(y0, y1, y2, y3, extrema);
\r
12971 if (extrema[1] < extrema[0] && nExtrema > 1) {
\r
12974 y0_ = curve.cubicAt(y0, y1, y2, y3, extrema[0]);
\r
12975 if (nExtrema > 1) {
\r
12976 y1_ = curve.cubicAt(y0, y1, y2, y3, extrema[1]);
\r
12979 if (nExtrema == 2) {
\r
12981 if (t < extrema[0]) {
\r
12982 w += y0_ < y0 ? 1 : -1;
\r
12984 else if (t < extrema[1]) {
\r
12985 w += y1_ < y0_ ? 1 : -1;
\r
12988 w += y3 < y1_ ? 1 : -1;
\r
12993 if (t < extrema[0]) {
\r
12994 w += y0_ < y0 ? 1 : -1;
\r
12997 w += y3 < y0_ ? 1 : -1;
\r
13005 function windingQuadratic(x0, y0, x1, y1, x2, y2, x, y) {
\r
13008 (y > y0 && y > y1 && y > y2)
\r
13009 || (y < y0 && y < y1 && y < y2)
\r
13013 var nRoots = curve.quadraticRootAt(y0, y1, y2, y, roots);
\r
13014 if (nRoots === 0) {
\r
13018 var t = curve.quadraticExtremum(y0, y1, y2);
\r
13019 if (t >= 0 && t <= 1) {
\r
13021 var y_ = curve.quadraticAt(y0, y1, y2, t);
\r
13022 for (var i = 0; i < nRoots; i++) {
\r
13023 var x_ = curve.quadraticAt(x0, x1, x2, roots[i]);
\r
13024 if (x_ < x) { // Quick reject
\r
13027 if (roots[i] < t) {
\r
13028 w += y_ < y0 ? 1 : -1;
\r
13031 w += y2 < y_ ? 1 : -1;
\r
13037 var x_ = curve.quadraticAt(x0, x1, x2, roots[0]);
\r
13038 if (x_ < x) { // Quick reject
\r
13041 return y2 < y0 ? 1 : -1;
\r
13048 function windingArc(
\r
13049 cx, cy, r, startAngle, endAngle, anticlockwise, x, y
\r
13052 if (y > r || y < -r) {
\r
13055 var tmp = Math.sqrt(r * r - y * y);
\r
13059 var diff = Math.abs(startAngle - endAngle);
\r
13060 if (diff < 1e-4) {
\r
13063 if (diff % PI2 < 1e-4) {
\r
13067 var dir = anticlockwise ? 1 : -1;
\r
13068 if (x >= roots[0] + cx && x <= roots[1] + cx) {
\r
13075 if (anticlockwise) {
\r
13076 var tmp = startAngle;
\r
13077 startAngle = normalizeRadian(endAngle);
\r
13078 endAngle = normalizeRadian(tmp);
\r
13081 startAngle = normalizeRadian(startAngle);
\r
13082 endAngle = normalizeRadian(endAngle);
\r
13084 if (startAngle > endAngle) {
\r
13089 for (var i = 0; i < 2; i++) {
\r
13090 var x_ = roots[i];
\r
13091 if (x_ + cx > x) {
\r
13092 var angle = Math.atan2(y, x_);
\r
13093 var dir = anticlockwise ? 1 : -1;
\r
13095 angle = PI2 + angle;
\r
13098 (angle >= startAngle && angle <= endAngle)
\r
13099 || (angle + PI2 >= startAngle && angle + PI2 <= endAngle)
\r
13101 if (angle > Math.PI / 2 && angle < Math.PI * 1.5) {
\r
13111 function containPath(data, lineWidth, isStroke, x, y) {
\r
13118 for (var i = 0; i < data.length;) {
\r
13119 var cmd = data[i++];
\r
13120 // Begin a new subpath
\r
13121 if (cmd === CMD.M && i > 1) {
\r
13122 // Close previous subpath
\r
13124 w += windingLine(xi, yi, x0, y0, x, y);
\r
13126 // 如果被任何一个 subpath 包含
\r
13133 // 如果第一个命令是 L, C, Q
\r
13134 // 则 previous point 同绘制命令的第一个 point
\r
13136 // 第一个命令为 Arc 的情况下会在后面特殊处理
\r
13138 yi = data[i + 1];
\r
13146 // moveTo 命令重新创建一个新的 subpath, 并且更新新的起点
\r
13147 // 在 closePath 的时候使用
\r
13155 if (containStroke(xi, yi, data[i], data[i + 1], lineWidth, x, y)) {
\r
13160 // NOTE 在第一个命令为 L, C, Q 的时候会计算出 NaN
\r
13161 w += windingLine(xi, yi, data[i], data[i + 1], x, y) || 0;
\r
13168 if (cubic.containStroke(xi, yi,
\r
13169 data[i++], data[i++], data[i++], data[i++], data[i], data[i + 1],
\r
13176 w += windingCubic(
\r
13178 data[i++], data[i++], data[i++], data[i++], data[i], data[i + 1],
\r
13187 if (quadratic.containStroke(xi, yi,
\r
13188 data[i++], data[i++], data[i], data[i + 1],
\r
13195 w += windingQuadratic(
\r
13197 data[i++], data[i++], data[i], data[i + 1],
\r
13205 // TODO Arc 判断的开销比较大
\r
13206 var cx = data[i++];
\r
13207 var cy = data[i++];
\r
13208 var rx = data[i++];
\r
13209 var ry = data[i++];
\r
13210 var theta = data[i++];
\r
13211 var dTheta = data[i++];
\r
13213 var psi = data[i++];
\r
13214 var anticlockwise = 1 - data[i++];
\r
13215 var x1 = Math.cos(theta) * rx + cx;
\r
13216 var y1 = Math.sin(theta) * ry + cy;
\r
13219 w += windingLine(xi, yi, x1, y1, x, y);
\r
13226 // zr 使用scale来模拟椭圆, 这里也对x做一定的缩放
\r
13227 var _x = (x - cx) * ry / rx + cx;
\r
13229 if (arc.containStroke(
\r
13230 cx, cy, ry, theta, theta + dTheta, anticlockwise,
\r
13238 cx, cy, ry, theta, theta + dTheta, anticlockwise,
\r
13242 xi = Math.cos(theta + dTheta) * rx + cx;
\r
13243 yi = Math.sin(theta + dTheta) * ry + cy;
\r
13246 x0 = xi = data[i++];
\r
13247 y0 = yi = data[i++];
\r
13248 var width = data[i++];
\r
13249 var height = data[i++];
\r
13250 var x1 = x0 + width;
\r
13251 var y1 = y0 + height;
\r
13253 if (containStroke(x0, y0, x1, y0, lineWidth, x, y)
\r
13254 || containStroke(x1, y0, x1, y1, lineWidth, x, y)
\r
13255 || containStroke(x1, y1, x0, y1, lineWidth, x, y)
\r
13256 || containStroke(x0, y1, x1, y1, lineWidth, x, y)
\r
13262 // FIXME Clockwise ?
\r
13263 w += windingLine(x1, y0, x1, y1, x, y);
\r
13264 w += windingLine(x0, y1, x0, y0, x, y);
\r
13269 if (containStroke(
\r
13270 xi, yi, x0, y0, lineWidth, x, y
\r
13276 // Close a subpath
\r
13277 w += windingLine(xi, yi, x0, y0, x, y);
\r
13278 // 如果被任何一个 subpath 包含
\r
13288 if (!isStroke && !isAroundEqual(yi, y0)) {
\r
13289 w += windingLine(xi, yi, x0, y0, x, y) || 0;
\r
13294 module.exports = {
\r
13295 contain: function (pathData, x, y) {
\r
13296 return containPath(pathData, 0, false, x, y);
\r
13299 containStroke: function (pathData, lineWidth, x, y) {
\r
13300 return containPath(pathData, lineWidth, true, x, y);
\r
13307 /***/ function(module, exports) {
\r
13310 module.exports = {
\r
13313 * @param {number} x0
\r
13314 * @param {number} y0
\r
13315 * @param {number} x1
\r
13316 * @param {number} y1
\r
13317 * @param {number} lineWidth
\r
13318 * @param {number} x
\r
13319 * @param {number} y
\r
13320 * @return {boolean}
\r
13322 containStroke: function (x0, y0, x1, y1, lineWidth, x, y) {
\r
13323 if (lineWidth === 0) {
\r
13326 var _l = lineWidth;
\r
13331 (y > y0 + _l && y > y1 + _l)
\r
13332 || (y < y0 - _l && y < y1 - _l)
\r
13333 || (x > x0 + _l && x > x1 + _l)
\r
13334 || (x < x0 - _l && x < x1 - _l)
\r
13340 _a = (y0 - y1) / (x0 - x1);
\r
13341 _b = (x0 * y1 - x1 * y0) / (x0 - x1) ;
\r
13344 return Math.abs(x - x0) <= _l / 2;
\r
13346 var tmp = _a * x - y + _b;
\r
13347 var _s = tmp * tmp / (_a * _a + 1);
\r
13348 return _s <= _l / 2 * _l / 2;
\r
13355 /***/ function(module, exports, __webpack_require__) {
\r
13359 var curve = __webpack_require__(49);
\r
13361 module.exports = {
\r
13364 * @param {number} x0
\r
13365 * @param {number} y0
\r
13366 * @param {number} x1
\r
13367 * @param {number} y1
\r
13368 * @param {number} x2
\r
13369 * @param {number} y2
\r
13370 * @param {number} x3
\r
13371 * @param {number} y3
\r
13372 * @param {number} lineWidth
\r
13373 * @param {number} x
\r
13374 * @param {number} y
\r
13375 * @return {boolean}
\r
13377 containStroke: function(x0, y0, x1, y1, x2, y2, x3, y3, lineWidth, x, y) {
\r
13378 if (lineWidth === 0) {
\r
13381 var _l = lineWidth;
\r
13384 (y > y0 + _l && y > y1 + _l && y > y2 + _l && y > y3 + _l)
\r
13385 || (y < y0 - _l && y < y1 - _l && y < y2 - _l && y < y3 - _l)
\r
13386 || (x > x0 + _l && x > x1 + _l && x > x2 + _l && x > x3 + _l)
\r
13387 || (x < x0 - _l && x < x1 - _l && x < x2 - _l && x < x3 - _l)
\r
13391 var d = curve.cubicProjectPoint(
\r
13392 x0, y0, x1, y1, x2, y2, x3, y3,
\r
13395 return d <= _l / 2;
\r
13402 /***/ function(module, exports, __webpack_require__) {
\r
13406 var curve = __webpack_require__(49);
\r
13408 module.exports = {
\r
13411 * @param {number} x0
\r
13412 * @param {number} y0
\r
13413 * @param {number} x1
\r
13414 * @param {number} y1
\r
13415 * @param {number} x2
\r
13416 * @param {number} y2
\r
13417 * @param {number} lineWidth
\r
13418 * @param {number} x
\r
13419 * @param {number} y
\r
13420 * @return {boolean}
\r
13422 containStroke: function (x0, y0, x1, y1, x2, y2, lineWidth, x, y) {
\r
13423 if (lineWidth === 0) {
\r
13426 var _l = lineWidth;
\r
13429 (y > y0 + _l && y > y1 + _l && y > y2 + _l)
\r
13430 || (y < y0 - _l && y < y1 - _l && y < y2 - _l)
\r
13431 || (x > x0 + _l && x > x1 + _l && x > x2 + _l)
\r
13432 || (x < x0 - _l && x < x1 - _l && x < x2 - _l)
\r
13436 var d = curve.quadraticProjectPoint(
\r
13437 x0, y0, x1, y1, x2, y2,
\r
13440 return d <= _l / 2;
\r
13447 /***/ function(module, exports, __webpack_require__) {
\r
13451 var normalizeRadian = __webpack_require__(56).normalizeRadian;
\r
13452 var PI2 = Math.PI * 2;
\r
13454 module.exports = {
\r
13457 * @param {number} cx
\r
13458 * @param {number} cy
\r
13459 * @param {number} r
\r
13460 * @param {number} startAngle
\r
13461 * @param {number} endAngle
\r
13462 * @param {boolean} anticlockwise
\r
13463 * @param {number} lineWidth
\r
13464 * @param {number} x
\r
13465 * @param {number} y
\r
13466 * @return {Boolean}
\r
13468 containStroke: function (
\r
13469 cx, cy, r, startAngle, endAngle, anticlockwise,
\r
13473 if (lineWidth === 0) {
\r
13476 var _l = lineWidth;
\r
13480 var d = Math.sqrt(x * x + y * y);
\r
13482 if ((d - _l > r) || (d + _l < r)) {
\r
13485 if (Math.abs(startAngle - endAngle) % PI2 < 1e-4) {
\r
13489 if (anticlockwise) {
\r
13490 var tmp = startAngle;
\r
13491 startAngle = normalizeRadian(endAngle);
\r
13492 endAngle = normalizeRadian(tmp);
\r
13494 startAngle = normalizeRadian(startAngle);
\r
13495 endAngle = normalizeRadian(endAngle);
\r
13497 if (startAngle > endAngle) {
\r
13501 var angle = Math.atan2(y, x);
\r
13505 return (angle >= startAngle && angle <= endAngle)
\r
13506 || (angle + PI2 >= startAngle && angle + PI2 <= endAngle);
\r
13513 /***/ function(module, exports) {
\r
13517 var PI2 = Math.PI * 2;
\r
13518 module.exports = {
\r
13519 normalizeRadian: function(angle) {
\r
13531 /***/ function(module, exports) {
\r
13534 module.exports = function windingLine(x0, y0, x1, y1, x, y) {
\r
13535 if ((y > y0 && y > y1) || (y < y0 && y < y1)) {
\r
13541 var dir = y1 < y0 ? 1 : -1;
\r
13542 var t = (y - y0) / (y1 - y0);
\r
13543 var x_ = t * (x1 - x0) + x0;
\r
13545 return x_ > x ? dir : 0;
\r
13551 /***/ function(module, exports, __webpack_require__) {
\r
13555 var CMD = __webpack_require__(48).CMD;
\r
13556 var vec2 = __webpack_require__(16);
\r
13557 var v2ApplyTransform = vec2.applyTransform;
\r
13559 var points = [[], [], []];
\r
13560 var mathSqrt = Math.sqrt;
\r
13561 var mathAtan2 = Math.atan2;
\r
13562 function transformPath(path, m) {
\r
13563 var data = path.data;
\r
13578 for (i = 0, j = 0; i < data.length;) {
\r
13599 var sx = mathSqrt(m[0] * m[0] + m[1] * m[1]);
\r
13600 var sy = mathSqrt(m[2] * m[2] + m[3] * m[3]);
\r
13601 var angle = mathAtan2(-m[1] / sy, m[0] / sx);
\r
13606 // Scale rx and ry
\r
13607 // FIXME Assume psi is 0 here
\r
13612 data[i++] += angle;
\r
13614 data[i++] += angle;
\r
13621 p[0] = data[i++];
\r
13622 p[1] = data[i++];
\r
13623 v2ApplyTransform(p, p, m);
\r
13624 data[j++] = p[0];
\r
13625 data[j++] = p[1];
\r
13627 p[0] += data[i++];
\r
13628 p[1] += data[i++];
\r
13629 v2ApplyTransform(p, p, m);
\r
13630 data[j++] = p[0];
\r
13631 data[j++] = p[1];
\r
13634 for (k = 0; k < nPoint; k++) {
\r
13635 var p = points[k];
\r
13636 p[0] = data[i++];
\r
13637 p[1] = data[i++];
\r
13639 v2ApplyTransform(p, p, m);
\r
13641 data[j++] = p[0];
\r
13642 data[j++] = p[1];
\r
13647 module.exports = transformPath;
\r
13652 /***/ function(module, exports, __webpack_require__) {
\r
13656 * @module zrender/graphic/Image
\r
13661 var Displayable = __webpack_require__(45);
\r
13662 var BoundingRect = __webpack_require__(15);
\r
13663 var zrUtil = __webpack_require__(3);
\r
13664 var roundRectHelper = __webpack_require__(60);
\r
13666 var LRU = __webpack_require__(61);
\r
13667 var globalImageCache = new LRU(50);
\r
13669 * @alias zrender/graphic/Image
\r
13670 * @extends module:zrender/graphic/Displayable
\r
13672 * @param {Object} opts
\r
13674 function ZImage(opts) {
\r
13675 Displayable.call(this, opts);
\r
13678 ZImage.prototype = {
\r
13680 constructor: ZImage,
\r
13684 brush: function (ctx) {
\r
13685 var style = this.style;
\r
13686 var src = style.image;
\r
13688 // style.image is a url string
\r
13689 if (typeof src === 'string') {
\r
13690 image = this._image;
\r
13692 // style.image is an HTMLImageElement or HTMLCanvasElement or Canvas
\r
13696 // FIXME Case create many images with src
\r
13697 if (!image && src) {
\r
13698 // Try get from global image cache
\r
13699 var cachedImgObj = globalImageCache.get(src);
\r
13700 if (!cachedImgObj) {
\r
13701 // Create a new image
\r
13702 image = new Image();
\r
13703 image.onload = function () {
\r
13704 image.onload = null;
\r
13705 for (var i = 0; i < cachedImgObj.pending.length; i++) {
\r
13706 cachedImgObj.pending[i].dirty();
\r
13714 globalImageCache.put(src, cachedImgObj);
\r
13715 this._image = image;
\r
13719 image = cachedImgObj.image;
\r
13720 this._image = image;
\r
13721 // Image is not complete finish, add to pending list
\r
13722 if (!image.width || !image.height) {
\r
13723 cachedImgObj.pending.push(this);
\r
13731 // if (image.nodeName.toUpperCase() == 'IMG') {
\r
13732 // if (!image.complete) {
\r
13736 // Else is canvas
\r
13738 var width = style.width || image.width;
\r
13739 var height = style.height || image.height;
\r
13740 var x = style.x || 0;
\r
13741 var y = style.y || 0;
\r
13743 if (!image.width || !image.height) {
\r
13752 this.setTransform(ctx);
\r
13755 // Border radius clipping
\r
13758 roundRectHelper.buildPath(ctx, style);
\r
13762 if (style.sWidth && style.sHeight) {
\r
13763 var sx = style.sx || 0;
\r
13764 var sy = style.sy || 0;
\r
13767 sx, sy, style.sWidth, style.sHeight,
\r
13768 x, y, width, height
\r
13771 else if (style.sx && style.sy) {
\r
13772 var sx = style.sx;
\r
13773 var sy = style.sy;
\r
13774 var sWidth = width - sx;
\r
13775 var sHeight = height - sy;
\r
13778 sx, sy, sWidth, sHeight,
\r
13779 x, y, width, height
\r
13783 ctx.drawImage(image, x, y, width, height);
\r
13786 // 如果没设置宽和高的话自动根据图片宽高设置
\r
13787 if (style.width == null) {
\r
13788 style.width = width;
\r
13790 if (style.height == null) {
\r
13791 style.height = height;
\r
13794 // Draw rect text
\r
13795 if (style.text != null) {
\r
13796 this.drawRectText(ctx, this.getBoundingRect());
\r
13803 getBoundingRect: function () {
\r
13804 var style = this.style;
\r
13805 if (! this._rect) {
\r
13806 this._rect = new BoundingRect(
\r
13807 style.x || 0, style.y || 0, style.width || 0, style.height || 0
\r
13810 return this._rect;
\r
13814 zrUtil.inherits(ZImage, Displayable);
\r
13816 module.exports = ZImage;
\r
13821 /***/ function(module, exports) {
\r
13825 module.exports = {
\r
13826 buildPath: function (ctx, shape) {
\r
13829 var width = shape.width;
\r
13830 var height = shape.height;
\r
13837 // Convert width and height to positive for better borderRadius
\r
13842 if (height < 0) {
\r
13844 height = -height;
\r
13847 if (typeof r === 'number') {
\r
13848 r1 = r2 = r3 = r4 = r;
\r
13850 else if (r instanceof Array) {
\r
13851 if (r.length === 1) {
\r
13852 r1 = r2 = r3 = r4 = r[0];
\r
13854 else if (r.length === 2) {
\r
13858 else if (r.length === 3) {
\r
13871 r1 = r2 = r3 = r4 = 0;
\r
13875 if (r1 + r2 > width) {
\r
13877 r1 *= width / total;
\r
13878 r2 *= width / total;
\r
13880 if (r3 + r4 > width) {
\r
13882 r3 *= width / total;
\r
13883 r4 *= width / total;
\r
13885 if (r2 + r3 > height) {
\r
13887 r2 *= height / total;
\r
13888 r3 *= height / total;
\r
13890 if (r1 + r4 > height) {
\r
13892 r1 *= height / total;
\r
13893 r4 *= height / total;
\r
13895 ctx.moveTo(x + r1, y);
\r
13896 ctx.lineTo(x + width - r2, y);
\r
13897 r2 !== 0 && ctx.quadraticCurveTo(
\r
13898 x + width, y, x + width, y + r2
\r
13900 ctx.lineTo(x + width, y + height - r3);
\r
13901 r3 !== 0 && ctx.quadraticCurveTo(
\r
13902 x + width, y + height, x + width - r3, y + height
\r
13904 ctx.lineTo(x + r4, y + height);
\r
13905 r4 !== 0 && ctx.quadraticCurveTo(
\r
13906 x, y + height, x, y + height - r4
\r
13908 ctx.lineTo(x, y + r1);
\r
13909 r1 !== 0 && ctx.quadraticCurveTo(x, y, x + r1, y);
\r
13916 /***/ function(module, exports) {
\r
13918 // Simple LRU cache use doubly linked list
\r
13919 // @module zrender/core/LRU
\r
13923 * Simple double linked list. Compared with array, it has O(1) remove operation.
\r
13926 var LinkedList = function() {
\r
13929 * @type {module:zrender/core/LRU~Entry}
\r
13931 this.head = null;
\r
13934 * @type {module:zrender/core/LRU~Entry}
\r
13936 this.tail = null;
\r
13941 var linkedListProto = LinkedList.prototype;
\r
13943 * Insert a new value at the tail
\r
13945 * @return {module:zrender/core/LRU~Entry}
\r
13947 linkedListProto.insert = function(val) {
\r
13948 var entry = new Entry(val);
\r
13949 this.insertEntry(entry);
\r
13954 * Insert an entry at the tail
\r
13955 * @param {module:zrender/core/LRU~Entry} entry
\r
13957 linkedListProto.insertEntry = function(entry) {
\r
13958 if (!this.head) {
\r
13959 this.head = this.tail = entry;
\r
13962 this.tail.next = entry;
\r
13963 entry.prev = this.tail;
\r
13964 this.tail = entry;
\r
13971 * @param {module:zrender/core/LRU~Entry} entry
\r
13973 linkedListProto.remove = function(entry) {
\r
13974 var prev = entry.prev;
\r
13975 var next = entry.next;
\r
13977 prev.next = next;
\r
13981 this.head = next;
\r
13984 next.prev = prev;
\r
13988 this.tail = prev;
\r
13990 entry.next = entry.prev = null;
\r
13995 * @return {number}
\r
13997 linkedListProto.len = function() {
\r
13998 return this._len;
\r
14005 var Entry = function(val) {
\r
14009 this.value = val;
\r
14012 * @type {module:zrender/core/LRU~Entry}
\r
14017 * @type {module:zrender/core/LRU~Entry}
\r
14025 * @alias module:zrender/core/LRU
\r
14027 var LRU = function(maxSize) {
\r
14029 this._list = new LinkedList();
\r
14033 this._maxSize = maxSize || 10;
\r
14036 var LRUProto = LRU.prototype;
\r
14039 * @param {string} key
\r
14040 * @param {} value
\r
14042 LRUProto.put = function(key, value) {
\r
14043 var list = this._list;
\r
14044 var map = this._map;
\r
14045 if (map[key] == null) {
\r
14046 var len = list.len();
\r
14047 if (len >= this._maxSize && len > 0) {
\r
14048 // Remove the least recently used
\r
14049 var leastUsedEntry = list.head;
\r
14050 list.remove(leastUsedEntry);
\r
14051 delete map[leastUsedEntry.key];
\r
14054 var entry = list.insert(value);
\r
14056 map[key] = entry;
\r
14061 * @param {string} key
\r
14064 LRUProto.get = function(key) {
\r
14065 var entry = this._map[key];
\r
14066 var list = this._list;
\r
14067 if (entry != null) {
\r
14068 // Put the latest used entry in the tail
\r
14069 if (entry !== list.tail) {
\r
14070 list.remove(entry);
\r
14071 list.insertEntry(entry);
\r
14074 return entry.value;
\r
14079 * Clear the cache
\r
14081 LRUProto.clear = function() {
\r
14082 this._list.clear();
\r
14086 module.exports = LRU;
\r
14091 /***/ function(module, exports, __webpack_require__) {
\r
14095 * @module zrender/graphic/Text
\r
14102 var Displayable = __webpack_require__(45);
\r
14103 var zrUtil = __webpack_require__(3);
\r
14104 var textContain = __webpack_require__(14);
\r
14107 * @alias zrender/graphic/Text
\r
14108 * @extends module:zrender/graphic/Displayable
\r
14110 * @param {Object} opts
\r
14112 var Text = function (opts) {
\r
14113 Displayable.call(this, opts);
\r
14116 Text.prototype = {
\r
14118 constructor: Text,
\r
14122 brush: function (ctx) {
\r
14123 var style = this.style;
\r
14124 var x = style.x || 0;
\r
14125 var y = style.y || 0;
\r
14126 // Convert to string
\r
14127 var text = style.text;
\r
14128 var textFill = style.fill;
\r
14129 var textStroke = style.stroke;
\r
14131 // Convert to string
\r
14132 text != null && (text += '');
\r
14137 this.style.bind(ctx);
\r
14138 this.setTransform(ctx);
\r
14140 textFill && (ctx.fillStyle = textFill);
\r
14141 textStroke && (ctx.strokeStyle = textStroke);
\r
14143 ctx.font = style.textFont || style.font;
\r
14144 ctx.textAlign = style.textAlign;
\r
14146 if (style.textVerticalAlign) {
\r
14147 var rect = textContain.getBoundingRect(
\r
14148 text, ctx.font, style.textAlign, 'top'
\r
14150 // Ignore textBaseline
\r
14151 ctx.textBaseline = 'top';
\r
14152 switch (style.textVerticalAlign) {
\r
14154 y -= rect.height / 2;
\r
14157 y -= rect.height;
\r
14163 ctx.textBaseline = style.textBaseline;
\r
14165 var lineHeight = textContain.measureText('国', ctx.font).width;
\r
14167 var textLines = text.split('\n');
\r
14168 for (var i = 0; i < textLines.length; i++) {
\r
14169 textFill && ctx.fillText(textLines[i], x, y);
\r
14170 textStroke && ctx.strokeText(textLines[i], x, y);
\r
14178 getBoundingRect: function () {
\r
14179 if (!this._rect) {
\r
14180 var style = this.style;
\r
14181 var textVerticalAlign = style.textVerticalAlign;
\r
14182 var rect = textContain.getBoundingRect(
\r
14183 style.text + '', style.textFont || style.font, style.textAlign,
\r
14184 textVerticalAlign ? 'top' : style.textBaseline
\r
14186 switch (textVerticalAlign) {
\r
14188 rect.y -= rect.height / 2;
\r
14191 rect.y -= rect.height;
\r
14194 rect.x += style.x || 0;
\r
14195 rect.y += style.y || 0;
\r
14196 this._rect = rect;
\r
14198 return this._rect;
\r
14202 zrUtil.inherits(Text, Displayable);
\r
14204 module.exports = Text;
\r
14209 /***/ function(module, exports, __webpack_require__) {
\r
14214 * @module zrender/shape/Circle
\r
14219 module.exports = __webpack_require__(44).extend({
\r
14229 buildPath : function (ctx, shape) {
\r
14230 // Better stroking in ShapeBundle
\r
14231 ctx.moveTo(shape.cx + shape.r, shape.cy);
\r
14232 ctx.arc(shape.cx, shape.cy, shape.r, 0, Math.PI * 2, true);
\r
14241 /***/ function(module, exports, __webpack_require__) {
\r
14245 * @module zrender/graphic/shape/Sector
\r
14248 // FIXME clockwise seems wrong
\r
14251 module.exports = __webpack_require__(44).extend({
\r
14267 endAngle: Math.PI * 2,
\r
14272 buildPath: function (ctx, shape) {
\r
14274 var x = shape.cx;
\r
14275 var y = shape.cy;
\r
14276 var r0 = Math.max(shape.r0 || 0, 0);
\r
14277 var r = Math.max(shape.r, 0);
\r
14278 var startAngle = shape.startAngle;
\r
14279 var endAngle = shape.endAngle;
\r
14280 var clockwise = shape.clockwise;
\r
14282 var unitX = Math.cos(startAngle);
\r
14283 var unitY = Math.sin(startAngle);
\r
14285 ctx.moveTo(unitX * r0 + x, unitY * r0 + y);
\r
14287 ctx.lineTo(unitX * r + x, unitY * r + y);
\r
14289 ctx.arc(x, y, r, startAngle, endAngle, !clockwise);
\r
14292 Math.cos(endAngle) * r0 + x,
\r
14293 Math.sin(endAngle) * r0 + y
\r
14297 ctx.arc(x, y, r0, endAngle, startAngle, clockwise);
\r
14308 /***/ function(module, exports, __webpack_require__) {
\r
14312 * @module zrender/graphic/shape/Ring
\r
14316 module.exports = __webpack_require__(44).extend({
\r
14327 buildPath: function (ctx, shape) {
\r
14328 var x = shape.cx;
\r
14329 var y = shape.cy;
\r
14330 var PI2 = Math.PI * 2;
\r
14331 ctx.moveTo(x + shape.r, y);
\r
14332 ctx.arc(x, y, shape.r, 0, PI2, false);
\r
14333 ctx.moveTo(x + shape.r0, y);
\r
14334 ctx.arc(x, y, shape.r0, 0, PI2, true);
\r
14342 /***/ function(module, exports, __webpack_require__) {
\r
14346 * @module zrender/shape/Polygon
\r
14350 var polyHelper = __webpack_require__(67);
\r
14352 module.exports = __webpack_require__(44).extend({
\r
14361 smoothConstraint: null
\r
14364 buildPath: function (ctx, shape) {
\r
14365 polyHelper.buildPath(ctx, shape, true);
\r
14372 /***/ function(module, exports, __webpack_require__) {
\r
14376 var smoothSpline = __webpack_require__(68);
\r
14377 var smoothBezier = __webpack_require__(69);
\r
14379 module.exports = {
\r
14380 buildPath: function (ctx, shape, closePath) {
\r
14381 var points = shape.points;
\r
14382 var smooth = shape.smooth;
\r
14383 if (points && points.length >= 2) {
\r
14384 if (smooth && smooth !== 'spline') {
\r
14385 var controlPoints = smoothBezier(
\r
14386 points, smooth, closePath, shape.smoothConstraint
\r
14389 ctx.moveTo(points[0][0], points[0][1]);
\r
14390 var len = points.length;
\r
14391 for (var i = 0; i < (closePath ? len : len - 1); i++) {
\r
14392 var cp1 = controlPoints[i * 2];
\r
14393 var cp2 = controlPoints[i * 2 + 1];
\r
14394 var p = points[(i + 1) % len];
\r
14395 ctx.bezierCurveTo(
\r
14396 cp1[0], cp1[1], cp2[0], cp2[1], p[0], p[1]
\r
14401 if (smooth === 'spline') {
\r
14402 points = smoothSpline(points, closePath);
\r
14405 ctx.moveTo(points[0][0], points[0][1]);
\r
14406 for (var i = 1, l = points.length; i < l; i++) {
\r
14407 ctx.lineTo(points[i][0], points[i][1]);
\r
14411 closePath && ctx.closePath();
\r
14419 /***/ function(module, exports, __webpack_require__) {
\r
14422 * Catmull-Rom spline 插值折线
\r
14423 * @module zrender/shape/util/smoothSpline
\r
14424 * @author pissang (https://www.github.com/pissang)
\r
14425 * Kener (@Kener-林峰, kener.linfeng@gmail.com)
\r
14426 * errorrik (errorrik@gmail.com)
\r
14429 var vec2 = __webpack_require__(16);
\r
14434 function interpolate(p0, p1, p2, p3, t, t2, t3) {
\r
14435 var v0 = (p2 - p0) * 0.5;
\r
14436 var v1 = (p3 - p1) * 0.5;
\r
14437 return (2 * (p1 - p2) + v0 + v1) * t3
\r
14438 + (-3 * (p1 - p2) - 2 * v0 - v1) * t2
\r
14443 * @alias module:zrender/shape/util/smoothSpline
\r
14444 * @param {Array} points 线段顶点数组
\r
14445 * @param {boolean} isLoop
\r
14446 * @return {Array}
\r
14448 module.exports = function (points, isLoop) {
\r
14449 var len = points.length;
\r
14452 var distance = 0;
\r
14453 for (var i = 1; i < len; i++) {
\r
14454 distance += vec2.distance(points[i - 1], points[i]);
\r
14457 var segs = distance / 2;
\r
14458 segs = segs < len ? len : segs;
\r
14459 for (var i = 0; i < segs; i++) {
\r
14460 var pos = i / (segs - 1) * (isLoop ? len : len - 1);
\r
14461 var idx = Math.floor(pos);
\r
14463 var w = pos - idx;
\r
14466 var p1 = points[idx % len];
\r
14470 p0 = points[idx === 0 ? idx : idx - 1];
\r
14471 p2 = points[idx > len - 2 ? len - 1 : idx + 1];
\r
14472 p3 = points[idx > len - 3 ? len - 1 : idx + 2];
\r
14475 p0 = points[(idx - 1 + len) % len];
\r
14476 p2 = points[(idx + 1) % len];
\r
14477 p3 = points[(idx + 2) % len];
\r
14484 interpolate(p0[0], p1[0], p2[0], p3[0], w, w2, w3),
\r
14485 interpolate(p0[1], p1[1], p2[1], p3[1], w, w2, w3)
\r
14495 /***/ function(module, exports, __webpack_require__) {
\r
14499 * @module zrender/shape/util/smoothBezier
\r
14500 * @author pissang (https://www.github.com/pissang)
\r
14501 * Kener (@Kener-林峰, kener.linfeng@gmail.com)
\r
14502 * errorrik (errorrik@gmail.com)
\r
14506 var vec2 = __webpack_require__(16);
\r
14507 var v2Min = vec2.min;
\r
14508 var v2Max = vec2.max;
\r
14509 var v2Scale = vec2.scale;
\r
14510 var v2Distance = vec2.distance;
\r
14511 var v2Add = vec2.add;
\r
14515 * @alias module:zrender/shape/util/smoothBezier
\r
14516 * @param {Array} points 线段顶点数组
\r
14517 * @param {number} smooth 平滑等级, 0-1
\r
14518 * @param {boolean} isLoop
\r
14519 * @param {Array} constraint 将计算出来的控制点约束在一个包围盒内
\r
14520 * 比如 [[0, 0], [100, 100]], 这个包围盒会与
\r
14521 * 整个折线的包围盒做一个并集用来约束控制点。
\r
14522 * @param {Array} 计算出来的控制点数组
\r
14524 module.exports = function (points, smooth, isLoop, constraint) {
\r
14534 if (constraint) {
\r
14535 min = [Infinity, Infinity];
\r
14536 max = [-Infinity, -Infinity];
\r
14537 for (var i = 0, len = points.length; i < len; i++) {
\r
14538 v2Min(min, min, points[i]);
\r
14539 v2Max(max, max, points[i]);
\r
14542 v2Min(min, min, constraint[0]);
\r
14543 v2Max(max, max, constraint[1]);
\r
14546 for (var i = 0, len = points.length; i < len; i++) {
\r
14547 var point = points[i];
\r
14550 prevPoint = points[i ? i - 1 : len - 1];
\r
14551 nextPoint = points[(i + 1) % len];
\r
14554 if (i === 0 || i === len - 1) {
\r
14555 cps.push(vec2.clone(points[i]));
\r
14559 prevPoint = points[i - 1];
\r
14560 nextPoint = points[i + 1];
\r
14564 vec2.sub(v, nextPoint, prevPoint);
\r
14566 // use degree to scale the handle length
\r
14567 v2Scale(v, v, smooth);
\r
14569 var d0 = v2Distance(point, prevPoint);
\r
14570 var d1 = v2Distance(point, nextPoint);
\r
14571 var sum = d0 + d1;
\r
14577 v2Scale(v1, v, -d0);
\r
14578 v2Scale(v2, v, d1);
\r
14579 var cp0 = v2Add([], point, v1);
\r
14580 var cp1 = v2Add([], point, v2);
\r
14581 if (constraint) {
\r
14582 v2Max(cp0, cp0, min);
\r
14583 v2Min(cp0, cp0, max);
\r
14584 v2Max(cp1, cp1, min);
\r
14585 v2Min(cp1, cp1, max);
\r
14592 cps.push(cps.shift());
\r
14602 /***/ function(module, exports, __webpack_require__) {
\r
14605 * @module zrender/graphic/shape/Polyline
\r
14609 var polyHelper = __webpack_require__(67);
\r
14611 module.exports = __webpack_require__(44).extend({
\r
14613 type: 'polyline',
\r
14620 smoothConstraint: null
\r
14629 buildPath: function (ctx, shape) {
\r
14630 polyHelper.buildPath(ctx, shape, false);
\r
14637 /***/ function(module, exports, __webpack_require__) {
\r
14641 * @module zrender/graphic/shape/Rect
\r
14645 var roundRectHelper = __webpack_require__(60);
\r
14647 module.exports = __webpack_require__(44).extend({
\r
14652 // 左上、右上、右下、左下角的半径依次为r1、r2、r3、r4
\r
14653 // r缩写为1 相当于 [1, 1, 1, 1]
\r
14654 // r缩写为[1] 相当于 [1, 1, 1, 1]
\r
14655 // r缩写为[1, 2] 相当于 [1, 2, 1, 2]
\r
14656 // r缩写为[1, 2, 3] 相当于 [1, 2, 3, 2]
\r
14665 buildPath: function (ctx, shape) {
\r
14668 var width = shape.width;
\r
14669 var height = shape.height;
\r
14671 ctx.rect(x, y, width, height);
\r
14674 roundRectHelper.buildPath(ctx, shape);
\r
14685 /***/ function(module, exports, __webpack_require__) {
\r
14689 * @module zrender/graphic/shape/Line
\r
14692 module.exports = __webpack_require__(44).extend({
\r
14712 buildPath: function (ctx, shape) {
\r
14713 var x1 = shape.x1;
\r
14714 var y1 = shape.y1;
\r
14715 var x2 = shape.x2;
\r
14716 var y2 = shape.y2;
\r
14717 var percent = shape.percent;
\r
14719 if (percent === 0) {
\r
14723 ctx.moveTo(x1, y1);
\r
14725 if (percent < 1) {
\r
14726 x2 = x1 * (1 - percent) + x2 * percent;
\r
14727 y2 = y1 * (1 - percent) + y2 * percent;
\r
14729 ctx.lineTo(x2, y2);
\r
14733 * Get point at percent
\r
14734 * @param {number} percent
\r
14735 * @return {Array.<number>}
\r
14737 pointAt: function (p) {
\r
14738 var shape = this.shape;
\r
14740 shape.x1 * (1 - p) + shape.x2 * p,
\r
14741 shape.y1 * (1 - p) + shape.y2 * p
\r
14750 /***/ function(module, exports, __webpack_require__) {
\r
14755 * @module zrender/shape/BezierCurve
\r
14759 var curveTool = __webpack_require__(49);
\r
14760 var quadraticSubdivide = curveTool.quadraticSubdivide;
\r
14761 var cubicSubdivide = curveTool.cubicSubdivide;
\r
14762 var quadraticAt = curveTool.quadraticAt;
\r
14763 var cubicAt = curveTool.cubicAt;
\r
14766 module.exports = __webpack_require__(44).extend({
\r
14768 type: 'bezier-curve',
\r
14780 // Curve show percent, for animating
\r
14789 buildPath: function (ctx, shape) {
\r
14790 var x1 = shape.x1;
\r
14791 var y1 = shape.y1;
\r
14792 var x2 = shape.x2;
\r
14793 var y2 = shape.y2;
\r
14794 var cpx1 = shape.cpx1;
\r
14795 var cpy1 = shape.cpy1;
\r
14796 var cpx2 = shape.cpx2;
\r
14797 var cpy2 = shape.cpy2;
\r
14798 var percent = shape.percent;
\r
14799 if (percent === 0) {
\r
14803 ctx.moveTo(x1, y1);
\r
14805 if (cpx2 == null || cpy2 == null) {
\r
14806 if (percent < 1) {
\r
14807 quadraticSubdivide(
\r
14808 x1, cpx1, x2, percent, out
\r
14812 quadraticSubdivide(
\r
14813 y1, cpy1, y2, percent, out
\r
14819 ctx.quadraticCurveTo(
\r
14825 if (percent < 1) {
\r
14827 x1, cpx1, cpx2, x2, percent, out
\r
14833 y1, cpy1, cpy2, y2, percent, out
\r
14839 ctx.bezierCurveTo(
\r
14848 * Get point at percent
\r
14849 * @param {number} percent
\r
14850 * @return {Array.<number>}
\r
14852 pointAt: function (p) {
\r
14853 var shape = this.shape;
\r
14854 var cpx2 = shape.cpx2;
\r
14855 var cpy2 = shape.cpy2;
\r
14856 if (cpx2 === null || cpy2 === null) {
\r
14858 quadraticAt(shape.x1, shape.cpx1, shape.x2, p),
\r
14859 quadraticAt(shape.y1, shape.cpy1, shape.y2, p)
\r
14864 cubicAt(shape.x1, shape.cpx1, shape.cpx1, shape.x2, p),
\r
14865 cubicAt(shape.y1, shape.cpy1, shape.cpy1, shape.y2, p)
\r
14875 /***/ function(module, exports, __webpack_require__) {
\r
14879 * @module zrender/graphic/shape/Arc
\r
14883 module.exports = __webpack_require__(44).extend({
\r
14897 endAngle: Math.PI * 2,
\r
14909 buildPath: function (ctx, shape) {
\r
14911 var x = shape.cx;
\r
14912 var y = shape.cy;
\r
14913 var r = Math.max(shape.r, 0);
\r
14914 var startAngle = shape.startAngle;
\r
14915 var endAngle = shape.endAngle;
\r
14916 var clockwise = shape.clockwise;
\r
14918 var unitX = Math.cos(startAngle);
\r
14919 var unitY = Math.sin(startAngle);
\r
14921 ctx.moveTo(unitX * r + x, unitY * r + y);
\r
14922 ctx.arc(x, y, r, startAngle, endAngle, !clockwise);
\r
14929 /***/ function(module, exports, __webpack_require__) {
\r
14934 var zrUtil = __webpack_require__(3);
\r
14936 var Gradient = __webpack_require__(4);
\r
14939 * x, y, x2, y2 are all percent from 0 to 1
\r
14940 * @param {number} [x=0]
\r
14941 * @param {number} [y=0]
\r
14942 * @param {number} [x2=1]
\r
14943 * @param {number} [y2=0]
\r
14944 * @param {Array.<Object>} colorStops
\r
14946 var LinearGradient = function (x, y, x2, y2, colorStops) {
\r
14947 this.x = x == null ? 0 : x;
\r
14949 this.y = y == null ? 0 : y;
\r
14951 this.x2 = x2 == null ? 1 : x2;
\r
14953 this.y2 = y2 == null ? 0 : y2;
\r
14955 Gradient.call(this, colorStops);
\r
14958 LinearGradient.prototype = {
\r
14960 constructor: LinearGradient,
\r
14964 updateCanvasGradient: function (shape, ctx) {
\r
14965 var rect = shape.getBoundingRect();
\r
14967 var x = this.x * rect.width + rect.x;
\r
14968 var x2 = this.x2 * rect.width + rect.x;
\r
14969 var y = this.y * rect.height + rect.y;
\r
14970 var y2 = this.y2 * rect.height + rect.y;
\r
14972 var canvasGradient = ctx.createLinearGradient(x, y, x2, y2);
\r
14974 var colorStops = this.colorStops;
\r
14975 for (var i = 0; i < colorStops.length; i++) {
\r
14976 canvasGradient.addColorStop(
\r
14977 colorStops[i].offset, colorStops[i].color
\r
14981 this.canvasGradient = canvasGradient;
\r
14986 zrUtil.inherits(LinearGradient, Gradient);
\r
14988 module.exports = LinearGradient;
\r
14993 /***/ function(module, exports, __webpack_require__) {
\r
14998 var zrUtil = __webpack_require__(3);
\r
15000 var Gradient = __webpack_require__(4);
\r
15003 * x, y, r are all percent from 0 to 1
\r
15004 * @param {number} [x=0.5]
\r
15005 * @param {number} [y=0.5]
\r
15006 * @param {number} [r=0.5]
\r
15007 * @param {Array.<Object>} [colorStops]
\r
15009 var RadialGradient = function (x, y, r, colorStops) {
\r
15010 this.x = x == null ? 0.5 : x;
\r
15012 this.y = y == null ? 0.5 : y;
\r
15014 this.r = r == null ? 0.5 : r;
\r
15016 Gradient.call(this, colorStops);
\r
15019 RadialGradient.prototype = {
\r
15021 constructor: RadialGradient,
\r
15025 updateCanvasGradient: function (shape, ctx) {
\r
15026 var rect = shape.getBoundingRect();
\r
15028 var width = rect.width;
\r
15029 var height = rect.height;
\r
15030 var min = Math.min(width, height);
\r
15031 // var max = Math.max(width, height);
\r
15033 var x = this.x * width + rect.x;
\r
15034 var y = this.y * height + rect.y;
\r
15035 var r = this.r * min;
\r
15037 var canvasGradient = ctx.createRadialGradient(x, y, 0, x, y, r);
\r
15039 var colorStops = this.colorStops;
\r
15040 for (var i = 0; i < colorStops.length; i++) {
\r
15041 canvasGradient.addColorStop(
\r
15042 colorStops[i].offset, colorStops[i].color
\r
15046 this.canvasGradient = canvasGradient;
\r
15050 zrUtil.inherits(RadialGradient, Gradient);
\r
15052 module.exports = RadialGradient;
\r
15057 /***/ function(module, exports, __webpack_require__) {
\r
15060 * ZRender, a high performance 2d drawing library.
\r
15062 * Copyright (c) 2013, Baidu Inc.
\r
15063 * All rights reserved.
\r
15066 * https://github.com/ecomfe/zrender/blob/master/LICENSE.txt
\r
15068 // Global defines
\r
15070 var guid = __webpack_require__(31);
\r
15071 var env = __webpack_require__(78);
\r
15073 var Handler = __webpack_require__(79);
\r
15074 var Storage = __webpack_require__(83);
\r
15075 var Animation = __webpack_require__(84);
\r
15077 var useVML = !env.canvasSupported;
\r
15079 var painterCtors = {
\r
15080 canvas: __webpack_require__(85)
\r
15083 var instances = {}; // ZRender实例map索引
\r
15085 var zrender = {};
\r
15089 zrender.version = '3.0.6';
\r
15092 * @param {HTMLElement} dom
\r
15093 * @param {Object} opts
\r
15094 * @param {string} [opts.renderer='canvas'] 'canvas' or 'svg'
\r
15095 * @param {number} [opts.devicePixelRatio]
\r
15096 * @return {module:zrender/ZRender}
\r
15098 zrender.init = function(dom, opts) {
\r
15099 var zr = new ZRender(guid(), dom, opts);
\r
15100 instances[zr.id] = zr;
\r
15105 * Dispose zrender instance
\r
15106 * @param {module:zrender/ZRender} zr
\r
15108 zrender.dispose = function (zr) {
\r
15113 for (var key in instances) {
\r
15114 instances[key].dispose();
\r
15124 * @param {string} id ZRender对象索引
\r
15125 * @return {module:zrender/ZRender}
\r
15127 zrender.getInstance = function (id) {
\r
15128 return instances[id];
\r
15131 zrender.registerPainter = function (name, Ctor) {
\r
15132 painterCtors[name] = Ctor;
\r
15135 function delInstance(id) {
\r
15136 delete instances[id];
\r
15140 * @module zrender/ZRender
\r
15144 * @alias module:zrender/ZRender
\r
15145 * @param {string} id
\r
15146 * @param {HTMLDomElement} dom
\r
15147 * @param {Object} opts
\r
15148 * @param {string} [opts.renderer='canvas'] 'canvas' or 'svg'
\r
15149 * @param {number} [opts.devicePixelRatio]
\r
15151 var ZRender = function(id, dom, opts) {
\r
15153 opts = opts || {};
\r
15156 * @type {HTMLDomElement}
\r
15166 var storage = new Storage();
\r
15168 var rendererType = opts.renderer;
\r
15170 if (!painterCtors.vml) {
\r
15171 throw new Error('You need to require \'zrender/vml/vml\' to support IE8');
\r
15173 rendererType = 'vml';
\r
15175 else if (!rendererType || !painterCtors[rendererType]) {
\r
15176 rendererType = 'canvas';
\r
15178 var painter = new painterCtors[rendererType](dom, storage, opts);
\r
15180 this.storage = storage;
\r
15181 this.painter = painter;
\r
15183 this.handler = new Handler(painter.getViewportRoot(), storage, painter);
\r
15187 * @type {module:zrender/animation/Animation}
\r
15189 this.animation = new Animation({
\r
15191 update: function () {
\r
15192 if (self._needsRefresh) {
\r
15193 self.refreshImmediately();
\r
15198 this.animation.start();
\r
15201 * @type {boolean}
\r
15204 this._needsRefresh;
\r
15206 // 修改 storage.delFromMap, 每次删除元素之前删除动画
\r
15208 var oldDelFromMap = storage.delFromMap;
\r
15209 var oldAddToMap = storage.addToMap;
\r
15211 storage.delFromMap = function (elId) {
\r
15212 var el = storage.get(elId);
\r
15214 oldDelFromMap.call(storage, elId);
\r
15216 el && el.removeSelfFromZr(self);
\r
15219 storage.addToMap = function (el) {
\r
15220 oldAddToMap.call(storage, el);
\r
15222 el.addSelfToZr(self);
\r
15226 ZRender.prototype = {
\r
15228 constructor: ZRender,
\r
15231 * @return {string}
\r
15233 getId: function () {
\r
15239 * @param {string|module:zrender/Element} el
\r
15241 add: function (el) {
\r
15242 this.storage.addRoot(el);
\r
15243 this._needsRefresh = true;
\r
15248 * @param {string|module:zrender/Element} el
\r
15250 remove: function (el) {
\r
15251 this.storage.delRoot(el);
\r
15252 this._needsRefresh = true;
\r
15256 * 修改指定zlevel的绘制配置项
\r
15258 * @param {string} zLevel
\r
15259 * @param {Object} config 配置对象
\r
15260 * @param {string} [config.clearColor=0] 每次清空画布的颜色
\r
15261 * @param {string} [config.motionBlur=false] 是否开启动态模糊
\r
15262 * @param {number} [config.lastFrameAlpha=0.7]
\r
15263 * 在开启动态模糊的时候使用,与上一帧混合的alpha值,值越大尾迹越明显
\r
15265 configLayer: function (zLevel, config) {
\r
15266 this.painter.configLayer(zLevel, config);
\r
15267 this._needsRefresh = true;
\r
15273 refreshImmediately: function () {
\r
15274 // Clear needsRefresh ahead to avoid something wrong happens in refresh
\r
15275 // Or it will cause zrender refreshes again and again.
\r
15276 this._needsRefresh = false;
\r
15277 this.painter.refresh();
\r
15279 * Avoid trigger zr.refresh in Element#beforeUpdate hook
\r
15281 this._needsRefresh = false;
\r
15285 * 标记视图在浏览器下一帧需要绘制
\r
15287 refresh: function() {
\r
15288 this._needsRefresh = true;
\r
15294 resize: function() {
\r
15295 this.painter.resize();
\r
15296 this.handler && this.handler.resize();
\r
15302 clearAnimation: function () {
\r
15303 this.animation.clear();
\r
15309 getWidth: function() {
\r
15310 return this.painter.getWidth();
\r
15316 getHeight: function() {
\r
15317 return this.painter.getHeight();
\r
15322 * @param {string} type
\r
15323 * @param {string} [backgroundColor='#fff'] 背景色
\r
15324 * @return {string} 图片的Base64 url
\r
15326 toDataURL: function(type, backgroundColor, args) {
\r
15327 return this.painter.toDataURL(type, backgroundColor, args);
\r
15331 * 将常规shape转成image shape
\r
15332 * @param {module:zrender/graphic/Path} e
\r
15333 * @param {number} width
\r
15334 * @param {number} height
\r
15336 pathToImage: function(e, width, height) {
\r
15338 return this.painter.pathToImage(id, e, width, height);
\r
15342 * 设置默认的cursor style
\r
15343 * @param {string} cursorStyle 例如 crosshair
\r
15345 setDefaultCursorStyle: function (cursorStyle) {
\r
15346 this.handler.setDefaultCursorStyle(cursorStyle);
\r
15352 * @param {string} eventName 事件名称
\r
15353 * @param {Function} eventHandler 响应函数
\r
15354 * @param {Object} [context] 响应函数
\r
15356 on: function(eventName, eventHandler, context) {
\r
15357 this.handler && this.handler.on(eventName, eventHandler, context);
\r
15361 * 事件解绑定,参数为空则解绑所有自定义事件
\r
15363 * @param {string} eventName 事件名称
\r
15364 * @param {Function} eventHandler 响应函数
\r
15366 off: function(eventName, eventHandler) {
\r
15367 this.handler && this.handler.off(eventName, eventHandler);
\r
15373 * @param {string} eventName 事件名称,resize,hover,drag,etc
\r
15374 * @param {event=} event event dom事件对象
\r
15376 trigger: function (eventName, event) {
\r
15377 this.handler && this.handler.trigger(eventName, event);
\r
15382 * 清除当前ZRender下所有类图的数据和显示,clear后MVC和已绑定事件均还存在在,ZRender可用
\r
15384 clear: function () {
\r
15385 this.storage.delRoot();
\r
15386 this.painter.clear();
\r
15390 * 释放当前ZR实例(删除包括dom,数据、显示和事件绑定),dispose后ZR不可用
\r
15392 dispose: function () {
\r
15393 this.animation.stop();
\r
15396 this.storage.dispose();
\r
15397 this.painter.dispose();
\r
15398 this.handler && this.handler.dispose();
\r
15403 this.handler = null;
\r
15405 delInstance(this.id);
\r
15409 module.exports = zrender;
\r
15415 /***/ function(module, exports) {
\r
15420 * @desc echarts基于Canvas,纯Javascript图表库,提供直观,生动,可交互,可个性化定制的数据统计图表。
\r
15421 * @author firede[firede@firede.us]
\r
15422 * @desc thanks zepto.
\r
15426 if (typeof navigator === 'undefined') {
\r
15432 // Assume canvas is supported
\r
15433 canvasSupported: true
\r
15437 env = detect(navigator.userAgent);
\r
15440 module.exports = env;
\r
15443 // (c) 2010-2013 Thomas Fuchs
\r
15444 // Zepto.js may be freely distributed under the MIT license.
\r
15446 function detect(ua) {
\r
15448 var browser = {};
\r
15449 var webkit = ua.match(/Web[kK]it[\/]{0,1}([\d.]+)/);
\r
15450 var android = ua.match(/(Android);?[\s\/]+([\d.]+)?/);
\r
15451 var ipad = ua.match(/(iPad).*OS\s([\d_]+)/);
\r
15452 var ipod = ua.match(/(iPod)(.*OS\s([\d_]+))?/);
\r
15453 var iphone = !ipad && ua.match(/(iPhone\sOS)\s([\d_]+)/);
\r
15454 var webos = ua.match(/(webOS|hpwOS)[\s\/]([\d.]+)/);
\r
15455 var touchpad = webos && ua.match(/TouchPad/);
\r
15456 var kindle = ua.match(/Kindle\/([\d.]+)/);
\r
15457 var silk = ua.match(/Silk\/([\d._]+)/);
\r
15458 var blackberry = ua.match(/(BlackBerry).*Version\/([\d.]+)/);
\r
15459 var bb10 = ua.match(/(BB10).*Version\/([\d.]+)/);
\r
15460 var rimtabletos = ua.match(/(RIM\sTablet\sOS)\s([\d.]+)/);
\r
15461 var playbook = ua.match(/PlayBook/);
\r
15462 var chrome = ua.match(/Chrome\/([\d.]+)/) || ua.match(/CriOS\/([\d.]+)/);
\r
15463 var firefox = ua.match(/Firefox\/([\d.]+)/);
\r
15464 var safari = webkit && ua.match(/Mobile\//) && !chrome;
\r
15465 var webview = ua.match(/(iPhone|iPod|iPad).*AppleWebKit(?!.*Safari)/) && !chrome;
\r
15466 var ie = ua.match(/MSIE\s([\d.]+)/)
\r
15467 // IE 11 Trident/7.0; rv:11.0
\r
15468 || ua.match(/Trident\/.+?rv:(([\d.]+))/);
\r
15469 var edge = ua.match(/Edge\/([\d.]+)/); // IE 12 and 12+
\r
15471 // Todo: clean this up with a better OS/browser seperation:
\r
15472 // - discern (more) between multiple browsers on android
\r
15473 // - decide if kindle fire in silk mode is android or not
\r
15474 // - Firefox on Android doesn't specify the Android version
\r
15475 // - possibly devide in os, device and browser hashes
\r
15477 if (browser.webkit = !!webkit) browser.version = webkit[1];
\r
15479 if (android) os.android = true, os.version = android[2];
\r
15480 if (iphone && !ipod) os.ios = os.iphone = true, os.version = iphone[2].replace(/_/g, '.');
\r
15481 if (ipad) os.ios = os.ipad = true, os.version = ipad[2].replace(/_/g, '.');
\r
15482 if (ipod) os.ios = os.ipod = true, os.version = ipod[3] ? ipod[3].replace(/_/g, '.') : null;
\r
15483 if (webos) os.webos = true, os.version = webos[2];
\r
15484 if (touchpad) os.touchpad = true;
\r
15485 if (blackberry) os.blackberry = true, os.version = blackberry[2];
\r
15486 if (bb10) os.bb10 = true, os.version = bb10[2];
\r
15487 if (rimtabletos) os.rimtabletos = true, os.version = rimtabletos[2];
\r
15488 if (playbook) browser.playbook = true;
\r
15489 if (kindle) os.kindle = true, os.version = kindle[1];
\r
15490 if (silk) browser.silk = true, browser.version = silk[1];
\r
15491 if (!silk && os.android && ua.match(/Kindle Fire/)) browser.silk = true;
\r
15492 if (chrome) browser.chrome = true, browser.version = chrome[1];
\r
15493 if (firefox) browser.firefox = true, browser.version = firefox[1];
\r
15494 if (ie) browser.ie = true, browser.version = ie[1];
\r
15495 if (safari && (ua.match(/Safari/) || !!os.ios)) browser.safari = true;
\r
15496 if (webview) browser.webview = true;
\r
15497 if (ie) browser.ie = true, browser.version = ie[1];
\r
15498 if (edge) browser.edge = true, browser.version = edge[1];
\r
15500 os.tablet = !!(ipad || playbook || (android && !ua.match(/Mobile/)) ||
\r
15501 (firefox && ua.match(/Tablet/)) || (ie && !ua.match(/Phone/) && ua.match(/Touch/)));
\r
15502 os.phone = !!(!os.tablet && !os.ipod && (android || iphone || webos || blackberry || bb10 ||
\r
15503 (chrome && ua.match(/Android/)) || (chrome && ua.match(/CriOS\/([\d.]+)/)) ||
\r
15504 (firefox && ua.match(/Mobile/)) || (ie && ua.match(/Touch/))));
\r
15507 browser: browser,
\r
15510 // 原生canvas支持,改极端点了
\r
15511 // canvasSupported : !(browser.ie && parseFloat(browser.version) < 9)
\r
15512 canvasSupported : document.createElement('canvas').getContext ? true : false,
\r
15513 // @see <http://stackoverflow.com/questions/4817029/whats-the-best-way-to-detect-a-touch-screen-device-using-javascript>
\r
15514 // works on most browsers
\r
15515 // IE10/11 does not support touch event, and MS Edge supports them but not by
\r
15516 // default, so we dont check navigator.maxTouchPoints for them here.
\r
15517 touchEventsSupported: 'ontouchstart' in window && !browser.ie && !browser.edge,
\r
15518 // <http://caniuse.com/#search=pointer%20event>.
\r
15519 pointerEventsSupported: 'onpointerdown' in window
\r
15520 // Firefox supports pointer but not by default,
\r
15521 // only MS browsers are reliable on pointer events currently.
\r
15522 && (browser.edge || (browser.ie && browser.version >= 10))
\r
15529 /***/ function(module, exports, __webpack_require__) {
\r
15534 * @module zrender/Handler
\r
15535 * @author Kener (@Kener-林峰, kener.linfeng@gmail.com)
\r
15536 * errorrik (errorrik@gmail.com)
\r
15537 * pissang (shenyi.914@gmail.com)
\r
15541 var env = __webpack_require__(78);
\r
15542 var eventTool = __webpack_require__(80);
\r
15543 var util = __webpack_require__(3);
\r
15544 var Draggable = __webpack_require__(81);
\r
15545 var GestureMgr = __webpack_require__(82);
\r
15547 var Eventful = __webpack_require__(32);
\r
15549 var mouseHandlerNames = [
\r
15550 'click', 'dblclick', 'mousewheel', 'mouseout'
\r
15552 !usePointerEvent() && mouseHandlerNames.push(
\r
15553 'mouseup', 'mousedown', 'mousemove'
\r
15556 var touchHandlerNames = [
\r
15557 'touchstart', 'touchend', 'touchmove'
\r
15560 var pointerHandlerNames = [
\r
15561 'pointerdown', 'pointerup', 'pointermove'
\r
15564 var TOUCH_CLICK_DELAY = 300;
\r
15566 // touch指尖错觉的尝试偏移量配置
\r
15567 // var MOBILE_TOUCH_OFFSETS = [
\r
15570 // { x: 10, y: 10 },
\r
15574 var addEventListener = eventTool.addEventListener;
\r
15575 var removeEventListener = eventTool.removeEventListener;
\r
15576 var normalizeEvent = eventTool.normalizeEvent;
\r
15578 function makeEventPacket(eveType, target, event) {
\r
15583 cancelBubble: false,
\r
15584 offsetX: event.zrX,
\r
15585 offsetY: event.zrY,
\r
15586 gestureEvent: event.gestureEvent,
\r
15587 pinchX: event.pinchX,
\r
15588 pinchY: event.pinchY,
\r
15589 pinchScale: event.pinchScale,
\r
15590 wheelDelta: event.zrDelta
\r
15594 var domHandlers = {
\r
15596 * Mouse move handler
\r
15598 * @param {Event} event
\r
15600 mousemove: function (event) {
\r
15601 event = normalizeEvent(this.root, event);
\r
15603 var x = event.zrX;
\r
15604 var y = event.zrY;
\r
15606 var hovered = this.findHover(x, y, null);
\r
15607 var lastHovered = this._hovered;
\r
15609 this._hovered = hovered;
\r
15611 this.root.style.cursor = hovered ? hovered.cursor : this._defaultCursorStyle;
\r
15612 // Mouse out on previous hovered element
\r
15613 if (lastHovered && hovered !== lastHovered && lastHovered.__zr) {
\r
15614 this._dispatchProxy(lastHovered, 'mouseout', event);
\r
15617 // Mouse moving on one element
\r
15618 this._dispatchProxy(hovered, 'mousemove', event);
\r
15620 // Mouse over on a new element
\r
15621 if (hovered && hovered !== lastHovered) {
\r
15622 this._dispatchProxy(hovered, 'mouseover', event);
\r
15627 * Mouse out handler
\r
15629 * @param {Event} event
\r
15631 mouseout: function (event) {
\r
15632 event = normalizeEvent(this.root, event);
\r
15634 var element = event.toElement || event.relatedTarget;
\r
15635 if (element != this.root) {
\r
15636 while (element && element.nodeType != 9) {
\r
15637 // 忽略包含在root中的dom引起的mouseOut
\r
15638 if (element === this.root) {
\r
15642 element = element.parentNode;
\r
15646 this._dispatchProxy(this._hovered, 'mouseout', event);
\r
15648 this.trigger('globalout', {
\r
15656 * @param {Event} event
\r
15658 touchstart: function (event) {
\r
15660 // 移动端可能需要default行为,例如静态图表时。
\r
15661 // eventTool.stop(event);// 阻止浏览器默认事件,重要
\r
15662 event = normalizeEvent(this.root, event);
\r
15664 this._lastTouchMoment = new Date();
\r
15666 processGesture(this, event, 'start');
\r
15668 // 平板补充一次findHover
\r
15669 // this._mobileFindFixed(event);
\r
15670 // Trigger mousemove and mousedown
\r
15671 domHandlers.mousemove.call(this, event);
\r
15673 domHandlers.mousedown.call(this, event);
\r
15675 setTouchTimer(this);
\r
15681 * @param {Event} event
\r
15683 touchmove: function (event) {
\r
15684 // eventTool.stop(event);// 阻止浏览器默认事件,重要
\r
15685 event = normalizeEvent(this.root, event);
\r
15687 processGesture(this, event, 'change');
\r
15689 // Mouse move should always be triggered no matter whether
\r
15690 // there is gestrue event, because mouse move and pinch may
\r
15691 // be used at the same time.
\r
15692 domHandlers.mousemove.call(this, event);
\r
15694 setTouchTimer(this);
\r
15700 * @param {Event} event
\r
15702 touchend: function (event) {
\r
15703 // eventTool.stop(event);// 阻止浏览器默认事件,重要
\r
15704 event = normalizeEvent(this.root, event);
\r
15706 processGesture(this, event, 'end');
\r
15708 domHandlers.mouseup.call(this, event);
\r
15710 // click event should always be triggered no matter whether
\r
15711 // there is gestrue event. System click can not be prevented.
\r
15712 if (+new Date() - this._lastTouchMoment < TOUCH_CLICK_DELAY) {
\r
15713 // this._mobileFindFixed(event);
\r
15714 domHandlers.click.call(this, event);
\r
15717 setTouchTimer(this);
\r
15721 // Common handlers
\r
15722 util.each(['click', 'mousedown', 'mouseup', 'mousewheel', 'dblclick'], function (name) {
\r
15723 domHandlers[name] = function (event) {
\r
15724 event = normalizeEvent(this.root, event);
\r
15725 // Find hover again to avoid click event is dispatched manually. Or click is triggered without mouseover
\r
15726 var hovered = this.findHover(event.zrX, event.zrY, null);
\r
15727 this._dispatchProxy(hovered, name, event);
\r
15731 // Pointer event handlers
\r
15732 // util.each(['pointerdown', 'pointermove', 'pointerup'], function (name) {
\r
15733 // domHandlers[name] = function (event) {
\r
15734 // var mouseName = name.replace('pointer', 'mouse');
\r
15735 // domHandlers[mouseName].call(this, event);
\r
15739 function processGesture(zrHandler, event, stage) {
\r
15740 var gestureMgr = zrHandler._gestureMgr;
\r
15742 stage === 'start' && gestureMgr.clear();
\r
15744 var gestureInfo = gestureMgr.recognize(
\r
15746 zrHandler.findHover(event.zrX, event.zrY, null)
\r
15749 stage === 'end' && gestureMgr.clear();
\r
15751 if (gestureInfo) {
\r
15752 // eventTool.stop(event);
\r
15753 var type = gestureInfo.type;
\r
15754 event.gestureEvent = type;
\r
15756 zrHandler._dispatchProxy(gestureInfo.target, type, gestureInfo.event);
\r
15761 * 为控制类实例初始化dom 事件处理函数
\r
15764 * @param {module:zrender/Handler} instance 控制类实例
\r
15766 function initDomHandler(instance) {
\r
15767 var handlerNames = touchHandlerNames.concat(pointerHandlerNames);
\r
15768 for (var i = 0; i < handlerNames.length; i++) {
\r
15769 var name = handlerNames[i];
\r
15770 instance._handlers[name] = util.bind(domHandlers[name], instance);
\r
15773 for (var i = 0; i < mouseHandlerNames.length; i++) {
\r
15774 var name = mouseHandlerNames[i];
\r
15775 instance._handlers[name] = makeMouseHandler(domHandlers[name], instance);
\r
15778 function makeMouseHandler(fn, instance) {
\r
15779 return function () {
\r
15780 if (instance._touching) {
\r
15783 return fn.apply(instance, arguments);
\r
15789 * @alias module:zrender/Handler
\r
15791 * @extends module:zrender/mixin/Eventful
\r
15792 * @param {HTMLElement} root Main HTML element for painting.
\r
15793 * @param {module:zrender/Storage} storage Storage instance.
\r
15794 * @param {module:zrender/Painter} painter Painter instance.
\r
15796 var Handler = function(root, storage, painter) {
\r
15797 Eventful.call(this);
\r
15799 this.root = root;
\r
15800 this.storage = storage;
\r
15801 this.painter = painter;
\r
15805 * @type {boolean}
\r
15813 this._lastTouchMoment;
\r
15831 this._defaultCursorStyle = 'default';
\r
15835 * @type {module:zrender/core/GestureMgr}
\r
15837 this._gestureMgr = new GestureMgr();
\r
15841 * @type {Array.<Function>}
\r
15843 this._handlers = [];
\r
15847 * @type {boolean}
\r
15849 this._touching = false;
\r
15855 this._touchTimer;
\r
15857 initDomHandler(this);
\r
15859 if (usePointerEvent()) {
\r
15860 mountHandlers(pointerHandlerNames, this);
\r
15862 else if (useTouchEvent()) {
\r
15863 mountHandlers(touchHandlerNames, this);
\r
15865 // Handler of 'mouseout' event is needed in touch mode, which will be mounted below.
\r
15866 // addEventListener(root, 'mouseout', this._mouseoutHandler);
\r
15869 // Considering some devices that both enable touch and mouse event (like MS Surface
\r
15870 // and lenovo X240, @see #2350), we make mouse event be always listened, otherwise
\r
15871 // mouse event can not be handle in those devices.
\r
15872 mountHandlers(mouseHandlerNames, this);
\r
15874 Draggable.call(this);
\r
15876 function mountHandlers(handlerNames, instance) {
\r
15877 util.each(handlerNames, function (name) {
\r
15878 addEventListener(root, eventNameFix(name), instance._handlers[name]);
\r
15883 Handler.prototype = {
\r
15885 constructor: Handler,
\r
15890 resize: function (event) {
\r
15891 this._hovered = null;
\r
15896 * @param {string} eventName
\r
15897 * @param {event=} eventArgs
\r
15899 dispatch: function (eventName, eventArgs) {
\r
15900 var handler = this._handlers[eventName];
\r
15901 handler && handler.call(this, eventArgs);
\r
15907 dispose: function () {
\r
15908 var root = this.root;
\r
15910 var handlerNames = mouseHandlerNames.concat(touchHandlerNames);
\r
15912 for (var i = 0; i < handlerNames.length; i++) {
\r
15913 var name = handlerNames[i];
\r
15914 removeEventListener(root, eventNameFix(name), this._handlers[name]);
\r
15919 this.painter = null;
\r
15923 * 设置默认的cursor style
\r
15924 * @param {string} cursorStyle 例如 crosshair
\r
15926 setDefaultCursorStyle: function (cursorStyle) {
\r
15927 this._defaultCursorStyle = cursorStyle;
\r
15934 * @param {Object} targetEl 目标图形元素
\r
15935 * @param {string} eventName 事件名称
\r
15936 * @param {Object} event 事件对象
\r
15938 _dispatchProxy: function (targetEl, eventName, event) {
\r
15939 var eventHandler = 'on' + eventName;
\r
15940 var eventPacket = makeEventPacket(eventName, targetEl, event);
\r
15942 var el = targetEl;
\r
15946 && (eventPacket.cancelBubble = el[eventHandler].call(el, eventPacket));
\r
15948 el.trigger(eventName, eventPacket);
\r
15952 if (eventPacket.cancelBubble) {
\r
15957 if (!eventPacket.cancelBubble) {
\r
15958 // 冒泡到顶级 zrender 对象
\r
15959 this.trigger(eventName, eventPacket);
\r
15961 // 用户有可能在全局 click 事件中 dispose,所以需要判断下 painter 是否存在
\r
15962 this.painter && this.painter.eachOtherLayer(function (layer) {
\r
15963 if (typeof(layer[eventHandler]) == 'function') {
\r
15964 layer[eventHandler].call(layer, eventPacket);
\r
15966 if (layer.trigger) {
\r
15967 layer.trigger(eventName, eventPacket);
\r
15975 * @param {number} x
\r
15976 * @param {number} y
\r
15977 * @param {module:zrender/graphic/Displayable} exclude
\r
15980 findHover: function(x, y, exclude) {
\r
15981 var list = this.storage.getDisplayList();
\r
15982 for (var i = list.length - 1; i >= 0 ; i--) {
\r
15983 if (!list[i].silent
\r
15984 && list[i] !== exclude
\r
15985 // getDisplayList may include ignored item in VML mode
\r
15986 && !list[i].ignore
\r
15987 && isHover(list[i], x, y)) {
\r
15994 function isHover(displayable, x, y) {
\r
15995 if (displayable[displayable.rectHover ? 'rectContain' : 'contain'](x, y)) {
\r
15996 var p = displayable.parent;
\r
15998 if (p.clipPath && !p.clipPath.contain(x, y)) {
\r
15999 // Clipped by parents
\r
16011 * Prevent mouse event from being dispatched after Touch Events action
\r
16012 * @see <https://github.com/deltakosh/handjs/blob/master/src/hand.base.js>
\r
16013 * 1. Mobile browsers dispatch mouse events 300ms after touchend.
\r
16014 * 2. Chrome for Android dispatch mousedown for long-touch about 650ms
\r
16015 * Result: Blocking Mouse Events for 700ms.
\r
16017 function setTouchTimer(instance) {
\r
16018 instance._touching = true;
\r
16019 clearTimeout(instance._touchTimer);
\r
16020 instance._touchTimer = setTimeout(function () {
\r
16021 instance._touching = false;
\r
16026 * Althought MS Surface support screen touch, IE10/11 do not support
\r
16027 * touch event and MS Edge supported them but not by default (but chrome
\r
16028 * and firefox do). Thus we use Pointer event on MS browsers to handle touch.
\r
16030 function usePointerEvent() {
\r
16032 // pointermove event dont trigger when using finger.
\r
16033 // We may figger it out latter.
\r
16035 // return env.pointerEventsSupported
\r
16036 // In no-touch device we dont use pointer evnets but just
\r
16037 // use mouse event for avoiding problems.
\r
16038 // && window.navigator.maxTouchPoints;
\r
16041 function useTouchEvent() {
\r
16042 return env.touchEventsSupported;
\r
16045 function eventNameFix(name) {
\r
16046 return (name === 'mousewheel' && env.browser.firefox) ? 'DOMMouseScroll' : name;
\r
16049 util.mixin(Handler, Eventful);
\r
16050 util.mixin(Handler, Draggable);
\r
16052 module.exports = Handler;
\r
16057 /***/ function(module, exports, __webpack_require__) {
\r
16062 * @module zrender/core/event
\r
16063 * @author Kener (@Kener-林峰, kener.linfeng@gmail.com)
\r
16067 var Eventful = __webpack_require__(32);
\r
16069 var isDomLevel2 = (typeof window !== 'undefined') && !!window.addEventListener;
\r
16071 function getBoundingClientRect(el) {
\r
16072 // BlackBerry 5, iOS 3 (original iPhone) don't have getBoundingRect
\r
16073 return el.getBoundingClientRect ? el.getBoundingClientRect() : { left: 0, top: 0};
\r
16076 * 如果存在第三方嵌入的一些dom触发的事件,或touch事件,需要转换一下事件坐标
\r
16078 function normalizeEvent(el, e) {
\r
16080 e = e || window.event;
\r
16082 if (e.zrX != null) {
\r
16086 var eventType = e.type;
\r
16087 var isTouch = eventType && eventType.indexOf('touch') >= 0;
\r
16090 var box = getBoundingClientRect(el);
\r
16091 e.zrX = e.clientX - box.left;
\r
16092 e.zrY = e.clientY - box.top;
\r
16093 e.zrDelta = (e.wheelDelta) ? e.wheelDelta / 120 : -(e.detail || 0) / 3;
\r
16096 var touch = eventType != 'touchend'
\r
16097 ? e.targetTouches[0]
\r
16098 : e.changedTouches[0];
\r
16100 var rBounding = getBoundingClientRect(el);
\r
16101 // touch事件坐标是全屏的~
\r
16102 e.zrX = touch.clientX - rBounding.left;
\r
16103 e.zrY = touch.clientY - rBounding.top;
\r
16110 function addEventListener(el, name, handler) {
\r
16111 if (isDomLevel2) {
\r
16112 el.addEventListener(name, handler);
\r
16115 el.attachEvent('on' + name, handler);
\r
16119 function removeEventListener(el, name, handler) {
\r
16120 if (isDomLevel2) {
\r
16121 el.removeEventListener(name, handler);
\r
16124 el.detachEvent('on' + name, handler);
\r
16130 * @memberOf module:zrender/core/event
\r
16132 * @param {Event} e : event对象
\r
16134 var stop = isDomLevel2
\r
16136 e.preventDefault();
\r
16137 e.stopPropagation();
\r
16138 e.cancelBubble = true;
\r
16141 e.returnValue = false;
\r
16142 e.cancelBubble = true;
\r
16145 module.exports = {
\r
16146 normalizeEvent: normalizeEvent,
\r
16147 addEventListener: addEventListener,
\r
16148 removeEventListener: removeEventListener,
\r
16152 Dispatcher: Eventful
\r
16159 /***/ function(module, exports) {
\r
16161 // TODO Draggable for group
\r
16162 // FIXME Draggable on element which has parent rotation or scale
\r
16164 function Draggable() {
\r
16166 this.on('mousedown', this._dragStart, this);
\r
16167 this.on('mousemove', this._drag, this);
\r
16168 this.on('mouseup', this._dragEnd, this);
\r
16169 this.on('globalout', this._dragEnd, this);
\r
16170 // this._dropTarget = null;
\r
16171 // this._draggingTarget = null;
\r
16177 Draggable.prototype = {
\r
16179 constructor: Draggable,
\r
16181 _dragStart: function (e) {
\r
16182 var draggingTarget = e.target;
\r
16183 if (draggingTarget && draggingTarget.draggable) {
\r
16184 this._draggingTarget = draggingTarget;
\r
16185 draggingTarget.dragging = true;
\r
16186 this._x = e.offsetX;
\r
16187 this._y = e.offsetY;
\r
16189 this._dispatchProxy(draggingTarget, 'dragstart', e.event);
\r
16193 _drag: function (e) {
\r
16194 var draggingTarget = this._draggingTarget;
\r
16195 if (draggingTarget) {
\r
16197 var x = e.offsetX;
\r
16198 var y = e.offsetY;
\r
16200 var dx = x - this._x;
\r
16201 var dy = y - this._y;
\r
16205 draggingTarget.drift(dx, dy, e);
\r
16206 this._dispatchProxy(draggingTarget, 'drag', e.event);
\r
16208 var dropTarget = this.findHover(x, y, draggingTarget);
\r
16209 var lastDropTarget = this._dropTarget;
\r
16210 this._dropTarget = dropTarget;
\r
16212 if (draggingTarget !== dropTarget) {
\r
16213 if (lastDropTarget && dropTarget !== lastDropTarget) {
\r
16214 this._dispatchProxy(lastDropTarget, 'dragleave', e.event);
\r
16216 if (dropTarget && dropTarget !== lastDropTarget) {
\r
16217 this._dispatchProxy(dropTarget, 'dragenter', e.event);
\r
16223 _dragEnd: function (e) {
\r
16224 var draggingTarget = this._draggingTarget;
\r
16226 if (draggingTarget) {
\r
16227 draggingTarget.dragging = false;
\r
16230 this._dispatchProxy(draggingTarget, 'dragend', e.event);
\r
16232 if (this._dropTarget) {
\r
16233 this._dispatchProxy(this._dropTarget, 'drop', e.event);
\r
16236 this._draggingTarget = null;
\r
16237 this._dropTarget = null;
\r
16242 module.exports = Draggable;
\r
16247 /***/ function(module, exports) {
\r
16251 * Only implements needed gestures for mobile.
\r
16255 var GestureMgr = function () {
\r
16259 * @type {Array.<Object>}
\r
16261 this._track = [];
\r
16264 GestureMgr.prototype = {
\r
16266 constructor: GestureMgr,
\r
16268 recognize: function (event, target) {
\r
16269 this._doTrack(event, target);
\r
16270 return this._recognize(event);
\r
16273 clear: function () {
\r
16274 this._track.length = 0;
\r
16278 _doTrack: function (event, target) {
\r
16279 var touches = event.touches;
\r
16285 var trackItem = {
\r
16292 for (var i = 0, len = touches.length; i < len; i++) {
\r
16293 var touch = touches[i];
\r
16294 trackItem.points.push([touch.clientX, touch.clientY]);
\r
16295 trackItem.touches.push(touch);
\r
16298 this._track.push(trackItem);
\r
16301 _recognize: function (event) {
\r
16302 for (var eventName in recognizers) {
\r
16303 if (recognizers.hasOwnProperty(eventName)) {
\r
16304 var gestureInfo = recognizers[eventName](this._track, event);
\r
16305 if (gestureInfo) {
\r
16306 return gestureInfo;
\r
16313 function dist(pointPair) {
\r
16314 var dx = pointPair[1][0] - pointPair[0][0];
\r
16315 var dy = pointPair[1][1] - pointPair[0][1];
\r
16317 return Math.sqrt(dx * dx + dy * dy);
\r
16320 function center(pointPair) {
\r
16322 (pointPair[0][0] + pointPair[1][0]) / 2,
\r
16323 (pointPair[0][1] + pointPair[1][1]) / 2
\r
16327 var recognizers = {
\r
16329 pinch: function (track, event) {
\r
16330 var trackLen = track.length;
\r
16336 var pinchEnd = (track[trackLen - 1] || {}).points;
\r
16337 var pinchPre = (track[trackLen - 2] || {}).points || pinchEnd;
\r
16340 && pinchPre.length > 1
\r
16342 && pinchEnd.length > 1
\r
16344 var pinchScale = dist(pinchEnd) / dist(pinchPre);
\r
16345 !isFinite(pinchScale) && (pinchScale = 1);
\r
16347 event.pinchScale = pinchScale;
\r
16349 var pinchCenter = center(pinchEnd);
\r
16350 event.pinchX = pinchCenter[0];
\r
16351 event.pinchY = pinchCenter[1];
\r
16355 target: track[0].target,
\r
16361 // Only pinch currently.
\r
16364 module.exports = GestureMgr;
\r
16370 /***/ function(module, exports, __webpack_require__) {
\r
16375 * @module zrender/Storage
\r
16376 * @author Kener (@Kener-林峰, kener.linfeng@gmail.com)
\r
16377 * @author errorrik (errorrik@gmail.com)
\r
16378 * @author pissang (https://github.com/pissang/)
\r
16382 var util = __webpack_require__(3);
\r
16384 var Group = __webpack_require__(29);
\r
16386 function shapeCompareFunc(a, b) {
\r
16387 if (a.zlevel === b.zlevel) {
\r
16388 if (a.z === b.z) {
\r
16389 if (a.z2 === b.z2) {
\r
16390 return a.__renderidx - b.__renderidx;
\r
16392 return a.z2 - b.z2;
\r
16394 return a.z - b.z;
\r
16396 return a.zlevel - b.zlevel;
\r
16400 * @alias module:zrender/Storage
\r
16403 var Storage = function () {
\r
16404 // 所有常规形状,id索引的map
\r
16405 this._elements = {};
\r
16407 this._roots = [];
\r
16409 this._displayList = [];
\r
16411 this._displayListLen = 0;
\r
16414 Storage.prototype = {
\r
16416 constructor: Storage,
\r
16420 * @param {boolean} [update=false] 是否在返回前更新该数组
\r
16421 * @param {boolean} [includeIgnore=false] 是否包含 ignore 的数组, 在 update 为 true 的时候有效
\r
16423 * 详见{@link module:zrender/graphic/Displayable.prototype.updateDisplayList}
\r
16424 * @return {Array.<module:zrender/graphic/Displayable>}
\r
16426 getDisplayList: function (update, includeIgnore) {
\r
16427 includeIgnore = includeIgnore || false;
\r
16429 this.updateDisplayList(includeIgnore);
\r
16431 return this._displayList;
\r
16436 * 每次绘制前都会调用,该方法会先深度优先遍历整个树,更新所有Group和Shape的变换并且把所有可见的Shape保存到数组中,
\r
16437 * 最后根据绘制的优先级(zlevel > z > 插入顺序)排序得到绘制队列
\r
16438 * @param {boolean} [includeIgnore=false] 是否包含 ignore 的数组
\r
16440 updateDisplayList: function (includeIgnore) {
\r
16441 this._displayListLen = 0;
\r
16442 var roots = this._roots;
\r
16443 var displayList = this._displayList;
\r
16444 for (var i = 0, len = roots.length; i < len; i++) {
\r
16445 this._updateAndAddDisplayable(roots[i], null, includeIgnore);
\r
16447 displayList.length = this._displayListLen;
\r
16449 for (var i = 0, len = displayList.length; i < len; i++) {
\r
16450 displayList[i].__renderidx = i;
\r
16453 displayList.sort(shapeCompareFunc);
\r
16456 _updateAndAddDisplayable: function (el, clipPaths, includeIgnore) {
\r
16458 if (el.ignore && !includeIgnore) {
\r
16462 el.beforeUpdate();
\r
16466 el.afterUpdate();
\r
16468 var clipPath = el.clipPath;
\r
16470 // clipPath 的变换是基于 group 的变换
\r
16471 clipPath.parent = el;
\r
16472 clipPath.updateTransform();
\r
16476 clipPaths = clipPaths.slice();
\r
16477 clipPaths.push(clipPath);
\r
16480 clipPaths = [clipPath];
\r
16484 if (el.type == 'group') {
\r
16485 var children = el._children;
\r
16487 for (var i = 0; i < children.length; i++) {
\r
16488 var child = children[i];
\r
16490 // Force to mark as dirty if group is dirty
\r
16491 // FIXME __dirtyPath ?
\r
16492 child.__dirty = el.__dirty || child.__dirty;
\r
16494 this._updateAndAddDisplayable(child, clipPaths, includeIgnore);
\r
16497 // Mark group clean here
\r
16498 el.__dirty = false;
\r
16502 el.__clipPaths = clipPaths;
\r
16504 this._displayList[this._displayListLen++] = el;
\r
16509 * 添加图形(Shape)或者组(Group)到根节点
\r
16510 * @param {module:zrender/Element} el
\r
16512 addRoot: function (el) {
\r
16513 // Element has been added
\r
16514 if (this._elements[el.id]) {
\r
16518 if (el instanceof Group) {
\r
16519 el.addChildrenToStorage(this);
\r
16522 this.addToMap(el);
\r
16523 this._roots.push(el);
\r
16527 * 删除指定的图形(Shape)或者组(Group)
\r
16528 * @param {string|Array.<string>} [elId] 如果为空清空整个Storage
\r
16530 delRoot: function (elId) {
\r
16531 if (elId == null) {
\r
16533 for (var i = 0; i < this._roots.length; i++) {
\r
16534 var root = this._roots[i];
\r
16535 if (root instanceof Group) {
\r
16536 root.delChildrenFromStorage(this);
\r
16540 this._elements = {};
\r
16541 this._roots = [];
\r
16542 this._displayList = [];
\r
16543 this._displayListLen = 0;
\r
16548 if (elId instanceof Array) {
\r
16549 for (var i = 0, l = elId.length; i < l; i++) {
\r
16550 this.delRoot(elId[i]);
\r
16556 if (typeof(elId) == 'string') {
\r
16557 el = this._elements[elId];
\r
16563 var idx = util.indexOf(this._roots, el);
\r
16565 this.delFromMap(el.id);
\r
16566 this._roots.splice(idx, 1);
\r
16567 if (el instanceof Group) {
\r
16568 el.delChildrenFromStorage(this);
\r
16573 addToMap: function (el) {
\r
16574 if (el instanceof Group) {
\r
16575 el.__storage = this;
\r
16579 this._elements[el.id] = el;
\r
16584 get: function (elId) {
\r
16585 return this._elements[elId];
\r
16588 delFromMap: function (elId) {
\r
16589 var elements = this._elements;
\r
16590 var el = elements[elId];
\r
16592 delete elements[elId];
\r
16593 if (el instanceof Group) {
\r
16594 el.__storage = null;
\r
16604 dispose: function () {
\r
16606 this._renderList =
\r
16607 this._roots = null;
\r
16611 module.exports = Storage;
\r
16617 /***/ function(module, exports, __webpack_require__) {
\r
16621 * 动画主类, 调度和管理所有动画控制器
\r
16623 * @module zrender/animation/Animation
\r
16624 * @author pissang(https://github.com/pissang)
\r
16626 // TODO Additive animation
\r
16627 // http://iosoteric.com/additive-animations-animatewithduration-in-ios-8/
\r
16628 // https://developer.apple.com/videos/wwdc2014/#236
\r
16631 var util = __webpack_require__(3);
\r
16632 var Dispatcher = __webpack_require__(80).Dispatcher;
\r
16634 var requestAnimationFrame = (typeof window !== 'undefined' &&
\r
16635 (window.requestAnimationFrame
\r
16636 || window.msRequestAnimationFrame
\r
16637 || window.mozRequestAnimationFrame
\r
16638 || window.webkitRequestAnimationFrame))
\r
16639 || function (func) {
\r
16640 setTimeout(func, 16);
\r
16643 var Animator = __webpack_require__(35);
\r
16645 * @typedef {Object} IZRenderStage
\r
16646 * @property {Function} update
\r
16650 * @alias module:zrender/animation/Animation
\r
16652 * @param {Object} [options]
\r
16653 * @param {Function} [options.onframe]
\r
16654 * @param {IZRenderStage} [options.stage]
\r
16656 * var animation = new Animation();
\r
16661 * animation.animate(node.position)
\r
16670 * .start('spline');
\r
16672 var Animation = function (options) {
\r
16674 options = options || {};
\r
16676 this.stage = options.stage || {};
\r
16678 this.onframe = options.onframe || function() {};
\r
16680 // private properties
\r
16681 this._clips = [];
\r
16683 this._running = false;
\r
16687 Dispatcher.call(this);
\r
16690 Animation.prototype = {
\r
16692 constructor: Animation,
\r
16695 * @param {module:zrender/animation/Clip} clip
\r
16697 addClip: function (clip) {
\r
16698 this._clips.push(clip);
\r
16702 * @param {module:zrender/animation/Animator} animator
\r
16704 addAnimator: function (animator) {
\r
16705 animator.animation = this;
\r
16706 var clips = animator.getClips();
\r
16707 for (var i = 0; i < clips.length; i++) {
\r
16708 this.addClip(clips[i]);
\r
16713 * @param {module:zrender/animation/Clip} clip
\r
16715 removeClip: function(clip) {
\r
16716 var idx = util.indexOf(this._clips, clip);
\r
16718 this._clips.splice(idx, 1);
\r
16724 * @param {module:zrender/animation/Animator} animator
\r
16726 removeAnimator: function (animator) {
\r
16727 var clips = animator.getClips();
\r
16728 for (var i = 0; i < clips.length; i++) {
\r
16729 this.removeClip(clips[i]);
\r
16731 animator.animation = null;
\r
16734 _update: function() {
\r
16736 var time = new Date().getTime();
\r
16737 var delta = time - this._time;
\r
16738 var clips = this._clips;
\r
16739 var len = clips.length;
\r
16741 var deferredEvents = [];
\r
16742 var deferredClips = [];
\r
16743 for (var i = 0; i < len; i++) {
\r
16744 var clip = clips[i];
\r
16745 var e = clip.step(time);
\r
16746 // Throw out the events need to be called after
\r
16747 // stage.update, like destroy
\r
16749 deferredEvents.push(e);
\r
16750 deferredClips.push(clip);
\r
16754 // Remove the finished clip
\r
16755 for (var i = 0; i < len;) {
\r
16756 if (clips[i]._needsRemove) {
\r
16757 clips[i] = clips[len - 1];
\r
16766 len = deferredEvents.length;
\r
16767 for (var i = 0; i < len; i++) {
\r
16768 deferredClips[i].fire(deferredEvents[i]);
\r
16771 this._time = time;
\r
16773 this.onframe(delta);
\r
16775 this.trigger('frame', delta);
\r
16777 if (this.stage.update) {
\r
16778 this.stage.update();
\r
16784 start: function () {
\r
16787 this._running = true;
\r
16789 function step() {
\r
16790 if (self._running) {
\r
16792 requestAnimationFrame(step);
\r
16798 this._time = new Date().getTime();
\r
16799 requestAnimationFrame(step);
\r
16804 stop: function () {
\r
16805 this._running = false;
\r
16810 clear: function () {
\r
16811 this._clips = [];
\r
16814 * 对一个目标创建一个animator对象,可以指定目标中的属性使用动画
\r
16815 * @param {Object} target
\r
16816 * @param {Object} options
\r
16817 * @param {boolean} [options.loop=false] 是否循环播放动画
\r
16818 * @param {Function} [options.getter=null]
\r
16819 * 如果指定getter函数,会通过getter函数取属性值
\r
16820 * @param {Function} [options.setter=null]
\r
16821 * 如果指定setter函数,会通过setter函数设置属性值
\r
16822 * @return {module:zrender/animation/Animation~Animator}
\r
16824 animate: function (target, options) {
\r
16825 options = options || {};
\r
16826 var animator = new Animator(
\r
16837 util.mixin(Animation, Dispatcher);
\r
16839 module.exports = Animation;
\r
16845 /***/ function(module, exports, __webpack_require__) {
\r
16849 * Default canvas painter
\r
16850 * @module zrender/Painter
\r
16851 * @author Kener (@Kener-林峰, kener.linfeng@gmail.com)
\r
16852 * errorrik (errorrik@gmail.com)
\r
16853 * pissang (https://www.github.com/pissang)
\r
16857 var config = __webpack_require__(40);
\r
16858 var util = __webpack_require__(3);
\r
16859 var log = __webpack_require__(39);
\r
16860 var BoundingRect = __webpack_require__(15);
\r
16862 var Layer = __webpack_require__(86);
\r
16864 function parseInt10(val) {
\r
16865 return parseInt(val, 10);
\r
16868 function isLayerValid(layer) {
\r
16873 if (layer.isBuildin) {
\r
16877 if (typeof(layer.resize) !== 'function'
\r
16878 || typeof(layer.refresh) !== 'function'
\r
16886 function preProcessLayer(layer) {
\r
16887 layer.__unusedCount++;
\r
16890 function postProcessLayer(layer) {
\r
16891 layer.__dirty = false;
\r
16892 if (layer.__unusedCount == 1) {
\r
16897 var tmpRect = new BoundingRect(0, 0, 0, 0);
\r
16898 var viewRect = new BoundingRect(0, 0, 0, 0);
\r
16899 function isDisplayableCulled(el, width, height) {
\r
16900 tmpRect.copy(el.getBoundingRect());
\r
16901 if (el.transform) {
\r
16902 tmpRect.applyTransform(el.transform);
\r
16904 viewRect.width = width;
\r
16905 viewRect.height = height;
\r
16906 return !tmpRect.intersect(viewRect);
\r
16909 function isClipPathChanged(clipPaths, prevClipPaths) {
\r
16910 if (!clipPaths || !prevClipPaths || (clipPaths.length !== prevClipPaths.length)) {
\r
16913 for (var i = 0; i < clipPaths.length; i++) {
\r
16914 if (clipPaths[i] !== prevClipPaths[i]) {
\r
16920 function doClip(clipPaths, ctx) {
\r
16921 for (var i = 0; i < clipPaths.length; i++) {
\r
16922 var clipPath = clipPaths[i];
\r
16924 if (clipPath.transform) {
\r
16925 m = clipPath.transform;
\r
16932 var path = clipPath.path;
\r
16933 path.beginPath(ctx);
\r
16934 clipPath.buildPath(path, clipPath.shape);
\r
16936 // Transform back
\r
16937 if (clipPath.transform) {
\r
16938 m = clipPath.invTransform;
\r
16949 * @alias module:zrender/Painter
\r
16951 * @param {HTMLElement} root 绘图容器
\r
16952 * @param {module:zrender/Storage} storage
\r
16953 * @param {Ojbect} opts
\r
16955 var Painter = function (root, storage, opts) {
\r
16956 var singleCanvas = !root.nodeName // In node ?
\r
16957 || root.nodeName.toUpperCase() === 'CANVAS';
\r
16959 opts = opts || {};
\r
16964 this.dpr = opts.devicePixelRatio || config.devicePixelRatio;
\r
16966 * @type {boolean}
\r
16969 this._singleCanvas = singleCanvas;
\r
16972 * @type {HTMLElement}
\r
16974 this.root = root;
\r
16976 var rootStyle = root.style;
\r
16978 // In node environment using node-canvas
\r
16980 rootStyle['-webkit-tap-highlight-color'] = 'transparent';
\r
16981 rootStyle['-webkit-user-select'] = 'none';
\r
16982 rootStyle['user-select'] = 'none';
\r
16983 rootStyle['-webkit-touch-callout'] = 'none';
\r
16985 root.innerHTML = '';
\r
16989 * @type {module:zrender/Storage}
\r
16991 this.storage = storage;
\r
16993 if (!singleCanvas) {
\r
16994 var width = this._getWidth();
\r
16995 var height = this._getHeight();
\r
16996 this._width = width;
\r
16997 this._height = height;
\r
16999 var domRoot = document.createElement('div');
\r
17000 this._domRoot = domRoot;
\r
17001 var domRootStyle = domRoot.style;
\r
17003 // domRoot.onselectstart = returnFalse; // 避免页面选中的尴尬
\r
17004 domRootStyle.position = 'relative';
\r
17005 domRootStyle.overflow = 'hidden';
\r
17006 domRootStyle.width = this._width + 'px';
\r
17007 domRootStyle.height = this._height + 'px';
\r
17008 root.appendChild(domRoot);
\r
17011 * @type {Object.<key, module:zrender/Layer>}
\r
17014 this._layers = {};
\r
17016 * @type {Array.<number>}
\r
17019 this._zlevelList = [];
\r
17022 // Use canvas width and height directly
\r
17023 var width = root.width;
\r
17024 var height = root.height;
\r
17025 this._width = width;
\r
17026 this._height = height;
\r
17028 // Create layer if only one given canvas
\r
17029 // Device pixel ratio is fixed to 1 because given canvas has its specified width and height
\r
17030 var mainLayer = new Layer(root, this, 1);
\r
17031 mainLayer.initContext();
\r
17032 // FIXME Use canvas width and height
\r
17033 // mainLayer.resize(width, height);
\r
17037 this._zlevelList = [0];
\r
17040 this._layerConfig = {};
\r
17042 this.pathToImage = this._createPathToImage();
\r
17045 Painter.prototype = {
\r
17047 constructor: Painter,
\r
17050 * If painter use a single canvas
\r
17051 * @return {boolean}
\r
17053 isSingleCanvas: function () {
\r
17054 return this._singleCanvas;
\r
17057 * @return {HTMLDivElement}
\r
17059 getViewportRoot: function () {
\r
17060 return this._singleCanvas ? this._layers[0].dom : this._domRoot;
\r
17065 * @param {boolean} [paintAll=false] 强制绘制所有displayable
\r
17067 refresh: function (paintAll) {
\r
17068 var list = this.storage.getDisplayList(true);
\r
17069 var zlevelList = this._zlevelList;
\r
17071 this._paintList(list, paintAll);
\r
17073 // Paint custum layers
\r
17074 for (var i = 0; i < zlevelList.length; i++) {
\r
17075 var z = zlevelList[i];
\r
17076 var layer = this._layers[z];
\r
17077 if (!layer.isBuildin && layer.refresh) {
\r
17085 _paintList: function (list, paintAll) {
\r
17087 if (paintAll == null) {
\r
17088 paintAll = false;
\r
17091 this._updateLayerStatus(list);
\r
17093 var currentLayer;
\r
17094 var currentZLevel;
\r
17097 var viewWidth = this._width;
\r
17098 var viewHeight = this._height;
\r
17100 this.eachBuildinLayer(preProcessLayer);
\r
17102 // var invTransform = [];
\r
17103 var prevElClipPaths = null;
\r
17105 for (var i = 0, l = list.length; i < l; i++) {
\r
17106 var el = list[i];
\r
17107 var elZLevel = this._singleCanvas ? 0 : el.zlevel;
\r
17108 // Change draw layer
\r
17109 if (currentZLevel !== elZLevel) {
\r
17110 // Only 0 zlevel if only has one canvas
\r
17111 currentZLevel = elZLevel;
\r
17112 currentLayer = this.getLayer(currentZLevel);
\r
17114 if (!currentLayer.isBuildin) {
\r
17116 'ZLevel ' + currentZLevel
\r
17117 + ' has been used by unkown layer ' + currentLayer.id
\r
17121 ctx = currentLayer.ctx;
\r
17123 // Reset the count
\r
17124 currentLayer.__unusedCount = 0;
\r
17126 if (currentLayer.__dirty || paintAll) {
\r
17127 currentLayer.clear();
\r
17132 (currentLayer.__dirty || paintAll)
\r
17133 // Ignore invisible element
\r
17135 // Ignore transparent element
\r
17136 && el.style.opacity !== 0
\r
17137 // Ignore scale 0 element, in some environment like node-canvas
\r
17138 // Draw a scale 0 element can cause all following draw wrong
\r
17139 && el.scale[0] && el.scale[1]
\r
17140 // Ignore culled element
\r
17141 && !(el.culling && isDisplayableCulled(el, viewWidth, viewHeight))
\r
17143 var clipPaths = el.__clipPaths;
\r
17145 // Optimize when clipping on group with several elements
\r
17146 if (isClipPathChanged(clipPaths, prevElClipPaths)) {
\r
17147 // If has previous clipping state, restore from it
\r
17148 if (prevElClipPaths) {
\r
17151 // New clipping state
\r
17154 doClip(clipPaths, ctx);
\r
17156 prevElClipPaths = clipPaths;
\r
17158 el.beforeBrush && el.beforeBrush(ctx);
\r
17159 el.brush(ctx, false);
\r
17160 el.afterBrush && el.afterBrush(ctx);
\r
17163 el.__dirty = false;
\r
17166 // If still has clipping state
\r
17167 if (prevElClipPaths) {
\r
17171 this.eachBuildinLayer(postProcessLayer);
\r
17175 * 获取 zlevel 所在层,如果不存在则会创建一个新的层
\r
17176 * @param {number} zlevel
\r
17177 * @return {module:zrender/Layer}
\r
17179 getLayer: function (zlevel) {
\r
17180 if (this._singleCanvas) {
\r
17181 return this._layers[0];
\r
17184 var layer = this._layers[zlevel];
\r
17186 // Create a new layer
\r
17187 layer = new Layer('zr_' + zlevel, this, this.dpr);
\r
17188 layer.isBuildin = true;
\r
17190 if (this._layerConfig[zlevel]) {
\r
17191 util.merge(layer, this._layerConfig[zlevel], true);
\r
17194 this.insertLayer(zlevel, layer);
\r
17196 // Context is created after dom inserted to document
\r
17197 // Or excanvas will get 0px clientWidth and clientHeight
\r
17198 layer.initContext();
\r
17204 insertLayer: function (zlevel, layer) {
\r
17206 var layersMap = this._layers;
\r
17207 var zlevelList = this._zlevelList;
\r
17208 var len = zlevelList.length;
\r
17209 var prevLayer = null;
\r
17211 var domRoot = this._domRoot;
\r
17213 if (layersMap[zlevel]) {
\r
17214 log('ZLevel ' + zlevel + ' has been used already');
\r
17217 // Check if is a valid layer
\r
17218 if (!isLayerValid(layer)) {
\r
17219 log('Layer of zlevel ' + zlevel + ' is not valid');
\r
17223 if (len > 0 && zlevel > zlevelList[0]) {
\r
17224 for (i = 0; i < len - 1; i++) {
\r
17226 zlevelList[i] < zlevel
\r
17227 && zlevelList[i + 1] > zlevel
\r
17232 prevLayer = layersMap[zlevelList[i]];
\r
17234 zlevelList.splice(i + 1, 0, zlevel);
\r
17237 var prevDom = prevLayer.dom;
\r
17238 if (prevDom.nextSibling) {
\r
17239 domRoot.insertBefore(
\r
17241 prevDom.nextSibling
\r
17245 domRoot.appendChild(layer.dom);
\r
17249 if (domRoot.firstChild) {
\r
17250 domRoot.insertBefore(layer.dom, domRoot.firstChild);
\r
17253 domRoot.appendChild(layer.dom);
\r
17257 layersMap[zlevel] = layer;
\r
17260 // Iterate each layer
\r
17261 eachLayer: function (cb, context) {
\r
17262 var zlevelList = this._zlevelList;
\r
17265 for (i = 0; i < zlevelList.length; i++) {
\r
17266 z = zlevelList[i];
\r
17267 cb.call(context, this._layers[z], z);
\r
17271 // Iterate each buildin layer
\r
17272 eachBuildinLayer: function (cb, context) {
\r
17273 var zlevelList = this._zlevelList;
\r
17277 for (i = 0; i < zlevelList.length; i++) {
\r
17278 z = zlevelList[i];
\r
17279 layer = this._layers[z];
\r
17280 if (layer.isBuildin) {
\r
17281 cb.call(context, layer, z);
\r
17286 // Iterate each other layer except buildin layer
\r
17287 eachOtherLayer: function (cb, context) {
\r
17288 var zlevelList = this._zlevelList;
\r
17292 for (i = 0; i < zlevelList.length; i++) {
\r
17293 z = zlevelList[i];
\r
17294 layer = this._layers[z];
\r
17295 if (! layer.isBuildin) {
\r
17296 cb.call(context, layer, z);
\r
17303 * @param {Array.<module:zrender/Layer>} [prevLayer]
\r
17305 getLayers: function () {
\r
17306 return this._layers;
\r
17309 _updateLayerStatus: function (list) {
\r
17311 var layers = this._layers;
\r
17313 var elCounts = {};
\r
17315 this.eachBuildinLayer(function (layer, z) {
\r
17316 elCounts[z] = layer.elCount;
\r
17317 layer.elCount = 0;
\r
17320 for (var i = 0, l = list.length; i < l; i++) {
\r
17321 var el = list[i];
\r
17322 var zlevel = this._singleCanvas ? 0 : el.zlevel;
\r
17323 var layer = layers[zlevel];
\r
17327 if (layer.__dirty) {
\r
17330 layer.__dirty = el.__dirty;
\r
17335 this.eachBuildinLayer(function (layer, z) {
\r
17336 if (elCounts[z] !== layer.elCount) {
\r
17337 layer.__dirty = true;
\r
17345 clear: function () {
\r
17346 this.eachBuildinLayer(this._clearLayer);
\r
17350 _clearLayer: function (layer) {
\r
17355 * 修改指定zlevel的绘制参数
\r
17357 * @param {string} zlevel
\r
17358 * @param {Object} config 配置对象
\r
17359 * @param {string} [config.clearColor=0] 每次清空画布的颜色
\r
17360 * @param {string} [config.motionBlur=false] 是否开启动态模糊
\r
17361 * @param {number} [config.lastFrameAlpha=0.7]
\r
17362 * 在开启动态模糊的时候使用,与上一帧混合的alpha值,值越大尾迹越明显
\r
17364 configLayer: function (zlevel, config) {
\r
17366 var layerConfig = this._layerConfig;
\r
17367 if (!layerConfig[zlevel]) {
\r
17368 layerConfig[zlevel] = config;
\r
17371 util.merge(layerConfig[zlevel], config, true);
\r
17374 var layer = this._layers[zlevel];
\r
17377 util.merge(layer, layerConfig[zlevel], true);
\r
17384 * @param {number} zlevel 层所在的zlevel
\r
17386 delLayer: function (zlevel) {
\r
17387 var layers = this._layers;
\r
17388 var zlevelList = this._zlevelList;
\r
17389 var layer = layers[zlevel];
\r
17393 layer.dom.parentNode.removeChild(layer.dom);
\r
17394 delete layers[zlevel];
\r
17396 zlevelList.splice(util.indexOf(zlevelList, zlevel), 1);
\r
17402 resize: function (width, height) {
\r
17403 var domRoot = this._domRoot;
\r
17405 domRoot.style.display = 'none';
\r
17407 width = width || this._getWidth();
\r
17408 height = height || this._getHeight();
\r
17410 domRoot.style.display = '';
\r
17412 // 优化没有实际改变的resize
\r
17413 if (this._width != width || height != this._height) {
\r
17414 domRoot.style.width = width + 'px';
\r
17415 domRoot.style.height = height + 'px';
\r
17417 for (var id in this._layers) {
\r
17418 this._layers[id].resize(width, height);
\r
17421 this.refresh(true);
\r
17424 this._width = width;
\r
17425 this._height = height;
\r
17432 * @param {number} zlevel
\r
17434 clearLayer: function (zlevel) {
\r
17435 var layer = this._layers[zlevel];
\r
17444 dispose: function () {
\r
17445 this.root.innerHTML = '';
\r
17451 this._layers = null;
\r
17455 * Get canvas which has all thing rendered
\r
17456 * @param {Object} opts
\r
17457 * @param {string} [opts.backgroundColor]
\r
17459 getRenderedCanvas: function (opts) {
\r
17460 opts = opts || {};
\r
17461 if (this._singleCanvas) {
\r
17462 return this._layers[0].dom;
\r
17465 var imageLayer = new Layer('image', this, opts.pixelRatio || this.dpr);
\r
17466 imageLayer.initContext();
\r
17468 var ctx = imageLayer.ctx;
\r
17469 imageLayer.clearColor = opts.backgroundColor;
\r
17470 imageLayer.clear();
\r
17472 var displayList = this.storage.getDisplayList(true);
\r
17474 for (var i = 0; i < displayList.length; i++) {
\r
17475 var el = displayList[i];
\r
17476 if (!el.invisible) {
\r
17477 el.beforeBrush && el.beforeBrush(ctx);
\r
17478 // TODO Check image cross origin
\r
17479 el.brush(ctx, false);
\r
17480 el.afterBrush && el.afterBrush(ctx);
\r
17484 return imageLayer.dom;
\r
17489 getWidth: function () {
\r
17490 return this._width;
\r
17496 getHeight: function () {
\r
17497 return this._height;
\r
17500 _getWidth: function () {
\r
17501 var root = this.root;
\r
17502 var stl = document.defaultView.getComputedStyle(root);
\r
17504 // FIXME Better way to get the width and height when element has not been append to the document
\r
17505 return ((root.clientWidth || parseInt10(stl.width) || parseInt10(root.style.width))
\r
17506 - (parseInt10(stl.paddingLeft) || 0)
\r
17507 - (parseInt10(stl.paddingRight) || 0)) | 0;
\r
17510 _getHeight: function () {
\r
17511 var root = this.root;
\r
17512 var stl = document.defaultView.getComputedStyle(root);
\r
17514 return ((root.clientHeight || parseInt10(stl.height) || parseInt10(root.style.height))
\r
17515 - (parseInt10(stl.paddingTop) || 0)
\r
17516 - (parseInt10(stl.paddingBottom) || 0)) | 0;
\r
17519 _pathToImage: function (id, path, width, height, dpr) {
\r
17520 var canvas = document.createElement('canvas');
\r
17521 var ctx = canvas.getContext('2d');
\r
17523 canvas.width = width * dpr;
\r
17524 canvas.height = height * dpr;
\r
17526 ctx.clearRect(0, 0, width * dpr, height * dpr);
\r
17528 var pathTransform = {
\r
17529 position: path.position,
\r
17530 rotation: path.rotation,
\r
17531 scale: path.scale
\r
17533 path.position = [0, 0, 0];
\r
17534 path.rotation = 0;
\r
17535 path.scale = [1, 1];
\r
17540 var ImageShape = __webpack_require__(59);
\r
17541 var imgShape = new ImageShape({
\r
17550 if (pathTransform.position != null) {
\r
17551 imgShape.position = path.position = pathTransform.position;
\r
17554 if (pathTransform.rotation != null) {
\r
17555 imgShape.rotation = path.rotation = pathTransform.rotation;
\r
17558 if (pathTransform.scale != null) {
\r
17559 imgShape.scale = path.scale = pathTransform.scale;
\r
17565 _createPathToImage: function () {
\r
17568 return function (id, e, width, height) {
\r
17569 return me._pathToImage(
\r
17570 id, e, width, height, me.dpr
\r
17576 module.exports = Painter;
\r
17582 /***/ function(module, exports, __webpack_require__) {
\r
17585 * @module zrender/Layer
\r
17586 * @author pissang(https://www.github.com/pissang)
\r
17590 var util = __webpack_require__(3);
\r
17591 var config = __webpack_require__(40);
\r
17593 function returnFalse() {
\r
17601 * @param {string} id dom id 待用
\r
17602 * @param {string} type dom type,such as canvas, div etc.
\r
17603 * @param {Painter} painter painter instance
\r
17604 * @param {number} number
\r
17606 function createDom(id, type, painter, dpr) {
\r
17607 var newDom = document.createElement(type);
\r
17608 var width = painter.getWidth();
\r
17609 var height = painter.getHeight();
\r
17611 var newDomStyle = newDom.style;
\r
17612 // 没append呢,请原谅我这样写,清晰~
\r
17613 newDomStyle.position = 'absolute';
\r
17614 newDomStyle.left = 0;
\r
17615 newDomStyle.top = 0;
\r
17616 newDomStyle.width = width + 'px';
\r
17617 newDomStyle.height = height + 'px';
\r
17618 newDom.width = width * dpr;
\r
17619 newDom.height = height * dpr;
\r
17621 // id不作为索引用,避免可能造成的重名,定义为私有属性
\r
17622 newDom.setAttribute('data-zr-dom-id', id);
\r
17627 * @alias module:zrender/Layer
\r
17629 * @extends module:zrender/mixin/Transformable
\r
17630 * @param {string} id
\r
17631 * @param {module:zrender/Painter} painter
\r
17632 * @param {number} [dpr]
\r
17634 var Layer = function(id, painter, dpr) {
\r
17636 dpr = dpr || config.devicePixelRatio;
\r
17637 if (typeof id === 'string') {
\r
17638 dom = createDom(id, 'canvas', painter, dpr);
\r
17640 // Not using isDom because in node it will return false
\r
17641 else if (util.isObject(id)) {
\r
17648 var domStyle = dom.style;
\r
17649 if (domStyle) { // Not in node
\r
17650 dom.onselectstart = returnFalse; // 避免页面选中的尴尬
\r
17651 domStyle['-webkit-user-select'] = 'none';
\r
17652 domStyle['user-select'] = 'none';
\r
17653 domStyle['-webkit-touch-callout'] = 'none';
\r
17654 domStyle['-webkit-tap-highlight-color'] = 'rgba(0,0,0,0)';
\r
17657 this.domBack = null;
\r
17658 this.ctxBack = null;
\r
17660 this.painter = painter;
\r
17662 this.config = null;
\r
17670 this.clearColor = 0;
\r
17673 * @type {boolean}
\r
17676 this.motionBlur = false;
\r
17678 * 在开启动态模糊的时候使用,与上一帧混合的alpha值,值越大尾迹越明显
\r
17682 this.lastFrameAlpha = 0.7;
\r
17691 Layer.prototype = {
\r
17693 constructor: Layer,
\r
17699 initContext: function () {
\r
17700 this.ctx = this.dom.getContext('2d');
\r
17702 var dpr = this.dpr;
\r
17704 this.ctx.scale(dpr, dpr);
\r
17708 createBackBuffer: function () {
\r
17709 var dpr = this.dpr;
\r
17711 this.domBack = createDom('back-' + this.id, 'canvas', this.painter, dpr);
\r
17712 this.ctxBack = this.domBack.getContext('2d');
\r
17715 this.ctxBack.scale(dpr, dpr);
\r
17720 * @param {number} width
\r
17721 * @param {number} height
\r
17723 resize: function (width, height) {
\r
17724 var dpr = this.dpr;
\r
17726 var dom = this.dom;
\r
17727 var domStyle = dom.style;
\r
17728 var domBack = this.domBack;
\r
17730 domStyle.width = width + 'px';
\r
17731 domStyle.height = height + 'px';
\r
17733 dom.width = width * dpr;
\r
17734 dom.height = height * dpr;
\r
17737 this.ctx.scale(dpr, dpr);
\r
17741 domBack.width = width * dpr;
\r
17742 domBack.height = height * dpr;
\r
17745 this.ctxBack.scale(dpr, dpr);
\r
17752 * @param {boolean} clearAll Clear all with out motion blur
\r
17754 clear: function (clearAll) {
\r
17755 var dom = this.dom;
\r
17756 var ctx = this.ctx;
\r
17757 var width = dom.width;
\r
17758 var height = dom.height;
\r
17760 var haveClearColor = this.clearColor;
\r
17761 var haveMotionBLur = this.motionBlur && !clearAll;
\r
17762 var lastFrameAlpha = this.lastFrameAlpha;
\r
17764 var dpr = this.dpr;
\r
17766 if (haveMotionBLur) {
\r
17767 if (!this.domBack) {
\r
17768 this.createBackBuffer();
\r
17771 this.ctxBack.globalCompositeOperation = 'copy';
\r
17772 this.ctxBack.drawImage(
\r
17779 ctx.clearRect(0, 0, width / dpr, height / dpr);
\r
17780 if (haveClearColor) {
\r
17782 ctx.fillStyle = this.clearColor;
\r
17783 ctx.fillRect(0, 0, width / dpr, height / dpr);
\r
17787 if (haveMotionBLur) {
\r
17788 var domBack = this.domBack;
\r
17790 ctx.globalAlpha = lastFrameAlpha;
\r
17791 ctx.drawImage(domBack, 0, 0, width / dpr, height / dpr);
\r
17797 module.exports = Layer;
\r
17802 /***/ function(module, exports, __webpack_require__) {
\r
17806 var graphic = __webpack_require__(42);
\r
17807 var zrUtil = __webpack_require__(3);
\r
17808 var PI = Math.PI;
\r
17810 * @param {module:echarts/ExtensionAPI} api
\r
17811 * @param {Object} [opts]
\r
17812 * @param {string} [opts.text]
\r
17813 * @param {string} [opts.color]
\r
17814 * @param {string} [opts.textColor]
\r
17815 * @return {module:zrender/Element}
\r
17817 module.exports = function (api, opts) {
\r
17818 opts = opts || {};
\r
17819 zrUtil.defaults(opts, {
\r
17821 color: '#c23531',
\r
17822 textColor: '#000',
\r
17823 maskColor: 'rgba(255, 255, 255, 0.8)',
\r
17826 var mask = new graphic.Rect({
\r
17828 fill: opts.maskColor
\r
17830 zlevel: opts.zlevel,
\r
17833 var arc = new graphic.Arc({
\r
17835 startAngle: -PI / 2,
\r
17836 endAngle: -PI / 2 + 0.1,
\r
17840 stroke: opts.color,
\r
17841 lineCap: 'round',
\r
17844 zlevel: opts.zlevel,
\r
17847 var labelRect = new graphic.Rect({
\r
17851 textPosition: 'right',
\r
17852 textDistance: 10,
\r
17853 textFill: opts.textColor
\r
17855 zlevel: opts.zlevel,
\r
17859 arc.animateShape(true)
\r
17861 endAngle: PI * 3 / 2
\r
17863 .start('circularInOut');
\r
17864 arc.animateShape(true)
\r
17866 startAngle: PI * 3 / 2
\r
17869 .start('circularInOut');
\r
17871 var group = new graphic.Group();
\r
17873 group.add(labelRect);
\r
17876 group.resize = function () {
\r
17877 var cx = api.getWidth() / 2;
\r
17878 var cy = api.getHeight() / 2;
\r
17883 var r = arc.shape.r;
\r
17884 labelRect.setShape({
\r
17894 width: api.getWidth(),
\r
17895 height: api.getHeight()
\r
17905 /***/ function(module, exports, __webpack_require__) {
\r
17908 var Gradient = __webpack_require__(4);
\r
17909 module.exports = function (seriesType, styleType, ecModel) {
\r
17910 function encodeColor(seriesModel) {
\r
17911 var colorAccessPath = [styleType, 'normal', 'color'];
\r
17912 var colorList = ecModel.get('color');
\r
17913 var data = seriesModel.getData();
\r
17914 var color = seriesModel.get(colorAccessPath) // Set in itemStyle
\r
17915 || colorList[seriesModel.seriesIndex % colorList.length]; // Default color
\r
17917 // FIXME Set color function or use the platte color
\r
17918 data.setVisual('color', color);
\r
17920 // Only visible series has each data be visual encoded
\r
17921 if (!ecModel.isSeriesFiltered(seriesModel)) {
\r
17922 if (typeof color === 'function' && !(color instanceof Gradient)) {
\r
17923 data.each(function (idx) {
\r
17924 data.setItemVisual(
\r
17925 idx, 'color', color(seriesModel.getDataParams(idx))
\r
17930 data.each(function (idx) {
\r
17931 var itemModel = data.getItemModel(idx);
\r
17932 var color = itemModel.get(colorAccessPath, true);
\r
17933 if (color != null) {
\r
17934 data.setItemVisual(idx, 'color', color);
\r
17939 seriesType ? ecModel.eachSeriesByType(seriesType, encodeColor)
\r
17940 : ecModel.eachSeries(encodeColor);
\r
17946 /***/ function(module, exports, __webpack_require__) {
\r
17948 // Compatitable with 2.0
\r
17951 var zrUtil = __webpack_require__(3);
\r
17952 var compatStyle = __webpack_require__(90);
\r
17954 function get(opt, path) {
\r
17955 path = path.split(',');
\r
17957 for (var i = 0; i < path.length; i++) {
\r
17958 obj = obj && obj[path[i]];
\r
17959 if (obj == null) {
\r
17966 function set(opt, path, val, overwrite) {
\r
17967 path = path.split(',');
\r
17970 for (var i = 0; i < path.length - 1; i++) {
\r
17972 if (obj[key] == null) {
\r
17977 if (overwrite || obj[path[i]] == null) {
\r
17978 obj[path[i]] = val;
\r
17982 function compatLayoutProperties(option) {
\r
17983 each(LAYOUT_PROPERTIES, function (prop) {
\r
17984 if (prop[0] in option && !(prop[1] in option)) {
\r
17985 option[prop[1]] = option[prop[0]];
\r
17990 var LAYOUT_PROPERTIES = [
\r
17991 ['x', 'left'], ['y', 'top'], ['x2', 'right'], ['y2', 'bottom']
\r
17994 var COMPATITABLE_COMPONENTS = [
\r
17995 'grid', 'geo', 'parallel', 'legend', 'toolbox', 'title', 'visualMap', 'dataZoom', 'timeline'
\r
17998 var COMPATITABLE_SERIES = [
\r
17999 'bar', 'boxplot', 'candlestick', 'chord', 'effectScatter',
\r
18000 'funnel', 'gauge', 'lines', 'graph', 'heatmap', 'line', 'map', 'parallel',
\r
18001 'pie', 'radar', 'sankey', 'scatter', 'treemap'
\r
18004 var each = zrUtil.each;
\r
18006 module.exports = function (option) {
\r
18007 each(option.series, function (seriesOpt) {
\r
18008 if (!zrUtil.isObject(seriesOpt)) {
\r
18012 var seriesType = seriesOpt.type;
\r
18014 compatStyle(seriesOpt);
\r
18016 if (seriesType === 'pie' || seriesType === 'gauge') {
\r
18017 if (seriesOpt.clockWise != null) {
\r
18018 seriesOpt.clockwise = seriesOpt.clockWise;
\r
18021 if (seriesType === 'gauge') {
\r
18022 var pointerColor = get(seriesOpt, 'pointer.color');
\r
18023 pointerColor != null
\r
18024 && set(seriesOpt, 'itemStyle.normal.color', pointerColor);
\r
18027 for (var i = 0; i < COMPATITABLE_SERIES.length; i++) {
\r
18028 if (COMPATITABLE_SERIES[i] === seriesOpt.type) {
\r
18029 compatLayoutProperties(seriesOpt);
\r
18035 // dataRange has changed to visualMap
\r
18036 if (option.dataRange) {
\r
18037 option.visualMap = option.dataRange;
\r
18040 each(COMPATITABLE_COMPONENTS, function (componentName) {
\r
18041 var options = option[componentName];
\r
18043 if (!zrUtil.isArray(options)) {
\r
18044 options = [options];
\r
18046 each(options, function (option) {
\r
18047 compatLayoutProperties(option);
\r
18056 /***/ function(module, exports, __webpack_require__) {
\r
18060 var zrUtil = __webpack_require__(3);
\r
18062 var POSSIBLE_STYLES = [
\r
18063 'areaStyle', 'lineStyle', 'nodeStyle', 'linkStyle',
\r
18064 'chordStyle', 'label', 'labelLine'
\r
18067 function compatItemStyle(opt) {
\r
18068 var itemStyleOpt = opt && opt.itemStyle;
\r
18069 if (itemStyleOpt) {
\r
18070 zrUtil.each(POSSIBLE_STYLES, function (styleName) {
\r
18071 var normalItemStyleOpt = itemStyleOpt.normal;
\r
18072 var emphasisItemStyleOpt = itemStyleOpt.emphasis;
\r
18073 if (normalItemStyleOpt && normalItemStyleOpt[styleName]) {
\r
18074 opt[styleName] = opt[styleName] || {};
\r
18075 if (!opt[styleName].normal) {
\r
18076 opt[styleName].normal = normalItemStyleOpt[styleName];
\r
18079 zrUtil.merge(opt[styleName].normal, normalItemStyleOpt[styleName]);
\r
18081 normalItemStyleOpt[styleName] = null;
\r
18083 if (emphasisItemStyleOpt && emphasisItemStyleOpt[styleName]) {
\r
18084 opt[styleName] = opt[styleName] || {};
\r
18085 if (!opt[styleName].emphasis) {
\r
18086 opt[styleName].emphasis = emphasisItemStyleOpt[styleName];
\r
18089 zrUtil.merge(opt[styleName].emphasis, emphasisItemStyleOpt[styleName]);
\r
18091 emphasisItemStyleOpt[styleName] = null;
\r
18097 module.exports = function (seriesOpt) {
\r
18098 if (!seriesOpt) {
\r
18101 compatItemStyle(seriesOpt);
\r
18102 compatItemStyle(seriesOpt.markPoint);
\r
18103 compatItemStyle(seriesOpt.markLine);
\r
18104 var data = seriesOpt.data;
\r
18106 for (var i = 0; i < data.length; i++) {
\r
18107 compatItemStyle(data[i]);
\r
18109 // mark point data
\r
18110 var markPoint = seriesOpt.markPoint;
\r
18111 if (markPoint && markPoint.data) {
\r
18112 var mpData = markPoint.data;
\r
18113 for (var i = 0; i < mpData.length; i++) {
\r
18114 compatItemStyle(mpData[i]);
\r
18117 // mark line data
\r
18118 var markLine = seriesOpt.markLine;
\r
18119 if (markLine && markLine.data) {
\r
18120 var mlData = markLine.data;
\r
18121 for (var i = 0; i < mlData.length; i++) {
\r
18122 if (zrUtil.isArray(mlData[i])) {
\r
18123 compatItemStyle(mlData[i][0]);
\r
18124 compatItemStyle(mlData[i][1]);
\r
18127 compatItemStyle(mlData[i]);
\r
18137 /***/ function(module, exports, __webpack_require__) {
\r
18141 var zrUtil = __webpack_require__(3);
\r
18142 var echarts = __webpack_require__(1);
\r
18144 __webpack_require__(92);
\r
18145 __webpack_require__(97);
\r
18147 echarts.registerVisualCoding('chart', zrUtil.curry(
\r
18148 __webpack_require__(103), 'line', 'circle', 'line'
\r
18150 echarts.registerLayout(zrUtil.curry(
\r
18151 __webpack_require__(104), 'line'
\r
18154 // Down sample after filter
\r
18155 echarts.registerProcessor('statistic', zrUtil.curry(
\r
18156 __webpack_require__(105), 'line'
\r
18159 // In case developer forget to include grid component
\r
18160 __webpack_require__(106);
\r
18165 /***/ function(module, exports, __webpack_require__) {
\r
18170 var createListFromArray = __webpack_require__(93);
\r
18171 var SeriesModel = __webpack_require__(27);
\r
18173 module.exports = SeriesModel.extend({
\r
18175 type: 'series.line',
\r
18177 dependencies: ['grid', 'polar'],
\r
18179 getInitialData: function (option, ecModel) {
\r
18180 return createListFromArray(option.data, this, ecModel);
\r
18184 zlevel: 0, // 一级层叠
\r
18186 coordinateSystem: 'cartesian2d',
\r
18187 legendHoverLink: true,
\r
18189 hoverAnimation: true,
\r
18196 // If clip the overflow value
\r
18197 clipOverflow: true,
\r
18203 // formatter: 标签文本格式器,同Tooltip.formatter,不支持异步回调
\r
18204 // position: 默认自适应,水平布局为'top',垂直布局为'right',可选为
\r
18205 // 'inside'|'left'|'right'|'top'|'bottom'
\r
18206 // textStyle: null // 默认使用全局文本样式,详见TEXTSTYLE
\r
18210 // position: 'top'
\r
18211 // formatter: 标签文本格式器,同Tooltip.formatter,不支持异步回调
\r
18212 // position: 默认自适应,水平布局为'top',垂直布局为'right',可选为
\r
18213 // 'inside'|'left'|'right'|'top'|'bottom'
\r
18214 // textStyle: null // 默认使用全局文本样式,详见TEXTSTYLE
\r
18233 // smooth: false,
\r
18234 // smoothMonotone: null,
\r
18236 symbol: 'emptyCircle',
\r
18240 // symbolRotate: null,
\r
18242 // 是否显示 symbol, 只有在 tooltip hover 的时候显示
\r
18243 showSymbol: true,
\r
18244 // 标志图形默认只有主轴显示(随主轴标签间隔隐藏策略)
\r
18245 // showAllSymbol: false
\r
18247 // 大数据过滤,'average', 'max', 'min', 'sum'
\r
18248 // sampling: 'none'
\r
18250 animationEasing: 'linear'
\r
18257 /***/ function(module, exports, __webpack_require__) {
\r
18262 var List = __webpack_require__(94);
\r
18263 var completeDimensions = __webpack_require__(96);
\r
18264 var zrUtil = __webpack_require__(3);
\r
18265 var modelUtil = __webpack_require__(5);
\r
18266 var CoordinateSystem = __webpack_require__(25);
\r
18267 var getDataItemValue = modelUtil.getDataItemValue;
\r
18268 var converDataValue = modelUtil.converDataValue;
\r
18270 function firstDataNotNull(data) {
\r
18272 while (i < data.length && data[i] == null) {
\r
18277 function ifNeedCompleteOrdinalData(data) {
\r
18278 var sampleItem = firstDataNotNull(data);
\r
18279 return sampleItem != null
\r
18280 && !zrUtil.isArray(getDataItemValue(sampleItem));
\r
18284 * Helper function to create a list from option data
\r
18286 function createListFromArray(data, seriesModel, ecModel) {
\r
18287 // If data is undefined
\r
18288 data = data || [];
\r
18290 var coordSysName = seriesModel.get('coordinateSystem');
\r
18291 var creator = creators[coordSysName];
\r
18292 var registeredCoordSys = CoordinateSystem.get(coordSysName);
\r
18294 var result = creator && creator(data, seriesModel, ecModel);
\r
18295 var dimensions = result && result.dimensions;
\r
18296 if (!dimensions) {
\r
18297 // Get dimensions from registered coordinate system
\r
18298 dimensions = (registeredCoordSys && registeredCoordSys.dimensions) || ['x', 'y'];
\r
18299 dimensions = completeDimensions(dimensions, data, dimensions.concat(['value']));
\r
18301 var categoryAxisModel = result && result.categoryAxisModel;
\r
18303 var categoryDimIndex = dimensions[0].type === 'ordinal'
\r
18304 ? 0 : (dimensions[1].type === 'ordinal' ? 1 : -1);
\r
18306 var list = new List(dimensions, seriesModel);
\r
18308 var nameList = createNameList(result, data);
\r
18310 var dimValueGetter = (categoryAxisModel && ifNeedCompleteOrdinalData(data))
\r
18311 ? function (itemOpt, dimName, dataIndex, dimIndex) {
\r
18312 // Use dataIndex as ordinal value in categoryAxis
\r
18313 return dimIndex === categoryDimIndex
\r
18315 : converDataValue(getDataItemValue(itemOpt), dimensions[dimIndex]);
\r
18317 : function (itemOpt, dimName, dataIndex, dimIndex) {
\r
18318 var val = getDataItemValue(itemOpt);
\r
18319 return converDataValue(val && val[dimIndex], dimensions[dimIndex]);
\r
18322 list.initData(data, nameList, dimValueGetter);
\r
18327 function isStackable(axisType) {
\r
18328 return axisType !== 'category' && axisType !== 'time';
\r
18331 function getDimTypeByAxis(axisType) {
\r
18332 return axisType === 'category'
\r
18334 : axisType === 'time'
\r
18340 * Creaters for each coord system.
\r
18341 * @return {Object} {dimensions, categoryAxisModel};
\r
18345 cartesian2d: function (data, seriesModel, ecModel) {
\r
18346 var xAxisModel = ecModel.getComponent('xAxis', seriesModel.get('xAxisIndex'));
\r
18347 var yAxisModel = ecModel.getComponent('yAxis', seriesModel.get('yAxisIndex'));
\r
18348 var xAxisType = xAxisModel.get('type');
\r
18349 var yAxisType = yAxisModel.get('type');
\r
18351 var dimensions = [
\r
18354 type: getDimTypeByAxis(xAxisType),
\r
18355 stackable: isStackable(xAxisType)
\r
18359 // If two category axes
\r
18360 type: getDimTypeByAxis(yAxisType),
\r
18361 stackable: isStackable(yAxisType)
\r
18365 var isXAxisCateogry = xAxisType === 'category';
\r
18367 completeDimensions(dimensions, data, ['x', 'y', 'z']);
\r
18370 dimensions: dimensions,
\r
18371 categoryIndex: isXAxisCateogry ? 0 : 1,
\r
18372 categoryAxisModel: isXAxisCateogry
\r
18374 : (yAxisType === 'category' ? yAxisModel : null)
\r
18378 polar: function (data, seriesModel, ecModel) {
\r
18379 var polarIndex = seriesModel.get('polarIndex') || 0;
\r
18381 var axisFinder = function (axisModel) {
\r
18382 return axisModel.get('polarIndex') === polarIndex;
\r
18385 var angleAxisModel = ecModel.findComponents({
\r
18386 mainType: 'angleAxis', filter: axisFinder
\r
18388 var radiusAxisModel = ecModel.findComponents({
\r
18389 mainType: 'radiusAxis', filter: axisFinder
\r
18392 var radiusAxisType = radiusAxisModel.get('type');
\r
18393 var angleAxisType = angleAxisModel.get('type');
\r
18395 var dimensions = [
\r
18398 type: getDimTypeByAxis(radiusAxisType),
\r
18399 stackable: isStackable(radiusAxisType)
\r
18403 type: getDimTypeByAxis(angleAxisType),
\r
18404 stackable: isStackable(angleAxisType)
\r
18407 var isAngleAxisCateogry = angleAxisType === 'category';
\r
18409 completeDimensions(dimensions, data, ['radius', 'angle', 'value']);
\r
18412 dimensions: dimensions,
\r
18413 categoryIndex: isAngleAxisCateogry ? 1 : 0,
\r
18414 categoryAxisModel: isAngleAxisCateogry
\r
18416 : (radiusAxisType === 'category' ? radiusAxisModel : null)
\r
18420 geo: function (data, seriesModel, ecModel) {
\r
18422 // 多个散点图系列在同一个地区的时候
\r
18424 dimensions: completeDimensions([
\r
18427 ], data, ['lng', 'lat', 'value'])
\r
18432 function createNameList(result, data) {
\r
18433 var nameList = [];
\r
18435 if (result && result.categoryAxisModel) {
\r
18436 // FIXME Two category axis
\r
18437 var categories = result.categoryAxisModel.getCategories();
\r
18438 if (categories) {
\r
18439 var dataLen = data.length;
\r
18440 // Ordered data is given explicitly like
\r
18441 // [[3, 0.2], [1, 0.3], [2, 0.15]]
\r
18442 // or given scatter data,
\r
18443 // pick the category
\r
18444 if (zrUtil.isArray(data[0]) && data[0].length > 1) {
\r
18446 for (var i = 0; i < dataLen; i++) {
\r
18447 nameList[i] = categories[data[i][result.categoryIndex || 0]];
\r
18451 nameList = categories.slice(0);
\r
18459 module.exports = createListFromArray;
\r
18465 /***/ function(module, exports, __webpack_require__) {
\r
18467 /* WEBPACK VAR INJECTION */(function(global) {/**
\r
18468 * List for data storage
\r
18469 * @module echarts/data/List
\r
18473 var UNDEFINED = 'undefined';
\r
18474 var globalObj = typeof window === 'undefined' ? global : window;
\r
18475 var Float64Array = typeof globalObj.Float64Array === UNDEFINED
\r
18476 ? Array : globalObj.Float64Array;
\r
18477 var Int32Array = typeof globalObj.Int32Array === UNDEFINED
\r
18478 ? Array : globalObj.Int32Array;
\r
18480 var dataCtors = {
\r
18481 'float': Float64Array,
\r
18482 'int': Int32Array,
\r
18483 // Ordinal data type can be string or int
\r
18484 'ordinal': Array,
\r
18489 var Model = __webpack_require__(8);
\r
18490 var DataDiffer = __webpack_require__(95);
\r
18492 var zrUtil = __webpack_require__(3);
\r
18493 var modelUtil = __webpack_require__(5);
\r
18494 var isObject = zrUtil.isObject;
\r
18496 var IMMUTABLE_PROPERTIES = [
\r
18497 'stackedOn', '_nameList', '_idList', '_rawData'
\r
18500 var transferImmuProperties = function (a, b, wrappedMethod) {
\r
18501 zrUtil.each(IMMUTABLE_PROPERTIES.concat(wrappedMethod || []), function (propName) {
\r
18502 if (b.hasOwnProperty(propName)) {
\r
18503 a[propName] = b[propName];
\r
18510 * @alias module:echarts/data/List
\r
18512 * @param {Array.<string>} dimensions
\r
18513 * Dimensions should be concrete names like x, y, z, lng, lat, angle, radius
\r
18514 * @param {module:echarts/model/Model} hostModel
\r
18516 var List = function (dimensions, hostModel) {
\r
18518 dimensions = dimensions || ['x', 'y'];
\r
18520 var dimensionInfos = {};
\r
18521 var dimensionNames = [];
\r
18522 for (var i = 0; i < dimensions.length; i++) {
\r
18523 var dimensionName;
\r
18524 var dimensionInfo = {};
\r
18525 if (typeof dimensions[i] === 'string') {
\r
18526 dimensionName = dimensions[i];
\r
18527 dimensionInfo = {
\r
18528 name: dimensionName,
\r
18529 stackable: false,
\r
18530 // Type can be 'float', 'int', 'number'
\r
18531 // Default is number, Precision of float may not enough
\r
18536 dimensionInfo = dimensions[i];
\r
18537 dimensionName = dimensionInfo.name;
\r
18538 dimensionInfo.type = dimensionInfo.type || 'number';
\r
18540 dimensionNames.push(dimensionName);
\r
18541 dimensionInfos[dimensionName] = dimensionInfo;
\r
18545 * @type {Array.<string>}
\r
18547 this.dimensions = dimensionNames;
\r
18550 * Infomation of each data dimension, like data type.
\r
18553 this._dimensionInfos = dimensionInfos;
\r
18556 * @type {module:echarts/model/Model}
\r
18558 this.hostModel = hostModel;
\r
18561 * Indices stores the indices of data subset after filtered.
\r
18562 * This data subset will be used in chart.
\r
18563 * @type {Array.<number>}
\r
18566 this.indices = [];
\r
18570 * @type {Object.<key, TypedArray|Array>}
\r
18573 this._storage = {};
\r
18576 * @type {Array.<string>}
\r
18578 this._nameList = [];
\r
18580 * @type {Array.<string>}
\r
18582 this._idList = [];
\r
18584 * Models of data option is stored sparse for optimizing memory cost
\r
18585 * @type {Array.<module:echarts/model/Model>}
\r
18588 this._optionModels = [];
\r
18591 * @param {module:echarts/data/List}
\r
18593 this.stackedOn = null;
\r
18596 * Global visual properties after visual coding
\r
18600 this._visual = {};
\r
18603 * Globel layout properties.
\r
18607 this._layout = {};
\r
18610 * Item visual properties after visual coding
\r
18611 * @type {Array.<Object>}
\r
18614 this._itemVisuals = [];
\r
18617 * Item layout properties after layout
\r
18618 * @type {Array.<Object>}
\r
18621 this._itemLayouts = [];
\r
18624 * Graphic elemnents
\r
18625 * @type {Array.<module:zrender/Element>}
\r
18628 this._graphicEls = [];
\r
18631 * @type {Array.<Array|Object>}
\r
18643 var listProto = List.prototype;
\r
18645 listProto.type = 'list';
\r
18648 * Get dimension name
\r
18649 * @param {string|number} dim
\r
18650 * Dimension can be concrete names like x, y, z, lng, lat, angle, radius
\r
18651 * Or a ordinal number. For example getDimensionInfo(0) will return 'x' or 'lng' or 'radius'
\r
18653 listProto.getDimension = function (dim) {
\r
18654 if (!isNaN(dim)) {
\r
18655 dim = this.dimensions[dim] || dim;
\r
18660 * Get type and stackable info of particular dimension
\r
18661 * @param {string|number} dim
\r
18662 * Dimension can be concrete names like x, y, z, lng, lat, angle, radius
\r
18663 * Or a ordinal number. For example getDimensionInfo(0) will return 'x' or 'lng' or 'radius'
\r
18665 listProto.getDimensionInfo = function (dim) {
\r
18666 return zrUtil.clone(this._dimensionInfos[this.getDimension(dim)]);
\r
18670 * Initialize from data
\r
18671 * @param {Array.<Object|number|Array>} data
\r
18672 * @param {Array.<string>} [nameList]
\r
18673 * @param {Function} [dimValueGetter] (dataItem, dimName, dataIndex, dimIndex) => number
\r
18675 listProto.initData = function (data, nameList, dimValueGetter) {
\r
18676 data = data || [];
\r
18678 this._rawData = data;
\r
18681 var storage = this._storage = {};
\r
18682 var indices = this.indices = [];
\r
18684 var dimensions = this.dimensions;
\r
18685 var size = data.length;
\r
18686 var dimensionInfoMap = this._dimensionInfos;
\r
18689 var nameRepeatCount = {};
\r
18691 nameList = nameList || [];
\r
18694 for (var i = 0; i < dimensions.length; i++) {
\r
18695 var dimInfo = dimensionInfoMap[dimensions[i]];
\r
18696 var DataCtor = dataCtors[dimInfo.type];
\r
18697 storage[dimensions[i]] = new DataCtor(size);
\r
18700 // Default dim value getter
\r
18701 dimValueGetter = dimValueGetter || function (dataItem, dimName, dataIndex, dimIndex) {
\r
18702 var value = modelUtil.getDataItemValue(dataItem);
\r
18703 return modelUtil.converDataValue(
\r
18704 zrUtil.isArray(value)
\r
18705 ? value[dimIndex]
\r
18706 // If value is a single number or something else not array.
\r
18708 dimensionInfoMap[dimName]
\r
18712 for (var idx = 0; idx < data.length; idx++) {
\r
18713 var dataItem = data[idx];
\r
18714 // Each data item is value
\r
18717 // Bar chart, line chart which uses category axis
\r
18718 // only gives the 'y' value. 'x' value is the indices of cateogry
\r
18719 // Use a tempValue to normalize the value to be a (x, y) value
\r
18721 // Store the data by dimensions
\r
18722 for (var k = 0; k < dimensions.length; k++) {
\r
18723 var dim = dimensions[k];
\r
18724 var dimStorage = storage[dim];
\r
18725 // PENDING NULL is empty or zero
\r
18726 dimStorage[idx] = dimValueGetter(dataItem, dim, idx, k);
\r
18729 indices.push(idx);
\r
18732 // Use the name in option and create id
\r
18733 for (var i = 0; i < data.length; i++) {
\r
18735 if (!nameList[i]) {
\r
18736 nameList[i] = data[i].name;
\r
18737 // Try using the id in option
\r
18740 var name = nameList[i] || '';
\r
18741 if (!id && name) {
\r
18742 // Use name as id and add counter to avoid same name
\r
18743 nameRepeatCount[name] = nameRepeatCount[name] || 0;
\r
18745 if (nameRepeatCount[name] > 0) {
\r
18746 id += '__ec__' + nameRepeatCount[name];
\r
18748 nameRepeatCount[name]++;
\r
18750 id && (idList[i] = id);
\r
18753 this._nameList = nameList;
\r
18754 this._idList = idList;
\r
18758 * @return {number}
\r
18760 listProto.count = function () {
\r
18761 return this.indices.length;
\r
18765 * Get value. Return NaN if idx is out of range.
\r
18766 * @param {string} dim Dim must be concrete name.
\r
18767 * @param {number} idx
\r
18768 * @param {boolean} stack
\r
18769 * @return {number}
\r
18771 listProto.get = function (dim, idx, stack) {
\r
18772 var storage = this._storage;
\r
18773 var dataIndex = this.indices[idx];
\r
18775 // If value not exists
\r
18776 if (dataIndex == null) {
\r
18780 var value = storage[dim] && storage[dim][dataIndex];
\r
18781 // FIXME ordinal data type is not stackable
\r
18783 var dimensionInfo = this._dimensionInfos[dim];
\r
18784 if (dimensionInfo && dimensionInfo.stackable) {
\r
18785 var stackedOn = this.stackedOn;
\r
18786 while (stackedOn) {
\r
18787 // Get no stacked data of stacked on
\r
18788 var stackedValue = stackedOn.get(dim, idx);
\r
18789 // Considering positive stack, negative stack and empty data
\r
18790 if ((value >= 0 && stackedValue > 0) // Positive stack
\r
18791 || (value <= 0 && stackedValue < 0) // Negative stack
\r
18793 value += stackedValue;
\r
18795 stackedOn = stackedOn.stackedOn;
\r
18803 * Get value for multi dimensions.
\r
18804 * @param {Array.<string>} [dimensions] If ignored, using all dimensions.
\r
18805 * @param {number} idx
\r
18806 * @param {boolean} stack
\r
18807 * @return {number}
\r
18809 listProto.getValues = function (dimensions, idx, stack) {
\r
18812 if (!zrUtil.isArray(dimensions)) {
\r
18814 idx = dimensions;
\r
18815 dimensions = this.dimensions;
\r
18818 for (var i = 0, len = dimensions.length; i < len; i++) {
\r
18819 values.push(this.get(dimensions[i], idx, stack));
\r
18826 * If value is NaN. Inlcuding '-'
\r
18827 * @param {string} dim
\r
18828 * @param {number} idx
\r
18829 * @return {number}
\r
18831 listProto.hasValue = function (idx) {
\r
18832 var dimensions = this.dimensions;
\r
18833 var dimensionInfos = this._dimensionInfos;
\r
18834 for (var i = 0, len = dimensions.length; i < len; i++) {
\r
18836 // Ordinal type can be string or number
\r
18837 dimensionInfos[dimensions[i]].type !== 'ordinal'
\r
18838 && isNaN(this.get(dimensions[i], idx))
\r
18847 * Get extent of data in one dimension
\r
18848 * @param {string} dim
\r
18849 * @param {boolean} stack
\r
18851 listProto.getDataExtent = function (dim, stack) {
\r
18852 var dimData = this._storage[dim];
\r
18853 var dimInfo = this.getDimensionInfo(dim);
\r
18854 stack = (dimInfo && dimInfo.stackable) && stack;
\r
18855 var dimExtent = (this._extent || (this._extent = {}))[dim + (!!stack)];
\r
18858 return dimExtent;
\r
18860 // var dimInfo = this._dimensionInfos[dim];
\r
18862 var min = Infinity;
\r
18863 var max = -Infinity;
\r
18864 // var isOrdinal = dimInfo.type === 'ordinal';
\r
18865 for (var i = 0, len = this.count(); i < len; i++) {
\r
18866 value = this.get(dim, i, stack);
\r
18868 // if (isOrdinal && typeof value === 'string') {
\r
18869 // value = zrUtil.indexOf(dimData, value);
\r
18870 // console.log(value);
\r
18872 value < min && (min = value);
\r
18873 value > max && (max = value);
\r
18875 return (this._extent[dim + stack] = [min, max]);
\r
18878 return [Infinity, -Infinity];
\r
18883 * Get sum of data in one dimension
\r
18884 * @param {string} dim
\r
18885 * @param {boolean} stack
\r
18887 listProto.getSum = function (dim, stack) {
\r
18888 var dimData = this._storage[dim];
\r
18891 for (var i = 0, len = this.count(); i < len; i++) {
\r
18892 var value = this.get(dim, i, stack);
\r
18893 if (!isNaN(value)) {
\r
18902 * Retreive the index with given value
\r
18903 * @param {number} idx
\r
18904 * @param {number} value
\r
18905 * @return {number}
\r
18907 // FIXME Precision of float value
\r
18908 listProto.indexOf = function (dim, value) {
\r
18909 var storage = this._storage;
\r
18910 var dimData = storage[dim];
\r
18911 var indices = this.indices;
\r
18914 for (var i = 0, len = indices.length; i < len; i++) {
\r
18915 var rawIndex = indices[i];
\r
18916 if (dimData[rawIndex] === value) {
\r
18925 * Retreive the index with given name
\r
18926 * @param {number} idx
\r
18927 * @param {number} name
\r
18928 * @return {number}
\r
18930 listProto.indexOfName = function (name) {
\r
18931 var indices = this.indices;
\r
18932 var nameList = this._nameList;
\r
18934 for (var i = 0, len = indices.length; i < len; i++) {
\r
18935 var rawIndex = indices[i];
\r
18936 if (nameList[rawIndex] === name) {
\r
18945 * Retreive the index of nearest value
\r
18946 * @param {string>} dim
\r
18947 * @param {number} value
\r
18948 * @param {boolean} stack If given value is after stacked
\r
18949 * @return {number}
\r
18951 listProto.indexOfNearest = function (dim, value, stack) {
\r
18952 var storage = this._storage;
\r
18953 var dimData = storage[dim];
\r
18956 var minDist = Number.MAX_VALUE;
\r
18957 var nearestIdx = -1;
\r
18958 for (var i = 0, len = this.count(); i < len; i++) {
\r
18959 var diff = value - this.get(dim, i, stack);
\r
18960 var dist = Math.abs(diff);
\r
18961 if (dist < minDist
\r
18962 // For the case of two data are same on xAxis, which has sequence data.
\r
18963 // Show the nearest index
\r
18964 // https://github.com/ecomfe/echarts/issues/2869
\r
18965 || (dist === minDist && diff > 0)
\r
18971 return nearestIdx;
\r
18977 * Get raw data index
\r
18978 * @param {number} idx
\r
18979 * @return {number}
\r
18981 listProto.getRawIndex = function (idx) {
\r
18982 var rawIdx = this.indices[idx];
\r
18983 return rawIdx == null ? -1 : rawIdx;
\r
18987 * @param {number} idx
\r
18988 * @param {boolean} [notDefaultIdx=false]
\r
18989 * @return {string}
\r
18991 listProto.getName = function (idx) {
\r
18992 return this._nameList[this.indices[idx]] || '';
\r
18996 * @param {number} idx
\r
18997 * @param {boolean} [notDefaultIdx=false]
\r
18998 * @return {string}
\r
19000 listProto.getId = function (idx) {
\r
19001 return this._idList[this.indices[idx]] || (this.getRawIndex(idx) + '');
\r
19005 function normalizeDimensions(dimensions) {
\r
19006 if (!zrUtil.isArray(dimensions)) {
\r
19007 dimensions = [dimensions];
\r
19009 return dimensions;
\r
19014 * @param {string|Array.<string>}
\r
19015 * @param {Function} cb
\r
19016 * @param {boolean} [stack=false]
\r
19017 * @param {*} [context=this]
\r
19020 * list.each('x', function (x, idx) {});
\r
19021 * list.each(['x', 'y'], function (x, y, idx) {});
\r
19022 * list.each(function (idx) {})
\r
19024 listProto.each = function (dimensions, cb, stack, context) {
\r
19025 if (typeof dimensions === 'function') {
\r
19032 dimensions = zrUtil.map(
\r
19033 normalizeDimensions(dimensions), this.getDimension, this
\r
19037 var dimSize = dimensions.length;
\r
19038 var indices = this.indices;
\r
19040 context = context || this;
\r
19042 for (var i = 0; i < indices.length; i++) {
\r
19043 if (dimSize === 0) {
\r
19044 cb.call(context, i);
\r
19046 // Simple optimization
\r
19047 else if (dimSize === 1) {
\r
19048 cb.call(context, this.get(dimensions[0], i, stack), i);
\r
19051 for (var k = 0; k < dimSize; k++) {
\r
19052 value[k] = this.get(dimensions[k], i, stack);
\r
19056 cb.apply(context, value);
\r
19063 * @param {string|Array.<string>}
\r
19064 * @param {Function} cb
\r
19065 * @param {boolean} [stack=false]
\r
19066 * @param {*} [context=this]
\r
19068 listProto.filterSelf = function (dimensions, cb, stack, context) {
\r
19069 if (typeof dimensions === 'function') {
\r
19076 dimensions = zrUtil.map(
\r
19077 normalizeDimensions(dimensions), this.getDimension, this
\r
19080 var newIndices = [];
\r
19082 var dimSize = dimensions.length;
\r
19083 var indices = this.indices;
\r
19085 context = context || this;
\r
19087 for (var i = 0; i < indices.length; i++) {
\r
19089 // Simple optimization
\r
19090 if (dimSize === 1) {
\r
19092 context, this.get(dimensions[0], i, stack), i
\r
19096 for (var k = 0; k < dimSize; k++) {
\r
19097 value[k] = this.get(dimensions[k], i, stack);
\r
19100 keep = cb.apply(context, value);
\r
19103 newIndices.push(indices[i]);
\r
19107 this.indices = newIndices;
\r
19109 // Reset data extent
\r
19110 this._extent = {};
\r
19116 * Data mapping to a plain array
\r
19117 * @param {string|Array.<string>} [dimensions]
\r
19118 * @param {Function} cb
\r
19119 * @param {boolean} [stack=false]
\r
19120 * @param {*} [context=this]
\r
19121 * @return {Array}
\r
19123 listProto.mapArray = function (dimensions, cb, stack, context) {
\r
19124 if (typeof dimensions === 'function') {
\r
19132 this.each(dimensions, function () {
\r
19133 result.push(cb && cb.apply(this, arguments));
\r
19134 }, stack, context);
\r
19138 function cloneListForMapAndSample(original, excludeDimensions) {
\r
19139 var allDimensions = original.dimensions;
\r
19140 var list = new List(
\r
19141 zrUtil.map(allDimensions, original.getDimensionInfo, original),
\r
19142 original.hostModel
\r
19144 // FIXME If needs stackedOn, value may already been stacked
\r
19145 transferImmuProperties(list, original, original._wrappedMethods);
\r
19147 var storage = list._storage = {};
\r
19148 var originalStorage = original._storage;
\r
19150 for (var i = 0; i < allDimensions.length; i++) {
\r
19151 var dim = allDimensions[i];
\r
19152 var dimStore = originalStorage[dim];
\r
19153 if (zrUtil.indexOf(excludeDimensions, dim) >= 0) {
\r
19154 storage[dim] = new dimStore.constructor(
\r
19155 originalStorage[dim].length
\r
19159 // Direct reference for other dimensions
\r
19160 storage[dim] = originalStorage[dim];
\r
19167 * Data mapping to a new List with given dimensions
\r
19168 * @param {string|Array.<string>} dimensions
\r
19169 * @param {Function} cb
\r
19170 * @param {boolean} [stack=false]
\r
19171 * @param {*} [context=this]
\r
19172 * @return {Array}
\r
19174 listProto.map = function (dimensions, cb, stack, context) {
\r
19175 dimensions = zrUtil.map(
\r
19176 normalizeDimensions(dimensions), this.getDimension, this
\r
19179 var list = cloneListForMapAndSample(this, dimensions);
\r
19180 // Following properties are all immutable.
\r
19181 // So we can reference to the same value
\r
19182 var indices = list.indices = this.indices;
\r
19184 var storage = list._storage;
\r
19186 var tmpRetValue = [];
\r
19187 this.each(dimensions, function () {
\r
19188 var idx = arguments[arguments.length - 1];
\r
19189 var retValue = cb && cb.apply(this, arguments);
\r
19190 if (retValue != null) {
\r
19192 if (typeof retValue === 'number') {
\r
19193 tmpRetValue[0] = retValue;
\r
19194 retValue = tmpRetValue;
\r
19196 for (var i = 0; i < retValue.length; i++) {
\r
19197 var dim = dimensions[i];
\r
19198 var dimStore = storage[dim];
\r
19199 var rawIdx = indices[idx];
\r
19201 dimStore[rawIdx] = retValue[i];
\r
19205 }, stack, context);
\r
19211 * Large data down sampling on given dimension
\r
19212 * @param {string} dimension
\r
19213 * @param {number} rate
\r
19214 * @param {Function} sampleValue
\r
19215 * @param {Function} sampleIndex Sample index for name and id
\r
19217 listProto.downSample = function (dimension, rate, sampleValue, sampleIndex) {
\r
19218 var list = cloneListForMapAndSample(this, [dimension]);
\r
19219 var storage = this._storage;
\r
19220 var targetStorage = list._storage;
\r
19222 var originalIndices = this.indices;
\r
19223 var indices = list.indices = [];
\r
19225 var frameValues = [];
\r
19226 var frameIndices = [];
\r
19227 var frameSize = Math.floor(1 / rate);
\r
19229 var dimStore = targetStorage[dimension];
\r
19230 var len = this.count();
\r
19231 // Copy data from original data
\r
19232 for (var i = 0; i < storage[dimension].length; i++) {
\r
19233 targetStorage[dimension][i] = storage[dimension][i];
\r
19235 for (var i = 0; i < len; i += frameSize) {
\r
19237 if (frameSize > len - i) {
\r
19238 frameSize = len - i;
\r
19239 frameValues.length = frameSize;
\r
19241 for (var k = 0; k < frameSize; k++) {
\r
19242 var idx = originalIndices[i + k];
\r
19243 frameValues[k] = dimStore[idx];
\r
19244 frameIndices[k] = idx;
\r
19246 var value = sampleValue(frameValues);
\r
19247 var idx = frameIndices[sampleIndex(frameValues, value) || 0];
\r
19248 // Only write value on the filtered data
\r
19249 dimStore[idx] = value;
\r
19250 indices.push(idx);
\r
19256 * Get model of one data item.
\r
19258 * @param {number} idx
\r
19260 // FIXME Model proxy ?
\r
19261 listProto.getItemModel = function (idx) {
\r
19262 var hostModel = this.hostModel;
\r
19263 idx = this.indices[idx];
\r
19264 return new Model(this._rawData[idx], hostModel, hostModel.ecModel);
\r
19268 * Create a data differ
\r
19269 * @param {module:echarts/data/List} otherList
\r
19270 * @return {module:echarts/data/DataDiffer}
\r
19272 listProto.diff = function (otherList) {
\r
19273 var idList = this._idList;
\r
19274 var otherIdList = otherList && otherList._idList;
\r
19275 return new DataDiffer(
\r
19276 otherList ? otherList.indices : [], this.indices, function (idx) {
\r
19277 return otherIdList[idx] || (idx + '');
\r
19278 }, function (idx) {
\r
19279 return idList[idx] || (idx + '');
\r
19284 * Get visual property.
\r
19285 * @param {string} key
\r
19287 listProto.getVisual = function (key) {
\r
19288 var visual = this._visual;
\r
19289 return visual && visual[key];
\r
19293 * Set visual property
\r
19294 * @param {string|Object} key
\r
19295 * @param {*} [value]
\r
19298 * setVisual('color', color);
\r
19303 listProto.setVisual = function (key, val) {
\r
19304 if (isObject(key)) {
\r
19305 for (var name in key) {
\r
19306 if (key.hasOwnProperty(name)) {
\r
19307 this.setVisual(name, key[name]);
\r
19312 this._visual = this._visual || {};
\r
19313 this._visual[key] = val;
\r
19317 * Set layout property.
\r
19318 * @param {string} key
\r
19319 * @param {*} [val]
\r
19321 listProto.setLayout = function (key, val) {
\r
19322 if (isObject(key)) {
\r
19323 for (var name in key) {
\r
19324 if (key.hasOwnProperty(name)) {
\r
19325 this.setLayout(name, key[name]);
\r
19330 this._layout[key] = val;
\r
19334 * Get layout property.
\r
19335 * @param {string} key.
\r
19338 listProto.getLayout = function (key) {
\r
19339 return this._layout[key];
\r
19343 * Get layout of single data item
\r
19344 * @param {number} idx
\r
19346 listProto.getItemLayout = function (idx) {
\r
19347 return this._itemLayouts[idx];
\r
19351 * Set layout of single data item
\r
19352 * @param {number} idx
\r
19353 * @param {Object} layout
\r
19354 * @param {boolean=} [merge=false]
\r
19356 listProto.setItemLayout = function (idx, layout, merge) {
\r
19357 this._itemLayouts[idx] = merge
\r
19358 ? zrUtil.extend(this._itemLayouts[idx] || {}, layout)
\r
19363 * Get visual property of single data item
\r
19364 * @param {number} idx
\r
19365 * @param {string} key
\r
19366 * @param {boolean} ignoreParent
\r
19368 listProto.getItemVisual = function (idx, key, ignoreParent) {
\r
19369 var itemVisual = this._itemVisuals[idx];
\r
19370 var val = itemVisual && itemVisual[key];
\r
19371 if (val == null && !ignoreParent) {
\r
19372 // Use global visual property
\r
19373 return this.getVisual(key);
\r
19379 * Set visual property of single data item
\r
19381 * @param {number} idx
\r
19382 * @param {string|Object} key
\r
19383 * @param {*} [value]
\r
19386 * setItemVisual(0, 'color', color);
\r
19387 * setItemVisual(0, {
\r
19391 listProto.setItemVisual = function (idx, key, value) {
\r
19392 var itemVisual = this._itemVisuals[idx] || {};
\r
19393 this._itemVisuals[idx] = itemVisual;
\r
19395 if (isObject(key)) {
\r
19396 for (var name in key) {
\r
19397 if (key.hasOwnProperty(name)) {
\r
19398 itemVisual[name] = key[name];
\r
19403 itemVisual[key] = value;
\r
19406 var setItemDataAndSeriesIndex = function (child) {
\r
19407 child.seriesIndex = this.seriesIndex;
\r
19408 child.dataIndex = this.dataIndex;
\r
19411 * Set graphic element relative to data. It can be set as null
\r
19412 * @param {number} idx
\r
19413 * @param {module:zrender/Element} [el]
\r
19415 listProto.setItemGraphicEl = function (idx, el) {
\r
19416 var hostModel = this.hostModel;
\r
19419 // Add data index and series index for indexing the data by element
\r
19420 // Useful in tooltip
\r
19421 el.dataIndex = idx;
\r
19422 el.seriesIndex = hostModel && hostModel.seriesIndex;
\r
19423 if (el.type === 'group') {
\r
19424 el.traverse(setItemDataAndSeriesIndex, el);
\r
19428 this._graphicEls[idx] = el;
\r
19432 * @param {number} idx
\r
19433 * @return {module:zrender/Element}
\r
19435 listProto.getItemGraphicEl = function (idx) {
\r
19436 return this._graphicEls[idx];
\r
19440 * @param {Function} cb
\r
19441 * @param {*} context
\r
19443 listProto.eachItemGraphicEl = function (cb, context) {
\r
19444 zrUtil.each(this._graphicEls, function (el, idx) {
\r
19446 cb && cb.call(context, el, idx);
\r
19452 * Shallow clone a new list except visual and layout properties, and graph elements.
\r
19453 * New list only change the indices.
\r
19455 listProto.cloneShallow = function () {
\r
19456 var dimensionInfoList = zrUtil.map(this.dimensions, this.getDimensionInfo, this);
\r
19457 var list = new List(dimensionInfoList, this.hostModel);
\r
19460 list._storage = this._storage;
\r
19462 transferImmuProperties(list, this, this._wrappedMethods);
\r
19464 list.indices = this.indices.slice();
\r
19470 * Wrap some method to add more feature
\r
19471 * @param {string} methodName
\r
19472 * @param {Function} injectFunction
\r
19474 listProto.wrapMethod = function (methodName, injectFunction) {
\r
19475 var originalMethod = this[methodName];
\r
19476 if (typeof originalMethod !== 'function') {
\r
19479 this._wrappedMethods = this._wrappedMethods || [];
\r
19480 this._wrappedMethods.push(methodName);
\r
19481 this[methodName] = function () {
\r
19482 var res = originalMethod.apply(this, arguments);
\r
19483 return injectFunction.call(this, res);
\r
19487 module.exports = List;
\r
19489 /* WEBPACK VAR INJECTION */}.call(exports, (function() { return this; }())))
\r
19493 /***/ function(module, exports) {
\r
19498 function defaultKeyGetter(item) {
\r
19502 function DataDiffer(oldArr, newArr, oldKeyGetter, newKeyGetter) {
\r
19503 this._old = oldArr;
\r
19504 this._new = newArr;
\r
19506 this._oldKeyGetter = oldKeyGetter || defaultKeyGetter;
\r
19507 this._newKeyGetter = newKeyGetter || defaultKeyGetter;
\r
19510 DataDiffer.prototype = {
\r
19512 constructor: DataDiffer,
\r
19515 * Callback function when add a data
\r
19517 add: function (func) {
\r
19518 this._add = func;
\r
19523 * Callback function when update a data
\r
19525 update: function (func) {
\r
19526 this._update = func;
\r
19531 * Callback function when remove a data
\r
19533 remove: function (func) {
\r
19534 this._remove = func;
\r
19538 execute: function () {
\r
19539 var oldArr = this._old;
\r
19540 var newArr = this._new;
\r
19541 var oldKeyGetter = this._oldKeyGetter;
\r
19542 var newKeyGetter = this._newKeyGetter;
\r
19544 var oldDataIndexMap = {};
\r
19545 var newDataIndexMap = {};
\r
19548 initIndexMap(oldArr, oldDataIndexMap, oldKeyGetter);
\r
19549 initIndexMap(newArr, newDataIndexMap, newKeyGetter);
\r
19551 // Travel by inverted order to make sure order consistency
\r
19552 // when duplicate keys exists (consider newDataIndex.pop() below).
\r
19553 // For performance consideration, these code below do not look neat.
\r
19554 for (i = 0; i < oldArr.length; i++) {
\r
19555 var key = oldKeyGetter(oldArr[i]);
\r
19556 var idx = newDataIndexMap[key];
\r
19558 // idx can never be empty array here. see 'set null' logic below.
\r
19559 if (idx != null) {
\r
19560 // Consider there is duplicate key (for example, use dataItem.name as key).
\r
19561 // We should make sure every item in newArr and oldArr can be visited.
\r
19562 var len = idx.length;
\r
19564 len === 1 && (newDataIndexMap[key] = null);
\r
19565 idx = idx.unshift();
\r
19568 newDataIndexMap[key] = null;
\r
19570 this._update && this._update(idx, i);
\r
19573 this._remove && this._remove(i);
\r
19577 for (var key in newDataIndexMap) {
\r
19578 if (newDataIndexMap.hasOwnProperty(key)) {
\r
19579 var idx = newDataIndexMap[key];
\r
19580 if (idx == null) {
\r
19583 // idx can never be empty array here. see 'set null' logic above.
\r
19584 if (!idx.length) {
\r
19585 this._add && this._add(idx);
\r
19588 for (var i = 0, len = idx.length; i < len; i++) {
\r
19589 this._add && this._add(idx[i]);
\r
19597 function initIndexMap(arr, map, keyGetter) {
\r
19598 for (var i = 0; i < arr.length; i++) {
\r
19599 var key = keyGetter(arr[i]);
\r
19600 var existence = map[key];
\r
19601 if (existence == null) {
\r
19605 if (!existence.length) {
\r
19606 map[key] = existence = [existence];
\r
19608 existence.push(i);
\r
19613 module.exports = DataDiffer;
\r
19618 /***/ function(module, exports, __webpack_require__) {
\r
19621 * Complete dimensions by data (guess dimension).
\r
19625 var zrUtil = __webpack_require__(3);
\r
19628 * Complete the dimensions array guessed from the data structure.
\r
19629 * @param {Array.<string>} dimensions Necessary dimensions, like ['x', 'y']
\r
19630 * @param {Array} data Data list. [[1, 2, 3], [2, 3, 4]]
\r
19631 * @param {Array.<string>} defaultNames Default names to fill not necessary dimensions, like ['value']
\r
19632 * @param {string} extraPrefix Prefix of name when filling the left dimensions.
\r
19633 * @return {Array.<string>}
\r
19635 function completeDimensions(dimensions, data, defaultNames, extraPrefix) {
\r
19637 return dimensions;
\r
19640 var value0 = retrieveValue(data[0]);
\r
19641 var dimSize = zrUtil.isArray(value0) && value0.length || 1;
\r
19643 defaultNames = defaultNames || [];
\r
19644 extraPrefix = extraPrefix || 'extra';
\r
19645 for (var i = 0; i < dimSize; i++) {
\r
19646 if (!dimensions[i]) {
\r
19647 var name = defaultNames[i] || (extraPrefix + (i - defaultNames.length));
\r
19648 dimensions[i] = guessOrdinal(data, i)
\r
19649 ? {type: 'ordinal', name: name}
\r
19654 return dimensions;
\r
19657 // The rule should not be complex, otherwise user might not
\r
19658 // be able to known where the data is wrong.
\r
19659 function guessOrdinal(data, dimIndex) {
\r
19660 for (var i = 0, len = data.length; i < len; i++) {
\r
19661 var value = retrieveValue(data[i]);
\r
19663 if (!zrUtil.isArray(value)) {
\r
19667 var value = value[dimIndex];
\r
19668 if (value != null && isFinite(value)) {
\r
19671 else if (zrUtil.isString(value) && value !== '-') {
\r
19678 function retrieveValue(o) {
\r
19679 return zrUtil.isArray(o) ? o : zrUtil.isObject(o) ? o.value: o;
\r
19682 module.exports = completeDimensions;
\r
19688 /***/ function(module, exports, __webpack_require__) {
\r
19693 var zrUtil = __webpack_require__(3);
\r
19694 var SymbolDraw = __webpack_require__(98);
\r
19695 var Symbol = __webpack_require__(99);
\r
19696 var lineAnimationDiff = __webpack_require__(101);
\r
19697 var graphic = __webpack_require__(42);
\r
19699 var polyHelper = __webpack_require__(102);
\r
19701 var ChartView = __webpack_require__(41);
\r
19703 function isPointsSame(points1, points2) {
\r
19704 if (points1.length !== points2.length) {
\r
19707 for (var i = 0; i < points1.length; i++) {
\r
19708 var p1 = points1[i];
\r
19709 var p2 = points2[i];
\r
19710 if (p1[0] !== p2[0] || p1[1] !== p2[1]) {
\r
19717 function getSmooth(smooth) {
\r
19718 return typeof (smooth) === 'number' ? smooth : (smooth ? 0.3 : 0);
\r
19721 function getAxisExtentWithGap(axis) {
\r
19722 var extent = axis.getGlobalExtent();
\r
19723 if (axis.onBand) {
\r
19724 // Remove extra 1px to avoid line miter in clipped edge
\r
19725 var halfBandWidth = axis.getBandWidth() / 2 - 1;
\r
19726 var dir = extent[1] > extent[0] ? 1 : -1;
\r
19727 extent[0] += dir * halfBandWidth;
\r
19728 extent[1] -= dir * halfBandWidth;
\r
19733 function sign(val) {
\r
19734 return val >= 0 ? 1 : -1;
\r
19737 * @param {module:echarts/coord/cartesian/Cartesian2D|module:echarts/coord/polar/Polar} coordSys
\r
19738 * @param {module:echarts/data/List} data
\r
19739 * @param {Array.<Array.<number>>} points
\r
19742 function getStackedOnPoints(coordSys, data) {
\r
19743 var baseAxis = coordSys.getBaseAxis();
\r
19744 var valueAxis = coordSys.getOtherAxis(baseAxis);
\r
19745 var valueStart = baseAxis.onZero
\r
19746 ? 0 : valueAxis.scale.getExtent()[0];
\r
19748 var valueDim = valueAxis.dim;
\r
19750 var baseDataOffset = valueDim === 'x' || valueDim === 'radius' ? 1 : 0;
\r
19752 return data.mapArray([valueDim], function (val, idx) {
\r
19753 var stackedOnSameSign;
\r
19754 var stackedOn = data.stackedOn;
\r
19755 // Find first stacked value with same sign
\r
19756 while (stackedOn &&
\r
19757 sign(stackedOn.get(valueDim, idx)) === sign(val)
\r
19759 stackedOnSameSign = stackedOn;
\r
19762 var stackedData = [];
\r
19763 stackedData[baseDataOffset] = data.get(baseAxis.dim, idx);
\r
19764 stackedData[1 - baseDataOffset] = stackedOnSameSign
\r
19765 ? stackedOnSameSign.get(valueDim, idx, true) : valueStart;
\r
19767 return coordSys.dataToPoint(stackedData);
\r
19771 function queryDataIndex(data, payload) {
\r
19772 if (payload.dataIndex != null) {
\r
19773 return payload.dataIndex;
\r
19775 else if (payload.name != null) {
\r
19776 return data.indexOfName(payload.name);
\r
19780 function createGridClipShape(cartesian, hasAnimation, seriesModel) {
\r
19781 var xExtent = getAxisExtentWithGap(cartesian.getAxis('x'));
\r
19782 var yExtent = getAxisExtentWithGap(cartesian.getAxis('y'));
\r
19783 var isHorizontal = cartesian.getBaseAxis().isHorizontal();
\r
19785 var x = xExtent[0];
\r
19786 var y = yExtent[0];
\r
19787 var width = xExtent[1] - x;
\r
19788 var height = yExtent[1] - y;
\r
19789 // Expand clip shape to avoid line value exceeds axis
\r
19790 if (!seriesModel.get('clipOverflow')) {
\r
19791 if (isHorizontal) {
\r
19800 var clipPath = new graphic.Rect({
\r
19809 if (hasAnimation) {
\r
19810 clipPath.shape[isHorizontal ? 'width' : 'height'] = 0;
\r
19811 graphic.initProps(clipPath, {
\r
19822 function createPolarClipShape(polar, hasAnimation, seriesModel) {
\r
19823 var angleAxis = polar.getAngleAxis();
\r
19824 var radiusAxis = polar.getRadiusAxis();
\r
19826 var radiusExtent = radiusAxis.getExtent();
\r
19827 var angleExtent = angleAxis.getExtent();
\r
19829 var RADIAN = Math.PI / 180;
\r
19831 var clipPath = new graphic.Sector({
\r
19835 r0: radiusExtent[0],
\r
19836 r: radiusExtent[1],
\r
19837 startAngle: -angleExtent[0] * RADIAN,
\r
19838 endAngle: -angleExtent[1] * RADIAN,
\r
19839 clockwise: angleAxis.inverse
\r
19843 if (hasAnimation) {
\r
19844 clipPath.shape.endAngle = -angleExtent[0] * RADIAN;
\r
19845 graphic.initProps(clipPath, {
\r
19847 endAngle: -angleExtent[1] * RADIAN
\r
19855 function createClipShape(coordSys, hasAnimation, seriesModel) {
\r
19856 return coordSys.type === 'polar'
\r
19857 ? createPolarClipShape(coordSys, hasAnimation, seriesModel)
\r
19858 : createGridClipShape(coordSys, hasAnimation, seriesModel);
\r
19861 module.exports = ChartView.extend({
\r
19865 init: function () {
\r
19866 var lineGroup = new graphic.Group();
\r
19868 var symbolDraw = new SymbolDraw();
\r
19869 this.group.add(symbolDraw.group);
\r
19871 this._symbolDraw = symbolDraw;
\r
19872 this._lineGroup = lineGroup;
\r
19875 render: function (seriesModel, ecModel, api) {
\r
19876 var coordSys = seriesModel.coordinateSystem;
\r
19877 var group = this.group;
\r
19878 var data = seriesModel.getData();
\r
19879 var lineStyleModel = seriesModel.getModel('lineStyle.normal');
\r
19880 var areaStyleModel = seriesModel.getModel('areaStyle.normal');
\r
19882 var points = data.mapArray(data.getItemLayout, true);
\r
19884 var isCoordSysPolar = coordSys.type === 'polar';
\r
19885 var prevCoordSys = this._coordSys;
\r
19887 var symbolDraw = this._symbolDraw;
\r
19888 var polyline = this._polyline;
\r
19889 var polygon = this._polygon;
\r
19891 var lineGroup = this._lineGroup;
\r
19893 var hasAnimation = seriesModel.get('animation');
\r
19895 var isAreaChart = !areaStyleModel.isEmpty();
\r
19896 var stackedOnPoints = getStackedOnPoints(coordSys, data);
\r
19898 var showSymbol = seriesModel.get('showSymbol');
\r
19900 var isSymbolIgnore = showSymbol && !isCoordSysPolar && !seriesModel.get('showAllSymbol')
\r
19901 && this._getSymbolIgnoreFunc(data, coordSys);
\r
19903 // Remove temporary symbols
\r
19904 var oldData = this._data;
\r
19905 oldData && oldData.eachItemGraphicEl(function (el, idx) {
\r
19907 group.remove(el);
\r
19908 oldData.setItemGraphicEl(idx, null);
\r
19912 // Remove previous created symbols if showSymbol changed to false
\r
19913 if (!showSymbol) {
\r
19914 symbolDraw.remove();
\r
19917 group.add(lineGroup);
\r
19919 // Initialization animation or coordinate system changed
\r
19921 !(polyline && prevCoordSys.type === coordSys.type)
\r
19923 showSymbol && symbolDraw.updateData(data, isSymbolIgnore);
\r
19925 polyline = this._newPolyline(points, coordSys, hasAnimation);
\r
19926 if (isAreaChart) {
\r
19927 polygon = this._newPolygon(
\r
19928 points, stackedOnPoints,
\r
19929 coordSys, hasAnimation
\r
19932 lineGroup.setClipPath(createClipShape(coordSys, true, seriesModel));
\r
19935 if (isAreaChart && !polygon) {
\r
19936 // If areaStyle is added
\r
19937 polygon = this._newPolygon(
\r
19938 points, stackedOnPoints,
\r
19939 coordSys, hasAnimation
\r
19942 else if (polygon && !isAreaChart) {
\r
19943 // If areaStyle is removed
\r
19944 lineGroup.remove(polygon);
\r
19945 polygon = this._polygon = null;
\r
19948 // Update clipPath
\r
19949 lineGroup.setClipPath(createClipShape(coordSys, false, seriesModel));
\r
19951 // Always update, or it is wrong in the case turning on legend
\r
19952 // because points are not changed
\r
19953 showSymbol && symbolDraw.updateData(data, isSymbolIgnore);
\r
19955 // Stop symbol animation and sync with line points
\r
19956 // FIXME performance?
\r
19957 data.eachItemGraphicEl(function (el) {
\r
19958 el.stopAnimation(true);
\r
19961 // In the case data zoom triggerred refreshing frequently
\r
19962 // Data may not change if line has a category axis. So it should animate nothing
\r
19963 if (!isPointsSame(this._stackedOnPoints, stackedOnPoints)
\r
19964 || !isPointsSame(this._points, points)
\r
19966 if (hasAnimation) {
\r
19967 this._updateAnimation(
\r
19968 data, stackedOnPoints, coordSys, api
\r
19972 polyline.setShape({
\r
19975 polygon && polygon.setShape({
\r
19977 stackedOnPoints: stackedOnPoints
\r
19983 polyline.setStyle(zrUtil.defaults(
\r
19984 // Use color in lineStyle first
\r
19985 lineStyleModel.getLineStyle(),
\r
19987 stroke: data.getVisual('color'),
\r
19988 lineJoin: 'bevel'
\r
19992 var smooth = seriesModel.get('smooth');
\r
19993 smooth = getSmooth(seriesModel.get('smooth'));
\r
19994 polyline.setShape({
\r
19996 smoothMonotone: seriesModel.get('smoothMonotone')
\r
20000 var stackedOn = data.stackedOn;
\r
20001 var stackedOnSmooth = 0;
\r
20003 polygon.style.opacity = 0.7;
\r
20004 polygon.setStyle(zrUtil.defaults(
\r
20005 areaStyleModel.getAreaStyle(),
\r
20007 fill: data.getVisual('color'),
\r
20008 lineJoin: 'bevel'
\r
20013 var stackedOnSeries = stackedOn.hostModel;
\r
20014 stackedOnSmooth = getSmooth(stackedOnSeries.get('smooth'));
\r
20017 polygon.setShape({
\r
20019 stackedOnSmooth: stackedOnSmooth,
\r
20020 smoothMonotone: seriesModel.get('smoothMonotone')
\r
20024 this._data = data;
\r
20025 // Save the coordinate system for transition animation when data changed
\r
20026 this._coordSys = coordSys;
\r
20027 this._stackedOnPoints = stackedOnPoints;
\r
20028 this._points = points;
\r
20031 highlight: function (seriesModel, ecModel, api, payload) {
\r
20032 var data = seriesModel.getData();
\r
20033 var dataIndex = queryDataIndex(data, payload);
\r
20035 if (dataIndex != null && dataIndex >= 0) {
\r
20036 var symbol = data.getItemGraphicEl(dataIndex);
\r
20038 // Create a temporary symbol if it is not exists
\r
20039 var pt = data.getItemLayout(dataIndex);
\r
20040 symbol = new Symbol(data, dataIndex, api);
\r
20041 symbol.position = pt;
\r
20043 seriesModel.get('zlevel'),
\r
20044 seriesModel.get('z')
\r
20046 symbol.ignore = isNaN(pt[0]) || isNaN(pt[1]);
\r
20047 symbol.__temp = true;
\r
20048 data.setItemGraphicEl(dataIndex, symbol);
\r
20050 // Stop scale animation
\r
20051 symbol.stopSymbolAnimation(true);
\r
20053 this.group.add(symbol);
\r
20055 symbol.highlight();
\r
20058 // Highlight whole series
\r
20059 ChartView.prototype.highlight.call(
\r
20060 this, seriesModel, ecModel, api, payload
\r
20065 downplay: function (seriesModel, ecModel, api, payload) {
\r
20066 var data = seriesModel.getData();
\r
20067 var dataIndex = queryDataIndex(data, payload);
\r
20068 if (dataIndex != null && dataIndex >= 0) {
\r
20069 var symbol = data.getItemGraphicEl(dataIndex);
\r
20071 if (symbol.__temp) {
\r
20072 data.setItemGraphicEl(dataIndex, null);
\r
20073 this.group.remove(symbol);
\r
20076 symbol.downplay();
\r
20081 // Downplay whole series
\r
20082 ChartView.prototype.downplay.call(
\r
20083 this, seriesModel, ecModel, api, payload
\r
20089 * @param {module:zrender/container/Group} group
\r
20090 * @param {Array.<Array.<number>>} points
\r
20093 _newPolyline: function (points) {
\r
20094 var polyline = this._polyline;
\r
20095 // Remove previous created polyline
\r
20097 this._lineGroup.remove(polyline);
\r
20100 polyline = new polyHelper.Polyline({
\r
20108 this._lineGroup.add(polyline);
\r
20110 this._polyline = polyline;
\r
20116 * @param {module:zrender/container/Group} group
\r
20117 * @param {Array.<Array.<number>>} stackedOnPoints
\r
20118 * @param {Array.<Array.<number>>} points
\r
20121 _newPolygon: function (points, stackedOnPoints) {
\r
20122 var polygon = this._polygon;
\r
20123 // Remove previous created polygon
\r
20125 this._lineGroup.remove(polygon);
\r
20128 polygon = new polyHelper.Polygon({
\r
20131 stackedOnPoints: stackedOnPoints
\r
20136 this._lineGroup.add(polygon);
\r
20138 this._polygon = polygon;
\r
20144 _getSymbolIgnoreFunc: function (data, coordSys) {
\r
20145 var categoryAxis = coordSys.getAxesByScale('ordinal')[0];
\r
20146 // `getLabelInterval` is provided by echarts/component/axis
\r
20147 if (categoryAxis && categoryAxis.isLabelIgnored) {
\r
20148 return zrUtil.bind(categoryAxis.isLabelIgnored, categoryAxis);
\r
20155 // FIXME Two value axis
\r
20156 _updateAnimation: function (data, stackedOnPoints, coordSys, api) {
\r
20157 var polyline = this._polyline;
\r
20158 var polygon = this._polygon;
\r
20159 var seriesModel = data.hostModel;
\r
20161 var diff = lineAnimationDiff(
\r
20162 this._data, data,
\r
20163 this._stackedOnPoints, stackedOnPoints,
\r
20164 this._coordSys, coordSys
\r
20166 polyline.shape.points = diff.current;
\r
20168 graphic.updateProps(polyline, {
\r
20170 points: diff.next
\r
20175 polygon.setShape({
\r
20176 points: diff.current,
\r
20177 stackedOnPoints: diff.stackedOnCurrent
\r
20179 graphic.updateProps(polygon, {
\r
20181 points: diff.next,
\r
20182 stackedOnPoints: diff.stackedOnNext
\r
20187 var updatedDataInfo = [];
\r
20188 var diffStatus = diff.status;
\r
20190 for (var i = 0; i < diffStatus.length; i++) {
\r
20191 var cmd = diffStatus[i].cmd;
\r
20192 if (cmd === '=') {
\r
20193 var el = data.getItemGraphicEl(diffStatus[i].idx1);
\r
20195 updatedDataInfo.push({
\r
20197 ptIdx: i // Index of points
\r
20203 if (polyline.animators && polyline.animators.length) {
\r
20204 polyline.animators[0].during(function () {
\r
20205 for (var i = 0; i < updatedDataInfo.length; i++) {
\r
20206 var el = updatedDataInfo[i].el;
\r
20207 el.attr('position', polyline.shape.points[updatedDataInfo[i].ptIdx]);
\r
20213 remove: function (ecModel) {
\r
20214 var group = this.group;
\r
20215 var oldData = this._data;
\r
20216 this._lineGroup.removeAll();
\r
20217 this._symbolDraw.remove(true);
\r
20218 // Remove temporary created elements when highlighting
\r
20219 oldData && oldData.eachItemGraphicEl(function (el, idx) {
\r
20221 group.remove(el);
\r
20222 oldData.setItemGraphicEl(idx, null);
\r
20230 this._stackedOnPoints =
\r
20231 this._data = null;
\r
20238 /***/ function(module, exports, __webpack_require__) {
\r
20241 * @module echarts/chart/helper/SymbolDraw
\r
20245 var graphic = __webpack_require__(42);
\r
20246 var Symbol = __webpack_require__(99);
\r
20250 * @alias module:echarts/chart/helper/SymbolDraw
\r
20251 * @param {module:zrender/graphic/Group} [symbolCtor]
\r
20253 function SymbolDraw(symbolCtor) {
\r
20254 this.group = new graphic.Group();
\r
20256 this._symbolCtor = symbolCtor || Symbol;
\r
20259 var symbolDrawProto = SymbolDraw.prototype;
\r
20261 function symbolNeedsDraw(data, idx, isIgnore) {
\r
20262 var point = data.getItemLayout(idx);
\r
20263 return point && !isNaN(point[0]) && !isNaN(point[1]) && !(isIgnore && isIgnore(idx))
\r
20264 && data.getItemVisual(idx, 'symbol') !== 'none';
\r
20267 * Update symbols draw by new data
\r
20268 * @param {module:echarts/data/List} data
\r
20269 * @param {Array.<boolean>} [isIgnore]
\r
20271 symbolDrawProto.updateData = function (data, isIgnore) {
\r
20272 var group = this.group;
\r
20273 var seriesModel = data.hostModel;
\r
20274 var oldData = this._data;
\r
20276 var SymbolCtor = this._symbolCtor;
\r
20278 data.diff(oldData)
\r
20279 .add(function (newIdx) {
\r
20280 var point = data.getItemLayout(newIdx);
\r
20281 if (symbolNeedsDraw(data, newIdx, isIgnore)) {
\r
20282 var symbolEl = new SymbolCtor(data, newIdx);
\r
20283 symbolEl.attr('position', point);
\r
20284 data.setItemGraphicEl(newIdx, symbolEl);
\r
20285 group.add(symbolEl);
\r
20288 .update(function (newIdx, oldIdx) {
\r
20289 var symbolEl = oldData.getItemGraphicEl(oldIdx);
\r
20290 var point = data.getItemLayout(newIdx);
\r
20291 if (!symbolNeedsDraw(data, newIdx, isIgnore)) {
\r
20292 group.remove(symbolEl);
\r
20296 symbolEl = new SymbolCtor(data, newIdx);
\r
20297 symbolEl.attr('position', point);
\r
20300 symbolEl.updateData(data, newIdx);
\r
20301 graphic.updateProps(symbolEl, {
\r
20307 group.add(symbolEl);
\r
20309 data.setItemGraphicEl(newIdx, symbolEl);
\r
20311 .remove(function (oldIdx) {
\r
20312 var el = oldData.getItemGraphicEl(oldIdx);
\r
20313 el && el.fadeOut(function () {
\r
20314 group.remove(el);
\r
20319 this._data = data;
\r
20322 symbolDrawProto.updateLayout = function () {
\r
20323 var data = this._data;
\r
20325 // Not use animation
\r
20326 data.eachItemGraphicEl(function (el, idx) {
\r
20327 el.attr('position', data.getItemLayout(idx));
\r
20332 symbolDrawProto.remove = function (enableAnimation) {
\r
20333 var group = this.group;
\r
20334 var data = this._data;
\r
20336 if (enableAnimation) {
\r
20337 data.eachItemGraphicEl(function (el) {
\r
20338 el.fadeOut(function () {
\r
20339 group.remove(el);
\r
20344 group.removeAll();
\r
20349 module.exports = SymbolDraw;
\r
20354 /***/ function(module, exports, __webpack_require__) {
\r
20357 * @module echarts/chart/helper/Symbol
\r
20361 var zrUtil = __webpack_require__(3);
\r
20362 var symbolUtil = __webpack_require__(100);
\r
20363 var graphic = __webpack_require__(42);
\r
20364 var numberUtil = __webpack_require__(7);
\r
20366 function normalizeSymbolSize(symbolSize) {
\r
20367 if (!zrUtil.isArray(symbolSize)) {
\r
20368 symbolSize = [+symbolSize, +symbolSize];
\r
20370 return symbolSize;
\r
20375 * @alias {module:echarts/chart/helper/Symbol}
\r
20376 * @param {module:echarts/data/List} data
\r
20377 * @param {number} idx
\r
20378 * @extends {module:zrender/graphic/Group}
\r
20380 function Symbol(data, idx) {
\r
20381 graphic.Group.call(this);
\r
20383 this.updateData(data, idx);
\r
20386 var symbolProto = Symbol.prototype;
\r
20388 function driftSymbol(dx, dy) {
\r
20389 this.parent.drift(dx, dy);
\r
20392 symbolProto._createSymbol = function (symbolType, data, idx) {
\r
20393 // Remove paths created before
\r
20394 this.removeAll();
\r
20396 var seriesModel = data.hostModel;
\r
20397 var color = data.getItemVisual(idx, 'color');
\r
20399 var symbolPath = symbolUtil.createSymbol(
\r
20400 symbolType, -0.5, -0.5, 1, 1, color
\r
20403 symbolPath.attr({
\r
20405 strokeNoScale: true
\r
20411 // Rewrite drift method
\r
20412 symbolPath.drift = driftSymbol;
\r
20414 var size = normalizeSymbolSize(data.getItemVisual(idx, 'symbolSize'));
\r
20416 graphic.initProps(symbolPath, {
\r
20420 this._symbolType = symbolType;
\r
20422 this.add(symbolPath);
\r
20427 * @param {boolean} toLastFrame
\r
20429 symbolProto.stopSymbolAnimation = function (toLastFrame) {
\r
20430 this.childAt(0).stopAnimation(toLastFrame);
\r
20434 * Get scale(aka, current symbol size).
\r
20435 * Including the change caused by animation
\r
20436 * @param {Array.<number>} toLastFrame
\r
20438 symbolProto.getScale = function () {
\r
20439 return this.childAt(0).scale;
\r
20443 * Highlight symbol
\r
20445 symbolProto.highlight = function () {
\r
20446 this.childAt(0).trigger('emphasis');
\r
20450 * Downplay symbol
\r
20452 symbolProto.downplay = function () {
\r
20453 this.childAt(0).trigger('normal');
\r
20457 * @param {number} zlevel
\r
20458 * @param {number} z
\r
20460 symbolProto.setZ = function (zlevel, z) {
\r
20461 var symbolPath = this.childAt(0);
\r
20462 symbolPath.zlevel = zlevel;
\r
20463 symbolPath.z = z;
\r
20466 symbolProto.setDraggable = function (draggable) {
\r
20467 var symbolPath = this.childAt(0);
\r
20468 symbolPath.draggable = draggable;
\r
20469 symbolPath.cursor = draggable ? 'move' : 'pointer';
\r
20472 * Update symbol properties
\r
20473 * @param {module:echarts/data/List} data
\r
20474 * @param {number} idx
\r
20476 symbolProto.updateData = function (data, idx) {
\r
20477 var symbolType = data.getItemVisual(idx, 'symbol') || 'circle';
\r
20478 var seriesModel = data.hostModel;
\r
20479 var symbolSize = normalizeSymbolSize(data.getItemVisual(idx, 'symbolSize'));
\r
20480 if (symbolType !== this._symbolType) {
\r
20481 this._createSymbol(symbolType, data, idx);
\r
20484 var symbolPath = this.childAt(0);
\r
20485 graphic.updateProps(symbolPath, {
\r
20486 scale: symbolSize
\r
20489 this._updateCommon(data, idx, symbolSize);
\r
20491 this._seriesModel = seriesModel;
\r
20494 // Update common properties
\r
20495 var normalStyleAccessPath = ['itemStyle', 'normal'];
\r
20496 var emphasisStyleAccessPath = ['itemStyle', 'emphasis'];
\r
20497 var normalLabelAccessPath = ['label', 'normal'];
\r
20498 var emphasisLabelAccessPath = ['label', 'emphasis'];
\r
20500 symbolProto._updateCommon = function (data, idx, symbolSize) {
\r
20501 var symbolPath = this.childAt(0);
\r
20502 var seriesModel = data.hostModel;
\r
20503 var itemModel = data.getItemModel(idx);
\r
20504 var normalItemStyleModel = itemModel.getModel(normalStyleAccessPath);
\r
20505 var color = data.getItemVisual(idx, 'color');
\r
20507 var hoverStyle = itemModel.getModel(emphasisStyleAccessPath).getItemStyle();
\r
20509 symbolPath.rotation = itemModel.getShallow('symbolRotate') * Math.PI / 180 || 0;
\r
20511 var symbolOffset = itemModel.getShallow('symbolOffset');
\r
20512 if (symbolOffset) {
\r
20513 var pos = symbolPath.position;
\r
20514 pos[0] = numberUtil.parsePercent(symbolOffset[0], symbolSize[0]);
\r
20515 pos[1] = numberUtil.parsePercent(symbolOffset[1], symbolSize[1]);
\r
20518 symbolPath.setColor(color);
\r
20521 symbolPath.style,
\r
20522 // Color must be excluded.
\r
20523 // Because symbol provide setColor individually to set fill and stroke
\r
20524 normalItemStyleModel.getItemStyle(['color'])
\r
20527 var labelModel = itemModel.getModel(normalLabelAccessPath);
\r
20528 var hoverLabelModel = itemModel.getModel(emphasisLabelAccessPath);
\r
20530 var elStyle = symbolPath.style;
\r
20532 // Get last value dim
\r
20533 var dimensions = data.dimensions.slice();
\r
20534 var valueDim = dimensions.pop();
\r
20537 ((dataType = data.getDimensionInfo(valueDim).type) === 'ordinal')
\r
20538 || (dataType === 'time')
\r
20540 valueDim = dimensions.pop();
\r
20543 if (labelModel.get('show')) {
\r
20544 graphic.setText(elStyle, labelModel, color);
\r
20545 elStyle.text = zrUtil.retrieve(
\r
20546 seriesModel.getFormattedLabel(idx, 'normal'),
\r
20547 data.get(valueDim, idx)
\r
20551 elStyle.text = '';
\r
20554 if (hoverLabelModel.getShallow('show')) {
\r
20555 graphic.setText(hoverStyle, hoverLabelModel, color);
\r
20556 hoverStyle.text = zrUtil.retrieve(
\r
20557 seriesModel.getFormattedLabel(idx, 'emphasis'),
\r
20558 data.get(valueDim, idx)
\r
20562 hoverStyle.text = '';
\r
20565 var size = normalizeSymbolSize(data.getItemVisual(idx, 'symbolSize'));
\r
20567 symbolPath.off('mouseover')
\r
20572 graphic.setHoverStyle(symbolPath, hoverStyle);
\r
20574 if (itemModel.getShallow('hoverAnimation')) {
\r
20575 var onEmphasis = function() {
\r
20576 var ratio = size[1] / size[0];
\r
20579 Math.max(size[0] * 1.1, size[0] + 3),
\r
20580 Math.max(size[1] * 1.1, size[1] + 3 * ratio)
\r
20582 }, 400, 'elasticOut');
\r
20584 var onNormal = function() {
\r
20587 }, 400, 'elasticOut');
\r
20589 symbolPath.on('mouseover', onEmphasis)
\r
20590 .on('mouseout', onNormal)
\r
20591 .on('emphasis', onEmphasis)
\r
20592 .on('normal', onNormal);
\r
20596 symbolProto.fadeOut = function (cb) {
\r
20597 var symbolPath = this.childAt(0);
\r
20598 // Not show text when animating
\r
20599 symbolPath.style.text = '';
\r
20600 graphic.updateProps(symbolPath, {
\r
20602 }, this._seriesModel, cb);
\r
20605 zrUtil.inherits(Symbol, graphic.Group);
\r
20607 module.exports = Symbol;
\r
20612 /***/ function(module, exports, __webpack_require__) {
\r
20615 // Symbol factory
\r
20618 var graphic = __webpack_require__(42);
\r
20619 var BoundingRect = __webpack_require__(15);
\r
20625 var Triangle = graphic.extendShape({
\r
20626 type: 'triangle',
\r
20633 buildPath: function (path, shape) {
\r
20634 var cx = shape.cx;
\r
20635 var cy = shape.cy;
\r
20636 var width = shape.width / 2;
\r
20637 var height = shape.height / 2;
\r
20638 path.moveTo(cx, cy - height);
\r
20639 path.lineTo(cx + width, cy + height);
\r
20640 path.lineTo(cx - width, cy + height);
\r
20641 path.closePath();
\r
20648 var Diamond = graphic.extendShape({
\r
20656 buildPath: function (path, shape) {
\r
20657 var cx = shape.cx;
\r
20658 var cy = shape.cy;
\r
20659 var width = shape.width / 2;
\r
20660 var height = shape.height / 2;
\r
20661 path.moveTo(cx, cy - height);
\r
20662 path.lineTo(cx + width, cy);
\r
20663 path.lineTo(cx, cy + height);
\r
20664 path.lineTo(cx - width, cy);
\r
20665 path.closePath();
\r
20673 var Pin = graphic.extendShape({
\r
20676 // x, y on the cusp
\r
20683 buildPath: function (path, shape) {
\r
20686 var w = shape.width / 5 * 3;
\r
20687 // Height must be larger than width
\r
20688 var h = Math.max(w, shape.height);
\r
20691 // Dist on y with tangent point and circle center
\r
20692 var dy = r * r / (h - r);
\r
20693 var cy = y - h + r + dy;
\r
20694 var angle = Math.asin(dy / r);
\r
20695 // Dist on x with tangent point and circle center
\r
20696 var dx = Math.cos(angle) * r;
\r
20698 var tanX = Math.sin(angle);
\r
20699 var tanY = Math.cos(angle);
\r
20704 Math.PI * 2 + angle
\r
20707 var cpLen = r * 0.6;
\r
20708 var cpLen2 = r * 0.7;
\r
20709 path.bezierCurveTo(
\r
20710 x + dx - tanX * cpLen, cy + dy + tanY * cpLen,
\r
20714 path.bezierCurveTo(
\r
20716 x - dx + tanX * cpLen, cy + dy + tanY * cpLen,
\r
20719 path.closePath();
\r
20727 var Arrow = graphic.extendShape({
\r
20738 buildPath: function (ctx, shape) {
\r
20739 var height = shape.height;
\r
20740 var width = shape.width;
\r
20743 var dx = width / 3 * 2;
\r
20744 ctx.moveTo(x, y);
\r
20745 ctx.lineTo(x + dx, y + height);
\r
20746 ctx.lineTo(x, y + height / 4 * 3);
\r
20747 ctx.lineTo(x - dx, y + height);
\r
20748 ctx.lineTo(x, y);
\r
20754 * Map of path contructors
\r
20755 * @type {Object.<string, module:zrender/graphic/Path>}
\r
20757 var symbolCtors = {
\r
20758 line: graphic.Line,
\r
20760 rect: graphic.Rect,
\r
20762 roundRect: graphic.Rect,
\r
20764 square: graphic.Rect,
\r
20766 circle: graphic.Circle,
\r
20768 diamond: Diamond,
\r
20774 triangle: Triangle
\r
20777 var symbolShapeMakers = {
\r
20779 line: function (x, y, w, h, shape) {
\r
20782 shape.y1 = y + h / 2;
\r
20783 shape.x2 = x + w;
\r
20784 shape.y2 = y + h / 2;
\r
20787 rect: function (x, y, w, h, shape) {
\r
20791 shape.height = h;
\r
20794 roundRect: function (x, y, w, h, shape) {
\r
20798 shape.height = h;
\r
20799 shape.r = Math.min(w, h) / 4;
\r
20802 square: function (x, y, w, h, shape) {
\r
20803 var size = Math.min(w, h);
\r
20806 shape.width = size;
\r
20807 shape.height = size;
\r
20810 circle: function (x, y, w, h, shape) {
\r
20811 // Put circle in the center of square
\r
20812 shape.cx = x + w / 2;
\r
20813 shape.cy = y + h / 2;
\r
20814 shape.r = Math.min(w, h) / 2;
\r
20817 diamond: function (x, y, w, h, shape) {
\r
20818 shape.cx = x + w / 2;
\r
20819 shape.cy = y + h / 2;
\r
20821 shape.height = h;
\r
20824 pin: function (x, y, w, h, shape) {
\r
20825 shape.x = x + w / 2;
\r
20826 shape.y = y + h / 2;
\r
20828 shape.height = h;
\r
20831 arrow: function (x, y, w, h, shape) {
\r
20832 shape.x = x + w / 2;
\r
20833 shape.y = y + h / 2;
\r
20835 shape.height = h;
\r
20838 triangle: function (x, y, w, h, shape) {
\r
20839 shape.cx = x + w / 2;
\r
20840 shape.cy = y + h / 2;
\r
20842 shape.height = h;
\r
20846 var symbolBuildProxies = {};
\r
20847 for (var name in symbolCtors) {
\r
20848 symbolBuildProxies[name] = new symbolCtors[name]();
\r
20851 var Symbol = graphic.extendShape({
\r
20863 beforeBrush: function () {
\r
20864 var style = this.style;
\r
20865 var shape = this.shape;
\r
20867 if (shape.symbolType === 'pin' && style.textPosition === 'inside') {
\r
20868 style.textPosition = ['50%', '40%'];
\r
20869 style.textAlign = 'center';
\r
20870 style.textVerticalAlign = 'middle';
\r
20874 buildPath: function (ctx, shape) {
\r
20875 var symbolType = shape.symbolType;
\r
20876 var proxySymbol = symbolBuildProxies[symbolType];
\r
20877 if (shape.symbolType !== 'none') {
\r
20878 if (!proxySymbol) {
\r
20880 symbolType = 'rect';
\r
20881 proxySymbol = symbolBuildProxies[symbolType];
\r
20883 symbolShapeMakers[symbolType](
\r
20884 shape.x, shape.y, shape.width, shape.height, proxySymbol.shape
\r
20886 proxySymbol.buildPath(ctx, proxySymbol.shape);
\r
20891 // Provide setColor helper method to avoid determine if set the fill or stroke outside
\r
20892 var symbolPathSetColor = function (color) {
\r
20893 if (this.type !== 'image') {
\r
20894 var symbolStyle = this.style;
\r
20895 var symbolShape = this.shape;
\r
20896 if (symbolShape && symbolShape.symbolType === 'line') {
\r
20897 symbolStyle.stroke = color;
\r
20899 else if (this.__isEmptyBrush) {
\r
20900 symbolStyle.stroke = color;
\r
20901 symbolStyle.fill = '#fff';
\r
20904 // FIXME 判断图形默认是填充还是描边,使用 onlyStroke ?
\r
20905 symbolStyle.fill && (symbolStyle.fill = color);
\r
20906 symbolStyle.stroke && (symbolStyle.stroke = color);
\r
20912 var symbolUtil = {
\r
20914 * Create a symbol element with given symbol configuration: shape, x, y, width, height, color
\r
20915 * @param {string} symbolType
\r
20916 * @param {number} x
\r
20917 * @param {number} y
\r
20918 * @param {number} w
\r
20919 * @param {number} h
\r
20920 * @param {string} color
\r
20922 createSymbol: function (symbolType, x, y, w, h, color) {
\r
20923 var isEmpty = symbolType.indexOf('empty') === 0;
\r
20925 symbolType = symbolType.substr(5, 1).toLowerCase() + symbolType.substr(6);
\r
20929 if (symbolType.indexOf('image://') === 0) {
\r
20930 symbolPath = new graphic.Image({
\r
20932 image: symbolType.slice(8),
\r
20940 else if (symbolType.indexOf('path://') === 0) {
\r
20941 symbolPath = graphic.makePath(symbolType.slice(7), {}, new BoundingRect(x, y, w, h));
\r
20944 symbolPath = new Symbol({
\r
20946 symbolType: symbolType,
\r
20955 symbolPath.__isEmptyBrush = isEmpty;
\r
20957 symbolPath.setColor = symbolPathSetColor;
\r
20959 symbolPath.setColor(color);
\r
20961 return symbolPath;
\r
20965 module.exports = symbolUtil;
\r
20970 /***/ function(module, exports) {
\r
20974 // var arrayDiff = require('zrender/lib/core/arrayDiff');
\r
20975 // 'zrender/core/arrayDiff' has been used before, but it did
\r
20976 // not do well in performance when roam with fixed dataZoom window.
\r
20978 function sign(val) {
\r
20979 return val >= 0 ? 1 : -1;
\r
20982 function getStackedOnPoint(coordSys, data, idx) {
\r
20983 var baseAxis = coordSys.getBaseAxis();
\r
20984 var valueAxis = coordSys.getOtherAxis(baseAxis);
\r
20985 var valueStart = baseAxis.onZero
\r
20986 ? 0 : valueAxis.scale.getExtent()[0];
\r
20988 var valueDim = valueAxis.dim;
\r
20989 var baseDataOffset = valueDim === 'x' || valueDim === 'radius' ? 1 : 0;
\r
20991 var stackedOnSameSign;
\r
20992 var stackedOn = data.stackedOn;
\r
20993 var val = data.get(valueDim, idx);
\r
20994 // Find first stacked value with same sign
\r
20995 while (stackedOn &&
\r
20996 sign(stackedOn.get(valueDim, idx)) === sign(val)
\r
20998 stackedOnSameSign = stackedOn;
\r
21001 var stackedData = [];
\r
21002 stackedData[baseDataOffset] = data.get(baseAxis.dim, idx);
\r
21003 stackedData[1 - baseDataOffset] = stackedOnSameSign
\r
21004 ? stackedOnSameSign.get(valueDim, idx, true) : valueStart;
\r
21006 return coordSys.dataToPoint(stackedData);
\r
21009 // function convertToIntId(newIdList, oldIdList) {
\r
21010 // // Generate int id instead of string id.
\r
21011 // // Compare string maybe slow in score function of arrDiff
\r
21013 // // Assume id in idList are all unique
\r
21014 // var idIndicesMap = {};
\r
21016 // for (var i = 0; i < newIdList.length; i++) {
\r
21017 // idIndicesMap[newIdList[i]] = idx;
\r
21018 // newIdList[i] = idx++;
\r
21020 // for (var i = 0; i < oldIdList.length; i++) {
\r
21021 // var oldId = oldIdList[i];
\r
21022 // // Same with newIdList
\r
21023 // if (idIndicesMap[oldId]) {
\r
21024 // oldIdList[i] = idIndicesMap[oldId];
\r
21027 // oldIdList[i] = idx++;
\r
21032 function diffData(oldData, newData) {
\r
21033 var diffResult = [];
\r
21035 newData.diff(oldData)
\r
21036 .add(function (idx) {
\r
21037 diffResult.push({cmd: '+', idx: idx});
\r
21039 .update(function (newIdx, oldIdx) {
\r
21040 diffResult.push({cmd: '=', idx: oldIdx, idx1: newIdx});
\r
21042 .remove(function (idx) {
\r
21043 diffResult.push({cmd: '-', idx: idx});
\r
21047 return diffResult;
\r
21050 module.exports = function (
\r
21051 oldData, newData,
\r
21052 oldStackedOnPoints, newStackedOnPoints,
\r
21053 oldCoordSys, newCoordSys
\r
21055 var diff = diffData(oldData, newData);
\r
21057 // var newIdList = newData.mapArray(newData.getId);
\r
21058 // var oldIdList = oldData.mapArray(oldData.getId);
\r
21060 // convertToIntId(newIdList, oldIdList);
\r
21062 // // FIXME One data ?
\r
21063 // diff = arrayDiff(oldIdList, newIdList);
\r
21065 var currPoints = [];
\r
21066 var nextPoints = [];
\r
21067 // Points for stacking base line
\r
21068 var currStackedPoints = [];
\r
21069 var nextStackedPoints = [];
\r
21072 var sortedIndices = [];
\r
21073 var rawIndices = [];
\r
21074 var dims = newCoordSys.dimensions;
\r
21075 for (var i = 0; i < diff.length; i++) {
\r
21076 var diffItem = diff[i];
\r
21077 var pointAdded = true;
\r
21079 // FIXME, animation is not so perfect when dataZoom window moves fast
\r
21080 // Which is in case remvoing or add more than one data in the tail or head
\r
21081 switch (diffItem.cmd) {
\r
21083 var currentPt = oldData.getItemLayout(diffItem.idx);
\r
21084 var nextPt = newData.getItemLayout(diffItem.idx1);
\r
21085 // If previous data is NaN, use next point directly
\r
21086 if (isNaN(currentPt[0]) || isNaN(currentPt[1])) {
\r
21087 currentPt = nextPt.slice();
\r
21089 currPoints.push(currentPt);
\r
21090 nextPoints.push(nextPt);
\r
21092 currStackedPoints.push(oldStackedOnPoints[diffItem.idx]);
\r
21093 nextStackedPoints.push(newStackedOnPoints[diffItem.idx1]);
\r
21095 rawIndices.push(newData.getRawIndex(diffItem.idx1));
\r
21098 var idx = diffItem.idx;
\r
21100 oldCoordSys.dataToPoint([
\r
21101 newData.get(dims[0], idx, true), newData.get(dims[1], idx, true)
\r
21105 nextPoints.push(newData.getItemLayout(idx).slice());
\r
21107 currStackedPoints.push(
\r
21108 getStackedOnPoint(oldCoordSys, newData, idx)
\r
21110 nextStackedPoints.push(newStackedOnPoints[idx]);
\r
21112 rawIndices.push(newData.getRawIndex(idx));
\r
21115 var idx = diffItem.idx;
\r
21116 var rawIndex = oldData.getRawIndex(idx);
\r
21117 // Data is replaced. In the case of dynamic data queue
\r
21118 // FIXME FIXME FIXME
\r
21119 if (rawIndex !== idx) {
\r
21120 currPoints.push(oldData.getItemLayout(idx));
\r
21121 nextPoints.push(newCoordSys.dataToPoint([
\r
21122 oldData.get(dims[0], idx, true), oldData.get(dims[1], idx, true)
\r
21125 currStackedPoints.push(oldStackedOnPoints[idx]);
\r
21126 nextStackedPoints.push(
\r
21127 getStackedOnPoint(
\r
21128 newCoordSys, oldData, idx
\r
21132 rawIndices.push(rawIndex);
\r
21135 pointAdded = false;
\r
21139 // Original indices
\r
21140 if (pointAdded) {
\r
21141 status.push(diffItem);
\r
21142 sortedIndices.push(sortedIndices.length);
\r
21146 // Diff result may be crossed if all items are changed
\r
21147 // Sort by data index
\r
21148 sortedIndices.sort(function (a, b) {
\r
21149 return rawIndices[a] - rawIndices[b];
\r
21152 var sortedCurrPoints = [];
\r
21153 var sortedNextPoints = [];
\r
21155 var sortedCurrStackedPoints = [];
\r
21156 var sortedNextStackedPoints = [];
\r
21158 var sortedStatus = [];
\r
21159 for (var i = 0; i < sortedIndices.length; i++) {
\r
21160 var idx = sortedIndices[i];
\r
21161 sortedCurrPoints[i] = currPoints[idx];
\r
21162 sortedNextPoints[i] = nextPoints[idx];
\r
21164 sortedCurrStackedPoints[i] = currStackedPoints[idx];
\r
21165 sortedNextStackedPoints[i] = nextStackedPoints[idx];
\r
21167 sortedStatus[i] = status[idx];
\r
21171 current: sortedCurrPoints,
\r
21172 next: sortedNextPoints,
\r
21174 stackedOnCurrent: sortedCurrStackedPoints,
\r
21175 stackedOnNext: sortedNextStackedPoints,
\r
21177 status: sortedStatus
\r
21184 /***/ function(module, exports, __webpack_require__) {
\r
21186 // Poly path support NaN point
\r
21189 var Path = __webpack_require__(44);
\r
21190 var vec2 = __webpack_require__(16);
\r
21192 var vec2Min = vec2.min;
\r
21193 var vec2Max = vec2.max;
\r
21195 var scaleAndAdd = vec2.scaleAndAdd;
\r
21196 var v2Copy = vec2.copy;
\r
21198 // Temporary variable
\r
21203 function drawSegment(
\r
21204 ctx, points, start, stop, len,
\r
21205 dir, smoothMin, smoothMax, smooth, smoothMonotone
\r
21208 for (var k = 0; k < len; k++) {
\r
21209 var p = points[idx];
\r
21210 if (idx >= stop || idx < 0 || isNaN(p[0]) || isNaN(p[1])) {
\r
21214 if (idx === start) {
\r
21215 ctx[dir > 0 ? 'moveTo' : 'lineTo'](p[0], p[1]);
\r
21219 if (smooth > 0) {
\r
21220 var prevIdx = idx - dir;
\r
21221 var nextIdx = idx + dir;
\r
21223 var ratioNextSeg = 0.5;
\r
21224 var prevP = points[prevIdx];
\r
21225 var nextP = points[nextIdx];
\r
21227 if ((dir > 0 && (idx === len - 1 || isNaN(nextP[0]) || isNaN(nextP[1])))
\r
21228 || (dir <= 0 && (idx === 0 || isNaN(nextP[0]) || isNaN(nextP[1])))
\r
21233 // If next data is null
\r
21234 if (isNaN(nextP[0]) || isNaN(nextP[1])) {
\r
21238 vec2.sub(v, nextP, prevP);
\r
21242 if (smoothMonotone === 'x' || smoothMonotone === 'y') {
\r
21243 var dim = smoothMonotone === 'x' ? 0 : 1;
\r
21244 lenPrevSeg = Math.abs(p[dim] - prevP[dim]);
\r
21245 lenNextSeg = Math.abs(p[dim] - nextP[dim]);
\r
21248 lenPrevSeg = vec2.dist(p, prevP);
\r
21249 lenNextSeg = vec2.dist(p, nextP);
\r
21252 // Use ratio of seg length
\r
21253 ratioNextSeg = lenNextSeg / (lenNextSeg + lenPrevSeg);
\r
21255 scaleAndAdd(cp1, p, v, -smooth * (1 - ratioNextSeg));
\r
21257 // Smooth constraint
\r
21258 vec2Min(cp0, cp0, smoothMax);
\r
21259 vec2Max(cp0, cp0, smoothMin);
\r
21260 vec2Min(cp1, cp1, smoothMax);
\r
21261 vec2Max(cp1, cp1, smoothMin);
\r
21263 ctx.bezierCurveTo(
\r
21268 // cp0 of next segment
\r
21269 scaleAndAdd(cp0, p, v, smooth * ratioNextSeg);
\r
21272 ctx.lineTo(p[0], p[1]);
\r
21282 function getBoundingBox(points, smoothConstraint) {
\r
21283 var ptMin = [Infinity, Infinity];
\r
21284 var ptMax = [-Infinity, -Infinity];
\r
21285 if (smoothConstraint) {
\r
21286 for (var i = 0; i < points.length; i++) {
\r
21287 var pt = points[i];
\r
21288 if (pt[0] < ptMin[0]) { ptMin[0] = pt[0]; }
\r
21289 if (pt[1] < ptMin[1]) { ptMin[1] = pt[1]; }
\r
21290 if (pt[0] > ptMax[0]) { ptMax[0] = pt[0]; }
\r
21291 if (pt[1] > ptMax[1]) { ptMax[1] = pt[1]; }
\r
21295 min: smoothConstraint ? ptMin : ptMax,
\r
21296 max: smoothConstraint ? ptMax : ptMin
\r
21300 module.exports = {
\r
21302 Polyline: Path.extend({
\r
21304 type: 'ec-polyline',
\r
21311 smoothConstraint: true,
\r
21313 smoothMonotone: null
\r
21322 buildPath: function (ctx, shape) {
\r
21323 var points = shape.points;
\r
21326 var len = points.length;
\r
21328 var result = getBoundingBox(points, shape.smoothConstraint);
\r
21330 while (i < len) {
\r
21331 i += drawSegment(
\r
21332 ctx, points, i, len, len,
\r
21333 1, result.min, result.max, shape.smooth,
\r
21334 shape.smoothMonotone
\r
21340 Polygon: Path.extend({
\r
21342 type: 'ec-polygon',
\r
21347 // Offset between stacked base points and points
\r
21348 stackedOnPoints: [],
\r
21352 stackedOnSmooth: 0,
\r
21354 smoothConstraint: true,
\r
21356 smoothMonotone: null
\r
21359 buildPath: function (ctx, shape) {
\r
21360 var points = shape.points;
\r
21361 var stackedOnPoints = shape.stackedOnPoints;
\r
21364 var len = points.length;
\r
21365 var smoothMonotone = shape.smoothMonotone;
\r
21366 var bbox = getBoundingBox(points, shape.smoothConstraint);
\r
21367 var stackedOnBBox = getBoundingBox(stackedOnPoints, shape.smoothConstraint);
\r
21368 while (i < len) {
\r
21369 var k = drawSegment(
\r
21370 ctx, points, i, len, len,
\r
21371 1, bbox.min, bbox.max, shape.smooth,
\r
21375 ctx, stackedOnPoints, i + k - 1, len, k,
\r
21376 -1, stackedOnBBox.min, stackedOnBBox.max, shape.stackedOnSmooth,
\r
21390 /***/ function(module, exports) {
\r
21394 module.exports = function (seriesType, defaultSymbolType, legendSymbol, ecModel, api) {
\r
21396 // Encoding visual for all series include which is filtered for legend drawing
\r
21397 ecModel.eachRawSeriesByType(seriesType, function (seriesModel) {
\r
21398 var data = seriesModel.getData();
\r
21400 var symbolType = seriesModel.get('symbol') || defaultSymbolType;
\r
21401 var symbolSize = seriesModel.get('symbolSize');
\r
21404 legendSymbol: legendSymbol || symbolType,
\r
21405 symbol: symbolType,
\r
21406 symbolSize: symbolSize
\r
21409 // Only visible series has each data be visual encoded
\r
21410 if (!ecModel.isSeriesFiltered(seriesModel)) {
\r
21411 if (typeof symbolSize === 'function') {
\r
21412 data.each(function (idx) {
\r
21413 var rawValue = seriesModel.getRawValue(idx);
\r
21415 var params = seriesModel.getDataParams(idx);
\r
21416 data.setItemVisual(idx, 'symbolSize', symbolSize(rawValue, params));
\r
21419 data.each(function (idx) {
\r
21420 var itemModel = data.getItemModel(idx);
\r
21421 var itemSymbolType = itemModel.get('symbol', true);
\r
21422 var itemSymbolSize = itemModel.get('symbolSize', true);
\r
21423 // If has item symbol
\r
21424 if (itemSymbolType != null) {
\r
21425 data.setItemVisual(idx, 'symbol', itemSymbolType);
\r
21427 if (itemSymbolSize != null) {
\r
21428 // PENDING Transform symbolSize ?
\r
21429 data.setItemVisual(idx, 'symbolSize', itemSymbolSize);
\r
21439 /***/ function(module, exports) {
\r
21443 module.exports = function (seriesType, ecModel, api) {
\r
21444 ecModel.eachSeriesByType(seriesType, function (seriesModel) {
\r
21445 var data = seriesModel.getData();
\r
21446 var coordSys = seriesModel.coordinateSystem;
\r
21448 var dims = coordSys.dimensions;
\r
21449 data.each(dims, function (x, y, idx) {
\r
21451 if (!isNaN(x) && !isNaN(y)) {
\r
21452 point = coordSys.dataToPoint([x, y]);
\r
21455 // Also {Array.<number>}, not undefined to avoid if...else... statement
\r
21456 point = [NaN, NaN];
\r
21459 data.setItemLayout(idx, point);
\r
21467 /***/ function(module, exports) {
\r
21471 average: function (frame) {
\r
21474 for (var i = 0; i < frame.length; i++) {
\r
21475 if (!isNaN(frame[i])) {
\r
21480 // Return NaN if count is 0
\r
21481 return count === 0 ? NaN : sum / count;
\r
21483 sum: function (frame) {
\r
21485 for (var i = 0; i < frame.length; i++) {
\r
21487 sum += frame[i] || 0;
\r
21491 max: function (frame) {
\r
21492 var max = -Infinity;
\r
21493 for (var i = 0; i < frame.length; i++) {
\r
21494 frame[i] > max && (max = frame[i]);
\r
21498 min: function (frame) {
\r
21499 var min = Infinity;
\r
21500 for (var i = 0; i < frame.length; i++) {
\r
21501 frame[i] < min && (min = frame[i]);
\r
21507 var indexSampler = function (frame, value) {
\r
21508 return Math.round(frame.length / 2);
\r
21510 module.exports = function (seriesType, ecModel, api) {
\r
21511 ecModel.eachSeriesByType(seriesType, function (seriesModel) {
\r
21512 var data = seriesModel.getData();
\r
21513 var sampling = seriesModel.get('sampling');
\r
21514 var coordSys = seriesModel.coordinateSystem;
\r
21515 // Only cartesian2d support down sampling
\r
21516 if (coordSys.type === 'cartesian2d' && sampling) {
\r
21517 var baseAxis = coordSys.getBaseAxis();
\r
21518 var valueAxis = coordSys.getOtherAxis(baseAxis);
\r
21519 var extent = baseAxis.getExtent();
\r
21520 // Coordinste system has been resized
\r
21521 var size = extent[1] - extent[0];
\r
21522 var rate = Math.round(data.count() / size);
\r
21525 if (typeof sampling === 'string') {
\r
21526 sampler = samplers[sampling];
\r
21528 else if (typeof sampling === 'function') {
\r
21529 sampler = sampling;
\r
21532 data = data.downSample(
\r
21533 valueAxis.dim, 1 / rate, sampler, indexSampler
\r
21535 seriesModel.setData(data);
\r
21545 /***/ function(module, exports, __webpack_require__) {
\r
21550 var graphic = __webpack_require__(42);
\r
21551 var zrUtil = __webpack_require__(3);
\r
21553 __webpack_require__(107);
\r
21555 __webpack_require__(124);
\r
21558 __webpack_require__(1).extendComponentView({
\r
21562 render: function (gridModel, ecModel) {
\r
21563 this.group.removeAll();
\r
21564 if (gridModel.get('show')) {
\r
21565 this.group.add(new graphic.Rect({
\r
21566 shape:gridModel.coordinateSystem.getRect(),
\r
21567 style: zrUtil.defaults({
\r
21568 fill: gridModel.get('backgroundColor')
\r
21569 }, gridModel.getItemStyle()),
\r
21579 /***/ function(module, exports, __webpack_require__) {
\r
21582 * Grid is a region which contains at most 4 cartesian systems
\r
21584 * TODO Default cartesian
\r
21586 var factory = exports;
\r
21588 var layout = __webpack_require__(21);
\r
21589 var axisHelper = __webpack_require__(108);
\r
21591 var zrUtil = __webpack_require__(3);
\r
21592 var Cartesian2D = __webpack_require__(114);
\r
21593 var Axis2D = __webpack_require__(116);
\r
21595 var each = zrUtil.each;
\r
21597 var ifAxisCrossZero = axisHelper.ifAxisCrossZero;
\r
21598 var niceScaleExtent = axisHelper.niceScaleExtent;
\r
21600 // 依赖 GridModel, AxisModel 做预处理
\r
21601 __webpack_require__(119);
\r
21604 * Check if the axis is used in the specified grid
\r
21607 function isAxisUsedInTheGrid(axisModel, gridModel, ecModel) {
\r
21608 return ecModel.getComponent('grid', axisModel.get('gridIndex')) === gridModel;
\r
21611 function getLabelUnionRect(axis) {
\r
21612 var axisModel = axis.model;
\r
21613 var labels = axisModel.getFormattedLabels();
\r
21616 var labelCount = labels.length;
\r
21617 if (labelCount > 40) {
\r
21618 // Simple optimization for large amount of labels
\r
21619 step = Math.ceil(labelCount / 40);
\r
21621 for (var i = 0; i < labelCount; i += step) {
\r
21622 if (!axis.isLabelIgnored(i)) {
\r
21623 var singleRect = axisModel.getTextRect(labels[i]);
\r
21624 // FIXME consider label rotate
\r
21625 rect ? rect.union(singleRect) : (rect = singleRect);
\r
21631 function Grid(gridModel, ecModel, api) {
\r
21633 * @type {Object.<string, module:echarts/coord/cartesian/Cartesian2D>}
\r
21636 this._coordsMap = {};
\r
21639 * @type {Array.<module:echarts/coord/cartesian/Cartesian>}
\r
21642 this._coordsList = [];
\r
21645 * @type {Object.<string, module:echarts/coord/cartesian/Axis2D>}
\r
21648 this._axesMap = {};
\r
21651 * @type {Array.<module:echarts/coord/cartesian/Axis2D>}
\r
21654 this._axesList = [];
\r
21656 this._initCartesian(gridModel, ecModel, api);
\r
21658 this._model = gridModel;
\r
21661 var gridProto = Grid.prototype;
\r
21663 gridProto.type = 'grid';
\r
21665 gridProto.getRect = function () {
\r
21666 return this._rect;
\r
21669 gridProto.update = function (ecModel, api) {
\r
21671 var axesMap = this._axesMap;
\r
21673 this._updateScale(ecModel, this._model);
\r
21675 function ifAxisCanNotOnZero(otherAxisDim) {
\r
21676 var axes = axesMap[otherAxisDim];
\r
21677 for (var idx in axes) {
\r
21678 var axis = axes[idx];
\r
21679 if (axis && (axis.type === 'category' || !ifAxisCrossZero(axis))) {
\r
21686 each(axesMap.x, function (xAxis) {
\r
21687 niceScaleExtent(xAxis, xAxis.model);
\r
21689 each(axesMap.y, function (yAxis) {
\r
21690 niceScaleExtent(yAxis, yAxis.model);
\r
21692 // Fix configuration
\r
21693 each(axesMap.x, function (xAxis) {
\r
21694 // onZero can not be enabled in these two situations
\r
21695 // 1. When any other axis is a category axis
\r
21696 // 2. When any other axis not across 0 point
\r
21697 if (ifAxisCanNotOnZero('y')) {
\r
21698 xAxis.onZero = false;
\r
21701 each(axesMap.y, function (yAxis) {
\r
21702 if (ifAxisCanNotOnZero('x')) {
\r
21703 yAxis.onZero = false;
\r
21707 // Resize again if containLabel is enabled
\r
21708 // FIXME It may cause getting wrong grid size in data processing stage
\r
21709 this.resize(this._model, api);
\r
21713 * Resize the grid
\r
21714 * @param {module:echarts/coord/cartesian/GridModel} gridModel
\r
21715 * @param {module:echarts/ExtensionAPI} api
\r
21717 gridProto.resize = function (gridModel, api) {
\r
21719 var gridRect = layout.getLayoutRect(
\r
21720 gridModel.getBoxLayoutParams(), {
\r
21721 width: api.getWidth(),
\r
21722 height: api.getHeight()
\r
21725 this._rect = gridRect;
\r
21727 var axesList = this._axesList;
\r
21731 // Minus label size
\r
21732 if (gridModel.get('containLabel')) {
\r
21733 each(axesList, function (axis) {
\r
21734 if (!axis.model.get('axisLabel.inside')) {
\r
21735 var labelUnionRect = getLabelUnionRect(axis);
\r
21736 if (labelUnionRect) {
\r
21737 var dim = axis.isHorizontal() ? 'height' : 'width';
\r
21738 var margin = axis.model.get('axisLabel.margin');
\r
21739 gridRect[dim] -= labelUnionRect[dim] + margin;
\r
21740 if (axis.position === 'top') {
\r
21741 gridRect.y += labelUnionRect.height + margin;
\r
21743 else if (axis.position === 'left') {
\r
21744 gridRect.x += labelUnionRect.width + margin;
\r
21753 function adjustAxes() {
\r
21754 each(axesList, function (axis) {
\r
21755 var isHorizontal = axis.isHorizontal();
\r
21756 var extent = isHorizontal ? [0, gridRect.width] : [0, gridRect.height];
\r
21757 var idx = axis.inverse ? 1 : 0;
\r
21758 axis.setExtent(extent[idx], extent[1 - idx]);
\r
21759 updateAxisTransfrom(axis, isHorizontal ? gridRect.x : gridRect.y);
\r
21765 * @param {string} axisType
\r
21766 * @param {ndumber} [axisIndex]
\r
21768 gridProto.getAxis = function (axisType, axisIndex) {
\r
21769 var axesMapOnDim = this._axesMap[axisType];
\r
21770 if (axesMapOnDim != null) {
\r
21771 if (axisIndex == null) {
\r
21772 // Find first axis
\r
21773 for (var name in axesMapOnDim) {
\r
21774 return axesMapOnDim[name];
\r
21777 return axesMapOnDim[axisIndex];
\r
21781 gridProto.getCartesian = function (xAxisIndex, yAxisIndex) {
\r
21782 var key = 'x' + xAxisIndex + 'y' + yAxisIndex;
\r
21783 return this._coordsMap[key];
\r
21787 * Initialize cartesian coordinate systems
\r
21790 gridProto._initCartesian = function (gridModel, ecModel, api) {
\r
21791 var axisPositionUsed = {
\r
21802 var axesCount = {
\r
21808 ecModel.eachComponent('xAxis', createAxisCreator('x'), this);
\r
21809 ecModel.eachComponent('yAxis', createAxisCreator('y'), this);
\r
21811 if (!axesCount.x || !axesCount.y) {
\r
21812 // Roll back when there no either x or y axis
\r
21813 this._axesMap = {};
\r
21814 this._axesList = [];
\r
21818 this._axesMap = axesMap;
\r
21820 /// Create cartesian2d
\r
21821 each(axesMap.x, function (xAxis, xAxisIndex) {
\r
21822 each(axesMap.y, function (yAxis, yAxisIndex) {
\r
21823 var key = 'x' + xAxisIndex + 'y' + yAxisIndex;
\r
21824 var cartesian = new Cartesian2D(key);
\r
21826 cartesian.grid = this;
\r
21828 this._coordsMap[key] = cartesian;
\r
21829 this._coordsList.push(cartesian);
\r
21831 cartesian.addAxis(xAxis);
\r
21832 cartesian.addAxis(yAxis);
\r
21836 function createAxisCreator(axisType) {
\r
21837 return function (axisModel, idx) {
\r
21838 if (!isAxisUsedInTheGrid(axisModel, gridModel, ecModel)) {
\r
21842 var axisPosition = axisModel.get('position');
\r
21843 if (axisType === 'x') {
\r
21845 if (axisPosition !== 'top' && axisPosition !== 'bottom') {
\r
21846 // Default bottom of X
\r
21847 axisPosition = 'bottom';
\r
21849 if (axisPositionUsed[axisPosition]) {
\r
21850 axisPosition = axisPosition === 'top' ? 'bottom' : 'top';
\r
21855 if (axisPosition !== 'left' && axisPosition !== 'right') {
\r
21856 // Default left of Y
\r
21857 axisPosition = 'left';
\r
21859 if (axisPositionUsed[axisPosition]) {
\r
21860 axisPosition = axisPosition === 'left' ? 'right' : 'left';
\r
21863 axisPositionUsed[axisPosition] = true;
\r
21865 var axis = new Axis2D(
\r
21866 axisType, axisHelper.createScaleByModel(axisModel),
\r
21868 axisModel.get('type'),
\r
21872 var isCategory = axis.type === 'category';
\r
21873 axis.onBand = isCategory && axisModel.get('boundaryGap');
\r
21874 axis.inverse = axisModel.get('inverse');
\r
21876 axis.onZero = axisModel.get('axisLine.onZero');
\r
21878 // Inject axis into axisModel
\r
21879 axisModel.axis = axis;
\r
21881 // Inject axisModel into axis
\r
21882 axis.model = axisModel;
\r
21884 // Index of axis, can be used as key
\r
21885 axis.index = idx;
\r
21887 this._axesList.push(axis);
\r
21889 axesMap[axisType][idx] = axis;
\r
21890 axesCount[axisType]++;
\r
21896 * Update cartesian properties from series
\r
21897 * @param {module:echarts/model/Option} option
\r
21900 gridProto._updateScale = function (ecModel, gridModel) {
\r
21902 zrUtil.each(this._axesList, function (axis) {
\r
21903 axis.scale.setExtent(Infinity, -Infinity);
\r
21905 ecModel.eachSeries(function (seriesModel) {
\r
21906 if (seriesModel.get('coordinateSystem') === 'cartesian2d') {
\r
21907 var xAxisIndex = seriesModel.get('xAxisIndex');
\r
21908 var yAxisIndex = seriesModel.get('yAxisIndex');
\r
21910 var xAxisModel = ecModel.getComponent('xAxis', xAxisIndex);
\r
21911 var yAxisModel = ecModel.getComponent('yAxis', yAxisIndex);
\r
21913 if (!isAxisUsedInTheGrid(xAxisModel, gridModel, ecModel)
\r
21914 || !isAxisUsedInTheGrid(yAxisModel, gridModel, ecModel)
\r
21919 var cartesian = this.getCartesian(xAxisIndex, yAxisIndex);
\r
21920 var data = seriesModel.getData();
\r
21921 var xAxis = cartesian.getAxis('x');
\r
21922 var yAxis = cartesian.getAxis('y');
\r
21924 if (data.type === 'list') {
\r
21925 unionExtent(data, xAxis, seriesModel);
\r
21926 unionExtent(data, yAxis, seriesModel);
\r
21931 function unionExtent(data, axis, seriesModel) {
\r
21932 each(seriesModel.coordDimToDataDim(axis.dim), function (dim) {
\r
21933 axis.scale.unionExtent(data.getDataExtent(
\r
21934 dim, axis.scale.type !== 'ordinal'
\r
21943 function updateAxisTransfrom(axis, coordBase) {
\r
21944 var axisExtent = axis.getExtent();
\r
21945 var axisExtentSum = axisExtent[0] + axisExtent[1];
\r
21947 // Fast transform
\r
21948 axis.toGlobalCoord = axis.dim === 'x'
\r
21949 ? function (coord) {
\r
21950 return coord + coordBase;
\r
21952 : function (coord) {
\r
21953 return axisExtentSum - coord + coordBase;
\r
21955 axis.toLocalCoord = axis.dim === 'x'
\r
21956 ? function (coord) {
\r
21957 return coord - coordBase;
\r
21959 : function (coord) {
\r
21960 return axisExtentSum - coord + coordBase;
\r
21964 Grid.create = function (ecModel, api) {
\r
21966 ecModel.eachComponent('grid', function (gridModel, idx) {
\r
21967 var grid = new Grid(gridModel, ecModel, api);
\r
21968 grid.name = 'grid_' + idx;
\r
21969 grid.resize(gridModel, api);
\r
21971 gridModel.coordinateSystem = grid;
\r
21973 grids.push(grid);
\r
21976 // Inject the coordinateSystems into seriesModel
\r
21977 ecModel.eachSeries(function (seriesModel) {
\r
21978 if (seriesModel.get('coordinateSystem') !== 'cartesian2d') {
\r
21981 var xAxisIndex = seriesModel.get('xAxisIndex');
\r
21983 var xAxisModel = ecModel.getComponent('xAxis', xAxisIndex);
\r
21984 var grid = grids[xAxisModel.get('gridIndex')];
\r
21985 seriesModel.coordinateSystem = grid.getCartesian(
\r
21986 xAxisIndex, seriesModel.get('yAxisIndex')
\r
21993 // For deciding which dimensions to use when creating list data
\r
21994 Grid.dimensions = Cartesian2D.prototype.dimensions;
\r
21996 __webpack_require__(25).register('cartesian2d', Grid);
\r
21998 module.exports = Grid;
\r
22003 /***/ function(module, exports, __webpack_require__) {
\r
22007 var OrdinalScale = __webpack_require__(109);
\r
22008 var IntervalScale = __webpack_require__(111);
\r
22009 __webpack_require__(112);
\r
22010 __webpack_require__(113);
\r
22011 var Scale = __webpack_require__(110);
\r
22013 var numberUtil = __webpack_require__(7);
\r
22014 var zrUtil = __webpack_require__(3);
\r
22015 var textContain = __webpack_require__(14);
\r
22016 var axisHelper = {};
\r
22019 * Get axis scale extent before niced.
\r
22021 axisHelper.getScaleExtent = function (axis, model) {
\r
22022 var scale = axis.scale;
\r
22023 var originalExtent = scale.getExtent();
\r
22024 var span = originalExtent[1] - originalExtent[0];
\r
22025 if (scale.type === 'ordinal') {
\r
22026 // If series has no data, scale extent may be wrong
\r
22027 if (!isFinite(span)) {
\r
22031 return originalExtent;
\r
22034 var min = model.getMin ? model.getMin() : model.get('min');
\r
22035 var max = model.getMax ? model.getMax() : model.get('max');
\r
22036 var crossZero = model.getNeedCrossZero
\r
22037 ? model.getNeedCrossZero() : !model.get('scale');
\r
22038 var boundaryGap = model.get('boundaryGap');
\r
22039 if (!zrUtil.isArray(boundaryGap)) {
\r
22040 boundaryGap = [boundaryGap || 0, boundaryGap || 0];
\r
22042 boundaryGap[0] = numberUtil.parsePercent(boundaryGap[0], 1);
\r
22043 boundaryGap[1] = numberUtil.parsePercent(boundaryGap[1], 1);
\r
22044 var fixMin = true;
\r
22045 var fixMax = true;
\r
22046 // Add boundary gap
\r
22047 if (min == null) {
\r
22048 min = originalExtent[0] - boundaryGap[0] * span;
\r
22051 if (max == null) {
\r
22052 max = originalExtent[1] + boundaryGap[1] * span;
\r
22055 // TODO Only one data
\r
22056 if (min === 'dataMin') {
\r
22057 min = originalExtent[0];
\r
22059 if (max === 'dataMax') {
\r
22060 max = originalExtent[1];
\r
22062 // Evaluate if axis needs cross zero
\r
22064 // Axis is over zero and min is not set
\r
22065 if (min > 0 && max > 0 && !fixMin) {
\r
22068 // Axis is under zero and max is not set
\r
22069 if (min < 0 && max < 0 && !fixMax) {
\r
22073 return [min, max];
\r
22076 axisHelper.niceScaleExtent = function (axis, model) {
\r
22077 var scale = axis.scale;
\r
22078 var extent = axisHelper.getScaleExtent(axis, model);
\r
22079 var fixMin = (model.getMin ? model.getMin() : model.get('min')) != null;
\r
22080 var fixMax = (model.getMax ? model.getMax() : model.get('max')) != null;
\r
22081 scale.setExtent(extent[0], extent[1]);
\r
22082 scale.niceExtent(model.get('splitNumber'), fixMin, fixMax);
\r
22084 // If some one specified the min, max. And the default calculated interval
\r
22085 // is not good enough. He can specify the interval. It is often appeared
\r
22086 // in angle axis with angle 0 - 360. Interval calculated in interval scale is hard
\r
22089 var interval = model.get('interval');
\r
22090 if (interval != null) {
\r
22091 scale.setInterval && scale.setInterval(interval);
\r
22096 * @param {module:echarts/model/Model} model
\r
22097 * @param {string} [axisType] Default retrieve from model.type
\r
22098 * @return {module:echarts/scale/*}
\r
22100 axisHelper.createScaleByModel = function(model, axisType) {
\r
22101 axisType = axisType || model.get('type');
\r
22103 switch (axisType) {
\r
22106 return new OrdinalScale(
\r
22107 model.getCategories(), [Infinity, -Infinity]
\r
22110 return new IntervalScale();
\r
22111 // Extended scale, like time and log
\r
22113 return (Scale.getClass(axisType) || IntervalScale).create(model);
\r
22119 * Check if the axis corss 0
\r
22121 axisHelper.ifAxisCrossZero = function (axis) {
\r
22122 var dataExtent = axis.scale.getExtent();
\r
22123 var min = dataExtent[0];
\r
22124 var max = dataExtent[1];
\r
22125 return !((min > 0 && max > 0) || (min < 0 && max < 0));
\r
22129 * @param {Array.<number>} tickCoords In axis self coordinate.
\r
22130 * @param {Array.<string>} labels
\r
22131 * @param {string} font
\r
22132 * @param {boolean} isAxisHorizontal
\r
22133 * @return {number}
\r
22135 axisHelper.getAxisLabelInterval = function (tickCoords, labels, font, isAxisHorizontal) {
\r
22137 // 不同角的axis和label,不只是horizontal和vertical.
\r
22139 var textSpaceTakenRect;
\r
22140 var autoLabelInterval = 0;
\r
22141 var accumulatedLabelInterval = 0;
\r
22144 if (labels.length > 40) {
\r
22145 // Simple optimization for large amount of labels
\r
22146 step = Math.round(labels.length / 40);
\r
22148 for (var i = 0; i < tickCoords.length; i += step) {
\r
22149 var tickCoord = tickCoords[i];
\r
22150 var rect = textContain.getBoundingRect(
\r
22151 labels[i], font, 'center', 'top'
\r
22153 rect[isAxisHorizontal ? 'x' : 'y'] += tickCoord;
\r
22154 rect[isAxisHorizontal ? 'width' : 'height'] *= 1.5;
\r
22155 if (!textSpaceTakenRect) {
\r
22156 textSpaceTakenRect = rect.clone();
\r
22158 // There is no space for current label;
\r
22159 else if (textSpaceTakenRect.intersect(rect)) {
\r
22160 accumulatedLabelInterval++;
\r
22161 autoLabelInterval = Math.max(autoLabelInterval, accumulatedLabelInterval);
\r
22164 textSpaceTakenRect.union(rect);
\r
22166 accumulatedLabelInterval = 0;
\r
22169 if (autoLabelInterval === 0 && step > 1) {
\r
22172 return autoLabelInterval * step;
\r
22176 * @param {Object} axis
\r
22177 * @param {Function} labelFormatter
\r
22178 * @return {Array.<string>}
\r
22180 axisHelper.getFormattedLabels = function (axis, labelFormatter) {
\r
22181 var scale = axis.scale;
\r
22182 var labels = scale.getTicksLabels();
\r
22183 var ticks = scale.getTicks();
\r
22184 if (typeof labelFormatter === 'string') {
\r
22185 labelFormatter = (function (tpl) {
\r
22186 return function (val) {
\r
22187 return tpl.replace('{value}', val);
\r
22189 })(labelFormatter);
\r
22190 return zrUtil.map(labels, labelFormatter);
\r
22192 else if (typeof labelFormatter === 'function') {
\r
22193 return zrUtil.map(ticks, function (tick, idx) {
\r
22194 return labelFormatter(
\r
22195 axis.type === 'category' ? scale.getLabel(tick) : tick,
\r
22205 module.exports = axisHelper;
\r
22210 /***/ function(module, exports, __webpack_require__) {
\r
22213 * Linear continuous scale
\r
22214 * @module echarts/coord/scale/Ordinal
\r
22216 * http://en.wikipedia.org/wiki/Level_of_measurement
\r
22219 // FIXME only one data
\r
22222 var zrUtil = __webpack_require__(3);
\r
22223 var Scale = __webpack_require__(110);
\r
22225 var scaleProto = Scale.prototype;
\r
22227 var OrdinalScale = Scale.extend({
\r
22231 init: function (data, extent) {
\r
22232 this._data = data;
\r
22233 this._extent = extent || [0, data.length - 1];
\r
22236 parse: function (val) {
\r
22237 return typeof val === 'string'
\r
22238 ? zrUtil.indexOf(this._data, val)
\r
22239 // val might be float.
\r
22240 : Math.round(val);
\r
22243 contain: function (rank) {
\r
22244 rank = this.parse(rank);
\r
22245 return scaleProto.contain.call(this, rank)
\r
22246 && this._data[rank] != null;
\r
22250 * Normalize given rank or name to linear [0, 1]
\r
22251 * @param {number|string} [val]
\r
22252 * @return {number}
\r
22254 normalize: function (val) {
\r
22255 return scaleProto.normalize.call(this, this.parse(val));
\r
22258 scale: function (val) {
\r
22259 return Math.round(scaleProto.scale.call(this, val));
\r
22263 * @return {Array}
\r
22265 getTicks: function () {
\r
22267 var extent = this._extent;
\r
22268 var rank = extent[0];
\r
22270 while (rank <= extent[1]) {
\r
22271 ticks.push(rank);
\r
22279 * Get item on rank n
\r
22280 * @param {number} n
\r
22281 * @return {string}
\r
22283 getLabel: function (n) {
\r
22284 return this._data[n];
\r
22288 * @return {number}
\r
22290 count: function () {
\r
22291 return this._extent[1] - this._extent[0] + 1;
\r
22294 niceTicks: zrUtil.noop,
\r
22295 niceExtent: zrUtil.noop
\r
22299 * @return {module:echarts/scale/Time}
\r
22301 OrdinalScale.create = function () {
\r
22302 return new OrdinalScale();
\r
22305 module.exports = OrdinalScale;
\r
22310 /***/ function(module, exports, __webpack_require__) {
\r
22313 * // Scale class management
\r
22314 * @module echarts/scale/Scale
\r
22318 var clazzUtil = __webpack_require__(9);
\r
22320 function Scale() {
\r
22323 * @type {Array.<number>}
\r
22326 this._extent = [Infinity, -Infinity];
\r
22329 * Step is calculated in adjustExtent
\r
22330 * @type {Array.<number>}
\r
22333 this._interval = 0;
\r
22335 this.init && this.init.apply(this, arguments);
\r
22338 var scaleProto = Scale.prototype;
\r
22341 * Parse input val to valid inner number.
\r
22343 * @return {number}
\r
22345 scaleProto.parse = function (val) {
\r
22346 // Notice: This would be a trap here, If the implementation
\r
22347 // of this method depends on extent, and this method is used
\r
22348 // before extent set (like in dataZoom), it would be wrong.
\r
22349 // Nevertheless, parse does not depend on extent generally.
\r
22353 scaleProto.contain = function (val) {
\r
22354 var extent = this._extent;
\r
22355 return val >= extent[0] && val <= extent[1];
\r
22359 * Normalize value to linear [0, 1], return 0.5 if extent span is 0
\r
22360 * @param {number} val
\r
22361 * @return {number}
\r
22363 scaleProto.normalize = function (val) {
\r
22364 var extent = this._extent;
\r
22365 if (extent[1] === extent[0]) {
\r
22368 return (val - extent[0]) / (extent[1] - extent[0]);
\r
22372 * Scale normalized value
\r
22373 * @param {number} val
\r
22374 * @return {number}
\r
22376 scaleProto.scale = function (val) {
\r
22377 var extent = this._extent;
\r
22378 return val * (extent[1] - extent[0]) + extent[0];
\r
22382 * Set extent from data
\r
22383 * @param {Array.<number>} other
\r
22385 scaleProto.unionExtent = function (other) {
\r
22386 var extent = this._extent;
\r
22387 other[0] < extent[0] && (extent[0] = other[0]);
\r
22388 other[1] > extent[1] && (extent[1] = other[1]);
\r
22389 // not setExtent because in log axis it may transformed to power
\r
22390 // this.setExtent(extent[0], extent[1]);
\r
22395 * @return {Array.<number>}
\r
22397 scaleProto.getExtent = function () {
\r
22398 return this._extent.slice();
\r
22403 * @param {number} start
\r
22404 * @param {number} end
\r
22406 scaleProto.setExtent = function (start, end) {
\r
22407 var thisExtent = this._extent;
\r
22408 if (!isNaN(start)) {
\r
22409 thisExtent[0] = start;
\r
22411 if (!isNaN(end)) {
\r
22412 thisExtent[1] = end;
\r
22417 * @return {Array.<string>}
\r
22419 scaleProto.getTicksLabels = function () {
\r
22421 var ticks = this.getTicks();
\r
22422 for (var i = 0; i < ticks.length; i++) {
\r
22423 labels.push(this.getLabel(ticks[i]));
\r
22428 clazzUtil.enableClassExtend(Scale);
\r
22429 clazzUtil.enableClassManagement(Scale, {
\r
22430 registerWhenExtend: true
\r
22433 module.exports = Scale;
\r
22438 /***/ function(module, exports, __webpack_require__) {
\r
22442 * @module echarts/scale/Interval
\r
22447 var numberUtil = __webpack_require__(7);
\r
22448 var formatUtil = __webpack_require__(6);
\r
22449 var Scale = __webpack_require__(110);
\r
22451 var mathFloor = Math.floor;
\r
22452 var mathCeil = Math.ceil;
\r
22454 * @alias module:echarts/coord/scale/Interval
\r
22457 var IntervalScale = Scale.extend({
\r
22459 type: 'interval',
\r
22463 setExtent: function (start, end) {
\r
22464 var thisExtent = this._extent;
\r
22465 //start,end may be a Number like '25',so...
\r
22466 if (!isNaN(start)) {
\r
22467 thisExtent[0] = parseFloat(start);
\r
22469 if (!isNaN(end)) {
\r
22470 thisExtent[1] = parseFloat(end);
\r
22474 unionExtent: function (other) {
\r
22475 var extent = this._extent;
\r
22476 other[0] < extent[0] && (extent[0] = other[0]);
\r
22477 other[1] > extent[1] && (extent[1] = other[1]);
\r
22479 // unionExtent may called by it's sub classes
\r
22480 IntervalScale.prototype.setExtent.call(this, extent[0], extent[1]);
\r
22485 getInterval: function () {
\r
22486 if (!this._interval) {
\r
22487 this.niceTicks();
\r
22489 return this._interval;
\r
22495 setInterval: function (interval) {
\r
22496 this._interval = interval;
\r
22497 // Dropped auto calculated niceExtent and use user setted extent
\r
22498 // We assume user wan't to set both interval, min, max to get a better result
\r
22499 this._niceExtent = this._extent.slice();
\r
22503 * @return {Array.<number>}
\r
22505 getTicks: function () {
\r
22506 if (!this._interval) {
\r
22507 this.niceTicks();
\r
22509 var interval = this._interval;
\r
22510 var extent = this._extent;
\r
22513 // Consider this case: using dataZoom toolbox, zoom and zoom.
\r
22514 var safeLimit = 10000;
\r
22517 var niceExtent = this._niceExtent;
\r
22518 if (extent[0] < niceExtent[0]) {
\r
22519 ticks.push(extent[0]);
\r
22521 var tick = niceExtent[0];
\r
22522 while (tick <= niceExtent[1]) {
\r
22523 ticks.push(tick);
\r
22524 // Avoid rounding error
\r
22525 tick = numberUtil.round(tick + interval);
\r
22526 if (ticks.length > safeLimit) {
\r
22530 if (extent[1] > niceExtent[1]) {
\r
22531 ticks.push(extent[1]);
\r
22539 * @return {Array.<string>}
\r
22541 getTicksLabels: function () {
\r
22543 var ticks = this.getTicks();
\r
22544 for (var i = 0; i < ticks.length; i++) {
\r
22545 labels.push(this.getLabel(ticks[i]));
\r
22551 * @param {number} n
\r
22552 * @return {number}
\r
22554 getLabel: function (data) {
\r
22555 return formatUtil.addCommas(data);
\r
22559 * Update interval and extent of intervals for nice ticks
\r
22561 * @param {number} [splitNumber = 5] Desired number of ticks
\r
22563 niceTicks: function (splitNumber) {
\r
22564 splitNumber = splitNumber || 5;
\r
22565 var extent = this._extent;
\r
22566 var span = extent[1] - extent[0];
\r
22567 if (!isFinite(span)) {
\r
22570 // User may set axis min 0 and data are all negative
\r
22571 // FIXME If it needs to reverse ?
\r
22574 extent.reverse();
\r
22577 // From "Nice Numbers for Graph Labels" of Graphic Gems
\r
22578 // var niceSpan = numberUtil.nice(span, false);
\r
22579 var step = numberUtil.nice(span / splitNumber, true);
\r
22581 // Niced extent inside original extent
\r
22582 var niceExtent = [
\r
22583 numberUtil.round(mathCeil(extent[0] / step) * step),
\r
22584 numberUtil.round(mathFloor(extent[1] / step) * step)
\r
22587 this._interval = step;
\r
22588 this._niceExtent = niceExtent;
\r
22593 * @param {number} [splitNumber = 5] Given approx tick number
\r
22594 * @param {boolean} [fixMin=false]
\r
22595 * @param {boolean} [fixMax=false]
\r
22597 niceExtent: function (splitNumber, fixMin, fixMax) {
\r
22598 var extent = this._extent;
\r
22599 // If extent start and end are same, expand them
\r
22600 if (extent[0] === extent[1]) {
\r
22601 if (extent[0] !== 0) {
\r
22603 var expandSize = extent[0] / 2;
\r
22604 extent[0] -= expandSize;
\r
22605 extent[1] += expandSize;
\r
22611 var span = extent[1] - extent[0];
\r
22612 // If there are no data and extent are [Infinity, -Infinity]
\r
22613 if (!isFinite(span)) {
\r
22618 this.niceTicks(splitNumber);
\r
22620 // var extent = this._extent;
\r
22621 var interval = this._interval;
\r
22624 extent[0] = numberUtil.round(mathFloor(extent[0] / interval) * interval);
\r
22627 extent[1] = numberUtil.round(mathCeil(extent[1] / interval) * interval);
\r
22633 * @return {module:echarts/scale/Time}
\r
22635 IntervalScale.create = function () {
\r
22636 return new IntervalScale();
\r
22639 module.exports = IntervalScale;
\r
22645 /***/ function(module, exports, __webpack_require__) {
\r
22649 * @module echarts/coord/scale/Time
\r
22654 var zrUtil = __webpack_require__(3);
\r
22655 var numberUtil = __webpack_require__(7);
\r
22656 var formatUtil = __webpack_require__(6);
\r
22658 var IntervalScale = __webpack_require__(111);
\r
22660 var intervalScaleProto = IntervalScale.prototype;
\r
22662 var mathCeil = Math.ceil;
\r
22663 var mathFloor = Math.floor;
\r
22664 var ONE_DAY = 3600000 * 24;
\r
22667 var bisect = function (a, x, lo, hi) {
\r
22668 while (lo < hi) {
\r
22669 var mid = lo + hi >>> 1;
\r
22670 if (a[mid][2] < x) {
\r
22681 * @alias module:echarts/coord/scale/Time
\r
22684 var TimeScale = IntervalScale.extend({
\r
22688 getLabel: function (val) {
\r
22689 var stepLvl = this._stepLvl;
\r
22691 var date = new Date(val);
\r
22693 return formatUtil.formatTime(stepLvl[0], date);
\r
22697 niceExtent: function (approxTickNum, fixMin, fixMax) {
\r
22698 var extent = this._extent;
\r
22699 // If extent start and end are same, expand them
\r
22700 if (extent[0] === extent[1]) {
\r
22702 extent[0] -= ONE_DAY;
\r
22703 extent[1] += ONE_DAY;
\r
22705 // If there are no data and extent are [Infinity, -Infinity]
\r
22706 if (extent[1] === -Infinity && extent[0] === Infinity) {
\r
22707 var d = new Date();
\r
22708 extent[1] = new Date(d.getFullYear(), d.getMonth(), d.getDate());
\r
22709 extent[0] = extent[1] - ONE_DAY;
\r
22712 this.niceTicks(approxTickNum, fixMin, fixMax);
\r
22714 // var extent = this._extent;
\r
22715 var interval = this._interval;
\r
22718 extent[0] = numberUtil.round(mathFloor(extent[0] / interval) * interval);
\r
22721 extent[1] = numberUtil.round(mathCeil(extent[1] / interval) * interval);
\r
22726 niceTicks: function (approxTickNum) {
\r
22727 approxTickNum = approxTickNum || 10;
\r
22729 var extent = this._extent;
\r
22730 var span = extent[1] - extent[0];
\r
22731 var approxInterval = span / approxTickNum;
\r
22732 var scaleLevelsLen = scaleLevels.length;
\r
22733 var idx = bisect(scaleLevels, approxInterval, 0, scaleLevelsLen);
\r
22735 var level = scaleLevels[Math.min(idx, scaleLevelsLen - 1)];
\r
22736 var interval = level[2];
\r
22737 // Same with interval scale if span is much larger than 1 year
\r
22738 if (level[0] === 'year') {
\r
22739 var yearSpan = span / interval;
\r
22741 // From "Nice Numbers for Graph Labels" of Graphic Gems
\r
22742 // var niceYearSpan = numberUtil.nice(yearSpan, false);
\r
22743 var yearStep = numberUtil.nice(yearSpan / approxTickNum, true);
\r
22745 interval *= yearStep;
\r
22748 var niceExtent = [
\r
22749 mathCeil(extent[0] / interval) * interval,
\r
22750 mathFloor(extent[1] / interval) * interval
\r
22753 this._stepLvl = level;
\r
22754 // Interval will be used in getTicks
\r
22755 this._interval = interval;
\r
22756 this._niceExtent = niceExtent;
\r
22759 parse: function (val) {
\r
22760 // val might be float.
\r
22761 return +numberUtil.parseDate(val);
\r
22765 zrUtil.each(['contain', 'normalize'], function (methodName) {
\r
22766 TimeScale.prototype[methodName] = function (val) {
\r
22767 return intervalScaleProto[methodName].call(this, this.parse(val));
\r
22772 var scaleLevels = [
\r
22773 // Format step interval
\r
22774 ['hh:mm:ss', 1, 1000], // 1s
\r
22775 ['hh:mm:ss', 5, 1000 * 5], // 5s
\r
22776 ['hh:mm:ss', 10, 1000 * 10], // 10s
\r
22777 ['hh:mm:ss', 15, 1000 * 15], // 15s
\r
22778 ['hh:mm:ss', 30, 1000 * 30], // 30s
\r
22779 ['hh:mm\nMM-dd',1, 60000], // 1m
\r
22780 ['hh:mm\nMM-dd',5, 60000 * 5], // 5m
\r
22781 ['hh:mm\nMM-dd',10, 60000 * 10], // 10m
\r
22782 ['hh:mm\nMM-dd',15, 60000 * 15], // 15m
\r
22783 ['hh:mm\nMM-dd',30, 60000 * 30], // 30m
\r
22784 ['hh:mm\nMM-dd',1, 3600000], // 1h
\r
22785 ['hh:mm\nMM-dd',2, 3600000 * 2], // 2h
\r
22786 ['hh:mm\nMM-dd',6, 3600000 * 6], // 6h
\r
22787 ['hh:mm\nMM-dd',12, 3600000 * 12], // 12h
\r
22788 ['MM-dd\nyyyy', 1, ONE_DAY], // 1d
\r
22789 ['week', 7, ONE_DAY * 7], // 7d
\r
22790 ['month', 1, ONE_DAY * 31], // 1M
\r
22791 ['quarter', 3, ONE_DAY * 380 / 4], // 3M
\r
22792 ['half-year', 6, ONE_DAY * 380 / 2], // 6M
\r
22793 ['year', 1, ONE_DAY * 380] // 1Y
\r
22797 * @return {module:echarts/scale/Time}
\r
22799 TimeScale.create = function () {
\r
22800 return new TimeScale();
\r
22803 module.exports = TimeScale;
\r
22808 /***/ function(module, exports, __webpack_require__) {
\r
22812 * @module echarts/scale/Log
\r
22816 var zrUtil = __webpack_require__(3);
\r
22817 var Scale = __webpack_require__(110);
\r
22818 var numberUtil = __webpack_require__(7);
\r
22820 // Use some method of IntervalScale
\r
22821 var IntervalScale = __webpack_require__(111);
\r
22823 var scaleProto = Scale.prototype;
\r
22824 var intervalScaleProto = IntervalScale.prototype;
\r
22826 var mathFloor = Math.floor;
\r
22827 var mathCeil = Math.ceil;
\r
22828 var mathPow = Math.pow;
\r
22830 var LOG_BASE = 10;
\r
22831 var mathLog = Math.log;
\r
22833 var LogScale = Scale.extend({
\r
22838 * @return {Array.<number>}
\r
22840 getTicks: function () {
\r
22841 return zrUtil.map(intervalScaleProto.getTicks.call(this), function (val) {
\r
22842 return numberUtil.round(mathPow(LOG_BASE, val));
\r
22847 * @param {number} val
\r
22848 * @return {string}
\r
22850 getLabel: intervalScaleProto.getLabel,
\r
22853 * @param {number} val
\r
22854 * @return {number}
\r
22856 scale: function (val) {
\r
22857 val = scaleProto.scale.call(this, val);
\r
22858 return mathPow(LOG_BASE, val);
\r
22862 * @param {number} start
\r
22863 * @param {number} end
\r
22865 setExtent: function (start, end) {
\r
22866 start = mathLog(start) / mathLog(LOG_BASE);
\r
22867 end = mathLog(end) / mathLog(LOG_BASE);
\r
22868 intervalScaleProto.setExtent.call(this, start, end);
\r
22872 * @return {number} end
\r
22874 getExtent: function () {
\r
22875 var extent = scaleProto.getExtent.call(this);
\r
22876 extent[0] = mathPow(LOG_BASE, extent[0]);
\r
22877 extent[1] = mathPow(LOG_BASE, extent[1]);
\r
22882 * @param {Array.<number>} extent
\r
22884 unionExtent: function (extent) {
\r
22885 extent[0] = mathLog(extent[0]) / mathLog(LOG_BASE);
\r
22886 extent[1] = mathLog(extent[1]) / mathLog(LOG_BASE);
\r
22887 scaleProto.unionExtent.call(this, extent);
\r
22891 * Update interval and extent of intervals for nice ticks
\r
22892 * @param {number} [approxTickNum = 10] Given approx tick number
\r
22894 niceTicks: function (approxTickNum) {
\r
22895 approxTickNum = approxTickNum || 10;
\r
22896 var extent = this._extent;
\r
22897 var span = extent[1] - extent[0];
\r
22898 if (span === Infinity || span <= 0) {
\r
22902 var interval = mathPow(10, mathFloor(mathLog(span / approxTickNum) / Math.LN10));
\r
22903 var err = approxTickNum / span * interval;
\r
22905 // Filter ticks to get closer to the desired count.
\r
22906 if (err <= 0.5) {
\r
22909 var niceExtent = [
\r
22910 numberUtil.round(mathCeil(extent[0] / interval) * interval),
\r
22911 numberUtil.round(mathFloor(extent[1] / interval) * interval)
\r
22914 this._interval = interval;
\r
22915 this._niceExtent = niceExtent;
\r
22920 * @param {number} [approxTickNum = 10] Given approx tick number
\r
22921 * @param {boolean} [fixMin=false]
\r
22922 * @param {boolean} [fixMax=false]
\r
22924 niceExtent: intervalScaleProto.niceExtent
\r
22927 zrUtil.each(['contain', 'normalize'], function (methodName) {
\r
22928 LogScale.prototype[methodName] = function (val) {
\r
22929 val = mathLog(val) / mathLog(LOG_BASE);
\r
22930 return scaleProto[methodName].call(this, val);
\r
22934 LogScale.create = function () {
\r
22935 return new LogScale();
\r
22938 module.exports = LogScale;
\r
22943 /***/ function(module, exports, __webpack_require__) {
\r
22948 var zrUtil = __webpack_require__(3);
\r
22949 var Cartesian = __webpack_require__(115);
\r
22951 function Cartesian2D(name) {
\r
22953 Cartesian.call(this, name);
\r
22956 Cartesian2D.prototype = {
\r
22958 constructor: Cartesian2D,
\r
22960 type: 'cartesian2d',
\r
22963 * @type {Array.<string>}
\r
22966 dimensions: ['x', 'y'],
\r
22969 * Base axis will be used on stacking.
\r
22971 * @return {module:echarts/coord/cartesian/Axis2D}
\r
22973 getBaseAxis: function () {
\r
22974 return this.getAxesByScale('ordinal')[0]
\r
22975 || this.getAxesByScale('time')[0]
\r
22976 || this.getAxis('x');
\r
22980 * If contain point
\r
22981 * @param {Array.<number>} point
\r
22982 * @return {boolean}
\r
22984 containPoint: function (point) {
\r
22985 var axisX = this.getAxis('x');
\r
22986 var axisY = this.getAxis('y');
\r
22987 return axisX.contain(axisX.toLocalCoord(point[0]))
\r
22988 && axisY.contain(axisY.toLocalCoord(point[1]));
\r
22992 * If contain data
\r
22993 * @param {Array.<number>} data
\r
22994 * @return {boolean}
\r
22996 containData: function (data) {
\r
22997 return this.getAxis('x').containData(data[0])
\r
22998 && this.getAxis('y').containData(data[1]);
\r
23002 * Convert series data to an array of points
\r
23003 * @param {module:echarts/data/List} data
\r
23004 * @param {boolean} stack
\r
23005 * @return {Array}
\r
23006 * Return array of points. For example:
\r
23007 * `[[10, 10], [20, 20], [30, 30]]`
\r
23009 dataToPoints: function (data, stack) {
\r
23010 return data.mapArray(['x', 'y'], function (x, y) {
\r
23011 return this.dataToPoint([x, y]);
\r
23016 * @param {Array.<number>} data
\r
23017 * @param {boolean} [clamp=false]
\r
23018 * @return {Array.<number>}
\r
23020 dataToPoint: function (data, clamp) {
\r
23021 var xAxis = this.getAxis('x');
\r
23022 var yAxis = this.getAxis('y');
\r
23024 xAxis.toGlobalCoord(xAxis.dataToCoord(data[0], clamp)),
\r
23025 yAxis.toGlobalCoord(yAxis.dataToCoord(data[1], clamp))
\r
23030 * @param {Array.<number>} point
\r
23031 * @param {boolean} [clamp=false]
\r
23032 * @return {Array.<number>}
\r
23034 pointToData: function (point, clamp) {
\r
23035 var xAxis = this.getAxis('x');
\r
23036 var yAxis = this.getAxis('y');
\r
23038 xAxis.coordToData(xAxis.toLocalCoord(point[0]), clamp),
\r
23039 yAxis.coordToData(yAxis.toLocalCoord(point[1]), clamp)
\r
23045 * @param {module:echarts/coord/cartesian/Axis2D} axis
\r
23047 getOtherAxis: function (axis) {
\r
23048 return this.getAxis(axis.dim === 'x' ? 'y' : 'x');
\r
23052 zrUtil.inherits(Cartesian2D, Cartesian);
\r
23054 module.exports = Cartesian2D;
\r
23059 /***/ function(module, exports, __webpack_require__) {
\r
23063 * Cartesian coordinate system
\r
23064 * @module echarts/coord/Cartesian
\r
23069 var zrUtil = __webpack_require__(3);
\r
23071 function dimAxisMapper(dim) {
\r
23072 return this._axes[dim];
\r
23076 * @alias module:echarts/coord/Cartesian
\r
23079 var Cartesian = function (name) {
\r
23082 this._dimList = [];
\r
23087 this.name = name || '';
\r
23090 Cartesian.prototype = {
\r
23092 constructor: Cartesian,
\r
23094 type: 'cartesian',
\r
23098 * @param {number|string} dim
\r
23099 * @return {module:echarts/coord/Cartesian~Axis}
\r
23101 getAxis: function (dim) {
\r
23102 return this._axes[dim];
\r
23107 * @return {Array.<module:echarts/coord/Cartesian~Axis>}
\r
23109 getAxes: function () {
\r
23110 return zrUtil.map(this._dimList, dimAxisMapper, this);
\r
23114 * Get axes list by given scale type
\r
23116 getAxesByScale: function (scaleType) {
\r
23117 scaleType = scaleType.toLowerCase();
\r
23118 return zrUtil.filter(
\r
23120 function (axis) {
\r
23121 return axis.scale.type === scaleType;
\r
23128 * @param {module:echarts/coord/Cartesian.Axis}
\r
23130 addAxis: function (axis) {
\r
23131 var dim = axis.dim;
\r
23133 this._axes[dim] = axis;
\r
23135 this._dimList.push(dim);
\r
23139 * Convert data to coord in nd space
\r
23140 * @param {Array.<number>|Object.<string, number>} val
\r
23141 * @return {Array.<number>|Object.<string, number>}
\r
23143 dataToCoord: function (val) {
\r
23144 return this._dataCoordConvert(val, 'dataToCoord');
\r
23148 * Convert coord in nd space to data
\r
23149 * @param {Array.<number>|Object.<string, number>} val
\r
23150 * @return {Array.<number>|Object.<string, number>}
\r
23152 coordToData: function (val) {
\r
23153 return this._dataCoordConvert(val, 'coordToData');
\r
23156 _dataCoordConvert: function (input, method) {
\r
23157 var dimList = this._dimList;
\r
23159 var output = input instanceof Array ? [] : {};
\r
23161 for (var i = 0; i < dimList.length; i++) {
\r
23162 var dim = dimList[i];
\r
23163 var axis = this._axes[dim];
\r
23165 output[dim] = axis[method](input[dim]);
\r
23172 module.exports = Cartesian;
\r
23177 /***/ function(module, exports, __webpack_require__) {
\r
23181 var zrUtil = __webpack_require__(3);
\r
23182 var Axis = __webpack_require__(117);
\r
23183 var axisLabelInterval = __webpack_require__(118);
\r
23187 * @constructor module:echarts/coord/cartesian/Axis2D
\r
23188 * @extends {module:echarts/coord/cartesian/Axis}
\r
23189 * @param {string} dim
\r
23190 * @param {*} scale
\r
23191 * @param {Array.<number>} coordExtent
\r
23192 * @param {string} axisType
\r
23193 * @param {string} position
\r
23195 var Axis2D = function (dim, scale, coordExtent, axisType, position) {
\r
23196 Axis.call(this, dim, scale, coordExtent);
\r
23205 this.type = axisType || 'value';
\r
23214 this.position = position || 'bottom';
\r
23217 Axis2D.prototype = {
\r
23219 constructor: Axis2D,
\r
23222 * Index of axis, can be used as key
\r
23226 * If axis is on the zero position of the other axis
\r
23227 * @type {boolean}
\r
23233 * @param {module:echarts/coord/cartesian/AxisModel}
\r
23237 isHorizontal: function () {
\r
23238 var position = this.position;
\r
23239 return position === 'top' || position === 'bottom';
\r
23242 getGlobalExtent: function () {
\r
23243 var ret = this.getExtent();
\r
23244 ret[0] = this.toGlobalCoord(ret[0]);
\r
23245 ret[1] = this.toGlobalCoord(ret[1]);
\r
23250 * @return {number}
\r
23252 getLabelInterval: function () {
\r
23253 var labelInterval = this._labelInterval;
\r
23254 if (!labelInterval) {
\r
23255 labelInterval = this._labelInterval = axisLabelInterval(this);
\r
23257 return labelInterval;
\r
23261 * If label is ignored.
\r
23262 * Automatically used when axis is category and label can not be all shown
\r
23263 * @param {number} idx
\r
23264 * @return {boolean}
\r
23266 isLabelIgnored: function (idx) {
\r
23267 if (this.type === 'category') {
\r
23268 var labelInterval = this.getLabelInterval();
\r
23269 return ((typeof labelInterval === 'function')
\r
23270 && !labelInterval(idx, this.scale.getLabel(idx)))
\r
23271 || idx % (labelInterval + 1);
\r
23276 * Transform global coord to local coord,
\r
23277 * i.e. var localCoord = axis.toLocalCoord(80);
\r
23278 * designate by module:echarts/coord/cartesian/Grid.
\r
23279 * @type {Function}
\r
23281 toLocalCoord: null,
\r
23284 * Transform global coord to local coord,
\r
23285 * i.e. var globalCoord = axis.toLocalCoord(40);
\r
23286 * designate by module:echarts/coord/cartesian/Grid.
\r
23287 * @type {Function}
\r
23289 toGlobalCoord: null
\r
23292 zrUtil.inherits(Axis2D, Axis);
\r
23294 module.exports = Axis2D;
\r
23299 /***/ function(module, exports, __webpack_require__) {
\r
23303 var numberUtil = __webpack_require__(7);
\r
23304 var linearMap = numberUtil.linearMap;
\r
23305 var zrUtil = __webpack_require__(3);
\r
23307 function fixExtentWithBands(extent, nTick) {
\r
23308 var size = extent[1] - extent[0];
\r
23310 var margin = size / len / 2;
\r
23311 extent[0] += margin;
\r
23312 extent[1] -= margin;
\r
23315 var normalizedExtent = [0, 1];
\r
23317 * @name module:echarts/coord/CartesianAxis
\r
23320 var Axis = function (dim, scale, extent) {
\r
23323 * Axis dimension. Such as 'x', 'y', 'z', 'angle', 'radius'
\r
23330 * @type {module:echarts/coord/scale/*}
\r
23332 this.scale = scale;
\r
23335 * @type {Array.<number>}
\r
23338 this._extent = extent || [0, 0];
\r
23341 * @type {boolean}
\r
23343 this.inverse = false;
\r
23346 * Usually true when axis has a ordinal scale
\r
23347 * @type {boolean}
\r
23349 this.onBand = false;
\r
23352 Axis.prototype = {
\r
23354 constructor: Axis,
\r
23357 * If axis extent contain given coord
\r
23358 * @param {number} coord
\r
23359 * @return {boolean}
\r
23361 contain: function (coord) {
\r
23362 var extent = this._extent;
\r
23363 var min = Math.min(extent[0], extent[1]);
\r
23364 var max = Math.max(extent[0], extent[1]);
\r
23365 return coord >= min && coord <= max;
\r
23369 * If axis extent contain given data
\r
23370 * @param {number} data
\r
23371 * @return {boolean}
\r
23373 containData: function (data) {
\r
23374 return this.contain(this.dataToCoord(data));
\r
23378 * Get coord extent.
\r
23379 * @return {Array.<number>}
\r
23381 getExtent: function () {
\r
23382 var ret = this._extent.slice();
\r
23387 * Get precision used for formatting
\r
23388 * @param {Array.<number>} [dataExtent]
\r
23389 * @return {number}
\r
23391 getPixelPrecision: function (dataExtent) {
\r
23392 return numberUtil.getPixelPrecision(
\r
23393 dataExtent || this.scale.getExtent(),
\r
23399 * Set coord extent
\r
23400 * @param {number} start
\r
23401 * @param {number} end
\r
23403 setExtent: function (start, end) {
\r
23404 var extent = this._extent;
\r
23405 extent[0] = start;
\r
23410 * Convert data to coord. Data is the rank if it has a ordinal scale
\r
23411 * @param {number} data
\r
23412 * @param {boolean} clamp
\r
23413 * @return {number}
\r
23415 dataToCoord: function (data, clamp) {
\r
23416 var extent = this._extent;
\r
23417 var scale = this.scale;
\r
23418 data = scale.normalize(data);
\r
23420 if (this.onBand && scale.type === 'ordinal') {
\r
23421 extent = extent.slice();
\r
23422 fixExtentWithBands(extent, scale.count());
\r
23425 return linearMap(data, normalizedExtent, extent, clamp);
\r
23429 * Convert coord to data. Data is the rank if it has a ordinal scale
\r
23430 * @param {number} coord
\r
23431 * @param {boolean} clamp
\r
23432 * @return {number}
\r
23434 coordToData: function (coord, clamp) {
\r
23435 var extent = this._extent;
\r
23436 var scale = this.scale;
\r
23438 if (this.onBand && scale.type === 'ordinal') {
\r
23439 extent = extent.slice();
\r
23440 fixExtentWithBands(extent, scale.count());
\r
23443 var t = linearMap(coord, extent, normalizedExtent, clamp);
\r
23445 return this.scale.scale(t);
\r
23448 * @return {Array.<number>}
\r
23450 getTicksCoords: function () {
\r
23451 if (this.onBand) {
\r
23452 var bands = this.getBands();
\r
23454 for (var i = 0; i < bands.length; i++) {
\r
23455 coords.push(bands[i][0]);
\r
23457 if (bands[i - 1]) {
\r
23458 coords.push(bands[i - 1][1]);
\r
23463 return zrUtil.map(this.scale.getTicks(), this.dataToCoord, this);
\r
23468 * Coords of labels are on the ticks or on the middle of bands
\r
23469 * @return {Array.<number>}
\r
23471 getLabelsCoords: function () {
\r
23472 if (this.onBand) {
\r
23473 var bands = this.getBands();
\r
23476 for (var i = 0; i < bands.length; i++) {
\r
23478 coords.push((band[0] + band[1]) / 2);
\r
23483 return zrUtil.map(this.scale.getTicks(), this.dataToCoord, this);
\r
23490 * If axis has labels [1, 2, 3, 4]. Bands on the axis are
\r
23491 * |---1---|---2---|---3---|---4---|.
\r
23493 * @return {Array}
\r
23495 // FIXME Situation when labels is on ticks
\r
23496 getBands: function () {
\r
23497 var extent = this.getExtent();
\r
23499 var len = this.scale.count();
\r
23500 var start = extent[0];
\r
23501 var end = extent[1];
\r
23502 var span = end - start;
\r
23504 for (var i = 0; i < len; i++) {
\r
23506 span * i / len + start,
\r
23507 span * (i + 1) / len + start
\r
23514 * Get width of band
\r
23515 * @return {number}
\r
23517 getBandWidth: function () {
\r
23518 var axisExtent = this._extent;
\r
23519 var dataExtent = this.scale.getExtent();
\r
23521 var len = dataExtent[1] - dataExtent[0] + (this.onBand ? 1 : 0);
\r
23522 // Fix #2728, avoid NaN when only one data.
\r
23523 len === 0 && (len = 1);
\r
23525 var size = Math.abs(axisExtent[1] - axisExtent[0]);
\r
23527 return Math.abs(size) / len;
\r
23531 module.exports = Axis;
\r
23536 /***/ function(module, exports, __webpack_require__) {
\r
23540 * Helper function for axisLabelInterval calculation
\r
23545 var zrUtil = __webpack_require__(3);
\r
23546 var axisHelper = __webpack_require__(108);
\r
23548 module.exports = function (axis) {
\r
23549 var axisModel = axis.model;
\r
23550 var labelModel = axisModel.getModel('axisLabel');
\r
23551 var labelInterval = labelModel.get('interval');
\r
23552 if (!(axis.type === 'category' && labelInterval === 'auto')) {
\r
23553 return labelInterval === 'auto' ? 0 : labelInterval;
\r
23556 return axisHelper.getAxisLabelInterval(
\r
23557 zrUtil.map(axis.scale.getTicks(), axis.dataToCoord, axis),
\r
23558 axisModel.getFormattedLabels(),
\r
23559 labelModel.getModel('textStyle').getFont(),
\r
23560 axis.isHorizontal()
\r
23567 /***/ function(module, exports, __webpack_require__) {
\r
23570 // Grid 是在有直角坐标系的时候必须要存在的
\r
23571 // 所以这里也要被 Cartesian2D 依赖
\r
23574 __webpack_require__(120);
\r
23575 var ComponentModel = __webpack_require__(19);
\r
23577 module.exports = ComponentModel.extend({
\r
23581 dependencies: ['xAxis', 'yAxis'],
\r
23583 layoutMode: 'box',
\r
23586 * @type {module:echarts/coord/cartesian/Grid}
\r
23588 coordinateSystem: null,
\r
23598 // If grid size contain label
\r
23599 containLabel: false,
\r
23600 // width: {totalWidth} - left - right,
\r
23601 // height: {totalHeight} - top - bottom,
\r
23602 backgroundColor: 'rgba(0,0,0,0)',
\r
23604 borderColor: '#ccc'
\r
23611 /***/ function(module, exports, __webpack_require__) {
\r
23616 var ComponentModel = __webpack_require__(19);
\r
23617 var zrUtil = __webpack_require__(3);
\r
23618 var axisModelCreator = __webpack_require__(121);
\r
23620 var AxisModel = ComponentModel.extend({
\r
23622 type: 'cartesian2dAxis',
\r
23625 * @type {module:echarts/coord/cartesian/Axis2D}
\r
23632 init: function () {
\r
23633 AxisModel.superApply(this, 'init', arguments);
\r
23634 this._resetRange();
\r
23640 mergeOption: function () {
\r
23641 AxisModel.superApply(this, 'mergeOption', arguments);
\r
23642 this._resetRange();
\r
23648 restoreData: function () {
\r
23649 AxisModel.superApply(this, 'restoreData', arguments);
\r
23650 this._resetRange();
\r
23655 * @param {number} rangeStart
\r
23656 * @param {number} rangeEnd
\r
23658 setRange: function (rangeStart, rangeEnd) {
\r
23659 this.option.rangeStart = rangeStart;
\r
23660 this.option.rangeEnd = rangeEnd;
\r
23665 * @return {Array.<number|string|Date>}
\r
23667 getMin: function () {
\r
23668 var option = this.option;
\r
23669 return option.rangeStart != null ? option.rangeStart : option.min;
\r
23674 * @return {Array.<number|string|Date>}
\r
23676 getMax: function () {
\r
23677 var option = this.option;
\r
23678 return option.rangeEnd != null ? option.rangeEnd : option.max;
\r
23683 * @return {boolean}
\r
23685 getNeedCrossZero: function () {
\r
23686 var option = this.option;
\r
23687 return (option.rangeStart != null || option.rangeEnd != null)
\r
23688 ? false : !option.scale;
\r
23694 _resetRange: function () {
\r
23695 // rangeStart and rangeEnd is readonly.
\r
23696 this.option.rangeStart = this.option.rangeEnd = null;
\r
23701 function getAxisType(axisDim, option) {
\r
23702 // Default axis with data is category axis
\r
23703 return option.type || (option.data ? 'category' : 'value');
\r
23706 zrUtil.merge(AxisModel.prototype, __webpack_require__(123));
\r
23708 var extraOption = {
\r
23712 axisModelCreator('x', AxisModel, getAxisType, extraOption);
\r
23713 axisModelCreator('y', AxisModel, getAxisType, extraOption);
\r
23715 module.exports = AxisModel;
\r
23720 /***/ function(module, exports, __webpack_require__) {
\r
23724 var axisDefault = __webpack_require__(122);
\r
23725 var zrUtil = __webpack_require__(3);
\r
23726 var ComponentModel = __webpack_require__(19);
\r
23727 var layout = __webpack_require__(21);
\r
23729 // FIXME axisType is fixed ?
\r
23730 var AXIS_TYPES = ['value', 'category', 'time', 'log'];
\r
23733 * Generate sub axis model class
\r
23734 * @param {string} axisName 'x' 'y' 'radius' 'angle' 'parallel'
\r
23735 * @param {module:echarts/model/Component} BaseAxisModelClass
\r
23736 * @param {Function} axisTypeDefaulter
\r
23737 * @param {Object} [extraDefaultOption]
\r
23739 module.exports = function (axisName, BaseAxisModelClass, axisTypeDefaulter, extraDefaultOption) {
\r
23741 zrUtil.each(AXIS_TYPES, function (axisType) {
\r
23743 BaseAxisModelClass.extend({
\r
23745 type: axisName + 'Axis.' + axisType,
\r
23747 mergeDefaultAndTheme: function (option, ecModel) {
\r
23748 var layoutMode = this.layoutMode;
\r
23749 var inputPositionParams = layoutMode
\r
23750 ? layout.getLayoutParams(option) : {};
\r
23752 var themeModel = ecModel.getTheme();
\r
23753 zrUtil.merge(option, themeModel.get(axisType + 'Axis'));
\r
23754 zrUtil.merge(option, this.getDefaultOption());
\r
23756 option.type = axisTypeDefaulter(axisName, option);
\r
23758 if (layoutMode) {
\r
23759 layout.mergeLayoutParam(option, inputPositionParams, layoutMode);
\r
23763 defaultOption: zrUtil.mergeAll(
\r
23766 axisDefault[axisType + 'Axis'],
\r
23767 extraDefaultOption
\r
23774 ComponentModel.registerSubTypeDefaulter(
\r
23775 axisName + 'Axis',
\r
23776 zrUtil.curry(axisTypeDefaulter, axisName)
\r
23783 /***/ function(module, exports, __webpack_require__) {
\r
23787 var zrUtil = __webpack_require__(3);
\r
23789 var defaultOption = {
\r
23791 zlevel: 0, // 一级层叠
\r
23797 // 坐标轴名字位置,支持'start' | 'middle' | 'end'
\r
23798 nameLocation: 'end',
\r
23799 // 坐标轴文字样式,默认取全局样式
\r
23800 nameTextStyle: {},
\r
23805 // 默认显示,属性show控制显示与否
\r
23808 // 属性lineStyle控制线条样式
\r
23817 // 属性show控制显示与否,默认显示
\r
23823 // 属性lineStyle控制线条样式
\r
23829 // 坐标轴文本标签,详见axis.axisLabel
\r
23832 // 控制文本标签是否在grid里
\r
23836 // formatter: null,
\r
23837 // 其余属性默认使用全局文本样式,详见TEXTSTYLE
\r
23845 // 默认显示,属性show控制显示与否
\r
23847 // 属性lineStyle(详见lineStyle)控制线条样式
\r
23856 // 默认不显示,属性show控制显示与否
\r
23858 // 属性areaStyle(详见areaStyle)控制区域样式
\r
23860 color: ['rgba(250,250,250,0.3)','rgba(200,200,200,0.3)']
\r
23865 var categoryAxis = zrUtil.merge({
\r
23867 boundaryGap: true,
\r
23872 // 坐标轴文本标签,详见axis.axisLabel
\r
23876 }, defaultOption);
\r
23878 var valueAxis = zrUtil.defaults({
\r
23880 boundaryGap: [0, 0],
\r
23881 // 最小值, 设置成 'dataMin' 则从数据中计算最小值
\r
23883 // 最大值,设置成 'dataMax' 则从数据中计算最大值
\r
23885 // Readonly prop, specifies start value of the range when using data zoom.
\r
23886 // rangeStart: null
\r
23887 // Readonly prop, specifies end value of the range when using data zoom.
\r
23888 // rangeEnd: null
\r
23889 // 脱离0值比例,放大聚焦到最终_min,_max区间
\r
23893 }, defaultOption);
\r
23896 var timeAxis = zrUtil.defaults({
\r
23901 var logAxis = zrUtil.defaults({}, valueAxis);
\r
23902 logAxis.scale = true;
\r
23904 module.exports = {
\r
23905 categoryAxis: categoryAxis,
\r
23906 valueAxis: valueAxis,
\r
23907 timeAxis: timeAxis,
\r
23914 /***/ function(module, exports, __webpack_require__) {
\r
23918 var zrUtil = __webpack_require__(3);
\r
23919 var axisHelper = __webpack_require__(108);
\r
23921 function getName(obj) {
\r
23922 if (zrUtil.isObject(obj) && obj.value != null) {
\r
23923 return obj.value;
\r
23932 function getCategories() {
\r
23933 return this.get('type') === 'category'
\r
23934 && zrUtil.map(this.get('data'), getName);
\r
23939 * @return {Array.<string>}
\r
23941 function getFormattedLabels() {
\r
23942 return axisHelper.getFormattedLabels(
\r
23944 this.get('axisLabel.formatter')
\r
23948 module.exports = {
\r
23950 getFormattedLabels: getFormattedLabels,
\r
23952 getCategories: getCategories
\r
23958 /***/ function(module, exports, __webpack_require__) {
\r
23961 // TODO boundaryGap
\r
23964 __webpack_require__(120);
\r
23966 __webpack_require__(125);
\r
23971 /***/ function(module, exports, __webpack_require__) {
\r
23975 var zrUtil = __webpack_require__(3);
\r
23976 var graphic = __webpack_require__(42);
\r
23977 var AxisBuilder = __webpack_require__(126);
\r
23978 var ifIgnoreOnTick = AxisBuilder.ifIgnoreOnTick;
\r
23979 var getInterval = AxisBuilder.getInterval;
\r
23981 var axisBuilderAttrs = [
\r
23982 'axisLine', 'axisLabel', 'axisTick', 'axisName'
\r
23984 var selfBuilderAttrs = [
\r
23985 'splitLine', 'splitArea'
\r
23988 var AxisView = __webpack_require__(1).extendComponentView({
\r
23992 render: function (axisModel, ecModel) {
\r
23994 this.group.removeAll();
\r
23996 if (!axisModel.get('show')) {
\r
24000 var gridModel = ecModel.getComponent('grid', axisModel.get('gridIndex'));
\r
24002 var layout = layoutAxis(gridModel, axisModel);
\r
24004 var axisBuilder = new AxisBuilder(axisModel, layout);
\r
24006 zrUtil.each(axisBuilderAttrs, axisBuilder.add, axisBuilder);
\r
24008 this.group.add(axisBuilder.getGroup());
\r
24010 zrUtil.each(selfBuilderAttrs, function (name) {
\r
24011 if (axisModel.get(name +'.show')) {
\r
24012 this['_' + name](axisModel, gridModel, layout.labelInterval);
\r
24018 * @param {module:echarts/coord/cartesian/AxisModel} axisModel
\r
24019 * @param {module:echarts/coord/cartesian/GridModel} gridModel
\r
24020 * @param {number|Function} labelInterval
\r
24023 _splitLine: function (axisModel, gridModel, labelInterval) {
\r
24024 var axis = axisModel.axis;
\r
24026 var splitLineModel = axisModel.getModel('splitLine');
\r
24027 var lineStyleModel = splitLineModel.getModel('lineStyle');
\r
24028 var lineWidth = lineStyleModel.get('width');
\r
24029 var lineColors = lineStyleModel.get('color');
\r
24031 var lineInterval = getInterval(splitLineModel, labelInterval);
\r
24033 lineColors = zrUtil.isArray(lineColors) ? lineColors : [lineColors];
\r
24035 var gridRect = gridModel.coordinateSystem.getRect();
\r
24036 var isHorizontal = axis.isHorizontal();
\r
24038 var splitLines = [];
\r
24039 var lineCount = 0;
\r
24041 var ticksCoords = axis.getTicksCoords();
\r
24045 for (var i = 0; i < ticksCoords.length; i++) {
\r
24046 if (ifIgnoreOnTick(axis, i, lineInterval)) {
\r
24050 var tickCoord = axis.toGlobalCoord(ticksCoords[i]);
\r
24052 if (isHorizontal) {
\r
24053 p1[0] = tickCoord;
\r
24054 p1[1] = gridRect.y;
\r
24055 p2[0] = tickCoord;
\r
24056 p2[1] = gridRect.y + gridRect.height;
\r
24059 p1[0] = gridRect.x;
\r
24060 p1[1] = tickCoord;
\r
24061 p2[0] = gridRect.x + gridRect.width;
\r
24062 p2[1] = tickCoord;
\r
24065 var colorIndex = (lineCount++) % lineColors.length;
\r
24066 splitLines[colorIndex] = splitLines[colorIndex] || [];
\r
24067 splitLines[colorIndex].push(new graphic.Line(graphic.subPixelOptimizeLine({
\r
24075 lineWidth: lineWidth
\r
24081 // Simple optimization
\r
24082 // Batching the lines if color are the same
\r
24083 var lineStyle = lineStyleModel.getLineStyle();
\r
24084 for (var i = 0; i < splitLines.length; i++) {
\r
24085 this.group.add(graphic.mergePath(splitLines[i], {
\r
24086 style: zrUtil.defaults({
\r
24087 stroke: lineColors[i % lineColors.length]
\r
24095 * @param {module:echarts/coord/cartesian/AxisModel} axisModel
\r
24096 * @param {module:echarts/coord/cartesian/GridModel} gridModel
\r
24097 * @param {number|Function} labelInterval
\r
24100 _splitArea: function (axisModel, gridModel, labelInterval) {
\r
24101 var axis = axisModel.axis;
\r
24103 var splitAreaModel = axisModel.getModel('splitArea');
\r
24104 var areaStyleModel = splitAreaModel.getModel('areaStyle');
\r
24105 var areaColors = areaStyleModel.get('color');
\r
24107 var gridRect = gridModel.coordinateSystem.getRect();
\r
24108 var ticksCoords = axis.getTicksCoords();
\r
24110 var prevX = axis.toGlobalCoord(ticksCoords[0]);
\r
24111 var prevY = axis.toGlobalCoord(ticksCoords[0]);
\r
24113 var splitAreaRects = [];
\r
24116 var areaInterval = getInterval(splitAreaModel, labelInterval);
\r
24118 areaColors = zrUtil.isArray(areaColors) ? areaColors : [areaColors];
\r
24120 for (var i = 1; i < ticksCoords.length; i++) {
\r
24121 if (ifIgnoreOnTick(axis, i, areaInterval)) {
\r
24125 var tickCoord = axis.toGlobalCoord(ticksCoords[i]);
\r
24131 if (axis.isHorizontal()) {
\r
24134 width = tickCoord - x;
\r
24135 height = gridRect.height;
\r
24140 width = gridRect.width;
\r
24141 height = tickCoord - y;
\r
24144 var colorIndex = (count++) % areaColors.length;
\r
24145 splitAreaRects[colorIndex] = splitAreaRects[colorIndex] || [];
\r
24146 splitAreaRects[colorIndex].push(new graphic.Rect({
\r
24156 prevX = x + width;
\r
24157 prevY = y + height;
\r
24160 // Simple optimization
\r
24161 // Batching the rects if color are the same
\r
24162 var areaStyle = areaStyleModel.getAreaStyle();
\r
24163 for (var i = 0; i < splitAreaRects.length; i++) {
\r
24164 this.group.add(graphic.mergePath(splitAreaRects[i], {
\r
24165 style: zrUtil.defaults({
\r
24166 fill: areaColors[i % areaColors.length]
\r
24174 AxisView.extend({
\r
24177 AxisView.extend({
\r
24184 function layoutAxis(gridModel, axisModel) {
\r
24185 var grid = gridModel.coordinateSystem;
\r
24186 var axis = axisModel.axis;
\r
24189 var rawAxisPosition = axis.position;
\r
24190 var axisPosition = axis.onZero ? 'onZero' : rawAxisPosition;
\r
24191 var axisDim = axis.dim;
\r
24193 // [left, right, top, bottom]
\r
24194 var rect = grid.getRect();
\r
24195 var rectBound = [rect.x, rect.x + rect.width, rect.y, rect.y + rect.height];
\r
24198 x: {top: rectBound[2], bottom: rectBound[3]},
\r
24199 y: {left: rectBound[0], right: rectBound[1]}
\r
24201 posMap.x.onZero = Math.max(Math.min(getZero('y'), posMap.x.bottom), posMap.x.top);
\r
24202 posMap.y.onZero = Math.max(Math.min(getZero('x'), posMap.y.right), posMap.y.left);
\r
24204 function getZero(dim, val) {
\r
24205 var theAxis = grid.getAxis(dim);
\r
24206 return theAxis.toGlobalCoord(theAxis.dataToCoord(0));
\r
24210 layout.position = [
\r
24211 axisDim === 'y' ? posMap.y[axisPosition] : rectBound[0],
\r
24212 axisDim === 'x' ? posMap.x[axisPosition] : rectBound[3]
\r
24216 var r = {x: 0, y: 1};
\r
24217 layout.rotation = Math.PI / 2 * r[axisDim];
\r
24219 // Tick and label direction, x y is axisDim
\r
24220 var dirMap = {top: -1, bottom: 1, left: -1, right: 1};
\r
24222 layout.labelDirection = layout.tickDirection = layout.nameDirection = dirMap[rawAxisPosition];
\r
24223 if (axis.onZero) {
\r
24224 layout.labelOffset = posMap[axisDim][rawAxisPosition] - posMap[axisDim].onZero;
\r
24227 if (axisModel.getModel('axisTick').get('inside')) {
\r
24228 layout.tickDirection = -layout.tickDirection;
\r
24230 if (axisModel.getModel('axisLabel').get('inside')) {
\r
24231 layout.labelDirection = -layout.labelDirection;
\r
24234 // Special label rotation
\r
24235 var labelRotation = axisModel.getModel('axisLabel').get('rotate');
\r
24236 layout.labelRotation = axisPosition === 'top' ? -labelRotation : labelRotation;
\r
24238 // label interval when auto mode.
\r
24239 layout.labelInterval = axis.getLabelInterval();
\r
24241 // Over splitLine and splitArea
\r
24250 /***/ function(module, exports, __webpack_require__) {
\r
24254 var zrUtil = __webpack_require__(3);
\r
24255 var graphic = __webpack_require__(42);
\r
24256 var Model = __webpack_require__(8);
\r
24257 var numberUtil = __webpack_require__(7);
\r
24258 var remRadian = numberUtil.remRadian;
\r
24259 var isRadianAroundZero = numberUtil.isRadianAroundZero;
\r
24261 var PI = Math.PI;
\r
24264 * A final axis is translated and rotated from a "standard axis".
\r
24265 * So opt.position and opt.rotation is required.
\r
24267 * A standard axis is and axis from [0, 0] to [0, axisExtent[1]],
\r
24268 * for example: (0, 0) ------------> (0, 50)
\r
24270 * nameDirection or tickDirection or labelDirection is 1 means tick
\r
24271 * or label is below the standard axis, whereas is -1 means above
\r
24272 * the standard axis. labelOffset means offset between label and axis,
\r
24273 * which is useful when 'onZero', where axisLabel is in the grid and
\r
24274 * label in outside grid.
\r
24276 * Tips: like always,
\r
24277 * positive rotation represents anticlockwise, and negative rotation
\r
24278 * represents clockwise.
\r
24279 * The direction of position coordinate is the same as the direction
\r
24280 * of screen coordinate.
\r
24282 * Do not need to consider axis 'inverse', which is auto processed by
\r
24285 * @param {module:zrender/container/Group} group
\r
24286 * @param {Object} axisModel
\r
24287 * @param {Object} opt Standard axis parameters.
\r
24288 * @param {Array.<number>} opt.position [x, y]
\r
24289 * @param {number} opt.rotation by radian
\r
24290 * @param {number} [opt.nameDirection=1] 1 or -1 Used when nameLocation is 'middle'.
\r
24291 * @param {number} [opt.tickDirection=1] 1 or -1
\r
24292 * @param {number} [opt.labelDirection=1] 1 or -1
\r
24293 * @param {number} [opt.labelOffset=0] Usefull when onZero.
\r
24294 * @param {string} [opt.axisName] default get from axisModel.
\r
24295 * @param {number} [opt.labelRotation] by degree, default get from axisModel.
\r
24296 * @param {number} [opt.labelInterval] Default label interval when label
\r
24297 * interval from model is null or 'auto'.
\r
24298 * @param {number} [opt.strokeContainThreshold] Default label interval when label
\r
24299 * @param {number} [opt.silent=true]
\r
24301 var AxisBuilder = function (axisModel, opt) {
\r
24311 this.axisModel = axisModel;
\r
24318 nameDirection: 1,
\r
24319 tickDirection: 1,
\r
24320 labelDirection: 1,
\r
24328 this.group = new graphic.Group({
\r
24329 position: opt.position.slice(),
\r
24330 rotation: opt.rotation
\r
24334 AxisBuilder.prototype = {
\r
24336 constructor: AxisBuilder,
\r
24338 hasBuilder: function (name) {
\r
24339 return !!builders[name];
\r
24342 add: function (name) {
\r
24343 builders[name].call(this);
\r
24346 getGroup: function () {
\r
24347 return this.group;
\r
24357 axisLine: function () {
\r
24358 var opt = this.opt;
\r
24359 var axisModel = this.axisModel;
\r
24361 if (!axisModel.get('axisLine.show')) {
\r
24365 var extent = this.axisModel.axis.getExtent();
\r
24367 this.group.add(new graphic.Line({
\r
24374 style: zrUtil.extend(
\r
24375 {lineCap: 'round'},
\r
24376 axisModel.getModel('axisLine.lineStyle').getLineStyle()
\r
24378 strokeContainThreshold: opt.strokeContainThreshold,
\r
24379 silent: !!opt.silent,
\r
24387 axisTick: function () {
\r
24388 var axisModel = this.axisModel;
\r
24390 if (!axisModel.get('axisTick.show')) {
\r
24394 var axis = axisModel.axis;
\r
24395 var tickModel = axisModel.getModel('axisTick');
\r
24396 var opt = this.opt;
\r
24398 var lineStyleModel = tickModel.getModel('lineStyle');
\r
24399 var tickLen = tickModel.get('length');
\r
24400 var tickInterval = getInterval(tickModel, opt.labelInterval);
\r
24401 var ticksCoords = axis.getTicksCoords();
\r
24402 var tickLines = [];
\r
24404 for (var i = 0; i < ticksCoords.length; i++) {
\r
24405 // Only ordinal scale support tick interval
\r
24406 if (ifIgnoreOnTick(axis, i, tickInterval)) {
\r
24410 var tickCoord = ticksCoords[i];
\r
24413 tickLines.push(new graphic.Line(graphic.subPixelOptimizeLine({
\r
24418 y2: opt.tickDirection * tickLen
\r
24421 lineWidth: lineStyleModel.get('width')
\r
24427 this.group.add(graphic.mergePath(tickLines, {
\r
24428 style: lineStyleModel.getLineStyle(),
\r
24435 * @param {module:echarts/coord/cartesian/AxisModel} axisModel
\r
24436 * @param {module:echarts/coord/cartesian/GridModel} gridModel
\r
24439 axisLabel: function () {
\r
24440 var axisModel = this.axisModel;
\r
24442 if (!axisModel.get('axisLabel.show')) {
\r
24446 var opt = this.opt;
\r
24447 var axis = axisModel.axis;
\r
24448 var labelModel = axisModel.getModel('axisLabel');
\r
24449 var textStyleModel = labelModel.getModel('textStyle');
\r
24450 var labelMargin = labelModel.get('margin');
\r
24451 var ticks = axis.scale.getTicks();
\r
24452 var labels = axisModel.getFormattedLabels();
\r
24454 // Special label rotate.
\r
24455 var labelRotation = opt.labelRotation;
\r
24456 if (labelRotation == null) {
\r
24457 labelRotation = labelModel.get('rotate') || 0;
\r
24460 labelRotation = labelRotation * PI / 180;
\r
24462 var labelLayout = innerTextLayout(opt, labelRotation, opt.labelDirection);
\r
24463 var categoryData = axisModel.get('data');
\r
24465 var textEls = [];
\r
24466 for (var i = 0; i < ticks.length; i++) {
\r
24467 if (ifIgnoreOnTick(axis, i, opt.labelInterval)) {
\r
24471 var itemTextStyleModel = textStyleModel;
\r
24472 if (categoryData && categoryData[i] && categoryData[i].textStyle) {
\r
24473 itemTextStyleModel = new Model(
\r
24474 categoryData[i].textStyle, textStyleModel, axisModel.ecModel
\r
24478 var tickCoord = axis.dataToCoord(ticks[i]);
\r
24481 opt.labelOffset + opt.labelDirection * labelMargin
\r
24484 var textEl = new graphic.Text({
\r
24487 textAlign: itemTextStyleModel.get('align', true) || labelLayout.textAlign,
\r
24488 textVerticalAlign: itemTextStyleModel.get('baseline', true) || labelLayout.verticalAlign,
\r
24489 textFont: itemTextStyleModel.getFont(),
\r
24490 fill: itemTextStyleModel.getTextColor()
\r
24493 rotation: labelLayout.rotation,
\r
24497 textEls.push(textEl);
\r
24498 this.group.add(textEl);
\r
24501 function isTwoLabelOverlapped(current, next) {
\r
24502 var firstRect = current && current.getBoundingRect().clone();
\r
24503 var nextRect = next && next.getBoundingRect().clone();
\r
24504 if (firstRect && nextRect) {
\r
24505 firstRect.applyTransform(current.getLocalTransform());
\r
24506 nextRect.applyTransform(next.getLocalTransform());
\r
24507 return firstRect.intersect(nextRect);
\r
24510 if (axis.type !== 'category') {
\r
24511 // If min or max are user set, we need to check
\r
24512 // If the tick on min(max) are overlap on their neighbour tick
\r
24513 // If they are overlapped, we need to hide the min(max) tick label
\r
24514 if (axisModel.getMin ? axisModel.getMin() : axisModel.get('min')) {
\r
24515 var firstLabel = textEls[0];
\r
24516 var nextLabel = textEls[1];
\r
24517 if (isTwoLabelOverlapped(firstLabel, nextLabel)) {
\r
24518 firstLabel.ignore = true;
\r
24521 if (axisModel.getMax ? axisModel.getMax() : axisModel.get('max')) {
\r
24522 var lastLabel = textEls[textEls.length - 1];
\r
24523 var prevLabel = textEls[textEls.length - 2];
\r
24524 if (isTwoLabelOverlapped(prevLabel, lastLabel)) {
\r
24525 lastLabel.ignore = true;
\r
24534 axisName: function () {
\r
24535 var opt = this.opt;
\r
24536 var axisModel = this.axisModel;
\r
24538 var name = this.opt.axisName;
\r
24539 // If name is '', do not get name from axisMode.
\r
24540 if (name == null) {
\r
24541 name = axisModel.get('name');
\r
24548 var nameLocation = axisModel.get('nameLocation');
\r
24549 var nameDirection = opt.nameDirection;
\r
24550 var textStyleModel = axisModel.getModel('nameTextStyle');
\r
24551 var gap = axisModel.get('nameGap') || 0;
\r
24553 var extent = this.axisModel.axis.getExtent();
\r
24554 var gapSignal = extent[0] > extent[1] ? -1 : 1;
\r
24556 nameLocation === 'start'
\r
24557 ? extent[0] - gapSignal * gap
\r
24558 : nameLocation === 'end'
\r
24559 ? extent[1] + gapSignal * gap
\r
24560 : (extent[0] + extent[1]) / 2, // 'middle'
\r
24561 // Reuse labelOffset.
\r
24562 nameLocation === 'middle' ? opt.labelOffset + nameDirection * gap : 0
\r
24567 if (nameLocation === 'middle') {
\r
24568 labelLayout = innerTextLayout(opt, opt.rotation, nameDirection);
\r
24571 labelLayout = endTextLayout(opt, nameLocation, extent);
\r
24574 this.group.add(new graphic.Text({
\r
24577 textFont: textStyleModel.getFont(),
\r
24578 fill: textStyleModel.getTextColor()
\r
24579 || axisModel.get('axisLine.lineStyle.color'),
\r
24580 textAlign: labelLayout.textAlign,
\r
24581 textVerticalAlign: labelLayout.verticalAlign
\r
24584 rotation: labelLayout.rotation,
\r
24595 function innerTextLayout(opt, textRotation, direction) {
\r
24596 var rotationDiff = remRadian(textRotation - opt.rotation);
\r
24598 var verticalAlign;
\r
24600 if (isRadianAroundZero(rotationDiff)) { // Label is parallel with axis line.
\r
24601 verticalAlign = direction > 0 ? 'top' : 'bottom';
\r
24602 textAlign = 'center';
\r
24604 else if (isRadianAroundZero(rotationDiff - PI)) { // Label is inverse parallel with axis line.
\r
24605 verticalAlign = direction > 0 ? 'bottom' : 'top';
\r
24606 textAlign = 'center';
\r
24609 verticalAlign = 'middle';
\r
24611 if (rotationDiff > 0 && rotationDiff < PI) {
\r
24612 textAlign = direction > 0 ? 'right' : 'left';
\r
24615 textAlign = direction > 0 ? 'left' : 'right';
\r
24620 rotation: rotationDiff,
\r
24621 textAlign: textAlign,
\r
24622 verticalAlign: verticalAlign
\r
24629 function endTextLayout(opt, textPosition, extent) {
\r
24630 var rotationDiff = remRadian(-opt.rotation);
\r
24632 var verticalAlign;
\r
24633 var inverse = extent[0] > extent[1];
\r
24634 var onLeft = (textPosition === 'start' && !inverse)
\r
24635 || (textPosition !== 'start' && inverse);
\r
24637 if (isRadianAroundZero(rotationDiff - PI / 2)) {
\r
24638 verticalAlign = onLeft ? 'bottom' : 'top';
\r
24639 textAlign = 'center';
\r
24641 else if (isRadianAroundZero(rotationDiff - PI * 1.5)) {
\r
24642 verticalAlign = onLeft ? 'top' : 'bottom';
\r
24643 textAlign = 'center';
\r
24646 verticalAlign = 'middle';
\r
24647 if (rotationDiff < PI * 1.5 && rotationDiff > PI / 2) {
\r
24648 textAlign = onLeft ? 'left' : 'right';
\r
24651 textAlign = onLeft ? 'right' : 'left';
\r
24656 rotation: rotationDiff,
\r
24657 textAlign: textAlign,
\r
24658 verticalAlign: verticalAlign
\r
24665 var ifIgnoreOnTick = AxisBuilder.ifIgnoreOnTick = function (axis, i, interval) {
\r
24667 var scale = axis.scale;
\r
24668 return scale.type === 'ordinal'
\r
24670 typeof interval === 'function'
\r
24672 rawTick = scale.getTicks()[i],
\r
24673 !interval(rawTick, scale.getLabel(rawTick))
\r
24675 : i % (interval + 1)
\r
24682 var getInterval = AxisBuilder.getInterval = function (model, labelInterval) {
\r
24683 var interval = model.get('interval');
\r
24684 if (interval == null || interval == 'auto') {
\r
24685 interval = labelInterval;
\r
24690 module.exports = AxisBuilder;
\r
24696 /***/ function(module, exports, __webpack_require__) {
\r
24700 var zrUtil = __webpack_require__(3);
\r
24702 __webpack_require__(107);
\r
24704 __webpack_require__(128);
\r
24705 __webpack_require__(129);
\r
24707 var barLayoutGrid = __webpack_require__(131);
\r
24708 var echarts = __webpack_require__(1);
\r
24710 echarts.registerLayout(zrUtil.curry(barLayoutGrid, 'bar'));
\r
24711 // Visual coding for legend
\r
24712 echarts.registerVisualCoding('chart', function (ecModel) {
\r
24713 ecModel.eachSeriesByType('bar', function (seriesModel) {
\r
24714 var data = seriesModel.getData();
\r
24715 data.setVisual('legendSymbol', 'roundRect');
\r
24719 // In case developer forget to include grid component
\r
24720 __webpack_require__(106);
\r
24725 /***/ function(module, exports, __webpack_require__) {
\r
24730 var SeriesModel = __webpack_require__(27);
\r
24731 var createListFromArray = __webpack_require__(93);
\r
24733 module.exports = SeriesModel.extend({
\r
24735 type: 'series.bar',
\r
24737 dependencies: ['grid', 'polar'],
\r
24739 getInitialData: function (option, ecModel) {
\r
24740 return createListFromArray(option.data, this, ecModel);
\r
24743 getMarkerPosition: function (value) {
\r
24744 var coordSys = this.coordinateSystem;
\r
24746 var pt = coordSys.dataToPoint(value);
\r
24747 var data = this.getData();
\r
24748 var offset = data.getLayout('offset');
\r
24749 var size = data.getLayout('size');
\r
24750 var offsetIndex = coordSys.getBaseAxis().isHorizontal() ? 0 : 1;
\r
24751 pt[offsetIndex] += offset + size / 2;
\r
24754 return [NaN, NaN];
\r
24758 zlevel: 0, // 一级层叠
\r
24760 coordinateSystem: 'cartesian2d',
\r
24761 legendHoverLink: true,
\r
24764 // Cartesian coordinate system
\r
24771 // barMaxWidth: null,
\r
24773 // barWidth: null,
\r
24774 // 柱间距离,默认为柱形宽度的30%,可设固定值
\r
24775 // barGap: '30%',
\r
24776 // 类目间柱形距离,默认为类目间距的20%,可设固定值
\r
24777 // barCategoryGap: '20%',
\r
24781 // formatter: 标签文本格式器,同Tooltip.formatter,不支持异步回调
\r
24783 // // 默认自适应,水平布局为'top',垂直布局为'right',可选为
\r
24784 // // 'inside' | 'insideleft' | 'insideTop' | 'insideRight' | 'insideBottom' |
\r
24785 // // 'outside' |'left' | 'right'|'top'|'bottom'
\r
24788 // textStyle: null // 默认使用全局文本样式,详见TEXTSTYLE
\r
24795 barBorderColor: '#fff',
\r
24796 // 柱条边线线宽,单位px,默认为1
\r
24797 barBorderWidth: 0
\r
24802 barBorderColor: '#fff',
\r
24803 // 柱条边线线宽,单位px,默认为1
\r
24804 barBorderWidth: 0
\r
24813 /***/ function(module, exports, __webpack_require__) {
\r
24818 var zrUtil = __webpack_require__(3);
\r
24819 var graphic = __webpack_require__(42);
\r
24821 zrUtil.extend(__webpack_require__(8).prototype, __webpack_require__(130));
\r
24823 function fixLayoutWithLineWidth(layout, lineWidth) {
\r
24824 var signX = layout.width > 0 ? 1 : -1;
\r
24825 var signY = layout.height > 0 ? 1 : -1;
\r
24826 // In case width or height are too small.
\r
24827 lineWidth = Math.min(lineWidth, Math.abs(layout.width), Math.abs(layout.height));
\r
24828 layout.x += signX * lineWidth / 2;
\r
24829 layout.y += signY * lineWidth / 2;
\r
24830 layout.width -= signX * lineWidth;
\r
24831 layout.height -= signY * lineWidth;
\r
24834 module.exports = __webpack_require__(1).extendChartView({
\r
24838 render: function (seriesModel, ecModel, api) {
\r
24839 var coordinateSystemType = seriesModel.get('coordinateSystem');
\r
24841 if (coordinateSystemType === 'cartesian2d') {
\r
24842 this._renderOnCartesian(seriesModel, ecModel, api);
\r
24845 return this.group;
\r
24848 _renderOnCartesian: function (seriesModel, ecModel, api) {
\r
24849 var group = this.group;
\r
24850 var data = seriesModel.getData();
\r
24851 var oldData = this._data;
\r
24853 var cartesian = seriesModel.coordinateSystem;
\r
24854 var baseAxis = cartesian.getBaseAxis();
\r
24855 var isHorizontal = baseAxis.isHorizontal();
\r
24857 var enableAnimation = seriesModel.get('animation');
\r
24859 var barBorderWidthQuery = ['itemStyle', 'normal', 'barBorderWidth'];
\r
24861 function createRect(dataIndex, isUpdate) {
\r
24862 var layout = data.getItemLayout(dataIndex);
\r
24863 var lineWidth = data.getItemModel(dataIndex).get(barBorderWidthQuery) || 0;
\r
24864 fixLayoutWithLineWidth(layout, lineWidth);
\r
24866 var rect = new graphic.Rect({
\r
24867 shape: zrUtil.extend({}, layout)
\r
24870 if (enableAnimation) {
\r
24871 var rectShape = rect.shape;
\r
24872 var animateProperty = isHorizontal ? 'height' : 'width';
\r
24873 var animateTarget = {};
\r
24874 rectShape[animateProperty] = 0;
\r
24875 animateTarget[animateProperty] = layout[animateProperty];
\r
24876 graphic[isUpdate? 'updateProps' : 'initProps'](rect, {
\r
24877 shape: animateTarget
\r
24882 data.diff(oldData)
\r
24883 .add(function (dataIndex) {
\r
24885 if (!data.hasValue(dataIndex)) {
\r
24889 var rect = createRect(dataIndex);
\r
24891 data.setItemGraphicEl(dataIndex, rect);
\r
24896 .update(function (newIndex, oldIndex) {
\r
24897 var rect = oldData.getItemGraphicEl(oldIndex);
\r
24899 if (!data.hasValue(newIndex)) {
\r
24900 group.remove(rect);
\r
24904 rect = createRect(newIndex, true);
\r
24907 var layout = data.getItemLayout(newIndex);
\r
24908 var lineWidth = data.getItemModel(newIndex).get(barBorderWidthQuery) || 0;
\r
24909 fixLayoutWithLineWidth(layout, lineWidth);
\r
24911 graphic.updateProps(rect, {
\r
24915 data.setItemGraphicEl(newIndex, rect);
\r
24920 .remove(function (idx) {
\r
24921 var rect = oldData.getItemGraphicEl(idx);
\r
24923 // Not show text when animating
\r
24924 rect.style.text = '';
\r
24925 graphic.updateProps(rect, {
\r
24929 }, seriesModel, function () {
\r
24930 group.remove(rect);
\r
24936 this._updateStyle(seriesModel, data, isHorizontal);
\r
24938 this._data = data;
\r
24941 _updateStyle: function (seriesModel, data, isHorizontal) {
\r
24942 function setLabel(style, model, color, labelText, labelPositionOutside) {
\r
24943 graphic.setText(style, model, color);
\r
24944 style.text = labelText;
\r
24945 if (style.textPosition === 'outside') {
\r
24946 style.textPosition = labelPositionOutside;
\r
24950 data.eachItemGraphicEl(function (rect, idx) {
\r
24951 var itemModel = data.getItemModel(idx);
\r
24952 var color = data.getItemVisual(idx, 'color');
\r
24953 var layout = data.getItemLayout(idx);
\r
24954 var itemStyleModel = itemModel.getModel('itemStyle.normal');
\r
24956 var hoverStyle = itemModel.getModel('itemStyle.emphasis').getItemStyle();
\r
24958 rect.setShape('r', itemStyleModel.get('barBorderRadius') || 0);
\r
24960 rect.setStyle(zrUtil.defaults(
\r
24964 itemStyleModel.getBarItemStyle()
\r
24967 var labelPositionOutside = isHorizontal
\r
24968 ? (layout.height > 0 ? 'bottom' : 'top')
\r
24969 : (layout.width > 0 ? 'left' : 'right');
\r
24971 var labelModel = itemModel.getModel('label.normal');
\r
24972 var hoverLabelModel = itemModel.getModel('label.emphasis');
\r
24973 var rectStyle = rect.style;
\r
24974 if (labelModel.get('show')) {
\r
24976 rectStyle, labelModel, color,
\r
24978 seriesModel.getFormattedLabel(idx, 'normal'),
\r
24979 seriesModel.getRawValue(idx)
\r
24981 labelPositionOutside
\r
24985 rectStyle.text = '';
\r
24987 if (hoverLabelModel.get('show')) {
\r
24989 hoverStyle, hoverLabelModel, color,
\r
24991 seriesModel.getFormattedLabel(idx, 'emphasis'),
\r
24992 seriesModel.getRawValue(idx)
\r
24994 labelPositionOutside
\r
24998 hoverStyle.text = '';
\r
25000 graphic.setHoverStyle(rect, hoverStyle);
\r
25004 remove: function (ecModel, api) {
\r
25005 var group = this.group;
\r
25006 if (ecModel.get('animation')) {
\r
25007 if (this._data) {
\r
25008 this._data.eachItemGraphicEl(function (el) {
\r
25009 // Not show text when animating
\r
25010 el.style.text = '';
\r
25011 graphic.updateProps(el, {
\r
25015 }, ecModel, function () {
\r
25016 group.remove(el);
\r
25022 group.removeAll();
\r
25030 /***/ function(module, exports, __webpack_require__) {
\r
25033 module.exports = {
\r
25034 getBarItemStyle: __webpack_require__(11)(
\r
25036 ['fill', 'color'],
\r
25037 ['stroke', 'barBorderColor'],
\r
25038 ['lineWidth', 'barBorderWidth'],
\r
25041 ['shadowOffsetX'],
\r
25042 ['shadowOffsetY'],
\r
25051 /***/ function(module, exports, __webpack_require__) {
\r
25056 var zrUtil = __webpack_require__(3);
\r
25057 var numberUtil = __webpack_require__(7);
\r
25058 var parsePercent = numberUtil.parsePercent;
\r
25060 function getSeriesStackId(seriesModel) {
\r
25061 return seriesModel.get('stack') || '__ec_stack_' + seriesModel.seriesIndex;
\r
25064 function calBarWidthAndOffset(barSeries, api) {
\r
25065 // Columns info on each category axis. Key is cartesian name
\r
25066 var columnsMap = {};
\r
25068 zrUtil.each(barSeries, function (seriesModel, idx) {
\r
25069 var cartesian = seriesModel.coordinateSystem;
\r
25071 var baseAxis = cartesian.getBaseAxis();
\r
25073 var columnsOnAxis = columnsMap[baseAxis.index] || {
\r
25074 remainedWidth: baseAxis.getBandWidth(),
\r
25075 autoWidthCount: 0,
\r
25076 categoryGap: '20%',
\r
25081 var stacks = columnsOnAxis.stacks;
\r
25082 columnsMap[baseAxis.index] = columnsOnAxis;
\r
25084 var stackId = getSeriesStackId(seriesModel);
\r
25086 if (!stacks[stackId]) {
\r
25087 columnsOnAxis.autoWidthCount++;
\r
25089 stacks[stackId] = stacks[stackId] || {
\r
25094 var barWidth = seriesModel.get('barWidth');
\r
25095 var barMaxWidth = seriesModel.get('barMaxWidth');
\r
25096 var barGap = seriesModel.get('barGap');
\r
25097 var barCategoryGap = seriesModel.get('barCategoryGap');
\r
25099 if (barWidth && ! stacks[stackId].width) {
\r
25100 barWidth = Math.min(columnsOnAxis.remainedWidth, barWidth);
\r
25101 stacks[stackId].width = barWidth;
\r
25102 columnsOnAxis.remainedWidth -= barWidth;
\r
25105 barMaxWidth && (stacks[stackId].maxWidth = barMaxWidth);
\r
25106 (barGap != null) && (columnsOnAxis.gap = barGap);
\r
25107 (barCategoryGap != null) && (columnsOnAxis.categoryGap = barCategoryGap);
\r
25112 zrUtil.each(columnsMap, function (columnsOnAxis, coordSysName) {
\r
25114 result[coordSysName] = {};
\r
25116 var stacks = columnsOnAxis.stacks;
\r
25117 var baseAxis = columnsOnAxis.axis;
\r
25118 var bandWidth = baseAxis.getBandWidth();
\r
25119 var categoryGap = parsePercent(columnsOnAxis.categoryGap, bandWidth);
\r
25120 var barGapPercent = parsePercent(columnsOnAxis.gap, 1);
\r
25122 var remainedWidth = columnsOnAxis.remainedWidth;
\r
25123 var autoWidthCount = columnsOnAxis.autoWidthCount;
\r
25124 var autoWidth = (remainedWidth - categoryGap)
\r
25125 / (autoWidthCount + (autoWidthCount - 1) * barGapPercent);
\r
25126 autoWidth = Math.max(autoWidth, 0);
\r
25128 // Find if any auto calculated bar exceeded maxBarWidth
\r
25129 zrUtil.each(stacks, function (column, stack) {
\r
25130 var maxWidth = column.maxWidth;
\r
25131 if (!column.width && maxWidth && maxWidth < autoWidth) {
\r
25132 maxWidth = Math.min(maxWidth, remainedWidth);
\r
25133 remainedWidth -= maxWidth;
\r
25134 column.width = maxWidth;
\r
25135 autoWidthCount--;
\r
25139 // Recalculate width again
\r
25140 autoWidth = (remainedWidth - categoryGap)
\r
25141 / (autoWidthCount + (autoWidthCount - 1) * barGapPercent);
\r
25142 autoWidth = Math.max(autoWidth, 0);
\r
25144 var widthSum = 0;
\r
25146 zrUtil.each(stacks, function (column, idx) {
\r
25147 if (!column.width) {
\r
25148 column.width = autoWidth;
\r
25150 lastColumn = column;
\r
25151 widthSum += column.width * (1 + barGapPercent);
\r
25153 if (lastColumn) {
\r
25154 widthSum -= lastColumn.width * barGapPercent;
\r
25157 var offset = -widthSum / 2;
\r
25158 zrUtil.each(stacks, function (column, stackId) {
\r
25159 result[coordSysName][stackId] = result[coordSysName][stackId] || {
\r
25161 width: column.width
\r
25164 offset += column.width * (1 + barGapPercent);
\r
25172 * @param {string} seriesType
\r
25173 * @param {module:echarts/model/Global} ecModel
\r
25174 * @param {module:echarts/ExtensionAPI} api
\r
25176 function barLayoutGrid(seriesType, ecModel, api) {
\r
25178 var barWidthAndOffset = calBarWidthAndOffset(
\r
25180 ecModel.getSeriesByType(seriesType),
\r
25181 function (seriesModel) {
\r
25182 return !ecModel.isSeriesFiltered(seriesModel)
\r
25183 && seriesModel.coordinateSystem
\r
25184 && seriesModel.coordinateSystem.type === 'cartesian2d';
\r
25189 var lastStackCoords = {};
\r
25191 ecModel.eachSeriesByType(seriesType, function (seriesModel) {
\r
25193 var data = seriesModel.getData();
\r
25194 var cartesian = seriesModel.coordinateSystem;
\r
25195 var baseAxis = cartesian.getBaseAxis();
\r
25197 var stackId = getSeriesStackId(seriesModel);
\r
25198 var columnLayoutInfo = barWidthAndOffset[baseAxis.index][stackId];
\r
25199 var columnOffset = columnLayoutInfo.offset;
\r
25200 var columnWidth = columnLayoutInfo.width;
\r
25201 var valueAxis = cartesian.getOtherAxis(baseAxis);
\r
25203 var barMinHeight = seriesModel.get('barMinHeight') || 0;
\r
25205 var valueAxisStart = baseAxis.onZero
\r
25206 ? valueAxis.toGlobalCoord(valueAxis.dataToCoord(0))
\r
25207 : valueAxis.getGlobalExtent()[0];
\r
25209 var coords = cartesian.dataToPoints(data, true);
\r
25210 lastStackCoords[stackId] = lastStackCoords[stackId] || [];
\r
25213 offset: columnOffset,
\r
25214 size: columnWidth
\r
25216 data.each(valueAxis.dim, function (value, idx) {
\r
25218 if (isNaN(value)) {
\r
25221 if (!lastStackCoords[stackId][idx]) {
\r
25222 lastStackCoords[stackId][idx] = {
\r
25223 // Positive stack
\r
25224 p: valueAxisStart,
\r
25225 // Negative stack
\r
25226 n: valueAxisStart
\r
25229 var sign = value >= 0 ? 'p' : 'n';
\r
25230 var coord = coords[idx];
\r
25231 var lastCoord = lastStackCoords[stackId][idx][sign];
\r
25232 var x, y, width, height;
\r
25233 if (valueAxis.isHorizontal()) {
\r
25235 y = coord[1] + columnOffset;
\r
25236 width = coord[0] - lastCoord;
\r
25237 height = columnWidth;
\r
25239 if (Math.abs(width) < barMinHeight) {
\r
25240 width = (width < 0 ? -1 : 1) * barMinHeight;
\r
25242 lastStackCoords[stackId][idx][sign] += width;
\r
25245 x = coord[0] + columnOffset;
\r
25247 width = columnWidth;
\r
25248 height = coord[1] - lastCoord;
\r
25249 if (Math.abs(height) < barMinHeight) {
\r
25250 // Include zero to has a positive bar
\r
25251 height = (height <= 0 ? -1 : 1) * barMinHeight;
\r
25253 lastStackCoords[stackId][idx][sign] += height;
\r
25256 data.setItemLayout(idx, {
\r
25267 module.exports = barLayoutGrid;
\r
25272 /***/ function(module, exports, __webpack_require__) {
\r
25276 var zrUtil = __webpack_require__(3);
\r
25277 var echarts = __webpack_require__(1);
\r
25279 __webpack_require__(133);
\r
25280 __webpack_require__(135);
\r
25282 __webpack_require__(136)('pie', [{
\r
25283 type: 'pieToggleSelect',
\r
25284 event: 'pieselectchanged',
\r
25285 method: 'toggleSelected'
\r
25287 type: 'pieSelect',
\r
25288 event: 'pieselected',
\r
25291 type: 'pieUnSelect',
\r
25292 event: 'pieunselected',
\r
25293 method: 'unSelect'
\r
25296 echarts.registerVisualCoding(
\r
25297 'chart', zrUtil.curry(__webpack_require__(137), 'pie')
\r
25300 echarts.registerLayout(zrUtil.curry(
\r
25301 __webpack_require__(138), 'pie'
\r
25304 echarts.registerProcessor(
\r
25305 'filter', zrUtil.curry(__webpack_require__(140), 'pie')
\r
25311 /***/ function(module, exports, __webpack_require__) {
\r
25316 var List = __webpack_require__(94);
\r
25317 var zrUtil = __webpack_require__(3);
\r
25318 var modelUtil = __webpack_require__(5);
\r
25319 var completeDimensions = __webpack_require__(96);
\r
25321 var dataSelectableMixin = __webpack_require__(134);
\r
25323 var PieSeries = __webpack_require__(1).extendSeriesModel({
\r
25325 type: 'series.pie',
\r
25328 init: function (option) {
\r
25329 PieSeries.superApply(this, 'init', arguments);
\r
25331 // Enable legend selection for each data item
\r
25332 // Use a function instead of direct access because data reference may changed
\r
25333 this.legendDataProvider = function () {
\r
25334 return this._dataBeforeProcessed;
\r
25337 this.updateSelectedMap();
\r
25339 this._defaultLabelLine(option);
\r
25343 mergeOption: function (newOption) {
\r
25344 PieSeries.superCall(this, 'mergeOption', newOption);
\r
25345 this.updateSelectedMap();
\r
25348 getInitialData: function (option, ecModel) {
\r
25349 var dimensions = completeDimensions(['value'], option.data);
\r
25350 var list = new List(dimensions, this);
\r
25351 list.initData(option.data);
\r
25356 getDataParams: function (dataIndex) {
\r
25357 var data = this._data;
\r
25358 var params = PieSeries.superCall(this, 'getDataParams', dataIndex);
\r
25359 var sum = data.getSum('value');
\r
25360 // FIXME toFixed?
\r
25362 // Percent is 0 if sum is 0
\r
25363 params.percent = !sum ? 0 : +(data.get('value', dataIndex) / sum * 100).toFixed(2);
\r
25365 params.$vars.push('percent');
\r
25369 _defaultLabelLine: function (option) {
\r
25370 // Extend labelLine emphasis
\r
25371 modelUtil.defaultEmphasis(option.labelLine, ['show']);
\r
25373 var labelLineNormalOpt = option.labelLine.normal;
\r
25374 var labelLineEmphasisOpt = option.labelLine.emphasis;
\r
25375 // Not show label line if `label.normal.show = false`
\r
25376 labelLineNormalOpt.show = labelLineNormalOpt.show
\r
25377 && option.label.normal.show;
\r
25378 labelLineEmphasisOpt.show = labelLineEmphasisOpt.show
\r
25379 && option.label.emphasis.show;
\r
25385 legendHoverLink: true,
\r
25387 hoverAnimation: true,
\r
25389 center: ['50%', '50%'],
\r
25390 radius: [0, '75%'],
\r
25397 selectedOffset: 10,
\r
25399 // If use strategy to avoid label overlapping
\r
25400 avoidLabelOverlap: true,
\r
25401 // 选择模式,默认关闭,可选single,multiple
\r
25402 // selectedMode: false,
\r
25403 // 南丁格尔玫瑰图模式,'radius'(半径) | 'area'(面积)
\r
25404 // roseType: null,
\r
25408 // If rotate around circle
\r
25411 // 'outer', 'inside', 'center'
\r
25412 position: 'outer'
\r
25413 // formatter: 标签文本格式器,同Tooltip.formatter,不支持异步回调
\r
25414 // textStyle: null // 默认使用全局文本样式,详见TEXTSTYLE
\r
25415 // distance: 当position为inner时有效,为label位置到圆心的距离与圆半径(环状图为内外半径和)的比例系数
\r
25419 // Enabled when label.normal.position is 'outer'
\r
25438 borderColor: 'rgba(0,0,0,0)',
\r
25443 borderColor: 'rgba(0,0,0,0)',
\r
25448 animationEasing: 'cubicOut',
\r
25454 zrUtil.mixin(PieSeries, dataSelectableMixin);
\r
25456 module.exports = PieSeries;
\r
25461 /***/ function(module, exports, __webpack_require__) {
\r
25464 * Data selectable mixin for chart series.
\r
25465 * To eanble data select, option of series must have `selectedMode`.
\r
25466 * And each data item will use `selected` to toggle itself selected status
\r
25468 * @module echarts/chart/helper/DataSelectable
\r
25472 var zrUtil = __webpack_require__(3);
\r
25474 module.exports = {
\r
25476 updateSelectedMap: function () {
\r
25477 var option = this.option;
\r
25478 this._dataOptMap = zrUtil.reduce(option.data, function (dataOptMap, dataOpt) {
\r
25479 dataOptMap[dataOpt.name] = dataOpt;
\r
25480 return dataOptMap;
\r
25484 * @param {string} name
\r
25486 // PENGING If selectedMode is null ?
\r
25487 select: function (name) {
\r
25488 var dataOptMap = this._dataOptMap;
\r
25489 var dataOpt = dataOptMap[name];
\r
25490 var selectedMode = this.get('selectedMode');
\r
25491 if (selectedMode === 'single') {
\r
25492 zrUtil.each(dataOptMap, function (dataOpt) {
\r
25493 dataOpt.selected = false;
\r
25496 dataOpt && (dataOpt.selected = true);
\r
25500 * @param {string} name
\r
25502 unSelect: function (name) {
\r
25503 var dataOpt = this._dataOptMap[name];
\r
25504 // var selectedMode = this.get('selectedMode');
\r
25505 // selectedMode !== 'single' && dataOpt && (dataOpt.selected = false);
\r
25506 dataOpt && (dataOpt.selected = false);
\r
25510 * @param {string} name
\r
25512 toggleSelected: function (name) {
\r
25513 var dataOpt = this._dataOptMap[name];
\r
25514 if (dataOpt != null) {
\r
25515 this[dataOpt.selected ? 'unSelect' : 'select'](name);
\r
25516 return dataOpt.selected;
\r
25521 * @param {string} name
\r
25523 isSelected: function (name) {
\r
25524 var dataOpt = this._dataOptMap[name];
\r
25525 return dataOpt && dataOpt.selected;
\r
25532 /***/ function(module, exports, __webpack_require__) {
\r
25536 var graphic = __webpack_require__(42);
\r
25537 var zrUtil = __webpack_require__(3);
\r
25540 * @param {module:echarts/model/Series} seriesModel
\r
25541 * @param {boolean} hasAnimation
\r
25544 function updateDataSelected(uid, seriesModel, hasAnimation, api) {
\r
25545 var data = seriesModel.getData();
\r
25546 var dataIndex = this.dataIndex;
\r
25547 var name = data.getName(dataIndex);
\r
25548 var selectedOffset = seriesModel.get('selectedOffset');
\r
25550 api.dispatchAction({
\r
25551 type: 'pieToggleSelect',
\r
25554 seriesId: seriesModel.id
\r
25557 data.each(function (idx) {
\r
25558 toggleItemSelected(
\r
25559 data.getItemGraphicEl(idx),
\r
25560 data.getItemLayout(idx),
\r
25561 seriesModel.isSelected(data.getName(idx)),
\r
25569 * @param {module:zrender/graphic/Sector} el
\r
25570 * @param {Object} layout
\r
25571 * @param {boolean} isSelected
\r
25572 * @param {number} selectedOffset
\r
25573 * @param {boolean} hasAnimation
\r
25576 function toggleItemSelected(el, layout, isSelected, selectedOffset, hasAnimation) {
\r
25577 var midAngle = (layout.startAngle + layout.endAngle) / 2;
\r
25579 var dx = Math.cos(midAngle);
\r
25580 var dy = Math.sin(midAngle);
\r
25582 var offset = isSelected ? selectedOffset : 0;
\r
25583 var position = [dx * offset, dy * offset];
\r
25586 // animateTo will stop revious animation like update transition
\r
25589 position: position
\r
25591 .start('bounceOut')
\r
25592 : el.attr('position', position);
\r
25596 * Piece of pie including Sector, Label, LabelLine
\r
25598 * @extends {module:zrender/graphic/Group}
\r
25600 function PiePiece(data, idx) {
\r
25602 graphic.Group.call(this);
\r
25604 var sector = new graphic.Sector({
\r
25607 var polyline = new graphic.Polyline();
\r
25608 var text = new graphic.Text();
\r
25609 this.add(sector);
\r
25610 this.add(polyline);
\r
25613 this.updateData(data, idx, true);
\r
25615 // Hover to change label and labelLine
\r
25616 function onEmphasis() {
\r
25617 polyline.ignore = polyline.hoverIgnore;
\r
25618 text.ignore = text.hoverIgnore;
\r
25620 function onNormal() {
\r
25621 polyline.ignore = polyline.normalIgnore;
\r
25622 text.ignore = text.normalIgnore;
\r
25624 this.on('emphasis', onEmphasis)
\r
25625 .on('normal', onNormal)
\r
25626 .on('mouseover', onEmphasis)
\r
25627 .on('mouseout', onNormal);
\r
25630 var piePieceProto = PiePiece.prototype;
\r
25632 function getLabelStyle(data, idx, state, labelModel, labelPosition) {
\r
25633 var textStyleModel = labelModel.getModel('textStyle');
\r
25634 var isLabelInside = labelPosition === 'inside' || labelPosition === 'inner';
\r
25636 fill: textStyleModel.getTextColor()
\r
25637 || (isLabelInside ? '#fff' : data.getItemVisual(idx, 'color')),
\r
25638 textFont: textStyleModel.getFont(),
\r
25639 text: zrUtil.retrieve(
\r
25640 data.hostModel.getFormattedLabel(idx, state), data.getName(idx)
\r
25645 piePieceProto.updateData = function (data, idx, firstCreate) {
\r
25647 var sector = this.childAt(0);
\r
25649 var seriesModel = data.hostModel;
\r
25650 var itemModel = data.getItemModel(idx);
\r
25651 var layout = data.getItemLayout(idx);
\r
25652 var sectorShape = zrUtil.extend({}, layout);
\r
25653 sectorShape.label = null;
\r
25654 if (firstCreate) {
\r
25655 sector.setShape(sectorShape);
\r
25656 sector.shape.endAngle = layout.startAngle;
\r
25657 graphic.updateProps(sector, {
\r
25659 endAngle: layout.endAngle
\r
25664 graphic.updateProps(sector, {
\r
25665 shape: sectorShape
\r
25669 // Update common style
\r
25670 var itemStyleModel = itemModel.getModel('itemStyle');
\r
25671 var visualColor = data.getItemVisual(idx, 'color');
\r
25676 fill: visualColor
\r
25678 itemStyleModel.getModel('normal').getItemStyle()
\r
25681 sector.hoverStyle = itemStyleModel.getModel('emphasis').getItemStyle();
\r
25683 // Toggle selected
\r
25684 toggleItemSelected(
\r
25686 data.getItemLayout(idx),
\r
25687 itemModel.get('selected'),
\r
25688 seriesModel.get('selectedOffset'),
\r
25689 seriesModel.get('animation')
\r
25692 function onEmphasis() {
\r
25693 // Sector may has animation of updating data. Force to move to the last frame
\r
25694 // Or it may stopped on the wrong shape
\r
25695 sector.stopAnimation(true);
\r
25696 sector.animateTo({
\r
25700 }, 300, 'elasticOut');
\r
25702 function onNormal() {
\r
25703 sector.stopAnimation(true);
\r
25704 sector.animateTo({
\r
25708 }, 300, 'elasticOut');
\r
25710 sector.off('mouseover').off('mouseout').off('emphasis').off('normal');
\r
25711 if (itemModel.get('hoverAnimation')) {
\r
25713 .on('mouseover', onEmphasis)
\r
25714 .on('mouseout', onNormal)
\r
25715 .on('emphasis', onEmphasis)
\r
25716 .on('normal', onNormal);
\r
25719 this._updateLabel(data, idx);
\r
25721 graphic.setHoverStyle(this);
\r
25724 piePieceProto._updateLabel = function (data, idx) {
\r
25726 var labelLine = this.childAt(1);
\r
25727 var labelText = this.childAt(2);
\r
25729 var seriesModel = data.hostModel;
\r
25730 var itemModel = data.getItemModel(idx);
\r
25731 var layout = data.getItemLayout(idx);
\r
25732 var labelLayout = layout.label;
\r
25733 var visualColor = data.getItemVisual(idx, 'color');
\r
25735 graphic.updateProps(labelLine, {
\r
25737 points: labelLayout.linePoints || [
\r
25738 [labelLayout.x, labelLayout.y], [labelLayout.x, labelLayout.y], [labelLayout.x, labelLayout.y]
\r
25743 graphic.updateProps(labelText, {
\r
25745 x: labelLayout.x,
\r
25751 textVerticalAlign: labelLayout.verticalAlign,
\r
25752 textAlign: labelLayout.textAlign,
\r
25753 textFont: labelLayout.font
\r
25755 rotation: labelLayout.rotation,
\r
25756 origin: [labelLayout.x, labelLayout.y],
\r
25760 var labelModel = itemModel.getModel('label.normal');
\r
25761 var labelHoverModel = itemModel.getModel('label.emphasis');
\r
25762 var labelLineModel = itemModel.getModel('labelLine.normal');
\r
25763 var labelLineHoverModel = itemModel.getModel('labelLine.emphasis');
\r
25764 var labelPosition = labelModel.get('position') || labelHoverModel.get('position');
\r
25766 labelText.setStyle(getLabelStyle(data, idx, 'normal', labelModel, labelPosition));
\r
25768 labelText.ignore = labelText.normalIgnore = !labelModel.get('show');
\r
25769 labelText.hoverIgnore = !labelHoverModel.get('show');
\r
25771 labelLine.ignore = labelLine.normalIgnore = !labelLineModel.get('show');
\r
25772 labelLine.hoverIgnore = !labelLineHoverModel.get('show');
\r
25774 // Default use item visual color
\r
25775 labelLine.setStyle({
\r
25776 stroke: visualColor
\r
25778 labelLine.setStyle(labelLineModel.getModel('lineStyle').getLineStyle());
\r
25780 labelText.hoverStyle = getLabelStyle(data, idx, 'emphasis', labelHoverModel, labelPosition);
\r
25781 labelLine.hoverStyle = labelLineHoverModel.getModel('lineStyle').getLineStyle();
\r
25783 var smooth = labelLineModel.get('smooth');
\r
25784 if (smooth && smooth === true) {
\r
25787 labelLine.setShape({
\r
25792 zrUtil.inherits(PiePiece, graphic.Group);
\r
25796 var Pie = __webpack_require__(41).extend({
\r
25800 init: function () {
\r
25801 var sectorGroup = new graphic.Group();
\r
25802 this._sectorGroup = sectorGroup;
\r
25805 render: function (seriesModel, ecModel, api, payload) {
\r
25806 if (payload && (payload.from === this.uid)) {
\r
25810 var data = seriesModel.getData();
\r
25811 var oldData = this._data;
\r
25812 var group = this.group;
\r
25814 var hasAnimation = ecModel.get('animation');
\r
25815 var isFirstRender = !oldData;
\r
25817 var onSectorClick = zrUtil.curry(
\r
25818 updateDataSelected, this.uid, seriesModel, hasAnimation, api
\r
25821 var selectedMode = seriesModel.get('selectedMode');
\r
25823 data.diff(oldData)
\r
25824 .add(function (idx) {
\r
25825 var piePiece = new PiePiece(data, idx);
\r
25826 if (isFirstRender) {
\r
25827 piePiece.eachChild(function (child) {
\r
25828 child.stopAnimation(true);
\r
25832 selectedMode && piePiece.on('click', onSectorClick);
\r
25834 data.setItemGraphicEl(idx, piePiece);
\r
25836 group.add(piePiece);
\r
25838 .update(function (newIdx, oldIdx) {
\r
25839 var piePiece = oldData.getItemGraphicEl(oldIdx);
\r
25841 piePiece.updateData(data, newIdx);
\r
25843 piePiece.off('click');
\r
25844 selectedMode && piePiece.on('click', onSectorClick);
\r
25845 group.add(piePiece);
\r
25846 data.setItemGraphicEl(newIdx, piePiece);
\r
25848 .remove(function (idx) {
\r
25849 var piePiece = oldData.getItemGraphicEl(idx);
\r
25850 group.remove(piePiece);
\r
25854 if (hasAnimation && isFirstRender && data.count() > 0) {
\r
25855 var shape = data.getItemLayout(0);
\r
25856 var r = Math.max(api.getWidth(), api.getHeight()) / 2;
\r
25858 var removeClipPath = zrUtil.bind(group.removeClipPath, group);
\r
25859 group.setClipPath(this._createClipPath(
\r
25860 shape.cx, shape.cy, r, shape.startAngle, shape.clockwise, removeClipPath, seriesModel
\r
25864 this._data = data;
\r
25867 _createClipPath: function (
\r
25868 cx, cy, r, startAngle, clockwise, cb, seriesModel
\r
25870 var clipPath = new graphic.Sector({
\r
25876 startAngle: startAngle,
\r
25877 endAngle: startAngle,
\r
25878 clockwise: clockwise
\r
25882 graphic.initProps(clipPath, {
\r
25884 endAngle: startAngle + (clockwise ? 1 : -1) * Math.PI * 2
\r
25886 }, seriesModel, cb);
\r
25892 module.exports = Pie;
\r
25897 /***/ function(module, exports, __webpack_require__) {
\r
25900 var echarts = __webpack_require__(1);
\r
25901 var zrUtil = __webpack_require__(3);
\r
25902 module.exports = function (seriesType, actionInfos) {
\r
25903 zrUtil.each(actionInfos, function (actionInfo) {
\r
25904 actionInfo.update = 'updateView';
\r
25907 * @property {string} seriesName
\r
25908 * @property {string} name
\r
25910 echarts.registerAction(actionInfo, function (payload, ecModel) {
\r
25911 var selected = {};
\r
25912 ecModel.eachComponent(
\r
25913 {mainType: 'series', subType: seriesType, query: payload},
\r
25914 function (seriesModel) {
\r
25915 if (seriesModel[actionInfo.method]) {
\r
25916 seriesModel[actionInfo.method](payload.name);
\r
25918 var data = seriesModel.getData();
\r
25919 // Create selected map
\r
25920 data.each(function (idx) {
\r
25921 var name = data.getName(idx);
\r
25922 selected[name] = seriesModel.isSelected(name) || false;
\r
25927 name: payload.name,
\r
25928 selected: selected
\r
25937 /***/ function(module, exports) {
\r
25939 // Pick color from palette for each data item
\r
25942 module.exports = function (seriesType, ecModel) {
\r
25943 var globalColorList = ecModel.get('color');
\r
25945 ecModel.eachRawSeriesByType(seriesType, function (seriesModel) {
\r
25946 var colorList = seriesModel.get('color', true);
\r
25947 var dataAll = seriesModel.getRawData();
\r
25948 if (!ecModel.isSeriesFiltered(seriesModel)) {
\r
25949 var data = seriesModel.getData();
\r
25950 data.each(function (idx) {
\r
25951 var itemModel = data.getItemModel(idx);
\r
25952 var rawIdx = data.getRawIndex(idx);
\r
25953 // If series.itemStyle.normal.color is a function. itemVisual may be encoded
\r
25954 var singleDataColor = data.getItemVisual(idx, 'color', true);
\r
25955 if (!singleDataColor) {
\r
25956 var paletteColor = colorList ? colorList[rawIdx % colorList.length]
\r
25957 : globalColorList[(rawIdx + offset) % globalColorList.length];
\r
25958 var color = itemModel.get('itemStyle.normal.color') || paletteColor;
\r
25959 // Legend may use the visual info in data before processed
\r
25960 dataAll.setItemVisual(rawIdx, 'color', color);
\r
25961 data.setItemVisual(idx, 'color', color);
\r
25964 // Set data all color for legend
\r
25965 dataAll.setItemVisual(rawIdx, 'color', singleDataColor);
\r
25969 offset += dataAll.count();
\r
25976 /***/ function(module, exports, __webpack_require__) {
\r
25982 var numberUtil = __webpack_require__(7);
\r
25983 var parsePercent = numberUtil.parsePercent;
\r
25984 var labelLayout = __webpack_require__(139);
\r
25985 var zrUtil = __webpack_require__(3);
\r
25987 var PI2 = Math.PI * 2;
\r
25988 var RADIAN = Math.PI / 180;
\r
25990 module.exports = function (seriesType, ecModel, api) {
\r
25991 ecModel.eachSeriesByType(seriesType, function (seriesModel) {
\r
25992 var center = seriesModel.get('center');
\r
25993 var radius = seriesModel.get('radius');
\r
25995 if (!zrUtil.isArray(radius)) {
\r
25996 radius = [0, radius];
\r
25998 if (!zrUtil.isArray(center)) {
\r
25999 center = [center, center];
\r
26002 var width = api.getWidth();
\r
26003 var height = api.getHeight();
\r
26004 var size = Math.min(width, height);
\r
26005 var cx = parsePercent(center[0], width);
\r
26006 var cy = parsePercent(center[1], height);
\r
26007 var r0 = parsePercent(radius[0], size / 2);
\r
26008 var r = parsePercent(radius[1], size / 2);
\r
26010 var data = seriesModel.getData();
\r
26012 var startAngle = -seriesModel.get('startAngle') * RADIAN;
\r
26014 var minAngle = seriesModel.get('minAngle') * RADIAN;
\r
26016 var sum = data.getSum('value');
\r
26018 var unitRadian = Math.PI / (sum || data.count()) * 2;
\r
26020 var clockwise = seriesModel.get('clockwise');
\r
26022 var roseType = seriesModel.get('roseType');
\r
26025 var extent = data.getDataExtent('value');
\r
26028 // In the case some sector angle is smaller than minAngle
\r
26029 var restAngle = PI2;
\r
26030 var valueSumLargerThanMinAngle = 0;
\r
26032 var currentAngle = startAngle;
\r
26034 var dir = clockwise ? 1 : -1;
\r
26035 data.each('value', function (value, idx) {
\r
26037 // FIXME 兼容 2.0 但是 roseType 是 area 的时候才是这样?
\r
26038 if (roseType !== 'area') {
\r
26039 angle = sum === 0 ? unitRadian : (value * unitRadian);
\r
26042 angle = PI2 / (data.count() || 1);
\r
26045 if (angle < minAngle) {
\r
26046 angle = minAngle;
\r
26047 restAngle -= minAngle;
\r
26050 valueSumLargerThanMinAngle += value;
\r
26053 var endAngle = currentAngle + dir * angle;
\r
26054 data.setItemLayout(idx, {
\r
26056 startAngle: currentAngle,
\r
26057 endAngle: endAngle,
\r
26058 clockwise: clockwise,
\r
26063 ? numberUtil.linearMap(value, extent, [r0, r])
\r
26067 currentAngle = endAngle;
\r
26070 // Some sector is constrained by minAngle
\r
26071 // Rest sectors needs recalculate angle
\r
26072 if (restAngle < PI2) {
\r
26073 // Average the angle if rest angle is not enough after all angles is
\r
26074 // Constrained by minAngle
\r
26075 if (restAngle <= 1e-3) {
\r
26076 var angle = PI2 / data.count();
\r
26077 data.each(function (idx) {
\r
26078 var layout = data.getItemLayout(idx);
\r
26079 layout.startAngle = startAngle + dir * idx * angle;
\r
26080 layout.endAngle = startAngle + dir * (idx + 1) * angle;
\r
26084 unitRadian = restAngle / valueSumLargerThanMinAngle;
\r
26085 currentAngle = startAngle;
\r
26086 data.each('value', function (value, idx) {
\r
26087 var layout = data.getItemLayout(idx);
\r
26088 var angle = layout.angle === minAngle
\r
26089 ? minAngle : value * unitRadian;
\r
26090 layout.startAngle = currentAngle;
\r
26091 layout.endAngle = currentAngle + dir * angle;
\r
26092 currentAngle += angle;
\r
26097 labelLayout(seriesModel, r, width, height);
\r
26104 /***/ function(module, exports, __webpack_require__) {
\r
26107 // FIXME emphasis label position is not same with normal label position
\r
26110 var textContain = __webpack_require__(14);
\r
26112 function adjustSingleSide(list, cx, cy, r, dir, viewWidth, viewHeight) {
\r
26113 list.sort(function (a, b) {
\r
26114 return a.y - b.y;
\r
26118 function shiftDown(start, end, delta, dir) {
\r
26119 for (var j = start; j < end; j++) {
\r
26120 list[j].y += delta;
\r
26123 && list[j + 1].y > list[j].y + list[j].height
\r
26125 shiftUp(j, delta / 2);
\r
26130 shiftUp(end - 1, delta / 2);
\r
26134 function shiftUp(end, delta) {
\r
26135 for (var j = end; j >= 0; j--) {
\r
26136 list[j].y -= delta;
\r
26138 && list[j].y > list[j - 1].y + list[j - 1].height
\r
26145 function changeX(list, isDownList, cx, cy, r, dir) {
\r
26146 var lastDeltaX = dir > 0
\r
26147 ? isDownList // 右侧
\r
26148 ? Number.MAX_VALUE // 下
\r
26150 : isDownList // 左侧
\r
26151 ? Number.MAX_VALUE // 下
\r
26154 for (var i = 0, l = list.length; i < l; i++) {
\r
26155 // Not change x for center label
\r
26156 if (list[i].position === 'center') {
\r
26159 var deltaY = Math.abs(list[i].y - cy);
\r
26160 var length = list[i].len;
\r
26161 var length2 = list[i].len2;
\r
26162 var deltaX = (deltaY < r + length)
\r
26164 (r + length + length2) * (r + length + length2)
\r
26165 - deltaY * deltaY
\r
26167 : Math.abs(list[i].x - cx);
\r
26168 if (isDownList && deltaX >= lastDeltaX) {
\r
26170 deltaX = lastDeltaX - 10;
\r
26172 if (!isDownList && deltaX <= lastDeltaX) {
\r
26174 deltaX = lastDeltaX + 10;
\r
26177 list[i].x = cx + deltaX * dir;
\r
26178 lastDeltaX = deltaX;
\r
26184 var len = list.length;
\r
26186 var downList = [];
\r
26187 for (var i = 0; i < len; i++) {
\r
26188 delta = list[i].y - lastY;
\r
26190 shiftDown(i, len, -delta, dir);
\r
26192 lastY = list[i].y + list[i].height;
\r
26194 if (viewHeight - lastY < 0) {
\r
26195 shiftUp(len - 1, lastY - viewHeight);
\r
26197 for (var i = 0; i < len; i++) {
\r
26198 if (list[i].y >= cy) {
\r
26199 downList.push(list[i]);
\r
26202 upList.push(list[i]);
\r
26205 changeX(upList, false, cx, cy, r, dir);
\r
26206 changeX(downList, true, cx, cy, r, dir);
\r
26209 function avoidOverlap(labelLayoutList, cx, cy, r, viewWidth, viewHeight) {
\r
26210 var leftList = [];
\r
26211 var rightList = [];
\r
26212 for (var i = 0; i < labelLayoutList.length; i++) {
\r
26213 if (labelLayoutList[i].x < cx) {
\r
26214 leftList.push(labelLayoutList[i]);
\r
26217 rightList.push(labelLayoutList[i]);
\r
26221 adjustSingleSide(rightList, cx, cy, r, 1, viewWidth, viewHeight);
\r
26222 adjustSingleSide(leftList, cx, cy, r, -1, viewWidth, viewHeight);
\r
26224 for (var i = 0; i < labelLayoutList.length; i++) {
\r
26225 var linePoints = labelLayoutList[i].linePoints;
\r
26226 if (linePoints) {
\r
26227 var dist = linePoints[1][0] - linePoints[2][0];
\r
26228 if (labelLayoutList[i].x < cx) {
\r
26229 linePoints[2][0] = labelLayoutList[i].x + 3;
\r
26232 linePoints[2][0] = labelLayoutList[i].x - 3;
\r
26234 linePoints[1][1] = linePoints[2][1] = labelLayoutList[i].y;
\r
26235 linePoints[1][0] = linePoints[2][0] + dist;
\r
26240 module.exports = function (seriesModel, r, viewWidth, viewHeight) {
\r
26241 var data = seriesModel.getData();
\r
26242 var labelLayoutList = [];
\r
26245 var hasLabelRotate = false;
\r
26247 data.each(function (idx) {
\r
26248 var layout = data.getItemLayout(idx);
\r
26250 var itemModel = data.getItemModel(idx);
\r
26251 var labelModel = itemModel.getModel('label.normal');
\r
26252 // Use position in normal or emphasis
\r
26253 var labelPosition = labelModel.get('position') || itemModel.get('label.emphasis.position');
\r
26255 var labelLineModel = itemModel.getModel('labelLine.normal');
\r
26256 var labelLineLen = labelLineModel.get('length');
\r
26257 var labelLineLen2 = labelLineModel.get('length2');
\r
26259 var midAngle = (layout.startAngle + layout.endAngle) / 2;
\r
26260 var dx = Math.cos(midAngle);
\r
26261 var dy = Math.sin(midAngle);
\r
26271 var isLabelInside = labelPosition === 'inside' || labelPosition === 'inner';
\r
26272 if (labelPosition === 'center') {
\r
26273 textX = layout.cx;
\r
26274 textY = layout.cy;
\r
26275 textAlign = 'center';
\r
26278 var x1 = (isLabelInside ? layout.r / 2 * dx : layout.r * dx) + cx;
\r
26279 var y1 = (isLabelInside ? layout.r / 2 * dy : layout.r * dy) + cy;
\r
26281 textX = x1 + dx * 3;
\r
26282 textY = y1 + dy * 3;
\r
26284 if (!isLabelInside) {
\r
26286 var x2 = x1 + dx * (labelLineLen + r - layout.r);
\r
26287 var y2 = y1 + dy * (labelLineLen + r - layout.r);
\r
26288 var x3 = x2 + ((dx < 0 ? -1 : 1) * labelLineLen2);
\r
26291 textX = x3 + (dx < 0 ? -5 : 5);
\r
26293 linePoints = [[x1, y1], [x2, y2], [x3, y3]];
\r
26296 textAlign = isLabelInside ? 'center' : (dx > 0 ? 'left' : 'right');
\r
26298 var font = labelModel.getModel('textStyle').getFont();
\r
26300 var labelRotate = labelModel.get('rotate')
\r
26301 ? (dx < 0 ? -midAngle + Math.PI : -midAngle) : 0;
\r
26302 var text = seriesModel.getFormattedLabel(idx, 'normal')
\r
26303 || data.getName(idx);
\r
26304 var textRect = textContain.getBoundingRect(
\r
26305 text, font, textAlign, 'top'
\r
26307 hasLabelRotate = !!labelRotate;
\r
26311 position: labelPosition,
\r
26312 height: textRect.height,
\r
26313 len: labelLineLen,
\r
26314 len2: labelLineLen2,
\r
26315 linePoints: linePoints,
\r
26316 textAlign: textAlign,
\r
26317 verticalAlign: 'middle',
\r
26319 rotation: labelRotate
\r
26322 // Not layout the inside label
\r
26323 if (!isLabelInside) {
\r
26324 labelLayoutList.push(layout.label);
\r
26327 if (!hasLabelRotate && seriesModel.get('avoidLabelOverlap')) {
\r
26328 avoidOverlap(labelLayoutList, cx, cy, r, viewWidth, viewHeight);
\r
26335 /***/ function(module, exports) {
\r
26338 module.exports = function (seriesType, ecModel) {
\r
26339 var legendModels = ecModel.findComponents({
\r
26340 mainType: 'legend'
\r
26342 if (!legendModels || !legendModels.length) {
\r
26345 ecModel.eachSeriesByType(seriesType, function (series) {
\r
26346 var data = series.getData();
\r
26347 data.filterSelf(function (idx) {
\r
26348 var name = data.getName(idx);
\r
26349 // If in any legend component the status is not selected.
\r
26350 for (var i = 0; i < legendModels.length; i++) {
\r
26351 if (!legendModels[i].isSelected(name)) {
\r
26363 /***/ function(module, exports, __webpack_require__) {
\r
26367 var zrUtil = __webpack_require__(3);
\r
26368 var echarts = __webpack_require__(1);
\r
26370 __webpack_require__(142);
\r
26371 __webpack_require__(143);
\r
26373 echarts.registerVisualCoding('chart', zrUtil.curry(
\r
26374 __webpack_require__(103), 'scatter', 'circle', null
\r
26376 echarts.registerLayout(zrUtil.curry(
\r
26377 __webpack_require__(104), 'scatter'
\r
26380 // In case developer forget to include grid component
\r
26381 __webpack_require__(106);
\r
26386 /***/ function(module, exports, __webpack_require__) {
\r
26391 var createListFromArray = __webpack_require__(93);
\r
26392 var SeriesModel = __webpack_require__(27);
\r
26394 module.exports = SeriesModel.extend({
\r
26396 type: 'series.scatter',
\r
26398 dependencies: ['grid', 'polar'],
\r
26400 getInitialData: function (option, ecModel) {
\r
26401 var list = createListFromArray(option.data, this, ecModel);
\r
26406 coordinateSystem: 'cartesian2d',
\r
26409 legendHoverLink: true,
\r
26411 hoverAnimation: true,
\r
26412 // Cartesian coordinate system
\r
26416 // Polar coordinate system
\r
26419 // Geo coordinate system
\r
26422 // symbol: null, // 图形类型
\r
26423 symbolSize: 10, // 图形大小,半宽(半径)参数,当图形为方向或菱形则总宽度为symbolSize * 2
\r
26424 // symbolRotate: null, // 图形旋转控制
\r
26427 // Available when large is true
\r
26428 largeThreshold: 2000,
\r
26434 // formatter: 标签文本格式器,同Tooltip.formatter,不支持异步回调
\r
26435 // position: 默认自适应,水平布局为'top',垂直布局为'right',可选为
\r
26436 // 'inside'|'left'|'right'|'top'|'bottom'
\r
26437 // textStyle: null // 默认使用全局文本样式,详见TEXTSTYLE
\r
26452 /***/ function(module, exports, __webpack_require__) {
\r
26456 var SymbolDraw = __webpack_require__(98);
\r
26457 var LargeSymbolDraw = __webpack_require__(144);
\r
26459 __webpack_require__(1).extendChartView({
\r
26463 init: function () {
\r
26464 this._normalSymbolDraw = new SymbolDraw();
\r
26465 this._largeSymbolDraw = new LargeSymbolDraw();
\r
26468 render: function (seriesModel, ecModel, api) {
\r
26469 var data = seriesModel.getData();
\r
26470 var largeSymbolDraw = this._largeSymbolDraw;
\r
26471 var normalSymbolDraw = this._normalSymbolDraw;
\r
26472 var group = this.group;
\r
26474 var symbolDraw = seriesModel.get('large') && data.count() > seriesModel.get('largeThreshold')
\r
26475 ? largeSymbolDraw : normalSymbolDraw;
\r
26477 this._symbolDraw = symbolDraw;
\r
26478 symbolDraw.updateData(data);
\r
26479 group.add(symbolDraw.group);
\r
26482 symbolDraw === largeSymbolDraw
\r
26483 ? normalSymbolDraw.group : largeSymbolDraw.group
\r
26487 updateLayout: function (seriesModel) {
\r
26488 this._symbolDraw.updateLayout(seriesModel);
\r
26491 remove: function (ecModel, api) {
\r
26492 this._symbolDraw && this._symbolDraw.remove(api, true);
\r
26499 /***/ function(module, exports, __webpack_require__) {
\r
26503 var graphic = __webpack_require__(42);
\r
26504 var symbolUtil = __webpack_require__(100);
\r
26505 var zrUtil = __webpack_require__(3);
\r
26507 var LargeSymbolPath = graphic.extendShape({
\r
26513 symbolProxy: null,
\r
26515 buildPath: function (path, shape) {
\r
26516 var points = shape.points;
\r
26517 var sizes = shape.sizes;
\r
26519 var symbolProxy = this.symbolProxy;
\r
26520 var symbolProxyShape = symbolProxy.shape;
\r
26521 for (var i = 0; i < points.length; i++) {
\r
26522 var pt = points[i];
\r
26523 var size = sizes[i];
\r
26524 if (size[0] < 4) {
\r
26525 // Optimize for small symbol
\r
26527 pt[0] - size[0] / 2, pt[1] - size[1] / 2,
\r
26532 symbolProxyShape.x = pt[0] - size[0] / 2;
\r
26533 symbolProxyShape.y = pt[1] - size[1] / 2;
\r
26534 symbolProxyShape.width = size[0];
\r
26535 symbolProxyShape.height = size[1];
\r
26537 symbolProxy.buildPath(path, symbolProxyShape);
\r
26543 function LargeSymbolDraw() {
\r
26544 this.group = new graphic.Group();
\r
26546 this._symbolEl = new LargeSymbolPath({
\r
26551 var largeSymbolProto = LargeSymbolDraw.prototype;
\r
26554 * Update symbols draw by new data
\r
26555 * @param {module:echarts/data/List} data
\r
26557 largeSymbolProto.updateData = function (data) {
\r
26558 this.group.removeAll();
\r
26560 var symbolEl = this._symbolEl;
\r
26562 var seriesModel = data.hostModel;
\r
26564 symbolEl.setShape({
\r
26565 points: data.mapArray(data.getItemLayout),
\r
26566 sizes: data.mapArray(
\r
26568 var size = data.getItemVisual(idx, 'symbolSize');
\r
26569 if (!zrUtil.isArray(size)) {
\r
26570 size = [size, size];
\r
26577 // Create symbolProxy to build path for each data
\r
26578 symbolEl.symbolProxy = symbolUtil.createSymbol(
\r
26579 data.getVisual('symbol'), 0, 0, 0, 0
\r
26581 // Use symbolProxy setColor method
\r
26582 symbolEl.setColor = symbolEl.symbolProxy.setColor;
\r
26584 symbolEl.setStyle(
\r
26585 seriesModel.getModel('itemStyle.normal').getItemStyle(['color'])
\r
26588 var visualColor = data.getVisual('color');
\r
26589 if (visualColor) {
\r
26590 symbolEl.setColor(visualColor);
\r
26594 this.group.add(this._symbolEl);
\r
26597 largeSymbolProto.updateLayout = function (seriesModel) {
\r
26598 var data = seriesModel.getData();
\r
26599 this._symbolEl.setShape({
\r
26600 points: data.mapArray(data.getItemLayout)
\r
26604 largeSymbolProto.remove = function () {
\r
26605 this.group.removeAll();
\r
26608 module.exports = LargeSymbolDraw;
\r
26613 /***/ function(module, exports, __webpack_require__) {
\r
26617 var zrUtil = __webpack_require__(3);
\r
26618 var echarts = __webpack_require__(1);
\r
26620 // Must use radar component
\r
26621 __webpack_require__(146);
\r
26623 __webpack_require__(151);
\r
26624 __webpack_require__(152);
\r
26626 echarts.registerVisualCoding(
\r
26627 'chart', zrUtil.curry(__webpack_require__(137), 'radar')
\r
26629 echarts.registerVisualCoding('chart', zrUtil.curry(
\r
26630 __webpack_require__(103), 'radar', 'circle', null
\r
26632 echarts.registerLayout(__webpack_require__(153));
\r
26634 echarts.registerProcessor(
\r
26635 'filter', zrUtil.curry(__webpack_require__(140), 'radar')
\r
26638 echarts.registerPreprocessor(__webpack_require__(154));
\r
26643 /***/ function(module, exports, __webpack_require__) {
\r
26647 __webpack_require__(147);
\r
26648 __webpack_require__(149);
\r
26650 __webpack_require__(150);
\r
26655 /***/ function(module, exports, __webpack_require__) {
\r
26657 // TODO clockwise
\r
26660 var zrUtil = __webpack_require__(3);
\r
26661 var IndicatorAxis = __webpack_require__(148);
\r
26662 var IntervalScale = __webpack_require__(111);
\r
26663 var numberUtil = __webpack_require__(7);
\r
26664 var axisHelper = __webpack_require__(108);
\r
26666 function Radar(radarModel, ecModel, api) {
\r
26668 this._model = radarModel;
\r
26670 * Radar dimensions
\r
26671 * @type {Array.<string>}
\r
26673 this.dimensions = [];
\r
26675 this._indicatorAxes = zrUtil.map(radarModel.getIndicatorModels(), function (indicatorModel, idx) {
\r
26676 var dim = 'indicator_' + idx;
\r
26677 var indicatorAxis = new IndicatorAxis(dim, new IntervalScale());
\r
26678 indicatorAxis.name = indicatorModel.get('name');
\r
26679 // Inject model and axis
\r
26680 indicatorAxis.model = indicatorModel;
\r
26681 indicatorModel.axis = indicatorAxis;
\r
26682 this.dimensions.push(dim);
\r
26683 return indicatorAxis;
\r
26686 this.resize(radarModel, api);
\r
26710 Radar.prototype.getIndicatorAxes = function () {
\r
26711 return this._indicatorAxes;
\r
26714 Radar.prototype.dataToPoint = function (value, indicatorIndex) {
\r
26715 var indicatorAxis = this._indicatorAxes[indicatorIndex];
\r
26717 return this.coordToPoint(indicatorAxis.dataToCoord(value), indicatorIndex);
\r
26720 Radar.prototype.coordToPoint = function (coord, indicatorIndex) {
\r
26721 var indicatorAxis = this._indicatorAxes[indicatorIndex];
\r
26722 var angle = indicatorAxis.angle;
\r
26723 var x = this.cx + coord * Math.cos(angle);
\r
26724 var y = this.cy - coord * Math.sin(angle);
\r
26728 Radar.prototype.pointToData = function (pt) {
\r
26729 var dx = pt[0] - this.cx;
\r
26730 var dy = pt[1] - this.cy;
\r
26731 var radius = Math.sqrt(dx * dx + dy * dy);
\r
26735 var radian = Math.atan2(-dy, dx);
\r
26737 // Find the closest angle
\r
26738 // FIXME index can calculated directly
\r
26739 var minRadianDiff = Infinity;
\r
26741 var closestAxisIdx = -1;
\r
26742 for (var i = 0; i < this._indicatorAxes.length; i++) {
\r
26743 var indicatorAxis = this._indicatorAxes[i];
\r
26744 var diff = Math.abs(radian - indicatorAxis.angle);
\r
26745 if (diff < minRadianDiff) {
\r
26746 closestAxis = indicatorAxis;
\r
26747 closestAxisIdx = i;
\r
26748 minRadianDiff = diff;
\r
26752 return [closestAxisIdx, +(closestAxis && closestAxis.coodToData(radius))];
\r
26755 Radar.prototype.resize = function (radarModel, api) {
\r
26756 var center = radarModel.get('center');
\r
26757 var viewWidth = api.getWidth();
\r
26758 var viewHeight = api.getHeight();
\r
26759 var viewSize = Math.min(viewWidth, viewHeight) / 2;
\r
26760 this.cx = numberUtil.parsePercent(center[0], viewWidth);
\r
26761 this.cy = numberUtil.parsePercent(center[1], viewHeight);
\r
26763 this.startAngle = radarModel.get('startAngle') * Math.PI / 180;
\r
26765 this.r = numberUtil.parsePercent(radarModel.get('radius'), viewSize);
\r
26767 zrUtil.each(this._indicatorAxes, function (indicatorAxis, idx) {
\r
26768 indicatorAxis.setExtent(0, this.r);
\r
26769 var angle = (this.startAngle + idx * Math.PI * 2 / this._indicatorAxes.length);
\r
26770 // Normalize to [-PI, PI]
\r
26771 angle = Math.atan2(Math.sin(angle), Math.cos(angle));
\r
26772 indicatorAxis.angle = angle;
\r
26776 Radar.prototype.update = function (ecModel, api) {
\r
26777 var indicatorAxes = this._indicatorAxes;
\r
26778 var radarModel = this._model;
\r
26779 zrUtil.each(indicatorAxes, function (indicatorAxis) {
\r
26780 indicatorAxis.scale.setExtent(Infinity, -Infinity);
\r
26782 ecModel.eachSeriesByType('radar', function (radarSeries, idx) {
\r
26783 if (radarSeries.get('coordinateSystem') !== 'radar'
\r
26784 || ecModel.getComponent('radar', radarSeries.get('radarIndex')) !== radarModel
\r
26788 var data = radarSeries.getData();
\r
26789 zrUtil.each(indicatorAxes, function (indicatorAxis) {
\r
26790 indicatorAxis.scale.unionExtent(data.getDataExtent(indicatorAxis.dim));
\r
26794 var splitNumber = radarModel.get('splitNumber');
\r
26796 function increaseInterval(interval) {
\r
26797 var exp10 = Math.pow(10, Math.floor(Math.log(interval) / Math.LN10));
\r
26798 // Increase interval
\r
26799 var f = interval / exp10;
\r
26803 else { // f is 2 or 5
\r
26806 return f * exp10;
\r
26808 // Force all the axis fixing the maxSplitNumber.
\r
26809 zrUtil.each(indicatorAxes, function (indicatorAxis, idx) {
\r
26810 var rawExtent = axisHelper.getScaleExtent(indicatorAxis, indicatorAxis.model);
\r
26811 axisHelper.niceScaleExtent(indicatorAxis, indicatorAxis.model);
\r
26813 var axisModel = indicatorAxis.model;
\r
26814 var scale = indicatorAxis.scale;
\r
26815 var fixedMin = axisModel.get('min');
\r
26816 var fixedMax = axisModel.get('max');
\r
26817 var interval = scale.getInterval();
\r
26819 if (fixedMin != null && fixedMax != null) {
\r
26820 // User set min, max, divide to get new interval
\r
26821 // FIXME precision
\r
26822 scale.setInterval(
\r
26823 (fixedMax - fixedMin) / splitNumber
\r
26826 else if (fixedMin != null) {
\r
26828 // User set min, expand extent on the other side
\r
26830 max = fixedMin + interval * splitNumber;
\r
26831 scale.setExtent(+fixedMin, max);
\r
26832 // Interval must been set after extent
\r
26834 scale.setInterval(interval);
\r
26836 interval = increaseInterval(interval);
\r
26837 } while (max < rawExtent[1] && isFinite(max) && isFinite(rawExtent[1]));
\r
26839 else if (fixedMax != null) {
\r
26841 // User set min, expand extent on the other side
\r
26843 min = fixedMax - interval * splitNumber;
\r
26844 scale.setExtent(min, +fixedMax);
\r
26845 scale.setInterval(interval);
\r
26846 interval = increaseInterval(interval);
\r
26847 } while (min > rawExtent[0] && isFinite(min) && isFinite(rawExtent[0]));
\r
26850 var nicedSplitNumber = scale.getTicks().length - 1;
\r
26851 if (nicedSplitNumber > splitNumber) {
\r
26852 interval = increaseInterval(interval);
\r
26855 var center = Math.round((rawExtent[0] + rawExtent[1]) / 2 / interval) * interval;
\r
26856 var halfSplitNumber = Math.round(splitNumber / 2);
\r
26858 numberUtil.round(center - halfSplitNumber * interval),
\r
26859 numberUtil.round(center + (splitNumber - halfSplitNumber) * interval)
\r
26861 scale.setInterval(interval);
\r
26867 * Radar dimensions is based on the data
\r
26870 Radar.dimensions = [];
\r
26872 Radar.create = function (ecModel, api) {
\r
26873 var radarList = [];
\r
26874 ecModel.eachComponent('radar', function (radarModel) {
\r
26875 var radar = new Radar(radarModel, ecModel, api);
\r
26876 radarList.push(radar);
\r
26877 radarModel.coordinateSystem = radar;
\r
26879 ecModel.eachSeriesByType('radar', function (radarSeries) {
\r
26880 if (radarSeries.get('coordinateSystem') === 'radar') {
\r
26881 // Inject coordinate system
\r
26882 radarSeries.coordinateSystem = radarList[radarSeries.get('radarIndex') || 0];
\r
26885 return radarList;
\r
26888 __webpack_require__(25).register('radar', Radar);
\r
26889 module.exports = Radar;
\r
26894 /***/ function(module, exports, __webpack_require__) {
\r
26898 var zrUtil = __webpack_require__(3);
\r
26899 var Axis = __webpack_require__(117);
\r
26901 function IndicatorAxis(dim, scale, radiusExtent) {
\r
26902 Axis.call(this, dim, scale, radiusExtent);
\r
26912 this.type = 'value';
\r
26922 * @type {module:echarts/model/Model}
\r
26927 zrUtil.inherits(IndicatorAxis, Axis);
\r
26929 module.exports = IndicatorAxis;
\r
26934 /***/ function(module, exports, __webpack_require__) {
\r
26939 var axisDefault = __webpack_require__(122);
\r
26940 var valueAxisDefault = axisDefault.valueAxis;
\r
26941 var Model = __webpack_require__(8);
\r
26942 var zrUtil = __webpack_require__(3);
\r
26944 var axisModelCommonMixin = __webpack_require__(123);
\r
26946 function defaultsShow(opt, show) {
\r
26947 return zrUtil.defaults({
\r
26952 var RadarModel = __webpack_require__(1).extendComponentModel({
\r
26956 optionUpdated: function () {
\r
26957 var boundaryGap = this.get('boundaryGap');
\r
26958 var splitNumber = this.get('splitNumber');
\r
26959 var scale = this.get('scale');
\r
26960 var axisLine = this.get('axisLine');
\r
26961 var axisTick = this.get('axisTick');
\r
26962 var axisLabel = this.get('axisLabel');
\r
26963 var nameTextStyle = this.get('name.textStyle');
\r
26964 var showName = this.get('name.show');
\r
26965 var nameFormatter = this.get('name.formatter');
\r
26966 var nameGap = this.get('nameGap');
\r
26967 var indicatorModels = zrUtil.map(this.get('indicator') || [], function (indicatorOpt) {
\r
26969 if (indicatorOpt.max != null && indicatorOpt.max > 0) {
\r
26970 indicatorOpt.min = 0;
\r
26972 else if (indicatorOpt.min != null && indicatorOpt.min < 0) {
\r
26973 indicatorOpt.max = 0;
\r
26975 // Use same configuration
\r
26976 indicatorOpt = zrUtil.merge(zrUtil.clone(indicatorOpt), {
\r
26977 boundaryGap: boundaryGap,
\r
26978 splitNumber: splitNumber,
\r
26980 axisLine: axisLine,
\r
26981 axisTick: axisTick,
\r
26982 axisLabel: axisLabel,
\r
26983 // Competitable with 2 and use text
\r
26984 name: indicatorOpt.text,
\r
26985 nameLocation: 'end',
\r
26986 nameGap: nameGap,
\r
26988 nameTextStyle: nameTextStyle
\r
26991 indicatorOpt.name = '';
\r
26993 if (typeof nameFormatter === 'string') {
\r
26994 indicatorOpt.name = nameFormatter.replace('{value}', indicatorOpt.name);
\r
26996 else if (typeof nameFormatter === 'function') {
\r
26997 indicatorOpt.name = nameFormatter(
\r
26998 indicatorOpt.name, indicatorOpt
\r
27001 return zrUtil.extend(
\r
27002 new Model(indicatorOpt, null, this.ecModel),
\r
27003 axisModelCommonMixin
\r
27006 this.getIndicatorModels = function () {
\r
27007 return indicatorModels;
\r
27017 center: ['50%', '50%'],
\r
27025 // formatter: null
\r
27029 boundaryGap: [0, 0],
\r
27037 // Polygon or circle
\r
27038 shape: 'polygon',
\r
27040 axisLine: zrUtil.merge(
\r
27046 valueAxisDefault.axisLine
\r
27048 axisLabel: defaultsShow(valueAxisDefault.axisLabel, false),
\r
27049 axisTick: defaultsShow(valueAxisDefault.axisTick, false),
\r
27050 splitLine: defaultsShow(valueAxisDefault.splitLine, true),
\r
27051 splitArea: defaultsShow(valueAxisDefault.splitArea, true),
\r
27053 // {text, min, max}
\r
27058 module.exports = RadarModel;
\r
27063 /***/ function(module, exports, __webpack_require__) {
\r
27067 var AxisBuilder = __webpack_require__(126);
\r
27068 var zrUtil = __webpack_require__(3);
\r
27069 var graphic = __webpack_require__(42);
\r
27071 var axisBuilderAttrs = [
\r
27072 'axisLine', 'axisLabel', 'axisTick', 'axisName'
\r
27075 module.exports = __webpack_require__(1).extendComponentView({
\r
27079 render: function (radarModel, ecModel, api) {
\r
27080 var group = this.group;
\r
27081 group.removeAll();
\r
27083 this._buildAxes(radarModel);
\r
27084 this._buildSplitLineAndArea(radarModel);
\r
27087 _buildAxes: function (radarModel) {
\r
27088 var radar = radarModel.coordinateSystem;
\r
27089 var indicatorAxes = radar.getIndicatorAxes();
\r
27090 var axisBuilders = zrUtil.map(indicatorAxes, function (indicatorAxis) {
\r
27091 var axisBuilder = new AxisBuilder(indicatorAxis.model, {
\r
27092 position: [radar.cx, radar.cy],
\r
27093 rotation: indicatorAxis.angle,
\r
27094 labelDirection: -1,
\r
27095 tickDirection: -1,
\r
27098 return axisBuilder;
\r
27101 zrUtil.each(axisBuilders, function (axisBuilder) {
\r
27102 zrUtil.each(axisBuilderAttrs, axisBuilder.add, axisBuilder);
\r
27103 this.group.add(axisBuilder.getGroup());
\r
27107 _buildSplitLineAndArea: function (radarModel) {
\r
27108 var radar = radarModel.coordinateSystem;
\r
27109 var splitNumber = radarModel.get('splitNumber');
\r
27110 var indicatorAxes = radar.getIndicatorAxes();
\r
27111 if (!indicatorAxes.length) {
\r
27114 var shape = radarModel.get('shape');
\r
27115 var splitLineModel = radarModel.getModel('splitLine');
\r
27116 var splitAreaModel = radarModel.getModel('splitArea');
\r
27117 var lineStyleModel = splitLineModel.getModel('lineStyle');
\r
27118 var areaStyleModel = splitAreaModel.getModel('areaStyle');
\r
27120 var showSplitLine = splitLineModel.get('show');
\r
27121 var showSplitArea = splitAreaModel.get('show');
\r
27122 var splitLineColors = lineStyleModel.get('color');
\r
27123 var splitAreaColors = areaStyleModel.get('color');
\r
27125 splitLineColors = zrUtil.isArray(splitLineColors) ? splitLineColors : [splitLineColors];
\r
27126 splitAreaColors = zrUtil.isArray(splitAreaColors) ? splitAreaColors : [splitAreaColors];
\r
27128 var splitLines = [];
\r
27129 var splitAreas = [];
\r
27131 function getColorIndex(areaOrLine, areaOrLineColorList, idx) {
\r
27132 var colorIndex = idx % areaOrLineColorList.length;
\r
27133 areaOrLine[colorIndex] = areaOrLine[colorIndex] || [];
\r
27134 return colorIndex;
\r
27137 if (shape === 'circle') {
\r
27138 var ticksRadius = indicatorAxes[0].getTicksCoords();
\r
27139 var cx = radar.cx;
\r
27140 var cy = radar.cy;
\r
27141 for (var i = 0; i < ticksRadius.length; i++) {
\r
27142 if (showSplitLine) {
\r
27143 var colorIndex = getColorIndex(splitLines, splitLineColors, i);
\r
27144 splitLines[colorIndex].push(new graphic.Circle({
\r
27148 r: ticksRadius[i]
\r
27152 if (showSplitArea && i < ticksRadius.length - 1) {
\r
27153 var colorIndex = getColorIndex(splitAreas, splitAreaColors, i);
\r
27154 splitAreas[colorIndex].push(new graphic.Ring({
\r
27158 r0: ticksRadius[i],
\r
27159 r: ticksRadius[i + 1]
\r
27167 var axesTicksPoints = zrUtil.map(indicatorAxes, function (indicatorAxis, idx) {
\r
27168 var ticksCoords = indicatorAxis.getTicksCoords();
\r
27169 return zrUtil.map(ticksCoords, function (tickCoord) {
\r
27170 return radar.coordToPoint(tickCoord, idx);
\r
27174 var prevPoints = [];
\r
27175 for (var i = 0; i <= splitNumber; i++) {
\r
27177 for (var j = 0; j < indicatorAxes.length; j++) {
\r
27178 points.push(axesTicksPoints[j][i]);
\r
27181 points.push(points[0].slice());
\r
27182 if (showSplitLine) {
\r
27183 var colorIndex = getColorIndex(splitLines, splitLineColors, i);
\r
27184 splitLines[colorIndex].push(new graphic.Polyline({
\r
27190 if (showSplitArea && prevPoints) {
\r
27191 var colorIndex = getColorIndex(splitAreas, splitAreaColors, i - 1);
\r
27192 splitAreas[colorIndex].push(new graphic.Polygon({
\r
27194 points: points.concat(prevPoints)
\r
27198 prevPoints = points.slice().reverse();
\r
27202 var lineStyle = lineStyleModel.getLineStyle();
\r
27203 var areaStyle = areaStyleModel.getAreaStyle();
\r
27204 // Add splitArea before splitLine
\r
27205 zrUtil.each(splitAreas, function (splitAreas, idx) {
\r
27206 this.group.add(graphic.mergePath(
\r
27208 style: zrUtil.defaults({
\r
27210 fill: splitAreaColors[idx % splitAreaColors.length]
\r
27217 zrUtil.each(splitLines, function (splitLines, idx) {
\r
27218 this.group.add(graphic.mergePath(
\r
27220 style: zrUtil.defaults({
\r
27222 stroke: splitLineColors[idx % splitLineColors.length]
\r
27235 /***/ function(module, exports, __webpack_require__) {
\r
27240 var SeriesModel = __webpack_require__(27);
\r
27241 var List = __webpack_require__(94);
\r
27242 var completeDimensions = __webpack_require__(96);
\r
27243 var zrUtil = __webpack_require__(3);
\r
27244 var formatUtil = __webpack_require__(6);
\r
27246 var RadarSeries = SeriesModel.extend({
\r
27248 type: 'series.radar',
\r
27250 dependencies: ['radar'],
\r
27254 init: function (option) {
\r
27255 RadarSeries.superApply(this, 'init', arguments);
\r
27257 // Enable legend selection for each data item
\r
27258 // Use a function instead of direct access because data reference may changed
\r
27259 this.legendDataProvider = function () {
\r
27260 return this._dataBeforeProcessed;
\r
27264 getInitialData: function (option, ecModel) {
\r
27265 var data = option.data || [];
\r
27266 var dimensions = completeDimensions(
\r
27267 [], data, [], 'indicator_'
\r
27269 var list = new List(dimensions, this);
\r
27270 list.initData(data);
\r
27274 formatTooltip: function (dataIndex) {
\r
27275 var value = this.getRawValue(dataIndex);
\r
27276 var coordSys = this.coordinateSystem;
\r
27277 var indicatorAxes = coordSys.getIndicatorAxes();
\r
27278 return this._data.getName(dataIndex) + '<br />'
\r
27279 + zrUtil.map(indicatorAxes, function (axis, idx) {
\r
27280 return axis.name + ' : ' + value[idx];
\r
27281 }).join('<br />');
\r
27284 getFormattedLabel: function (dataIndex, status, formatter, indicatorIndex) {
\r
27285 status = status || 'normal';
\r
27286 var data = this.getData();
\r
27287 var itemModel = data.getItemModel(dataIndex);
\r
27289 var params = this.getDataParams(dataIndex);
\r
27290 if (formatter == null) {
\r
27291 formatter = itemModel.get(['label', status, 'formatter']);
\r
27293 // Get value of specified indicator
\r
27294 params.value = params.value[indicatorIndex || 0];
\r
27295 if (typeof formatter === 'function') {
\r
27296 params.status = status;
\r
27297 return formatter(params);
\r
27299 else if (typeof formatter === 'string') {
\r
27300 return formatUtil.formatTpl(formatter, params);
\r
27307 coordinateSystem: 'radar',
\r
27308 legendHoverLink: true,
\r
27324 symbol: 'emptyCircle',
\r
27326 // symbolRotate: null
\r
27330 module.exports = RadarSeries;
\r
27335 /***/ function(module, exports, __webpack_require__) {
\r
27339 var graphic = __webpack_require__(42);
\r
27340 var zrUtil = __webpack_require__(3);
\r
27341 var symbolUtil = __webpack_require__(100);
\r
27343 function normalizeSymbolSize(symbolSize) {
\r
27344 if (!zrUtil.isArray(symbolSize)) {
\r
27345 symbolSize = [+symbolSize, +symbolSize];
\r
27347 return symbolSize;
\r
27349 module.exports = __webpack_require__(1).extendChartView({
\r
27352 render: function (seriesModel, ecModel, api) {
\r
27353 var polar = seriesModel.coordinateSystem;
\r
27354 var group = this.group;
\r
27356 var data = seriesModel.getData();
\r
27357 var oldData = this._data;
\r
27359 function createSymbol(data, idx) {
\r
27360 var symbolType = data.getItemVisual(idx, 'symbol') || 'circle';
\r
27361 var color = data.getItemVisual(idx, 'color');
\r
27362 if (symbolType === 'none') {
\r
27365 var symbolPath = symbolUtil.createSymbol(
\r
27366 symbolType, -0.5, -0.5, 1, 1, color
\r
27368 symbolPath.attr({
\r
27370 strokeNoScale: true
\r
27373 scale: normalizeSymbolSize(data.getItemVisual(idx, 'symbolSize'))
\r
27375 return symbolPath;
\r
27378 function updateSymbols(oldPoints, newPoints, symbolGroup, data, idx, isInit) {
\r
27379 // Simply rerender all
\r
27380 symbolGroup.removeAll();
\r
27381 for (var i = 0; i < newPoints.length - 1; i++) {
\r
27382 var symbolPath = createSymbol(data, idx);
\r
27383 if (symbolPath) {
\r
27384 symbolPath.__dimIdx = i;
\r
27385 if (oldPoints[i]) {
\r
27386 symbolPath.attr('position', oldPoints[i]);
\r
27387 graphic[isInit ? 'initProps' : 'updateProps'](
\r
27389 position: newPoints[i]
\r
27394 symbolPath.attr('position', newPoints[i]);
\r
27396 symbolGroup.add(symbolPath);
\r
27401 function getInitialPoints(points) {
\r
27402 return zrUtil.map(points, function (pt) {
\r
27403 return [polar.cx, polar.cy];
\r
27406 data.diff(oldData)
\r
27407 .add(function (idx) {
\r
27408 var points = data.getItemLayout(idx);
\r
27412 var polygon = new graphic.Polygon();
\r
27413 var polyline = new graphic.Polyline();
\r
27419 polygon.shape.points = getInitialPoints(points);
\r
27420 polyline.shape.points = getInitialPoints(points);
\r
27421 graphic.initProps(polygon, target, seriesModel);
\r
27422 graphic.initProps(polyline, target, seriesModel);
\r
27424 var itemGroup = new graphic.Group();
\r
27425 var symbolGroup = new graphic.Group();
\r
27426 itemGroup.add(polyline);
\r
27427 itemGroup.add(polygon);
\r
27428 itemGroup.add(symbolGroup);
\r
27431 polyline.shape.points, points, symbolGroup, data, idx, true
\r
27434 data.setItemGraphicEl(idx, itemGroup);
\r
27436 .update(function (newIdx, oldIdx) {
\r
27437 var itemGroup = oldData.getItemGraphicEl(oldIdx);
\r
27438 var polyline = itemGroup.childAt(0);
\r
27439 var polygon = itemGroup.childAt(1);
\r
27440 var symbolGroup = itemGroup.childAt(2);
\r
27443 points: data.getItemLayout(newIdx)
\r
27446 if (!target.shape.points) {
\r
27450 polyline.shape.points, target.shape.points, symbolGroup, data, newIdx, false
\r
27453 graphic.updateProps(polyline, target, seriesModel);
\r
27454 graphic.updateProps(polygon, target, seriesModel);
\r
27456 data.setItemGraphicEl(newIdx, itemGroup);
\r
27458 .remove(function (idx) {
\r
27459 group.remove(oldData.getItemGraphicEl(idx));
\r
27463 data.eachItemGraphicEl(function (itemGroup, idx) {
\r
27464 var itemModel = data.getItemModel(idx);
\r
27465 var polyline = itemGroup.childAt(0);
\r
27466 var polygon = itemGroup.childAt(1);
\r
27467 var symbolGroup = itemGroup.childAt(2);
\r
27468 var color = data.getItemVisual(idx, 'color');
\r
27470 group.add(itemGroup);
\r
27472 polyline.setStyle(
\r
27474 itemModel.getModel('lineStyle.normal').getLineStyle(),
\r
27480 polyline.hoverStyle = itemModel.getModel('lineStyle.emphasis').getLineStyle();
\r
27482 var areaStyleModel = itemModel.getModel('areaStyle.normal');
\r
27483 var hoverAreaStyleModel = itemModel.getModel('areaStyle.emphasis');
\r
27484 var polygonIgnore = areaStyleModel.isEmpty() && areaStyleModel.parentModel.isEmpty();
\r
27485 var hoverPolygonIgnore = hoverAreaStyleModel.isEmpty() && hoverAreaStyleModel.parentModel.isEmpty();
\r
27487 hoverPolygonIgnore = hoverPolygonIgnore && polygonIgnore;
\r
27488 polygon.ignore = polygonIgnore;
\r
27490 polygon.setStyle(
\r
27492 areaStyleModel.getAreaStyle(),
\r
27499 polygon.hoverStyle = hoverAreaStyleModel.getAreaStyle();
\r
27501 var itemStyle = itemModel.getModel('itemStyle.normal').getItemStyle(['color']);
\r
27502 var itemHoverStyle = itemModel.getModel('itemStyle.emphasis').getItemStyle();
\r
27503 var labelModel = itemModel.getModel('label.normal');
\r
27504 var labelHoverModel = itemModel.getModel('label.emphasis');
\r
27505 symbolGroup.eachChild(function (symbolPath) {
\r
27506 symbolPath.setStyle(itemStyle);
\r
27507 symbolPath.hoverStyle = zrUtil.clone(itemHoverStyle);
\r
27509 var defaultText = data.get(data.dimensions[symbolPath.__dimIdx], idx);
\r
27510 graphic.setText(symbolPath.style, labelModel, color);
\r
27511 symbolPath.setStyle({
\r
27512 text: labelModel.get('show') ? zrUtil.retrieve(
\r
27513 seriesModel.getFormattedLabel(
\r
27514 idx, 'normal', null, symbolPath.__dimIdx
\r
27520 graphic.setText(symbolPath.hoverStyle, labelHoverModel, color);
\r
27521 symbolPath.hoverStyle.text = labelHoverModel.get('show') ? zrUtil.retrieve(
\r
27522 seriesModel.getFormattedLabel(
\r
27523 idx, 'emphasis', null, symbolPath.__dimIdx
\r
27529 function onEmphasis() {
\r
27530 polygon.attr('ignore', hoverPolygonIgnore);
\r
27533 function onNormal() {
\r
27534 polygon.attr('ignore', polygonIgnore);
\r
27537 itemGroup.off('mouseover').off('mouseout').off('normal').off('emphasis');
\r
27538 itemGroup.on('emphasis', onEmphasis)
\r
27539 .on('mouseover', onEmphasis)
\r
27540 .on('normal', onNormal)
\r
27541 .on('mouseout', onNormal);
\r
27543 graphic.setHoverStyle(itemGroup);
\r
27546 this._data = data;
\r
27549 remove: function () {
\r
27550 this.group.removeAll();
\r
27551 this._data = null;
\r
27558 /***/ function(module, exports) {
\r
27562 module.exports = function (ecModel, api) {
\r
27563 ecModel.eachSeriesByType('radar', function (seriesModel) {
\r
27564 var data = seriesModel.getData();
\r
27566 var coordSys = seriesModel.coordinateSystem;
\r
27571 function pointsConverter(val, idx) {
\r
27572 points[idx] = points[idx] || [];
\r
27573 points[idx][i] = coordSys.dataToPoint(val, i);
\r
27575 for (var i = 0; i < coordSys.getIndicatorAxes().length; i++) {
\r
27576 var dim = data.dimensions[i];
\r
27577 data.each(dim, pointsConverter);
\r
27580 data.each(function (idx) {
\r
27582 points[idx][0] && points[idx].push(points[idx][0].slice());
\r
27583 data.setItemLayout(idx, points[idx]);
\r
27591 /***/ function(module, exports, __webpack_require__) {
\r
27593 // Backward compat for radar chart in 2
\r
27596 var zrUtil = __webpack_require__(3);
\r
27598 module.exports = function (option) {
\r
27599 var polarOptArr = option.polar;
\r
27600 if (polarOptArr) {
\r
27601 if (!zrUtil.isArray(polarOptArr)) {
\r
27602 polarOptArr = [polarOptArr];
\r
27604 var polarNotRadar = [];
\r
27605 zrUtil.each(polarOptArr, function (polarOpt, idx) {
\r
27606 if (polarOpt.indicator) {
\r
27607 if (polarOpt.type && !polarOpt.shape) {
\r
27608 polarOpt.shape = polarOpt.type;
\r
27610 option.radar = option.radar || [];
\r
27611 if (!zrUtil.isArray(option.radar)) {
\r
27612 option.radar = [option.radar];
\r
27614 option.radar.push(polarOpt);
\r
27617 polarNotRadar.push(polarOpt);
\r
27620 option.polar = polarNotRadar;
\r
27622 zrUtil.each(option.series, function (seriesOpt) {
\r
27623 if (seriesOpt.type === 'radar' && seriesOpt.polarIndex) {
\r
27624 seriesOpt.radarIndex = seriesOpt.polarIndex;
\r
27632 /***/ function(module, exports, __webpack_require__) {
\r
27636 var echarts = __webpack_require__(1);
\r
27638 __webpack_require__(156);
\r
27640 __webpack_require__(157);
\r
27642 __webpack_require__(161);
\r
27644 __webpack_require__(163);
\r
27646 echarts.registerLayout(__webpack_require__(173));
\r
27648 echarts.registerVisualCoding('chart', __webpack_require__(174));
\r
27650 echarts.registerProcessor('statistic', __webpack_require__(175));
\r
27652 echarts.registerPreprocessor(__webpack_require__(176));
\r
27654 __webpack_require__(136)('map', [{
\r
27655 type: 'mapToggleSelect',
\r
27656 event: 'mapselectchanged',
\r
27657 method: 'toggleSelected'
\r
27659 type: 'mapSelect',
\r
27660 event: 'mapselected',
\r
27663 type: 'mapUnSelect',
\r
27664 event: 'mapunselected',
\r
27665 method: 'unSelect'
\r
27671 /***/ function(module, exports, __webpack_require__) {
\r
27675 var List = __webpack_require__(94);
\r
27676 var echarts = __webpack_require__(1);
\r
27677 var SeriesModel = __webpack_require__(27);
\r
27678 var zrUtil = __webpack_require__(3);
\r
27679 var completeDimensions = __webpack_require__(96);
\r
27681 var formatUtil = __webpack_require__(6);
\r
27682 var encodeHTML = formatUtil.encodeHTML;
\r
27683 var addCommas = formatUtil.addCommas;
\r
27685 var dataSelectableMixin = __webpack_require__(134);
\r
27687 function fillData(dataOpt, geoJson) {
\r
27688 var dataNameMap = {};
\r
27689 var features = geoJson.features;
\r
27690 for (var i = 0; i < dataOpt.length; i++) {
\r
27691 dataNameMap[dataOpt[i].name] = dataOpt[i];
\r
27694 for (var i = 0; i < features.length; i++) {
\r
27695 var name = features[i].properties.name;
\r
27696 if (!dataNameMap[name]) {
\r
27706 var MapSeries = SeriesModel.extend({
\r
27708 type: 'series.map',
\r
27711 * Only first map series of same mapType will drawMap
\r
27712 * @type {boolean}
\r
27714 needsDrawMap: false,
\r
27717 * Group of all map series with same mapType
\r
27718 * @type {boolean}
\r
27722 init: function (option) {
\r
27724 option = this._fillOption(option);
\r
27725 this.option = option;
\r
27727 MapSeries.superApply(this, 'init', arguments);
\r
27729 this.updateSelectedMap();
\r
27732 getInitialData: function (option) {
\r
27733 var dimensions = completeDimensions(['value'], option.data || []);
\r
27735 var list = new List(dimensions, this);
\r
27737 list.initData(option.data);
\r
27742 mergeOption: function (newOption) {
\r
27743 newOption = this._fillOption(newOption);
\r
27745 MapSeries.superCall(this, 'mergeOption', newOption);
\r
27747 this.updateSelectedMap();
\r
27750 _fillOption: function (option) {
\r
27752 option = zrUtil.extend({}, option);
\r
27754 var map = echarts.getMap(option.mapType);
\r
27755 var geoJson = map && map.geoJson;
\r
27756 geoJson && option.data
\r
27757 && (option.data = fillData(option.data, geoJson));
\r
27763 * @param {number} zoom
\r
27765 setRoamZoom: function (zoom) {
\r
27766 var roamDetail = this.option.roamDetail;
\r
27767 roamDetail && (roamDetail.zoom = zoom);
\r
27771 * @param {number} x
\r
27772 * @param {number} y
\r
27774 setRoamPan: function (x, y) {
\r
27775 var roamDetail = this.option.roamDetail;
\r
27776 if (roamDetail) {
\r
27777 roamDetail.x = x;
\r
27778 roamDetail.y = y;
\r
27782 getRawValue: function (dataIndex) {
\r
27783 // Use value stored in data instead because it is calculated from multiple series
\r
27784 // FIXME Provide all value of multiple series ?
\r
27785 return this._data.get('value', dataIndex);
\r
27789 * Map tooltip formatter
\r
27791 * @param {number} dataIndex
\r
27793 formatTooltip: function (dataIndex) {
\r
27794 var data = this._data;
\r
27795 var formattedValue = addCommas(this.getRawValue(dataIndex));
\r
27796 var name = data.getName(dataIndex);
\r
27798 var seriesGroup = this.seriesGroup;
\r
27799 var seriesNames = [];
\r
27800 for (var i = 0; i < seriesGroup.length; i++) {
\r
27801 if (!isNaN(seriesGroup[i].getRawValue(dataIndex))) {
\r
27802 seriesNames.push(
\r
27803 encodeHTML(seriesGroup[i].name)
\r
27808 return seriesNames.join(', ') + '<br />'
\r
27809 + name + ' : ' + formattedValue;
\r
27817 coordinateSystem: 'geo',
\r
27818 // 各省的 map 暂时都用中文
\r
27821 // 'center' | 'left' | 'right' | 'x%' | {number}
\r
27823 // 'center' | 'top' | 'bottom' | 'x%' | {number}
\r
27830 // 数值合并方式,默认加和,可选为:
\r
27831 // 'sum' | 'average' | 'max' | 'min'
\r
27832 // mapValueCalculation: 'sum',
\r
27834 // mapValuePrecision: 0,
\r
27835 // 显示图例颜色标识(系列标识的小圆点),图例开启时有效
\r
27836 showLegendSymbol: true,
\r
27837 // 选择模式,默认关闭,可选single,multiple
\r
27838 // selectedMode: false,
\r
27839 dataRangeHoverLink: true,
\r
27843 // 在 roam 开启的时候使用
\r
27850 scaleLimit: null,
\r
27866 // scaleLimit: null,
\r
27870 borderWidth: 0.5,
\r
27871 borderColor: '#444',
\r
27872 areaColor: '#eee'
\r
27876 areaColor: 'rgba(255,215, 0, 0.8)'
\r
27882 zrUtil.mixin(MapSeries, dataSelectableMixin);
\r
27884 module.exports = MapSeries;
\r
27889 /***/ function(module, exports, __webpack_require__) {
\r
27893 // var zrUtil = require('zrender/lib/core/util');
\r
27894 var graphic = __webpack_require__(42);
\r
27896 var MapDraw = __webpack_require__(158);
\r
27898 __webpack_require__(1).extendChartView({
\r
27902 render: function (mapModel, ecModel, api, payload) {
\r
27903 // Not render if it is an toggleSelect action from self
\r
27904 if (payload && payload.type === 'mapToggleSelect'
\r
27905 && payload.from === this.uid
\r
27910 var group = this.group;
\r
27911 group.removeAll();
\r
27912 // Not update map if it is an roam action from self
\r
27913 if (!(payload && payload.type === 'geoRoam'
\r
27914 && payload.component === 'series'
\r
27915 && payload.name === mapModel.name)) {
\r
27917 if (mapModel.needsDrawMap) {
\r
27918 var mapDraw = this._mapDraw || new MapDraw(api, true);
\r
27919 group.add(mapDraw.group);
\r
27921 mapDraw.draw(mapModel, ecModel, api, this);
\r
27923 this._mapDraw = mapDraw;
\r
27926 // Remove drawed map
\r
27927 this._mapDraw && this._mapDraw.remove();
\r
27928 this._mapDraw = null;
\r
27932 var mapDraw = this._mapDraw;
\r
27933 mapDraw && group.add(mapDraw.group);
\r
27936 mapModel.get('showLegendSymbol') && ecModel.getComponent('legend')
\r
27937 && this._renderSymbols(mapModel, ecModel, api);
\r
27940 remove: function () {
\r
27941 this._mapDraw && this._mapDraw.remove();
\r
27942 this._mapDraw = null;
\r
27943 this.group.removeAll();
\r
27946 _renderSymbols: function (mapModel, ecModel, api) {
\r
27947 var data = mapModel.getData();
\r
27948 var group = this.group;
\r
27950 data.each('value', function (value, idx) {
\r
27951 if (isNaN(value)) {
\r
27955 var layout = data.getItemLayout(idx);
\r
27957 if (!layout || !layout.point) {
\r
27958 // Not exists in map
\r
27962 var point = layout.point;
\r
27963 var offset = layout.offset;
\r
27965 var circle = new graphic.Circle({
\r
27967 fill: data.getVisual('color')
\r
27970 cx: point[0] + offset * 9,
\r
27978 // First data on the same region
\r
27980 var labelText = data.getName(idx);
\r
27982 var itemModel = data.getItemModel(idx);
\r
27983 var labelModel = itemModel.getModel('label.normal');
\r
27984 var hoverLabelModel = itemModel.getModel('label.emphasis');
\r
27986 var textStyleModel = labelModel.getModel('textStyle');
\r
27987 var hoverTextStyleModel = hoverLabelModel.getModel('textStyle');
\r
27989 var polygonGroups = data.getItemGraphicEl(idx);
\r
27990 circle.setStyle({
\r
27991 textPosition: 'bottom'
\r
27994 var onEmphasis = function () {
\r
27995 circle.setStyle({
\r
27996 text: hoverLabelModel.get('show') ? labelText : '',
\r
27997 textFill: hoverTextStyleModel.getTextColor(),
\r
27998 textFont: hoverTextStyleModel.getFont()
\r
28002 var onNormal = function () {
\r
28003 circle.setStyle({
\r
28004 text: labelModel.get('show') ? labelText : '',
\r
28005 textFill: textStyleModel.getTextColor(),
\r
28006 textFont: textStyleModel.getFont()
\r
28010 polygonGroups.on('mouseover', onEmphasis)
\r
28011 .on('mouseout', onNormal)
\r
28012 .on('emphasis', onEmphasis)
\r
28013 .on('normal', onNormal);
\r
28018 group.add(circle);
\r
28026 /***/ function(module, exports, __webpack_require__) {
\r
28029 * @module echarts/component/helper/MapDraw
\r
28033 var RoamController = __webpack_require__(159);
\r
28034 var graphic = __webpack_require__(42);
\r
28035 var zrUtil = __webpack_require__(3);
\r
28037 function getFixedItemStyle(model, scale) {
\r
28038 var itemStyle = model.getItemStyle();
\r
28039 var areaColor = model.get('areaColor');
\r
28041 itemStyle.fill = areaColor;
\r
28044 return itemStyle;
\r
28047 function updateMapSelectHandler(mapOrGeoModel, data, group, api, fromView) {
\r
28048 group.off('click');
\r
28049 mapOrGeoModel.get('selectedMode')
\r
28050 && group.on('click', function (e) {
\r
28051 var dataIndex = e.target.dataIndex;
\r
28052 if (dataIndex != null) {
\r
28053 var name = data.getName(dataIndex);
\r
28055 api.dispatchAction({
\r
28056 type: 'mapToggleSelect',
\r
28057 seriesIndex: mapOrGeoModel.seriesIndex,
\r
28059 from: fromView.uid
\r
28062 updateMapSelected(mapOrGeoModel, data, api);
\r
28067 function updateMapSelected(mapOrGeoModel, data) {
\r
28068 data.eachItemGraphicEl(function (el, idx) {
\r
28069 var name = data.getName(idx);
\r
28070 el.trigger(mapOrGeoModel.isSelected(name) ? 'emphasis' : 'normal');
\r
28075 * @alias module:echarts/component/helper/MapDraw
\r
28076 * @param {module:echarts/ExtensionAPI} api
\r
28077 * @param {boolean} updateGroup
\r
28079 function MapDraw(api, updateGroup) {
\r
28081 var group = new graphic.Group();
\r
28084 * @type {module:echarts/component/helper/RoamController}
\r
28087 this._controller = new RoamController(
\r
28088 api.getZr(), updateGroup ? group : null, null
\r
28092 * @type {module:zrender/container/Group}
\r
28095 this.group = group;
\r
28098 * @type {boolean}
\r
28101 this._updateGroup = updateGroup;
\r
28104 MapDraw.prototype = {
\r
28106 constructor: MapDraw,
\r
28108 draw: function (mapOrGeoModel, ecModel, api, fromView) {
\r
28110 // geoModel has no data
\r
28111 var data = mapOrGeoModel.getData && mapOrGeoModel.getData();
\r
28113 var geo = mapOrGeoModel.coordinateSystem;
\r
28115 var group = this.group;
\r
28116 group.removeAll();
\r
28118 var scale = geo.scale;
\r
28119 group.position = geo.position.slice();
\r
28120 group.scale = scale.slice();
\r
28122 var itemStyleModel;
\r
28123 var hoverItemStyleModel;
\r
28125 var hoverItemStyle;
\r
28128 var hoverLabelModel;
\r
28130 var itemStyleAccessPath = ['itemStyle', 'normal'];
\r
28131 var hoverItemStyleAccessPath = ['itemStyle', 'emphasis'];
\r
28132 var labelAccessPath = ['label', 'normal'];
\r
28133 var hoverLabelAccessPath = ['label', 'emphasis'];
\r
28135 itemStyleModel = mapOrGeoModel.getModel(itemStyleAccessPath);
\r
28136 hoverItemStyleModel = mapOrGeoModel.getModel(hoverItemStyleAccessPath);
\r
28138 itemStyle = getFixedItemStyle(itemStyleModel, scale);
\r
28139 hoverItemStyle = getFixedItemStyle(hoverItemStyleModel, scale);
\r
28141 labelModel = mapOrGeoModel.getModel(labelAccessPath);
\r
28142 hoverLabelModel = mapOrGeoModel.getModel(hoverLabelAccessPath);
\r
28145 zrUtil.each(geo.regions, function (region) {
\r
28147 var regionGroup = new graphic.Group();
\r
28149 // Use the itemStyle in data if has data
\r
28151 // FIXME If dataIdx < 0
\r
28152 dataIdx = data.indexOfName(region.name);
\r
28153 var itemModel = data.getItemModel(dataIdx);
\r
28155 // Only visual color of each item will be used. It can be encoded by dataRange
\r
28156 // But visual color of series is used in symbol drawing
\r
28158 // Visual color for each series is for the symbol draw
\r
28159 var visualColor = data.getItemVisual(dataIdx, 'color', true);
\r
28161 itemStyleModel = itemModel.getModel(itemStyleAccessPath);
\r
28162 hoverItemStyleModel = itemModel.getModel(hoverItemStyleAccessPath);
\r
28164 itemStyle = getFixedItemStyle(itemStyleModel, scale);
\r
28165 hoverItemStyle = getFixedItemStyle(hoverItemStyleModel, scale);
\r
28167 labelModel = itemModel.getModel(labelAccessPath);
\r
28168 hoverLabelModel = itemModel.getModel(hoverLabelAccessPath);
\r
28170 if (visualColor) {
\r
28171 itemStyle.fill = visualColor;
\r
28174 var textStyleModel = labelModel.getModel('textStyle');
\r
28175 var hoverTextStyleModel = hoverLabelModel.getModel('textStyle');
\r
28177 zrUtil.each(region.contours, function (contour) {
\r
28179 var polygon = new graphic.Polygon({
\r
28184 strokeNoScale: true
\r
28189 polygon.setStyle(itemStyle);
\r
28191 regionGroup.add(polygon);
\r
28195 var showLabel = labelModel.get('show');
\r
28196 var hoverShowLabel = hoverLabelModel.get('show');
\r
28198 var isDataNaN = data && isNaN(data.get('value', dataIdx));
\r
28199 var itemLayout = data && data.getItemLayout(dataIdx);
\r
28200 // In the following cases label will be drawn
\r
28201 // 1. In map series and data value is NaN
\r
28202 // 2. In geo component
\r
28203 // 4. Region has no series legendSymbol, which will be add a showLabel flag in mapSymbolLayout
\r
28205 (!data || isDataNaN && (showLabel || hoverShowLabel))
\r
28206 || (itemLayout && itemLayout.showLabel)
\r
28208 var query = data ? dataIdx : region.name;
\r
28209 var formattedStr = mapOrGeoModel.getFormattedLabel(query, 'normal');
\r
28210 var hoverFormattedStr = mapOrGeoModel.getFormattedLabel(query, 'emphasis');
\r
28211 var text = new graphic.Text({
\r
28213 text: showLabel ? (formattedStr || region.name) : '',
\r
28214 fill: textStyleModel.getTextColor(),
\r
28215 textFont: textStyleModel.getFont(),
\r
28216 textAlign: 'center',
\r
28217 textVerticalAlign: 'middle'
\r
28220 text: hoverShowLabel ? (hoverFormattedStr || region.name) : '',
\r
28221 fill: hoverTextStyleModel.getTextColor(),
\r
28222 textFont: hoverTextStyleModel.getFont()
\r
28224 position: region.center.slice(),
\r
28225 scale: [1 / scale[0], 1 / scale[1]],
\r
28230 regionGroup.add(text);
\r
28233 // setItemGraphicEl, setHoverStyle after all polygons and labels
\r
28234 // are added to the rigionGroup
\r
28235 data && data.setItemGraphicEl(dataIdx, regionGroup);
\r
28237 graphic.setHoverStyle(regionGroup, hoverItemStyle);
\r
28239 group.add(regionGroup);
\r
28242 this._updateController(mapOrGeoModel, ecModel, api);
\r
28244 data && updateMapSelectHandler(mapOrGeoModel, data, group, api, fromView);
\r
28246 data && updateMapSelected(mapOrGeoModel, data);
\r
28249 remove: function () {
\r
28250 this.group.removeAll();
\r
28251 this._controller.dispose();
\r
28254 _updateController: function (mapOrGeoModel, ecModel, api) {
\r
28255 var geo = mapOrGeoModel.coordinateSystem;
\r
28256 var controller = this._controller;
\r
28257 controller.zoomLimit = mapOrGeoModel.get('scaleLimit');
\r
28258 // Update zoom from model
\r
28259 controller.zoom = mapOrGeoModel.get('roamDetail.zoom');
\r
28260 // roamType is will be set default true if it is null
\r
28261 controller.enable(mapOrGeoModel.get('roam') || false);
\r
28262 // FIXME mainType, subType 作为 component 的属性?
\r
28263 var mainType = mapOrGeoModel.type.split('.')[0];
\r
28264 controller.off('pan')
\r
28265 .on('pan', function (dx, dy) {
\r
28266 api.dispatchAction({
\r
28268 component: mainType,
\r
28269 name: mapOrGeoModel.name,
\r
28274 controller.off('zoom')
\r
28275 .on('zoom', function (zoom, mouseX, mouseY) {
\r
28276 api.dispatchAction({
\r
28278 component: mainType,
\r
28279 name: mapOrGeoModel.name,
\r
28285 if (this._updateGroup) {
\r
28286 var group = this.group;
\r
28287 var scale = group.scale;
\r
28288 group.traverse(function (el) {
\r
28289 if (el.type === 'text') {
\r
28290 el.attr('scale', [1 / scale[0], 1 / scale[1]]);
\r
28296 controller.rect = geo.getViewRect();
\r
28300 module.exports = MapDraw;
\r
28305 /***/ function(module, exports, __webpack_require__) {
\r
28308 * @module echarts/component/helper/RoamController
\r
28313 var Eventful = __webpack_require__(32);
\r
28314 var zrUtil = __webpack_require__(3);
\r
28315 var eventTool = __webpack_require__(80);
\r
28316 var interactionMutex = __webpack_require__(160);
\r
28318 function mousedown(e) {
\r
28319 if (e.target && e.target.draggable) {
\r
28323 var x = e.offsetX;
\r
28324 var y = e.offsetY;
\r
28325 var rect = this.rect;
\r
28326 if (rect && rect.contain(x, y)) {
\r
28329 this._dragging = true;
\r
28333 function mousemove(e) {
\r
28334 if (!this._dragging) {
\r
28338 eventTool.stop(e.event);
\r
28340 if (e.gestureEvent !== 'pinch') {
\r
28342 if (interactionMutex.isTaken('globalPan', this._zr)) {
\r
28346 var x = e.offsetX;
\r
28347 var y = e.offsetY;
\r
28349 var dx = x - this._x;
\r
28350 var dy = y - this._y;
\r
28355 var target = this.target;
\r
28358 var pos = target.position;
\r
28364 eventTool.stop(e.event);
\r
28365 this.trigger('pan', dx, dy);
\r
28369 function mouseup(e) {
\r
28370 this._dragging = false;
\r
28373 function mousewheel(e) {
\r
28374 eventTool.stop(e.event);
\r
28376 // Mac and VM Windows on Mac: scroll up: zoom out.
\r
28377 // Windows: scroll up: zoom in.
\r
28378 var zoomDelta = e.wheelDelta > 0 ? 1.1 : 1 / 1.1;
\r
28379 zoom.call(this, e, zoomDelta, e.offsetX, e.offsetY);
\r
28382 function pinch(e) {
\r
28383 if (interactionMutex.isTaken('globalPan', this._zr)) {
\r
28387 eventTool.stop(e.event);
\r
28388 var zoomDelta = e.pinchScale > 1 ? 1.1 : 1 / 1.1;
\r
28389 zoom.call(this, e, zoomDelta, e.pinchX, e.pinchY);
\r
28392 function zoom(e, zoomDelta, zoomX, zoomY) {
\r
28393 var rect = this.rect;
\r
28395 if (rect && rect.contain(zoomX, zoomY)) {
\r
28397 var target = this.target;
\r
28398 var zoomLimit = this.zoomLimit;
\r
28401 var pos = target.position;
\r
28402 var scale = target.scale;
\r
28404 var newZoom = this.zoom = this.zoom || 1;
\r
28405 newZoom *= zoomDelta;
\r
28407 newZoom = Math.max(
\r
28408 Math.min(zoomLimit.max, newZoom),
\r
28412 var zoomScale = newZoom / this.zoom;
\r
28413 this.zoom = newZoom;
\r
28414 // Keep the mouse center when scaling
\r
28415 pos[0] -= (zoomX - pos[0]) * (zoomScale - 1);
\r
28416 pos[1] -= (zoomY - pos[1]) * (zoomScale - 1);
\r
28417 scale[0] *= zoomScale;
\r
28418 scale[1] *= zoomScale;
\r
28423 this.trigger('zoom', zoomDelta, zoomX, zoomY);
\r
28428 * @alias module:echarts/component/helper/RoamController
\r
28430 * @mixin {module:zrender/mixin/Eventful}
\r
28432 * @param {module:zrender/zrender~ZRender} zr
\r
28433 * @param {module:zrender/Element} target
\r
28434 * @param {module:zrender/core/BoundingRect} rect
\r
28436 function RoamController(zr, target, rect) {
\r
28439 * @type {module:zrender/Element}
\r
28441 this.target = target;
\r
28444 * @type {module:zrender/core/BoundingRect}
\r
28446 this.rect = rect;
\r
28449 * { min: 1, max: 2 }
\r
28459 * @type {module:zrender}
\r
28463 // Avoid two roamController bind the same handler
\r
28464 var bind = zrUtil.bind;
\r
28465 var mousedownHandler = bind(mousedown, this);
\r
28466 var mousemoveHandler = bind(mousemove, this);
\r
28467 var mouseupHandler = bind(mouseup, this);
\r
28468 var mousewheelHandler = bind(mousewheel, this);
\r
28469 var pinchHandler = bind(pinch, this);
\r
28471 Eventful.call(this);
\r
28474 * Notice: only enable needed types. For example, if 'zoom'
\r
28475 * is not needed, 'zoom' should not be enabled, otherwise
\r
28476 * default mousewheel behaviour (scroll page) will be disabled.
\r
28478 * @param {boolean|string} [controlType=true] Specify the control type,
\r
28479 * which can be null/undefined or true/false
\r
28480 * or 'pan/move' or 'zoom'/'scale'
\r
28482 this.enable = function (controlType) {
\r
28483 // Disable previous first
\r
28486 if (controlType == null) {
\r
28487 controlType = true;
\r
28490 if (controlType === true || (controlType === 'move' || controlType === 'pan')) {
\r
28491 zr.on('mousedown', mousedownHandler);
\r
28492 zr.on('mousemove', mousemoveHandler);
\r
28493 zr.on('mouseup', mouseupHandler);
\r
28495 if (controlType === true || (controlType === 'scale' || controlType === 'zoom')) {
\r
28496 zr.on('mousewheel', mousewheelHandler);
\r
28497 zr.on('pinch', pinchHandler);
\r
28501 this.disable = function () {
\r
28502 zr.off('mousedown', mousedownHandler);
\r
28503 zr.off('mousemove', mousemoveHandler);
\r
28504 zr.off('mouseup', mouseupHandler);
\r
28505 zr.off('mousewheel', mousewheelHandler);
\r
28506 zr.off('pinch', pinchHandler);
\r
28509 this.dispose = this.disable;
\r
28511 this.isDragging = function () {
\r
28512 return this._dragging;
\r
28515 this.isPinching = function () {
\r
28516 return this._pinching;
\r
28520 zrUtil.mixin(RoamController, Eventful);
\r
28522 module.exports = RoamController;
\r
28527 /***/ function(module, exports) {
\r
28531 var ATTR = '\0_ec_interaction_mutex';
\r
28533 var interactionMutex = {
\r
28535 take: function (key, zr) {
\r
28536 getStore(zr)[key] = true;
\r
28539 release: function (key, zr) {
\r
28540 getStore(zr)[key] = false;
\r
28543 isTaken: function (key, zr) {
\r
28544 return !!getStore(zr)[key];
\r
28548 function getStore(zr) {
\r
28549 return zr[ATTR] || (zr[ATTR] = {});
\r
28552 module.exports = interactionMutex;
\r
28557 /***/ function(module, exports, __webpack_require__) {
\r
28561 var zrUtil = __webpack_require__(3);
\r
28562 var roamHelper = __webpack_require__(162);
\r
28564 var echarts = __webpack_require__(1);
\r
28565 var actionInfo = {
\r
28567 event: 'geoRoam',
\r
28568 update: 'updateLayout'
\r
28573 * @property {string} [component=series]
\r
28574 * @property {string} name Component name
\r
28575 * @property {number} [dx]
\r
28576 * @property {number} [dy]
\r
28577 * @property {number} [zoom]
\r
28578 * @property {number} [originX]
\r
28579 * @property {number} [originY]
\r
28581 echarts.registerAction(actionInfo, function (payload, ecModel) {
\r
28582 var componentType = payload.component || 'series';
\r
28584 ecModel.eachComponent(componentType, function (componentModel) {
\r
28585 if (componentModel.name === payload.name) {
\r
28586 var geo = componentModel.coordinateSystem;
\r
28587 if (geo.type !== 'geo') {
\r
28591 var roamDetailModel = componentModel.getModel('roamDetail');
\r
28592 var res = roamHelper.calcPanAndZoom(
\r
28593 roamDetailModel, payload, componentModel.get('scaleLimit')
\r
28596 componentModel.setRoamPan
\r
28597 && componentModel.setRoamPan(res.x, res.y);
\r
28599 componentModel.setRoamZoom
\r
28600 && componentModel.setRoamZoom(res.zoom);
\r
28602 geo && geo.setPan(res.x, res.y);
\r
28603 geo && geo.setZoom(res.zoom);
\r
28605 // All map series with same `map` use the same geo coordinate system
\r
28606 // So the roamDetail must be in sync. Include the series not selected by legend
\r
28607 if (componentType === 'series') {
\r
28608 zrUtil.each(componentModel.seriesGroup, function (seriesModel) {
\r
28609 seriesModel.setRoamPan(res.x, res.y);
\r
28610 seriesModel.setRoamZoom(res.zoom);
\r
28620 /***/ function(module, exports) {
\r
28624 var roamHelper = {};
\r
28627 * Calculate pan and zoom which from roamDetail model
\r
28628 * @param {module:echarts/model/Model} roamDetailModel
\r
28629 * @param {Object} payload
\r
28630 * @param {Object} [zoomLimit]
\r
28632 roamHelper.calcPanAndZoom = function (
\r
28633 roamDetailModel, payload, zoomLimit
\r
28635 var dx = payload.dx;
\r
28636 var dy = payload.dy;
\r
28637 var zoom = payload.zoom;
\r
28639 var panX = roamDetailModel.get('x') || 0;
\r
28640 var panY = roamDetailModel.get('y') || 0;
\r
28642 var previousZoom = roamDetailModel.get('zoom') || 1;
\r
28644 if (dx != null && dy != null) {
\r
28648 if (zoom != null) {
\r
28651 Math.min(previousZoom * zoom, zoomLimit.max),
\r
28653 ) / previousZoom;
\r
28655 var fixX = (payload.originX - panX) * (zoom - 1);
\r
28656 var fixY = (payload.originY - panY) * (zoom - 1);
\r
28665 zoom: (zoom || 1) * previousZoom
\r
28669 module.exports = roamHelper;
\r
28674 /***/ function(module, exports, __webpack_require__) {
\r
28678 __webpack_require__(164);
\r
28680 var Geo = __webpack_require__(165);
\r
28682 var layout = __webpack_require__(21);
\r
28683 var zrUtil = __webpack_require__(3);
\r
28685 var mapDataStores = {};
\r
28688 * Resize method bound to the geo
\r
28689 * @param {module:echarts/coord/geo/GeoModel|module:echarts/chart/map/MapModel} geoModel
\r
28690 * @param {module:echarts/ExtensionAPI} api
\r
28692 function resizeGeo (geoModel, api) {
\r
28693 var rect = this.getBoundingRect();
\r
28695 var boxLayoutOption = geoModel.getBoxLayoutParams();
\r
28697 boxLayoutOption.aspect = rect.width / rect.height * 0.75;
\r
28699 var viewRect = layout.getLayoutRect(boxLayoutOption, {
\r
28700 width: api.getWidth(),
\r
28701 height: api.getHeight()
\r
28704 this.setViewRect(viewRect.x, viewRect.y, viewRect.width, viewRect.height);
\r
28706 var roamDetailModel = geoModel.getModel('roamDetail');
\r
28708 var panX = roamDetailModel.get('x') || 0;
\r
28709 var panY = roamDetailModel.get('y') || 0;
\r
28710 var zoom = roamDetailModel.get('zoom') || 1;
\r
28712 this.setPan(panX, panY);
\r
28713 this.setZoom(zoom);
\r
28717 * @param {module:echarts/coord/Geo} geo
\r
28718 * @param {module:echarts/model/Model} model
\r
28721 function setGeoCoords(geo, model) {
\r
28722 zrUtil.each(model.get('geoCoord'), function (geoCoord, name) {
\r
28723 geo.addGeoCoord(name, geoCoord);
\r
28727 function mapNotExistsError(name) {
\r
28728 console.error('Map ' + name + ' not exists');
\r
28731 var geoCreator = {
\r
28733 // For deciding which dimensions to use when creating list data
\r
28734 dimensions: Geo.prototype.dimensions,
\r
28736 create: function (ecModel, api) {
\r
28737 var geoList = [];
\r
28739 // FIXME Create each time may be slow
\r
28740 ecModel.eachComponent('geo', function (geoModel, idx) {
\r
28741 var name = geoModel.get('map');
\r
28742 var mapData = mapDataStores[name];
\r
28744 mapNotExistsError(name);
\r
28746 var geo = new Geo(
\r
28747 name + idx, name,
\r
28748 mapData && mapData.geoJson, mapData && mapData.specialAreas,
\r
28749 geoModel.get('nameMap')
\r
28751 geo.zoomLimit = geoModel.get('scaleLimit');
\r
28752 geoList.push(geo);
\r
28754 setGeoCoords(geo, geoModel);
\r
28756 geoModel.coordinateSystem = geo;
\r
28757 geo.model = geoModel;
\r
28759 // Inject resize method
\r
28760 geo.resize = resizeGeo;
\r
28762 geo.resize(geoModel, api);
\r
28765 ecModel.eachSeries(function (seriesModel) {
\r
28766 var coordSys = seriesModel.get('coordinateSystem');
\r
28767 if (coordSys === 'geo') {
\r
28768 var geoIndex = seriesModel.get('geoIndex') || 0;
\r
28769 seriesModel.coordinateSystem = geoList[geoIndex];
\r
28773 // If has map series
\r
28774 var mapModelGroupBySeries = {};
\r
28776 ecModel.eachSeriesByType('map', function (seriesModel) {
\r
28777 var mapType = seriesModel.get('map');
\r
28779 mapModelGroupBySeries[mapType] = mapModelGroupBySeries[mapType] || [];
\r
28781 mapModelGroupBySeries[mapType].push(seriesModel);
\r
28784 zrUtil.each(mapModelGroupBySeries, function (mapSeries, mapType) {
\r
28785 var mapData = mapDataStores[mapType];
\r
28787 mapNotExistsError(name);
\r
28790 var nameMapList = zrUtil.map(mapSeries, function (singleMapSeries) {
\r
28791 return singleMapSeries.get('nameMap');
\r
28793 var geo = new Geo(
\r
28794 mapType, mapType,
\r
28795 mapData && mapData.geoJson, mapData && mapData.specialAreas,
\r
28796 zrUtil.mergeAll(nameMapList)
\r
28798 geo.zoomLimit = zrUtil.retrieve.apply(null, zrUtil.map(mapSeries, function (singleMapSeries) {
\r
28799 return singleMapSeries.get('scaleLimit');
\r
28801 geoList.push(geo);
\r
28803 // Inject resize method
\r
28804 geo.resize = resizeGeo;
\r
28806 geo.resize(mapSeries[0], api);
\r
28808 zrUtil.each(mapSeries, function (singleMapSeries) {
\r
28809 singleMapSeries.coordinateSystem = geo;
\r
28811 setGeoCoords(geo, singleMapSeries);
\r
28819 * @param {string} mapName
\r
28820 * @param {Object|string} geoJson
\r
28821 * @param {Object} [specialAreas]
\r
28824 * $.get('USA.json', function (geoJson) {
\r
28825 * echarts.registerMap('USA', geoJson);
\r
28827 * echarts.registerMap('USA', {
\r
28828 * geoJson: geoJson,
\r
28829 * specialAreas: {}
\r
28833 registerMap: function (mapName, geoJson, specialAreas) {
\r
28834 if (geoJson.geoJson && !geoJson.features) {
\r
28835 specialAreas = geoJson.specialAreas;
\r
28836 geoJson = geoJson.geoJson;
\r
28838 if (typeof geoJson === 'string') {
\r
28839 geoJson = (typeof JSON !== 'undefined' && JSON.parse)
\r
28840 ? JSON.parse(geoJson) : (new Function('return (' + geoJson + ');'))();
\r
28842 mapDataStores[mapName] = {
\r
28843 geoJson: geoJson,
\r
28844 specialAreas: specialAreas
\r
28849 * @param {string} mapName
\r
28850 * @return {Object}
\r
28852 getMap: function (mapName) {
\r
28853 return mapDataStores[mapName];
\r
28857 // Inject methods into echarts
\r
28858 var echarts = __webpack_require__(1);
\r
28860 echarts.registerMap = geoCreator.registerMap;
\r
28862 echarts.getMap = geoCreator.getMap;
\r
28865 echarts.loadMap = function () {};
\r
28867 echarts.registerCoordinateSystem('geo', geoCreator);
\r
28872 /***/ function(module, exports, __webpack_require__) {
\r
28876 var modelUtil = __webpack_require__(5);
\r
28877 var ComponentModel = __webpack_require__(19);
\r
28879 ComponentModel.extend({
\r
28884 * @type {module:echarts/coord/geo/Geo}
\r
28886 coordinateSystem: null,
\r
28888 init: function (option) {
\r
28889 ComponentModel.prototype.init.apply(this, arguments);
\r
28891 // Default label emphasis `position` and `show`
\r
28892 modelUtil.defaultEmphasis(
\r
28893 option.label, ['position', 'show', 'textStyle', 'distance', 'formatter']
\r
28918 // 在 roam 开启的时候使用
\r
28925 scaleLimit: null,
\r
28937 color: 'rgb(100,0,0)'
\r
28945 borderWidth: 0.5,
\r
28946 borderColor: '#444',
\r
28949 emphasis: { // 也是选中样式
\r
28950 color: 'rgba(255,215,0,0.8)'
\r
28957 * @param {string} name Region name
\r
28958 * @param {string} [status='normal'] 'normal' or 'emphasis'
\r
28959 * @return {string}
\r
28961 getFormattedLabel: function (name, status) {
\r
28962 var formatter = this.get('label.' + status + '.formatter');
\r
28966 if (typeof formatter === 'function') {
\r
28967 params.status = status;
\r
28968 return formatter(params);
\r
28970 else if (typeof formatter === 'string') {
\r
28971 return formatter.replace('{a}', params.seriesName);
\r
28975 setRoamZoom: function (zoom) {
\r
28976 var roamDetail = this.option.roamDetail;
\r
28977 roamDetail && (roamDetail.zoom = zoom);
\r
28980 setRoamPan: function (x, y) {
\r
28981 var roamDetail = this.option.roamDetail;
\r
28982 if (roamDetail) {
\r
28983 roamDetail.x = x;
\r
28984 roamDetail.y = y;
\r
28992 /***/ function(module, exports, __webpack_require__) {
\r
28996 var parseGeoJson = __webpack_require__(166);
\r
28998 var zrUtil = __webpack_require__(3);
\r
29000 var BoundingRect = __webpack_require__(15);
\r
29002 var View = __webpack_require__(169);
\r
29005 // Geo fix functions
\r
29006 var geoFixFuncs = [
\r
29007 __webpack_require__(170),
\r
29008 __webpack_require__(171),
\r
29009 __webpack_require__(172)
\r
29013 * [Geo description]
\r
29014 * @param {string} name Geo name
\r
29015 * @param {string} map Map type
\r
29016 * @param {Object} geoJson
\r
29017 * @param {Object} [specialAreas]
\r
29018 * Specify the positioned areas by left, top, width, height
\r
29019 * @param {Object.<string, string>} [nameMap]
\r
29020 * Specify name alias
\r
29022 function Geo(name, map, geoJson, specialAreas, nameMap) {
\r
29024 View.call(this, name);
\r
29032 this._nameCoordMap = {};
\r
29034 this.loadGeoJson(geoJson, specialAreas, nameMap);
\r
29037 Geo.prototype = {
\r
29039 constructor: Geo,
\r
29044 * @param {Array.<string>}
\r
29047 dimensions: ['lng', 'lat'],
\r
29050 * @param {Object} geoJson
\r
29051 * @param {Object} [specialAreas]
\r
29052 * Specify the positioned areas by left, top, width, height
\r
29053 * @param {Object.<string, string>} [nameMap]
\r
29054 * Specify name alias
\r
29056 loadGeoJson: function (geoJson, specialAreas, nameMap) {
\r
29057 // https://jsperf.com/try-catch-performance-overhead
\r
29059 this.regions = geoJson ? parseGeoJson(geoJson) : [];
\r
29062 throw 'Invalid geoJson format\n' + e;
\r
29064 specialAreas = specialAreas || {};
\r
29065 nameMap = nameMap || {};
\r
29066 var regions = this.regions;
\r
29067 var regionsMap = {};
\r
29068 for (var i = 0; i < regions.length; i++) {
\r
29069 var regionName = regions[i].name;
\r
29070 // Try use the alias in nameMap
\r
29071 regionName = nameMap[regionName] || regionName;
\r
29072 regions[i].name = regionName;
\r
29074 regionsMap[regionName] = regions[i];
\r
29076 this.addGeoCoord(regionName, regions[i].center);
\r
29078 // Some area like Alaska in USA map needs to be tansformed
\r
29079 // to look better
\r
29080 var specialArea = specialAreas[regionName];
\r
29081 if (specialArea) {
\r
29082 regions[i].transformTo(
\r
29083 specialArea.left, specialArea.top, specialArea.width, specialArea.height
\r
29088 this._regionsMap = regionsMap;
\r
29090 this._rect = null;
\r
29092 zrUtil.each(geoFixFuncs, function (fixFunc) {
\r
29098 transformTo: function (x, y, width, height) {
\r
29099 var rect = this.getBoundingRect();
\r
29101 rect = rect.clone();
\r
29102 // Longitute is inverted
\r
29103 rect.y = -rect.y - rect.height;
\r
29105 var viewTransform = this._viewTransform;
\r
29107 viewTransform.transform = rect.calculateTransform(
\r
29108 new BoundingRect(x, y, width, height)
\r
29111 viewTransform.decomposeTransform();
\r
29113 var scale = viewTransform.scale;
\r
29114 scale[1] = -scale[1];
\r
29116 viewTransform.updateTransform();
\r
29118 this._updateTransform();
\r
29122 * @param {string} name
\r
29123 * @return {module:echarts/coord/geo/Region}
\r
29125 getRegion: function (name) {
\r
29126 return this._regionsMap[name];
\r
29130 * Add geoCoord for indexing by name
\r
29131 * @param {string} name
\r
29132 * @param {Array.<number>} geoCoord
\r
29134 addGeoCoord: function (name, geoCoord) {
\r
29135 this._nameCoordMap[name] = geoCoord;
\r
29139 * Get geoCoord by name
\r
29140 * @param {string} name
\r
29141 * @return {Array.<number>}
\r
29143 getGeoCoord: function (name) {
\r
29144 return this._nameCoordMap[name];
\r
29148 getBoundingRect: function () {
\r
29149 if (this._rect) {
\r
29150 return this._rect;
\r
29154 var regions = this.regions;
\r
29155 for (var i = 0; i < regions.length; i++) {
\r
29156 var regionRect = regions[i].getBoundingRect();
\r
29157 rect = rect || regionRect.clone();
\r
29158 rect.union(regionRect);
\r
29160 // FIXME Always return new ?
\r
29161 return (this._rect = rect || new BoundingRect(0, 0, 0, 0));
\r
29165 * Convert series data to a list of points
\r
29166 * @param {module:echarts/data/List} data
\r
29167 * @param {boolean} stack
\r
29168 * @return {Array}
\r
29169 * Return list of points. For example:
\r
29170 * `[[10, 10], [20, 20], [30, 30]]`
\r
29172 dataToPoints: function (data) {
\r
29174 return data.mapArray(['lng', 'lat'], function (lon, lat) {
\r
29177 return this.dataToPoint(item);
\r
29183 * @param {string|Array.<number>} data
\r
29184 * @return {Array.<number>}
\r
29186 dataToPoint: function (data) {
\r
29187 if (typeof data === 'string') {
\r
29188 // Map area name to geoCoord
\r
29189 data = this.getGeoCoord(data);
\r
29192 return View.prototype.dataToPoint.call(this, data);
\r
29197 zrUtil.mixin(Geo, View);
\r
29199 module.exports = Geo;
\r
29204 /***/ function(module, exports, __webpack_require__) {
\r
29207 * Parse and decode geo json
\r
29208 * @module echarts/coord/geo/parseGeoJson
\r
29212 var zrUtil = __webpack_require__(3);
\r
29214 var Region = __webpack_require__(167);
\r
29216 function decode(json) {
\r
29217 if (!json.UTF8Encoding) {
\r
29220 var features = json.features;
\r
29222 for (var f = 0; f < features.length; f++) {
\r
29223 var feature = features[f];
\r
29224 var geometry = feature.geometry;
\r
29225 var coordinates = geometry.coordinates;
\r
29226 var encodeOffsets = geometry.encodeOffsets;
\r
29228 for (var c = 0; c < coordinates.length; c++) {
\r
29229 var coordinate = coordinates[c];
\r
29231 if (geometry.type === 'Polygon') {
\r
29232 coordinates[c] = decodePolygon(
\r
29237 else if (geometry.type === 'MultiPolygon') {
\r
29238 for (var c2 = 0; c2 < coordinate.length; c2++) {
\r
29239 var polygon = coordinate[c2];
\r
29240 coordinate[c2] = decodePolygon(
\r
29242 encodeOffsets[c][c2]
\r
29248 // Has been decoded
\r
29249 json.UTF8Encoding = false;
\r
29253 function decodePolygon(coordinate, encodeOffsets) {
\r
29255 var prevX = encodeOffsets[0];
\r
29256 var prevY = encodeOffsets[1];
\r
29258 for (var i = 0; i < coordinate.length; i += 2) {
\r
29259 var x = coordinate.charCodeAt(i) - 64;
\r
29260 var y = coordinate.charCodeAt(i + 1) - 64;
\r
29261 // ZigZag decoding
\r
29262 x = (x >> 1) ^ (-(x & 1));
\r
29263 y = (y >> 1) ^ (-(y & 1));
\r
29264 // Delta deocding
\r
29271 result.push([x / 1024, y / 1024]);
\r
29280 function flattern2D(array) {
\r
29282 for (var i = 0; i < array.length; i++) {
\r
29283 for (var k = 0; k < array[i].length; k++) {
\r
29284 ret.push(array[i][k]);
\r
29291 * @alias module:echarts/coord/geo/parseGeoJson
\r
29292 * @param {Object} geoJson
\r
29293 * @return {module:zrender/container/Group}
\r
29295 module.exports = function (geoJson) {
\r
29299 return zrUtil.map(zrUtil.filter(geoJson.features, function (featureObj) {
\r
29300 // Output of mapshaper may have geometry null
\r
29301 return featureObj.geometry && featureObj.properties;
\r
29302 }), function (featureObj) {
\r
29303 var properties = featureObj.properties;
\r
29304 var geometry = featureObj.geometry;
\r
29306 var coordinates = geometry.coordinates;
\r
29308 if (geometry.type === 'MultiPolygon') {
\r
29309 coordinates = flattern2D(coordinates);
\r
29312 return new Region(
\r
29323 /***/ function(module, exports, __webpack_require__) {
\r
29326 * @module echarts/coord/geo/Region
\r
29330 var polygonContain = __webpack_require__(168);
\r
29332 var BoundingRect = __webpack_require__(15);
\r
29334 var bbox = __webpack_require__(50);
\r
29335 var vec2 = __webpack_require__(16);
\r
29338 * @param {string} name
\r
29339 * @param {Array} contours
\r
29340 * @param {Array.<number>} cp
\r
29342 function Region(name, contours, cp) {
\r
29348 this.name = name;
\r
29351 * @type {Array.<Array>}
\r
29354 this.contours = contours;
\r
29357 var rect = this.getBoundingRect();
\r
29359 rect.x + rect.width / 2,
\r
29360 rect.y + rect.height / 2
\r
29364 cp = [cp[0], cp[1]];
\r
29367 * @type {Array.<number>}
\r
29369 this.center = cp;
\r
29372 Region.prototype = {
\r
29374 constructor: Region,
\r
29377 * @return {module:zrender/core/BoundingRect}
\r
29379 getBoundingRect: function () {
\r
29380 var rect = this._rect;
\r
29385 var MAX_NUMBER = Number.MAX_VALUE;
\r
29386 var min = [MAX_NUMBER, MAX_NUMBER];
\r
29387 var max = [-MAX_NUMBER, -MAX_NUMBER];
\r
29390 var contours = this.contours;
\r
29391 for (var i = 0; i < contours.length; i++) {
\r
29392 bbox.fromPoints(contours[i], min2, max2);
\r
29393 vec2.min(min, min, min2);
\r
29394 vec2.max(max, max, max2);
\r
29398 min[0] = min[1] = max[0] = max[1] = 0;
\r
29401 return (this._rect = new BoundingRect(
\r
29402 min[0], min[1], max[0] - min[0], max[1] - min[1]
\r
29407 * @param {<Array.<number>} coord
\r
29408 * @return {boolean}
\r
29410 contain: function (coord) {
\r
29411 var rect = this.getBoundingRect();
\r
29412 var contours = this.contours;
\r
29413 if (rect.contain(coord[0], coord[1])) {
\r
29414 for (var i = 0, len = contours.length; i < len; i++) {
\r
29415 if (polygonContain.contain(contours[i], coord[0], coord[1])) {
\r
29423 transformTo: function (x, y, width, height) {
\r
29424 var rect = this.getBoundingRect();
\r
29425 var aspect = rect.width / rect.height;
\r
29427 width = aspect * height;
\r
29429 else if (!height) {
\r
29430 height = width / aspect ;
\r
29432 var target = new BoundingRect(x, y, width, height);
\r
29433 var transform = rect.calculateTransform(target);
\r
29434 var contours = this.contours;
\r
29435 for (var i = 0; i < contours.length; i++) {
\r
29436 for (var p = 0; p < contours[i].length; p++) {
\r
29437 vec2.applyTransform(contours[i][p], contours[i][p], transform);
\r
29440 rect = this._rect;
\r
29441 rect.copy(target);
\r
29444 rect.x + rect.width / 2,
\r
29445 rect.y + rect.height / 2
\r
29450 module.exports = Region;
\r
29455 /***/ function(module, exports, __webpack_require__) {
\r
29459 var windingLine = __webpack_require__(57);
\r
29461 var EPSILON = 1e-8;
\r
29463 function isAroundEqual(a, b) {
\r
29464 return Math.abs(a - b) < EPSILON;
\r
29467 function contain(points, x, y) {
\r
29469 var p = points[0];
\r
29475 for (var i = 1; i < points.length; i++) {
\r
29476 var p2 = points[i];
\r
29477 w += windingLine(p[0], p[1], p2[0], p2[1], x, y);
\r
29482 var p0 = points[0];
\r
29483 if (!isAroundEqual(p[0], p0[0]) || !isAroundEqual(p[1], p0[1])) {
\r
29484 w += windingLine(p[0], p[1], p0[0], p0[1], x, y);
\r
29491 module.exports = {
\r
29498 /***/ function(module, exports, __webpack_require__) {
\r
29501 * Simple view coordinate system
\r
29502 * Mapping given x, y to transformd view x, y
\r
29506 var vector = __webpack_require__(16);
\r
29507 var matrix = __webpack_require__(17);
\r
29509 var Transformable = __webpack_require__(33);
\r
29510 var zrUtil = __webpack_require__(3);
\r
29512 var BoundingRect = __webpack_require__(15);
\r
29514 var v2ApplyTransform = vector.applyTransform;
\r
29516 // Dummy transform node
\r
29517 function TransformDummy() {
\r
29518 Transformable.call(this);
\r
29520 zrUtil.mixin(TransformDummy, Transformable);
\r
29522 function View(name) {
\r
29526 this.name = name;
\r
29529 * @type {Array.<number>}
\r
29533 Transformable.call(this);
\r
29535 this._roamTransform = new TransformDummy();
\r
29537 this._viewTransform = new TransformDummy();
\r
29540 View.prototype = {
\r
29542 constructor: View,
\r
29547 * @param {Array.<string>}
\r
29550 dimensions: ['x', 'y'],
\r
29553 * Set bounding rect
\r
29554 * @param {number} x
\r
29555 * @param {number} y
\r
29556 * @param {number} width
\r
29557 * @param {number} height
\r
29560 // PENDING to getRect
\r
29561 setBoundingRect: function (x, y, width, height) {
\r
29562 this._rect = new BoundingRect(x, y, width, height);
\r
29563 return this._rect;
\r
29567 * @return {module:zrender/core/BoundingRect}
\r
29569 // PENDING to getRect
\r
29570 getBoundingRect: function () {
\r
29571 return this._rect;
\r
29575 * @param {number} x
\r
29576 * @param {number} y
\r
29577 * @param {number} width
\r
29578 * @param {number} height
\r
29580 setViewRect: function (x, y, width, height) {
\r
29581 this.transformTo(x, y, width, height);
\r
29582 this._viewRect = new BoundingRect(x, y, width, height);
\r
29586 * Transformed to particular position and size
\r
29587 * @param {number} x
\r
29588 * @param {number} y
\r
29589 * @param {number} width
\r
29590 * @param {number} height
\r
29592 transformTo: function (x, y, width, height) {
\r
29593 var rect = this.getBoundingRect();
\r
29594 var viewTransform = this._viewTransform;
\r
29596 viewTransform.transform = rect.calculateTransform(
\r
29597 new BoundingRect(x, y, width, height)
\r
29600 viewTransform.decomposeTransform();
\r
29602 this._updateTransform();
\r
29606 * @param {number} x
\r
29607 * @param {number} y
\r
29609 setPan: function (x, y) {
\r
29611 this._roamTransform.position = [x, y];
\r
29613 this._updateTransform();
\r
29617 * @param {number} zoom
\r
29619 setZoom: function (zoom) {
\r
29620 var zoomLimit = this.zoomLimit;
\r
29623 Math.min(zoom, zoomLimit.max), zoomLimit.min
\r
29627 this._roamTransform.scale = [zoom, zoom];
\r
29629 this._updateTransform();
\r
29633 * @return {Array.<number}
\r
29635 getRoamTransform: function () {
\r
29636 return this._roamTransform.transform;
\r
29640 * Update transform from roam and mapLocation
\r
29643 _updateTransform: function () {
\r
29644 var roamTransform = this._roamTransform;
\r
29645 var viewTransform = this._viewTransform;
\r
29646 // var scale = this.scale;
\r
29648 viewTransform.parent = roamTransform;
\r
29649 roamTransform.updateTransform();
\r
29650 viewTransform.updateTransform();
\r
29652 viewTransform.transform
\r
29653 && matrix.copy(this.transform || (this.transform = []), viewTransform.transform);
\r
29655 this.decomposeTransform();
\r
29659 * @return {module:zrender/core/BoundingRect}
\r
29661 getViewRect: function () {
\r
29662 return this._viewRect;
\r
29666 * Convert a single (lon, lat) data item to (x, y) point.
\r
29667 * @param {Array.<number>} data
\r
29668 * @return {Array.<number>}
\r
29670 dataToPoint: function (data) {
\r
29671 var transform = this.transform;
\r
29673 ? v2ApplyTransform([], data, transform)
\r
29674 : [data[0], data[1]];
\r
29678 * Convert a (x, y) point to (lon, lat) data
\r
29679 * @param {Array.<number>} point
\r
29680 * @return {Array.<number>}
\r
29682 pointToData: function (point) {
\r
29683 var invTransform = this.invTransform;
\r
29684 return invTransform
\r
29685 ? v2ApplyTransform([], point, invTransform)
\r
29686 : [point[0], point[1]];
\r
29690 * @return {number}
\r
29692 // getScalarScale: function () {
\r
29693 // // Use determinant square root of transform to mutiply scalar
\r
29694 // var m = this.transform;
\r
29695 // var det = Math.sqrt(Math.abs(m[0] * m[3] - m[2] * m[1]));
\r
29700 zrUtil.mixin(View, Transformable);
\r
29702 module.exports = View;
\r
29707 /***/ function(module, exports, __webpack_require__) {
\r
29712 var Region = __webpack_require__(167);
\r
29714 var geoCoord = [126, 25];
\r
29717 [[0,3.5],[7,11.2],[15,11.9],[30,7],[42,0.7],[52,0.7],
\r
29718 [56,7.7],[59,0.7],[64,0.7],[64,0],[5,0],[0,3.5]],
\r
29719 [[13,16.1],[19,14.7],[16,21.7],[11,23.1],[13,16.1]],
\r
29720 [[12,32.2],[14,38.5],[15,38.5],[13,32.2],[12,32.2]],
\r
29721 [[16,47.6],[12,53.2],[13,53.2],[18,47.6],[16,47.6]],
\r
29722 [[6,64.4],[8,70],[9,70],[8,64.4],[6,64.4]],
\r
29723 [[23,82.6],[29,79.8],[30,79.8],[25,82.6],[23,82.6]],
\r
29724 [[37,70.7],[43,62.3],[44,62.3],[39,70.7],[37,70.7]],
\r
29725 [[48,51.1],[51,45.5],[53,45.5],[50,51.1],[48,51.1]],
\r
29726 [[51,35],[51,28.7],[53,28.7],[53,35],[51,35]],
\r
29727 [[52,22.4],[55,17.5],[56,17.5],[53,22.4],[52,22.4]],
\r
29728 [[58,12.6],[62,7],[63,7],[60,12.6],[58,12.6]],
\r
29729 [[0,3.5],[0,93.1],[64,93.1],[64,0],[63,0],[63,92.4],
\r
29730 [1,92.4],[1,3.5],[0,3.5]]
\r
29732 for (var i = 0; i < points.length; i++) {
\r
29733 for (var k = 0; k < points[i].length; k++) {
\r
29734 points[i][k][0] /= 10.5;
\r
29735 points[i][k][1] /= -10.5 / 0.75;
\r
29737 points[i][k][0] += geoCoord[0];
\r
29738 points[i][k][1] += geoCoord[1];
\r
29741 module.exports = function (geo) {
\r
29742 if (geo.map === 'china') {
\r
29743 geo.regions.push(new Region(
\r
29744 '南海诸岛', points, geoCoord
\r
29752 /***/ function(module, exports, __webpack_require__) {
\r
29756 var zrUtil = __webpack_require__(3);
\r
29758 var coordsOffsetMap = {
\r
29759 '南海诸岛' : [32, 80],
\r
29764 //'北京': [-10, 0],
\r
29768 module.exports = function (geo) {
\r
29769 zrUtil.each(geo.regions, function (region) {
\r
29770 var coordFix = coordsOffsetMap[region.name];
\r
29772 var cp = region.center;
\r
29773 cp[0] += coordFix[0] / 10.5;
\r
29774 cp[1] += -coordFix[1] / (10.5 / 0.75);
\r
29782 /***/ function(module, exports, __webpack_require__) {
\r
29786 var zrUtil = __webpack_require__(3);
\r
29788 var geoCoordMap = {
\r
29789 'Russia': [100, 60],
\r
29790 'United States of America': [-99, 38]
\r
29793 module.exports = function (geo) {
\r
29794 zrUtil.each(geo.regions, function (region) {
\r
29795 var geoCoord = geoCoordMap[region.name];
\r
29797 var cp = region.center;
\r
29798 cp[0] = geoCoord[0];
\r
29799 cp[1] = geoCoord[1];
\r
29807 /***/ function(module, exports, __webpack_require__) {
\r
29811 var zrUtil = __webpack_require__(3);
\r
29813 module.exports = function (ecModel) {
\r
29815 var processedMapType = {};
\r
29817 ecModel.eachSeriesByType('map', function (mapSeries) {
\r
29818 var mapType = mapSeries.get('mapType');
\r
29819 if (processedMapType[mapType]) {
\r
29823 var mapSymbolOffsets = {};
\r
29825 zrUtil.each(mapSeries.seriesGroup, function (subMapSeries) {
\r
29826 var geo = subMapSeries.coordinateSystem;
\r
29827 var data = subMapSeries.getData();
\r
29828 if (subMapSeries.get('showLegendSymbol') && ecModel.getComponent('legend')) {
\r
29829 data.each('value', function (value, idx) {
\r
29830 var name = data.getName(idx);
\r
29831 var region = geo.getRegion(name);
\r
29833 // No region or no value
\r
29834 // In MapSeries data regions will be filled with NaN
\r
29835 // If they are not in the series.data array.
\r
29836 // So here must validate if value is NaN
\r
29837 if (!region || isNaN(value)) {
\r
29841 var offset = mapSymbolOffsets[name] || 0;
\r
29843 var point = geo.dataToPoint(region.center);
\r
29845 mapSymbolOffsets[name] = offset + 1;
\r
29847 data.setItemLayout(idx, {
\r
29855 // Show label of those region not has legendSymbol(which is offset 0)
\r
29856 var data = mapSeries.getData();
\r
29857 data.each(function (idx) {
\r
29858 var name = data.getName(idx);
\r
29859 var layout = data.getItemLayout(idx) || {};
\r
29860 layout.showLabel = !mapSymbolOffsets[name];
\r
29861 data.setItemLayout(idx, layout);
\r
29864 processedMapType[mapType] = true;
\r
29871 /***/ function(module, exports) {
\r
29874 module.exports = function (ecModel) {
\r
29875 ecModel.eachSeriesByType('map', function (seriesModel) {
\r
29876 var colorList = seriesModel.get('color');
\r
29877 var itemStyleModel = seriesModel.getModel('itemStyle.normal');
\r
29879 var areaColor = itemStyleModel.get('areaColor');
\r
29880 var color = itemStyleModel.get('color')
\r
29881 || colorList[seriesModel.seriesIndex % colorList.length];
\r
29883 seriesModel.getData().setVisual({
\r
29884 'areaColor': areaColor,
\r
29893 /***/ function(module, exports, __webpack_require__) {
\r
29897 var zrUtil = __webpack_require__(3);
\r
29901 * @param {Array.<module:echarts/data/List>} datas
\r
29902 * @param {string} statisticsType 'average' 'sum'
\r
29905 function dataStatistics(datas, statisticsType) {
\r
29906 var dataNameMap = {};
\r
29907 var dims = ['value'];
\r
29909 for (var i = 0; i < datas.length; i++) {
\r
29910 datas[i].each(dims, function (value, idx) {
\r
29911 var name = datas[i].getName(idx);
\r
29912 dataNameMap[name] = dataNameMap[name] || [];
\r
29913 if (!isNaN(value)) {
\r
29914 dataNameMap[name].push(value);
\r
29919 return datas[0].map(dims, function (value, idx) {
\r
29920 var name = datas[0].getName(idx);
\r
29922 var min = Infinity;
\r
29923 var max = -Infinity;
\r
29924 var len = dataNameMap[name].length;
\r
29925 for (var i = 0; i < len; i++) {
\r
29926 min = Math.min(min, dataNameMap[name][i]);
\r
29927 max = Math.max(max, dataNameMap[name][i]);
\r
29928 sum += dataNameMap[name][i];
\r
29931 if (statisticsType === 'min') {
\r
29934 else if (statisticsType === 'max') {
\r
29937 else if (statisticsType === 'average') {
\r
29938 result = sum / len;
\r
29943 return len === 0 ? NaN : result;
\r
29947 module.exports = function (ecModel) {
\r
29948 var seriesGroupByMapType = {};
\r
29949 ecModel.eachSeriesByType('map', function (seriesModel) {
\r
29950 var mapType = seriesModel.get('map');
\r
29951 seriesGroupByMapType[mapType] = seriesGroupByMapType[mapType] || [];
\r
29952 seriesGroupByMapType[mapType].push(seriesModel);
\r
29955 zrUtil.each(seriesGroupByMapType, function (seriesList, mapType) {
\r
29956 var data = dataStatistics(
\r
29957 zrUtil.map(seriesList, function (seriesModel) {
\r
29958 return seriesModel.getData();
\r
29960 seriesList[0].get('mapValueCalculation')
\r
29963 seriesList[0].seriesGroup = [];
\r
29965 seriesList[0].setData(data);
\r
29967 // FIXME Put where?
\r
29968 for (var i = 0; i < seriesList.length; i++) {
\r
29969 seriesList[i].seriesGroup = seriesList;
\r
29970 seriesList[i].needsDrawMap = i === 0;
\r
29978 /***/ function(module, exports, __webpack_require__) {
\r
29982 var zrUtil = __webpack_require__(3);
\r
29984 'x', 'y', 'x2', 'y2', 'width', 'height', 'map', 'roam', 'roamDetail', 'label', 'itemStyle'
\r
29987 var geoCoordsMap = {};
\r
29989 function createGeoFromMap(mapSeriesOpt) {
\r
29991 zrUtil.each(geoProps, function (propName) {
\r
29992 if (mapSeriesOpt[propName] != null) {
\r
29993 geoOpt[propName] = mapSeriesOpt[propName];
\r
29998 module.exports = function (option) {
\r
30000 var mapSeries = [];
\r
30001 zrUtil.each(option.series, function (seriesOpt) {
\r
30002 if (seriesOpt.type === 'map') {
\r
30003 mapSeries.push(seriesOpt);
\r
30005 zrUtil.extend(geoCoordsMap, seriesOpt.geoCoord);
\r
30008 var newCreatedGeoOptMap = {};
\r
30009 zrUtil.each(mapSeries, function (seriesOpt) {
\r
30010 seriesOpt.map = seriesOpt.map || seriesOpt.mapType;
\r
30011 // Put x, y, width, height, x2, y2 in the top level
\r
30012 zrUtil.defaults(seriesOpt, seriesOpt.mapLocation);
\r
30013 if (seriesOpt.markPoint) {
\r
30014 var markPoint = seriesOpt.markPoint;
\r
30015 // Convert name or geoCoord in markPoint to lng and lat
\r
30017 // { name: 'xxx', value: 10} Or
\r
30018 // { geoCoord: [lng, lat], value: 10} to
\r
30019 // { name: 'xxx', value: [lng, lat, 10]}
\r
30020 markPoint.data = zrUtil.map(markPoint.data, function (dataOpt) {
\r
30021 if (!zrUtil.isArray(dataOpt.value)) {
\r
30023 if (dataOpt.geoCoord) {
\r
30024 geoCoord = dataOpt.geoCoord;
\r
30026 else if (dataOpt.name) {
\r
30027 geoCoord = geoCoordsMap[dataOpt.name];
\r
30029 var newValue = geoCoord ? [geoCoord[0], geoCoord[1]] : [NaN, NaN];
\r
30030 if (dataOpt.value != null) {
\r
30031 newValue.push(dataOpt.value);
\r
30033 dataOpt.value = newValue;
\r
30037 // Convert map series which only has markPoint without data to scatter series
\r
30039 if (!(seriesOpt.data && seriesOpt.data.length)) {
\r
30040 if (!option.geo) {
\r
30044 // Use same geo if multiple map series has same map type
\r
30045 var geoOpt = newCreatedGeoOptMap[seriesOpt.map];
\r
30047 geoOpt = newCreatedGeoOptMap[seriesOpt.map] = createGeoFromMap(seriesOpt);
\r
30048 option.geo.push(geoOpt);
\r
30051 var scatterSeries = seriesOpt.markPoint;
\r
30052 scatterSeries.type = option.effect && option.effect.show ? 'effectScatter' : 'scatter';
\r
30053 scatterSeries.coordinateSystem = 'geo';
\r
30054 scatterSeries.geoIndex = zrUtil.indexOf(option.geo, geoOpt);
\r
30055 scatterSeries.name = seriesOpt.name;
\r
30057 option.series.splice(zrUtil.indexOf(option.series, seriesOpt), 1, scatterSeries);
\r
30066 /***/ function(module, exports, __webpack_require__) {
\r
30070 var echarts = __webpack_require__(1);
\r
30072 __webpack_require__(178);
\r
30073 __webpack_require__(182);
\r
30074 __webpack_require__(185);
\r
30076 echarts.registerVisualCoding('chart', __webpack_require__(186));
\r
30078 echarts.registerLayout(__webpack_require__(188));
\r
30083 /***/ function(module, exports, __webpack_require__) {
\r
30087 var SeriesModel = __webpack_require__(27);
\r
30088 var Tree = __webpack_require__(179);
\r
30089 var zrUtil = __webpack_require__(3);
\r
30090 var Model = __webpack_require__(8);
\r
30091 var formatUtil = __webpack_require__(6);
\r
30092 var helper = __webpack_require__(181);
\r
30093 var encodeHTML = formatUtil.encodeHTML;
\r
30094 var addCommas = formatUtil.addCommas;
\r
30097 module.exports = SeriesModel.extend({
\r
30099 type: 'series.treemap',
\r
30101 dependencies: ['grid', 'polar'],
\r
30104 * @type {module:echarts/data/Tree~Node}
\r
30109 // center: ['50%', '50%'], // not supported in ec3.
\r
30110 // size: ['80%', '80%'], // deprecated, compatible with ec2.
\r
30117 sort: true, // Can be null or false or true
\r
30118 // (order by desc default, asc not supported yet (strange effect))
\r
30119 clipWindow: 'origin', // Size of clipped window when zooming. 'origin' or 'fullscreen'
\r
30120 squareRatio: 0.5 * (1 + Math.sqrt(5)), // golden ratio
\r
30121 leafDepth: null, // Nodes on depth from root are regarded as leaves.
\r
30122 // Count from zero (zero represents only view root).
\r
30123 visualDimension: 0, // Can be 0, 1, 2, 3.
\r
30124 zoomToNodeRatio: 0.32 * 0.32, // Be effective when using zoomToNode. Specify the proportion of the
\r
30125 // target node area in the view area.
\r
30126 roam: true, // true, false, 'scale' or 'zoom', 'move'.
\r
30127 nodeClick: 'zoomToNode', // Leaf node click behaviour: 'zoomToNode', 'link', false.
\r
30128 // If leafDepth is set and clicking a node which has children but
\r
30129 // be on left depth, the behaviour would be changing root. Otherwise
\r
30130 // use behavious defined above.
\r
30132 animationDurationUpdate: 900,
\r
30133 animationEasing: 'quinticInOut',
\r
30141 emptyItemWidth: 25, // Width of empty node.
\r
30144 color: 'rgba(0,0,0,0.7)', //'#5793f3',
\r
30145 borderColor: 'rgba(255,255,255,0.7)',
\r
30147 shadowColor: 'rgba(150,150,150,1)',
\r
30149 shadowOffsetX: 0,
\r
30150 shadowOffsetY: 0,
\r
30163 position: ['50%', '50%'], // Can be 5, '5%' or position stirng like 'insideTopLeft', ...
\r
30166 baseline: 'middle',
\r
30174 color: null, // Can be 'none' if not necessary.
\r
30175 colorAlpha: null, // Can be 'none' if not necessary.
\r
30176 colorSaturation: null, // Can be 'none' if not necessary.
\r
30179 borderColor: '#fff',
\r
30180 borderColorSaturation: null // If specified, borderColor will be ineffective, and the
\r
30181 // border color is evaluated by color of current node and
\r
30182 // borderColorSaturation.
\r
30188 color: 'none', // Array. Specify color list of each level.
\r
30189 // level[0].color would be global color list.
\r
30190 colorAlpha: null, // Array. Specify color alpha range of each level, like [0.2, 0.8]
\r
30191 colorSaturation: null, // Array. Specify color saturation of each level, like [0.2, 0.5]
\r
30192 colorMappingBy: 'index', // 'value' or 'index' or 'id'.
\r
30193 visibleMin: 10, // If area less than this threshold (unit: pixel^2), node will not
\r
30194 // be rendered. Only works when sort is 'asc' or 'desc'.
\r
30195 childrenVisibleMin: null, // If area of a node less than this threshold (unit: pixel^2),
\r
30196 // grandchildren will not show.
\r
30197 // Why grandchildren? If not grandchildren but children,
\r
30198 // some siblings show children and some not,
\r
30199 // the appearance may be mess and not consistent,
\r
30200 levels: [] // Each item: {
\r
30201 // visibleMin, itemStyle, visualDimension, label
\r
30206 // link: 'http://xxx.xxx.xxx',
\r
30207 // target: 'blank' or 'self'
\r
30214 getInitialData: function (option, ecModel) {
\r
30215 var data = option.data || [];
\r
30216 var rootName = option.name;
\r
30217 rootName == null && (rootName = option.name);
\r
30219 // Create a virtual root.
\r
30220 var root = {name: rootName, children: option.data};
\r
30221 var value0 = (data[0] || {}).value;
\r
30223 completeTreeValue(root, zrUtil.isArray(value0) ? value0.length : -1);
\r
30226 // sereis.mergeOption 的 getInitData是否放在merge后,从而能直接获取merege后的结果而非手动判断。
\r
30227 var levels = option.levels || [];
\r
30229 levels = option.levels = setDefault(levels, ecModel);
\r
30231 // Make sure always a new tree is created when setOption,
\r
30232 // in TreemapView, we check whether oldTree === newTree
\r
30233 // to choose mappings approach among old shapes and new shapes.
\r
30234 return Tree.createTree(root, this, levels).data;
\r
30237 optionUpdated: function () {
\r
30238 this.resetViewRoot();
\r
30243 * @param {number} dataIndex
\r
30244 * @param {boolean} [mutipleSeries=false]
\r
30246 formatTooltip: function (dataIndex) {
\r
30247 var data = this.getData();
\r
30248 var value = this.getRawValue(dataIndex);
\r
30249 var formattedValue = zrUtil.isArray(value)
\r
30250 ? addCommas(value[0]) : addCommas(value);
\r
30251 var name = data.getName(dataIndex);
\r
30253 return encodeHTML(name) + ': ' + formattedValue;
\r
30257 * Add tree path to tooltip param
\r
30260 * @param {number} dataIndex
\r
30261 * @return {Object}
\r
30263 getDataParams: function (dataIndex) {
\r
30264 var params = SeriesModel.prototype.getDataParams.apply(this, arguments);
\r
30266 var data = this.getData();
\r
30267 var node = data.tree.getNodeByDataIndex(dataIndex);
\r
30268 var treePathInfo = params.treePathInfo = [];
\r
30271 var nodeDataIndex = node.dataIndex;
\r
30272 treePathInfo.push({
\r
30274 dataIndex: nodeDataIndex,
\r
30275 value: this.getRawValue(nodeDataIndex)
\r
30277 node = node.parentNode;
\r
30280 treePathInfo.reverse();
\r
30287 * @param {Object} layoutInfo {
\r
30288 * x: containerGroup x
\r
30289 * y: containerGroup y
\r
30290 * width: containerGroup width
\r
30291 * height: containerGroup height
\r
30294 setLayoutInfo: function (layoutInfo) {
\r
30299 this.layoutInfo = this.layoutInfo || {};
\r
30300 zrUtil.extend(this.layoutInfo, layoutInfo);
\r
30304 * @param {string} id
\r
30305 * @return {number} index
\r
30307 mapIdToIndex: function (id) {
\r
30308 // A feature is implemented:
\r
30309 // index is monotone increasing with the sequence of
\r
30310 // input id at the first time.
\r
30311 // This feature can make sure that each data item and its
\r
30312 // mapped color have the same index between data list and
\r
30313 // color list at the beginning, which is useful for user
\r
30314 // to adjust data-color mapping.
\r
30320 var idIndexMap = this._idIndexMap;
\r
30322 if (!idIndexMap) {
\r
30323 idIndexMap = this._idIndexMap = {};
\r
30328 this._idIndexMapCount = 0;
\r
30331 var index = idIndexMap[id];
\r
30332 if (index == null) {
\r
30333 idIndexMap[id] = index = this._idIndexMapCount++;
\r
30339 getViewRoot: function () {
\r
30340 return this._viewRoot;
\r
30344 * @param {module:echarts/data/Tree~Node} [viewRoot]
\r
30345 * @return {string} direction 'drilldown' or 'rollup'
\r
30347 resetViewRoot: function (viewRoot) {
\r
30349 ? (this._viewRoot = viewRoot)
\r
30350 : (viewRoot = this._viewRoot);
\r
30352 var root = this.getData().tree.root;
\r
30355 || (viewRoot !== root && !root.contains(viewRoot))
\r
30357 this._viewRoot = root;
\r
30363 * @param {Object} dataNode
\r
30365 function completeTreeValue(dataNode, arrValueLength) {
\r
30366 // Postorder travel tree.
\r
30367 // If value of none-leaf node is not set,
\r
30368 // calculate it by suming up the value of all children.
\r
30371 zrUtil.each(dataNode.children, function (child) {
\r
30373 completeTreeValue(child, arrValueLength);
\r
30375 var childValue = child.value;
\r
30376 zrUtil.isArray(childValue) && (childValue = childValue[0]);
\r
30378 sum += childValue;
\r
30381 var thisValue = dataNode.value;
\r
30383 if (arrValueLength >= 0) {
\r
30384 if (!zrUtil.isArray(thisValue)) {
\r
30385 dataNode.value = new Array(arrValueLength);
\r
30388 thisValue = thisValue[0];
\r
30392 if (thisValue == null || isNaN(thisValue)) {
\r
30395 // Value should not less than 0.
\r
30396 if (thisValue < 0) {
\r
30400 arrValueLength >= 0
\r
30401 ? (dataNode.value[0] = thisValue)
\r
30402 : (dataNode.value = thisValue);
\r
30406 * set default to level configuration
\r
30408 function setDefault(levels, ecModel) {
\r
30409 var globalColorList = ecModel.get('color');
\r
30411 if (!globalColorList) {
\r
30415 levels = levels || [];
\r
30416 var hasColorDefine;
\r
30417 zrUtil.each(levels, function (levelDefine) {
\r
30418 var model = new Model(levelDefine);
\r
30419 var modelColor = model.get('color');
\r
30420 if (model.get('itemStyle.normal.color')
\r
30421 || (modelColor && modelColor !== 'none')
\r
30423 hasColorDefine = true;
\r
30427 if (!hasColorDefine) {
\r
30428 var level0 = levels[0] || (levels[0] = {});
\r
30429 level0.color = globalColorList.slice();
\r
30439 /***/ function(module, exports, __webpack_require__) {
\r
30442 * Tree data structure
\r
30444 * @module echarts/data/Tree
\r
30448 var zrUtil = __webpack_require__(3);
\r
30449 var Model = __webpack_require__(8);
\r
30450 var List = __webpack_require__(94);
\r
30451 var linkListHelper = __webpack_require__(180);
\r
30452 var completeDimensions = __webpack_require__(96);
\r
30455 * @constructor module:echarts/data/Tree~TreeNode
\r
30456 * @param {string} name
\r
30457 * @param {number} [dataIndex=-1]
\r
30458 * @param {module:echarts/data/Tree} hostTree
\r
30460 var TreeNode = function (name, dataIndex, hostTree) {
\r
30464 this.name = name || '';
\r
30475 * Height of the subtree rooted at this node.
\r
30482 * @type {module:echarts/data/Tree~TreeNode}
\r
30485 this.parentNode = null;
\r
30488 * Reference to list item.
\r
30489 * Do not persistent dataIndex outside,
\r
30490 * besause it may be changed by list.
\r
30491 * If dataIndex -1,
\r
30492 * this node is logical deleted (filtered) in list.
\r
30497 this.dataIndex = dataIndex == null ? -1 : dataIndex;
\r
30500 * @type {Array.<module:echarts/data/Tree~TreeNode>}
\r
30503 this.children = [];
\r
30506 * @type {Array.<module:echarts/data/Tree~TreeNode>}
\r
30509 this.viewChildren = [];
\r
30512 * @type {moduel:echarts/data/Tree}
\r
30515 this.hostTree = hostTree;
\r
30518 TreeNode.prototype = {
\r
30520 constructor: TreeNode,
\r
30523 * The node is removed.
\r
30524 * @return {boolean} is removed.
\r
30526 isRemoved: function () {
\r
30527 return this.dataIndex < 0;
\r
30531 * Travel this subtree (include this node).
\r
30533 * node.eachNode(function () { ... }); // preorder
\r
30534 * node.eachNode('preorder', function () { ... }); // preorder
\r
30535 * node.eachNode('postorder', function () { ... }); // postorder
\r
30537 * {order: 'postorder', attr: 'viewChildren'},
\r
30538 * function () { ... }
\r
30539 * ); // postorder
\r
30541 * @param {(Object|string)} options If string, means order.
\r
30542 * @param {string=} options.order 'preorder' or 'postorder'
\r
30543 * @param {string=} options.attr 'children' or 'viewChildren'
\r
30544 * @param {Function} cb If in preorder and return false,
\r
30545 * its subtree will not be visited.
\r
30546 * @param {Object} [context]
\r
30548 eachNode: function (options, cb, context) {
\r
30549 if (typeof options === 'function') {
\r
30555 options = options || {};
\r
30556 if (zrUtil.isString(options)) {
\r
30557 options = {order: options};
\r
30560 var order = options.order || 'preorder';
\r
30561 var children = this[options.attr || 'children'];
\r
30563 var suppressVisitSub;
\r
30564 order === 'preorder' && (suppressVisitSub = cb.call(context, this));
\r
30566 for (var i = 0; !suppressVisitSub && i < children.length; i++) {
\r
30567 children[i].eachNode(options, cb, context);
\r
30570 order === 'postorder' && cb.call(context, this);
\r
30574 * Update depth and height of this subtree.
\r
30576 * @param {number} depth
\r
30578 updateDepthAndHeight: function (depth) {
\r
30580 this.depth = depth;
\r
30581 for (var i = 0; i < this.children.length; i++) {
\r
30582 var child = this.children[i];
\r
30583 child.updateDepthAndHeight(depth + 1);
\r
30584 if (child.height > height) {
\r
30585 height = child.height;
\r
30588 this.height = height + 1;
\r
30592 * @param {string} id
\r
30593 * @return {module:echarts/data/Tree~TreeNode}
\r
30595 getNodeById: function (id) {
\r
30596 if (this.getId() === id) {
\r
30599 for (var i = 0, children = this.children, len = children.length; i < len; i++) {
\r
30600 var res = children[i].getNodeById(id);
\r
30608 * @param {module:echarts/data/Tree~TreeNode} node
\r
30609 * @return {boolean}
\r
30611 contains: function (node) {
\r
30612 if (node === this) {
\r
30615 for (var i = 0, children = this.children, len = children.length; i < len; i++) {
\r
30616 var res = children[i].contains(node);
\r
30624 * @param {boolean} includeSelf Default false.
\r
30625 * @return {Array.<module:echarts/data/Tree~TreeNode>} order: [root, child, grandchild, ...]
\r
30627 getAncestors: function (includeSelf) {
\r
30628 var ancestors = [];
\r
30629 var node = includeSelf ? this : this.parentNode;
\r
30631 ancestors.push(node);
\r
30632 node = node.parentNode;
\r
30634 ancestors.reverse();
\r
30635 return ancestors;
\r
30639 * @param {string|Array=} [dimension='value'] Default 'value'. can be 0, 1, 2, 3
\r
30640 * @return {number} Value.
\r
30642 getValue: function (dimension) {
\r
30643 var data = this.hostTree.data;
\r
30644 return data.get(data.getDimension(dimension || 'value'), this.dataIndex);
\r
30648 * @param {Object} layout
\r
30649 * @param {boolean=} [merge=false]
\r
30651 setLayout: function (layout, merge) {
\r
30652 this.dataIndex >= 0
\r
30653 && this.hostTree.data.setItemLayout(this.dataIndex, layout, merge);
\r
30657 * @return {Object} layout
\r
30659 getLayout: function () {
\r
30660 return this.hostTree.data.getItemLayout(this.dataIndex);
\r
30664 * @param {string} path
\r
30665 * @return {module:echarts/model/Model}
\r
30667 getModel: function (path) {
\r
30668 if (this.dataIndex < 0) {
\r
30671 var hostTree = this.hostTree;
\r
30672 var itemModel = hostTree.data.getItemModel(this.dataIndex);
\r
30673 var levelModel = this.getLevelModel();
\r
30675 return itemModel.getModel(path, (levelModel || hostTree.hostModel).getModel(path));
\r
30679 * @return {module:echarts/model/Model}
\r
30681 getLevelModel: function () {
\r
30682 return (this.hostTree.levelModels || [])[this.depth];
\r
30687 * setItemVisual('color', color);
\r
30688 * setItemVisual({
\r
30692 setVisual: function (key, value) {
\r
30693 this.dataIndex >= 0
\r
30694 && this.hostTree.data.setItemVisual(this.dataIndex, key, value);
\r
30700 getVisual: function (key, ignoreParent) {
\r
30701 return this.hostTree.data.getItemVisual(this.dataIndex, key, ignoreParent);
\r
30706 * @return {number}
\r
30708 getRawIndex: function () {
\r
30709 return this.hostTree.data.getRawIndex(this.dataIndex);
\r
30714 * @return {string}
\r
30716 getId: function () {
\r
30717 return this.hostTree.data.getId(this.dataIndex);
\r
30723 * @alias module:echarts/data/Tree
\r
30724 * @param {module:echarts/model/Model} hostModel
\r
30725 * @param {Array.<Object>} levelOptions
\r
30727 function Tree(hostModel, levelOptions) {
\r
30729 * @type {module:echarts/data/Tree~TreeNode}
\r
30735 * @type {module:echarts/data/List}
\r
30741 * Index of each item is the same as the raw index of coresponding list item.
\r
30743 * @type {Array.<module:echarts/data/Tree~TreeNode}
\r
30745 this._nodes = [];
\r
30750 * @type {module:echarts/model/Model}
\r
30752 this.hostModel = hostModel;
\r
30757 * @type {Array.<module:echarts/model/Model}
\r
30759 this.levelModels = zrUtil.map(levelOptions || [], function (levelDefine) {
\r
30760 return new Model(levelDefine, hostModel, hostModel.ecModel);
\r
30764 Tree.prototype = {
\r
30766 constructor: Tree,
\r
30771 * Travel this subtree (include this node).
\r
30773 * node.eachNode(function () { ... }); // preorder
\r
30774 * node.eachNode('preorder', function () { ... }); // preorder
\r
30775 * node.eachNode('postorder', function () { ... }); // postorder
\r
30777 * {order: 'postorder', attr: 'viewChildren'},
\r
30778 * function () { ... }
\r
30779 * ); // postorder
\r
30781 * @param {(Object|string)} options If string, means order.
\r
30782 * @param {string=} options.order 'preorder' or 'postorder'
\r
30783 * @param {string=} options.attr 'children' or 'viewChildren'
\r
30784 * @param {Function} cb
\r
30785 * @param {Object} [context]
\r
30787 eachNode: function(options, cb, context) {
\r
30788 this.root.eachNode(options, cb, context);
\r
30792 * @param {number} dataIndex
\r
30793 * @return {module:echarts/data/Tree~TreeNode}
\r
30795 getNodeByDataIndex: function (dataIndex) {
\r
30796 var rawIndex = this.data.getRawIndex(dataIndex);
\r
30797 return this._nodes[rawIndex];
\r
30801 * @param {string} name
\r
30802 * @return {module:echarts/data/Tree~TreeNode}
\r
30804 getNodeByName: function (name) {
\r
30805 return this.root.getNodeByName(name);
\r
30809 * Update item available by list,
\r
30810 * when list has been performed options like 'filterSelf' or 'map'.
\r
30812 update: function () {
\r
30813 var data = this.data;
\r
30814 var nodes = this._nodes;
\r
30816 for (var i = 0, len = nodes.length; i < len; i++) {
\r
30817 nodes[i].dataIndex = -1;
\r
30820 for (var i = 0, len = data.count(); i < len; i++) {
\r
30821 nodes[data.getRawIndex(i)].dataIndex = i;
\r
30827 * data node format:
\r
30842 * @param {Objec} dataRoot Root node.
\r
30843 * @param {module:echarts/model/Model} hostModel
\r
30844 * @param {Array.<Object>} levelOptions
\r
30845 * @return module:echarts/data/Tree
\r
30847 Tree.createTree = function (dataRoot, hostModel, levelOptions) {
\r
30849 var tree = new Tree(hostModel, levelOptions);
\r
30850 var listData = [];
\r
30852 buildHierarchy(dataRoot);
\r
30854 function buildHierarchy(dataNode, parentNode) {
\r
30855 listData.push(dataNode);
\r
30857 var node = new TreeNode(dataNode.name, listData.length - 1, tree);
\r
30859 ? addChild(node, parentNode)
\r
30860 : (tree.root = node);
\r
30862 var children = dataNode.children;
\r
30864 for (var i = 0; i < children.length; i++) {
\r
30865 buildHierarchy(children[i], node);
\r
30870 tree.root.updateDepthAndHeight(0);
\r
30872 var dimensions = completeDimensions([{name: 'value'}], listData);
\r
30873 var list = new List(dimensions, hostModel);
\r
30874 list.initData(listData);
\r
30876 linkListHelper.linkToTree(list, tree);
\r
30882 * It is needed to consider the mess of 'list', 'hostModel' when creating a TreeNote,
\r
30883 * so this function is not ready and not necessary to be public.
\r
30885 * @param {(module:echarts/data/Tree~TreeNode|Object)} child
\r
30887 function addChild(child, node) {
\r
30888 var children = node.children;
\r
30889 if (child.parentNode === node) {
\r
30893 children.push(child);
\r
30894 child.parentNode = node;
\r
30896 node.hostTree._nodes.push(child);
\r
30899 module.exports = Tree;
\r
30904 /***/ function(module, exports, __webpack_require__) {
\r
30907 * Link list to graph or tree
\r
30911 var zrUtil = __webpack_require__(3);
\r
30912 var arraySlice = Array.prototype.slice;
\r
30915 // In most case, only one of the list and its shallow clones (see list.cloneShallow)
\r
30916 // can be active in echarts process. Considering heap memory consumption,
\r
30917 // we do not clone tree or graph, but share them among list and its shallow clones.
\r
30918 // But in some rare case, we have to keep old list (like do animation in chart). So
\r
30919 // please take care that both the old list and the new list share the same tree/graph.
\r
30921 function linkList(list, target, targetType) {
\r
30922 zrUtil.each(listProxyMethods, function (method, methodName) {
\r
30923 var originMethod = list[methodName];
\r
30924 list[methodName] = zrUtil.curry(method, originMethod, target, targetType);
\r
30927 list[targetType] = target;
\r
30928 target.data = list;
\r
30933 var listProxyMethods = {
\r
30934 cloneShallow: function (originMethod, target, targetType) {
\r
30935 var newList = originMethod.apply(this, arraySlice.call(arguments, 3));
\r
30936 return linkList(newList, target, targetType);
\r
30938 map: function (originMethod, target, targetType) {
\r
30939 var newList = originMethod.apply(this, arraySlice.call(arguments, 3));
\r
30940 return linkList(newList, target, targetType);
\r
30942 filterSelf: function (originMethod, target, targetType) {
\r
30943 var result = originMethod.apply(this, arraySlice.call(arguments, 3));
\r
30949 module.exports = {
\r
30950 linkToGraph: function (list, graph) {
\r
30951 linkList(list, graph, 'graph');
\r
30954 linkToTree: function (list, tree) {
\r
30955 linkList(list, tree, 'tree');
\r
30962 /***/ function(module, exports, __webpack_require__) {
\r
30966 var zrUtil = __webpack_require__(3);
\r
30970 retrieveTargetInfo: function (payload, seriesModel) {
\r
30973 payload.type === 'treemapZoomToNode'
\r
30974 || payload.type === 'treemapRootToNode'
\r
30977 var root = seriesModel.getData().tree.root;
\r
30978 var targetNode = payload.targetNode;
\r
30979 if (targetNode && root.contains(targetNode)) {
\r
30980 return {node: targetNode};
\r
30983 var targetNodeId = payload.targetNodeId;
\r
30984 if (targetNodeId != null && (targetNode = root.getNodeById(targetNodeId))) {
\r
30985 return {node: targetNode};
\r
30990 getPathToRoot: function (node) {
\r
30994 node = node.parentNode;
\r
30996 return path.reverse();
\r
30999 aboveViewRoot: function (viewRoot, node) {
\r
31000 var viewPath = helper.getPathToRoot(viewRoot);
\r
31001 return helper.aboveViewRootByViewPath(viewPath, node);
\r
31004 // viewPath should obtained from getPathToRoot(viewRoot)
\r
31005 aboveViewRootByViewPath: function (viewPath, node) {
\r
31006 var index = zrUtil.indexOf(viewPath, node);
\r
31007 // The last one is viewRoot
\r
31008 return index >= 0 && index !== viewPath.length - 1;
\r
31013 module.exports = helper;
\r
31018 /***/ function(module, exports, __webpack_require__) {
\r
31022 var zrUtil = __webpack_require__(3);
\r
31023 var graphic = __webpack_require__(42);
\r
31024 var DataDiffer = __webpack_require__(95);
\r
31025 var helper = __webpack_require__(181);
\r
31026 var Breadcrumb = __webpack_require__(183);
\r
31027 var RoamController = __webpack_require__(159);
\r
31028 var BoundingRect = __webpack_require__(15);
\r
31029 var matrix = __webpack_require__(17);
\r
31030 var animationUtil = __webpack_require__(184);
\r
31031 var bind = zrUtil.bind;
\r
31032 var Group = graphic.Group;
\r
31033 var Rect = graphic.Rect;
\r
31034 var each = zrUtil.each;
\r
31036 var DRAG_THRESHOLD = 3;
\r
31038 module.exports = __webpack_require__(1).extendChartView({
\r
31045 init: function (o, api) {
\r
31049 * @type {module:zrender/container/Group}
\r
31051 this._containerGroup;
\r
31055 * @type {Object.<string, Array.<module:zrender/container/Group>>}
\r
31057 this._storage = createStorage();
\r
31061 * @type {module:echarts/data/Tree}
\r
31067 * @type {module:echarts/chart/treemap/Breadcrumb}
\r
31069 this._breadcrumb;
\r
31073 * @type {module:echarts/component/helper/RoamController}
\r
31075 this._controller;
\r
31078 * 'ready', 'animating'
\r
31081 this._state = 'ready';
\r
31085 * @type {boolean}
\r
31093 render: function (seriesModel, ecModel, api, payload) {
\r
31095 var models = ecModel.findComponents({
\r
31096 mainType: 'series', subType: 'treemap', query: payload
\r
31098 if (zrUtil.indexOf(models, seriesModel) < 0) {
\r
31102 this.seriesModel = seriesModel;
\r
31104 this.ecModel = ecModel;
\r
31106 var targetInfo = helper.retrieveTargetInfo(payload, seriesModel);
\r
31107 var payloadType = payload && payload.type;
\r
31108 var layoutInfo = seriesModel.layoutInfo;
\r
31109 var isInit = !this._oldTree;
\r
31110 var thisStorage = this._storage;
\r
31112 // Mark new root when action is treemapRootToNode.
\r
31113 var reRoot = (payloadType === 'treemapRootToNode' && targetInfo && thisStorage)
\r
31115 rootNodeGroup: thisStorage.nodeGroup[targetInfo.node.getRawIndex()],
\r
31116 direction: payload.direction
\r
31120 var containerGroup = this._giveContainerGroup(layoutInfo);
\r
31122 var renderResult = this._doRender(containerGroup, seriesModel, reRoot);
\r
31127 || payloadType === 'treemapZoomToNode'
\r
31128 || payloadType === 'treemapRootToNode'
\r
31131 ? this._doAnimation(containerGroup, renderResult, seriesModel, reRoot)
\r
31132 : renderResult.renderFinally();
\r
31134 this._resetController(api);
\r
31136 this._renderBreadcrumb(seriesModel, api, targetInfo);
\r
31142 _giveContainerGroup: function (layoutInfo) {
\r
31143 var containerGroup = this._containerGroup;
\r
31144 if (!containerGroup) {
\r
31146 // 加一层containerGroup是为了clip,但是现在clip功能并没有实现。
\r
31147 containerGroup = this._containerGroup = new Group();
\r
31148 this._initEvents(containerGroup);
\r
31149 this.group.add(containerGroup);
\r
31151 containerGroup.position = [layoutInfo.x, layoutInfo.y];
\r
31153 return containerGroup;
\r
31159 _doRender: function (containerGroup, seriesModel, reRoot) {
\r
31160 var thisTree = seriesModel.getData().tree;
\r
31161 var oldTree = this._oldTree;
\r
31163 // Clear last shape records.
\r
31164 var lastsForAnimation = createStorage();
\r
31165 var thisStorage = createStorage();
\r
31166 var oldStorage = this._storage;
\r
31167 var willInvisibleEls = [];
\r
31168 var willVisibleEls = [];
\r
31169 var willDeleteEls = [];
\r
31170 var renderNode = bind(
\r
31171 this._renderNode, this,
\r
31172 thisStorage, oldStorage, reRoot,
\r
31173 lastsForAnimation, willInvisibleEls, willVisibleEls
\r
31175 var viewRoot = seriesModel.getViewRoot();
\r
31176 var viewPath = helper.getPathToRoot(viewRoot);
\r
31178 // Notice: when thisTree and oldTree are the same tree (see list.cloneShadow),
\r
31179 // the oldTree is actually losted, so we can not find all of the old graphic
\r
31180 // elements from tree. So we use this stragegy: make element storage, move
\r
31181 // from old storage to new storage, clear old storage.
\r
31184 thisTree.root ? [thisTree.root] : [],
\r
31185 (oldTree && oldTree.root) ? [oldTree.root] : [],
\r
31187 thisTree === oldTree || !oldTree,
\r
31191 // Process all removing.
\r
31192 var willDeleteEls = clearStorage(oldStorage);
\r
31194 this._oldTree = thisTree;
\r
31195 this._storage = thisStorage;
\r
31198 lastsForAnimation: lastsForAnimation,
\r
31199 willDeleteEls: willDeleteEls,
\r
31200 renderFinally: renderFinally
\r
31203 function dualTravel(thisViewChildren, oldViewChildren, parentGroup, sameTree, viewPathIndex) {
\r
31204 // When 'render' is triggered by action,
\r
31205 // 'this' and 'old' may be the same tree,
\r
31206 // we use rawIndex in that case.
\r
31208 oldViewChildren = thisViewChildren;
\r
31209 each(thisViewChildren, function (child, index) {
\r
31210 !child.isRemoved() && processNode(index, index);
\r
31213 // Diff hierarchically (diff only in each subtree, but not whole).
\r
31214 // because, consistency of view is important.
\r
31216 (new DataDiffer(oldViewChildren, thisViewChildren, getKey, getKey))
\r
31217 .add(processNode)
\r
31218 .update(processNode)
\r
31219 .remove(zrUtil.curry(processNode, null))
\r
31223 function getKey(node) {
\r
31224 // Identify by name or raw index.
\r
31225 return node.getId();
\r
31228 function processNode(newIndex, oldIndex) {
\r
31229 var thisNode = newIndex != null ? thisViewChildren[newIndex] : null;
\r
31230 var oldNode = oldIndex != null ? oldViewChildren[oldIndex] : null;
\r
31232 // Whether under viewRoot.
\r
31234 || isNaN(viewPathIndex)
\r
31235 || (viewPathIndex < viewPath.length && viewPath[viewPathIndex] !== thisNode)
\r
31237 // Deleting nodes will be performed finally. This method just find
\r
31238 // element from old storage, or create new element, set them to new
\r
31239 // storage, and set styles.
\r
31243 var group = renderNode(thisNode, oldNode, parentGroup);
\r
31245 group && dualTravel(
\r
31246 thisNode && thisNode.viewChildren || [],
\r
31247 oldNode && oldNode.viewChildren || [],
\r
31250 viewPathIndex + 1
\r
31255 function clearStorage(storage) {
\r
31256 var willDeleteEls = createStorage();
\r
31257 storage && each(storage, function (store, storageName) {
\r
31258 var delEls = willDeleteEls[storageName];
\r
31259 each(store, function (el) {
\r
31260 el && (delEls.push(el), el.__tmWillDelete = storageName);
\r
31263 return willDeleteEls;
\r
31266 function renderFinally() {
\r
31267 each(willDeleteEls, function (els) {
\r
31268 each(els, function (el) {
\r
31269 el.parent && el.parent.remove(el);
\r
31272 // Theoritically there is no intersection between willInvisibleEls
\r
31273 // and willVisibleEls have, but we set visible after for robustness.
\r
31274 each(willInvisibleEls, function (el) {
\r
31275 el.invisible = true;
\r
31276 // Setting invisible is for optimizing, so no need to set dirty,
\r
31277 // just mark as invisible.
\r
31280 each(willVisibleEls, function (el) {
\r
31281 el.invisible = false;
\r
31282 el.__tmWillVisible = false;
\r
31291 _renderNode: function (
\r
31292 thisStorage, oldStorage, reRoot,
\r
31293 lastsForAnimation, willInvisibleEls, willVisibleEls,
\r
31294 thisNode, oldNode, parentGroup
\r
31296 var thisRawIndex = thisNode && thisNode.getRawIndex();
\r
31297 var oldRawIndex = oldNode && oldNode.getRawIndex();
\r
31299 var layout = thisNode.getLayout();
\r
31300 var thisWidth = layout.width;
\r
31301 var thisHeight = layout.height;
\r
31302 var invisible = layout.invisible;
\r
31305 var group = giveGraphic('nodeGroup', Group);
\r
31309 parentGroup.add(group);
\r
31310 group.position = [layout.x, layout.y];
\r
31311 group.__tmNodeWidth = thisWidth;
\r
31312 group.__tmNodeHeight = thisHeight;
\r
31315 var bg = giveGraphic('background', Rect, 0);
\r
31317 bg.setShape({x: 0, y: 0, width: thisWidth, height: thisHeight});
\r
31318 updateStyle(bg, {fill: thisNode.getVisual('borderColor', true)});
\r
31322 var thisViewChildren = thisNode.viewChildren;
\r
31324 // No children, render content.
\r
31325 if (!thisViewChildren || !thisViewChildren.length) {
\r
31326 var borderWidth = layout.borderWidth;
\r
31327 var content = giveGraphic('content', Rect, 3);
\r
31329 var contentWidth = Math.max(thisWidth - 2 * borderWidth, 0);
\r
31330 var contentHeight = Math.max(thisHeight - 2 * borderWidth, 0);
\r
31331 var labelModel = thisNode.getModel('label.normal');
\r
31332 var textStyleModel = thisNode.getModel('label.normal.textStyle');
\r
31333 var hoverStyle = thisNode.getModel('itemStyle.emphasis').getItemStyle();
\r
31334 var text = thisNode.getModel().get('name');
\r
31335 var textRect = textStyleModel.getTextRect(text);
\r
31336 var showLabel = labelModel.get('show');
\r
31338 if (!showLabel || textRect.height > contentHeight) {
\r
31341 else if (textRect.width > contentWidth) {
\r
31342 text = textStyleModel.get('ellipsis')
\r
31343 ? textStyleModel.ellipsis(text, contentWidth) : '';
\r
31346 graphic.setHoverStyle(content, hoverStyle);
\r
31349 content.dataIndex = thisNode.dataIndex;
\r
31350 content.seriesIndex = this.seriesModel.seriesIndex;
\r
31352 content.culling = true;
\r
31353 content.setShape({
\r
31356 width: contentWidth,
\r
31357 height: contentHeight
\r
31360 updateStyle(content, {
\r
31361 fill: thisNode.getVisual('color', true),
\r
31363 textPosition: labelModel.get('position'),
\r
31364 textFill: textStyleModel.getTextColor(),
\r
31365 textAlign: textStyleModel.get('align'),
\r
31366 textVerticalAlign: textStyleModel.get('baseline'),
\r
31367 textFont: textStyleModel.getFont()
\r
31369 group.add(content);
\r
31375 function giveGraphic(storageName, Ctor, z) {
\r
31376 var element = oldRawIndex != null && oldStorage[storageName][oldRawIndex];
\r
31377 var lasts = lastsForAnimation[storageName];
\r
31380 // Remove from oldStorage
\r
31381 oldStorage[storageName][oldRawIndex] = null;
\r
31382 prepareAnimationWhenHasOld(lasts, element, storageName);
\r
31384 // If invisible and no old element, do not create new element (for optimizing).
\r
31385 else if (!invisible) {
\r
31386 element = new Ctor({z: z});
\r
31387 prepareAnimationWhenNoOld(lasts, element, storageName);
\r
31390 // Set to thisStorage
\r
31391 return (thisStorage[storageName][thisRawIndex] = element);
\r
31394 function prepareAnimationWhenHasOld(lasts, element, storageName) {
\r
31395 var lastCfg = lasts[thisRawIndex] = {};
\r
31396 lastCfg.old = storageName === 'nodeGroup'
\r
31397 ? element.position.slice()
\r
31398 : zrUtil.extend({}, element.shape);
\r
31401 // If a element is new, we need to find the animation start point carefully,
\r
31402 // otherwise it will looks strange when 'zoomToNode'.
\r
31403 function prepareAnimationWhenNoOld(lasts, element, storageName) {
\r
31404 // New background do not animate but delay show.
\r
31405 if (storageName === 'background') {
\r
31406 element.invisible = true;
\r
31407 element.__tmWillVisible = true;
\r
31408 willVisibleEls.push(element);
\r
31411 var lastCfg = lasts[thisRawIndex] = {};
\r
31412 var parentNode = thisNode.parentNode;
\r
31414 if (parentNode && (!reRoot || reRoot.direction === 'drilldown')) {
\r
31415 var parentOldX = 0;
\r
31416 var parentOldY = 0;
\r
31417 // For convenience, get old bounding rect from background.
\r
31418 var parentOldBg = lastsForAnimation.background[parentNode.getRawIndex()];
\r
31420 if (parentOldBg && parentOldBg.old) {
\r
31421 parentOldX = parentOldBg.old.width / 2; // Devided by 2 for reRoot effect.
\r
31422 parentOldY = parentOldBg.old.height / 2;
\r
31424 // When no parent old shape found, its parent is new too,
\r
31425 // so we can just use {x:0, y:0}.
\r
31426 lastCfg.old = storageName === 'nodeGroup'
\r
31427 ? [parentOldX, parentOldY]
\r
31428 : {x: parentOldX, y: parentOldY, width: 0, height: 0};
\r
31431 // Fade in, user can be aware that these nodes are new.
\r
31432 lastCfg.fadein = storageName !== 'nodeGroup';
\r
31436 function updateStyle(element, style) {
\r
31437 if (!invisible) {
\r
31438 // If invisible, do not set visual, otherwise the element will
\r
31439 // change immediately before animation. We think it is OK to
\r
31440 // remain its origin color when moving out of the view window.
\r
31441 element.setStyle(style);
\r
31442 if (!element.__tmWillVisible) {
\r
31443 element.invisible = false;
\r
31447 // Delay invisible setting utill animation finished,
\r
31448 // avoid element vanish suddenly before animation.
\r
31449 !element.invisible && willInvisibleEls.push(element);
\r
31457 _doAnimation: function (containerGroup, renderResult, seriesModel, reRoot) {
\r
31458 if (!seriesModel.get('animation')) {
\r
31462 var duration = seriesModel.get('animationDurationUpdate');
\r
31463 var easing = seriesModel.get('animationEasing');
\r
31464 var animationWrap = animationUtil.createWrap();
\r
31466 // Make delete animations.
\r
31467 each(renderResult.willDeleteEls, function (store, storageName) {
\r
31468 each(store, function (el, rawIndex) {
\r
31471 if (el.invisible || !(storageName = el.__tmWillDelete)) {
\r
31475 var parent = el.parent; // Always has parent, and parent is nodeGroup.
\r
31478 if (reRoot && reRoot.direction === 'drilldown') {
\r
31479 if (parent === reRoot.rootNodeGroup) {
\r
31480 // Only 'content' will enter this branch, but not nodeGroup.
\r
31484 width: parent.__tmNodeWidth, height: parent.__tmNodeHeight
\r
31490 target = {style: {opacity: 0}};
\r
31498 if (!parent.__tmWillDelete) {
\r
31499 // Let node animate to right-bottom corner, cooperating with fadeout,
\r
31500 // which is appropriate for user understanding.
\r
31501 // Divided by 2 for reRoot rollup effect.
\r
31502 targetX = parent.__tmNodeWidth / 2;
\r
31503 targetY = parent.__tmNodeHeight / 2;
\r
31505 target = storageName === 'nodeGroup'
\r
31506 ? {position: [targetX, targetY], style: {opacity: 0}}
\r
31508 shape: {x: targetX, y: targetY, width: 0, height: 0},
\r
31509 style: {opacity: 0}
\r
31513 target && animationWrap.add(el, target, duration, easing);
\r
31517 // Make other animations
\r
31518 each(this._storage, function (store, storageName) {
\r
31519 each(store, function (el, rawIndex) {
\r
31520 var last = renderResult.lastsForAnimation[storageName][rawIndex];
\r
31527 if (storageName === 'nodeGroup') {
\r
31529 target.position = el.position.slice();
\r
31530 el.position = last.old;
\r
31535 target.shape = zrUtil.extend({}, el.shape);
\r
31536 el.setShape(last.old);
\r
31539 if (last.fadein) {
\r
31540 el.setStyle('opacity', 0);
\r
31541 target.style = {opacity: 1};
\r
31543 // When animation is stopped for succedent animation starting,
\r
31544 // el.style.opacity might not be 1
\r
31545 else if (el.style.opacity !== 1) {
\r
31546 target.style = {opacity: 1};
\r
31549 animationWrap.add(el, target, duration, easing);
\r
31553 this._state = 'animating';
\r
31556 .done(bind(function () {
\r
31557 this._state = 'ready';
\r
31558 renderResult.renderFinally();
\r
31566 _resetController: function (api) {
\r
31567 var controller = this._controller;
\r
31569 // Init controller.
\r
31570 if (!controller) {
\r
31571 controller = this._controller = new RoamController(api.getZr());
\r
31572 controller.enable(this.seriesModel.get('roam'));
\r
31573 controller.on('pan', bind(this._onPan, this));
\r
31574 controller.on('zoom', bind(this._onZoom, this));
\r
31577 controller.rect = new BoundingRect(0, 0, api.getWidth(), api.getHeight());
\r
31583 _clearController: function () {
\r
31584 var controller = this._controller;
\r
31585 if (controller) {
\r
31586 controller.off('pan').off('zoom');
\r
31587 controller = null;
\r
31594 _onPan: function (dx, dy) {
\r
31595 this._mayClick = false;
\r
31597 if (this._state !== 'animating'
\r
31598 && (Math.abs(dx) > DRAG_THRESHOLD || Math.abs(dy) > DRAG_THRESHOLD)
\r
31600 // These param must not be cached.
\r
31601 var viewRoot = this.seriesModel.getViewRoot();
\r
31607 var rootLayout = viewRoot.getLayout();
\r
31609 if (!rootLayout) {
\r
31613 this.api.dispatchAction({
\r
31614 type: 'treemapMove',
\r
31616 seriesId: this.seriesModel.id,
\r
31618 x: rootLayout.x + dx, y: rootLayout.y + dy,
\r
31619 width: rootLayout.width, height: rootLayout.height
\r
31628 _onZoom: function (scale, mouseX, mouseY) {
\r
31629 this._mayClick = false;
\r
31631 if (this._state !== 'animating') {
\r
31632 // These param must not be cached.
\r
31633 var viewRoot = this.seriesModel.getViewRoot();
\r
31639 var rootLayout = viewRoot.getLayout();
\r
31641 if (!rootLayout) {
\r
31645 var rect = new BoundingRect(
\r
31646 rootLayout.x, rootLayout.y, rootLayout.width, rootLayout.height
\r
31648 var layoutInfo = this.seriesModel.layoutInfo;
\r
31650 // Transform mouse coord from global to containerGroup.
\r
31651 mouseX -= layoutInfo.x;
\r
31652 mouseY -= layoutInfo.y;
\r
31654 // Scale root bounding rect.
\r
31655 var m = matrix.create();
\r
31656 matrix.translate(m, m, [-mouseX, -mouseY]);
\r
31657 matrix.scale(m, m, [scale, scale]);
\r
31658 matrix.translate(m, m, [mouseX, mouseY]);
\r
31660 rect.applyTransform(m);
\r
31662 this.api.dispatchAction({
\r
31663 type: 'treemapRender',
\r
31665 seriesId: this.seriesModel.id,
\r
31667 x: rect.x, y: rect.y,
\r
31668 width: rect.width, height: rect.height
\r
31677 _initEvents: function (containerGroup) {
\r
31679 // 不用click以及silent的原因是,animate时视图设置silent true来避免click生效,
\r
31680 // 但是animate中,按下鼠标,animate结束后(silent设回为false)松开鼠标,
\r
31681 // 还是会触发click,期望是不触发。
\r
31683 // Mousedown occurs when drag start, and mouseup occurs when drag end,
\r
31684 // click event should not be triggered in that case.
\r
31686 containerGroup.on('mousedown', function (e) {
\r
31687 this._state === 'ready' && (this._mayClick = true);
\r
31689 containerGroup.on('mouseup', function (e) {
\r
31690 if (this._mayClick) {
\r
31691 this._mayClick = false;
\r
31692 this._state === 'ready' && onClick.call(this, e);
\r
31696 function onClick(e) {
\r
31697 var nodeClick = this.seriesModel.get('nodeClick', true);
\r
31699 if (!nodeClick) {
\r
31703 var targetInfo = this.findTarget(e.offsetX, e.offsetY);
\r
31705 if (!targetInfo) {
\r
31709 var node = targetInfo.node;
\r
31710 if (node.getLayout().isLeafRoot) {
\r
31711 this._rootToNode(targetInfo);
\r
31714 if (nodeClick === 'zoomToNode') {
\r
31715 this._zoomToNode(targetInfo);
\r
31717 else if (nodeClick === 'link') {
\r
31718 var itemModel = node.hostTree.data.getItemModel(node.dataIndex);
\r
31719 var link = itemModel.get('link', true);
\r
31720 var linkTarget = itemModel.get('target', true) || 'blank';
\r
31721 link && window.open(link, linkTarget);
\r
31730 _renderBreadcrumb: function (seriesModel, api, targetInfo) {
\r
31731 if (!targetInfo) {
\r
31732 // Find breadcrumb tail on center of containerGroup.
\r
31733 targetInfo = this.findTarget(api.getWidth() / 2, api.getHeight() / 2);
\r
31735 if (!targetInfo) {
\r
31736 targetInfo = {node: seriesModel.getData().tree.root};
\r
31740 (this._breadcrumb || (this._breadcrumb = new Breadcrumb(this.group, bind(onSelect, this))))
\r
31741 .render(seriesModel, api, targetInfo.node);
\r
31743 function onSelect(node) {
\r
31744 if (this._state !== 'animating') {
\r
31745 helper.aboveViewRoot(seriesModel.getViewRoot(), node)
\r
31746 ? this._rootToNode({node: node})
\r
31747 : this._zoomToNode({node: node});
\r
31755 remove: function () {
\r
31756 this._clearController();
\r
31757 this._containerGroup && this._containerGroup.removeAll();
\r
31758 this._storage = createStorage();
\r
31759 this._state = 'ready';
\r
31760 this._breadcrumb && this._breadcrumb.remove();
\r
31763 dispose: function () {
\r
31764 this._clearController();
\r
31770 _zoomToNode: function (targetInfo) {
\r
31771 this.api.dispatchAction({
\r
31772 type: 'treemapZoomToNode',
\r
31774 seriesId: this.seriesModel.id,
\r
31775 targetNode: targetInfo.node
\r
31782 _rootToNode: function (targetInfo) {
\r
31783 this.api.dispatchAction({
\r
31784 type: 'treemapRootToNode',
\r
31786 seriesId: this.seriesModel.id,
\r
31787 targetNode: targetInfo.node
\r
31793 * @param {number} x Global coord x.
\r
31794 * @param {number} y Global coord y.
\r
31795 * @return {Object} info If not found, return undefined;
\r
31796 * @return {number} info.node Target node.
\r
31797 * @return {number} info.offsetX x refer to target node.
\r
31798 * @return {number} info.offsetY y refer to target node.
\r
31800 findTarget: function (x, y) {
\r
31802 var viewRoot = this.seriesModel.getViewRoot();
\r
31804 viewRoot.eachNode({attr: 'viewChildren', order: 'preorder'}, function (node) {
\r
31805 var bgEl = this._storage.background[node.getRawIndex()];
\r
31806 // If invisible, there might be no element.
\r
31808 var point = bgEl.transformCoordToLocal(x, y);
\r
31809 var shape = bgEl.shape;
\r
31811 // For performance consideration, dont use 'getBoundingRect'.
\r
31812 if (shape.x <= point[0]
\r
31813 && point[0] <= shape.x + shape.width
\r
31814 && shape.y <= point[1]
\r
31815 && point[1] <= shape.y + shape.height
\r
31817 targetInfo = {node: node, offsetX: point[0], offsetY: point[1]};
\r
31820 return false; // Suppress visit subtree.
\r
31825 return targetInfo;
\r
31830 function createStorage() {
\r
31831 return {nodeGroup: [], background: [], content: []};
\r
31838 /***/ function(module, exports, __webpack_require__) {
\r
31842 var graphic = __webpack_require__(42);
\r
31843 var layout = __webpack_require__(21);
\r
31844 var zrUtil = __webpack_require__(3);
\r
31846 var TEXT_PADDING = 8;
\r
31847 var ITEM_GAP = 8;
\r
31848 var ARRAY_LENGTH = 5;
\r
31850 function Breadcrumb(containerGroup, onSelect) {
\r
31853 * @type {module:zrender/container/Group}
\r
31855 this.group = new graphic.Group();
\r
31857 containerGroup.add(this.group);
\r
31861 * @type {Function}
\r
31863 this._onSelect = onSelect || zrUtil.noop;
\r
31866 Breadcrumb.prototype = {
\r
31868 constructor: Breadcrumb,
\r
31870 render: function (seriesModel, api, targetNode) {
\r
31871 var model = seriesModel.getModel('breadcrumb');
\r
31872 var thisGroup = this.group;
\r
31874 thisGroup.removeAll();
\r
31876 if (!model.get('show') || !targetNode) {
\r
31880 var normalStyleModel = model.getModel('itemStyle.normal');
\r
31881 // var emphasisStyleModel = model.getModel('itemStyle.emphasis');
\r
31882 var textStyleModel = normalStyleModel.getModel('textStyle');
\r
31884 var layoutParam = {
\r
31886 left: model.get('left'),
\r
31887 right: model.get('right'),
\r
31888 top: model.get('top'),
\r
31889 bottom: model.get('bottom')
\r
31892 width: api.getWidth(),
\r
31893 height: api.getHeight()
\r
31895 emptyItemWidth: model.get('emptyItemWidth'),
\r
31901 model, targetNode, layoutParam, textStyleModel
\r
31903 this._renderContent(
\r
31904 model, targetNode, layoutParam, normalStyleModel, textStyleModel
\r
31907 layout.positionGroup(thisGroup, layoutParam.pos, layoutParam.box);
\r
31911 * Prepare render list and total width
\r
31914 _prepare: function (model, targetNode, layoutParam, textStyleModel) {
\r
31915 for (var node = targetNode; node; node = node.parentNode) {
\r
31916 var text = node.getModel().get('name');
\r
31917 var textRect = textStyleModel.getTextRect(text);
\r
31918 var itemWidth = Math.max(
\r
31919 textRect.width + TEXT_PADDING * 2,
\r
31920 layoutParam.emptyItemWidth
\r
31922 layoutParam.totalWidth += itemWidth + ITEM_GAP;
\r
31923 layoutParam.renderList.push({node: node, text: text, width: itemWidth});
\r
31930 _renderContent: function (
\r
31931 model, targetNode, layoutParam, normalStyleModel, textStyleModel
\r
31933 // Start rendering.
\r
31935 var emptyItemWidth = layoutParam.emptyItemWidth;
\r
31936 var height = model.get('height');
\r
31937 var availableSize = layout.getAvailableSize(layoutParam.pos, layoutParam.box);
\r
31938 var totalWidth = layoutParam.totalWidth;
\r
31939 var renderList = layoutParam.renderList;
\r
31941 for (var i = renderList.length - 1; i >= 0; i--) {
\r
31942 var item = renderList[i];
\r
31943 var itemWidth = item.width;
\r
31944 var text = item.text;
\r
31946 // Hdie text and shorten width if necessary.
\r
31947 if (totalWidth > availableSize.width) {
\r
31948 totalWidth -= itemWidth - emptyItemWidth;
\r
31949 itemWidth = emptyItemWidth;
\r
31953 this.group.add(new graphic.Polygon({
\r
31955 points: makeItemPoints(
\r
31956 lastX, 0, itemWidth, height,
\r
31957 i === renderList.length - 1, i === 0
\r
31960 style: zrUtil.defaults(
\r
31961 normalStyleModel.getItemStyle(),
\r
31963 lineJoin: 'bevel',
\r
31965 textFill: textStyleModel.getTextColor(),
\r
31966 textFont: textStyleModel.getFont()
\r
31970 onclick: zrUtil.bind(this._onSelect, this, item.node)
\r
31973 lastX += itemWidth + ITEM_GAP;
\r
31980 remove: function () {
\r
31981 this.group.removeAll();
\r
31985 function makeItemPoints(x, y, itemWidth, itemHeight, head, tail) {
\r
31987 [head ? x : x - ARRAY_LENGTH, y],
\r
31988 [x + itemWidth, y],
\r
31989 [x + itemWidth, y + itemHeight],
\r
31990 [head ? x : x - ARRAY_LENGTH, y + itemHeight]
\r
31992 !tail && points.splice(2, 0, [x + itemWidth + ARRAY_LENGTH, y + itemHeight / 2]);
\r
31993 !head && points.push([x, y + itemHeight / 2]);
\r
31997 module.exports = Breadcrumb;
\r
32002 /***/ function(module, exports, __webpack_require__) {
\r
32006 var zrUtil = __webpack_require__(3);
\r
32009 * @param {number} [time=500] Time in ms
\r
32010 * @param {string} [easing='linear']
\r
32011 * @param {number} [delay=0]
\r
32012 * @param {Function} [callback]
\r
32015 * // Animate position
\r
32018 * .add(el1, {position: [10, 10]})
\r
32019 * .add(el2, {shape: {width: 500}, style: {fill: 'red'}}, 400)
\r
32020 * .done(function () { // done })
\r
32021 * .start('cubicOut');
\r
32023 function createWrap() {
\r
32025 var storage = [];
\r
32026 var elExistsMap = {};
\r
32027 var doneCallback;
\r
32032 * Caution: a el can only be added once, otherwise 'done'
\r
32033 * might not be called. This method checks this (by el.id),
\r
32034 * suppresses adding and returns false when existing el found.
\r
32036 * @param {modele:zrender/Element} el
\r
32037 * @param {Object} target
\r
32038 * @param {number} [time=500]
\r
32039 * @param {number} [delay=0]
\r
32040 * @param {string} [easing='linear']
\r
32041 * @return {boolean} Whether adding succeeded.
\r
32044 * add(el, target, time, delay, easing);
\r
32045 * add(el, target, time, easing);
\r
32046 * add(el, target, time);
\r
32047 * add(el, target);
\r
32049 add: function (el, target, time, delay, easing) {
\r
32050 if (zrUtil.isString(delay)) {
\r
32055 if (elExistsMap[el.id]) {
\r
32058 elExistsMap[el.id] = 1;
\r
32061 {el: el, target: target, time: time, delay: delay, easing: easing}
\r
32068 * Only execute when animation finished. Will not execute when any
\r
32069 * of 'stop' or 'stopAnimation' called.
\r
32071 * @param {Function} callback
\r
32073 done: function (callback) {
\r
32074 doneCallback = callback;
\r
32079 * Will stop exist animation firstly.
\r
32081 start: function () {
\r
32082 var count = storage.length;
\r
32084 for (var i = 0, len = storage.length; i < len; i++) {
\r
32085 var item = storage[i];
\r
32086 item.el.animateTo(item.target, item.time, item.delay, item.easing, done);
\r
32091 function done() {
\r
32094 storage.length = 0;
\r
32095 elExistsMap = {};
\r
32096 doneCallback && doneCallback();
\r
32103 module.exports = {createWrap: createWrap};
\r
32108 /***/ function(module, exports, __webpack_require__) {
\r
32111 * @file Treemap action
\r
32115 var echarts = __webpack_require__(1);
\r
32116 var helper = __webpack_require__(181);
\r
32118 var noop = function () {};
\r
32120 var actionTypes = [
\r
32121 'treemapZoomToNode',
\r
32126 for (var i = 0; i < actionTypes.length; i++) {
\r
32127 echarts.registerAction({type: actionTypes[i], update: 'updateView'}, noop);
\r
32130 echarts.registerAction(
\r
32131 {type: 'treemapRootToNode', update: 'updateView'},
\r
32132 function (payload, ecModel) {
\r
32133 ecModel.eachComponent(
\r
32134 {mainType: 'series', subType: 'treemap', query: payload},
\r
32135 function (model, index) {
\r
32136 var targetInfo = helper.retrieveTargetInfo(payload, model);
\r
32138 if (targetInfo) {
\r
32139 var originViewRoot = model.getViewRoot();
\r
32140 if (originViewRoot) {
\r
32141 payload.direction = helper.aboveViewRoot(originViewRoot, targetInfo.node)
\r
32142 ? 'rollup' : 'drilldown';
\r
32144 model.resetViewRoot(targetInfo.node);
\r
32155 /***/ function(module, exports, __webpack_require__) {
\r
32159 var VisualMapping = __webpack_require__(187);
\r
32160 var zrColor = __webpack_require__(38);
\r
32161 var zrUtil = __webpack_require__(3);
\r
32162 var isArray = zrUtil.isArray;
\r
32164 var ITEM_STYLE_NORMAL = 'itemStyle.normal';
\r
32166 module.exports = function (ecModel, payload) {
\r
32168 var condition = {mainType: 'series', subType: 'treemap', query: payload};
\r
32169 ecModel.eachComponent(condition, function (seriesModel) {
\r
32171 var tree = seriesModel.getData().tree;
\r
32172 var root = tree.root;
\r
32173 var seriesItemStyleModel = seriesModel.getModel(ITEM_STYLE_NORMAL);
\r
32175 if (root.isRemoved()) {
\r
32179 var levelItemStyles = zrUtil.map(tree.levelModels, function (levelModel) {
\r
32180 return levelModel ? levelModel.get(ITEM_STYLE_NORMAL) : null;
\r
32187 seriesItemStyleModel,
\r
32188 seriesModel.getViewRoot().getAncestors(),
\r
32194 function travelTree(
\r
32195 node, designatedVisual, levelItemStyles, seriesItemStyleModel,
\r
32196 viewRootAncestors, seriesModel
\r
32198 var nodeModel = node.getModel();
\r
32199 var nodeLayout = node.getLayout();
\r
32202 if (nodeLayout.invisible) {
\r
32206 var nodeItemStyleModel = node.getModel(ITEM_STYLE_NORMAL);
\r
32207 var levelItemStyle = levelItemStyles[node.depth];
\r
32208 var visuals = buildVisuals(
\r
32209 nodeItemStyleModel, designatedVisual, levelItemStyle, seriesItemStyleModel
\r
32212 // calculate border color
\r
32213 var borderColor = nodeItemStyleModel.get('borderColor');
\r
32214 var borderColorSaturation = nodeItemStyleModel.get('borderColorSaturation');
\r
32215 var thisNodeColor;
\r
32216 if (borderColorSaturation != null) {
\r
32217 // For performance, do not always execute 'calculateColor'.
\r
32218 thisNodeColor = calculateColor(visuals, node);
\r
32219 borderColor = calculateBorderColor(borderColorSaturation, thisNodeColor);
\r
32221 node.setVisual('borderColor', borderColor);
\r
32223 var viewChildren = node.viewChildren;
\r
32224 if (!viewChildren || !viewChildren.length) {
\r
32225 thisNodeColor = calculateColor(visuals, node);
\r
32226 // Apply visual to this node.
\r
32227 node.setVisual('color', thisNodeColor);
\r
32230 var mapping = buildVisualMapping(
\r
32231 node, nodeModel, nodeLayout, nodeItemStyleModel, visuals, viewChildren
\r
32233 // Designate visual to children.
\r
32234 zrUtil.each(viewChildren, function (child, index) {
\r
32235 // If higher than viewRoot, only ancestors of viewRoot is needed to visit.
\r
32236 if (child.depth >= viewRootAncestors.length
\r
32237 || child === viewRootAncestors[child.depth]
\r
32239 var childVisual = mapVisual(
\r
32240 nodeModel, visuals, child, index, mapping, seriesModel
\r
32243 child, childVisual, levelItemStyles, seriesItemStyleModel,
\r
32244 viewRootAncestors, seriesModel
\r
32251 function buildVisuals(
\r
32252 nodeItemStyleModel, designatedVisual, levelItemStyle, seriesItemStyleModel
\r
32254 var visuals = zrUtil.extend({}, designatedVisual);
\r
32256 zrUtil.each(['color', 'colorAlpha', 'colorSaturation'], function (visualName) {
\r
32257 // Priority: thisNode > thisLevel > parentNodeDesignated > seriesModel
\r
32258 var val = nodeItemStyleModel.get(visualName, true); // Ignore parent
\r
32259 val == null && levelItemStyle && (val = levelItemStyle[visualName]);
\r
32260 val == null && (val = designatedVisual[visualName]);
\r
32261 val == null && (val = seriesItemStyleModel.get(visualName));
\r
32263 val != null && (visuals[visualName] = val);
\r
32269 function calculateColor(visuals) {
\r
32270 var color = getValueVisualDefine(visuals, 'color');
\r
32273 var colorAlpha = getValueVisualDefine(visuals, 'colorAlpha');
\r
32274 var colorSaturation = getValueVisualDefine(visuals, 'colorSaturation');
\r
32275 if (colorSaturation) {
\r
32276 color = zrColor.modifyHSL(color, null, null, colorSaturation);
\r
32278 if (colorAlpha) {
\r
32279 color = zrColor.modifyAlpha(color, colorAlpha);
\r
32286 function calculateBorderColor(borderColorSaturation, thisNodeColor) {
\r
32287 return thisNodeColor != null
\r
32288 ? zrColor.modifyHSL(thisNodeColor, null, null, borderColorSaturation)
\r
32292 function getValueVisualDefine(visuals, name) {
\r
32293 var value = visuals[name];
\r
32294 if (value != null && value !== 'none') {
\r
32299 function buildVisualMapping(
\r
32300 node, nodeModel, nodeLayout, nodeItemStyleModel, visuals, viewChildren
\r
32302 if (!viewChildren || !viewChildren.length) {
\r
32306 var rangeVisual = getRangeVisual(nodeModel, 'color')
\r
32308 visuals.color != null
\r
32309 && visuals.color !== 'none'
\r
32311 getRangeVisual(nodeModel, 'colorAlpha')
\r
32312 || getRangeVisual(nodeModel, 'colorSaturation')
\r
32316 if (!rangeVisual) {
\r
32320 var colorMappingBy = nodeModel.get('colorMappingBy');
\r
32322 type: rangeVisual.name,
\r
32323 dataExtent: nodeLayout.dataExtent,
\r
32324 visual: rangeVisual.range
\r
32326 if (opt.type === 'color'
\r
32327 && (colorMappingBy === 'index' || colorMappingBy === 'id')
\r
32329 opt.mappingMethod = 'category';
\r
32331 // categories is ordinal, so do not set opt.categories.
\r
32334 opt.mappingMethod = 'linear';
\r
32337 var mapping = new VisualMapping(opt);
\r
32338 mapping.__drColorMappingBy = colorMappingBy;
\r
32343 // Notice: If we dont have the attribute 'colorRange', but only use
\r
32344 // attribute 'color' to represent both concepts of 'colorRange' and 'color',
\r
32345 // (It means 'colorRange' when 'color' is Array, means 'color' when not array),
\r
32346 // this problem will be encountered:
\r
32347 // If a level-1 node dont have children, and its siblings has children,
\r
32348 // and colorRange is set on level-1, then the node can not be colored.
\r
32349 // So we separate 'colorRange' and 'color' to different attributes.
\r
32350 function getRangeVisual(nodeModel, name) {
\r
32351 // 'colorRange', 'colorARange', 'colorSRange'.
\r
32352 // If not exsits on this node, fetch from levels and series.
\r
32353 var range = nodeModel.get(name);
\r
32354 return (isArray(range) && range.length) ? {name: name, range: range} : null;
\r
32357 function mapVisual(nodeModel, visuals, child, index, mapping, seriesModel) {
\r
32358 var childVisuals = zrUtil.extend({}, visuals);
\r
32361 var mappingType = mapping.type;
\r
32362 var colorMappingBy = mappingType === 'color' && mapping.__drColorMappingBy;
\r
32364 colorMappingBy === 'index'
\r
32366 : colorMappingBy === 'id'
\r
32367 ? seriesModel.mapIdToIndex(child.getId())
\r
32368 : child.getValue(nodeModel.get('visualDimension'));
\r
32370 childVisuals[mappingType] = mapping.mapValueToVisual(value);
\r
32373 return childVisuals;
\r
32380 /***/ function(module, exports, __webpack_require__) {
\r
32383 * @file Visual mapping.
\r
32387 var zrUtil = __webpack_require__(3);
\r
32388 var zrColor = __webpack_require__(38);
\r
32389 var linearMap = __webpack_require__(7).linearMap;
\r
32390 var each = zrUtil.each;
\r
32391 var isObject = zrUtil.isObject;
\r
32393 var CATEGORY_DEFAULT_VISUAL_INDEX = -1;
\r
32395 function linearMapArray(val, domain, range, clamp) {
\r
32396 if (zrUtil.isArray(val)) {
\r
32397 return zrUtil.map(val, function (v) {
\r
32398 return linearMap(v, domain, range, clamp);
\r
32401 return linearMap(val, domain, range, clamp);
\r
32404 * @param {Object} option
\r
32405 * @param {string} [option.type] See visualHandlers.
\r
32406 * @param {string} [option.mappingMethod] 'linear' or 'piecewise' or 'category'
\r
32407 * @param {Array.<number>=} [option.dataExtent] [minExtent, maxExtent],
\r
32408 * required when mappingMethod is 'linear'
\r
32409 * @param {Array.<Object>=} [option.pieceList] [
\r
32410 * {value: someValue},
\r
32411 * {interval: [min1, max1], visual: {...}},
\r
32412 * {interval: [min2, max2]}
\r
32414 * required when mappingMethod is 'piecewise'.
\r
32415 * Visual for only each piece can be specified.
\r
32416 * @param {Array.<string|Object>=} [option.categories] ['cate1', 'cate2']
\r
32417 * required when mappingMethod is 'category'.
\r
32418 * If no option.categories, it represents
\r
32419 * categories is [0, 1, 2, ...].
\r
32420 * @param {boolean} [option.loop=false] Whether loop mapping when mappingMethod is 'category'.
\r
32421 * @param {(Array|Object|*)} [option.visual] Visual data.
\r
32422 * when mappingMethod is 'category',
\r
32423 * visual data can be array or object
\r
32424 * (like: {cate1: '#222', none: '#fff'})
\r
32425 * or primary types (which represents
\r
32426 * defualt category visual), otherwise visual
\r
32427 * can only be array.
\r
32430 var VisualMapping = function (option) {
\r
32431 var mappingMethod = option.mappingMethod;
\r
32432 var visualType = option.type;
\r
32438 this.type = visualType;
\r
32444 this.mappingMethod = mappingMethod;
\r
32450 var thisOption = this.option = zrUtil.clone(option);
\r
32454 * @type {Function}
\r
32456 this._normalizeData = normalizers[mappingMethod];
\r
32460 * @type {Function}
\r
32462 this._getSpecifiedVisual = zrUtil.bind(
\r
32463 specifiedVisualGetters[mappingMethod], this, visualType
\r
32466 zrUtil.extend(this, visualHandlers[visualType]);
\r
32468 if (mappingMethod === 'piecewise') {
\r
32469 preprocessForPiecewise(thisOption);
\r
32471 if (mappingMethod === 'category') {
\r
32472 preprocessForCategory(thisOption);
\r
32476 VisualMapping.prototype = {
\r
32478 constructor: VisualMapping,
\r
32480 applyVisual: null,
\r
32482 isValueActive: null,
\r
32484 mapValueToVisual: null,
\r
32486 getNormalizer: function () {
\r
32487 return zrUtil.bind(this._normalizeData, this);
\r
32491 var visualHandlers = VisualMapping.visualHandlers = {
\r
32495 applyVisual: defaultApplyColor,
\r
32498 * Create a mapper function
\r
32499 * @return {Function}
\r
32501 getColorMapper: function () {
\r
32502 var visual = isCategory(this)
\r
32503 ? this.option.visual
\r
32504 : zrUtil.map(this.option.visual, zrColor.parse);
\r
32505 return zrUtil.bind(
\r
32507 ? function (value, isNormalized) {
\r
32508 !isNormalized && (value = this._normalizeData(value));
\r
32509 return getVisualForCategory(this, visual, value);
\r
32511 : function (value, isNormalized, out) {
\r
32512 // If output rgb array
\r
32513 // which will be much faster and useful in pixel manipulation
\r
32514 var returnRGBArray = !!out;
\r
32515 !isNormalized && (value = this._normalizeData(value));
\r
32516 out = zrColor.fastMapToColor(value, visual, out);
\r
32517 return returnRGBArray ? out : zrUtil.stringify(out, 'rgba');
\r
32523 // (2) {Array.<number>} Represents a interval, for colorStops.
\r
32525 // (1) {string} color value like '#444'
\r
32526 // (2) {Array.<Object>} colorStops,
\r
32527 // like [{color: '#fff', offset: 0}, {color: '#444', offset: 1}]
\r
32528 // where offset is between 0 and 1.
\r
32529 mapValueToVisual: function (value) {
\r
32530 var visual = this.option.visual;
\r
32532 if (zrUtil.isArray(value)) {
\r
32534 this._normalizeData(value[0]),
\r
32535 this._normalizeData(value[1])
\r
32538 // For creating gradient color list.
\r
32539 return zrColor.mapIntervalToColor(value, visual);
\r
32542 var normalized = this._normalizeData(value);
\r
32543 var result = this._getSpecifiedVisual(value);
\r
32545 if (result == null) {
\r
32546 result = isCategory(this)
\r
32547 ? getVisualForCategory(this, visual, normalized)
\r
32548 : zrColor.mapToColor(normalized, visual);
\r
32556 colorHue: makePartialColorVisualHandler(function (color, value) {
\r
32557 return zrColor.modifyHSL(color, value);
\r
32560 colorSaturation: makePartialColorVisualHandler(function (color, value) {
\r
32561 return zrColor.modifyHSL(color, null, value);
\r
32564 colorLightness: makePartialColorVisualHandler(function (color, value) {
\r
32565 return zrColor.modifyHSL(color, null, null, value);
\r
32568 colorAlpha: makePartialColorVisualHandler(function (color, value) {
\r
32569 return zrColor.modifyAlpha(color, value);
\r
32573 applyVisual: function (value, getter, setter) {
\r
32574 var symbolCfg = this.mapValueToVisual(value);
\r
32575 if (zrUtil.isString(symbolCfg)) {
\r
32576 setter('symbol', symbolCfg);
\r
32578 else if (isObject(symbolCfg)) {
\r
32579 for (var name in symbolCfg) {
\r
32580 if (symbolCfg.hasOwnProperty(name)) {
\r
32581 setter(name, symbolCfg[name]);
\r
32587 mapValueToVisual: function (value) {
\r
32588 var normalized = this._normalizeData(value);
\r
32589 var result = this._getSpecifiedVisual(value);
\r
32590 var visual = this.option.visual;
\r
32592 if (result == null) {
\r
32593 result = isCategory(this)
\r
32594 ? getVisualForCategory(this, visual, normalized)
\r
32595 : (arrayGetByNormalizedValue(visual, normalized) || {});
\r
32603 applyVisual: function (value, getter, setter) {
\r
32604 setter('symbolSize', this.mapValueToVisual(value));
\r
32607 mapValueToVisual: function (value) {
\r
32608 var normalized = this._normalizeData(value);
\r
32609 var result = this._getSpecifiedVisual(value);
\r
32610 var visual = this.option.visual;
\r
32612 if (result == null) {
\r
32613 result = isCategory(this)
\r
32614 ? getVisualForCategory(this, visual, normalized)
\r
32615 : linearMapArray(normalized, [0, 1], visual, true);
\r
32622 function preprocessForPiecewise(thisOption) {
\r
32623 var pieceList = thisOption.pieceList;
\r
32624 thisOption.hasSpecialVisual = false;
\r
32626 zrUtil.each(pieceList, function (piece, index) {
\r
32627 piece.originIndex = index;
\r
32628 if (piece.visual) {
\r
32629 thisOption.hasSpecialVisual = true;
\r
32634 function preprocessForCategory(thisOption) {
\r
32635 // Hash categories.
\r
32636 var categories = thisOption.categories;
\r
32637 var visual = thisOption.visual;
\r
32638 var isVisualArray = zrUtil.isArray(visual);
\r
32640 if (!categories) {
\r
32641 if (!isVisualArray) {
\r
32642 // visual should be array when no categories.
\r
32643 throw new Error();
\r
32650 var categoryMap = thisOption.categoryMap = {};
\r
32651 each(categories, function (cate, index) {
\r
32652 categoryMap[cate] = index;
\r
32655 // Process visual map input.
\r
32656 if (!isVisualArray) {
\r
32657 var visualArr = [];
\r
32659 if (zrUtil.isObject(visual)) {
\r
32660 each(visual, function (v, cate) {
\r
32661 var index = categoryMap[cate];
\r
32662 visualArr[index != null ? index : CATEGORY_DEFAULT_VISUAL_INDEX] = v;
\r
32665 else { // Is primary type, represents default visual.
\r
32666 visualArr[CATEGORY_DEFAULT_VISUAL_INDEX] = visual;
\r
32669 visual = thisOption.visual = visualArr;
\r
32672 // Remove categories that has no visual,
\r
32673 // then we can mapping them to CATEGORY_DEFAULT_VISUAL_INDEX.
\r
32674 for (var i = categories.length - 1; i >= 0; i--) {
\r
32675 if (visual[i] == null) {
\r
32676 delete categoryMap[categories[i]];
\r
32677 categories.pop();
\r
32682 function makePartialColorVisualHandler(applyValue) {
\r
32685 applyVisual: function (value, getter, setter) {
\r
32686 // color can be {string} or {Array.<Object>} (for gradient color stops)
\r
32687 var color = getter('color');
\r
32688 var isArrayValue = zrUtil.isArray(value);
\r
32689 value = isArrayValue
\r
32690 ? [this.mapValueToVisual(value[0]), this.mapValueToVisual(value[1])]
\r
32691 : this.mapValueToVisual(value);
\r
32693 if (zrUtil.isArray(color)) {
\r
32694 for (var i = 0, len = color.length; i < len; i++) {
\r
32695 color[i].color = applyValue(
\r
32696 color[i].color, isArrayValue ? value[i] : value
\r
32701 // Must not be array value
\r
32702 setter('color', applyValue(color, value));
\r
32706 mapValueToVisual: function (value) {
\r
32707 var normalized = this._normalizeData(value);
\r
32708 var result = this._getSpecifiedVisual(value);
\r
32709 var visual = this.option.visual;
\r
32711 if (result == null) {
\r
32712 result = isCategory(this)
\r
32713 ? getVisualForCategory(this, visual, normalized)
\r
32714 : linearMapArray(normalized, [0, 1], visual, true);
\r
32721 function arrayGetByNormalizedValue(arr, normalized) {
\r
32723 Math.round(linearMapArray(normalized, [0, 1], [0, arr.length - 1], true))
\r
32727 function defaultApplyColor(value, getter, setter) {
\r
32728 setter('color', this.mapValueToVisual(value));
\r
32731 function getVisualForCategory(me, visual, normalized) {
\r
32733 (me.option.loop && normalized !== CATEGORY_DEFAULT_VISUAL_INDEX)
\r
32734 ? normalized % visual.length
\r
32739 function isCategory(me) {
\r
32740 return me.option.mappingMethod === 'category';
\r
32744 var normalizers = {
\r
32746 linear: function (value) {
\r
32747 return linearMapArray(value, this.option.dataExtent, [0, 1], true);
\r
32750 piecewise: function (value) {
\r
32751 var pieceList = this.option.pieceList;
\r
32752 var pieceIndex = VisualMapping.findPieceIndex(value, pieceList);
\r
32753 if (pieceIndex != null) {
\r
32754 return linearMapArray(pieceIndex, [0, pieceList.length - 1], [0, 1], true);
\r
32758 category: function (value) {
\r
32759 var index = this.option.categories
\r
32760 ? this.option.categoryMap[value]
\r
32761 : value; // ordinal
\r
32762 return index == null ? CATEGORY_DEFAULT_VISUAL_INDEX : index;
\r
32769 var specifiedVisualGetters = {
\r
32771 // Linear do not support this feature.
\r
32772 linear: zrUtil.noop,
\r
32774 piecewise: function (visualType, value) {
\r
32775 var thisOption = this.option;
\r
32776 var pieceList = thisOption.pieceList;
\r
32777 if (thisOption.hasSpecialVisual) {
\r
32778 var pieceIndex = VisualMapping.findPieceIndex(value, pieceList);
\r
32779 var piece = pieceList[pieceIndex];
\r
32780 if (piece && piece.visual) {
\r
32781 return piece.visual[visualType];
\r
32786 // Category do not need to support this feature.
\r
32787 // Visual can be set in visualMap.inRange or
\r
32788 // visualMap.outOfRange directly.
\r
32789 category: zrUtil.noop
\r
32795 VisualMapping.addVisualHandler = function (name, handler) {
\r
32796 visualHandlers[name] = handler;
\r
32802 VisualMapping.isValidType = function (visualType) {
\r
32803 return visualHandlers.hasOwnProperty(visualType);
\r
32807 * Convinent method.
\r
32808 * Visual can be Object or Array or primary type.
\r
32812 VisualMapping.eachVisual = function (visual, callback, context) {
\r
32813 if (zrUtil.isObject(visual)) {
\r
32814 zrUtil.each(visual, callback, context);
\r
32817 callback.call(context, visual);
\r
32821 VisualMapping.mapVisual = function (visual, callback, context) {
\r
32823 var newVisual = zrUtil.isArray(visual)
\r
32825 : zrUtil.isObject(visual)
\r
32827 : (isPrimary = true, null);
\r
32829 VisualMapping.eachVisual(visual, function (v, key) {
\r
32830 var newVal = callback.call(context, v, key);
\r
32831 isPrimary ? (newVisual = newVal) : (newVisual[key] = newVal);
\r
32833 return newVisual;
\r
32837 * 'color', 'colorSaturation', 'colorAlpha', ... are in the same visualCluster named 'color'.
\r
32838 * Other visuals are in the cluster named as the same as theirselves.
\r
32841 * @param {string} visualType
\r
32842 * @param {string} visualCluster
\r
32843 * @return {boolean}
\r
32845 VisualMapping.isInVisualCluster = function (visualType, visualCluster) {
\r
32846 return visualCluster === 'color'
\r
32847 ? !!(visualType && visualType.indexOf(visualCluster) === 0)
\r
32848 : visualType === visualCluster;
\r
32853 * @param {Object} obj
\r
32854 * @return {Oject} new object containers visual values.
\r
32855 * If no visuals, return null.
\r
32857 VisualMapping.retrieveVisuals = function (obj) {
\r
32861 obj && each(visualHandlers, function (h, visualType) {
\r
32862 if (obj.hasOwnProperty(visualType)) {
\r
32863 ret[visualType] = obj[visualType];
\r
32864 hasVisual = true;
\r
32868 return hasVisual ? ret : null;
\r
32872 * Give order to visual types, considering colorSaturation, colorAlpha depends on color.
\r
32875 * @param {(Object|Array)} visualTypes If Object, like: {color: ..., colorSaturation: ...}
\r
32876 * IF Array, like: ['color', 'symbol', 'colorSaturation']
\r
32877 * @return {Array.<string>} Sorted visual types.
\r
32879 VisualMapping.prepareVisualTypes = function (visualTypes) {
\r
32880 if (isObject(visualTypes)) {
\r
32882 each(visualTypes, function (item, type) {
\r
32883 types.push(type);
\r
32885 visualTypes = types;
\r
32887 else if (zrUtil.isArray(visualTypes)) {
\r
32888 visualTypes = visualTypes.slice();
\r
32894 visualTypes.sort(function (type1, type2) {
\r
32895 // color should be front of colorSaturation, colorAlpha, ...
\r
32896 // symbol and symbolSize do not matter.
\r
32897 return (type2 === 'color' && type1 !== 'color' && type1.indexOf('color') === 0)
\r
32901 return visualTypes;
\r
32905 * @public {Array.<Object>} [{value: ..., interval: [min, max]}, ...]
\r
32906 * @return {number} index
\r
32908 VisualMapping.findPieceIndex = function (value, pieceList) {
\r
32909 // value has high priority.
\r
32910 for (var i = 0, len = pieceList.length; i < len; i++) {
\r
32911 var piece = pieceList[i];
\r
32912 if (piece.value != null && piece.value === value) {
\r
32917 for (var i = 0, len = pieceList.length; i < len; i++) {
\r
32918 var piece = pieceList[i];
\r
32919 var interval = piece.interval;
\r
32921 if (interval[0] === -Infinity) {
\r
32922 if (value < interval[1]) {
\r
32926 else if (interval[1] === Infinity) {
\r
32927 if (interval[0] < value) {
\r
32932 piece.interval[0] <= value
\r
32933 && value <= piece.interval[1]
\r
32941 module.exports = VisualMapping;
\r
32948 /***/ function(module, exports, __webpack_require__) {
\r
32952 var mathMax = Math.max;
\r
32953 var mathMin = Math.min;
\r
32954 var zrUtil = __webpack_require__(3);
\r
32955 var numberUtil = __webpack_require__(7);
\r
32956 var layout = __webpack_require__(21);
\r
32957 var helper = __webpack_require__(181);
\r
32958 var parsePercent = numberUtil.parsePercent;
\r
32959 var retrieveValue = zrUtil.retrieve;
\r
32960 var BoundingRect = __webpack_require__(15);
\r
32961 var helper = __webpack_require__(181);
\r
32966 function update(ecModel, api, payload) {
\r
32967 // Layout result in each node:
\r
32968 // {x, y, width, height, area, borderWidth}
\r
32969 var condition = {mainType: 'series', subType: 'treemap', query: payload};
\r
32970 ecModel.eachComponent(condition, function (seriesModel) {
\r
32972 var ecWidth = api.getWidth();
\r
32973 var ecHeight = api.getHeight();
\r
32974 var seriesOption = seriesModel.option;
\r
32976 var size = seriesOption.size || []; // Compatible with ec2.
\r
32977 var containerWidth = parsePercent(
\r
32978 retrieveValue(seriesOption.width, size[0]),
\r
32981 var containerHeight = parsePercent(
\r
32982 retrieveValue(seriesOption.height, size[1]),
\r
32986 var layoutInfo = layout.getLayoutRect(
\r
32987 seriesModel.getBoxLayoutParams(),
\r
32989 width: api.getWidth(),
\r
32990 height: api.getHeight()
\r
32994 // Fetch payload info.
\r
32995 var payloadType = payload && payload.type;
\r
32996 var targetInfo = helper.retrieveTargetInfo(payload, seriesModel);
\r
32997 var rootRect = (payloadType === 'treemapRender' || payloadType === 'treemapMove')
\r
32998 ? payload.rootRect : null;
\r
32999 var viewRoot = seriesModel.getViewRoot();
\r
33001 if (payloadType !== 'treemapMove') {
\r
33002 var rootSize = payloadType === 'treemapZoomToNode'
\r
33003 ? estimateRootSize(
\r
33004 seriesModel, targetInfo, viewRoot, containerWidth, containerHeight
\r
33007 ? [rootRect.width, rootRect.height]
\r
33008 : [containerWidth, containerHeight];
\r
33010 var sort = seriesOption.sort;
\r
33011 if (sort && sort !== 'asc' && sort !== 'desc') {
\r
33015 squareRatio: seriesOption.squareRatio,
\r
33017 leafDepth: seriesOption.leafDepth
\r
33020 viewRoot.setLayout({
\r
33022 width: rootSize[0], height: rootSize[1],
\r
33023 area: rootSize[0] * rootSize[1]
\r
33026 squarify(viewRoot, options, false, 0);
\r
33029 // Set root position
\r
33030 viewRoot.setLayout(
\r
33031 calculateRootPosition(layoutInfo, rootRect, targetInfo),
\r
33035 seriesModel.setLayoutInfo(layoutInfo);
\r
33039 // 现在没有clip功能,暂时取ec高宽。
\r
33041 seriesModel.getData().tree.root,
\r
33042 // Transform to base element coordinate system.
\r
33043 new BoundingRect(-layoutInfo.x, -layoutInfo.y, ecWidth, ecHeight),
\r
33044 helper.getPathToRoot(viewRoot)
\r
33051 * Layout treemap with squarify algorithm.
\r
33052 * @see https://graphics.ethz.ch/teaching/scivis_common/Literature/squarifiedTreeMaps.pdf
\r
33053 * @see https://github.com/mbostock/d3/blob/master/src/layout/treemap.js
\r
33056 * @param {module:echarts/data/Tree~TreeNode} node
\r
33057 * @param {Object} options
\r
33058 * @param {string} options.sort 'asc' or 'desc'
\r
33059 * @param {number} options.squareRatio
\r
33060 * @param {boolean} hideChildren
\r
33061 * @param {number} depth
\r
33063 function squarify(node, options, hideChildren, depth) {
\r
33067 if (node.isRemoved()) {
\r
33071 var thisLayout = node.getLayout();
\r
33072 width = thisLayout.width;
\r
33073 height = thisLayout.height;
\r
33075 // Considering border and gap
\r
33076 var itemStyleModel = node.getModel('itemStyle.normal');
\r
33077 var borderWidth = itemStyleModel.get('borderWidth');
\r
33078 var halfGapWidth = itemStyleModel.get('gapWidth') / 2;
\r
33079 var layoutOffset = borderWidth - halfGapWidth;
\r
33080 var nodeModel = node.getModel();
\r
33082 node.setLayout({borderWidth: borderWidth}, true);
\r
33084 width = mathMax(width - 2 * layoutOffset, 0);
\r
33085 height = mathMax(height - 2 * layoutOffset, 0);
\r
33087 var totalArea = width * height;
\r
33088 var viewChildren = initChildren(
\r
33089 node, nodeModel, totalArea, options, hideChildren, depth
\r
33092 if (!viewChildren.length) {
\r
33096 var rect = {x: layoutOffset, y: layoutOffset, width: width, height: height};
\r
33097 var rowFixedLength = mathMin(width, height);
\r
33098 var best = Infinity; // the best row score so far
\r
33102 for (var i = 0, len = viewChildren.length; i < len;) {
\r
33103 var child = viewChildren[i];
\r
33106 row.area += child.getLayout().area;
\r
33107 var score = worst(row, rowFixedLength, options.squareRatio);
\r
33109 // continue with this orientation
\r
33110 if (score <= best) {
\r
33114 // abort, and try a different orientation
\r
33116 row.area -= row.pop().getLayout().area;
\r
33117 position(row, rowFixedLength, rect, halfGapWidth, false);
\r
33118 rowFixedLength = mathMin(rect.width, rect.height);
\r
33119 row.length = row.area = 0;
\r
33124 if (row.length) {
\r
33125 position(row, rowFixedLength, rect, halfGapWidth, true);
\r
33128 if (!hideChildren) {
\r
33129 var childrenVisibleMin = nodeModel.get('childrenVisibleMin');
\r
33130 if (childrenVisibleMin != null && totalArea < childrenVisibleMin) {
\r
33131 hideChildren = true;
\r
33135 for (var i = 0, len = viewChildren.length; i < len; i++) {
\r
33136 squarify(viewChildren[i], options, hideChildren, depth + 1);
\r
33141 * Set area to each child, and calculate data extent for visual coding.
\r
33143 function initChildren(node, nodeModel, totalArea, options, hideChildren, depth) {
\r
33144 var viewChildren = node.children || [];
\r
33145 var orderBy = options.sort;
\r
33146 orderBy !== 'asc' && orderBy !== 'desc' && (orderBy = null);
\r
33148 var overLeafDepth = options.leafDepth != null && options.leafDepth <= depth;
\r
33150 // leafDepth has higher priority.
\r
33151 if (hideChildren && !overLeafDepth) {
\r
33152 return (node.viewChildren = []);
\r
33155 // Sort children, order by desc.
\r
33156 viewChildren = zrUtil.filter(viewChildren, function (child) {
\r
33157 return !child.isRemoved();
\r
33160 sort(viewChildren, orderBy);
\r
33162 var info = statistic(nodeModel, viewChildren, orderBy);
\r
33164 if (info.sum === 0) {
\r
33165 return (node.viewChildren = []);
\r
33168 info.sum = filterByThreshold(nodeModel, totalArea, info.sum, orderBy, viewChildren);
\r
33170 if (info.sum === 0) {
\r
33171 return (node.viewChildren = []);
\r
33174 // Set area to each child.
\r
33175 for (var i = 0, len = viewChildren.length; i < len; i++) {
\r
33176 var area = viewChildren[i].getValue() / info.sum * totalArea;
\r
33177 // Do not use setLayout({...}, true), because it is needed to clear last layout.
\r
33178 viewChildren[i].setLayout({area: area});
\r
33181 if (overLeafDepth) {
\r
33182 viewChildren.length && node.setLayout({isLeafRoot: true}, true);
\r
33183 viewChildren.length = 0;
\r
33186 node.viewChildren = viewChildren;
\r
33187 node.setLayout({dataExtent: info.dataExtent}, true);
\r
33189 return viewChildren;
\r
33193 * Consider 'visibleMin'. Modify viewChildren and get new sum.
\r
33195 function filterByThreshold(nodeModel, totalArea, sum, orderBy, orderedChildren) {
\r
33197 // visibleMin is not supported yet when no option.sort.
\r
33202 var visibleMin = nodeModel.get('visibleMin');
\r
33203 var len = orderedChildren.length;
\r
33204 var deletePoint = len;
\r
33206 // Always travel from little value to big value.
\r
33207 for (var i = len - 1; i >= 0; i--) {
\r
33208 var value = orderedChildren[
\r
33209 orderBy === 'asc' ? len - i - 1 : i
\r
33212 if (value / sum * totalArea < visibleMin) {
\r
33218 orderBy === 'asc'
\r
33219 ? orderedChildren.splice(0, len - deletePoint)
\r
33220 : orderedChildren.splice(deletePoint, len - deletePoint);
\r
33228 function sort(viewChildren, orderBy) {
\r
33230 viewChildren.sort(function (a, b) {
\r
33231 return orderBy === 'asc'
\r
33232 ? a.getValue() - b.getValue() : b.getValue() - a.getValue();
\r
33235 return viewChildren;
\r
33241 function statistic(nodeModel, children, orderBy) {
\r
33242 // Calculate sum.
\r
33244 for (var i = 0, len = children.length; i < len; i++) {
\r
33245 sum += children[i].getValue();
\r
33248 // Statistic data extent for latter visual coding.
\r
33249 // Notice: data extent should be calculate based on raw children
\r
33250 // but not filtered view children, otherwise visual mapping will not
\r
33251 // be stable when zoom (where children is filtered by visibleMin).
\r
33253 var dimension = nodeModel.get('visualDimension');
\r
33256 // The same as area dimension.
\r
33257 if (!children || !children.length) {
\r
33258 dataExtent = [NaN, NaN];
\r
33260 else if (dimension === 'value' && orderBy) {
\r
33262 children[children.length - 1].getValue(),
\r
33263 children[0].getValue()
\r
33265 orderBy === 'asc' && dataExtent.reverse();
\r
33267 // Other dimension.
\r
33269 var dataExtent = [Infinity, -Infinity];
\r
33270 zrUtil.each(children, function (child) {
\r
33271 var value = child.getValue(dimension);
\r
33272 value < dataExtent[0] && (dataExtent[0] = value);
\r
33273 value > dataExtent[1] && (dataExtent[1] = value);
\r
33277 return {sum: sum, dataExtent: dataExtent};
\r
33281 * Computes the score for the specified row,
\r
33282 * as the worst aspect ratio.
\r
33284 function worst(row, rowFixedLength, ratio) {
\r
33286 var areaMin = Infinity;
\r
33288 for (var i = 0, area, len = row.length; i < len; i++) {
\r
33289 area = row[i].getLayout().area;
\r
33291 area < areaMin && (areaMin = area);
\r
33292 area > areaMax && (areaMax = area);
\r
33296 var squareArea = row.area * row.area;
\r
33297 var f = rowFixedLength * rowFixedLength * ratio;
\r
33299 return squareArea
\r
33301 (f * areaMax) / squareArea,
\r
33302 squareArea / (f * areaMin)
\r
33308 * Positions the specified row of nodes. Modifies `rect`.
\r
33310 function position(row, rowFixedLength, rect, halfGapWidth, flush) {
\r
33311 // When rowFixedLength === rect.width,
\r
33312 // it is horizontal subdivision,
\r
33313 // rowFixedLength is the width of the subdivision,
\r
33314 // rowOtherLength is the height of the subdivision,
\r
33315 // and nodes will be positioned from left to right.
\r
33317 // wh[idx0WhenH] means: when horizontal,
\r
33318 // wh[idx0WhenH] => wh[0] => 'width'.
\r
33319 // xy[idx1WhenH] => xy[1] => 'y'.
\r
33320 var idx0WhenH = rowFixedLength === rect.width ? 0 : 1;
\r
33321 var idx1WhenH = 1 - idx0WhenH;
\r
33322 var xy = ['x', 'y'];
\r
33323 var wh = ['width', 'height'];
\r
33325 var last = rect[xy[idx0WhenH]];
\r
33326 var rowOtherLength = rowFixedLength
\r
33327 ? row.area / rowFixedLength : 0;
\r
33329 if (flush || rowOtherLength > rect[wh[idx1WhenH]]) {
\r
33330 rowOtherLength = rect[wh[idx1WhenH]]; // over+underflow
\r
33332 for (var i = 0, rowLen = row.length; i < rowLen; i++) {
\r
33333 var node = row[i];
\r
33334 var nodeLayout = {};
\r
33335 var step = rowOtherLength
\r
33336 ? node.getLayout().area / rowOtherLength : 0;
\r
33338 var wh1 = nodeLayout[wh[idx1WhenH]] = mathMax(rowOtherLength - 2 * halfGapWidth, 0);
\r
33340 // We use Math.max/min to avoid negative width/height when considering gap width.
\r
33341 var remain = rect[xy[idx0WhenH]] + rect[wh[idx0WhenH]] - last;
\r
33342 var modWH = (i === rowLen - 1 || remain < step) ? remain : step;
\r
33343 var wh0 = nodeLayout[wh[idx0WhenH]] = mathMax(modWH - 2 * halfGapWidth, 0);
\r
33345 nodeLayout[xy[idx1WhenH]] = rect[xy[idx1WhenH]] + mathMin(halfGapWidth, wh1 / 2);
\r
33346 nodeLayout[xy[idx0WhenH]] = last + mathMin(halfGapWidth, wh0 / 2);
\r
33349 node.setLayout(nodeLayout, true);
\r
33352 rect[xy[idx1WhenH]] += rowOtherLength;
\r
33353 rect[wh[idx1WhenH]] -= rowOtherLength;
\r
33356 // Return [containerWidth, containerHeight] as defualt.
\r
33357 function estimateRootSize(seriesModel, targetInfo, viewRoot, containerWidth, containerHeight) {
\r
33358 // If targetInfo.node exists, we zoom to the node,
\r
33359 // so estimate whold width and heigth by target node.
\r
33360 var currNode = (targetInfo || {}).node;
\r
33361 var defaultSize = [containerWidth, containerHeight];
\r
33363 if (!currNode || currNode === viewRoot) {
\r
33364 return defaultSize;
\r
33368 var viewArea = containerWidth * containerHeight;
\r
33369 var area = viewArea * seriesModel.option.zoomToNodeRatio;
\r
33371 while (parent = currNode.parentNode) { // jshint ignore:line
\r
33373 var siblings = parent.children;
\r
33375 for (var i = 0, len = siblings.length; i < len; i++) {
\r
33376 sum += siblings[i].getValue();
\r
33378 var currNodeValue = currNode.getValue();
\r
33379 if (currNodeValue === 0) {
\r
33380 return defaultSize;
\r
33382 area *= sum / currNodeValue;
\r
33384 var borderWidth = parent.getModel('itemStyle.normal').get('borderWidth');
\r
33386 if (isFinite(borderWidth)) {
\r
33387 // Considering border, suppose aspect ratio is 1.
\r
33388 area += 4 * borderWidth * borderWidth + 4 * borderWidth * Math.pow(area, 0.5);
\r
33391 area > numberUtil.MAX_SAFE_INTEGER && (area = numberUtil.MAX_SAFE_INTEGER);
\r
33393 currNode = parent;
\r
33396 area < viewArea && (area = viewArea);
\r
33397 var scale = Math.pow(area / viewArea, 0.5);
\r
33399 return [containerWidth * scale, containerHeight * scale];
\r
33402 // Root postion base on coord of containerGroup
\r
33403 function calculateRootPosition(layoutInfo, rootRect, targetInfo) {
\r
33405 return {x: rootRect.x, y: rootRect.y};
\r
33408 var defaultPosition = {x: 0, y: 0};
\r
33409 if (!targetInfo) {
\r
33410 return defaultPosition;
\r
33413 // If targetInfo is fetched by 'retrieveTargetInfo',
\r
33414 // old tree and new tree are the same tree,
\r
33415 // so the node still exists and we can visit it.
\r
33417 var targetNode = targetInfo.node;
\r
33418 var layout = targetNode.getLayout();
\r
33421 return defaultPosition;
\r
33424 // Transform coord from local to container.
\r
33425 var targetCenter = [layout.width / 2, layout.height / 2];
\r
33426 var node = targetNode;
\r
33428 var nodeLayout = node.getLayout();
\r
33429 targetCenter[0] += nodeLayout.x;
\r
33430 targetCenter[1] += nodeLayout.y;
\r
33431 node = node.parentNode;
\r
33435 x: layoutInfo.width / 2 - targetCenter[0],
\r
33436 y: layoutInfo.height / 2 - targetCenter[1]
\r
33440 // Mark invisible nodes for prunning when visual coding and rendering.
\r
33441 // Prunning depends on layout and root position, so we have to do it after them.
\r
33442 function prunning(node, clipRect, viewPath) {
\r
33443 var nodeLayout = node.getLayout();
\r
33446 invisible: nodeLayout
\r
33447 ? !clipRect.intersect(nodeLayout)
\r
33448 : !helper.aboveViewRootByViewPath(viewPath, node)
\r
33451 var viewChildren = node.viewChildren || [];
\r
33452 for (var i = 0, len = viewChildren.length; i < len; i++) {
\r
33453 // Transform to child coordinate.
\r
33454 var childClipRect = new BoundingRect(
\r
33455 clipRect.x - nodeLayout.x,
\r
33456 clipRect.y - nodeLayout.y,
\r
33460 prunning(viewChildren[i], childClipRect, viewPath);
\r
33464 module.exports = update;
\r
33469 /***/ function(module, exports, __webpack_require__) {
\r
33473 var echarts = __webpack_require__(1);
\r
33474 var zrUtil = __webpack_require__(3);
\r
33476 __webpack_require__(190);
\r
33477 __webpack_require__(193);
\r
33479 __webpack_require__(197);
\r
33481 echarts.registerProcessor('filter', __webpack_require__(198));
\r
33483 echarts.registerVisualCoding('chart', zrUtil.curry(
\r
33484 __webpack_require__(103), 'graph', 'circle', null
\r
33486 echarts.registerVisualCoding('chart', __webpack_require__(199));
\r
33488 echarts.registerLayout(__webpack_require__(200));
\r
33489 echarts.registerLayout(__webpack_require__(202));
\r
33490 echarts.registerLayout(__webpack_require__(204));
\r
33492 // Graph view coordinate system
\r
33493 echarts.registerCoordinateSystem('graphView', {
\r
33494 create: __webpack_require__(206)
\r
33500 /***/ function(module, exports, __webpack_require__) {
\r
33505 var List = __webpack_require__(94);
\r
33506 var zrUtil = __webpack_require__(3);
\r
33508 var createGraphFromNodeEdge = __webpack_require__(191);
\r
33510 var GraphSeries = __webpack_require__(1).extendSeriesModel({
\r
33512 type: 'series.graph',
\r
33514 init: function (option) {
\r
33515 GraphSeries.superApply(this, 'init', arguments);
\r
33517 // Provide data for legend select
\r
33518 this.legendDataProvider = function () {
\r
33519 return this._categoriesData;
\r
33522 this._updateCategoriesData();
\r
33525 mergeOption: function (option) {
\r
33526 GraphSeries.superApply(this, 'mergeOption', arguments);
\r
33528 this._updateCategoriesData();
\r
33531 getInitialData: function (option, ecModel) {
\r
33532 var edges = option.edges || option.links;
\r
33533 var nodes = option.data || option.nodes;
\r
33534 if (nodes && edges) {
\r
33535 var graph = createGraphFromNodeEdge(nodes, edges, this, true);
\r
33536 var list = graph.data;
\r
33538 // Overwrite list.getItemModel to
\r
33539 list.wrapMethod('getItemModel', function (model) {
\r
33540 var categoriesModels = self._categoriesModels;
\r
33541 var categoryIdx = model.getShallow('category');
\r
33542 var categoryModel = categoriesModels[categoryIdx];
\r
33543 if (categoryModel) {
\r
33544 categoryModel.parentModel = model.parentModel;
\r
33545 model.parentModel = categoryModel;
\r
33553 restoreData: function () {
\r
33554 GraphSeries.superApply(this, 'restoreData', arguments);
\r
33555 this.getGraph().restoreData();
\r
33559 * @return {module:echarts/data/Graph}
\r
33561 getGraph: function () {
\r
33562 return this.getData().graph;
\r
33566 * @return {module:echarts/data/List}
\r
33568 getEdgeData: function () {
\r
33569 return this.getGraph().edgeData;
\r
33573 * @return {module:echarts/data/List}
\r
33575 getCategoriesData: function () {
\r
33576 return this._categoriesData;
\r
33579 _updateCategoriesData: function () {
\r
33580 var categories = zrUtil.map(this.option.categories || [], function (category) {
\r
33581 // Data must has value
\r
33582 return category.value != null ? category : zrUtil.extend({
\r
33586 var categoriesData = new List(['value'], this);
\r
33587 categoriesData.initData(categories);
\r
33589 this._categoriesData = categoriesData;
\r
33591 this._categoriesModels = categoriesData.mapArray(function (idx) {
\r
33592 return categoriesData.getItemModel(idx, true);
\r
33597 * @param {number} zoom
\r
33599 setRoamZoom: function (zoom) {
\r
33600 var roamDetail = this.option.roamDetail;
\r
33601 roamDetail && (roamDetail.zoom = zoom);
\r
33605 * @param {number} x
\r
33606 * @param {number} y
\r
33608 setRoamPan: function (x, y) {
\r
33609 var roamDetail = this.option.roamDetail;
\r
33610 if (roamDetail) {
\r
33611 roamDetail.x = x;
\r
33612 roamDetail.y = y;
\r
33620 color: ['#61a0a8', '#d14a61', '#fd9c35', '#675bba', '#fec42c',
\r
33621 '#dd4444', '#fd9c35', '#cd4870'],
\r
33623 coordinateSystem: 'view',
\r
33625 legendHoverLink: true,
\r
33627 hoverAnimation: true,
\r
33631 // Configuration of force
\r
33633 initLayout: null,
\r
33638 layoutAnimation: true
\r
33646 // height: '80%',
\r
33648 symbol: 'circle',
\r
33651 draggable: false,
\r
33660 // Symbol size scale ratio in roam
\r
33661 nodeScaleRatio: 0.6,
\r
33663 // Line width scale ratio in roam
\r
33664 // edgeScaleRatio: 0.1,
\r
33666 // categories: [],
\r
33702 module.exports = GraphSeries;
\r
33707 /***/ function(module, exports, __webpack_require__) {
\r
33711 var List = __webpack_require__(94);
\r
33712 var Graph = __webpack_require__(192);
\r
33713 var linkList = __webpack_require__(180);
\r
33714 var completeDimensions = __webpack_require__(96);
\r
33715 var zrUtil = __webpack_require__(3);
\r
33717 module.exports = function (nodes, edges, hostModel, directed) {
\r
33718 var graph = new Graph(directed);
\r
33719 for (var i = 0; i < nodes.length; i++) {
\r
33720 graph.addNode(zrUtil.retrieve(
\r
33721 // Id, name, dataIndex
\r
33722 nodes[i].id, nodes[i].name, i
\r
33726 var linkNameList = [];
\r
33727 var validEdges = [];
\r
33728 for (var i = 0; i < edges.length; i++) {
\r
33729 var link = edges[i];
\r
33730 // addEdge may fail when source or target not exists
\r
33731 if (graph.addEdge(link.source, link.target, i)) {
\r
33732 validEdges.push(link);
\r
33733 linkNameList.push(zrUtil.retrieve(link.id, link.source + ' - ' + link.target));
\r
33738 var dimensionNames = completeDimensions(['value'], nodes);
\r
33740 var nodeData = new List(dimensionNames, hostModel);
\r
33741 var edgeData = new List(['value'], hostModel);
\r
33743 nodeData.initData(nodes);
\r
33744 edgeData.initData(validEdges, linkNameList);
\r
33746 graph.setEdgeData(edgeData);
\r
33748 linkList.linkToGraph(nodeData, graph);
\r
33749 // Update dataIndex of nodes and edges because invalid edge may be removed
\r
33758 /***/ function(module, exports, __webpack_require__) {
\r
33762 * Graph data structure
\r
33764 * @module echarts/data/Graph
\r
33765 * @author Yi Shen(https://www.github.com/pissang)
\r
33769 var zrUtil = __webpack_require__(3);
\r
33772 * @alias module:echarts/data/Graph
\r
33774 * @param {boolean} directed
\r
33776 var Graph = function(directed) {
\r
33779 * @type {boolean}
\r
33782 this._directed = directed || false;
\r
33785 * @type {Array.<module:echarts/data/Graph.Node>}
\r
33791 * @type {Array.<module:echarts/data/Graph.Edge>}
\r
33797 * @type {Object.<string, module:echarts/data/Graph.Node>}
\r
33800 this._nodesMap = {};
\r
33802 * @type {Object.<string, module:echarts/data/Graph.Edge>}
\r
33805 this._edgesMap = {};
\r
33808 * @type {module:echarts/data/List}
\r
33814 * @type {module:echarts/data/List}
\r
33820 var graphProto = Graph.prototype;
\r
33824 graphProto.type = 'graph';
\r
33827 * If is directed graph
\r
33828 * @return {boolean}
\r
33830 graphProto.isDirected = function () {
\r
33831 return this._directed;
\r
33836 * @param {string} id
\r
33837 * @param {number} [dataIndex]
\r
33839 graphProto.addNode = function (id, dataIndex) {
\r
33840 var nodesMap = this._nodesMap;
\r
33842 if (nodesMap[id]) {
\r
33846 var node = new Node(id, dataIndex);
\r
33847 node.hostGraph = this;
\r
33849 this.nodes.push(node);
\r
33851 nodesMap[id] = node;
\r
33856 * Get node by data index
\r
33857 * @param {number} dataIndex
\r
33858 * @return {module:echarts/data/Graph~Node}
\r
33860 graphProto.getNodeByIndex = function (dataIndex) {
\r
33861 var rawIdx = this.data.getRawIndex(dataIndex);
\r
33862 return this.nodes[rawIdx];
\r
33866 * @param {string} id
\r
33867 * @return {module:echarts/data/Graph.Node}
\r
33869 graphProto.getNodeById = function (id) {
\r
33870 return this._nodesMap[id];
\r
33875 * @param {string|module:echarts/data/Graph.Node} n1
\r
33876 * @param {string|module:echarts/data/Graph.Node} n2
\r
33877 * @param {number} [dataIndex=-1]
\r
33878 * @return {module:echarts/data/Graph.Edge}
\r
33880 graphProto.addEdge = function (n1, n2, dataIndex) {
\r
33881 var nodesMap = this._nodesMap;
\r
33882 var edgesMap = this._edgesMap;
\r
33884 if (!(n1 instanceof Node)) {
\r
33885 n1 = nodesMap[n1];
\r
33887 if (!(n2 instanceof Node)) {
\r
33888 n2 = nodesMap[n2];
\r
33890 if (!n1 || !n2) {
\r
33894 var key = n1.id + '-' + n2.id;
\r
33896 if (edgesMap[key]) {
\r
33900 var edge = new Edge(n1, n2, dataIndex);
\r
33901 edge.hostGraph = this;
\r
33903 if (this._directed) {
\r
33904 n1.outEdges.push(edge);
\r
33905 n2.inEdges.push(edge);
\r
33907 n1.edges.push(edge);
\r
33909 n2.edges.push(edge);
\r
33912 this.edges.push(edge);
\r
33913 edgesMap[key] = edge;
\r
33919 * Get edge by data index
\r
33920 * @param {number} dataIndex
\r
33921 * @return {module:echarts/data/Graph~Node}
\r
33923 graphProto.getEdgeByIndex = function (dataIndex) {
\r
33924 var rawIdx = this.edgeData.getRawIndex(dataIndex);
\r
33925 return this.edges[rawIdx];
\r
33928 * Get edge by two linked nodes
\r
33929 * @param {module:echarts/data/Graph.Node|string} n1
\r
33930 * @param {module:echarts/data/Graph.Node|string} n2
\r
33931 * @return {module:echarts/data/Graph.Edge}
\r
33933 graphProto.getEdge = function (n1, n2) {
\r
33934 if (n1 instanceof Node) {
\r
33937 if (n2 instanceof Node) {
\r
33941 var edgesMap = this._edgesMap;
\r
33943 if (this._directed) {
\r
33944 return edgesMap[n1 + '-' + n2];
\r
33946 return edgesMap[n1 + '-' + n2]
\r
33947 || edgesMap[n2 + '-' + n1];
\r
33952 * Iterate all nodes
\r
33953 * @param {Function} cb
\r
33954 * @param {*} [context]
\r
33956 graphProto.eachNode = function (cb, context) {
\r
33957 var nodes = this.nodes;
\r
33958 var len = nodes.length;
\r
33959 for (var i = 0; i < len; i++) {
\r
33960 if (nodes[i].dataIndex >= 0) {
\r
33961 cb.call(context, nodes[i], i);
\r
33967 * Iterate all edges
\r
33968 * @param {Function} cb
\r
33969 * @param {*} [context]
\r
33971 graphProto.eachEdge = function (cb, context) {
\r
33972 var edges = this.edges;
\r
33973 var len = edges.length;
\r
33974 for (var i = 0; i < len; i++) {
\r
33975 if (edges[i].dataIndex >= 0
\r
33976 && edges[i].node1.dataIndex >= 0
\r
33977 && edges[i].node2.dataIndex >= 0
\r
33979 cb.call(context, edges[i], i);
\r
33985 * Breadth first traverse
\r
33986 * @param {Function} cb
\r
33987 * @param {module:echarts/data/Graph.Node} startNode
\r
33988 * @param {string} [direction='none'] 'none'|'in'|'out'
\r
33989 * @param {*} [context]
\r
33991 graphProto.breadthFirstTraverse = function (
\r
33992 cb, startNode, direction, context
\r
33994 if (!(startNode instanceof Node)) {
\r
33995 startNode = this._nodesMap[startNode];
\r
33997 if (!startNode) {
\r
34001 var edgeType = direction === 'out'
\r
34002 ? 'outEdges' : (direction === 'in' ? 'inEdges' : 'edges');
\r
34004 for (var i = 0; i < this.nodes.length; i++) {
\r
34005 this.nodes[i].__visited = false;
\r
34008 if (cb.call(context, startNode, null)) {
\r
34012 var queue = [startNode];
\r
34013 while (queue.length) {
\r
34014 var currentNode = queue.shift();
\r
34015 var edges = currentNode[edgeType];
\r
34017 for (var i = 0; i < edges.length; i++) {
\r
34018 var e = edges[i];
\r
34019 var otherNode = e.node1 === currentNode
\r
34020 ? e.node2 : e.node1;
\r
34021 if (!otherNode.__visited) {
\r
34022 if (cb.call(otherNode, otherNode, currentNode)) {
\r
34023 // Stop traversing
\r
34026 queue.push(otherNode);
\r
34027 otherNode.__visited = true;
\r
34034 // graphProto.depthFirstTraverse = function (
\r
34035 // cb, startNode, direction, context
\r
34041 graphProto.update = function () {
\r
34042 var data = this.data;
\r
34043 var edgeData = this.edgeData;
\r
34044 var nodes = this.nodes;
\r
34045 var edges = this.edges;
\r
34047 for (var i = 0, len = nodes.length; i < len; i++) {
\r
34048 nodes[i].dataIndex = -1;
\r
34050 for (var i = 0, len = data.count(); i < len; i++) {
\r
34051 nodes[data.getRawIndex(i)].dataIndex = i;
\r
34054 edgeData.filterSelf(function (idx) {
\r
34055 var edge = edges[edgeData.getRawIndex(idx)];
\r
34056 return edge.node1.dataIndex >= 0 && edge.node2.dataIndex >= 0;
\r
34060 for (var i = 0, len = edges.length; i < len; i++) {
\r
34061 edges[i].dataIndex = -1;
\r
34063 for (var i = 0, len = edgeData.count(); i < len; i++) {
\r
34064 edges[edgeData.getRawIndex(i)].dataIndex = i;
\r
34070 * @param {module:echarts/data/List} edgeData
\r
34072 graphProto.setEdgeData = function (edgeData) {
\r
34073 this.edgeData = edgeData;
\r
34074 this._edgeDataSaved = edgeData.cloneShallow();
\r
34077 graphProto.restoreData = function () {
\r
34078 this.edgeData = this._edgeDataSaved.cloneShallow();
\r
34082 * @return {module:echarts/data/Graph}
\r
34084 graphProto.clone = function () {
\r
34085 var graph = new Graph(this._directed);
\r
34086 var nodes = this.nodes;
\r
34087 var edges = this.edges;
\r
34088 for (var i = 0; i < nodes.length; i++) {
\r
34089 graph.addNode(nodes[i].id, nodes[i].dataIndex);
\r
34091 for (var i = 0; i < edges.length; i++) {
\r
34092 var e = edges[i];
\r
34093 graph.addEdge(e.node1.id, e.node2.id, e.dataIndex);
\r
34100 * @alias module:echarts/data/Graph.Node
\r
34102 function Node(id, dataIndex) {
\r
34106 this.id = id == null ? '' : id;
\r
34109 * @type {Array.<module:echarts/data/Graph.Edge>}
\r
34111 this.inEdges = [];
\r
34113 * @type {Array.<module:echarts/data/Graph.Edge>}
\r
34115 this.outEdges = [];
\r
34117 * @type {Array.<module:echarts/data/Graph.Edge>}
\r
34121 * @type {module:echarts/data/Graph}
\r
34128 this.dataIndex = dataIndex == null ? -1 : dataIndex;
\r
34131 Node.prototype = {
\r
34133 constructor: Node,
\r
34136 * @return {number}
\r
34138 degree: function () {
\r
34139 return this.edges.length;
\r
34143 * @return {number}
\r
34145 inDegree: function () {
\r
34146 return this.inEdges.length;
\r
34150 * @return {number}
\r
34152 outDegree: function () {
\r
34153 return this.outEdges.length;
\r
34157 * @param {string} [path]
\r
34158 * @return {module:echarts/model/Model}
\r
34160 getModel: function (path) {
\r
34161 if (this.dataIndex < 0) {
\r
34164 var graph = this.hostGraph;
\r
34165 var itemModel = graph.data.getItemModel(this.dataIndex);
\r
34167 return itemModel.getModel(path);
\r
34173 * @alias module:echarts/data/Graph.Edge
\r
34174 * @param {module:echarts/data/Graph.Node} n1
\r
34175 * @param {module:echarts/data/Graph.Node} n2
\r
34176 * @param {number} [dataIndex=-1]
\r
34178 function Edge(n1, n2, dataIndex) {
\r
34181 * 节点1,如果是有向图则为源节点
\r
34182 * @type {module:echarts/data/Graph.Node}
\r
34187 * 节点2,如果是有向图则为目标节点
\r
34188 * @type {module:echarts/data/Graph.Node}
\r
34192 this.dataIndex = dataIndex == null ? -1 : dataIndex;
\r
34196 * @param {string} [path]
\r
34197 * @return {module:echarts/model/Model}
\r
34199 Edge.prototype.getModel = function (path) {
\r
34200 if (this.dataIndex < 0) {
\r
34203 var graph = this.hostGraph;
\r
34204 var itemModel = graph.edgeData.getItemModel(this.dataIndex);
\r
34206 return itemModel.getModel(path);
\r
34209 var createGraphDataProxyMixin = function (hostName, dataName) {
\r
34212 * @param {string=} [dimension='value'] Default 'value'. can be 'a', 'b', 'c', 'd', 'e'.
\r
34213 * @return {number}
\r
34215 getValue: function (dimension) {
\r
34216 var data = this[hostName][dataName];
\r
34217 return data.get(data.getDimension(dimension || 'value'), this.dataIndex);
\r
34221 * @param {Object|string} key
\r
34222 * @param {*} [value]
\r
34224 setVisual: function (key, value) {
\r
34225 this.dataIndex >= 0
\r
34226 && this[hostName][dataName].setItemVisual(this.dataIndex, key, value);
\r
34230 * @param {string} key
\r
34231 * @return {boolean}
\r
34233 getVisual: function (key, ignoreParent) {
\r
34234 return this[hostName][dataName].getItemVisual(this.dataIndex, key, ignoreParent);
\r
34238 * @param {Object} layout
\r
34239 * @return {boolean} [merge=false]
\r
34241 setLayout: function (layout, merge) {
\r
34242 this.dataIndex >= 0
\r
34243 && this[hostName][dataName].setItemLayout(this.dataIndex, layout, merge);
\r
34247 * @return {Object}
\r
34249 getLayout: function () {
\r
34250 return this[hostName][dataName].getItemLayout(this.dataIndex);
\r
34254 * @return {module:zrender/Element}
\r
34256 getGraphicEl: function () {
\r
34257 return this[hostName][dataName].getItemGraphicEl(this.dataIndex);
\r
34261 * @return {number}
\r
34263 getRawIndex: function () {
\r
34264 return this[hostName][dataName].getRawIndex(this.dataIndex);
\r
34269 zrUtil.mixin(Node, createGraphDataProxyMixin('hostGraph', 'data'));
\r
34270 zrUtil.mixin(Edge, createGraphDataProxyMixin('hostGraph', 'edgeData'));
\r
34272 Graph.Node = Node;
\r
34273 Graph.Edge = Edge;
\r
34275 module.exports = Graph;
\r
34280 /***/ function(module, exports, __webpack_require__) {
\r
34285 var SymbolDraw = __webpack_require__(98);
\r
34286 var LineDraw = __webpack_require__(194);
\r
34287 var RoamController = __webpack_require__(159);
\r
34289 var modelUtil = __webpack_require__(5);
\r
34290 var graphic = __webpack_require__(42);
\r
34292 __webpack_require__(1).extendChartView({
\r
34296 init: function (ecModel, api) {
\r
34297 var symbolDraw = new SymbolDraw();
\r
34298 var lineDraw = new LineDraw();
\r
34299 var group = this.group;
\r
34301 var controller = new RoamController(api.getZr(), group);
\r
34303 group.add(symbolDraw.group);
\r
34304 group.add(lineDraw.group);
\r
34306 this._symbolDraw = symbolDraw;
\r
34307 this._lineDraw = lineDraw;
\r
34308 this._controller = controller;
\r
34310 this._firstRender = true;
\r
34313 render: function (seriesModel, ecModel, api) {
\r
34314 var coordSys = seriesModel.coordinateSystem;
\r
34315 // Only support view and geo coordinate system
\r
34316 if (coordSys.type !== 'geo' && coordSys.type !== 'view') {
\r
34320 var data = seriesModel.getData();
\r
34321 this._model = seriesModel;
\r
34323 var symbolDraw = this._symbolDraw;
\r
34324 var lineDraw = this._lineDraw;
\r
34326 symbolDraw.updateData(data);
\r
34328 var edgeData = data.graph.edgeData;
\r
34329 var rawOption = seriesModel.option;
\r
34330 var formatModel = modelUtil.createDataFormatModel(
\r
34331 seriesModel, edgeData, rawOption.edges || rawOption.links
\r
34333 formatModel.formatTooltip = function (dataIndex) {
\r
34334 var params = this.getDataParams(dataIndex);
\r
34335 var edge = data.graph.getEdgeByIndex(dataIndex);
\r
34336 var sourceName = data.getName(edge.node1.dataIndex);
\r
34337 var targetName = data.getName(edge.node2.dataIndex);
\r
34338 var html = sourceName + ' > ' + targetName;
\r
34339 if (params.value) {
\r
34340 html += ' : ' + params.value;
\r
34345 lineDraw.updateData(edgeData, null, null);
\r
34346 edgeData.eachItemGraphicEl(function (el) {
\r
34347 el.traverse(function (child) {
\r
34348 child.dataModel = formatModel;
\r
34352 // Save the original lineWidth
\r
34353 // data.graph.eachEdge(function (edge) {
\r
34354 // edge.__lineWidth = edge.getModel('lineStyle.normal').get('width');
\r
34357 var group = this.group;
\r
34358 var groupNewProp = {
\r
34359 position: coordSys.position,
\r
34360 scale: coordSys.scale
\r
34362 if (this._firstRender) {
\r
34363 group.attr(groupNewProp);
\r
34366 graphic.updateProps(group, groupNewProp, seriesModel);
\r
34369 this._nodeScaleRatio = seriesModel.get('nodeScaleRatio');
\r
34370 // this._edgeScaleRatio = seriesModel.get('edgeScaleRatio');
\r
34372 this._updateNodeAndLinkScale();
\r
34374 this._updateController(seriesModel, coordSys, api);
\r
34376 clearTimeout(this._layoutTimeout);
\r
34377 var forceLayout = seriesModel.forceLayout;
\r
34378 var layoutAnimation = seriesModel.get('force.layoutAnimation');
\r
34379 if (forceLayout) {
\r
34380 this._startForceLayoutIteration(forceLayout, layoutAnimation);
\r
34382 // Update draggable
\r
34383 data.eachItemGraphicEl(function (el, idx) {
\r
34384 var draggable = data.getItemModel(idx).get('draggable');
\r
34385 if (draggable && forceLayout) {
\r
34386 el.on('drag', function () {
\r
34387 forceLayout.warmUp();
\r
34389 && this._startForceLayoutIteration(forceLayout, layoutAnimation);
\r
34390 forceLayout.setFixed(idx);
\r
34391 // Write position back to layout
\r
34392 data.setItemLayout(idx, el.position);
\r
34393 }, this).on('dragend', function () {
\r
34394 forceLayout.setUnfixed(idx);
\r
34400 el.setDraggable(draggable);
\r
34403 this._firstRender = false;
\r
34406 _startForceLayoutIteration: function (forceLayout, layoutAnimation) {
\r
34408 (function step() {
\r
34409 forceLayout.step(function (stopped) {
\r
34410 self.updateLayout();
\r
34411 (self._layouting = !stopped) && (
\r
34413 ? (self._layoutTimeout = setTimeout(step, 16))
\r
34420 _updateController: function (seriesModel, coordSys, api) {
\r
34421 var controller = this._controller;
\r
34422 controller.rect = coordSys.getViewRect();
\r
34424 controller.enable(seriesModel.get('roam'));
\r
34429 .on('pan', function (dx, dy) {
\r
34430 api.dispatchAction({
\r
34431 seriesId: seriesModel.id,
\r
34432 type: 'graphRoam',
\r
34437 .on('zoom', function (zoom, mouseX, mouseY) {
\r
34438 api.dispatchAction({
\r
34439 seriesId: seriesModel.id,
\r
34440 type: 'graphRoam',
\r
34446 .on('zoom', this._updateNodeAndLinkScale, this);
\r
34449 _updateNodeAndLinkScale: function () {
\r
34450 var seriesModel = this._model;
\r
34451 var data = seriesModel.getData();
\r
34453 var group = this.group;
\r
34454 var nodeScaleRatio = this._nodeScaleRatio;
\r
34455 // var edgeScaleRatio = this._edgeScaleRatio;
\r
34457 // Assume scale aspect is 1
\r
34458 var groupScale = group.scale[0];
\r
34460 var nodeScale = (groupScale - 1) * nodeScaleRatio + 1;
\r
34461 // var edgeScale = (groupScale - 1) * edgeScaleRatio + 1;
\r
34463 nodeScale / groupScale,
\r
34464 nodeScale / groupScale
\r
34467 data.eachItemGraphicEl(function (el, idx) {
\r
34468 el.attr('scale', invScale);
\r
34470 // data.graph.eachEdge(function (edge) {
\r
34471 // var lineGroup = edge.getGraphicEl();
\r
34473 // lineGroup.childOfName('line').setStyle(
\r
34475 // edge.__lineWidth * edgeScale / groupScale
\r
34480 updateLayout: function (seriesModel, ecModel) {
\r
34481 this._symbolDraw.updateLayout();
\r
34482 this._lineDraw.updateLayout();
\r
34485 remove: function (ecModel, api) {
\r
34486 this._symbolDraw && this._symbolDraw.remove();
\r
34487 this._lineDraw && this._lineDraw.remove();
\r
34494 /***/ function(module, exports, __webpack_require__) {
\r
34497 * @module echarts/chart/helper/LineDraw
\r
34501 var graphic = __webpack_require__(42);
\r
34502 var LineGroup = __webpack_require__(195);
\r
34505 * @alias module:echarts/component/marker/LineDraw
\r
34508 function LineDraw(ctor) {
\r
34509 this._ctor = ctor || LineGroup;
\r
34510 this.group = new graphic.Group();
\r
34513 var lineDrawProto = LineDraw.prototype;
\r
34516 * @param {module:echarts/data/List} lineData
\r
34517 * @param {module:echarts/data/List} [fromData]
\r
34518 * @param {module:echarts/data/List} [toData]
\r
34520 lineDrawProto.updateData = function (lineData, fromData, toData) {
\r
34522 var oldLineData = this._lineData;
\r
34523 var group = this.group;
\r
34524 var LineCtor = this._ctor;
\r
34526 lineData.diff(oldLineData)
\r
34527 .add(function (idx) {
\r
34528 var lineGroup = new LineCtor(lineData, fromData, toData, idx);
\r
34530 lineData.setItemGraphicEl(idx, lineGroup);
\r
34532 group.add(lineGroup);
\r
34534 .update(function (newIdx, oldIdx) {
\r
34535 var lineGroup = oldLineData.getItemGraphicEl(oldIdx);
\r
34536 lineGroup.updateData(lineData, fromData, toData, newIdx);
\r
34538 lineData.setItemGraphicEl(newIdx, lineGroup);
\r
34540 group.add(lineGroup);
\r
34542 .remove(function (idx) {
\r
34543 group.remove(oldLineData.getItemGraphicEl(idx));
\r
34547 this._lineData = lineData;
\r
34548 this._fromData = fromData;
\r
34549 this._toData = toData;
\r
34552 lineDrawProto.updateLayout = function () {
\r
34553 var lineData = this._lineData;
\r
34554 lineData.eachItemGraphicEl(function (el, idx) {
\r
34555 el.updateLayout(lineData, this._fromData, this._toData, idx);
\r
34559 lineDrawProto.remove = function () {
\r
34560 this.group.removeAll();
\r
34563 module.exports = LineDraw;
\r
34568 /***/ function(module, exports, __webpack_require__) {
\r
34571 * @module echarts/chart/helper/Line
\r
34575 var symbolUtil = __webpack_require__(100);
\r
34576 var vector = __webpack_require__(16);
\r
34577 var LinePath = __webpack_require__(196);
\r
34578 var graphic = __webpack_require__(42);
\r
34579 var zrUtil = __webpack_require__(3);
\r
34580 var numberUtil = __webpack_require__(7);
\r
34585 function createSymbol(name, data, idx) {
\r
34586 var color = data.getItemVisual(idx, 'color');
\r
34587 var symbolType = data.getItemVisual(idx, 'symbol');
\r
34588 var symbolSize = data.getItemVisual(idx, 'symbolSize');
\r
34590 if (symbolType === 'none') {
\r
34594 if (!zrUtil.isArray(symbolSize)) {
\r
34595 symbolSize = [symbolSize, symbolSize];
\r
34597 var symbolPath = symbolUtil.createSymbol(
\r
34598 symbolType, -symbolSize[0] / 2, -symbolSize[1] / 2,
\r
34599 symbolSize[0], symbolSize[1], color
\r
34601 symbolPath.name = name;
\r
34603 return symbolPath;
\r
34606 function createLine(points) {
\r
34607 var line = new LinePath({
\r
34610 strokeNoScale: true
\r
34613 setLinePoints(line.shape, points);
\r
34617 function setLinePoints(targetShape, points) {
\r
34618 var p1 = points[0];
\r
34619 var p2 = points[1];
\r
34620 var cp1 = points[2];
\r
34621 targetShape.x1 = p1[0];
\r
34622 targetShape.y1 = p1[1];
\r
34623 targetShape.x2 = p2[0];
\r
34624 targetShape.y2 = p2[1];
\r
34625 targetShape.percent = 1;
\r
34628 targetShape.cpx1 = cp1[0];
\r
34629 targetShape.cpy1 = cp1[1];
\r
34633 function isSymbolArrow(symbol) {
\r
34634 return symbol.type === 'symbol' && symbol.shape.symbolType === 'arrow';
\r
34637 function updateSymbolBeforeLineUpdate () {
\r
34638 var lineGroup = this;
\r
34639 var line = lineGroup.childOfName('line');
\r
34640 // If line not changed
\r
34641 if (!this.__dirty && !line.__dirty) {
\r
34644 var symbolFrom = lineGroup.childOfName('fromSymbol');
\r
34645 var symbolTo = lineGroup.childOfName('toSymbol');
\r
34646 var label = lineGroup.childOfName('label');
\r
34647 var fromPos = line.pointAt(0);
\r
34648 var toPos = line.pointAt(line.shape.percent);
\r
34650 var d = vector.sub([], toPos, fromPos);
\r
34651 vector.normalize(d, d);
\r
34653 if (symbolFrom) {
\r
34654 symbolFrom.attr('position', fromPos);
\r
34655 // Rotate the arrow
\r
34656 // FIXME Hard coded ?
\r
34657 if (isSymbolArrow(symbolFrom)) {
\r
34658 symbolFrom.attr('rotation', tangentRotation(toPos, fromPos));
\r
34662 symbolTo.attr('position', toPos);
\r
34663 if (isSymbolArrow(symbolTo)) {
\r
34664 symbolTo.attr('rotation', tangentRotation(fromPos, toPos));
\r
34668 label.attr('position', toPos);
\r
34670 var textPosition;
\r
34672 var textVerticalAlign;
\r
34674 if (label.__position === 'end') {
\r
34675 textPosition = [d[0] * 5 + toPos[0], d[1] * 5 + toPos[1]];
\r
34676 textAlign = d[0] > 0.8 ? 'left' : (d[0] < -0.8 ? 'right' : 'center');
\r
34677 textVerticalAlign = d[1] > 0.8 ? 'top' : (d[1] < -0.8 ? 'bottom' : 'middle');
\r
34681 textPosition = [-d[0] * 5 + fromPos[0], -d[1] * 5 + fromPos[1]];
\r
34682 textAlign = d[0] > 0.8 ? 'right' : (d[0] < -0.8 ? 'left' : 'center');
\r
34683 textVerticalAlign = d[1] > 0.8 ? 'bottom' : (d[1] < -0.8 ? 'top' : 'middle');
\r
34687 // Use the user specified text align and baseline first
\r
34688 textVerticalAlign: label.__verticalAlign || textVerticalAlign,
\r
34689 textAlign: label.__textAlign || textAlign
\r
34691 position: textPosition
\r
34695 function tangentRotation(p1, p2) {
\r
34696 return -Math.PI / 2 - Math.atan2(
\r
34697 p2[1] - p1[1], p2[0] - p1[0]
\r
34703 * @extends {module:zrender/graphic/Group}
\r
34704 * @alias {module:echarts/chart/helper/Line}
\r
34706 function Line(lineData, fromData, toData, idx) {
\r
34707 graphic.Group.call(this);
\r
34709 this._createLine(lineData, fromData, toData, idx);
\r
34712 var lineProto = Line.prototype;
\r
34714 // Update symbol position and rotation
\r
34715 lineProto.beforeUpdate = updateSymbolBeforeLineUpdate;
\r
34717 lineProto._createLine = function (lineData, fromData, toData, idx) {
\r
34718 var seriesModel = lineData.hostModel;
\r
34719 var linePoints = lineData.getItemLayout(idx);
\r
34721 var line = createLine(linePoints);
\r
34722 line.shape.percent = 0;
\r
34723 graphic.initProps(line, {
\r
34731 var label = new graphic.Text({
\r
34737 var symbolFrom = createSymbol('fromSymbol', fromData, idx);
\r
34738 // symbols must added after line to make sure
\r
34739 // it will be updated after line#update.
\r
34740 // Or symbol position and rotation update in line#beforeUpdate will be one frame slow
\r
34741 this.add(symbolFrom);
\r
34743 this._fromSymbolType = fromData.getItemVisual(idx, 'symbol');
\r
34746 var symbolTo = createSymbol('toSymbol', toData, idx);
\r
34747 this.add(symbolTo);
\r
34749 this._toSymbolType = toData.getItemVisual(idx, 'symbol');
\r
34752 this._updateCommonStl(lineData, fromData, toData, idx);
\r
34755 lineProto.updateData = function (lineData, fromData, toData, idx) {
\r
34756 var seriesModel = lineData.hostModel;
\r
34758 var line = this.childOfName('line');
\r
34759 var linePoints = lineData.getItemLayout(idx);
\r
34763 setLinePoints(target.shape, linePoints);
\r
34764 graphic.updateProps(line, target, seriesModel);
\r
34766 // Symbol changed
\r
34768 var fromSymbolType = fromData.getItemVisual(idx, 'symbol');
\r
34769 if (this._fromSymbolType !== fromSymbolType) {
\r
34770 var symbolFrom = createSymbol('fromSymbol', fromData, idx);
\r
34771 this.remove(this.childOfName('fromSymbol'));
\r
34772 this.add(symbolFrom);
\r
34774 this._fromSymbolType = fromSymbolType;
\r
34777 var toSymbolType = toData.getItemVisual(idx, 'symbol');
\r
34778 // Symbol changed
\r
34779 if (toSymbolType !== this._toSymbolType) {
\r
34780 var symbolTo = createSymbol('toSymbol', toData, idx);
\r
34781 this.remove(this.childOfName('toSymbol'));
\r
34782 this.add(symbolTo);
\r
34784 this._toSymbolType = toSymbolType;
\r
34787 this._updateCommonStl(lineData, fromData, toData, idx);
\r
34790 lineProto._updateCommonStl = function (lineData, fromData, toData, idx) {
\r
34791 var seriesModel = lineData.hostModel;
\r
34793 var line = this.childOfName('line');
\r
34794 var itemModel = lineData.getItemModel(idx);
\r
34796 var labelModel = itemModel.getModel('label.normal');
\r
34797 var textStyleModel = labelModel.getModel('textStyle');
\r
34798 var labelHoverModel = itemModel.getModel('label.emphasis');
\r
34799 var textStyleHoverModel = labelHoverModel.getModel('textStyle');
\r
34801 var defaultText = numberUtil.round(seriesModel.getRawValue(idx));
\r
34802 if (isNaN(defaultText)) {
\r
34804 defaultText = lineData.getName(idx);
\r
34806 line.setStyle(zrUtil.extend(
\r
34808 stroke: lineData.getItemVisual(idx, 'color')
\r
34810 itemModel.getModel('lineStyle.normal').getLineStyle()
\r
34813 var label = this.childOfName('label');
\r
34815 text: labelModel.get('show')
\r
34816 ? zrUtil.retrieve(
\r
34817 seriesModel.getFormattedLabel(idx, 'normal'),
\r
34821 textFont: textStyleModel.getFont(),
\r
34822 fill: textStyleModel.getTextColor() || lineData.getItemVisual(idx, 'color')
\r
34824 label.hoverStyle = {
\r
34825 text: labelHoverModel.get('show')
\r
34826 ? zrUtil.retrieve(
\r
34827 seriesModel.getFormattedLabel(idx, 'emphasis'),
\r
34831 textFont: textStyleHoverModel.getFont(),
\r
34832 fill: textStyleHoverModel.getTextColor()
\r
34834 label.__textAlign = textStyleModel.get('align');
\r
34835 label.__verticalAlign = textStyleModel.get('baseline');
\r
34836 label.__position = labelModel.get('position');
\r
34838 graphic.setHoverStyle(
\r
34839 this, itemModel.getModel('lineStyle.emphasis').getLineStyle()
\r
34843 lineProto.updateLayout = function (lineData, fromData, toData, idx) {
\r
34844 var points = lineData.getItemLayout(idx);
\r
34845 var linePath = this.childOfName('line');
\r
34846 setLinePoints(linePath.shape, points);
\r
34847 linePath.dirty(true);
\r
34848 // var fromEl = fromData && fromData.getItemGraphicEl(idx);
\r
34849 // var toEl = toData && toData.getItemGraphicEl(idx);
\r
34850 // fromEl && fromEl.attr('position', points[0]);
\r
34851 // toEl && toEl.attr('position', points[1]);
\r
34854 zrUtil.inherits(Line, graphic.Group);
\r
34856 module.exports = Line;
\r
34861 /***/ function(module, exports, __webpack_require__) {
\r
34864 * Line path for bezier and straight line draw
\r
34867 var graphic = __webpack_require__(42);
\r
34869 var straightLineProto = graphic.Line.prototype;
\r
34870 var bezierCurveProto = graphic.BezierCurve.prototype;
\r
34872 module.exports = graphic.extendShape({
\r
34891 buildPath: function (ctx, shape) {
\r
34892 (shape.cpx1 == null || shape.cpy1 == null
\r
34893 ? straightLineProto : bezierCurveProto).buildPath(ctx, shape);
\r
34896 pointAt: function (t) {
\r
34897 var shape = this.shape;
\r
34898 return shape.cpx1 == null || shape.cpy1 == null
\r
34899 ? straightLineProto.pointAt.call(this, t)
\r
34900 : bezierCurveProto.pointAt.call(this, t);
\r
34907 /***/ function(module, exports, __webpack_require__) {
\r
34911 var echarts = __webpack_require__(1);
\r
34912 var roamHelper = __webpack_require__(162);
\r
34914 var actionInfo = {
\r
34915 type: 'graphRoam',
\r
34916 event: 'graphRoam',
\r
34922 * @property {string} name Series name
\r
34923 * @property {number} [dx]
\r
34924 * @property {number} [dy]
\r
34925 * @property {number} [zoom]
\r
34926 * @property {number} [originX]
\r
34927 * @property {number} [originY]
\r
34930 echarts.registerAction(actionInfo, function (payload, ecModel) {
\r
34931 ecModel.eachComponent({mainType: 'series', query: payload}, function (seriesModel) {
\r
34932 var coordSys = seriesModel.coordinateSystem;
\r
34934 var roamDetailModel = seriesModel.getModel('roamDetail');
\r
34935 var res = roamHelper.calcPanAndZoom(roamDetailModel, payload);
\r
34937 seriesModel.setRoamPan
\r
34938 && seriesModel.setRoamPan(res.x, res.y);
\r
34940 seriesModel.setRoamZoom
\r
34941 && seriesModel.setRoamZoom(res.zoom);
\r
34943 coordSys && coordSys.setPan(res.x, res.y);
\r
34944 coordSys && coordSys.setZoom(res.zoom);
\r
34951 /***/ function(module, exports) {
\r
34955 module.exports = function (ecModel) {
\r
34956 var legendModels = ecModel.findComponents({
\r
34957 mainType: 'legend'
\r
34959 if (!legendModels || !legendModels.length) {
\r
34962 ecModel.eachSeriesByType('graph', function (graphSeries) {
\r
34963 var categoriesData = graphSeries.getCategoriesData();
\r
34964 var graph = graphSeries.getGraph();
\r
34965 var data = graph.data;
\r
34967 var categoryNames = categoriesData.mapArray(categoriesData.getName);
\r
34969 data.filterSelf(function (idx) {
\r
34970 var model = data.getItemModel(idx);
\r
34971 var category = model.getShallow('category');
\r
34972 if (category != null) {
\r
34973 if (typeof category === 'number') {
\r
34974 category = categoryNames[category];
\r
34976 // If in any legend component the status is not selected.
\r
34977 for (var i = 0; i < legendModels.length; i++) {
\r
34978 if (!legendModels[i].isSelected(category)) {
\r
34991 /***/ function(module, exports) {
\r
34995 module.exports = function (ecModel) {
\r
34996 ecModel.eachSeriesByType('graph', function (seriesModel) {
\r
34997 var colorList = seriesModel.get('color');
\r
34998 var categoriesData = seriesModel.getCategoriesData();
\r
34999 var data = seriesModel.getData();
\r
35001 var categoryNameIdxMap = {};
\r
35003 categoriesData.each(function (idx) {
\r
35004 categoryNameIdxMap[categoriesData.getName(idx)] = idx;
\r
35006 var itemModel = categoriesData.getItemModel(idx);
\r
35007 var rawIdx = categoriesData.getRawIndex(idx);
\r
35008 var color = itemModel.get('itemStyle.normal.color')
\r
35009 || colorList[rawIdx % colorList.length];
\r
35010 categoriesData.setItemVisual(idx, 'color', color);
\r
35013 // Assign category color to visual
\r
35014 if (categoriesData.count()) {
\r
35015 data.each(function (idx) {
\r
35016 var model = data.getItemModel(idx);
\r
35017 var category = model.getShallow('category');
\r
35018 if (category != null) {
\r
35019 if (typeof category === 'string') {
\r
35020 category = categoryNameIdxMap[category];
\r
35022 data.setItemVisual(
\r
35024 categoriesData.getItemVisual(category, 'color')
\r
35035 /***/ function(module, exports, __webpack_require__) {
\r
35039 var simpleLayoutHelper = __webpack_require__(201);
\r
35040 module.exports = function (ecModel, api) {
\r
35041 ecModel.eachSeriesByType('graph', function (seriesModel) {
\r
35042 var layout = seriesModel.get('layout');
\r
35043 if (!layout || layout === 'none') {
\r
35044 simpleLayoutHelper(seriesModel);
\r
35052 /***/ function(module, exports) {
\r
35055 module.exports = function (seriesModel) {
\r
35056 var coordSys = seriesModel.coordinateSystem;
\r
35057 if (coordSys && coordSys.type !== 'view') {
\r
35060 var graph = seriesModel.getGraph();
\r
35062 graph.eachNode(function (node) {
\r
35063 var model = node.getModel();
\r
35064 node.setLayout([+model.get('x'), +model.get('y')]);
\r
35067 graph.eachEdge(function (edge) {
\r
35068 var curveness = edge.getModel().get('lineStyle.normal.curveness') || 0;
\r
35069 var p1 = edge.node1.getLayout();
\r
35070 var p2 = edge.node2.getLayout();
\r
35072 if (curveness > 0) {
\r
35074 (p1[0] + p2[0]) / 2 - (p1[1] - p2[1]) * curveness,
\r
35075 (p1[1] + p2[1]) / 2 - (p2[0] - p1[0]) * curveness
\r
35078 edge.setLayout([p1, p2, cp1]);
\r
35085 /***/ function(module, exports, __webpack_require__) {
\r
35088 var circularLayoutHelper = __webpack_require__(203);
\r
35089 module.exports = function (ecModel, api) {
\r
35090 ecModel.eachSeriesByType('graph', function (seriesModel) {
\r
35091 if (seriesModel.get('layout') === 'circular') {
\r
35092 circularLayoutHelper(seriesModel);
\r
35100 /***/ function(module, exports) {
\r
35103 module.exports = function (seriesModel) {
\r
35104 var coordSys = seriesModel.coordinateSystem;
\r
35105 if (coordSys && coordSys.type !== 'view') {
\r
35109 var rect = coordSys.getBoundingRect();
\r
35111 var nodeData = seriesModel.getData();
\r
35112 var graph = nodeData.graph;
\r
35115 var sum = nodeData.getSum('value');
\r
35116 var unitAngle = Math.PI * 2 / (sum || nodeData.count());
\r
35118 var cx = rect.width / 2 + rect.x;
\r
35119 var cy = rect.height / 2 + rect.y;
\r
35121 var r = Math.min(rect.width, rect.height) / 2;
\r
35123 graph.eachNode(function (node) {
\r
35124 var value = node.getValue('value');
\r
35126 angle += unitAngle * (sum ? value : 2) / 2;
\r
35129 r * Math.cos(angle) + cx,
\r
35130 r * Math.sin(angle) + cy
\r
35133 angle += unitAngle * (sum ? value : 2) / 2;
\r
35136 graph.eachEdge(function (edge) {
\r
35137 var curveness = edge.getModel().get('lineStyle.normal.curveness') || 0;
\r
35138 var p1 = edge.node1.getLayout();
\r
35139 var p2 = edge.node2.getLayout();
\r
35141 if (curveness > 0) {
\r
35144 edge.setLayout([p1, p2, cp1]);
\r
35151 /***/ function(module, exports, __webpack_require__) {
\r
35155 var forceHelper = __webpack_require__(205);
\r
35156 var numberUtil = __webpack_require__(7);
\r
35157 var simpleLayoutHelper = __webpack_require__(201);
\r
35158 var circularLayoutHelper = __webpack_require__(203);
\r
35159 var vec2 = __webpack_require__(16);
\r
35161 module.exports = function (ecModel, api) {
\r
35162 ecModel.eachSeriesByType('graph', function (graphSeries) {
\r
35163 if (graphSeries.get('layout') === 'force') {
\r
35164 var preservedPoints = graphSeries.preservedPoints || {};
\r
35165 var graph = graphSeries.getGraph();
\r
35166 var nodeData = graph.data;
\r
35167 var edgeData = graph.edgeData;
\r
35168 var forceModel = graphSeries.getModel('force');
\r
35169 var initLayout = forceModel.get('initLayout');
\r
35170 if (graphSeries.preservedPoints) {
\r
35171 nodeData.each(function (idx) {
\r
35172 var id = nodeData.getId(idx);
\r
35173 nodeData.setItemLayout(idx, preservedPoints[id] || [NaN, NaN]);
\r
35176 else if (!initLayout || initLayout === 'none') {
\r
35177 simpleLayoutHelper(graphSeries);
\r
35179 else if (initLayout === 'circular') {
\r
35180 circularLayoutHelper(graphSeries);
\r
35183 var nodeDataExtent = nodeData.getDataExtent('value');
\r
35184 // var edgeDataExtent = edgeData.getDataExtent('value');
\r
35185 var repulsion = forceModel.get('repulsion');
\r
35186 var edgeLength = forceModel.get('edgeLength');
\r
35187 var nodes = nodeData.mapArray('value', function (value, idx) {
\r
35188 var point = nodeData.getItemLayout(idx);
\r
35189 // var w = numberUtil.linearMap(value, nodeDataExtent, [0, 50]);
\r
35190 var rep = numberUtil.linearMap(value, nodeDataExtent, [0, repulsion]) || (repulsion / 2);
\r
35194 p: (!point || isNaN(point[0]) || isNaN(point[1])) ? null : point
\r
35197 var edges = edgeData.mapArray('value', function (value, idx) {
\r
35198 var edge = graph.getEdgeByIndex(idx);
\r
35199 // var w = numberUtil.linearMap(value, edgeDataExtent, [0, 100]);
\r
35201 n1: nodes[edge.node1.dataIndex],
\r
35202 n2: nodes[edge.node2.dataIndex],
\r
35204 curveness: edge.getModel().get('lineStyle.normal.curveness') || 0
\r
35208 var coordSys = graphSeries.coordinateSystem;
\r
35209 var rect = coordSys.getBoundingRect();
\r
35210 var forceInstance = forceHelper(nodes, edges, {
\r
35212 gravity: forceModel.get('gravity')
\r
35214 var oldStep = forceInstance.step;
\r
35215 forceInstance.step = function (cb) {
\r
35216 for (var i = 0, l = nodes.length; i < l; i++) {
\r
35217 if (nodes[i].fixed) {
\r
35218 // Write back to layout instance
\r
35219 vec2.copy(nodes[i].p, graph.getNodeByIndex(i).getLayout());
\r
35222 oldStep(function (nodes, edges, stopped) {
\r
35223 for (var i = 0, l = nodes.length; i < l; i++) {
\r
35224 if (!nodes[i].fixed) {
\r
35225 graph.getNodeByIndex(i).setLayout(nodes[i].p);
\r
35227 preservedPoints[nodeData.getId(i)] = nodes[i].p;
\r
35229 for (var i = 0, l = edges.length; i < l; i++) {
\r
35230 var e = edges[i];
\r
35233 var points = [p1, p2];
\r
35234 if (e.curveness > 0) {
\r
35236 (p1[0] + p2[0]) / 2 - (p1[1] - p2[1]) * e.curveness,
\r
35237 (p1[1] + p2[1]) / 2 - (p2[0] - p1[0]) * e.curveness
\r
35240 graph.getEdgeByIndex(i).setLayout(points);
\r
35244 cb && cb(stopped);
\r
35247 graphSeries.forceLayout = forceInstance;
\r
35248 graphSeries.preservedPoints = preservedPoints;
\r
35250 // Step to get the layout
\r
35251 forceInstance.step();
\r
35254 // Remove prev injected forceLayout instance
\r
35255 graphSeries.forceLayout = null;
\r
35263 /***/ function(module, exports, __webpack_require__) {
\r
35267 var vec2 = __webpack_require__(16);
\r
35268 var scaleAndAdd = vec2.scaleAndAdd;
\r
35270 // function adjacentNode(n, e) {
\r
35271 // return e.n1 === n ? e.n2 : e.n1;
\r
35274 module.exports = function (nodes, edges, opts) {
\r
35275 var rect = opts.rect;
\r
35276 var width = rect.width;
\r
35277 var height = rect.height;
\r
35278 var center = [rect.x + width / 2, rect.y + height / 2];
\r
35279 // var scale = opts.scale || 1;
\r
35280 var gravity = opts.gravity == null ? 0.1 : opts.gravity;
\r
35282 // for (var i = 0; i < edges.length; i++) {
\r
35283 // var e = edges[i];
\r
35284 // var n1 = e.n1;
\r
35285 // var n2 = e.n2;
\r
35286 // n1.edges = n1.edges || [];
\r
35287 // n2.edges = n2.edges || [];
\r
35288 // n1.edges.push(e);
\r
35289 // n2.edges.push(e);
\r
35292 for (var i = 0; i < nodes.length; i++) {
\r
35293 var n = nodes[i];
\r
35295 // Use the position from first adjecent node with defined position
\r
35296 // Or use a random position
\r
35298 // if (n.edges) {
\r
35300 // while (++j < n.edges.length) {
\r
35301 // var e = n.edges[j];
\r
35302 // var other = adjacentNode(n, e);
\r
35303 // if (other.p) {
\r
35304 // n.p = vec2.clone(other.p);
\r
35310 n.p = vec2.create(
\r
35311 width * (Math.random() - 0.5) + center[0],
\r
35312 height * (Math.random() - 0.5) + center[1]
\r
35316 n.pp = vec2.clone(n.p);
\r
35320 // Formula in 'Graph Drawing by Force-directed Placement'
\r
35321 // var k = scale * Math.sqrt(width * height / nodes.length);
\r
35322 // var k2 = k * k;
\r
35324 var friction = 0.6;
\r
35327 warmUp: function () {
\r
35331 setFixed: function (idx) {
\r
35332 nodes[idx].fixed = true;
\r
35335 setUnfixed: function (idx) {
\r
35336 nodes[idx].fixed = false;
\r
35339 step: function (cb) {
\r
35341 var nLen = nodes.length;
\r
35342 for (var i = 0; i < edges.length; i++) {
\r
35343 var e = edges[i];
\r
35347 vec2.sub(v12, n2.p, n1.p);
\r
35348 var d = vec2.len(v12) - e.d;
\r
35349 var w = n2.w / (n1.w + n2.w);
\r
35350 vec2.normalize(v12, v12);
\r
35352 !n1.fixed && scaleAndAdd(n1.p, n1.p, v12, w * d * friction);
\r
35353 !n2.fixed && scaleAndAdd(n2.p, n2.p, v12, -(1 - w) * d * friction);
\r
35356 for (var i = 0; i < nLen; i++) {
\r
35357 var n = nodes[i];
\r
35359 vec2.sub(v12, center, n.p);
\r
35360 // var d = vec2.len(v12);
\r
35361 // vec2.scale(v12, v12, 1 / d);
\r
35362 // var gravityFactor = gravity;
\r
35363 vec2.scaleAndAdd(n.p, n.p, v12, gravity * friction);
\r
35369 for (var i = 0; i < nLen; i++) {
\r
35370 var n1 = nodes[i];
\r
35371 for (var j = i + 1; j < nLen; j++) {
\r
35372 var n2 = nodes[j];
\r
35373 vec2.sub(v12, n2.p, n1.p);
\r
35374 var d = vec2.len(v12);
\r
35376 // Random repulse
\r
35377 vec2.set(v12, Math.random() - 0.5, Math.random() - 0.5);
\r
35380 var repFact = (n1.rep + n2.rep) / d / d;
\r
35381 !n1.fixed && scaleAndAdd(n1.pp, n1.pp, v12, repFact);
\r
35382 !n2.fixed && scaleAndAdd(n2.pp, n2.pp, v12, -repFact);
\r
35386 for (var i = 0; i < nLen; i++) {
\r
35387 var n = nodes[i];
\r
35389 vec2.sub(v, n.p, n.pp);
\r
35390 vec2.scaleAndAdd(n.p, n.p, v, friction);
\r
35391 vec2.copy(n.pp, n.p);
\r
35395 friction = friction * 0.992;
\r
35397 cb && cb(nodes, edges, friction < 0.01);
\r
35405 /***/ function(module, exports, __webpack_require__) {
\r
35408 // FIXME Where to create the simple view coordinate system
\r
35409 var View = __webpack_require__(169);
\r
35410 var layout = __webpack_require__(21);
\r
35411 var bbox = __webpack_require__(50);
\r
35413 function getViewRect(seriesModel, api, aspect) {
\r
35414 var option = seriesModel.getBoxLayoutParams();
\r
35415 option.aspect = aspect;
\r
35416 return layout.getLayoutRect(option, {
\r
35417 width: api.getWidth(),
\r
35418 height: api.getHeight()
\r
35422 module.exports = function (ecModel, api) {
\r
35423 var viewList = [];
\r
35424 ecModel.eachSeriesByType('graph', function (seriesModel) {
\r
35425 var coordSysType = seriesModel.get('coordinateSystem');
\r
35426 if (!coordSysType || coordSysType === 'view') {
\r
35427 var viewCoordSys = new View();
\r
35428 viewList.push(viewCoordSys);
\r
35430 var data = seriesModel.getData();
\r
35431 var positions = data.mapArray(function (idx) {
\r
35432 var itemModel = data.getItemModel(idx);
\r
35433 return [+itemModel.get('x'), +itemModel.get('y')];
\r
35439 bbox.fromPoints(positions, min, max);
\r
35441 // FIXME If get view rect after data processed?
\r
35442 var viewRect = getViewRect(
\r
35443 seriesModel, api, (max[0] - min[0]) / (max[1] - min[1]) || 1
\r
35445 // Position may be NaN, use view rect instead
\r
35446 if (isNaN(min[0]) || isNaN(min[1])) {
\r
35447 min = [viewRect.x, viewRect.y];
\r
35448 max = [viewRect.x + viewRect.width, viewRect.y + viewRect.height];
\r
35451 var bbWidth = max[0] - min[0];
\r
35452 var bbHeight = max[1] - min[1];
\r
35454 var viewWidth = viewRect.width;
\r
35455 var viewHeight = viewRect.height;
\r
35457 viewCoordSys = seriesModel.coordinateSystem = new View();
\r
35459 viewCoordSys.setBoundingRect(
\r
35460 min[0], min[1], bbWidth, bbHeight
\r
35462 viewCoordSys.setViewRect(
\r
35463 viewRect.x, viewRect.y, viewWidth, viewHeight
\r
35466 // Update roam info
\r
35467 var roamDetailModel = seriesModel.getModel('roamDetail');
\r
35468 viewCoordSys.setPan(roamDetailModel.get('x') || 0, roamDetailModel.get('y') || 0);
\r
35469 viewCoordSys.setZoom(roamDetailModel.get('zoom') || 1);
\r
35478 /***/ function(module, exports, __webpack_require__) {
\r
35481 __webpack_require__(208);
\r
35482 __webpack_require__(209);
\r
35487 /***/ function(module, exports, __webpack_require__) {
\r
35491 var List = __webpack_require__(94);
\r
35492 var SeriesModel = __webpack_require__(27);
\r
35493 var zrUtil = __webpack_require__(3);
\r
35495 var GaugeSeries = SeriesModel.extend({
\r
35497 type: 'series.gauge',
\r
35499 getInitialData: function (option, ecModel) {
\r
35500 var list = new List(['value'], this);
\r
35501 var dataOpt = option.data || [];
\r
35502 if (!zrUtil.isArray(dataOpt)) {
\r
35503 dataOpt = [dataOpt];
\r
35505 // Only use the first data item
\r
35506 list.initData(dataOpt);
\r
35514 center: ['50%', '50%'],
\r
35515 legendHoverLink: true,
\r
35528 // 默认显示,属性show控制显示与否
\r
35530 lineStyle: { // 属性lineStyle控制线条样式
\r
35531 color: [[0.2, '#91c7ae'], [0.8, '#63869e'], [1, '#c23531']],
\r
35537 // 默认显示,属性show控制显示与否
\r
35541 // 属性lineStyle(详见lineStyle)控制线条样式
\r
35550 // 属性show控制显示与否,默认不显示
\r
35556 // 属性lineStyle控制线条样式
\r
35565 // formatter: null,
\r
35566 textStyle: { // 其余属性默认使用全局文本样式,详见TEXTSTYLE
\r
35583 offsetCenter: [0, '-40%'],
\r
35584 // 其余属性默认使用全局文本样式,详见TEXTSTYLE
\r
35592 backgroundColor: 'rgba(0,0,0,0)',
\r
35594 borderColor: '#ccc',
\r
35598 offsetCenter: [0, '40%'],
\r
35599 // formatter: null,
\r
35600 // 其余属性默认使用全局文本样式,详见TEXTSTYLE
\r
35609 module.exports = GaugeSeries;
\r
35614 /***/ function(module, exports, __webpack_require__) {
\r
35618 var PointerPath = __webpack_require__(210);
\r
35620 var graphic = __webpack_require__(42);
\r
35621 var numberUtil = __webpack_require__(7);
\r
35622 var parsePercent = numberUtil.parsePercent;
\r
35624 function parsePosition(seriesModel, api) {
\r
35625 var center = seriesModel.get('center');
\r
35626 var width = api.getWidth();
\r
35627 var height = api.getHeight();
\r
35628 var size = Math.min(width, height);
\r
35629 var cx = parsePercent(center[0], api.getWidth());
\r
35630 var cy = parsePercent(center[1], api.getHeight());
\r
35631 var r = parsePercent(seriesModel.get('radius'), size / 2);
\r
35640 function formatLabel(label, labelFormatter) {
\r
35641 if (labelFormatter) {
\r
35642 if (typeof labelFormatter === 'string') {
\r
35643 label = labelFormatter.replace('{value}', label);
\r
35645 else if (typeof labelFormatter === 'function') {
\r
35646 label = labelFormatter(label);
\r
35653 var PI2 = Math.PI * 2;
\r
35655 var GaugeView = __webpack_require__(41).extend({
\r
35659 render: function (seriesModel, ecModel, api) {
\r
35661 this.group.removeAll();
\r
35663 var colorList = seriesModel.get('axisLine.lineStyle.color');
\r
35664 var posInfo = parsePosition(seriesModel, api);
\r
35666 this._renderMain(
\r
35667 seriesModel, ecModel, api, colorList, posInfo
\r
35671 _renderMain: function (seriesModel, ecModel, api, colorList, posInfo) {
\r
35672 var group = this.group;
\r
35674 var axisLineModel = seriesModel.getModel('axisLine');
\r
35675 var lineStyleModel = axisLineModel.getModel('lineStyle');
\r
35677 var clockwise = seriesModel.get('clockwise');
\r
35678 var startAngle = -seriesModel.get('startAngle') / 180 * Math.PI;
\r
35679 var endAngle = -seriesModel.get('endAngle') / 180 * Math.PI;
\r
35681 var angleRangeSpan = (endAngle - startAngle) % PI2;
\r
35683 var prevEndAngle = startAngle;
\r
35684 var axisLineWidth = lineStyleModel.get('width');
\r
35686 for (var i = 0; i < colorList.length; i++) {
\r
35687 var endAngle = startAngle + angleRangeSpan * colorList[i][0];
\r
35688 var sector = new graphic.Sector({
\r
35690 startAngle: prevEndAngle,
\r
35691 endAngle: endAngle,
\r
35694 clockwise: clockwise,
\r
35695 r0: posInfo.r - axisLineWidth,
\r
35701 sector.setStyle({
\r
35702 fill: colorList[i][1]
\r
35705 sector.setStyle(lineStyleModel.getLineStyle(
\r
35706 // Because we use sector to simulate arc
\r
35707 // so the properties for stroking are useless
\r
35708 ['color', 'borderWidth', 'borderColor']
\r
35711 group.add(sector);
\r
35713 prevEndAngle = endAngle;
\r
35716 var getColor = function (percent) {
\r
35718 if (percent <= 0) {
\r
35719 return colorList[0][1];
\r
35721 for (var i = 0; i < colorList.length; i++) {
\r
35722 if (colorList[i][0] >= percent
\r
35723 && (i === 0 ? 0 : colorList[i - 1][0]) < percent
\r
35725 return colorList[i][1];
\r
35729 return colorList[i - 1][1];
\r
35732 if (!clockwise) {
\r
35733 var tmp = startAngle;
\r
35734 startAngle = endAngle;
\r
35738 this._renderTicks(
\r
35739 seriesModel, ecModel, api, getColor, posInfo,
\r
35740 startAngle, endAngle, clockwise
\r
35743 this._renderPointer(
\r
35744 seriesModel, ecModel, api, getColor, posInfo,
\r
35745 startAngle, endAngle, clockwise
\r
35748 this._renderTitle(
\r
35749 seriesModel, ecModel, api, getColor, posInfo
\r
35751 this._renderDetail(
\r
35752 seriesModel, ecModel, api, getColor, posInfo
\r
35756 _renderTicks: function (
\r
35757 seriesModel, ecModel, api, getColor, posInfo,
\r
35758 startAngle, endAngle, clockwise
\r
35760 var group = this.group;
\r
35761 var cx = posInfo.cx;
\r
35762 var cy = posInfo.cy;
\r
35763 var r = posInfo.r;
\r
35765 var minVal = seriesModel.get('min');
\r
35766 var maxVal = seriesModel.get('max');
\r
35768 var splitLineModel = seriesModel.getModel('splitLine');
\r
35769 var tickModel = seriesModel.getModel('axisTick');
\r
35770 var labelModel = seriesModel.getModel('axisLabel');
\r
35772 var splitNumber = seriesModel.get('splitNumber');
\r
35773 var subSplitNumber = tickModel.get('splitNumber');
\r
35775 var splitLineLen = parsePercent(
\r
35776 splitLineModel.get('length'), r
\r
35778 var tickLen = parsePercent(
\r
35779 tickModel.get('length'), r
\r
35782 var angle = startAngle;
\r
35783 var step = (endAngle - startAngle) / splitNumber;
\r
35784 var subStep = step / subSplitNumber;
\r
35786 var splitLineStyle = splitLineModel.getModel('lineStyle').getLineStyle();
\r
35787 var tickLineStyle = tickModel.getModel('lineStyle').getLineStyle();
\r
35788 var textStyleModel = labelModel.getModel('textStyle');
\r
35790 for (var i = 0; i <= splitNumber; i++) {
\r
35791 var unitX = Math.cos(angle);
\r
35792 var unitY = Math.sin(angle);
\r
35794 if (splitLineModel.get('show')) {
\r
35795 var splitLine = new graphic.Line({
\r
35797 x1: unitX * r + cx,
\r
35798 y1: unitY * r + cy,
\r
35799 x2: unitX * (r - splitLineLen) + cx,
\r
35800 y2: unitY * (r - splitLineLen) + cy
\r
35802 style: splitLineStyle,
\r
35805 if (splitLineStyle.stroke === 'auto') {
\r
35806 splitLine.setStyle({
\r
35807 stroke: getColor(i / splitNumber)
\r
35811 group.add(splitLine);
\r
35815 if (labelModel.get('show')) {
\r
35816 var label = formatLabel(
\r
35817 numberUtil.round(i / splitNumber * (maxVal - minVal) + minVal),
\r
35818 labelModel.get('formatter')
\r
35821 var text = new graphic.Text({
\r
35824 x: unitX * (r - splitLineLen - 5) + cx,
\r
35825 y: unitY * (r - splitLineLen - 5) + cy,
\r
35826 fill: textStyleModel.getTextColor(),
\r
35827 textFont: textStyleModel.getFont(),
\r
35828 textVerticalAlign: unitY < -0.4 ? 'top' : (unitY > 0.4 ? 'bottom' : 'middle'),
\r
35829 textAlign: unitX < -0.4 ? 'left' : (unitX > 0.4 ? 'right' : 'center')
\r
35833 if (text.style.fill === 'auto') {
\r
35835 fill: getColor(i / splitNumber)
\r
35843 if (tickModel.get('show') && i !== splitNumber) {
\r
35844 for (var j = 0; j <= subSplitNumber; j++) {
\r
35845 var unitX = Math.cos(angle);
\r
35846 var unitY = Math.sin(angle);
\r
35847 var tickLine = new graphic.Line({
\r
35849 x1: unitX * r + cx,
\r
35850 y1: unitY * r + cy,
\r
35851 x2: unitX * (r - tickLen) + cx,
\r
35852 y2: unitY * (r - tickLen) + cy
\r
35855 style: tickLineStyle
\r
35858 if (tickLineStyle.stroke === 'auto') {
\r
35859 tickLine.setStyle({
\r
35860 stroke: getColor((i + j / subSplitNumber) / splitNumber)
\r
35864 group.add(tickLine);
\r
35865 angle += subStep;
\r
35867 angle -= subStep;
\r
35875 _renderPointer: function (
\r
35876 seriesModel, ecModel, api, getColor, posInfo,
\r
35877 startAngle, endAngle, clockwise
\r
35879 var linearMap = numberUtil.linearMap;
\r
35880 var valueExtent = [+seriesModel.get('min'), +seriesModel.get('max')];
\r
35881 var angleExtent = [startAngle, endAngle];
\r
35883 if (!clockwise) {
\r
35884 angleExtent = angleExtent.reverse();
\r
35887 var data = seriesModel.getData();
\r
35888 var oldData = this._data;
\r
35890 var group = this.group;
\r
35892 data.diff(oldData)
\r
35893 .add(function (idx) {
\r
35894 var pointer = new PointerPath({
\r
35896 angle: startAngle
\r
35900 graphic.updateProps(pointer, {
\r
35902 angle: linearMap(data.get('value', idx), valueExtent, angleExtent)
\r
35906 group.add(pointer);
\r
35907 data.setItemGraphicEl(idx, pointer);
\r
35909 .update(function (newIdx, oldIdx) {
\r
35910 var pointer = oldData.getItemGraphicEl(oldIdx);
\r
35912 graphic.updateProps(pointer, {
\r
35914 angle: linearMap(data.get('value', newIdx), valueExtent, angleExtent)
\r
35918 group.add(pointer);
\r
35919 data.setItemGraphicEl(newIdx, pointer);
\r
35921 .remove(function (idx) {
\r
35922 var pointer = oldData.getItemGraphicEl(idx);
\r
35923 group.remove(pointer);
\r
35927 data.eachItemGraphicEl(function (pointer, idx) {
\r
35928 var itemModel = data.getItemModel(idx);
\r
35929 var pointerModel = itemModel.getModel('pointer');
\r
35935 width: parsePercent(
\r
35936 pointerModel.get('width'), posInfo.r
\r
35938 r: parsePercent(pointerModel.get('length'), posInfo.r)
\r
35940 style: itemModel.getModel('itemStyle.normal').getItemStyle()
\r
35943 if (pointer.style.fill === 'auto') {
\r
35944 pointer.setStyle('fill', getColor(
\r
35945 (data.get('value', idx) - valueExtent[0]) / (valueExtent[1] - valueExtent[0])
\r
35949 graphic.setHoverStyle(
\r
35950 pointer, itemModel.getModel('itemStyle.emphasis').getItemStyle()
\r
35954 this._data = data;
\r
35957 _renderTitle: function (
\r
35958 seriesModel, ecModel, api, getColor, posInfo
\r
35960 var titleModel = seriesModel.getModel('title');
\r
35961 if (titleModel.get('show')) {
\r
35962 var textStyleModel = titleModel.getModel('textStyle');
\r
35963 var offsetCenter = titleModel.get('offsetCenter');
\r
35964 var x = posInfo.cx + parsePercent(offsetCenter[0], posInfo.r);
\r
35965 var y = posInfo.cy + parsePercent(offsetCenter[1], posInfo.r);
\r
35966 var text = new graphic.Text({
\r
35970 // FIXME First data name ?
\r
35971 text: seriesModel.getData().getName(0),
\r
35972 fill: textStyleModel.getTextColor(),
\r
35973 textFont: textStyleModel.getFont(),
\r
35974 textAlign: 'center',
\r
35975 textVerticalAlign: 'middle'
\r
35978 this.group.add(text);
\r
35982 _renderDetail: function (
\r
35983 seriesModel, ecModel, api, getColor, posInfo
\r
35985 var detailModel = seriesModel.getModel('detail');
\r
35986 var minVal = seriesModel.get('min');
\r
35987 var maxVal = seriesModel.get('max');
\r
35988 if (detailModel.get('show')) {
\r
35989 var textStyleModel = detailModel.getModel('textStyle');
\r
35990 var offsetCenter = detailModel.get('offsetCenter');
\r
35991 var x = posInfo.cx + parsePercent(offsetCenter[0], posInfo.r);
\r
35992 var y = posInfo.cy + parsePercent(offsetCenter[1], posInfo.r);
\r
35993 var width = parsePercent(detailModel.get('width'), posInfo.r);
\r
35994 var height = parsePercent(detailModel.get('height'), posInfo.r);
\r
35995 var value = seriesModel.getData().get('value', 0);
\r
35996 var rect = new graphic.Rect({
\r
35998 x: x - width / 2,
\r
35999 y: y - height / 2,
\r
36004 text: formatLabel(
\r
36005 // FIXME First data name ?
\r
36006 value, detailModel.get('formatter')
\r
36008 fill: detailModel.get('backgroundColor'),
\r
36009 textFill: textStyleModel.getTextColor(),
\r
36010 textFont: textStyleModel.getFont()
\r
36013 if (rect.style.textFill === 'auto') {
\r
36014 rect.setStyle('textFill', getColor((value - minVal) / (maxVal - minVal)));
\r
36016 rect.setStyle(detailModel.getItemStyle(['color']));
\r
36017 this.group.add(rect);
\r
36022 module.exports = GaugeView;
\r
36027 /***/ function(module, exports, __webpack_require__) {
\r
36031 module.exports = __webpack_require__(44).extend({
\r
36033 type: 'echartsGaugePointer',
\r
36047 buildPath: function (ctx, shape) {
\r
36048 var mathCos = Math.cos;
\r
36049 var mathSin = Math.sin;
\r
36052 var width = shape.width;
\r
36053 var angle = shape.angle;
\r
36054 var x = shape.x - mathCos(angle) * width * (width >= r / 3 ? 1 : 2);
\r
36055 var y = shape.y - mathSin(angle) * width * (width >= r / 3 ? 1 : 2);
\r
36057 angle = shape.angle - Math.PI / 2;
\r
36058 ctx.moveTo(x, y);
\r
36060 shape.x + mathCos(angle) * width,
\r
36061 shape.y + mathSin(angle) * width
\r
36064 shape.x + mathCos(shape.angle) * r,
\r
36065 shape.y + mathSin(shape.angle) * r
\r
36068 shape.x - mathCos(angle) * width,
\r
36069 shape.y - mathSin(angle) * width
\r
36071 ctx.lineTo(x, y);
\r
36079 /***/ function(module, exports, __webpack_require__) {
\r
36083 var zrUtil = __webpack_require__(3);
\r
36084 var echarts = __webpack_require__(1);
\r
36086 __webpack_require__(212);
\r
36087 __webpack_require__(213);
\r
36089 echarts.registerVisualCoding(
\r
36090 'chart', zrUtil.curry(__webpack_require__(137), 'funnel')
\r
36092 echarts.registerLayout(__webpack_require__(214));
\r
36094 echarts.registerProcessor(
\r
36095 'filter', zrUtil.curry(__webpack_require__(140), 'funnel')
\r
36101 /***/ function(module, exports, __webpack_require__) {
\r
36106 var List = __webpack_require__(94);
\r
36107 var modelUtil = __webpack_require__(5);
\r
36108 var completeDimensions = __webpack_require__(96);
\r
36110 var FunnelSeries = __webpack_require__(1).extendSeriesModel({
\r
36112 type: 'series.funnel',
\r
36114 init: function (option) {
\r
36115 FunnelSeries.superApply(this, 'init', arguments);
\r
36117 // Enable legend selection for each data item
\r
36118 // Use a function instead of direct access because data reference may changed
\r
36119 this.legendDataProvider = function () {
\r
36120 return this._dataBeforeProcessed;
\r
36122 // Extend labelLine emphasis
\r
36123 this._defaultLabelLine(option);
\r
36126 getInitialData: function (option, ecModel) {
\r
36127 var dimensions = completeDimensions(['value'], option.data);
\r
36128 var list = new List(dimensions, this);
\r
36129 list.initData(option.data);
\r
36133 _defaultLabelLine: function (option) {
\r
36134 // Extend labelLine emphasis
\r
36135 modelUtil.defaultEmphasis(option.labelLine, ['show']);
\r
36137 var labelLineNormalOpt = option.labelLine.normal;
\r
36138 var labelLineEmphasisOpt = option.labelLine.emphasis;
\r
36139 // Not show label line if `label.normal.show = false`
\r
36140 labelLineNormalOpt.show = labelLineNormalOpt.show
\r
36141 && option.label.normal.show;
\r
36142 labelLineEmphasisOpt.show = labelLineEmphasisOpt.show
\r
36143 && option.label.emphasis.show;
\r
36147 zlevel: 0, // 一级层叠
\r
36149 legendHoverLink: true,
\r
36154 // width: {totalWidth} - left - right,
\r
36155 // height: {totalHeight} - top - bottom,
\r
36162 sort: 'descending', // 'ascending', 'descending'
\r
36164 funnelAlign: 'center',
\r
36168 position: 'outer'
\r
36169 // formatter: 标签文本格式器,同Tooltip.formatter,不支持异步回调
\r
36170 // textStyle: null // 默认使用全局文本样式,详见TEXTSTYLE
\r
36191 borderColor: '#fff',
\r
36201 module.exports = FunnelSeries;
\r
36206 /***/ function(module, exports, __webpack_require__) {
\r
36210 var graphic = __webpack_require__(42);
\r
36211 var zrUtil = __webpack_require__(3);
\r
36214 * Piece of pie including Sector, Label, LabelLine
\r
36216 * @extends {module:zrender/graphic/Group}
\r
36218 function FunnelPiece(data, idx) {
\r
36220 graphic.Group.call(this);
\r
36222 var polygon = new graphic.Polygon();
\r
36223 var labelLine = new graphic.Polyline();
\r
36224 var text = new graphic.Text();
\r
36225 this.add(polygon);
\r
36226 this.add(labelLine);
\r
36229 this.updateData(data, idx, true);
\r
36231 // Hover to change label and labelLine
\r
36232 function onEmphasis() {
\r
36233 labelLine.ignore = labelLine.hoverIgnore;
\r
36234 text.ignore = text.hoverIgnore;
\r
36236 function onNormal() {
\r
36237 labelLine.ignore = labelLine.normalIgnore;
\r
36238 text.ignore = text.normalIgnore;
\r
36240 this.on('emphasis', onEmphasis)
\r
36241 .on('normal', onNormal)
\r
36242 .on('mouseover', onEmphasis)
\r
36243 .on('mouseout', onNormal);
\r
36246 var funnelPieceProto = FunnelPiece.prototype;
\r
36248 function getLabelStyle(data, idx, state, labelModel) {
\r
36249 var textStyleModel = labelModel.getModel('textStyle');
\r
36250 var position = labelModel.get('position');
\r
36251 var isLabelInside = position === 'inside' || position === 'inner' || position === 'center';
\r
36253 fill: textStyleModel.getTextColor()
\r
36254 || (isLabelInside ? '#fff' : data.getItemVisual(idx, 'color')),
\r
36255 textFont: textStyleModel.getFont(),
\r
36256 text: zrUtil.retrieve(
\r
36257 data.hostModel.getFormattedLabel(idx, state),
\r
36258 data.getName(idx)
\r
36263 var opacityAccessPath = ['itemStyle', 'normal', 'opacity'];
\r
36264 funnelPieceProto.updateData = function (data, idx, firstCreate) {
\r
36266 var polygon = this.childAt(0);
\r
36268 var seriesModel = data.hostModel;
\r
36269 var itemModel = data.getItemModel(idx);
\r
36270 var layout = data.getItemLayout(idx);
\r
36271 var opacity = data.getItemModel(idx).get(opacityAccessPath);
\r
36272 opacity = opacity == null ? 1 : opacity;
\r
36273 if (firstCreate) {
\r
36274 polygon.setShape({
\r
36275 points: layout.points
\r
36277 polygon.setStyle({ opacity : 0 });
\r
36278 graphic.updateProps(polygon, {
\r
36285 graphic.initProps(polygon, {
\r
36287 points: layout.points
\r
36292 // Update common style
\r
36293 var itemStyleModel = itemModel.getModel('itemStyle');
\r
36294 var visualColor = data.getItemVisual(idx, 'color');
\r
36296 polygon.setStyle(
\r
36299 fill: visualColor
\r
36301 itemStyleModel.getModel('normal').getItemStyle()
\r
36304 polygon.hoverStyle = itemStyleModel.getModel('emphasis').getItemStyle();
\r
36306 this._updateLabel(data, idx);
\r
36308 graphic.setHoverStyle(this);
\r
36311 funnelPieceProto._updateLabel = function (data, idx) {
\r
36313 var labelLine = this.childAt(1);
\r
36314 var labelText = this.childAt(2);
\r
36316 var seriesModel = data.hostModel;
\r
36317 var itemModel = data.getItemModel(idx);
\r
36318 var layout = data.getItemLayout(idx);
\r
36319 var labelLayout = layout.label;
\r
36320 var visualColor = data.getItemVisual(idx, 'color');
\r
36322 graphic.updateProps(labelLine, {
\r
36324 points: labelLayout.linePoints || labelLayout.linePoints
\r
36328 graphic.updateProps(labelText, {
\r
36330 x: labelLayout.x,
\r
36336 textAlign: labelLayout.textAlign,
\r
36337 textVerticalAlign: labelLayout.verticalAlign,
\r
36338 textFont: labelLayout.font
\r
36340 rotation: labelLayout.rotation,
\r
36341 origin: [labelLayout.x, labelLayout.y],
\r
36345 var labelModel = itemModel.getModel('label.normal');
\r
36346 var labelHoverModel = itemModel.getModel('label.emphasis');
\r
36347 var labelLineModel = itemModel.getModel('labelLine.normal');
\r
36348 var labelLineHoverModel = itemModel.getModel('labelLine.emphasis');
\r
36350 labelText.setStyle(getLabelStyle(data, idx, 'normal', labelModel));
\r
36352 labelText.ignore = labelText.normalIgnore = !labelModel.get('show');
\r
36353 labelText.hoverIgnore = !labelHoverModel.get('show');
\r
36355 labelLine.ignore = labelLine.normalIgnore = !labelLineModel.get('show');
\r
36356 labelLine.hoverIgnore = !labelLineHoverModel.get('show');
\r
36358 // Default use item visual color
\r
36359 labelLine.setStyle({
\r
36360 stroke: visualColor
\r
36362 labelLine.setStyle(labelLineModel.getModel('lineStyle').getLineStyle());
\r
36364 labelText.hoverStyle = getLabelStyle(data, idx, 'emphasis', labelHoverModel);
\r
36365 labelLine.hoverStyle = labelLineHoverModel.getModel('lineStyle').getLineStyle();
\r
36368 zrUtil.inherits(FunnelPiece, graphic.Group);
\r
36371 var Funnel = __webpack_require__(41).extend({
\r
36375 render: function (seriesModel, ecModel, api) {
\r
36376 var data = seriesModel.getData();
\r
36377 var oldData = this._data;
\r
36379 var group = this.group;
\r
36381 data.diff(oldData)
\r
36382 .add(function (idx) {
\r
36383 var funnelPiece = new FunnelPiece(data, idx);
\r
36385 data.setItemGraphicEl(idx, funnelPiece);
\r
36387 group.add(funnelPiece);
\r
36389 .update(function (newIdx, oldIdx) {
\r
36390 var piePiece = oldData.getItemGraphicEl(oldIdx);
\r
36392 piePiece.updateData(data, newIdx);
\r
36394 group.add(piePiece);
\r
36395 data.setItemGraphicEl(newIdx, piePiece);
\r
36397 .remove(function (idx) {
\r
36398 var piePiece = oldData.getItemGraphicEl(idx);
\r
36399 group.remove(piePiece);
\r
36403 this._data = data;
\r
36406 remove: function () {
\r
36407 this.group.removeAll();
\r
36408 this._data = null;
\r
36412 module.exports = Funnel;
\r
36417 /***/ function(module, exports, __webpack_require__) {
\r
36421 var layout = __webpack_require__(21);
\r
36422 var number = __webpack_require__(7);
\r
36424 var parsePercent = number.parsePercent;
\r
36426 function getViewRect(seriesModel, api) {
\r
36427 return layout.getLayoutRect(
\r
36428 seriesModel.getBoxLayoutParams(), {
\r
36429 width: api.getWidth(),
\r
36430 height: api.getHeight()
\r
36435 function getSortedIndices(data, sort) {
\r
36436 var valueArr = data.mapArray('value', function (val) {
\r
36439 var indices = [];
\r
36440 var isAscending = sort === 'ascending';
\r
36441 for (var i = 0, len = data.count(); i < len; i++) {
\r
36444 indices.sort(function (a, b) {
\r
36445 return isAscending ? valueArr[a] - valueArr[b] : valueArr[b] - valueArr[a];
\r
36450 function labelLayout (data) {
\r
36451 data.each(function (idx) {
\r
36452 var itemModel = data.getItemModel(idx);
\r
36453 var labelModel = itemModel.getModel('label.normal');
\r
36454 var labelPosition = labelModel.get('position');
\r
36456 var labelLineModel = itemModel.getModel('labelLine.normal');
\r
36458 var layout = data.getItemLayout(idx);
\r
36459 var points = layout.points;
\r
36461 var isLabelInside = labelPosition === 'inner'
\r
36462 || labelPosition === 'inside' || labelPosition === 'center';
\r
36469 if (isLabelInside) {
\r
36470 textX = (points[0][0] + points[1][0] + points[2][0] + points[3][0]) / 4;
\r
36471 textY = (points[0][1] + points[1][1] + points[2][1] + points[3][1]) / 4;
\r
36472 textAlign = 'center';
\r
36474 [textX, textY], [textX, textY]
\r
36481 var labelLineLen = labelLineModel.get('length');
\r
36482 if (labelPosition === 'left') {
\r
36484 x1 = (points[3][0] + points[0][0]) / 2;
\r
36485 y1 = (points[3][1] + points[0][1]) / 2;
\r
36486 x2 = x1 - labelLineLen;
\r
36488 textAlign = 'right';
\r
36492 x1 = (points[1][0] + points[2][0]) / 2;
\r
36493 y1 = (points[1][1] + points[2][1]) / 2;
\r
36494 x2 = x1 + labelLineLen;
\r
36496 textAlign = 'left';
\r
36500 linePoints = [[x1, y1], [x2, y2]];
\r
36505 linePoints: linePoints,
\r
36508 verticalAlign: 'middle',
\r
36509 textAlign: textAlign,
\r
36510 inside: isLabelInside
\r
36515 module.exports = function (ecModel, api) {
\r
36516 ecModel.eachSeriesByType('funnel', function (seriesModel) {
\r
36517 var data = seriesModel.getData();
\r
36518 var sort = seriesModel.get('sort');
\r
36519 var viewRect = getViewRect(seriesModel, api);
\r
36520 var indices = getSortedIndices(data, sort);
\r
36522 var sizeExtent = [
\r
36523 parsePercent(seriesModel.get('minSize'), viewRect.width),
\r
36524 parsePercent(seriesModel.get('maxSize'), viewRect.width)
\r
36526 var dataExtent = data.getDataExtent('value');
\r
36527 var min = seriesModel.get('min');
\r
36528 var max = seriesModel.get('max');
\r
36529 if (min == null) {
\r
36530 min = Math.min(dataExtent[0], 0);
\r
36532 if (max == null) {
\r
36533 max = dataExtent[1];
\r
36536 var funnelAlign = seriesModel.get('funnelAlign');
\r
36537 var gap = seriesModel.get('gap');
\r
36538 var itemHeight = (viewRect.height - gap * (data.count() - 1)) / data.count();
\r
36540 var y = viewRect.y;
\r
36542 var getLinePoints = function (idx, offY) {
\r
36543 // End point index is data.count() and we assign it 0
\r
36544 var val = data.get('value', idx) || 0;
\r
36545 var itemWidth = number.linearMap(val, [min, max], sizeExtent, true);
\r
36547 switch (funnelAlign) {
\r
36552 x0 = viewRect.x + (viewRect.width - itemWidth) / 2;
\r
36555 x0 = viewRect.x + viewRect.width - itemWidth;
\r
36560 [x0 + itemWidth, offY]
\r
36564 if (sort === 'ascending') {
\r
36565 // From bottom to top
\r
36566 itemHeight = -itemHeight;
\r
36568 y += viewRect.height;
\r
36569 indices = indices.reverse();
\r
36572 for (var i = 0; i < indices.length; i++) {
\r
36573 var idx = indices[i];
\r
36574 var nextIdx = indices[i + 1];
\r
36575 var start = getLinePoints(idx, y);
\r
36576 var end = getLinePoints(nextIdx, y + itemHeight);
\r
36578 y += itemHeight + gap;
\r
36580 data.setItemLayout(idx, {
\r
36581 points: start.concat(end.slice().reverse())
\r
36585 labelLayout(data);
\r
36592 /***/ function(module, exports, __webpack_require__) {
\r
36596 var echarts = __webpack_require__(1);
\r
36598 __webpack_require__(216);
\r
36600 __webpack_require__(227);
\r
36601 __webpack_require__(228);
\r
36603 echarts.registerVisualCoding('chart', __webpack_require__(229));
\r
36609 /***/ function(module, exports, __webpack_require__) {
\r
36613 __webpack_require__(217);
\r
36614 __webpack_require__(220);
\r
36615 __webpack_require__(222);
\r
36617 var echarts = __webpack_require__(1);
\r
36620 echarts.extendComponentView({
\r
36624 echarts.registerPreprocessor(
\r
36625 __webpack_require__(226)
\r
36632 /***/ function(module, exports, __webpack_require__) {
\r
36635 * Parallel coordinate system creater.
\r
36639 var Parallel = __webpack_require__(218);
\r
36641 function create(ecModel, api) {
\r
36642 var coordSysList = [];
\r
36644 ecModel.eachComponent('parallel', function (parallelModel, idx) {
\r
36645 var coordSys = new Parallel(parallelModel, ecModel, api);
\r
36647 coordSys.name = 'parallel_' + idx;
\r
36648 coordSys.resize(parallelModel, api);
\r
36650 parallelModel.coordinateSystem = coordSys;
\r
36651 coordSys.model = parallelModel;
\r
36653 coordSysList.push(coordSys);
\r
36656 // Inject the coordinateSystems into seriesModel
\r
36657 ecModel.eachSeries(function (seriesModel) {
\r
36658 if (seriesModel.get('coordinateSystem') === 'parallel') {
\r
36659 var parallelIndex = seriesModel.get('parallelIndex');
\r
36660 seriesModel.coordinateSystem = coordSysList[parallelIndex];
\r
36664 return coordSysList;
\r
36667 __webpack_require__(25).register('parallel', {create: create});
\r
36673 /***/ function(module, exports, __webpack_require__) {
\r
36676 * Parallel Coordinates
\r
36677 * <https://en.wikipedia.org/wiki/Parallel_coordinates>
\r
36681 var layout = __webpack_require__(21);
\r
36682 var axisHelper = __webpack_require__(108);
\r
36683 var zrUtil = __webpack_require__(3);
\r
36684 var ParallelAxis = __webpack_require__(219);
\r
36685 var matrix = __webpack_require__(17);
\r
36686 var vector = __webpack_require__(16);
\r
36688 var each = zrUtil.each;
\r
36690 var PI = Math.PI;
\r
36692 function Parallel(parallelModel, ecModel, api) {
\r
36696 * @type {Object.<string, module:echarts/coord/parallel/Axis>}
\r
36699 this._axesMap = {};
\r
36703 * value: {position: [], rotation, }
\r
36704 * @type {Object.<string, Object>}
\r
36707 this._axesLayout = {};
\r
36710 * Always follow axis order.
\r
36711 * @type {Array.<string>}
\r
36714 this.dimensions = parallelModel.dimensions;
\r
36717 * @type {module:zrender/core/BoundingRect}
\r
36722 * @type {module:echarts/coord/parallel/ParallelModel}
\r
36724 this._model = parallelModel;
\r
36726 this._init(parallelModel, ecModel, api);
\r
36729 Parallel.prototype = {
\r
36731 type: 'parallel',
\r
36733 constructor: Parallel,
\r
36736 * Initialize cartesian coordinate systems
\r
36739 _init: function (parallelModel, ecModel, api) {
\r
36741 var dimensions = parallelModel.dimensions;
\r
36742 var parallelAxisIndex = parallelModel.parallelAxisIndex;
\r
36744 each(dimensions, function (dim, idx) {
\r
36746 var axisIndex = parallelAxisIndex[idx];
\r
36747 var axisModel = ecModel.getComponent('parallelAxis', axisIndex);
\r
36749 var axis = this._axesMap[dim] = new ParallelAxis(
\r
36751 axisHelper.createScaleByModel(axisModel),
\r
36753 axisModel.get('type'),
\r
36757 var isCategory = axis.type === 'category';
\r
36758 axis.onBand = isCategory && axisModel.get('boundaryGap');
\r
36759 axis.inverse = axisModel.get('inverse');
\r
36761 // Inject axis into axisModel
\r
36762 axisModel.axis = axis;
\r
36764 // Inject axisModel into axis
\r
36765 axis.model = axisModel;
\r
36770 * Update axis scale after data processed
\r
36771 * @param {module:echarts/model/Global} ecModel
\r
36772 * @param {module:echarts/ExtensionAPI} api
\r
36774 update: function (ecModel, api) {
\r
36775 this._updateAxesFromSeries(this._model, ecModel);
\r
36779 * Update properties from series
\r
36782 _updateAxesFromSeries: function (parallelModel, ecModel) {
\r
36783 ecModel.eachSeries(function (seriesModel) {
\r
36785 if (!parallelModel.contains(seriesModel, ecModel)) {
\r
36789 var data = seriesModel.getData();
\r
36791 each(this.dimensions, function (dim) {
\r
36792 var axis = this._axesMap[dim];
\r
36793 axis.scale.unionExtent(data.getDataExtent(dim));
\r
36794 axisHelper.niceScaleExtent(axis, axis.model);
\r
36800 * Resize the parallel coordinate system.
\r
36801 * @param {module:echarts/coord/parallel/ParallelModel} parallelModel
\r
36802 * @param {module:echarts/ExtensionAPI} api
\r
36804 resize: function (parallelModel, api) {
\r
36805 this._rect = layout.getLayoutRect(
\r
36806 parallelModel.getBoxLayoutParams(),
\r
36808 width: api.getWidth(),
\r
36809 height: api.getHeight()
\r
36813 this._layoutAxes(parallelModel);
\r
36817 * @return {module:zrender/core/BoundingRect}
\r
36819 getRect: function () {
\r
36820 return this._rect;
\r
36826 _layoutAxes: function (parallelModel) {
\r
36827 var rect = this._rect;
\r
36828 var layout = parallelModel.get('layout');
\r
36829 var axes = this._axesMap;
\r
36830 var dimensions = this.dimensions;
\r
36832 var size = [rect.width, rect.height];
\r
36833 var sizeIdx = layout === 'horizontal' ? 0 : 1;
\r
36834 var layoutLength = size[sizeIdx];
\r
36835 var axisLength = size[1 - sizeIdx];
\r
36836 var axisExtent = [0, axisLength];
\r
36838 each(axes, function (axis) {
\r
36839 var idx = axis.inverse ? 1 : 0;
\r
36840 axis.setExtent(axisExtent[idx], axisExtent[1 - idx]);
\r
36843 each(dimensions, function (dim, idx) {
\r
36844 var pos = layoutLength * idx / (dimensions.length - 1);
\r
36846 var positionTable = {
\r
36856 var rotationTable = {
\r
36857 horizontal: PI / 2,
\r
36862 positionTable[layout].x + rect.x,
\r
36863 positionTable[layout].y + rect.y
\r
36866 var rotation = rotationTable[layout];
\r
36867 var transform = matrix.create();
\r
36868 matrix.rotate(transform, transform, rotation);
\r
36869 matrix.translate(transform, transform, position);
\r
36875 // 根据axis order 更新 dimensions顺序。
\r
36877 this._axesLayout[dim] = {
\r
36878 position: position,
\r
36879 rotation: rotation,
\r
36880 transform: transform,
\r
36881 tickDirection: 1,
\r
36882 labelDirection: 1
\r
36888 * Get axis by dim.
\r
36889 * @param {string} dim
\r
36890 * @return {module:echarts/coord/parallel/ParallelAxis} [description]
\r
36892 getAxis: function (dim) {
\r
36893 return this._axesMap[dim];
\r
36897 * Convert a dim value of a single item of series data to Point.
\r
36898 * @param {*} value
\r
36899 * @param {string} dim
\r
36900 * @return {Array}
\r
36902 dataToPoint: function (value, dim) {
\r
36903 return this.axisCoordToPoint(
\r
36904 this._axesMap[dim].dataToCoord(value),
\r
36910 * @param {module:echarts/data/List} data
\r
36911 * @param {Functio} cb param: {string} activeState 'active' or 'inactive' or 'normal'
\r
36912 * {number} dataIndex
\r
36913 * @param {Object} context
\r
36915 eachActiveState: function (data, callback, context) {
\r
36916 var dimensions = this.dimensions;
\r
36917 var axesMap = this._axesMap;
\r
36918 var hasActiveSet = false;
\r
36920 for (var j = 0, lenj = dimensions.length; j < lenj; j++) {
\r
36921 if (axesMap[dimensions[j]].model.getActiveState() !== 'normal') {
\r
36922 hasActiveSet = true;
\r
36926 for (var i = 0, len = data.count(); i < len; i++) {
\r
36927 var values = data.getValues(dimensions, i);
\r
36930 if (!hasActiveSet) {
\r
36931 activeState = 'normal';
\r
36934 activeState = 'active';
\r
36935 for (var j = 0, lenj = dimensions.length; j < lenj; j++) {
\r
36936 var dimName = dimensions[j];
\r
36937 var state = axesMap[dimName].model.getActiveState(values[j], j);
\r
36939 if (state === 'inactive') {
\r
36940 activeState = 'inactive';
\r
36946 callback.call(context, activeState, i);
\r
36951 * Convert coords of each axis to Point.
\r
36952 * Return point. For example: [10, 20]
\r
36953 * @param {Array.<number>} coords
\r
36954 * @param {string} dim
\r
36955 * @return {Array.<number>}
\r
36957 axisCoordToPoint: function (coord, dim) {
\r
36958 var axisLayout = this._axesLayout[dim];
\r
36959 var point = [coord, 0];
\r
36960 vector.applyTransform(point, point, axisLayout.transform);
\r
36965 * Get axis layout.
\r
36967 getAxisLayout: function (dim) {
\r
36968 return zrUtil.clone(this._axesLayout[dim]);
\r
36973 module.exports = Parallel;
\r
36978 /***/ function(module, exports, __webpack_require__) {
\r
36982 var zrUtil = __webpack_require__(3);
\r
36983 var Axis = __webpack_require__(117);
\r
36986 * @constructor module:echarts/coord/parallel/ParallelAxis
\r
36987 * @extends {module:echarts/coord/Axis}
\r
36988 * @param {string} dim
\r
36989 * @param {*} scale
\r
36990 * @param {Array.<number>} coordExtent
\r
36991 * @param {string} axisType
\r
36993 var ParallelAxis = function (dim, scale, coordExtent, axisType, axisIndex) {
\r
36995 Axis.call(this, dim, scale, coordExtent);
\r
37005 this.type = axisType || 'value';
\r
37011 this.axisIndex = axisIndex;
\r
37014 ParallelAxis.prototype = {
\r
37016 constructor: ParallelAxis,
\r
37020 * @param {module:echarts/coord/parallel/AxisModel}
\r
37026 zrUtil.inherits(ParallelAxis, Axis);
\r
37028 module.exports = ParallelAxis;
\r
37033 /***/ function(module, exports, __webpack_require__) {
\r
37037 var zrUtil = __webpack_require__(3);
\r
37038 var Component = __webpack_require__(19);
\r
37040 __webpack_require__(221);
\r
37042 Component.extend({
\r
37044 type: 'parallel',
\r
37046 dependencies: ['parallelAxis'],
\r
37049 * @type {module:echarts/coord/parallel/Parallel}
\r
37051 coordinateSystem: null,
\r
37054 * Each item like: 'dim0', 'dim1', 'dim2', ...
\r
37055 * @type {Array.<string>}
\r
37058 dimensions: null,
\r
37061 * Coresponding to dimensions.
\r
37062 * @type {Array.<number>}
\r
37065 parallelAxisIndex: null,
\r
37068 zlevel: 0, // 一级层叠
\r
37074 // width: {totalWidth} - left - right,
\r
37075 // height: {totalHeight} - top - bottom,
\r
37077 layout: 'horizontal', // 'horizontal' or 'vertical'
\r
37079 parallelAxisDefault: null
\r
37085 init: function () {
\r
37086 Component.prototype.init.apply(this, arguments);
\r
37088 this.mergeOption({});
\r
37094 mergeOption: function (newOption) {
\r
37095 var thisOption = this.option;
\r
37097 newOption && zrUtil.merge(thisOption, newOption, true);
\r
37099 this._initDimensions();
\r
37103 * Whether series or axis is in this coordinate system.
\r
37104 * @param {module:echarts/model/Series|module:echarts/coord/parallel/AxisModel} model
\r
37105 * @param {module:echarts/model/Global} ecModel
\r
37107 contains: function (model, ecModel) {
\r
37108 var parallelIndex = model.get('parallelIndex');
\r
37109 return parallelIndex != null
\r
37110 && ecModel.getComponent('parallel', parallelIndex) === this;
\r
37116 _initDimensions: function () {
\r
37117 var dimensions = this.dimensions = [];
\r
37118 var parallelAxisIndex = this.parallelAxisIndex = [];
\r
37120 var axisModels = zrUtil.filter(this.dependentModels.parallelAxis, function (axisModel) {
\r
37121 // Can not use this.contains here, because
\r
37122 // initialization has not been completed yet.
\r
37123 return axisModel.get('parallelIndex') === this.componentIndex;
\r
37126 zrUtil.each(axisModels, function (axisModel) {
\r
37127 dimensions.push('dim' + axisModel.get('dim'));
\r
37128 parallelAxisIndex.push(axisModel.componentIndex);
\r
37138 /***/ function(module, exports, __webpack_require__) {
\r
37142 var ComponentModel = __webpack_require__(19);
\r
37143 var zrUtil = __webpack_require__(3);
\r
37144 var makeStyleMapper = __webpack_require__(11);
\r
37145 var axisModelCreator = __webpack_require__(121);
\r
37146 var numberUtil = __webpack_require__(7);
\r
37148 var AxisModel = ComponentModel.extend({
\r
37150 type: 'baseParallelAxis',
\r
37153 * @type {module:echarts/coord/parallel/Axis}
\r
37158 * @type {Array.<Array.<number>}
\r
37161 activeIntervals: [],
\r
37164 * @return {Object}
\r
37166 getAreaSelectStyle: function () {
\r
37167 return makeStyleMapper(
\r
37169 ['fill', 'color'],
\r
37170 ['lineWidth', 'borderWidth'],
\r
37171 ['stroke', 'borderColor'],
\r
37172 ['width', 'width'],
\r
37173 ['opacity', 'opacity']
\r
37175 ).call(this.getModel('areaSelectStyle'));
\r
37179 * The code of this feature is put on AxisModel but not ParallelAxis,
\r
37180 * because axisModel can be alive after echarts updating but instance of
\r
37181 * ParallelAxis having been disposed. this._activeInterval should be kept
\r
37182 * when action dispatched (i.e. legend click).
\r
37184 * @param {Array.<Array<number>>} intervals interval.length === 0
\r
37185 * means set all active.
\r
37188 setActiveIntervals: function (intervals) {
\r
37189 var activeIntervals = this.activeIntervals = zrUtil.clone(intervals);
\r
37192 if (activeIntervals) {
\r
37193 for (var i = activeIntervals.length - 1; i >= 0; i--) {
\r
37194 numberUtil.asc(activeIntervals[i]);
\r
37200 * @param {number|string} [value] When attempting to detect 'no activeIntervals set',
\r
37201 * value can not be input.
\r
37202 * @return {string} 'normal': no activeIntervals set,
\r
37207 getActiveState: function (value) {
\r
37208 var activeIntervals = this.activeIntervals;
\r
37210 if (!activeIntervals.length) {
\r
37214 if (value == null) {
\r
37215 return 'inactive';
\r
37218 for (var i = 0, len = activeIntervals.length; i < len; i++) {
\r
37219 if (activeIntervals[i][0] <= value && value <= activeIntervals[i][1]) {
\r
37223 return 'inactive';
\r
37228 var defaultOption = {
\r
37233 * @type {Array.<number>}
\r
37235 dim: null, // 0, 1, 2, ...
\r
37237 parallelIndex: null,
\r
37239 areaSelectStyle: {
\r
37242 borderColor: 'rgba(160,197,232)',
\r
37243 color: 'rgba(160,197,232)',
\r
37250 zrUtil.merge(AxisModel.prototype, __webpack_require__(123));
\r
37252 function getAxisType(axisName, option) {
\r
37253 return option.type || (option.data ? 'category' : 'value');
\r
37256 axisModelCreator('parallel', AxisModel, getAxisType, defaultOption);
\r
37258 module.exports = AxisModel;
\r
37263 /***/ function(module, exports, __webpack_require__) {
\r
37267 __webpack_require__(217);
\r
37268 __webpack_require__(223);
\r
37269 __webpack_require__(224);
\r
37275 /***/ function(module, exports, __webpack_require__) {
\r
37279 var echarts = __webpack_require__(1);
\r
37281 var actionInfo = {
\r
37282 type: 'axisAreaSelect',
\r
37283 event: 'axisAreaSelected',
\r
37284 update: 'updateVisual'
\r
37289 * @property {string} parallelAxisId
\r
37290 * @property {Array.<Array.<number>>} intervals
\r
37292 echarts.registerAction(actionInfo, function (payload, ecModel) {
\r
37293 ecModel.eachComponent(
\r
37294 {mainType: 'parallelAxis', query: payload},
\r
37295 function (parallelAxisModel) {
\r
37296 parallelAxisModel.axis.model.setActiveIntervals(payload.intervals);
\r
37305 /***/ function(module, exports, __webpack_require__) {
\r
37309 var zrUtil = __webpack_require__(3);
\r
37310 var AxisBuilder = __webpack_require__(126);
\r
37311 var SelectController = __webpack_require__(225);
\r
37313 var elementList = ['axisLine', 'axisLabel', 'axisTick', 'axisName'];
\r
37315 var AxisView = __webpack_require__(1).extendComponentView({
\r
37317 type: 'parallelAxis',
\r
37320 * @type {module:echarts/component/helper/SelectController}
\r
37322 _selectController: null,
\r
37327 render: function (axisModel, ecModel, api, payload) {
\r
37328 if (fromAxisAreaSelect(axisModel, ecModel, payload)) {
\r
37332 this.axisModel = axisModel;
\r
37335 this.group.removeAll();
\r
37337 if (!axisModel.get('show')) {
\r
37341 var coordSys = ecModel.getComponent(
\r
37342 'parallel', axisModel.get('parallelIndex')
\r
37343 ).coordinateSystem;
\r
37345 var areaSelectStyle = axisModel.getAreaSelectStyle();
\r
37346 var areaWidth = areaSelectStyle.width;
\r
37348 var axisLayout = coordSys.getAxisLayout(axisModel.axis.dim);
\r
37349 var builderOpt = zrUtil.extend(
\r
37351 strokeContainThreshold: areaWidth,
\r
37352 // lineWidth === 0 or no value.
\r
37353 silent: !(areaWidth > 0) // jshint ignore:line
\r
37358 var axisBuilder = new AxisBuilder(axisModel, builderOpt);
\r
37360 zrUtil.each(elementList, axisBuilder.add, axisBuilder);
\r
37362 var axisGroup = axisBuilder.getGroup();
\r
37364 this.group.add(axisGroup);
\r
37366 this._buildSelectController(
\r
37367 axisGroup, areaSelectStyle, axisModel, api
\r
37371 _buildSelectController: function (axisGroup, areaSelectStyle, axisModel, api) {
\r
37373 var axis = axisModel.axis;
\r
37374 var selectController = this._selectController;
\r
37376 if (!selectController) {
\r
37377 selectController = this._selectController = new SelectController(
\r
37383 selectController.on('selected', zrUtil.bind(this._onSelected, this));
\r
37386 selectController.enable(axisGroup);
\r
37388 // After filtering, axis may change, select area needs to be update.
\r
37389 var ranges = zrUtil.map(axisModel.activeIntervals, function (interval) {
\r
37391 axis.dataToCoord(interval[0], true),
\r
37392 axis.dataToCoord(interval[1], true)
\r
37395 selectController.update(ranges);
\r
37398 _onSelected: function (ranges) {
\r
37399 // Do not cache these object, because the mey be changed.
\r
37400 var axisModel = this.axisModel;
\r
37401 var axis = axisModel.axis;
\r
37403 var intervals = zrUtil.map(ranges, function (range) {
\r
37405 axis.coordToData(range[0], true),
\r
37406 axis.coordToData(range[1], true)
\r
37409 this.api.dispatchAction({
\r
37410 type: 'axisAreaSelect',
\r
37411 parallelAxisId: axisModel.id,
\r
37412 intervals: intervals
\r
37419 remove: function () {
\r
37420 this._selectController && this._selectController.disable();
\r
37426 dispose: function () {
\r
37427 if (this._selectController) {
\r
37428 this._selectController.dispose();
\r
37429 this._selectController = null;
\r
37434 function fromAxisAreaSelect(axisModel, ecModel, payload) {
\r
37436 && payload.type === 'axisAreaSelect'
\r
37437 && ecModel.findComponents(
\r
37438 {mainType: 'parallelAxis', query: payload}
\r
37439 )[0] === axisModel;
\r
37442 module.exports = AxisView;
\r
37447 /***/ function(module, exports, __webpack_require__) {
\r
37450 * Box selection tool.
\r
37452 * @module echarts/component/helper/SelectController
\r
37457 var Eventful = __webpack_require__(32);
\r
37458 var zrUtil = __webpack_require__(3);
\r
37459 var graphic = __webpack_require__(42);
\r
37460 var bind = zrUtil.bind;
\r
37461 var each = zrUtil.each;
\r
37462 var mathMin = Math.min;
\r
37463 var mathMax = Math.max;
\r
37464 var mathPow = Math.pow;
\r
37466 var COVER_Z = 10000;
\r
37467 var UNSELECT_THRESHOLD = 2;
\r
37468 var EVENTS = ['mousedown', 'mousemove', 'mouseup'];
\r
37471 * @alias module:echarts/component/helper/SelectController
\r
37473 * @mixin {module:zrender/mixin/Eventful}
\r
37475 * @param {string} type 'line', 'rect'
\r
37476 * @param {module:zrender/zrender~ZRender} zr
\r
37477 * @param {Object} [opt]
\r
37478 * @param {number} [opt.width]
\r
37479 * @param {number} [opt.lineWidth]
\r
37480 * @param {string} [opt.stroke]
\r
37481 * @param {string} [opt.fill]
\r
37483 function SelectController(type, zr, opt) {
\r
37485 Eventful.call(this);
\r
37491 this.type = type;
\r
37494 * @type {module:zrender/zrender~ZRender}
\r
37502 this.opt = zrUtil.clone(opt);
\r
37505 * @type {module:zrender/container/Group}
\r
37508 this.group = new graphic.Group();
\r
37511 * @type {module:zrender/core/BoundingRect}
\r
37513 this._containerRect = null;
\r
37516 * @type {Array.<nubmer>}
\r
37519 this._track = [];
\r
37522 * @type {boolean}
\r
37527 * @type {module:zrender/Element}
\r
37533 * @type {boolean}
\r
37536 this._disabled = true;
\r
37542 this._handlers = {
\r
37543 mousedown: bind(mousedown, this),
\r
37544 mousemove: bind(mousemove, this),
\r
37545 mouseup: bind(mouseup, this)
\r
37548 each(EVENTS, function (eventName) {
\r
37549 this.zr.on(eventName, this._handlers[eventName]);
\r
37553 SelectController.prototype = {
\r
37555 constructor: SelectController,
\r
37558 * @param {module:zrender/mixin/Transformable} container
\r
37559 * @param {module:zrender/core/BoundingRect|boolean} [rect] If not specified,
\r
37560 * use container.getBoundingRect().
\r
37561 * If false, do not use containerRect.
\r
37563 enable: function (container, rect) {
\r
37565 this._disabled = false;
\r
37567 // Remove from old container.
\r
37568 removeGroup.call(this);
\r
37570 // boundingRect will change when dragging, so we have
\r
37571 // to keep initial boundingRect.
\r
37572 this._containerRect = rect !== false
\r
37573 ? (rect || container.getBoundingRect()) : null;
\r
37575 // Add to new container.
\r
37576 container.add(this.group);
\r
37580 * Update cover location.
\r
37581 * @param {Array.<number>|Object} ranges If null/undefined, remove cover.
\r
37583 update: function (ranges) {
\r
37585 // Only support one interval yet.
\r
37586 renderCover.call(this, ranges && zrUtil.clone(ranges));
\r
37589 disable: function () {
\r
37590 this._disabled = true;
\r
37592 removeGroup.call(this);
\r
37595 dispose: function () {
\r
37598 each(EVENTS, function (eventName) {
\r
37599 this.zr.off(eventName, this._handlers[eventName]);
\r
37605 zrUtil.mixin(SelectController, Eventful);
\r
37607 function updateZ(group) {
\r
37608 group.traverse(function (el) {
\r
37613 function isInContainer(x, y) {
\r
37614 var localPos = this.group.transformCoordToLocal(x, y);
\r
37615 return !this._containerRect
\r
37616 || this._containerRect.contain(localPos[0], localPos[1]);
\r
37619 function preventDefault(e) {
\r
37620 var rawE = e.event;
\r
37621 rawE.preventDefault && rawE.preventDefault();
\r
37624 function mousedown(e) {
\r
37625 if (this._disabled || (e.target && e.target.draggable)) {
\r
37629 preventDefault(e);
\r
37631 var x = e.offsetX;
\r
37632 var y = e.offsetY;
\r
37634 if (isInContainer.call(this, x, y)) {
\r
37635 this._dragging = true;
\r
37636 this._track = [[x, y]];
\r
37640 function mousemove(e) {
\r
37641 if (!this._dragging || this._disabled) {
\r
37645 preventDefault(e);
\r
37647 updateViewByCursor.call(this, e);
\r
37650 function mouseup(e) {
\r
37651 if (!this._dragging || this._disabled) {
\r
37655 preventDefault(e);
\r
37657 updateViewByCursor.call(this, e, true);
\r
37659 this._dragging = false;
\r
37660 this._track = [];
\r
37663 function updateViewByCursor(e, isEnd) {
\r
37664 var x = e.offsetX;
\r
37665 var y = e.offsetY;
\r
37667 if (isInContainer.call(this, x, y)) {
\r
37668 this._track.push([x, y]);
\r
37670 // Create or update cover.
\r
37671 var ranges = shouldShowCover.call(this)
\r
37672 ? coverRenderers[this.type].getRanges.call(this)
\r
37676 renderCover.call(this, ranges);
\r
37678 this.trigger('selected', zrUtil.clone(ranges));
\r
37681 this.trigger('selectEnd', zrUtil.clone(ranges));
\r
37686 function shouldShowCover() {
\r
37687 var track = this._track;
\r
37689 if (!track.length) {
\r
37693 var p2 = track[track.length - 1];
\r
37694 var p1 = track[0];
\r
37695 var dx = p2[0] - p1[0];
\r
37696 var dy = p2[1] - p1[1];
\r
37697 var dist = mathPow(dx * dx + dy * dy, 0.5);
\r
37699 return dist > UNSELECT_THRESHOLD;
\r
37702 function renderCover(ranges) {
\r
37703 var coverRenderer = coverRenderers[this.type];
\r
37705 if (ranges && ranges.length) {
\r
37706 if (!this._cover) {
\r
37707 this._cover = coverRenderer.create.call(this);
\r
37708 this.group.add(this._cover);
\r
37710 coverRenderer.update.call(this, ranges);
\r
37713 this.group.remove(this._cover);
\r
37714 this._cover = null;
\r
37717 updateZ(this.group);
\r
37720 function removeGroup() {
\r
37721 // container may 'removeAll' outside.
\r
37722 var group = this.group;
\r
37723 var container = group.parent;
\r
37725 container.remove(group);
\r
37729 function createRectCover() {
\r
37730 var opt = this.opt;
\r
37731 return new graphic.Rect({
\r
37733 // customize style.
\r
37735 stroke: opt.stroke,
\r
37737 lineWidth: opt.lineWidth,
\r
37738 opacity: opt.opacity
\r
37743 function getLocalTrack() {
\r
37744 return zrUtil.map(this._track, function (point) {
\r
37745 return this.group.transformCoordToLocal(point[0], point[1]);
\r
37749 function getLocalTrackEnds() {
\r
37750 var localTrack = getLocalTrack.call(this);
\r
37751 var tail = localTrack.length - 1;
\r
37752 tail < 0 && (tail = 0);
\r
37753 return [localTrack[0], localTrack[tail]];
\r
37760 var coverRenderers = {
\r
37764 create: createRectCover,
\r
37766 getRanges: function () {
\r
37767 var ends = getLocalTrackEnds.call(this);
\r
37768 var min = mathMin(ends[0][0], ends[1][0]);
\r
37769 var max = mathMax(ends[0][0], ends[1][0]);
\r
37771 return [[min, max]];
\r
37774 update: function (ranges) {
\r
37775 var range = ranges[0];
\r
37776 var width = this.opt.width;
\r
37777 this._cover.setShape({
\r
37780 width: range[1] - range[0],
\r
37788 create: createRectCover,
\r
37790 getRanges: function () {
\r
37791 var ends = getLocalTrackEnds.call(this);
\r
37794 mathMin(ends[1][0], ends[0][0]),
\r
37795 mathMin(ends[1][1], ends[0][1])
\r
37798 mathMax(ends[1][0], ends[0][0]),
\r
37799 mathMax(ends[1][1], ends[0][1])
\r
37803 [min[0], max[0]], // x range
\r
37804 [min[1], max[1]] // y range
\r
37808 update: function (ranges) {
\r
37809 var range = ranges[0];
\r
37810 this._cover.setShape({
\r
37813 width: range[0][1] - range[0][0],
\r
37814 height: range[1][1] - range[1][0]
\r
37820 module.exports = SelectController;
\r
37825 /***/ function(module, exports, __webpack_require__) {
\r
37829 var zrUtil = __webpack_require__(3);
\r
37830 var modelUtil = __webpack_require__(5);
\r
37832 module.exports = function (option) {
\r
37833 createParallelIfNeeded(option);
\r
37834 mergeAxisOptionFromParallel(option);
\r
37838 * Create a parallel coordinate if not exists.
\r
37841 function createParallelIfNeeded(option) {
\r
37842 if (option.parallel) {
\r
37846 var hasParallelSeries = false;
\r
37848 zrUtil.each(option.series, function (seriesOpt) {
\r
37849 if (seriesOpt && seriesOpt.type === 'parallel') {
\r
37850 hasParallelSeries = true;
\r
37854 if (hasParallelSeries) {
\r
37855 option.parallel = [{}];
\r
37860 * Merge aixs definition from parallel option (if exists) to axis option.
\r
37863 function mergeAxisOptionFromParallel(option) {
\r
37864 var axes = modelUtil.normalizeToArray(option.parallelAxis);
\r
37866 zrUtil.each(axes, function (axisOption) {
\r
37867 if (!zrUtil.isObject(axisOption)) {
\r
37871 var parallelIndex = axisOption.parallelIndex || 0;
\r
37872 var parallelOption = modelUtil.normalizeToArray(option.parallel)[parallelIndex];
\r
37874 if (parallelOption && parallelOption.parallelAxisDefault) {
\r
37875 zrUtil.merge(axisOption, parallelOption.parallelAxisDefault, false);
\r
37884 /***/ function(module, exports, __webpack_require__) {
\r
37888 var List = __webpack_require__(94);
\r
37889 var zrUtil = __webpack_require__(3);
\r
37890 var SeriesModel = __webpack_require__(27);
\r
37892 module.exports = SeriesModel.extend({
\r
37894 type: 'series.parallel',
\r
37896 dependencies: ['parallel'],
\r
37898 getInitialData: function (option, ecModel) {
\r
37899 var parallelModel = ecModel.getComponent(
\r
37900 'parallel', this.get('parallelIndex')
\r
37902 var dimensions = parallelModel.dimensions;
\r
37903 var parallelAxisIndices = parallelModel.parallelAxisIndex;
\r
37905 var rawData = option.data;
\r
37907 var dimensionsInfo = zrUtil.map(dimensions, function (dim, index) {
\r
37908 var axisModel = ecModel.getComponent(
\r
37909 'parallelAxis', parallelAxisIndices[index]
\r
37911 if (axisModel.get('type') === 'category') {
\r
37912 translateCategoryValue(axisModel, dim, rawData);
\r
37913 return {name: dim, type: 'ordinal'};
\r
37920 var list = new List(dimensionsInfo, this);
\r
37921 list.initData(rawData);
\r
37927 zlevel: 0, // 一级层叠
\r
37930 coordinateSystem: 'parallel',
\r
37931 parallelIndex: 0,
\r
37937 // formatter: 标签文本格式器,同Tooltip.formatter,不支持异步回调
\r
37938 // position: 默认自适应,水平布局为'top',垂直布局为'right',可选为
\r
37939 // 'inside'|'left'|'right'|'top'|'bottom'
\r
37940 // textStyle: null // 默认使用全局文本样式,详见TEXTSTYLE
\r
37944 // formatter: 标签文本格式器,同Tooltip.formatter,不支持异步回调
\r
37945 // position: 默认自适应,水平布局为'top',垂直布局为'right',可选为
\r
37946 // 'inside'|'left'|'right'|'top'|'bottom'
\r
37947 // textStyle: null // 默认使用全局文本样式,详见TEXTSTYLE
\r
37951 inactiveOpacity: 0.05,
\r
37952 activeOpacity: 1,
\r
37963 animationEasing: 'linear'
\r
37967 function translateCategoryValue(axisModel, dim, rawData) {
\r
37968 var axisData = axisModel.get('data');
\r
37969 var numberDim = +dim.replace('dim', '');
\r
37971 if (axisData && axisData.length) {
\r
37972 zrUtil.each(rawData, function (dataItem) {
\r
37976 var index = zrUtil.indexOf(axisData, dataItem[numberDim]);
\r
37977 dataItem[numberDim] = index >= 0 ? index : NaN;
\r
37981 // 如果没有设置axis data, 应自动算出,或者提示。
\r
37987 /***/ function(module, exports, __webpack_require__) {
\r
37991 var graphic = __webpack_require__(42);
\r
37992 var zrUtil = __webpack_require__(3);
\r
37994 var ParallelView = __webpack_require__(41).extend({
\r
37996 type: 'parallel',
\r
37998 init: function () {
\r
38001 * @type {module:zrender/container/Group}
\r
38004 this._dataGroup = new graphic.Group();
\r
38006 this.group.add(this._dataGroup);
\r
38008 * @type {module:echarts/data/List}
\r
38016 render: function (seriesModel, ecModel, api, payload) {
\r
38018 var dataGroup = this._dataGroup;
\r
38019 var data = seriesModel.getData();
\r
38020 var oldData = this._data;
\r
38021 var coordSys = seriesModel.coordinateSystem;
\r
38022 var dimensions = coordSys.dimensions;
\r
38024 data.diff(oldData)
\r
38031 data.eachItemGraphicEl(function (elGroup, idx) {
\r
38032 var itemModel = data.getItemModel(idx);
\r
38033 var lineStyleModel = itemModel.getModel('lineStyle.normal');
\r
38034 elGroup.eachChild(function (child) {
\r
38035 child.setStyle(zrUtil.extend(
\r
38036 lineStyleModel.getLineStyle(),
\r
38038 stroke: data.getItemVisual(idx, 'color'),
\r
38039 opacity: data.getItemVisual(idx, 'opacity')
\r
38046 if (!this._data) {
\r
38047 dataGroup.setClipPath(createGridClipShape(
\r
38048 coordSys, seriesModel, function () {
\r
38049 dataGroup.removeClipPath();
\r
38054 this._data = data;
\r
38056 function add(newDataIndex) {
\r
38057 var values = data.getValues(dimensions, newDataIndex);
\r
38058 var elGroup = new graphic.Group();
\r
38059 dataGroup.add(elGroup);
\r
38062 values, dimensions, coordSys,
\r
38063 function (pointPair, pairIndex) {
\r
38065 // init animation
\r
38067 elGroup.add(createEl(pointPair));
\r
38072 data.setItemGraphicEl(newDataIndex, elGroup);
\r
38075 function update(newDataIndex, oldDataIndex) {
\r
38076 var values = data.getValues(dimensions, newDataIndex);
\r
38077 var elGroup = oldData.getItemGraphicEl(oldDataIndex);
\r
38079 var elGroupIndex = 0;
\r
38082 values, dimensions, coordSys,
\r
38083 function (pointPair, pairIndex) {
\r
38084 var el = elGroup.childAt(elGroupIndex++);
\r
38086 if (pointPair && !el) {
\r
38087 newEls.push(createEl(pointPair));
\r
38089 else if (pointPair) {
\r
38090 graphic.updateProps(el, {
\r
38092 points: pointPair
\r
38099 // Remove redundent els
\r
38100 for (var i = elGroup.childCount() - 1; i >= elGroupIndex; i--) {
\r
38101 elGroup.remove(elGroup.childAt(i));
\r
38105 for (var i = 0, len = newEls.length; i < len; i++) {
\r
38106 elGroup.add(newEls[i]);
\r
38109 data.setItemGraphicEl(newDataIndex, elGroup);
\r
38112 function remove(oldDataIndex) {
\r
38113 var elGroup = oldData.getItemGraphicEl(oldDataIndex);
\r
38114 dataGroup.remove(elGroup);
\r
38121 remove: function () {
\r
38122 this._dataGroup && this._dataGroup.removeAll();
\r
38123 this._data = null;
\r
38127 function createGridClipShape(coordSys, seriesModel, cb) {
\r
38128 var parallelModel = coordSys.model;
\r
38129 var rect = coordSys.getRect();
\r
38130 var rectEl = new graphic.Rect({
\r
38134 width: rect.width,
\r
38135 height: rect.height
\r
38138 var dim = parallelModel.get('layout') === 'horizontal' ? 'width' : 'height';
\r
38139 rectEl.setShape(dim, 0);
\r
38140 graphic.initProps(rectEl, {
\r
38142 width: rect.width,
\r
38143 height: rect.height
\r
38145 }, seriesModel, cb);
\r
38149 function eachAxisPair(values, dimensions, coordSys, cb) {
\r
38150 for (var i = 0, len = dimensions.length - 1; i < len; i++) {
\r
38151 var dimA = dimensions[i];
\r
38152 var dimB = dimensions[i + 1];
\r
38153 var valueA = values[i];
\r
38154 var valueB = values[i + 1];
\r
38157 (isEmptyValue(valueA, coordSys.getAxis(dimA).type)
\r
38158 || isEmptyValue(valueB, coordSys.getAxis(dimB).type)
\r
38162 coordSys.dataToPoint(valueA, dimA),
\r
38163 coordSys.dataToPoint(valueB, dimB)
\r
38170 function createEl(pointPair) {
\r
38171 return new graphic.Polyline({
\r
38172 shape: {points: pointPair},
\r
38180 function isEmptyValue(val, axisType) {
\r
38181 return axisType === 'category'
\r
38183 : (val == null || isNaN(val)); // axisType === 'value'
\r
38186 module.exports = ParallelView;
\r
38191 /***/ function(module, exports) {
\r
38197 * @property {string} parallelAxisId
\r
38198 * @property {Array.<number>} extent
\r
38200 module.exports = function (ecModel, payload) {
\r
38202 ecModel.eachSeriesByType('parallel', function (seriesModel) {
\r
38204 var itemStyleModel = seriesModel.getModel('itemStyle.normal');
\r
38205 var globalColors = ecModel.get('color');
\r
38207 var color = itemStyleModel.get('color')
\r
38208 || globalColors[seriesModel.seriesIndex % globalColors.length];
\r
38209 var inactiveOpacity = seriesModel.get('inactiveOpacity');
\r
38210 var activeOpacity = seriesModel.get('activeOpacity');
\r
38211 var lineStyle = seriesModel.getModel('lineStyle.normal').getLineStyle();
\r
38213 var coordSys = seriesModel.coordinateSystem;
\r
38214 var data = seriesModel.getData();
\r
38216 var opacityMap = {
\r
38217 normal: lineStyle.opacity,
\r
38218 active: activeOpacity,
\r
38219 inactive: inactiveOpacity
\r
38222 coordSys.eachActiveState(data, function (activeState, dataIndex) {
\r
38223 data.setItemVisual(dataIndex, 'opacity', opacityMap[activeState]);
\r
38226 data.setVisual('color', color);
\r
38233 /***/ function(module, exports, __webpack_require__) {
\r
38237 var echarts = __webpack_require__(1);
\r
38239 __webpack_require__(231);
\r
38240 __webpack_require__(232);
\r
38241 echarts.registerLayout(__webpack_require__(233));
\r
38242 echarts.registerVisualCoding('chart', __webpack_require__(235));
\r
38247 /***/ function(module, exports, __webpack_require__) {
\r
38252 var SeriesModel = __webpack_require__(27);
\r
38253 var createGraphFromNodeEdge = __webpack_require__(191);
\r
38255 module.exports = SeriesModel.extend({
\r
38257 type: 'series.sankey',
\r
38259 layoutInfo: null,
\r
38261 getInitialData: function (option, ecModel) {
\r
38262 var links = option.edges || option.links;
\r
38263 var nodes = option.data || option.nodes;
\r
38264 if (nodes && links) {
\r
38265 var graph = createGraphFromNodeEdge(nodes, links, this, true);
\r
38266 return graph.data;
\r
38271 * @return {module:echarts/data/Graph}
\r
38273 getGraph: function () {
\r
38274 return this.getData().graph;
\r
38278 * return {module:echarts/data/List}
\r
38280 getEdgeData: function() {
\r
38281 return this.getGraph().edgeData;
\r
38288 coordinateSystem: 'view',
\r
38292 // the position of the whole view
\r
38298 // the dx of the node
\r
38301 // the distance between two nodes
\r
38304 // the number of iterations to change the position of the node
\r
38305 layoutIterations: 32,
\r
38310 position: 'right',
\r
38324 borderColor: '#aaa'
\r
38330 color: '#314656',
\r
38340 // colorEncoded node
\r
38342 color: ['#9e0142', '#d53e4f', '#f46d43', '#fdae61', '#fee08b','#ffffbf',
\r
38343 '#e6f598', '#abdda4', '#66c2a5', '#3288bd', '#5e4fa2'],
\r
38345 animationEasing: 'linear',
\r
38347 animationDuration: 1000
\r
38356 /***/ function(module, exports, __webpack_require__) {
\r
38360 var graphic = __webpack_require__(42);
\r
38361 var modelUtil = __webpack_require__(5);
\r
38362 var zrUtil = __webpack_require__(3);
\r
38364 var SankeyShape = graphic.extendShape({
\r
38368 cpx1: 0, cpy1: 0,
\r
38369 cpx2: 0, cpy2: 0,
\r
38374 buildPath: function (ctx, shape) {
\r
38375 var halfExtent = shape.extent / 2;
\r
38376 ctx.moveTo(shape.x1, shape.y1 - halfExtent);
\r
38377 ctx.bezierCurveTo(
\r
38378 shape.cpx1, shape.cpy1 - halfExtent,
\r
38379 shape.cpx2, shape.cpy2 - halfExtent,
\r
38380 shape.x2, shape.y2 - halfExtent
\r
38382 ctx.lineTo(shape.x2, shape.y2 + halfExtent);
\r
38383 ctx.bezierCurveTo(
\r
38384 shape.cpx2, shape.cpy2 + halfExtent,
\r
38385 shape.cpx1, shape.cpy1 + halfExtent,
\r
38386 shape.x1, shape.y1 + halfExtent
\r
38392 module.exports = __webpack_require__(1).extendChartView({
\r
38398 * @type {module:echarts/chart/sankey/SankeySeries}
\r
38402 render: function(seriesModel, ecModel, api) {
\r
38403 var graph = seriesModel.getGraph();
\r
38404 var group = this.group;
\r
38405 var layoutInfo = seriesModel.layoutInfo;
\r
38407 this._model = seriesModel;
\r
38409 group.removeAll();
\r
38411 group.position = [layoutInfo.x, layoutInfo.y];
\r
38413 var edgeData = graph.edgeData;
\r
38414 var rawOption = seriesModel.option;
\r
38415 var formatModel = modelUtil.createDataFormatModel(
\r
38416 seriesModel, edgeData, rawOption.edges || rawOption.links
\r
38419 formatModel.formatTooltip = function (dataIndex) {
\r
38420 var params = this.getDataParams(dataIndex);
\r
38421 var rawDataOpt = params.data;
\r
38422 var html = rawDataOpt.source + ' -- ' + rawDataOpt.target;
\r
38423 if (params.value) {
\r
38424 html += ':' + params.value;
\r
38429 // generate a rect for each node
\r
38430 graph.eachNode(function (node) {
\r
38431 var layout = node.getLayout();
\r
38432 var itemModel = node.getModel();
\r
38433 var labelModel = itemModel.getModel('label.normal');
\r
38434 var textStyleModel = labelModel.getModel('textStyle');
\r
38435 var labelHoverModel = itemModel.getModel('label.emphasis');
\r
38436 var textStyleHoverModel = labelHoverModel.getModel('textStyle');
\r
38438 var rect = new graphic.Rect({
\r
38442 width: node.getLayout().dx,
\r
38443 height: node.getLayout().dy
\r
38446 // Get formatted label in label.normal option. Use node id if it is not specified
\r
38447 text: labelModel.get('show')
\r
38448 ? seriesModel.getFormattedLabel(node.dataIndex, 'normal') || node.id
\r
38449 // Use empty string to hide the label
\r
38451 textFont: textStyleModel.getFont(),
\r
38452 textFill: textStyleModel.getTextColor(),
\r
38453 textPosition: labelModel.get('position')
\r
38457 rect.setStyle(zrUtil.defaults(
\r
38459 fill: node.getVisual('color')
\r
38461 itemModel.getModel('itemStyle.normal').getItemStyle()
\r
38464 graphic.setHoverStyle(rect, zrUtil.extend(
\r
38465 node.getModel('itemStyle.emphasis'),
\r
38467 text: labelHoverModel.get('show')
\r
38468 ? seriesModel.getFormattedLabel(node.dataIndex, 'emphasis') || node.id
\r
38470 textFont: textStyleHoverModel.getFont(),
\r
38471 textFill: textStyleHoverModel.getTextColor(),
\r
38472 textPosition: labelHoverModel.get('position')
\r
38479 // generate a bezire Curve for each edge
\r
38480 graph.eachEdge(function (edge) {
\r
38481 var curve = new SankeyShape();
\r
38483 curve.dataIndex = edge.dataIndex;
\r
38484 curve.dataModel = formatModel;
\r
38486 var lineStyleModel = edge.getModel('lineStyle.normal');
\r
38487 var curvature = lineStyleModel.get('curveness');
\r
38488 var n1Layout = edge.node1.getLayout();
\r
38489 var n2Layout = edge.node2.getLayout();
\r
38490 var edgeLayout = edge.getLayout();
\r
38492 curve.shape.extent = Math.max(1, edgeLayout.dy);
\r
38494 var x1 = n1Layout.x + n1Layout.dx;
\r
38495 var y1 = n1Layout.y + edgeLayout.sy + edgeLayout.dy / 2;
\r
38496 var x2 = n2Layout.x;
\r
38497 var y2 = n2Layout.y + edgeLayout.ty + edgeLayout.dy /2;
\r
38498 var cpx1 = x1 * (1 - curvature) + x2 * curvature;
\r
38500 var cpx2 = x1 * curvature + x2 * (1 - curvature);
\r
38514 curve.setStyle(lineStyleModel.getItemStyle());
\r
38515 graphic.setHoverStyle(curve, edge.getModel('lineStyle.emphasis').getItemStyle());
\r
38517 group.add(curve);
\r
38520 if (!this._data) {
\r
38521 group.setClipPath(createGridClipShape(group.getBoundingRect(), seriesModel, function () {
\r
38522 group.removeClipPath();
\r
38525 this._data = seriesModel.getData();
\r
38529 //add animation to the view
\r
38530 function createGridClipShape(rect, seriesModel, cb) {
\r
38531 var rectEl = new graphic.Rect({
\r
38536 height: rect.height + 20
\r
38539 graphic.initProps(rectEl, {
\r
38541 width: rect.width + 20,
\r
38542 height: rect.height + 20
\r
38544 }, seriesModel, cb);
\r
38552 /***/ function(module, exports, __webpack_require__) {
\r
38556 var layout = __webpack_require__(21);
\r
38557 var nest = __webpack_require__(234);
\r
38558 var zrUtil = __webpack_require__(3);
\r
38560 module.exports = function (ecModel, api) {
\r
38562 ecModel.eachSeriesByType('sankey', function (seriesModel) {
\r
38564 var nodeWidth = seriesModel.get('nodeWidth');
\r
38565 var nodeGap = seriesModel.get('nodeGap');
\r
38567 var layoutInfo = getViewRect(seriesModel, api);
\r
38569 seriesModel.layoutInfo = layoutInfo;
\r
38571 var width = layoutInfo.width;
\r
38572 var height = layoutInfo.height;
\r
38574 var graph = seriesModel.getGraph();
\r
38576 var nodes = graph.nodes;
\r
38577 var edges = graph.edges;
\r
38579 computeNodeValues(nodes);
\r
38581 var filteredNodes = nodes.filter(function (node) {
\r
38582 return node.getLayout().value === 0;
\r
38585 var iterations = filteredNodes.length !== 0
\r
38586 ? 0 : seriesModel.get('layoutIterations');
\r
38588 layoutSankey(nodes, edges, nodeWidth, nodeGap, width, height, iterations);
\r
38593 * get the layout position of the whole view.
\r
38595 function getViewRect(seriesModel, api) {
\r
38596 return layout.getLayoutRect(
\r
38597 seriesModel.getBoxLayoutParams(), {
\r
38598 width: api.getWidth(),
\r
38599 height: api.getHeight()
\r
38604 function layoutSankey(nodes, edges, nodeWidth, nodeGap, width, height, iterations) {
\r
38605 computeNodeBreadths(nodes, nodeWidth, width);
\r
38606 computeNodeDepths(nodes, edges, height, nodeGap, iterations);
\r
38607 computeEdgeDepths(nodes);
\r
38611 * compute the value of each node by summing the associated edge's value.
\r
38612 * @param {module:echarts/data/Graph~Node} nodes
\r
38614 function computeNodeValues(nodes) {
\r
38615 zrUtil.each(nodes, function (node) {
\r
38616 var value1 = sum(node.outEdges, getEdgeValue);
\r
38617 var value2 = sum(node.inEdges, getEdgeValue);
\r
38618 var value = Math.max(value1, value2);
\r
38619 node.setLayout({value: value}, true);
\r
38624 * compute the x-position for each node.
\r
38625 * @param {module:echarts/data/Graph~Node} nodes
\r
38626 * @param {number} nodeWidth
\r
38627 * @param {number} width
\r
38629 function computeNodeBreadths(nodes, nodeWidth, width) {
\r
38630 var remainNodes = nodes;
\r
38631 var nextNode = null;
\r
38635 while (remainNodes.length) {
\r
38638 for (var i = 0, len = remainNodes.length; i < len; i++) {
\r
38639 var node = remainNodes[i];
\r
38640 node.setLayout({x: x}, true);
\r
38641 node.setLayout({dx: nodeWidth}, true);
\r
38643 for (var j = 0, lenj = node.outEdges.length; j < lenj; j++) {
\r
38644 nextNode.push(node.outEdges[j].node2);
\r
38647 remainNodes = nextNode;
\r
38651 moveSinksRight(nodes, x);
\r
38652 kx = (width - nodeWidth) / (x - 1);
\r
38654 scaleNodeBreadths(nodes, kx);
\r
38658 * all the node without outEgdes are assigned maximum breadth and
\r
38659 * be aligned in the last column.
\r
38660 * @param {module:echarts/data/Graph~Node} nodes
\r
38661 * @param {number} x
\r
38663 function moveSinksRight(nodes, x) {
\r
38664 zrUtil.each(nodes, function (node) {
\r
38665 if(!node.outEdges.length) {
\r
38666 node.setLayout({x: x-1}, true);
\r
38672 * scale node x-position to the width.
\r
38673 * @param {module:echarts/data/Graph~Node} nodes
\r
38674 * @param {number} kx
\r
38676 function scaleNodeBreadths(nodes, kx) {
\r
38677 zrUtil.each(nodes, function(node) {
\r
38678 var nodeX = node.getLayout().x * kx;
\r
38679 node.setLayout({x: nodeX}, true);
\r
38684 * using Gauss-Seidel iterations method to compute the node depth(y-position).
\r
38685 * @param {module:echarts/data/Graph~Node} nodes
\r
38686 * @param {module:echarts/data/Graph~Edge} edges
\r
38687 * @param {number} height
\r
38688 * @param {numbber} nodeGap
\r
38689 * @param {number} iterations
\r
38691 function computeNodeDepths(nodes, edges, height, nodeGap, iterations) {
\r
38692 var nodesByBreadth = nest()
\r
38693 .key(function (d) {
\r
38694 return d.getLayout().x;
\r
38696 .sortKeys(ascending)
\r
38698 .map(function (d) {
\r
38702 initializeNodeDepth(nodes, nodesByBreadth, edges, height, nodeGap);
\r
38703 resolveCollisions(nodesByBreadth, nodeGap, height);
\r
38705 for (var alpha = 1; iterations > 0; iterations--) {
\r
38707 relaxRightToLeft(nodesByBreadth, alpha);
\r
38708 resolveCollisions(nodesByBreadth, nodeGap, height);
\r
38709 relaxLeftToRight(nodesByBreadth, alpha);
\r
38710 resolveCollisions(nodesByBreadth, nodeGap, height);
\r
38715 * compute the original y-position for each node.
\r
38716 * @param {module:echarts/data/Graph~Node} nodes
\r
38717 * @param {Array.<Array.<module:echarts/data/Graph~Node>>} nodesByBreadth
\r
38718 * @param {module:echarts/data/Graph~Edge} edges
\r
38719 * @param {number} height
\r
38720 * @param {number} nodeGap
\r
38722 function initializeNodeDepth(nodes, nodesByBreadth, edges, height, nodeGap) {
\r
38723 var kyArray = [];
\r
38724 zrUtil.each(nodesByBreadth, function (nodes) {
\r
38725 var n = nodes.length;
\r
38727 zrUtil.each(nodes, function (node) {
\r
38728 sum += node.getLayout().value;
\r
38730 var ky = (height - (n-1) * nodeGap) / sum;
\r
38731 kyArray.push(ky);
\r
38733 kyArray.sort(function (a, b) {
\r
38736 var ky0 = kyArray[0];
\r
38738 zrUtil.each(nodesByBreadth, function (nodes) {
\r
38739 zrUtil.each(nodes, function (node, i) {
\r
38740 node.setLayout({y: i}, true);
\r
38741 var nodeDy = node.getLayout().value * ky0;
\r
38742 node.setLayout({dy: nodeDy}, true);
\r
38746 zrUtil.each(edges, function (edge) {
\r
38747 var edgeDy = +edge.getValue() * ky0;
\r
38748 edge.setLayout({dy: edgeDy}, true);
\r
38753 * resolve the collision of initialized depth.
\r
38754 * @param {Array.<Array.<module:echarts/data/Graph~Node>>} nodesByBreadth
\r
38755 * @param {number} nodeGap
\r
38756 * @param {number} height
\r
38758 function resolveCollisions(nodesByBreadth, nodeGap, height) {
\r
38759 zrUtil.each(nodesByBreadth, function (nodes) {
\r
38763 var n = nodes.length;
\r
38766 nodes.sort(ascendingDepth);
\r
38768 for (i = 0; i < n; i++) {
\r
38770 dy = y0 - node.getLayout().y;
\r
38772 var nodeY = node.getLayout().y + dy;
\r
38773 node.setLayout({y: nodeY}, true);
\r
38775 y0 = node.getLayout().y + node.getLayout().dy + nodeGap;
\r
38778 // if the bottommost node goes outside the biunds, push it back up
\r
38779 dy = y0 - nodeGap - height;
\r
38781 var nodeY = node.getLayout().y -dy;
\r
38782 node.setLayout({y: nodeY}, true);
\r
38783 y0 = node.getLayout().y;
\r
38784 for (i = n - 2; i >= 0; --i) {
\r
38786 dy = node.getLayout().y + node.getLayout().dy + nodeGap - y0;
\r
38788 nodeY = node.getLayout().y - dy;
\r
38789 node.setLayout({y: nodeY}, true);
\r
38791 y0 = node.getLayout().y;
\r
38798 * change the y-position of the nodes, except most the right side nodes.
\r
38799 * @param {Array.<Array.<module:echarts/data/Graph~Node>>} nodesByBreadth
\r
38800 * @param {number} alpha
\r
38802 function relaxRightToLeft(nodesByBreadth, alpha) {
\r
38803 zrUtil.each(nodesByBreadth.slice().reverse(), function (nodes) {
\r
38804 zrUtil.each(nodes, function (node) {
\r
38805 if (node.outEdges.length) {
\r
38806 var y = sum(node.outEdges, weightedTarget) / sum(node.outEdges, getEdgeValue);
\r
38807 var nodeY = node.getLayout().y + (y - center(node)) * alpha;
\r
38808 node.setLayout({y: nodeY}, true);
\r
38814 function weightedTarget(edge) {
\r
38815 return center(edge.node2) * edge.getValue();
\r
38819 * change the y-position of the nodes, except most the left side nodes.
\r
38820 * @param {Array.<Array.<module:echarts/data/Graph~Node>>} nodesByBreadth
\r
38821 * @param {number} alpha
\r
38823 function relaxLeftToRight(nodesByBreadth, alpha) {
\r
38824 zrUtil.each(nodesByBreadth, function (nodes) {
\r
38825 zrUtil.each(nodes, function (node) {
\r
38826 if (node.inEdges.length) {
\r
38827 var y = sum(node.inEdges, weightedSource) / sum(node.inEdges, getEdgeValue);
\r
38828 var nodeY = node.getLayout().y + (y - center(node)) * alpha;
\r
38829 node.setLayout({y: nodeY}, true);
\r
38835 function weightedSource(edge) {
\r
38836 return center(edge.node1) * edge.getValue();
\r
38840 * compute the depth(y-position) of each edge.
\r
38841 * @param {module:echarts/data/Graph~Node} nodes
\r
38843 function computeEdgeDepths(nodes) {
\r
38844 zrUtil.each(nodes, function (node) {
\r
38845 node.outEdges.sort(ascendingTargetDepth);
\r
38846 node.inEdges.sort(ascendingSourceDepth);
\r
38848 zrUtil.each(nodes, function (node) {
\r
38851 zrUtil.each(node.outEdges, function (edge) {
\r
38852 edge.setLayout({sy: sy}, true);
\r
38853 sy += edge.getLayout().dy;
\r
38855 zrUtil.each(node.inEdges, function (edge) {
\r
38856 edge.setLayout({ty: ty}, true);
\r
38857 ty += edge.getLayout().dy;
\r
38862 function ascendingTargetDepth(a, b) {
\r
38863 return a.node2.getLayout().y - b.node2.getLayout().y;
\r
38866 function ascendingSourceDepth(a, b) {
\r
38867 return a.node1.getLayout().y - b.node1.getLayout().y;
\r
38870 function sum(array, f) {
\r
38872 var n = array.length;
\r
38875 if (arguments.length === 1) {
\r
38876 while (++i < n) {
\r
38884 while (++i < n) {
\r
38885 a = +f.call(array, array[i], i);
\r
38894 function center(node) {
\r
38895 return node.getLayout().y + node.getLayout().dy / 2;
\r
38898 function ascendingDepth(a, b) {
\r
38899 return a.getLayout().y - b.getLayout().y;
\r
38902 function ascending(a, b) {
\r
38903 return a < b ? -1 : a > b ? 1 : a == b ? 0 : NaN;
\r
38906 function getEdgeValue(edge) {
\r
38907 return edge.getValue();
\r
38914 /***/ function(module, exports, __webpack_require__) {
\r
38918 var zrUtil = __webpack_require__(3);
\r
38921 * nest helper used to group by the array.
\r
38922 * can specified the keys and sort the keys.
\r
38924 function nest() {
\r
38926 var keysFunction = [];
\r
38927 var sortKeysFunction = [];
\r
38930 * map an Array into the mapObject.
\r
38931 * @param {Array} array
\r
38932 * @param {number} depth
\r
38934 function map(array, depth) {
\r
38935 if (depth >= keysFunction.length) {
\r
38939 var n = array.length;
\r
38940 var keyFunction = keysFunction[depth++];
\r
38941 var mapObject = {};
\r
38942 var valuesByKey = {};
\r
38944 while (++i < n) {
\r
38945 var keyValue = keyFunction(array[i]);
\r
38946 var values = valuesByKey[keyValue];
\r
38949 values.push(array[i]);
\r
38952 valuesByKey[keyValue] = [array[i]];
\r
38956 zrUtil.each(valuesByKey, function (value, key) {
\r
38957 mapObject[key] = map(value, depth);
\r
38960 return mapObject;
\r
38964 * transform the Map Object to multidimensional Array
\r
38965 * @param {Object} map
\r
38966 * @param {number} depth
\r
38968 function entriesMap(mapObject, depth) {
\r
38969 if (depth >= keysFunction.length) {
\r
38970 return mapObject;
\r
38973 var sortKeyFunction = sortKeysFunction[depth++];
\r
38975 zrUtil.each(mapObject, function (value, key) {
\r
38977 key: key, values: entriesMap(value, depth)
\r
38981 if (sortKeyFunction) {
\r
38982 return array.sort(function (a, b) {
\r
38983 return sortKeyFunction(a.key, b.key);
\r
38993 * specified the key to groupby the arrays.
\r
38994 * users can specified one more keys.
\r
38995 * @param {Function} d
\r
38997 key: function (d) {
\r
38998 keysFunction.push(d);
\r
39003 * specified the comparator to sort the keys
\r
39004 * @param {Function} order
\r
39006 sortKeys: function (order) {
\r
39007 sortKeysFunction[keysFunction.length - 1] = order;
\r
39012 * the array to be grouped by.
\r
39013 * @param {Array} array
\r
39015 entries: function (array) {
\r
39016 return entriesMap(map(array, 0), 0);
\r
39020 module.exports = nest;
\r
39025 /***/ function(module, exports, __webpack_require__) {
\r
39029 var VisualMapping = __webpack_require__(187);
\r
39031 module.exports = function (ecModel, payload) {
\r
39032 ecModel.eachSeriesByType('sankey', function (seriesModel) {
\r
39033 var graph = seriesModel.getGraph();
\r
39034 var nodes = graph.nodes;
\r
39036 nodes.sort(function (a, b) {
\r
39037 return a.getLayout().value - b.getLayout().value;
\r
39040 var minValue = nodes[0].getLayout().value;
\r
39041 var maxValue = nodes[nodes.length - 1].getLayout().value;
\r
39043 nodes.forEach(function (node) {
\r
39044 var mapping = new VisualMapping({
\r
39046 mappingMethod: 'linear',
\r
39047 dataExtent: [minValue, maxValue],
\r
39048 visual: seriesModel.get('color')
\r
39051 var mapValueToColor = mapping.mapValueToVisual(node.getLayout().value);
\r
39052 node.setVisual('color', mapValueToColor);
\r
39061 /***/ function(module, exports, __webpack_require__) {
\r
39065 var echarts = __webpack_require__(1);
\r
39067 __webpack_require__(237);
\r
39068 __webpack_require__(240);
\r
39070 echarts.registerVisualCoding('chart', __webpack_require__(241));
\r
39071 echarts.registerLayout(__webpack_require__(242));
\r
39077 /***/ function(module, exports, __webpack_require__) {
\r
39082 var zrUtil = __webpack_require__(3);
\r
39083 var SeriesModel = __webpack_require__(27);
\r
39084 var whiskerBoxCommon = __webpack_require__(238);
\r
39086 var BoxplotSeries = SeriesModel.extend({
\r
39088 type: 'series.boxplot',
\r
39090 dependencies: ['xAxis', 'yAxis', 'grid'],
\r
39093 // box width represents group size, so dimension should have 'size'.
\r
39096 * @see <https://en.wikipedia.org/wiki/Box_plot>
\r
39097 * The meanings of 'min' and 'max' depend on user,
\r
39098 * and echarts do not need to know it.
\r
39101 valueDimensions: ['min', 'Q1', 'median', 'Q3', 'max'],
\r
39104 * @type {Array.<string>}
\r
39107 dimensions: null,
\r
39113 zlevel: 0, // 一级层叠
\r
39115 coordinateSystem: 'cartesian2d',
\r
39116 legendHoverLink: true,
\r
39118 hoverAnimation: true,
\r
39123 layout: null, // 'horizontal' or 'vertical'
\r
39124 boxWidth: [7, 50], // [min, max] can be percent of band width.
\r
39134 shadowOffsetX: 2,
\r
39135 shadowOffsetY: 2,
\r
39136 shadowColor: 'rgba(0,0,0,0.4)'
\r
39140 animationEasing: 'elasticOut',
\r
39141 animationDuration: 800
\r
39145 zrUtil.mixin(BoxplotSeries, whiskerBoxCommon.seriesModelMixin, true);
\r
39147 module.exports = BoxplotSeries;
\r
39153 /***/ function(module, exports, __webpack_require__) {
\r
39158 var List = __webpack_require__(94);
\r
39159 var completeDimensions = __webpack_require__(96);
\r
39160 var WhiskerBoxDraw = __webpack_require__(239);
\r
39161 var zrUtil = __webpack_require__(3);
\r
39163 function getItemValue(item) {
\r
39164 return item.value == null ? item : item.value;
\r
39167 var seriesModelMixin = {
\r
39173 _baseAxisDim: null,
\r
39178 getInitialData: function (option, ecModel) {
\r
39179 // When both types of xAxis and yAxis are 'value', layout is
\r
39180 // needed to be specified by user. Otherwise, layout can be
\r
39181 // judged by which axis is category.
\r
39185 var xAxisModel = ecModel.getComponent('xAxis', this.get('xAxisIndex'));
\r
39186 var yAxisModel = ecModel.getComponent('yAxis', this.get('yAxisIndex'));
\r
39187 var xAxisType = xAxisModel.get('type');
\r
39188 var yAxisType = yAxisModel.get('type');
\r
39194 if (xAxisType === 'category') {
\r
39195 option.layout = 'horizontal';
\r
39196 categories = xAxisModel.getCategories();
\r
39197 addOrdinal = true;
\r
39199 else if (yAxisType === 'category') {
\r
39200 option.layout = 'vertical';
\r
39201 categories = yAxisModel.getCategories();
\r
39202 addOrdinal = true;
\r
39205 option.layout = option.layout || 'horizontal';
\r
39208 this._baseAxisDim = option.layout === 'horizontal' ? 'x' : 'y';
\r
39210 var data = option.data;
\r
39211 var dimensions = this.dimensions = ['base'].concat(this.valueDimensions);
\r
39212 completeDimensions(dimensions, data);
\r
39214 var list = new List(dimensions, this);
\r
39215 list.initData(data, categories ? categories.slice() : null, function (dataItem, dimName, idx, dimIdx) {
\r
39216 var value = getItemValue(dataItem);
\r
39217 return addOrdinal ? (dimName === 'base' ? idx : value[dimIdx - 1]) : value[dimIdx];
\r
39225 * @param {string} axisDim 'x' or 'y'
\r
39226 * @return {Array.<string>} dimensions on the axis.
\r
39228 coordDimToDataDim: function (axisDim) {
\r
39229 var dims = this.valueDimensions.slice();
\r
39230 var baseDim = ['base'];
\r
39232 horizontal: {x: baseDim, y: dims},
\r
39233 vertical: {x: dims, y: baseDim}
\r
39235 return map[this.get('layout')][axisDim];
\r
39240 * @param {string|number} dataDim
\r
39241 * @return {string} coord dimension
\r
39243 dataDimToCoordDim: function (dataDim) {
\r
39246 zrUtil.each(['x', 'y'], function (coordDim, index) {
\r
39247 var dataDims = this.coordDimToDataDim(coordDim);
\r
39248 if (zrUtil.indexOf(dataDims, dataDim) >= 0) {
\r
39257 * If horizontal, base axis is x, otherwise y.
\r
39260 getBaseAxis: function () {
\r
39261 var dim = this._baseAxisDim;
\r
39262 return this.ecModel.getComponent(dim + 'Axis', this.get(dim + 'AxisIndex')).axis;
\r
39266 var viewMixin = {
\r
39268 init: function () {
\r
39272 * @type {module:echarts/chart/helper/WhiskerBoxDraw}
\r
39274 var whiskerBoxDraw = this._whiskerBoxDraw = new WhiskerBoxDraw(
\r
39275 this.getStyleUpdater()
\r
39277 this.group.add(whiskerBoxDraw.group);
\r
39280 render: function (seriesModel, ecModel, api) {
\r
39281 this._whiskerBoxDraw.updateData(seriesModel.getData());
\r
39284 remove: function (ecModel) {
\r
39285 this._whiskerBoxDraw.remove();
\r
39289 module.exports = {
\r
39290 seriesModelMixin: seriesModelMixin,
\r
39291 viewMixin: viewMixin
\r
39297 /***/ function(module, exports, __webpack_require__) {
\r
39300 * @module echarts/chart/helper/Symbol
\r
39304 var zrUtil = __webpack_require__(3);
\r
39305 var graphic = __webpack_require__(42);
\r
39306 var Path = __webpack_require__(44);
\r
39308 var WhiskerPath = Path.extend({
\r
39310 type: 'whiskerInBox',
\r
39314 buildPath: function (ctx, shape) {
\r
39315 for (var i in shape) {
\r
39316 if (i.indexOf('ends') === 0) {
\r
39317 var pts = shape[i];
\r
39318 ctx.moveTo(pts[0][0], pts[0][1]);
\r
39319 ctx.lineTo(pts[1][0], pts[1][1]);
\r
39327 * @alias {module:echarts/chart/helper/WhiskerBox}
\r
39328 * @param {module:echarts/data/List} data
\r
39329 * @param {number} idx
\r
39330 * @param {Function} styleUpdater
\r
39331 * @param {boolean} isInit
\r
39332 * @extends {module:zrender/graphic/Group}
\r
39334 function WhiskerBox(data, idx, styleUpdater, isInit) {
\r
39335 graphic.Group.call(this);
\r
39347 this.whiskerIndex;
\r
39350 * @type {Function}
\r
39352 this.styleUpdater = styleUpdater;
\r
39354 this._createContent(data, idx, isInit);
\r
39356 this.updateData(data, idx, isInit);
\r
39359 * Last series model.
\r
39360 * @type {module:echarts/model/Series}
\r
39362 this._seriesModel;
\r
39365 var whiskerBoxProto = WhiskerBox.prototype;
\r
39367 whiskerBoxProto._createContent = function (data, idx, isInit) {
\r
39368 var itemLayout = data.getItemLayout(idx);
\r
39369 var constDim = itemLayout.chartLayout === 'horizontal' ? 1 : 0;
\r
39372 // Whisker element.
\r
39373 this.add(new graphic.Polygon({
\r
39376 ? transInit(itemLayout.bodyEnds, constDim, itemLayout)
\r
39377 : itemLayout.bodyEnds
\r
39379 style: {strokeNoScale: true},
\r
39382 this.bodyIndex = count++;
\r
39385 var whiskerEnds = zrUtil.map(itemLayout.whiskerEnds, function (ends) {
\r
39386 return isInit ? transInit(ends, constDim, itemLayout) : ends;
\r
39388 this.add(new WhiskerPath({
\r
39389 shape: makeWhiskerEndsShape(whiskerEnds),
\r
39390 style: {strokeNoScale: true},
\r
39393 this.whiskerIndex = count++;
\r
39396 function transInit(points, dim, itemLayout) {
\r
39397 return zrUtil.map(points, function (point) {
\r
39398 point = point.slice();
\r
39399 point[dim] = itemLayout.initBaseline;
\r
39404 function makeWhiskerEndsShape(whiskerEnds) {
\r
39405 // zr animation only support 2-dim array.
\r
39407 zrUtil.each(whiskerEnds, function (ends, i) {
\r
39408 shape['ends' + i] = ends;
\r
39414 * Update symbol properties
\r
39415 * @param {module:echarts/data/List} data
\r
39416 * @param {number} idx
\r
39418 whiskerBoxProto.updateData = function (data, idx, isInit) {
\r
39419 var seriesModel = this._seriesModel = data.hostModel;
\r
39420 var itemLayout = data.getItemLayout(idx);
\r
39421 var updateMethod = graphic[isInit ? 'initProps' : 'updateProps'];
\r
39422 // this.childAt(this.bodyIndex).stopAnimation(true);
\r
39423 // this.childAt(this.whiskerIndex).stopAnimation(true);
\r
39425 this.childAt(this.bodyIndex),
\r
39426 {shape: {points: itemLayout.bodyEnds}},
\r
39430 this.childAt(this.whiskerIndex),
\r
39431 {shape: makeWhiskerEndsShape(itemLayout.whiskerEnds)},
\r
39435 this.styleUpdater.call(null, this, data, idx);
\r
39438 zrUtil.inherits(WhiskerBox, graphic.Group);
\r
39443 * @alias module:echarts/chart/helper/WhiskerBoxDraw
\r
39445 function WhiskerBoxDraw(styleUpdater) {
\r
39446 this.group = new graphic.Group();
\r
39447 this.styleUpdater = styleUpdater;
\r
39450 var whiskerBoxDrawProto = WhiskerBoxDraw.prototype;
\r
39453 * Update symbols draw by new data
\r
39454 * @param {module:echarts/data/List} data
\r
39456 whiskerBoxDrawProto.updateData = function (data) {
\r
39457 var group = this.group;
\r
39458 var oldData = this._data;
\r
39459 var styleUpdater = this.styleUpdater;
\r
39461 data.diff(oldData)
\r
39462 .add(function (newIdx) {
\r
39463 if (data.hasValue(newIdx)) {
\r
39464 var symbolEl = new WhiskerBox(data, newIdx, styleUpdater, true);
\r
39465 data.setItemGraphicEl(newIdx, symbolEl);
\r
39466 group.add(symbolEl);
\r
39469 .update(function (newIdx, oldIdx) {
\r
39470 var symbolEl = oldData.getItemGraphicEl(oldIdx);
\r
39473 if (!data.hasValue(newIdx)) {
\r
39474 group.remove(symbolEl);
\r
39479 symbolEl = new WhiskerBox(data, newIdx, styleUpdater);
\r
39482 symbolEl.updateData(data, newIdx);
\r
39486 group.add(symbolEl);
\r
39488 data.setItemGraphicEl(newIdx, symbolEl);
\r
39490 .remove(function (oldIdx) {
\r
39491 var el = oldData.getItemGraphicEl(oldIdx);
\r
39492 el && group.remove(el);
\r
39496 this._data = data;
\r
39500 * Remove symbols.
\r
39501 * @param {module:echarts/data/List} data
\r
39503 whiskerBoxDrawProto.remove = function () {
\r
39504 var group = this.group;
\r
39505 var data = this._data;
\r
39506 this._data = null;
\r
39507 data && data.eachItemGraphicEl(function (el) {
\r
39508 el && group.remove(el);
\r
39512 module.exports = WhiskerBoxDraw;
\r
39517 /***/ function(module, exports, __webpack_require__) {
\r
39522 var zrUtil = __webpack_require__(3);
\r
39523 var ChartView = __webpack_require__(41);
\r
39524 var graphic = __webpack_require__(42);
\r
39525 var whiskerBoxCommon = __webpack_require__(238);
\r
39527 var BoxplotView = ChartView.extend({
\r
39531 getStyleUpdater: function () {
\r
39532 return updateStyle;
\r
39536 zrUtil.mixin(BoxplotView, whiskerBoxCommon.viewMixin, true);
\r
39538 // Update common properties
\r
39539 var normalStyleAccessPath = ['itemStyle', 'normal'];
\r
39540 var emphasisStyleAccessPath = ['itemStyle', 'emphasis'];
\r
39542 function updateStyle(itemGroup, data, idx) {
\r
39543 var itemModel = data.getItemModel(idx);
\r
39544 var normalItemStyleModel = itemModel.getModel(normalStyleAccessPath);
\r
39545 var borderColor = data.getItemVisual(idx, 'color');
\r
39547 // Exclude borderColor.
\r
39548 var itemStyle = normalItemStyleModel.getItemStyle(['borderColor']);
\r
39550 var whiskerEl = itemGroup.childAt(itemGroup.whiskerIndex);
\r
39551 whiskerEl.style.set(itemStyle);
\r
39552 whiskerEl.style.stroke = borderColor;
\r
39553 whiskerEl.dirty();
\r
39555 var bodyEl = itemGroup.childAt(itemGroup.bodyIndex);
\r
39556 bodyEl.style.set(itemStyle);
\r
39557 bodyEl.style.stroke = borderColor;
\r
39560 var hoverStyle = itemModel.getModel(emphasisStyleAccessPath).getItemStyle();
\r
39561 graphic.setHoverStyle(itemGroup, hoverStyle);
\r
39564 module.exports = BoxplotView;
\r
39570 /***/ function(module, exports) {
\r
39574 var borderColorQuery = ['itemStyle', 'normal', 'borderColor'];
\r
39576 module.exports = function (ecModel, api) {
\r
39578 var globalColors = ecModel.get('color');
\r
39580 ecModel.eachRawSeriesByType('boxplot', function (seriesModel) {
\r
39582 var defaulColor = globalColors[seriesModel.seriesIndex % globalColors.length];
\r
39583 var data = seriesModel.getData();
\r
39586 legendSymbol: 'roundRect',
\r
39587 // Use name 'color' but not 'borderColor' for legend usage and
\r
39588 // visual coding from other component like dataRange.
\r
39589 color: seriesModel.get(borderColorQuery) || defaulColor
\r
39592 // Only visible series has each data be visual encoded
\r
39593 if (!ecModel.isSeriesFiltered(seriesModel)) {
\r
39594 data.each(function (idx) {
\r
39595 var itemModel = data.getItemModel(idx);
\r
39596 data.setItemVisual(
\r
39598 {color: itemModel.get(borderColorQuery, true)}
\r
39609 /***/ function(module, exports, __webpack_require__) {
\r
39613 var zrUtil = __webpack_require__(3);
\r
39614 var numberUtil = __webpack_require__(7);
\r
39615 var parsePercent = numberUtil.parsePercent;
\r
39616 var each = zrUtil.each;
\r
39618 module.exports = function (ecModel, api) {
\r
39620 var groupResult = groupSeriesByAxis(ecModel);
\r
39622 each(groupResult, function (groupItem) {
\r
39623 var seriesModels = groupItem.seriesModels;
\r
39625 if (!seriesModels.length) {
\r
39629 calculateBase(groupItem);
\r
39631 each(seriesModels, function (seriesModel, idx) {
\r
39632 layoutSingleSeries(
\r
39634 groupItem.boxOffsetList[idx],
\r
39635 groupItem.boxWidthList[idx]
\r
39642 * Group series by axis.
\r
39644 function groupSeriesByAxis(ecModel) {
\r
39646 var axisList = [];
\r
39648 ecModel.eachSeriesByType('boxplot', function (seriesModel) {
\r
39649 var baseAxis = seriesModel.getBaseAxis();
\r
39650 var idx = zrUtil.indexOf(axisList, baseAxis);
\r
39653 idx = axisList.length;
\r
39654 axisList[idx] = baseAxis;
\r
39655 result[idx] = {axis: baseAxis, seriesModels: []};
\r
39658 result[idx].seriesModels.push(seriesModel);
\r
39665 * Calculate offset and box width for each series.
\r
39667 function calculateBase(groupItem) {
\r
39669 var baseAxis = groupItem.axis;
\r
39670 var seriesModels = groupItem.seriesModels;
\r
39671 var seriesCount = seriesModels.length;
\r
39673 var boxWidthList = groupItem.boxWidthList = [];
\r
39674 var boxOffsetList = groupItem.boxOffsetList = [];
\r
39675 var boundList = [];
\r
39678 if (baseAxis.type === 'category') {
\r
39679 bandWidth = baseAxis.getBandWidth();
\r
39682 var maxDataCount = 0;
\r
39683 each(seriesModels, function (seriesModel) {
\r
39684 maxDataCount = Math.max(maxDataCount, seriesModel.getData().count());
\r
39686 extent = baseAxis.getExtent(),
\r
39687 Math.abs(extent[1] - extent[0]) / maxDataCount;
\r
39690 each(seriesModels, function (seriesModel) {
\r
39691 var boxWidthBound = seriesModel.get('boxWidth');
\r
39692 if (!zrUtil.isArray(boxWidthBound)) {
\r
39693 boxWidthBound = [boxWidthBound, boxWidthBound];
\r
39696 parsePercent(boxWidthBound[0], bandWidth) || 0,
\r
39697 parsePercent(boxWidthBound[1], bandWidth) || 0
\r
39701 var availableWidth = bandWidth * 0.8 - 2;
\r
39702 var boxGap = availableWidth / seriesCount * 0.3;
\r
39703 var boxWidth = (availableWidth - boxGap * (seriesCount - 1)) / seriesCount;
\r
39704 var base = boxWidth / 2 - availableWidth / 2;
\r
39706 each(seriesModels, function (seriesModel, idx) {
\r
39707 boxOffsetList.push(base);
\r
39708 base += boxGap + boxWidth;
\r
39710 boxWidthList.push(
\r
39711 Math.min(Math.max(boxWidth, boundList[idx][0]), boundList[idx][1])
\r
39717 * Calculate points location for each series.
\r
39719 function layoutSingleSeries(seriesModel, offset, boxWidth) {
\r
39720 var coordSys = seriesModel.coordinateSystem;
\r
39721 var data = seriesModel.getData();
\r
39722 var dimensions = seriesModel.dimensions;
\r
39723 var chartLayout = seriesModel.get('layout');
\r
39724 var halfWidth = boxWidth / 2;
\r
39726 data.each(dimensions, function () {
\r
39727 var args = arguments;
\r
39728 var dimLen = dimensions.length;
\r
39729 var axisDimVal = args[0];
\r
39730 var idx = args[dimLen];
\r
39731 var variableDim = chartLayout === 'horizontal' ? 0 : 1;
\r
39732 var constDim = 1 - variableDim;
\r
39734 var median = getPoint(args[3]);
\r
39735 var end1 = getPoint(args[1]);
\r
39736 var end5 = getPoint(args[5]);
\r
39737 var whiskerEnds = [
\r
39738 [end1, getPoint(args[2])],
\r
39739 [end5, getPoint(args[4])]
\r
39741 layEndLine(end1);
\r
39742 layEndLine(end5);
\r
39743 layEndLine(median);
\r
39745 var bodyEnds = [];
\r
39746 addBodyEnd(whiskerEnds[0][1], 0);
\r
39747 addBodyEnd(whiskerEnds[1][1], 1);
\r
39749 data.setItemLayout(idx, {
\r
39750 chartLayout: chartLayout,
\r
39751 initBaseline: median[constDim],
\r
39753 bodyEnds: bodyEnds,
\r
39754 whiskerEnds: whiskerEnds
\r
39757 function getPoint(val) {
\r
39759 p[variableDim] = axisDimVal;
\r
39760 p[constDim] = val;
\r
39762 if (isNaN(axisDimVal) || isNaN(val)) {
\r
39763 point = [NaN, NaN];
\r
39766 point = coordSys.dataToPoint(p);
\r
39767 point[variableDim] += offset;
\r
39772 function addBodyEnd(point, start) {
\r
39773 var point1 = point.slice();
\r
39774 var point2 = point.slice();
\r
39775 point1[variableDim] += halfWidth;
\r
39776 point2[variableDim] -= halfWidth;
\r
39778 ? bodyEnds.push(point1, point2)
\r
39779 : bodyEnds.push(point2, point1);
\r
39782 function layEndLine(endCenter) {
\r
39783 var line = [endCenter.slice(), endCenter.slice()];
\r
39784 line[0][variableDim] -= halfWidth;
\r
39785 line[1][variableDim] += halfWidth;
\r
39786 whiskerEnds.push(line);
\r
39795 /***/ function(module, exports, __webpack_require__) {
\r
39799 var echarts = __webpack_require__(1);
\r
39801 __webpack_require__(244);
\r
39802 __webpack_require__(245);
\r
39804 echarts.registerPreprocessor(
\r
39805 __webpack_require__(246)
\r
39808 echarts.registerVisualCoding('chart', __webpack_require__(247));
\r
39809 echarts.registerLayout(__webpack_require__(248));
\r
39815 /***/ function(module, exports, __webpack_require__) {
\r
39820 var zrUtil = __webpack_require__(3);
\r
39821 var SeriesModel = __webpack_require__(27);
\r
39822 var whiskerBoxCommon = __webpack_require__(238);
\r
39823 var formatUtil = __webpack_require__(6);
\r
39824 var encodeHTML = formatUtil.encodeHTML;
\r
39825 var addCommas = formatUtil.addCommas;
\r
39827 var CandlestickSeries = SeriesModel.extend({
\r
39829 type: 'series.candlestick',
\r
39831 dependencies: ['xAxis', 'yAxis', 'grid'],
\r
39836 valueDimensions: ['open', 'close', 'lowest', 'highest'],
\r
39839 * @type {Array.<string>}
\r
39842 dimensions: null,
\r
39848 zlevel: 0, // 一级层叠
\r
39850 coordinateSystem: 'cartesian2d',
\r
39851 legendHoverLink: true,
\r
39853 hoverAnimation: true,
\r
39858 layout: null, // 'horizontal' or 'vertical'
\r
39862 color: '#c23531', // 阳线 positive
\r
39863 color0: '#314656', // 阴线 negative '#c23531', '#314656'
\r
39866 // ec2中使用的是lineStyle.color 和 lineStyle.color0
\r
39867 borderColor: '#c23531',
\r
39868 borderColor0: '#314656'
\r
39875 animationUpdate: false,
\r
39876 animationEasing: 'linear',
\r
39877 animationDuration: 300
\r
39881 * Get dimension for shadow in dataZoom
\r
39882 * @return {string} dimension name
\r
39884 getShadowDim: function () {
\r
39891 formatTooltip: function (dataIndex, mutipleSeries) {
\r
39892 // It rearly use mutiple candlestick series in one cartesian,
\r
39893 // so only consider one series in this default tooltip.
\r
39894 var valueHTMLArr = zrUtil.map(this.valueDimensions, function (dim) {
\r
39895 return dim + ': ' + addCommas(this._data.get(dim, dataIndex));
\r
39898 return encodeHTML(this.name) + '<br />' + valueHTMLArr.join('<br />');
\r
39903 zrUtil.mixin(CandlestickSeries, whiskerBoxCommon.seriesModelMixin, true);
\r
39905 module.exports = CandlestickSeries;
\r
39911 /***/ function(module, exports, __webpack_require__) {
\r
39916 var zrUtil = __webpack_require__(3);
\r
39917 var ChartView = __webpack_require__(41);
\r
39918 var graphic = __webpack_require__(42);
\r
39919 var whiskerBoxCommon = __webpack_require__(238);
\r
39921 var CandlestickView = ChartView.extend({
\r
39923 type: 'candlestick',
\r
39925 getStyleUpdater: function () {
\r
39926 return updateStyle;
\r
39931 zrUtil.mixin(CandlestickView, whiskerBoxCommon.viewMixin, true);
\r
39933 // Update common properties
\r
39934 var normalStyleAccessPath = ['itemStyle', 'normal'];
\r
39935 var emphasisStyleAccessPath = ['itemStyle', 'emphasis'];
\r
39937 function updateStyle(itemGroup, data, idx) {
\r
39938 var itemModel = data.getItemModel(idx);
\r
39939 var normalItemStyleModel = itemModel.getModel(normalStyleAccessPath);
\r
39940 var color = data.getItemVisual(idx, 'color');
\r
39941 var borderColor = data.getItemVisual(idx, 'borderColor');
\r
39943 // Color must be excluded.
\r
39944 // Because symbol provide setColor individually to set fill and stroke
\r
39945 var itemStyle = normalItemStyleModel.getItemStyle(
\r
39946 ['color', 'color0', 'borderColor', 'borderColor0']
\r
39949 var whiskerEl = itemGroup.childAt(itemGroup.whiskerIndex);
\r
39950 whiskerEl.style.set(itemStyle);
\r
39951 whiskerEl.style.stroke = borderColor;
\r
39952 whiskerEl.dirty();
\r
39954 var bodyEl = itemGroup.childAt(itemGroup.bodyIndex);
\r
39955 bodyEl.style.set(itemStyle);
\r
39956 bodyEl.style.fill = color;
\r
39957 bodyEl.style.stroke = borderColor;
\r
39960 var hoverStyle = itemModel.getModel(emphasisStyleAccessPath).getItemStyle();
\r
39961 graphic.setHoverStyle(itemGroup, hoverStyle);
\r
39965 module.exports = CandlestickView;
\r
39971 /***/ function(module, exports, __webpack_require__) {
\r
39975 var zrUtil = __webpack_require__(3);
\r
39977 module.exports = function (option) {
\r
39978 if (!option || !zrUtil.isArray(option.series)) {
\r
39982 // Translate 'k' to 'candlestick'.
\r
39983 zrUtil.each(option.series, function (seriesItem) {
\r
39984 if (zrUtil.isObject(seriesItem) && seriesItem.type === 'k') {
\r
39985 seriesItem.type = 'candlestick';
\r
39994 /***/ function(module, exports) {
\r
39998 var positiveBorderColorQuery = ['itemStyle', 'normal', 'borderColor'];
\r
39999 var negativeBorderColorQuery = ['itemStyle', 'normal', 'borderColor0'];
\r
40000 var positiveColorQuery = ['itemStyle', 'normal', 'color'];
\r
40001 var negativeColorQuery = ['itemStyle', 'normal', 'color0'];
\r
40003 module.exports = function (ecModel, api) {
\r
40005 ecModel.eachRawSeriesByType('candlestick', function (seriesModel) {
\r
40007 var data = seriesModel.getData();
\r
40010 legendSymbol: 'roundRect'
\r
40013 // Only visible series has each data be visual encoded
\r
40014 if (!ecModel.isSeriesFiltered(seriesModel)) {
\r
40015 data.each(function (idx) {
\r
40016 var itemModel = data.getItemModel(idx);
\r
40017 var sign = data.getItemLayout(idx).sign;
\r
40019 data.setItemVisual(
\r
40022 color: itemModel.get(
\r
40023 sign > 0 ? positiveColorQuery : negativeColorQuery
\r
40025 borderColor: itemModel.get(
\r
40026 sign > 0 ? positiveBorderColorQuery : negativeBorderColorQuery
\r
40039 /***/ function(module, exports) {
\r
40043 var CANDLE_MIN_WIDTH = 2;
\r
40044 var CANDLE_MIN_NICE_WIDTH = 5;
\r
40047 module.exports = function (ecModel, api) {
\r
40049 ecModel.eachSeriesByType('candlestick', function (seriesModel) {
\r
40051 var coordSys = seriesModel.coordinateSystem;
\r
40052 var data = seriesModel.getData();
\r
40053 var dimensions = seriesModel.dimensions;
\r
40054 var chartLayout = seriesModel.get('layout');
\r
40056 var candleWidth = calculateCandleWidth(seriesModel, data);
\r
40058 data.each(dimensions, function () {
\r
40059 var args = arguments;
\r
40060 var dimLen = dimensions.length;
\r
40061 var axisDimVal = args[0];
\r
40062 var idx = args[dimLen];
\r
40063 var variableDim = chartLayout === 'horizontal' ? 0 : 1;
\r
40064 var constDim = 1 - variableDim;
\r
40066 var openVal = args[1];
\r
40067 var closeVal = args[2];
\r
40068 var lowestVal = args[3];
\r
40069 var highestVal = args[4];
\r
40071 var ocLow = Math.min(openVal, closeVal);
\r
40072 var ocHigh = Math.max(openVal, closeVal);
\r
40074 var ocLowPoint = getPoint(ocLow);
\r
40075 var ocHighPoint = getPoint(ocHigh);
\r
40076 var lowestPoint = getPoint(lowestVal);
\r
40077 var highestPoint = getPoint(highestVal);
\r
40079 var whiskerEnds = [
\r
40080 [highestPoint, ocHighPoint],
\r
40081 [lowestPoint, ocLowPoint]
\r
40084 var bodyEnds = [];
\r
40085 addBodyEnd(ocHighPoint, 0);
\r
40086 addBodyEnd(ocLowPoint, 1);
\r
40088 data.setItemLayout(idx, {
\r
40089 chartLayout: chartLayout,
\r
40090 sign: openVal > closeVal ? -1 : openVal < closeVal ? 1 : 0,
\r
40091 initBaseline: openVal > closeVal
\r
40092 ? ocHighPoint[constDim] : ocLowPoint[constDim], // open point.
\r
40093 bodyEnds: bodyEnds,
\r
40094 whiskerEnds: whiskerEnds
\r
40097 function getPoint(val) {
\r
40099 p[variableDim] = axisDimVal;
\r
40100 p[constDim] = val;
\r
40101 return (isNaN(axisDimVal) || isNaN(val))
\r
40103 : coordSys.dataToPoint(p);
\r
40106 function addBodyEnd(point, start) {
\r
40107 var point1 = point.slice();
\r
40108 var point2 = point.slice();
\r
40109 point1[variableDim] += candleWidth / 2;
\r
40110 point2[variableDim] -= candleWidth / 2;
\r
40112 ? bodyEnds.push(point1, point2)
\r
40113 : bodyEnds.push(point2, point1);
\r
40120 function calculateCandleWidth(seriesModel, data) {
\r
40121 var baseAxis = seriesModel.getBaseAxis();
\r
40124 var bandWidth = baseAxis.type === 'category'
\r
40125 ? baseAxis.getBandWidth()
\r
40127 extent = baseAxis.getExtent(),
\r
40128 Math.abs(extent[1] - extent[0]) / data.count()
\r
40131 // Half band width is perfect when space is enouph, otherwise
\r
40132 // try not to be smaller than CANDLE_MIN_NICE_WIDTH (and only
\r
40133 // gap is compressed), otherwise ensure not to be smaller than
\r
40134 // CANDLE_MIN_WIDTH in spite of overlap.
\r
40136 return bandWidth / 2 - 2 > CANDLE_MIN_NICE_WIDTH // "- 2" is minus border width
\r
40137 ? bandWidth / 2 - 2
\r
40138 : bandWidth - CANDLE_MIN_NICE_WIDTH > GPA_MIN
\r
40139 ? CANDLE_MIN_NICE_WIDTH
\r
40140 : Math.max(bandWidth - GPA_MIN, CANDLE_MIN_WIDTH);
\r
40147 /***/ function(module, exports, __webpack_require__) {
\r
40151 var zrUtil = __webpack_require__(3);
\r
40152 var echarts = __webpack_require__(1);
\r
40154 __webpack_require__(250);
\r
40155 __webpack_require__(251);
\r
40157 echarts.registerVisualCoding('chart', zrUtil.curry(
\r
40158 __webpack_require__(103), 'effectScatter', 'circle', null
\r
40160 echarts.registerLayout(zrUtil.curry(
\r
40161 __webpack_require__(104), 'effectScatter'
\r
40167 /***/ function(module, exports, __webpack_require__) {
\r
40172 var createListFromArray = __webpack_require__(93);
\r
40173 var SeriesModel = __webpack_require__(27);
\r
40175 module.exports = SeriesModel.extend({
\r
40177 type: 'series.effectScatter',
\r
40179 dependencies: ['grid', 'polar'],
\r
40181 getInitialData: function (option, ecModel) {
\r
40182 var list = createListFromArray(option.data, this, ecModel);
\r
40187 coordinateSystem: 'cartesian2d',
\r
40190 legendHoverLink: true,
\r
40192 effectType: 'ripple',
\r
40194 // When to show the effect, option: 'render'|'emphasis'
\r
40195 showEffectOn: 'render',
\r
40197 // Ripple effect config
\r
40200 // Scale of ripple
\r
40202 // Brush type can be fill or stroke
\r
40203 brushType: 'fill'
\r
40206 // Cartesian coordinate system
\r
40210 // Polar coordinate system
\r
40213 // Geo coordinate system
\r
40216 // symbol: null, // 图形类型
\r
40217 symbolSize: 10 // 图形大小,半宽(半径)参数,当图形为方向或菱形则总宽度为symbolSize * 2
\r
40218 // symbolRotate: null, // 图形旋转控制
\r
40221 // Available when large is true
\r
40222 // largeThreshold: 2000,
\r
40235 /***/ function(module, exports, __webpack_require__) {
\r
40239 var SymbolDraw = __webpack_require__(98);
\r
40240 var EffectSymbol = __webpack_require__(252);
\r
40242 __webpack_require__(1).extendChartView({
\r
40244 type: 'effectScatter',
\r
40246 init: function () {
\r
40247 this._symbolDraw = new SymbolDraw(EffectSymbol);
\r
40250 render: function (seriesModel, ecModel, api) {
\r
40251 var data = seriesModel.getData();
\r
40252 var effectSymbolDraw = this._symbolDraw;
\r
40253 effectSymbolDraw.updateData(data);
\r
40254 this.group.add(effectSymbolDraw.group);
\r
40257 updateLayout: function () {
\r
40258 this._symbolDraw.updateLayout();
\r
40261 remove: function (ecModel, api) {
\r
40262 this._symbolDraw && this._symbolDraw.remove(api);
\r
40269 /***/ function(module, exports, __webpack_require__) {
\r
40272 * Symbol with ripple effect
\r
40273 * @module echarts/chart/helper/EffectSymbol
\r
40277 var zrUtil = __webpack_require__(3);
\r
40278 var symbolUtil = __webpack_require__(100);
\r
40279 var graphic = __webpack_require__(42);
\r
40280 var numberUtil = __webpack_require__(7);
\r
40281 var Symbol = __webpack_require__(99);
\r
40282 var Group = graphic.Group;
\r
40284 var EFFECT_RIPPLE_NUMBER = 3;
\r
40286 function normalizeSymbolSize(symbolSize) {
\r
40287 if (!zrUtil.isArray(symbolSize)) {
\r
40288 symbolSize = [+symbolSize, +symbolSize];
\r
40290 return symbolSize;
\r
40294 * @param {module:echarts/data/List} data
\r
40295 * @param {number} idx
\r
40296 * @extends {module:zrender/graphic/Group}
\r
40298 function EffectSymbol(data, idx) {
\r
40299 Group.call(this);
\r
40301 var symbol = new Symbol(data, idx);
\r
40302 var rippleGroup = new Group();
\r
40303 this.add(symbol);
\r
40304 this.add(rippleGroup);
\r
40306 rippleGroup.beforeUpdate = function () {
\r
40307 this.attr(symbol.getScale());
\r
40309 this.updateData(data, idx);
\r
40312 var effectSymbolProto = EffectSymbol.prototype;
\r
40314 effectSymbolProto.stopEffectAnimation = function () {
\r
40315 this.childAt(1).removeAll();
\r
40318 effectSymbolProto.startEffectAnimation = function (
\r
40319 period, brushType, rippleScale, effectOffset, z, zlevel
\r
40321 var symbolType = this._symbolType;
\r
40322 var color = this._color;
\r
40324 var rippleGroup = this.childAt(1);
\r
40326 for (var i = 0; i < EFFECT_RIPPLE_NUMBER; i++) {
\r
40327 var ripplePath = symbolUtil.createSymbol(
\r
40328 symbolType, -0.5, -0.5, 1, 1, color
\r
40330 ripplePath.attr({
\r
40332 stroke: brushType === 'stroke' ? color : null,
\r
40333 fill: brushType === 'fill' ? color : null,
\r
40334 strokeNoScale: true
\r
40343 var delay = -i / EFFECT_RIPPLE_NUMBER * period + effectOffset;
\r
40344 // TODO Configurable period
\r
40345 ripplePath.animate('', true)
\r
40347 scale: [rippleScale, rippleScale]
\r
40351 ripplePath.animateStyle(true)
\r
40358 rippleGroup.add(ripplePath);
\r
40363 * Highlight symbol
\r
40365 effectSymbolProto.highlight = function () {
\r
40366 this.trigger('emphasis');
\r
40370 * Downplay symbol
\r
40372 effectSymbolProto.downplay = function () {
\r
40373 this.trigger('normal');
\r
40377 * Update symbol properties
\r
40378 * @param {module:echarts/data/List} data
\r
40379 * @param {number} idx
\r
40381 effectSymbolProto.updateData = function (data, idx) {
\r
40382 var seriesModel = data.hostModel;
\r
40384 this.childAt(0).updateData(data, idx);
\r
40386 var rippleGroup = this.childAt(1);
\r
40387 var itemModel = data.getItemModel(idx);
\r
40388 var symbolType = data.getItemVisual(idx, 'symbol');
\r
40389 var symbolSize = normalizeSymbolSize(data.getItemVisual(idx, 'symbolSize'));
\r
40390 var color = data.getItemVisual(idx, 'color');
\r
40392 rippleGroup.attr('scale', symbolSize);
\r
40394 rippleGroup.traverse(function (ripplePath) {
\r
40395 ripplePath.attr({
\r
40400 var symbolOffset = itemModel.getShallow('symbolOffset');
\r
40401 if (symbolOffset) {
\r
40402 var pos = rippleGroup.position;
\r
40403 pos[0] = numberUtil.parsePercent(symbolOffset[0], symbolSize[0]);
\r
40404 pos[1] = numberUtil.parsePercent(symbolOffset[1], symbolSize[1]);
\r
40407 this._symbolType = symbolType;
\r
40408 this._color = color;
\r
40410 var showEffectOn = seriesModel.get('showEffectOn');
\r
40411 var rippleScale = itemModel.get('rippleEffect.scale');
\r
40412 var brushType = itemModel.get('rippleEffect.brushType');
\r
40413 var effectPeriod = itemModel.get('rippleEffect.period') * 1000;
\r
40414 var effectOffset = idx / data.count();
\r
40415 var z = itemModel.getShallow('z') || 0;
\r
40416 var zlevel = itemModel.getShallow('zlevel') || 0;
\r
40418 this.stopEffectAnimation();
\r
40419 if (showEffectOn === 'render') {
\r
40420 this.startEffectAnimation(
\r
40421 effectPeriod, brushType, rippleScale, effectOffset, z, zlevel
\r
40424 var symbol = this.childAt(0);
\r
40425 function onEmphasis() {
\r
40426 symbol.trigger('emphasis');
\r
40427 if (showEffectOn !== 'render') {
\r
40428 this.startEffectAnimation(
\r
40429 effectPeriod, brushType, rippleScale, effectOffset, z, zlevel
\r
40433 function onNormal() {
\r
40434 symbol.trigger('normal');
\r
40435 if (showEffectOn !== 'render') {
\r
40436 this.stopEffectAnimation();
\r
40439 this.on('mouseover', onEmphasis, this)
\r
40440 .on('mouseout', onNormal, this)
\r
40441 .on('emphasis', onEmphasis, this)
\r
40442 .on('normal', onNormal, this);
\r
40445 effectSymbolProto.fadeOut = function (cb) {
\r
40449 zrUtil.inherits(EffectSymbol, Group);
\r
40451 module.exports = EffectSymbol;
\r
40456 /***/ function(module, exports, __webpack_require__) {
\r
40460 __webpack_require__(254);
\r
40461 __webpack_require__(255);
\r
40463 var zrUtil = __webpack_require__(3);
\r
40464 var echarts = __webpack_require__(1);
\r
40465 echarts.registerLayout(
\r
40466 __webpack_require__(257)
\r
40469 echarts.registerVisualCoding(
\r
40470 'chart', zrUtil.curry(__webpack_require__(88), 'lines', 'lineStyle')
\r
40476 /***/ function(module, exports, __webpack_require__) {
\r
40481 var SeriesModel = __webpack_require__(27);
\r
40482 var List = __webpack_require__(94);
\r
40483 var zrUtil = __webpack_require__(3);
\r
40484 var CoordinateSystem = __webpack_require__(25);
\r
40486 module.exports = SeriesModel.extend({
\r
40488 type: 'series.lines',
\r
40490 dependencies: ['grid', 'polar'],
\r
40492 getInitialData: function (option, ecModel) {
\r
40493 var fromDataArr = [];
\r
40494 var toDataArr = [];
\r
40495 var lineDataArr = [];
\r
40496 zrUtil.each(option.data, function (opt) {
\r
40497 fromDataArr.push(opt[0]);
\r
40498 toDataArr.push(opt[1]);
\r
40499 lineDataArr.push(zrUtil.extend(
\r
40500 zrUtil.extend({}, zrUtil.isArray(opt[0]) ? null : opt[0]),
\r
40501 zrUtil.isArray(opt[1]) ? null : opt[1]
\r
40505 // var coordSys = option.coordinateSystem;
\r
40506 // if (coordSys !== 'cartesian2d' && coordSys !== 'geo') {
\r
40507 // throw new Error('Coordinate system can only be cartesian2d or geo in lines');
\r
40510 // var dimensions = coordSys === 'geo' ? ['lng', 'lat'] : ['x', 'y'];
\r
40511 var coordSys = CoordinateSystem.get(option.coordinateSystem);
\r
40513 throw new Error('Invalid coordinate system');
\r
40515 var dimensions = coordSys.dimensions;
\r
40517 var fromData = new List(dimensions, this);
\r
40518 var toData = new List(dimensions, this);
\r
40519 var lineData = new List(['value'], this);
\r
40521 function geoCoordGetter(item, dim, dataIndex, dimIndex) {
\r
40522 return item.coord && item.coord[dimIndex];
\r
40525 fromData.initData(fromDataArr, null, geoCoordGetter);
\r
40526 toData.initData(toDataArr, null, geoCoordGetter);
\r
40527 lineData.initData(lineDataArr);
\r
40529 this.fromData = fromData;
\r
40530 this.toData = toData;
\r
40535 formatTooltip: function (dataIndex) {
\r
40536 var fromName = this.fromData.getName(dataIndex);
\r
40537 var toName = this.toData.getName(dataIndex);
\r
40538 return fromName + ' > ' + toName;
\r
40542 coordinateSystem: 'geo',
\r
40545 legendHoverLink: true,
\r
40547 hoverAnimation: true,
\r
40548 // Cartesian coordinate system
\r
40552 // Geo coordinate system
\r
40556 // symbolSize: 10,
\r
40557 // symbolRotate: null,
\r
40562 symbol: 'circle',
\r
40564 // Length of trail, 0 - 1
\r
40566 // Same with lineStyle.normal.color
\r
40571 // Available when large is true
\r
40572 largeThreshold: 2000,
\r
40579 // formatter: 标签文本格式器,同Tooltip.formatter,不支持异步回调
\r
40597 /***/ function(module, exports, __webpack_require__) {
\r
40601 var LineDraw = __webpack_require__(194);
\r
40602 var EffectLine = __webpack_require__(256);
\r
40603 var Line = __webpack_require__(195);
\r
40605 __webpack_require__(1).extendChartView({
\r
40609 init: function () {},
\r
40611 render: function (seriesModel, ecModel, api) {
\r
40612 var data = seriesModel.getData();
\r
40613 var lineDraw = this._lineDraw;
\r
40615 var hasEffect = seriesModel.get('effect.show');
\r
40616 if (hasEffect !== this._hasEffet) {
\r
40618 lineDraw.remove();
\r
40620 lineDraw = this._lineDraw = new LineDraw(
\r
40621 hasEffect ? EffectLine : Line
\r
40623 this._hasEffet = hasEffect;
\r
40626 var zlevel = seriesModel.get('zlevel');
\r
40627 var trailLength = seriesModel.get('effect.trailLength');
\r
40629 var zr = api.getZr();
\r
40630 // Avoid the drag cause ghost shadow
\r
40631 // FIXME Better way ?
\r
40632 zr.painter.getLayer(zlevel).clear(true);
\r
40633 // Config layer with motion blur
\r
40634 if (this._lastZlevel != null) {
\r
40635 zr.configLayer(this._lastZlevel, {
\r
40636 motionBlur: false
\r
40639 if (hasEffect && trailLength) {
\r
40640 zr.configLayer(zlevel, {
\r
40641 motionBlur: true,
\r
40642 lastFrameAlpha: Math.max(Math.min(trailLength / 10 + 0.9, 1), 0)
\r
40646 this.group.add(lineDraw.group);
\r
40648 lineDraw.updateData(data);
\r
40650 this._lastZlevel = zlevel;
\r
40653 updateLayout: function (seriesModel, ecModel, api) {
\r
40654 this._lineDraw.updateLayout();
\r
40655 // Not use motion when dragging or zooming
\r
40656 var zr = api.getZr();
\r
40657 zr.painter.getLayer(this._lastZlevel).clear(true);
\r
40660 remove: function (ecModel, api) {
\r
40661 this._lineDraw && this._lineDraw.remove(api, true);
\r
40668 /***/ function(module, exports, __webpack_require__) {
\r
40671 * @module echarts/chart/helper/EffectLine
\r
40675 var graphic = __webpack_require__(42);
\r
40676 var Line = __webpack_require__(195);
\r
40677 var zrUtil = __webpack_require__(3);
\r
40678 var symbolUtil = __webpack_require__(100);
\r
40680 var curveUtil = __webpack_require__(49);
\r
40684 * @extends {module:zrender/graphic/Group}
\r
40685 * @alias {module:echarts/chart/helper/Line}
\r
40687 function EffectLine(lineData, fromData, toData, idx) {
\r
40688 graphic.Group.call(this);
\r
40690 var line = new Line(lineData, fromData, toData, idx);
\r
40693 this._updateEffectSymbol(lineData, idx);
\r
40696 var effectLineProto = EffectLine.prototype;
\r
40698 function setAnimationPoints(symbol, points) {
\r
40699 symbol.__p1 = points[0];
\r
40700 symbol.__p2 = points[1];
\r
40701 symbol.__cp1 = points[2] || [
\r
40702 (points[0][0] + points[1][0]) / 2,
\r
40703 (points[0][1] + points[1][1]) / 2
\r
40707 function updateSymbolPosition() {
\r
40708 var p1 = this.__p1;
\r
40709 var p2 = this.__p2;
\r
40710 var cp1 = this.__cp1;
\r
40711 var t = this.__t;
\r
40712 var pos = this.position;
\r
40713 var quadraticAt = curveUtil.quadraticAt;
\r
40714 var quadraticDerivativeAt = curveUtil.quadraticDerivativeAt;
\r
40715 pos[0] = quadraticAt(p1[0], cp1[0], p2[0], t);
\r
40716 pos[1] = quadraticAt(p1[1], cp1[1], p2[1], t);
\r
40719 var tx = quadraticDerivativeAt(p1[0], cp1[0], p2[0], t);
\r
40720 var ty = quadraticDerivativeAt(p1[1], cp1[1], p2[1], t);
\r
40722 this.rotation = -Math.atan2(ty, tx) - Math.PI / 2;
\r
40724 this.ignore = false;
\r
40727 effectLineProto._updateEffectSymbol = function (lineData, idx) {
\r
40728 var itemModel = lineData.getItemModel(idx);
\r
40729 var effectModel = itemModel.getModel('effect');
\r
40730 var size = effectModel.get('symbolSize');
\r
40731 var symbolType = effectModel.get('symbol');
\r
40732 if (!zrUtil.isArray(size)) {
\r
40733 size = [size, size];
\r
40735 var color = effectModel.get('color') || lineData.getItemVisual(idx, 'color');
\r
40736 var symbol = this.childAt(1);
\r
40737 var period = effectModel.get('period') * 1000;
\r
40738 if (this._symbolType !== symbolType || period !== this._period) {
\r
40739 symbol = symbolUtil.createSymbol(
\r
40740 symbolType, -0.5, -0.5, 1, 1, color
\r
40742 symbol.ignore = true;
\r
40744 this._symbolType = symbolType;
\r
40745 this._period = period;
\r
40747 this.add(symbol);
\r
40750 symbol.animate('', true)
\r
40754 .delay(idx / lineData.count() * period / 2)
\r
40755 .during(zrUtil.bind(updateSymbolPosition, symbol))
\r
40758 // Shadow color is same with color in default
\r
40759 symbol.setStyle('shadowColor', color);
\r
40760 symbol.setStyle(effectModel.getItemStyle(['color']));
\r
40762 symbol.attr('scale', size);
\r
40763 var points = lineData.getItemLayout(idx);
\r
40764 setAnimationPoints(symbol, points);
\r
40766 symbol.setColor(color);
\r
40767 symbol.attr('scale', size);
\r
40770 effectLineProto.updateData = function (lineData, fromData, toData, idx) {
\r
40771 this.childAt(0).updateData(lineData, fromData, toData, idx);
\r
40772 this._updateEffectSymbol(lineData, idx);
\r
40775 effectLineProto.updateLayout = function (lineData, fromData, toData, idx) {
\r
40776 this.childAt(0).updateLayout(lineData, fromData, toData, idx);
\r
40777 var symbol = this.childAt(1);
\r
40778 var points = lineData.getItemLayout(idx);
\r
40779 setAnimationPoints(symbol, points);
\r
40782 zrUtil.inherits(EffectLine, graphic.Group);
\r
40784 module.exports = EffectLine;
\r
40789 /***/ function(module, exports) {
\r
40793 module.exports = function (ecModel) {
\r
40794 ecModel.eachSeriesByType('lines', function (seriesModel) {
\r
40795 var coordSys = seriesModel.coordinateSystem;
\r
40796 var fromData = seriesModel.fromData;
\r
40797 var toData = seriesModel.toData;
\r
40798 var lineData = seriesModel.getData();
\r
40800 var dims = coordSys.dimensions;
\r
40801 fromData.each(dims, function (x, y, idx) {
\r
40802 fromData.setItemLayout(idx, coordSys.dataToPoint([x, y]));
\r
40804 toData.each(dims, function (x, y, idx) {
\r
40805 toData.setItemLayout(idx, coordSys.dataToPoint([x, y]));
\r
40807 lineData.each(function (idx) {
\r
40808 var p1 = fromData.getItemLayout(idx);
\r
40809 var p2 = toData.getItemLayout(idx);
\r
40810 var curveness = lineData.getItemModel(idx).get('lineStyle.normal.curveness');
\r
40812 if (curveness > 0) {
\r
40814 (p1[0] + p2[0]) / 2 - (p1[1] - p2[1]) * curveness,
\r
40815 (p1[1] + p2[1]) / 2 - (p2[0] - p1[0]) * curveness
\r
40818 lineData.setItemLayout(idx, [p1, p2, cp1]);
\r
40826 /***/ function(module, exports, __webpack_require__) {
\r
40830 __webpack_require__(259);
\r
40831 __webpack_require__(260);
\r
40836 /***/ function(module, exports, __webpack_require__) {
\r
40840 var SeriesModel = __webpack_require__(27);
\r
40841 var createListFromArray = __webpack_require__(93);
\r
40843 module.exports = SeriesModel.extend({
\r
40844 type: 'series.heatmap',
\r
40846 getInitialData: function (option, ecModel) {
\r
40847 return createListFromArray(option.data, this, ecModel);
\r
40852 // Cartesian2D or geo
\r
40853 coordinateSystem: 'cartesian2d',
\r
40859 // Cartesian coordinate system
\r
40863 // Geo coordinate system
\r
40879 /***/ function(module, exports, __webpack_require__) {
\r
40883 var graphic = __webpack_require__(42);
\r
40884 var HeatmapLayer = __webpack_require__(261);
\r
40885 var zrUtil = __webpack_require__(3);
\r
40887 function getIsInPiecewiseRange(dataExtent, pieceList, selected) {
\r
40888 var dataSpan = dataExtent[1] - dataExtent[0];
\r
40889 pieceList = zrUtil.map(pieceList, function (piece) {
\r
40892 (piece.interval[0] - dataExtent[0]) / dataSpan,
\r
40893 (piece.interval[1] - dataExtent[0]) / dataSpan
\r
40897 var len = pieceList.length;
\r
40898 var lastIndex = 0;
\r
40899 return function (val) {
\r
40900 // Try to find in the location of the last found
\r
40901 for (var i = lastIndex; i < len; i++) {
\r
40902 var interval = pieceList[i].interval;
\r
40903 if (interval[0] <= val && val <= interval[1]) {
\r
40908 if (i === len) { // Not found, back interation
\r
40909 for (var i = lastIndex - 1; i >= 0; i--) {
\r
40910 var interval = pieceList[i].interval;
\r
40911 if (interval[0] <= val && val <= interval[1]) {
\r
40917 return i >= 0 && i < len && selected[i];
\r
40921 function getIsInContinuousRange(dataExtent, range) {
\r
40922 var dataSpan = dataExtent[1] - dataExtent[0];
\r
40924 (range[0] - dataExtent[0]) / dataSpan,
\r
40925 (range[1] - dataExtent[0]) / dataSpan
\r
40927 return function (val) {
\r
40928 return val >= range[0] && val <= range[1];
\r
40932 function isGeoCoordSys(coordSys) {
\r
40933 var dimensions = coordSys.dimensions;
\r
40934 // Not use coorSys.type === 'geo' because coordSys maybe extended
\r
40935 return dimensions[0] === 'lng' && dimensions[1] === 'lat';
\r
40938 module.exports = __webpack_require__(1).extendChartView({
\r
40942 render: function (seriesModel, ecModel, api) {
\r
40943 var visualMapOfThisSeries;
\r
40944 ecModel.eachComponent('visualMap', function (visualMap) {
\r
40945 visualMap.eachTargetSeries(function (targetSeries) {
\r
40946 if (targetSeries === seriesModel) {
\r
40947 visualMapOfThisSeries = visualMap;
\r
40952 if (!visualMapOfThisSeries) {
\r
40953 throw new Error('Heatmap must use with visualMap');
\r
40956 this.group.removeAll();
\r
40957 var coordSys = seriesModel.coordinateSystem;
\r
40958 if (coordSys.type === 'cartesian2d') {
\r
40959 this._renderOnCartesian(coordSys, seriesModel, api);
\r
40961 else if (isGeoCoordSys(coordSys)) {
\r
40962 this._renderOnGeo(
\r
40963 coordSys, seriesModel, visualMapOfThisSeries, api
\r
40968 _renderOnCartesian: function (cartesian, seriesModel, api) {
\r
40969 var xAxis = cartesian.getAxis('x');
\r
40970 var yAxis = cartesian.getAxis('y');
\r
40971 var group = this.group;
\r
40973 if (!(xAxis.type === 'category' && yAxis.type === 'category')) {
\r
40974 throw new Error('Heatmap on cartesian must have two category axes');
\r
40976 if (!(xAxis.onBand && yAxis.onBand)) {
\r
40977 throw new Error('Heatmap on cartesian must have two axes with boundaryGap true');
\r
40979 var width = xAxis.getBandWidth();
\r
40980 var height = yAxis.getBandWidth();
\r
40982 var data = seriesModel.getData();
\r
40983 data.each(['x', 'y', 'z'], function (x, y, z, idx) {
\r
40984 var itemModel = data.getItemModel(idx);
\r
40985 var point = cartesian.dataToPoint([x, y]);
\r
40986 // Ignore empty data
\r
40990 var rect = new graphic.Rect({
\r
40992 x: point[0] - width / 2,
\r
40993 y: point[1] - height / 2,
\r
40998 fill: data.getItemVisual(idx, 'color')
\r
41001 var style = itemModel.getModel('itemStyle.normal').getItemStyle(['color']);
\r
41002 var hoverStl = itemModel.getModel('itemStyle.emphasis').getItemStyle();
\r
41003 var labelModel = itemModel.getModel('label.normal');
\r
41004 var hoverLabelModel = itemModel.getModel('label.emphasis');
\r
41006 var rawValue = seriesModel.getRawValue(idx);
\r
41007 var defaultText = '-';
\r
41008 if (rawValue && rawValue[2] != null) {
\r
41009 defaultText = rawValue[2];
\r
41011 if (labelModel.get('show')) {
\r
41012 graphic.setText(style, labelModel);
\r
41013 style.text = seriesModel.getFormattedLabel(idx, 'normal') || defaultText;
\r
41015 if (hoverLabelModel.get('show')) {
\r
41016 graphic.setText(hoverStl, hoverLabelModel);
\r
41017 hoverStl.text = seriesModel.getFormattedLabel(idx, 'emphasis') || defaultText;
\r
41020 rect.setStyle(style);
\r
41022 graphic.setHoverStyle(rect, hoverStl);
\r
41025 data.setItemGraphicEl(idx, rect);
\r
41029 _renderOnGeo: function (geo, seriesModel, visualMapModel, api) {
\r
41030 var inRangeVisuals = visualMapModel.targetVisuals.inRange;
\r
41031 var outOfRangeVisuals = visualMapModel.targetVisuals.outOfRange;
\r
41032 // if (!visualMapping) {
\r
41033 // throw new Error('Data range must have color visuals');
\r
41036 var data = seriesModel.getData();
\r
41037 var hmLayer = this._hmLayer || (this._hmLayer || new HeatmapLayer());
\r
41038 hmLayer.blurSize = seriesModel.get('blurSize');
\r
41039 hmLayer.pointSize = seriesModel.get('pointSize');
\r
41040 hmLayer.minOpacity = seriesModel.get('minOpacity');
\r
41041 hmLayer.maxOpacity = seriesModel.get('maxOpacity');
\r
41043 var rect = geo.getViewRect().clone();
\r
41044 var roamTransform = geo.getRoamTransform();
\r
41045 rect.applyTransform(roamTransform);
\r
41047 // Clamp on viewport
\r
41048 var x = Math.max(rect.x, 0);
\r
41049 var y = Math.max(rect.y, 0);
\r
41050 var x2 = Math.min(rect.width + rect.x, api.getWidth());
\r
41051 var y2 = Math.min(rect.height + rect.y, api.getHeight());
\r
41052 var width = x2 - x;
\r
41053 var height = y2 - y;
\r
41055 var points = data.mapArray(['lng', 'lat', 'value'], function (lng, lat, value) {
\r
41056 var pt = geo.dataToPoint([lng, lat]);
\r
41063 var dataExtent = visualMapModel.getExtent();
\r
41064 var isInRange = visualMapModel.type === 'visualMap.continuous'
\r
41065 ? getIsInContinuousRange(dataExtent, visualMapModel.option.range)
\r
41066 : getIsInPiecewiseRange(
\r
41067 dataExtent, visualMapModel.getPieceList(), visualMapModel.option.selected
\r
41071 points, width, height,
\r
41072 inRangeVisuals.color.getNormalizer(),
\r
41074 inRange: inRangeVisuals.color.getColorMapper(),
\r
41075 outOfRange: outOfRangeVisuals.color.getColorMapper()
\r
41079 var img = new graphic.Image({
\r
41085 image: hmLayer.canvas
\r
41089 this.group.add(img);
\r
41096 /***/ function(module, exports, __webpack_require__) {
\r
41099 * @file defines echarts Heatmap Chart
\r
41100 * @author Ovilia (me@zhangwenli.com)
\r
41101 * Inspired by https://github.com/mourner/simpleheat
\r
41107 var GRADIENT_LEVELS = 256;
\r
41108 var zrUtil = __webpack_require__(3);
\r
41115 function Heatmap() {
\r
41116 var canvas = zrUtil.createCanvas();
\r
41117 this.canvas = canvas;
\r
41119 this.blurSize = 30;
\r
41120 this.pointSize = 20;
\r
41122 this.maxOpacity = 1;
\r
41123 this.minOpacity = 0;
\r
41125 this._gradientPixels = {};
\r
41128 Heatmap.prototype = {
\r
41130 * Renders Heatmap and returns the rendered canvas
\r
41131 * @param {Array} data array of data, each has x, y, value
\r
41132 * @param {number} width canvas width
\r
41133 * @param {number} height canvas height
\r
41135 update: function(data, width, height, normalize, colorFunc, isInRange) {
\r
41136 var brush = this._getBrush();
\r
41137 var gradientInRange = this._getGradient(data, colorFunc, 'inRange');
\r
41138 var gradientOutOfRange = this._getGradient(data, colorFunc, 'outOfRange');
\r
41139 var r = this.pointSize + this.blurSize;
\r
41141 var canvas = this.canvas;
\r
41142 var ctx = canvas.getContext('2d');
\r
41143 var len = data.length;
\r
41144 canvas.width = width;
\r
41145 canvas.height = height;
\r
41146 for (var i = 0; i < len; ++i) {
\r
41150 var value = p[2];
\r
41152 // calculate alpha using value
\r
41153 var alpha = normalize(value);
\r
41155 // draw with the circle brush with alpha
\r
41156 ctx.globalAlpha = alpha;
\r
41157 ctx.drawImage(brush, x - r, y - r);
\r
41160 // colorize the canvas using alpha value and set with gradient
\r
41161 var imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
\r
41162 var pixels = imageData.data;
\r
41164 var pixelLen = pixels.length;
\r
41165 var minOpacity = this.minOpacity;
\r
41166 var maxOpacity = this.maxOpacity;
\r
41167 var diffOpacity = maxOpacity - minOpacity;
\r
41169 while(offset < pixelLen) {
\r
41170 var alpha = pixels[offset + 3] / 256;
\r
41171 var gradientOffset = Math.floor(alpha * (GRADIENT_LEVELS - 1)) * 4;
\r
41172 // Simple optimize to ignore the empty data
\r
41174 var gradient = isInRange(alpha) ? gradientInRange : gradientOutOfRange;
\r
41175 // Any alpha > 0 will be mapped to [minOpacity, maxOpacity]
\r
41176 alpha > 0 && (alpha = alpha * diffOpacity + minOpacity);
\r
41177 pixels[offset++] = gradient[gradientOffset];
\r
41178 pixels[offset++] = gradient[gradientOffset + 1];
\r
41179 pixels[offset++] = gradient[gradientOffset + 2];
\r
41180 pixels[offset++] = gradient[gradientOffset + 3] * alpha * 256;
\r
41186 ctx.putImageData(imageData, 0, 0);
\r
41192 * get canvas of a black circle brush used for canvas to draw later
\r
41194 * @returns {Object} circle brush canvas
\r
41196 _getBrush: function() {
\r
41197 var brushCanvas = this._brushCanvas || (this._brushCanvas = zrUtil.createCanvas());
\r
41198 // set brush size
\r
41199 var r = this.pointSize + this.blurSize;
\r
41201 brushCanvas.width = d;
\r
41202 brushCanvas.height = d;
\r
41204 var ctx = brushCanvas.getContext('2d');
\r
41205 ctx.clearRect(0, 0, d, d);
\r
41207 // in order to render shadow without the distinct circle,
\r
41208 // draw the distinct circle in an invisible place,
\r
41209 // and use shadowOffset to draw shadow in the center of the canvas
\r
41210 ctx.shadowOffsetX = d;
\r
41211 ctx.shadowBlur = this.blurSize;
\r
41212 // draw the shadow in black, and use alpha and shadow blur to generate
\r
41213 // color in color map
\r
41214 ctx.shadowColor = '#000';
\r
41216 // draw circle in the left to the canvas
\r
41218 ctx.arc(-r, r, this.pointSize, 0, Math.PI * 2, true);
\r
41221 return brushCanvas;
\r
41225 * get gradient color map
\r
41228 _getGradient: function (data, colorFunc, state) {
\r
41229 var gradientPixels = this._gradientPixels;
\r
41230 var pixelsSingleState = gradientPixels[state] || (gradientPixels[state] = new Uint8ClampedArray(256 * 4));
\r
41233 for (var i = 0; i < 256; i++) {
\r
41234 colorFunc[state](i / 255, true, color);
\r
41235 pixelsSingleState[off++] = color[0];
\r
41236 pixelsSingleState[off++] = color[1];
\r
41237 pixelsSingleState[off++] = color[2];
\r
41238 pixelsSingleState[off++] = color[3];
\r
41240 return pixelsSingleState;
\r
41244 module.exports = Heatmap;
\r
41250 /***/ function(module, exports, __webpack_require__) {
\r
41253 * Legend component entry file8
\r
41257 __webpack_require__(263);
\r
41258 __webpack_require__(264);
\r
41259 __webpack_require__(265);
\r
41261 var echarts = __webpack_require__(1);
\r
41263 echarts.registerProcessor('filter', __webpack_require__(267));
\r
41268 /***/ function(module, exports, __webpack_require__) {
\r
41273 var zrUtil = __webpack_require__(3);
\r
41274 var Model = __webpack_require__(8);
\r
41276 var LegendModel = __webpack_require__(1).extendComponentModel({
\r
41280 dependencies: ['series'],
\r
41287 init: function (option, parentModel, ecModel) {
\r
41288 this.mergeDefaultAndTheme(option, ecModel);
\r
41290 option.selected = option.selected || {};
\r
41292 this._updateData(ecModel);
\r
41294 var legendData = this._data;
\r
41295 // If has any selected in option.selected
\r
41296 var selectedMap = this.option.selected;
\r
41297 // If selectedMode is single, try to select one
\r
41298 if (legendData[0] && this.get('selectedMode') === 'single') {
\r
41299 var hasSelected = false;
\r
41300 for (var name in selectedMap) {
\r
41301 if (selectedMap[name]) {
\r
41302 this.select(name);
\r
41303 hasSelected = true;
\r
41306 // Try select the first if selectedMode is single
\r
41307 !hasSelected && this.select(legendData[0].get('name'));
\r
41311 mergeOption: function (option) {
\r
41312 LegendModel.superCall(this, 'mergeOption', option);
\r
41314 this._updateData(this.ecModel);
\r
41317 _updateData: function (ecModel) {
\r
41318 var legendData = zrUtil.map(this.get('data') || [], function (dataItem) {
\r
41319 if (typeof dataItem === 'string') {
\r
41324 return new Model(dataItem, this, this.ecModel);
\r
41326 this._data = legendData;
\r
41328 var availableNames = zrUtil.map(ecModel.getSeries(), function (series) {
\r
41329 return series.name;
\r
41331 ecModel.eachSeries(function (seriesModel) {
\r
41332 if (seriesModel.legendDataProvider) {
\r
41333 var data = seriesModel.legendDataProvider();
\r
41334 availableNames = availableNames.concat(data.mapArray(data.getName));
\r
41338 * @type {Array.<string>}
\r
41341 this._availableNames = availableNames;
\r
41345 * @return {Array.<module:echarts/model/Model>}
\r
41347 getData: function () {
\r
41348 return this._data;
\r
41352 * @param {string} name
\r
41354 select: function (name) {
\r
41355 var selected = this.option.selected;
\r
41356 var selectedMode = this.get('selectedMode');
\r
41357 if (selectedMode === 'single') {
\r
41358 var data = this._data;
\r
41359 zrUtil.each(data, function (dataItem) {
\r
41360 selected[dataItem.get('name')] = false;
\r
41363 selected[name] = true;
\r
41367 * @param {string} name
\r
41369 unSelect: function (name) {
\r
41370 if (this.get('selectedMode') !== 'single') {
\r
41371 this.option.selected[name] = false;
\r
41376 * @param {string} name
\r
41378 toggleSelected: function (name) {
\r
41379 var selected = this.option.selected;
\r
41380 // Default is true
\r
41381 if (!(name in selected)) {
\r
41382 selected[name] = true;
\r
41384 this[selected[name] ? 'unSelect' : 'select'](name);
\r
41388 * @param {string} name
\r
41390 isSelected: function (name) {
\r
41391 var selected = this.option.selected;
\r
41392 return !((name in selected) && !selected[name])
\r
41393 && zrUtil.indexOf(this._availableNames, name) >= 0;
\r
41403 // 布局方式,默认为水平布局,可选为:
\r
41404 // 'horizontal' | 'vertical'
\r
41405 orient: 'horizontal',
\r
41408 // right: 'center',
\r
41411 // bottom: 'top',
\r
41414 // 'auto' | 'left' | 'right'
\r
41415 // 默认为 'auto', 根据 x 的位置判断是左对齐还是右对齐
\r
41418 backgroundColor: 'rgba(0,0,0,0)',
\r
41420 borderColor: '#ccc',
\r
41421 // 图例边框线宽,单位px,默认为0(无边框)
\r
41423 // 图例内边距,单位px,默认各方向内边距为5,
\r
41424 // 接受数组分别设定上右下左边距,同css
\r
41426 // 各个item之间的间隔,单位px,默认为10,
\r
41427 // 横向布局时为水平间隔,纵向布局时为纵向间隔
\r
41437 // formatter: '',
\r
41439 selectedMode: true
\r
41440 // 配置默认选中状态,可配合LEGEND.SELECTED事件做动态数据载入
\r
41441 // selected: null,
\r
41442 // 图例内容(详见legend.data,数组中每一项代表一个item
\r
41447 module.exports = LegendModel;
\r
41452 /***/ function(module, exports, __webpack_require__) {
\r
41455 * @file Legend action
\r
41459 var echarts = __webpack_require__(1);
\r
41460 var zrUtil = __webpack_require__(3);
\r
41462 function legendSelectActionHandler(methodName, payload, ecModel) {
\r
41463 var selectedMap = {};
\r
41464 var isToggleSelect = methodName === 'toggleSelected';
\r
41466 // Update all legend components
\r
41467 ecModel.eachComponent('legend', function (legendModel) {
\r
41468 if (isToggleSelect && isSelected != null) {
\r
41469 // Force other legend has same selected status
\r
41470 // Or the first is toggled to true and other are toggled to false
\r
41471 // In the case one legend has some item unSelected in option. And if other legend
\r
41472 // doesn't has the item, they will assume it is selected.
\r
41473 legendModel[isSelected ? 'select' : 'unSelect'](payload.name);
\r
41476 legendModel[methodName](payload.name);
\r
41477 isSelected = legendModel.isSelected(payload.name);
\r
41479 var legendData = legendModel.getData();
\r
41480 zrUtil.each(legendData, function (model) {
\r
41481 var name = model.get('name');
\r
41483 if (name === '\n' || name === '') {
\r
41486 var isItemSelected = legendModel.isSelected(name);
\r
41487 if (name in selectedMap) {
\r
41488 // Unselected if any legend is unselected
\r
41489 selectedMap[name] = selectedMap[name] && isItemSelected;
\r
41492 selectedMap[name] = isItemSelected;
\r
41496 // Return the event explicitly
\r
41498 name: payload.name,
\r
41499 selected: selectedMap
\r
41503 * @event legendToggleSelect
\r
41505 * @property {string} type 'legendToggleSelect'
\r
41506 * @property {string} [from]
\r
41507 * @property {string} name Series name or data item name
\r
41509 echarts.registerAction(
\r
41510 'legendToggleSelect', 'legendselectchanged',
\r
41511 zrUtil.curry(legendSelectActionHandler, 'toggleSelected')
\r
41515 * @event legendSelect
\r
41517 * @property {string} type 'legendSelect'
\r
41518 * @property {string} name Series name or data item name
\r
41520 echarts.registerAction(
\r
41521 'legendSelect', 'legendselected',
\r
41522 zrUtil.curry(legendSelectActionHandler, 'select')
\r
41526 * @event legendUnSelect
\r
41528 * @property {string} type 'legendUnSelect'
\r
41529 * @property {string} name Series name or data item name
\r
41531 echarts.registerAction(
\r
41532 'legendUnSelect', 'legendunselected',
\r
41533 zrUtil.curry(legendSelectActionHandler, 'unSelect')
\r
41539 /***/ function(module, exports, __webpack_require__) {
\r
41543 var zrUtil = __webpack_require__(3);
\r
41544 var symbolCreator = __webpack_require__(100);
\r
41545 var graphic = __webpack_require__(42);
\r
41546 var listComponentHelper = __webpack_require__(266);
\r
41548 var curry = zrUtil.curry;
\r
41550 var LEGEND_DISABLE_COLOR = '#ccc';
\r
41552 function dispatchSelectAction(name, api) {
\r
41553 api.dispatchAction({
\r
41554 type: 'legendToggleSelect',
\r
41559 function dispatchHighlightAction(seriesModel, dataName, api) {
\r
41560 seriesModel.get('legendHoverLink') && api.dispatchAction({
\r
41561 type: 'highlight',
\r
41562 seriesName: seriesModel.name,
\r
41567 function dispatchDownplayAction(seriesModel, dataName, api) {
\r
41568 seriesModel.get('legendHoverLink') && api.dispatchAction({
\r
41569 type: 'downplay',
\r
41570 seriesName: seriesModel.name,
\r
41575 module.exports = __webpack_require__(1).extendComponentView({
\r
41579 init: function () {
\r
41580 this._symbolTypeStore = {};
\r
41583 render: function (legendModel, ecModel, api) {
\r
41584 var group = this.group;
\r
41585 group.removeAll();
\r
41587 if (!legendModel.get('show')) {
\r
41591 var selectMode = legendModel.get('selectedMode');
\r
41592 var itemAlign = legendModel.get('align');
\r
41594 if (itemAlign === 'auto') {
\r
41595 itemAlign = (legendModel.get('left') === 'right'
\r
41596 && legendModel.get('orient') === 'vertical')
\r
41597 ? 'right' : 'left';
\r
41600 var legendItemMap = {};
\r
41601 var legendDrawedMap = {};
\r
41602 zrUtil.each(legendModel.getData(), function (itemModel) {
\r
41603 var seriesName = itemModel.get('name');
\r
41604 // Use empty string or \n as a newline string
\r
41605 if (seriesName === '' || seriesName === '\n') {
\r
41606 group.add(new graphic.Group({
\r
41611 var seriesModel = ecModel.getSeriesByName(seriesName)[0];
\r
41613 legendItemMap[seriesName] = itemModel;
\r
41615 if (!seriesModel || legendDrawedMap[seriesName]) {
\r
41616 // Series not exists
\r
41620 var data = seriesModel.getData();
\r
41621 var color = data.getVisual('color');
\r
41623 // If color is a callback function
\r
41624 if (typeof color === 'function') {
\r
41625 // Use the first data
\r
41626 color = color(seriesModel.getDataParams(0));
\r
41629 // Using rect symbol defaultly
\r
41630 var legendSymbolType = data.getVisual('legendSymbol') || 'roundRect';
\r
41631 var symbolType = data.getVisual('symbol');
\r
41633 var itemGroup = this._createItem(
\r
41634 seriesName, itemModel, legendModel,
\r
41635 legendSymbolType, symbolType,
\r
41636 itemAlign, color,
\r
41640 itemGroup.on('click', curry(dispatchSelectAction, seriesName, api))
\r
41641 .on('mouseover', curry(dispatchHighlightAction, seriesModel, '', api))
\r
41642 .on('mouseout', curry(dispatchDownplayAction, seriesModel, '', api));
\r
41644 legendDrawedMap[seriesName] = true;
\r
41647 ecModel.eachRawSeries(function (seriesModel) {
\r
41648 if (seriesModel.legendDataProvider) {
\r
41649 var data = seriesModel.legendDataProvider();
\r
41650 data.each(function (idx) {
\r
41651 var name = data.getName(idx);
\r
41653 // Avoid mutiple series use the same data name
\r
41654 if (!legendItemMap[name] || legendDrawedMap[name]) {
\r
41658 var color = data.getItemVisual(idx, 'color');
\r
41660 var legendSymbolType = 'roundRect';
\r
41662 var itemGroup = this._createItem(
\r
41663 name, legendItemMap[name], legendModel,
\r
41664 legendSymbolType, null,
\r
41665 itemAlign, color,
\r
41669 itemGroup.on('click', curry(dispatchSelectAction, name, api))
\r
41670 // FIXME Should not specify the series name
\r
41671 .on('mouseover', curry(dispatchHighlightAction, seriesModel, name, api))
\r
41672 .on('mouseout', curry(dispatchDownplayAction, seriesModel, name, api));
\r
41674 legendDrawedMap[name] = true;
\r
41679 listComponentHelper.layout(group, legendModel, api);
\r
41680 // Render background after group is layout
\r
41682 listComponentHelper.addBackground(group, legendModel);
\r
41685 _createItem: function (
\r
41686 name, itemModel, legendModel,
\r
41687 legendSymbolType, symbolType,
\r
41688 itemAlign, color, selectMode
\r
41690 var itemWidth = legendModel.get('itemWidth');
\r
41691 var itemHeight = legendModel.get('itemHeight');
\r
41693 var isSelected = legendModel.isSelected(name);
\r
41694 var itemGroup = new graphic.Group();
\r
41696 var textStyleModel = itemModel.getModel('textStyle');
\r
41698 var itemIcon = itemModel.get('icon');
\r
41700 // Use user given icon first
\r
41701 legendSymbolType = itemIcon || legendSymbolType;
\r
41702 itemGroup.add(symbolCreator.createSymbol(
\r
41703 legendSymbolType, 0, 0, itemWidth, itemHeight, isSelected ? color : LEGEND_DISABLE_COLOR
\r
41706 // Compose symbols
\r
41708 if (!itemIcon && symbolType
\r
41709 // At least show one symbol, can't be all none
\r
41710 && ((symbolType !== legendSymbolType) || symbolType == 'none')
\r
41712 var size = itemHeight * 0.8;
\r
41713 if (symbolType === 'none') {
\r
41714 symbolType = 'circle';
\r
41716 // Put symbol in the center
\r
41717 itemGroup.add(symbolCreator.createSymbol(
\r
41718 symbolType, (itemWidth - size) / 2, (itemHeight - size) / 2, size, size,
\r
41719 isSelected ? color : LEGEND_DISABLE_COLOR
\r
41724 var textX = itemAlign === 'left' ? itemWidth + 5 : -5;
\r
41725 var textAlign = itemAlign;
\r
41727 var formatter = legendModel.get('formatter');
\r
41728 if (typeof formatter === 'string' && formatter) {
\r
41729 name = formatter.replace('{name}', name);
\r
41731 else if (typeof formatter === 'function') {
\r
41732 name = formatter(name);
\r
41735 var text = new graphic.Text({
\r
41739 y: itemHeight / 2,
\r
41740 fill: isSelected ? textStyleModel.getTextColor() : LEGEND_DISABLE_COLOR,
\r
41741 textFont: textStyleModel.getFont(),
\r
41742 textAlign: textAlign,
\r
41743 textVerticalAlign: 'middle'
\r
41746 itemGroup.add(text);
\r
41748 // Add a invisible rect to increase the area of mouse hover
\r
41749 itemGroup.add(new graphic.Rect({
\r
41750 shape: itemGroup.getBoundingRect(),
\r
41754 itemGroup.eachChild(function (child) {
\r
41755 child.silent = !selectMode;
\r
41758 this.group.add(itemGroup);
\r
41760 graphic.setHoverStyle(itemGroup);
\r
41762 return itemGroup;
\r
41769 /***/ function(module, exports, __webpack_require__) {
\r
41773 var layout = __webpack_require__(21);
\r
41774 var formatUtil = __webpack_require__(6);
\r
41775 var graphic = __webpack_require__(42);
\r
41777 function positionGroup(group, model, api) {
\r
41778 layout.positionGroup(
\r
41779 group, model.getBoxLayoutParams(),
\r
41781 width: api.getWidth(),
\r
41782 height: api.getHeight()
\r
41784 model.get('padding')
\r
41788 module.exports = {
\r
41790 * Layout list like component.
\r
41791 * It will box layout each items in group of component and then position the whole group in the viewport
\r
41792 * @param {module:zrender/group/Group} group
\r
41793 * @param {module:echarts/model/Component} componentModel
\r
41794 * @param {module:echarts/ExtensionAPI}
\r
41796 layout: function (group, componentModel, api) {
\r
41797 var rect = layout.getLayoutRect(componentModel.getBoxLayoutParams(), {
\r
41798 width: api.getWidth(),
\r
41799 height: api.getHeight()
\r
41800 }, componentModel.get('padding'));
\r
41802 componentModel.get('orient'),
\r
41804 componentModel.get('itemGap'),
\r
41809 positionGroup(group, componentModel, api);
\r
41812 addBackground: function (group, componentModel) {
\r
41813 var padding = formatUtil.normalizeCssArray(
\r
41814 componentModel.get('padding')
\r
41816 var boundingRect = group.getBoundingRect();
\r
41817 var style = componentModel.getItemStyle(['color', 'opacity']);
\r
41818 style.fill = componentModel.get('backgroundColor');
\r
41819 var rect = new graphic.Rect({
\r
41821 x: boundingRect.x - padding[3],
\r
41822 y: boundingRect.y - padding[0],
\r
41823 width: boundingRect.width + padding[1] + padding[3],
\r
41824 height: boundingRect.height + padding[0] + padding[2]
\r
41830 graphic.subPixelOptimizeRect(rect);
\r
41839 /***/ function(module, exports) {
\r
41842 module.exports = function (ecModel) {
\r
41843 var legendModels = ecModel.findComponents({
\r
41844 mainType: 'legend'
\r
41846 if (legendModels && legendModels.length) {
\r
41847 ecModel.filterSeries(function (series) {
\r
41848 // If in any legend component the status is not selected.
\r
41849 // Because in legend series is assumed selected when it is not in the legend data.
\r
41850 for (var i = 0; i < legendModels.length; i++) {
\r
41851 if (!legendModels[i].isSelected(series.name)) {
\r
41863 /***/ function(module, exports, __webpack_require__) {
\r
41865 // FIXME Better way to pack data in graphic element
\r
41868 __webpack_require__(269);
\r
41870 __webpack_require__(270);
\r
41872 // Show tip action
\r
41875 * @property {string} type
\r
41876 * @property {number} seriesIndex
\r
41877 * @property {number} dataIndex
\r
41878 * @property {number} [x]
\r
41879 * @property {number} [y]
\r
41881 __webpack_require__(1).registerAction(
\r
41884 event: 'showTip',
\r
41890 // Hide tip action
\r
41891 __webpack_require__(1).registerAction(
\r
41894 event: 'hideTip',
\r
41904 /***/ function(module, exports, __webpack_require__) {
\r
41908 __webpack_require__(1).extendComponentModel({
\r
41920 showContent: true,
\r
41922 // 触发类型,默认数据触发,见下图,可选为:'item' ¦ 'axis'
\r
41925 // 触发条件,支持 'click' | 'mousemove'
\r
41926 triggerOn: 'mousemove',
\r
41928 // 是否永远显示 content
\r
41929 alwaysShowContent: false,
\r
41931 // 位置 {Array} | {Function}
\r
41932 // position: null
\r
41934 // 内容格式器:{string}(Template) ¦ {Function}
\r
41935 // formatter: null
\r
41941 transitionDuration: 0.4,
\r
41943 enterable: false,
\r
41945 // 提示背景颜色,默认为透明度为0.7的黑色
\r
41946 backgroundColor: 'rgba(50,50,50,0.7)',
\r
41949 borderColor: '#333',
\r
41951 // 提示边框圆角,单位px,默认为4
\r
41954 // 提示边框线宽,单位px,默认为0(无边框)
\r
41957 // 提示内边距,单位px,默认各方向内边距为5,
\r
41958 // 接受数组分别设定上右下左边距,同css
\r
41961 // Extra css text
\r
41962 extraCssText: '',
\r
41964 // 坐标轴指示器,坐标轴触发有效
\r
41967 // 可选为:'line' | 'shadow' | 'cross'
\r
41970 // type 为 line 的时候有效,指定 tooltip line 所在的轴,可选
\r
41971 // 可选 'x' | 'y' | 'angle' | 'radius' | 'auto'
\r
41972 // 默认 'auto',会选择类型为 cateogry 的轴,对于双数值轴,笛卡尔坐标系会默认选择 x 轴
\r
41973 // 极坐标系会默认选择 angle 轴
\r
41977 animationDurationUpdate: 200,
\r
41978 animationEasingUpdate: 'exponentialOut',
\r
41992 // TODO formatter
\r
41998 color: 'rgba(150,150,150,0.3)'
\r
42011 /***/ function(module, exports, __webpack_require__) {
\r
42015 var TooltipContent = __webpack_require__(271);
\r
42016 var graphic = __webpack_require__(42);
\r
42017 var zrUtil = __webpack_require__(3);
\r
42018 var formatUtil = __webpack_require__(6);
\r
42019 var numberUtil = __webpack_require__(7);
\r
42020 var parsePercent = numberUtil.parsePercent;
\r
42021 var env = __webpack_require__(78);
\r
42023 function dataEqual(a, b) {
\r
42027 var round = numberUtil.round;
\r
42028 return round(a[0]) === round(b[0])
\r
42029 && round(a[1]) === round(b[1]);
\r
42034 function makeLineShape(x1, y1, x2, y2) {
\r
42046 function makeRectShape(x, y, width, height) {
\r
42058 function makeSectorShape(cx, cy, r0, r, startAngle, endAngle) {
\r
42064 startAngle: startAngle,
\r
42065 endAngle: endAngle,
\r
42070 function refixTooltipPosition(x, y, el, viewWidth, viewHeight) {
\r
42071 var width = el.clientWidth;
\r
42072 var height = el.clientHeight;
\r
42075 if (x + width + gap > viewWidth) {
\r
42076 x -= width + gap;
\r
42081 if (y + height + gap > viewHeight) {
\r
42082 y -= height + gap;
\r
42090 function calcTooltipPosition(position, rect, dom) {
\r
42091 var domWidth = dom.clientWidth;
\r
42092 var domHeight = dom.clientHeight;
\r
42096 var rectWidth = rect.width;
\r
42097 var rectHeight = rect.height;
\r
42098 switch (position) {
\r
42100 x = rect.x + rectWidth / 2 - domWidth / 2;
\r
42101 y = rect.y + rectHeight / 2 - domHeight / 2;
\r
42104 x = rect.x + rectWidth / 2 - domWidth / 2;
\r
42105 y = rect.y - domHeight - gap;
\r
42108 x = rect.x + rectWidth / 2 - domWidth / 2;
\r
42109 y = rect.y + rectHeight + gap;
\r
42112 x = rect.x - domWidth - gap;
\r
42113 y = rect.y + rectHeight / 2 - domHeight / 2;
\r
42116 x = rect.x + rectWidth + gap;
\r
42117 y = rect.y + rectHeight / 2 - domHeight / 2;
\r
42123 * @param {string|Function|Array.<number>} positionExpr
\r
42124 * @param {number} x Mouse x
\r
42125 * @param {number} y Mouse y
\r
42126 * @param {module:echarts/component/tooltip/TooltipContent} content
\r
42127 * @param {Object|<Array.<Object>} params
\r
42128 * @param {module:zrender/Element} el target element
\r
42129 * @param {module:echarts/ExtensionAPI} api
\r
42130 * @return {Array.<number>}
\r
42132 function updatePosition(positionExpr, x, y, content, params, el, api) {
\r
42133 var viewWidth = api.getWidth();
\r
42134 var viewHeight = api.getHeight();
\r
42136 var rect = el && el.getBoundingRect().clone();
\r
42137 el && rect.applyTransform(el.transform);
\r
42138 if (typeof positionExpr === 'function') {
\r
42139 // Callback of position can be an array or a string specify the positiont
\r
42140 positionExpr = positionExpr([x, y], params, rect);
\r
42143 if (zrUtil.isArray(positionExpr)) {
\r
42144 x = parsePercent(positionExpr[0], viewWidth);
\r
42145 y = parsePercent(positionExpr[1], viewHeight);
\r
42147 // Specify tooltip position by string 'top' 'bottom' 'left' 'right' around graphic element
\r
42148 else if (typeof positionExpr === 'string' && el) {
\r
42149 var pos = calcTooltipPosition(
\r
42150 positionExpr, rect, content.el
\r
42156 var pos = refixTooltipPosition(
\r
42157 x, y, content.el, viewWidth, viewHeight
\r
42163 content.moveTo(x, y);
\r
42166 function ifSeriesSupportAxisTrigger(seriesModel) {
\r
42167 var coordSys = seriesModel.coordinateSystem;
\r
42168 var trigger = seriesModel.get('tooltip.trigger', true);
\r
42169 // Ignore series use item tooltip trigger and series coordinate system is not cartesian or
\r
42170 return !(!coordSys
\r
42171 || (coordSys.type !== 'cartesian2d' && coordSys.type !== 'polar' && coordSys.type !== 'single')
\r
42172 || trigger === 'item');
\r
42175 __webpack_require__(1).extendComponentView({
\r
42179 _axisPointers: {},
\r
42181 init: function (ecModel, api) {
\r
42185 var tooltipContent = new TooltipContent(api.getDom(), api);
\r
42186 this._tooltipContent = tooltipContent;
\r
42188 api.on('showTip', this._manuallyShowTip, this);
\r
42189 api.on('hideTip', this._manuallyHideTip, this);
\r
42192 render: function (tooltipModel, ecModel, api) {
\r
42198 this.group.removeAll();
\r
42204 this._axisPointers = {};
\r
42208 * @type {module:echarts/component/tooltip/TooltipModel}
\r
42210 this._tooltipModel = tooltipModel;
\r
42214 * @type {module:echarts/model/Global}
\r
42216 this._ecModel = ecModel;
\r
42220 * @type {module:echarts/ExtensionAPI}
\r
42228 this._lastHover = {
\r
42233 var tooltipContent = this._tooltipContent;
\r
42234 tooltipContent.update();
\r
42235 tooltipContent.enterable = tooltipModel.get('enterable');
\r
42236 this._alwaysShowContent = tooltipModel.get('alwaysShowContent');
\r
42239 * @type {Object.<string, Array>}
\r
42241 this._seriesGroupByAxis = this._prepareAxisTriggerData(
\r
42242 tooltipModel, ecModel
\r
42245 var crossText = this._crossText;
\r
42247 this.group.add(crossText);
\r
42250 // Try to keep the tooltip show when refreshing
\r
42251 if (this._lastX != null && this._lastY != null) {
\r
42253 clearTimeout(this._refreshUpdateTimeout);
\r
42254 this._refreshUpdateTimeout = setTimeout(function () {
\r
42255 // Show tip next tick after other charts are rendered
\r
42256 // In case highlight action has wrong result
\r
42258 self._manuallyShowTip({
\r
42265 var zr = this._api.getZr();
\r
42266 var tryShow = this._tryShow;
\r
42267 zr.off('click', tryShow);
\r
42268 zr.off('mousemove', tryShow);
\r
42269 zr.off('mouseout', this._hide);
\r
42270 if (tooltipModel.get('triggerOn') === 'click') {
\r
42271 zr.on('click', tryShow, this);
\r
42274 zr.on('mousemove', tryShow, this);
\r
42275 zr.on('mouseout', this._hide, this);
\r
42281 * Show tip manually by
\r
42282 * dispatchAction({
\r
42283 * type: 'showTip',
\r
42288 * dispatchAction({
\r
42289 * type: 'showTip',
\r
42290 * seriesIndex: 0,
\r
42296 _manuallyShowTip: function (event) {
\r
42298 if (event.from === this.uid) {
\r
42302 var ecModel = this._ecModel;
\r
42303 var seriesIndex = event.seriesIndex;
\r
42304 var dataIndex = event.dataIndex;
\r
42305 var seriesModel = ecModel.getSeriesByIndex(seriesIndex);
\r
42306 var api = this._api;
\r
42308 if (event.x == null || event.y == null) {
\r
42309 if (!seriesModel) {
\r
42310 // Find the first series can use axis trigger
\r
42311 ecModel.eachSeries(function (_series) {
\r
42312 if (ifSeriesSupportAxisTrigger(_series) && !seriesModel) {
\r
42313 seriesModel = _series;
\r
42317 if (seriesModel) {
\r
42318 var data = seriesModel.getData();
\r
42319 if (dataIndex == null) {
\r
42320 dataIndex = data.indexOfName(event.name);
\r
42322 var el = data.getItemGraphicEl(dataIndex);
\r
42324 // Try to get the point in coordinate system
\r
42325 var coordSys = seriesModel.coordinateSystem;
\r
42326 if (coordSys && coordSys.dataToPoint) {
\r
42327 var point = coordSys.dataToPoint(
\r
42328 data.getValues(coordSys.dimensions, dataIndex, true)
\r
42330 cx = point && point[0];
\r
42331 cy = point && point[1];
\r
42334 // Use graphic bounding rect
\r
42335 var rect = el.getBoundingRect().clone();
\r
42336 rect.applyTransform(el.transform);
\r
42337 cx = rect.x + rect.width / 2;
\r
42338 cy = rect.y + rect.height / 2;
\r
42340 if (cx != null && cy != null) {
\r
42351 var el = api.getZr().handler.findHover(event.x, event.y);
\r
42353 offsetX: event.x,
\r
42354 offsetY: event.y,
\r
42361 _manuallyHideTip: function (e) {
\r
42362 if (e.from === this.uid) {
\r
42369 _prepareAxisTriggerData: function (tooltipModel, ecModel) {
\r
42370 // Prepare data for axis trigger
\r
42371 var seriesGroupByAxis = {};
\r
42372 ecModel.eachSeries(function (seriesModel) {
\r
42373 if (ifSeriesSupportAxisTrigger(seriesModel)) {
\r
42374 var coordSys = seriesModel.coordinateSystem;
\r
42378 // Only cartesian2d, polar and single support axis trigger
\r
42379 if (coordSys.type === 'cartesian2d') {
\r
42380 // FIXME `axisPointer.axis` is not baseAxis
\r
42381 baseAxis = coordSys.getBaseAxis();
\r
42382 key = baseAxis.dim + baseAxis.index;
\r
42384 else if (coordSys.type === 'single') {
\r
42385 baseAxis = coordSys.getAxis();
\r
42386 key = baseAxis.dim + baseAxis.type;
\r
42389 baseAxis = coordSys.getBaseAxis();
\r
42390 key = baseAxis.dim + coordSys.name;
\r
42393 seriesGroupByAxis[key] = seriesGroupByAxis[key] || {
\r
42397 seriesGroupByAxis[key].coordSys.push(coordSys);
\r
42398 seriesGroupByAxis[key].series.push(seriesModel);
\r
42402 return seriesGroupByAxis;
\r
42406 * mousemove handler
\r
42407 * @param {Object} e
\r
42410 _tryShow: function (e) {
\r
42411 var el = e.target;
\r
42412 var tooltipModel = this._tooltipModel;
\r
42413 var globalTrigger = tooltipModel.get('trigger');
\r
42414 var ecModel = this._ecModel;
\r
42415 var api = this._api;
\r
42417 if (!tooltipModel) {
\r
42421 // Save mouse x, mouse y. So we can try to keep showing the tip if chart is refreshed
\r
42422 this._lastX = e.offsetX;
\r
42423 this._lastY = e.offsetY;
\r
42425 // Always show item tooltip if mouse is on the element with dataIndex
\r
42426 if (el && el.dataIndex != null) {
\r
42427 // Use dataModel in element if possible
\r
42428 // Used when mouseover on a element like markPoint or edge
\r
42429 // In which case, the data is not main data in series.
\r
42430 var dataModel = el.dataModel || ecModel.getSeriesByIndex(el.seriesIndex);
\r
42431 var dataIndex = el.dataIndex;
\r
42432 var itemModel = dataModel.getData().getItemModel(dataIndex);
\r
42433 // Series or single data may use item trigger when global is axis trigger
\r
42434 if ((itemModel.get('tooltip.trigger') || globalTrigger) === 'axis') {
\r
42435 this._showAxisTooltip(tooltipModel, ecModel, e);
\r
42439 this._ticket = '';
\r
42440 // If either single data or series use item trigger
\r
42441 this._hideAxisPointer();
\r
42442 // Reset last hover and dispatch downplay action
\r
42443 this._resetLastHover();
\r
42445 this._showItemTooltipContent(dataModel, dataIndex, e);
\r
42448 api.dispatchAction({
\r
42451 dataIndex: el.dataIndex,
\r
42452 seriesIndex: el.seriesIndex
\r
42456 if (globalTrigger === 'item') {
\r
42460 // Try show axis tooltip
\r
42461 this._showAxisTooltip(tooltipModel, ecModel, e);
\r
42464 // Action of cross pointer
\r
42465 // other pointer types will trigger action in _dispatchAndShowSeriesTooltipContent method
\r
42466 if (tooltipModel.get('axisPointer.type') === 'cross') {
\r
42467 api.dispatchAction({
\r
42478 * Show tooltip on axis
\r
42479 * @param {module:echarts/component/tooltip/TooltipModel} tooltipModel
\r
42480 * @param {module:echarts/model/Global} ecModel
\r
42481 * @param {Object} e
\r
42484 _showAxisTooltip: function (tooltipModel, ecModel, e) {
\r
42485 var axisPointerModel = tooltipModel.getModel('axisPointer');
\r
42486 var axisPointerType = axisPointerModel.get('type');
\r
42488 if (axisPointerType === 'cross') {
\r
42489 var el = e.target;
\r
42490 if (el && el.dataIndex != null) {
\r
42491 var seriesModel = ecModel.getSeriesByIndex(el.seriesIndex);
\r
42492 var dataIndex = el.dataIndex;
\r
42493 this._showItemTooltipContent(seriesModel, dataIndex, e);
\r
42497 this._showAxisPointer();
\r
42498 var allNotShow = true;
\r
42499 zrUtil.each(this._seriesGroupByAxis, function (seriesCoordSysSameAxis) {
\r
42500 // Try show the axis pointer
\r
42501 var allCoordSys = seriesCoordSysSameAxis.coordSys;
\r
42502 var coordSys = allCoordSys[0];
\r
42504 // If mouse position is not in the grid or polar
\r
42505 var point = [e.offsetX, e.offsetY];
\r
42507 if (!coordSys.containPoint(point)) {
\r
42508 // Hide axis pointer
\r
42509 this._hideAxisPointer(coordSys.name);
\r
42513 allNotShow = false;
\r
42514 // Make sure point is discrete on cateogry axis
\r
42515 var dimensions = coordSys.dimensions;
\r
42516 var value = coordSys.pointToData(point, true);
\r
42517 point = coordSys.dataToPoint(value);
\r
42518 var baseAxis = coordSys.getBaseAxis();
\r
42519 var axisType = axisPointerModel.get('axis');
\r
42520 if (axisType === 'auto') {
\r
42521 axisType = baseAxis.dim;
\r
42524 var contentNotChange = false;
\r
42525 var lastHover = this._lastHover;
\r
42526 if (axisPointerType === 'cross') {
\r
42527 // If hover data not changed
\r
42528 // Possible when two axes are all category
\r
42529 if (dataEqual(lastHover.data, value)) {
\r
42530 contentNotChange = true;
\r
42532 lastHover.data = value;
\r
42535 var valIndex = zrUtil.indexOf(dimensions, axisType);
\r
42537 // If hover data not changed on the axis dimension
\r
42538 if (lastHover.data === value[valIndex]) {
\r
42539 contentNotChange = true;
\r
42541 lastHover.data = value[valIndex];
\r
42544 if (coordSys.type === 'cartesian2d' && !contentNotChange) {
\r
42545 this._showCartesianPointer(
\r
42546 axisPointerModel, coordSys, axisType, point
\r
42549 else if (coordSys.type === 'polar' && !contentNotChange) {
\r
42550 this._showPolarPointer(
\r
42551 axisPointerModel, coordSys, axisType, point
\r
42554 else if (coordSys.type === 'single' && !contentNotChange) {
\r
42555 this._showSinglePointer(
\r
42556 axisPointerModel, coordSys, axisType, point
\r
42560 if (axisPointerType !== 'cross') {
\r
42561 this._dispatchAndShowSeriesTooltipContent(
\r
42562 coordSys, seriesCoordSysSameAxis.series, point, value, contentNotChange
\r
42567 if (allNotShow) {
\r
42573 * Show tooltip on axis of cartesian coordinate
\r
42574 * @param {module:echarts/model/Model} axisPointerModel
\r
42575 * @param {module:echarts/coord/cartesian/Cartesian2D} cartesians
\r
42576 * @param {string} axisType
\r
42577 * @param {Array.<number>} point
\r
42580 _showCartesianPointer: function (axisPointerModel, cartesian, axisType, point) {
\r
42583 var axisPointerType = axisPointerModel.get('type');
\r
42584 var moveAnimation = axisPointerType !== 'cross';
\r
42586 if (axisPointerType === 'cross') {
\r
42587 moveGridLine('x', point, cartesian.getAxis('y').getGlobalExtent());
\r
42588 moveGridLine('y', point, cartesian.getAxis('x').getGlobalExtent());
\r
42590 this._updateCrossText(cartesian, point, axisPointerModel);
\r
42593 var otherAxis = cartesian.getAxis(axisType === 'x' ? 'y' : 'x');
\r
42594 var otherExtent = otherAxis.getGlobalExtent();
\r
42596 if (cartesian.type === 'cartesian2d') {
\r
42597 (axisPointerType === 'line' ? moveGridLine : moveGridShadow)(
\r
42598 axisType, point, otherExtent
\r
42606 function moveGridLine(axisType, point, otherExtent) {
\r
42607 var targetShape = axisType === 'x'
\r
42608 ? makeLineShape(point[0], otherExtent[0], point[0], otherExtent[1])
\r
42609 : makeLineShape(otherExtent[0], point[1], otherExtent[1], point[1]);
\r
42611 var pointerEl = self._getPointerElement(
\r
42612 cartesian, axisPointerModel, axisType, targetShape
\r
42615 ? graphic.updateProps(pointerEl, {
\r
42616 shape: targetShape
\r
42617 }, axisPointerModel)
\r
42618 : pointerEl.attr({
\r
42619 shape: targetShape
\r
42626 function moveGridShadow(axisType, point, otherExtent) {
\r
42627 var axis = cartesian.getAxis(axisType);
\r
42628 var bandWidth = axis.getBandWidth();
\r
42629 var span = otherExtent[1] - otherExtent[0];
\r
42630 var targetShape = axisType === 'x'
\r
42631 ? makeRectShape(point[0] - bandWidth / 2, otherExtent[0], bandWidth, span)
\r
42632 : makeRectShape(otherExtent[0], point[1] - bandWidth / 2, span, bandWidth);
\r
42634 var pointerEl = self._getPointerElement(
\r
42635 cartesian, axisPointerModel, axisType, targetShape
\r
42638 ? graphic.updateProps(pointerEl, {
\r
42639 shape: targetShape
\r
42640 }, axisPointerModel)
\r
42641 : pointerEl.attr({
\r
42642 shape: targetShape
\r
42647 _showSinglePointer: function (axisPointerModel, single, axisType, point) {
\r
42649 var axisPointerType = axisPointerModel.get('type');
\r
42650 var moveAnimation = axisPointerType !== 'cross';
\r
42651 var rect = single.getRect();
\r
42652 var otherExtent = [rect.y, rect.y + rect.height];
\r
42654 moveSingleLine(axisType, point, otherExtent);
\r
42659 function moveSingleLine(axisType, point, otherExtent) {
\r
42660 var axis = single.getAxis();
\r
42661 var orient = axis.orient;
\r
42663 var targetShape = orient === 'horizontal'
\r
42664 ? makeLineShape(point[0], otherExtent[0], point[0], otherExtent[1])
\r
42665 : makeLineShape(otherExtent[0], point[1], otherExtent[1], point[1]);
\r
42667 var pointerEl = self._getPointerElement(
\r
42668 single, axisPointerModel, axisType, targetShape
\r
42671 ? graphic.updateProps(pointerEl, {
\r
42672 shape: targetShape
\r
42673 }, axisPointerModel)
\r
42674 : pointerEl.attr({
\r
42675 shape: targetShape
\r
42682 * Show tooltip on axis of polar coordinate
\r
42683 * @param {module:echarts/model/Model} axisPointerModel
\r
42684 * @param {Array.<module:echarts/coord/polar/Polar>} polar
\r
42685 * @param {string} axisType
\r
42686 * @param {Array.<number>} point
\r
42688 _showPolarPointer: function (axisPointerModel, polar, axisType, point) {
\r
42691 var axisPointerType = axisPointerModel.get('type');
\r
42693 var angleAxis = polar.getAngleAxis();
\r
42694 var radiusAxis = polar.getRadiusAxis();
\r
42696 var moveAnimation = axisPointerType !== 'cross';
\r
42698 if (axisPointerType === 'cross') {
\r
42699 movePolarLine('angle', point, radiusAxis.getExtent());
\r
42700 movePolarLine('radius', point, angleAxis.getExtent());
\r
42702 this._updateCrossText(polar, point, axisPointerModel);
\r
42705 var otherAxis = polar.getAxis(axisType === 'radius' ? 'angle' : 'radius');
\r
42706 var otherExtent = otherAxis.getExtent();
\r
42708 (axisPointerType === 'line' ? movePolarLine : movePolarShadow)(
\r
42709 axisType, point, otherExtent
\r
42715 function movePolarLine(axisType, point, otherExtent) {
\r
42716 var mouseCoord = polar.pointToCoord(point);
\r
42720 if (axisType === 'angle') {
\r
42721 var p1 = polar.coordToPoint([otherExtent[0], mouseCoord[1]]);
\r
42722 var p2 = polar.coordToPoint([otherExtent[1], mouseCoord[1]]);
\r
42723 targetShape = makeLineShape(p1[0], p1[1], p2[0], p2[1]);
\r
42733 var pointerEl = self._getPointerElement(
\r
42734 polar, axisPointerModel, axisType, targetShape
\r
42738 ? graphic.updateProps(pointerEl, {
\r
42739 shape: targetShape
\r
42740 }, axisPointerModel)
\r
42741 : pointerEl.attr({
\r
42742 shape: targetShape
\r
42749 function movePolarShadow(axisType, point, otherExtent) {
\r
42750 var axis = polar.getAxis(axisType);
\r
42751 var bandWidth = axis.getBandWidth();
\r
42753 var mouseCoord = polar.pointToCoord(point);
\r
42757 var radian = Math.PI / 180;
\r
42759 if (axisType === 'angle') {
\r
42760 targetShape = makeSectorShape(
\r
42761 polar.cx, polar.cy,
\r
42762 otherExtent[0], otherExtent[1],
\r
42763 // In ECharts y is negative if angle is positive
\r
42764 (-mouseCoord[1] - bandWidth / 2) * radian,
\r
42765 (-mouseCoord[1] + bandWidth / 2) * radian
\r
42769 targetShape = makeSectorShape(
\r
42770 polar.cx, polar.cy,
\r
42771 mouseCoord[0] - bandWidth / 2,
\r
42772 mouseCoord[0] + bandWidth / 2,
\r
42777 var pointerEl = self._getPointerElement(
\r
42778 polar, axisPointerModel, axisType, targetShape
\r
42781 ? graphic.updateProps(pointerEl, {
\r
42782 shape: targetShape
\r
42783 }, axisPointerModel)
\r
42784 : pointerEl.attr({
\r
42785 shape: targetShape
\r
42790 _updateCrossText: function (coordSys, point, axisPointerModel) {
\r
42791 var crossStyleModel = axisPointerModel.getModel('crossStyle');
\r
42792 var textStyleModel = crossStyleModel.getModel('textStyle');
\r
42794 var tooltipModel = this._tooltipModel;
\r
42796 var text = this._crossText;
\r
42798 text = this._crossText = new graphic.Text({
\r
42800 textAlign: 'left',
\r
42801 textVerticalAlign: 'bottom'
\r
42804 this.group.add(text);
\r
42807 var value = coordSys.pointToData(point);
\r
42809 var dims = coordSys.dimensions;
\r
42810 value = zrUtil.map(value, function (val, idx) {
\r
42811 var axis = coordSys.getAxis(dims[idx]);
\r
42812 if (axis.type === 'category' || axis.type === 'time') {
\r
42813 val = axis.scale.getLabel(val);
\r
42816 val = formatUtil.addCommas(
\r
42817 val.toFixed(axis.getPixelPrecision())
\r
42824 fill: textStyleModel.getTextColor() || crossStyleModel.get('color'),
\r
42825 textFont: textStyleModel.getFont(),
\r
42826 text: value.join(', '),
\r
42830 text.z = tooltipModel.get('z');
\r
42831 text.zlevel = tooltipModel.get('zlevel');
\r
42834 _getPointerElement: function (coordSys, pointerModel, axisType, initShape) {
\r
42835 var tooltipModel = this._tooltipModel;
\r
42836 var z = tooltipModel.get('z');
\r
42837 var zlevel = tooltipModel.get('zlevel');
\r
42838 var axisPointers = this._axisPointers;
\r
42839 var coordSysName = coordSys.name;
\r
42840 axisPointers[coordSysName] = axisPointers[coordSysName] || {};
\r
42841 if (axisPointers[coordSysName][axisType]) {
\r
42842 return axisPointers[coordSysName][axisType];
\r
42845 // Create if not exists
\r
42846 var pointerType = pointerModel.get('type');
\r
42847 var styleModel = pointerModel.getModel(pointerType + 'Style');
\r
42848 var isShadow = pointerType === 'shadow';
\r
42849 var style = styleModel[isShadow ? 'getAreaStyle' : 'getLineStyle']();
\r
42851 var elementType = coordSys.type === 'polar'
\r
42852 ? (isShadow ? 'Sector' : (axisType === 'radius' ? 'Circle' : 'Line'))
\r
42853 : (isShadow ? 'Rect' : 'Line');
\r
42855 isShadow ? (style.stroke = null) : (style.fill = null);
\r
42857 var el = axisPointers[coordSysName][axisType] = new graphic[elementType]({
\r
42865 this.group.add(el);
\r
42870 * Dispatch actions and show tooltip on series
\r
42871 * @param {Array.<module:echarts/model/Series>} seriesList
\r
42872 * @param {Array.<number>} point
\r
42873 * @param {Array.<number>} value
\r
42874 * @param {boolean} contentNotChange
\r
42875 * @param {Object} e
\r
42877 _dispatchAndShowSeriesTooltipContent: function (
\r
42878 coordSys, seriesList, point, value, contentNotChange
\r
42881 var rootTooltipModel = this._tooltipModel;
\r
42882 var tooltipContent = this._tooltipContent;
\r
42884 var baseAxis = coordSys.getBaseAxis();
\r
42886 var payloadBatch = zrUtil.map(seriesList, function (series) {
\r
42888 seriesIndex: series.seriesIndex,
\r
42889 dataIndex: series.getAxisTooltipDataIndex
\r
42890 ? series.getAxisTooltipDataIndex(series.coordDimToDataDim(baseAxis.dim), value, baseAxis)
\r
42891 : series.getData().indexOfNearest(
\r
42892 series.coordDimToDataDim(baseAxis.dim)[0],
\r
42893 value[baseAxis.dim === 'x' || baseAxis.dim === 'radius' ? 0 : 1]
\r
42898 var lastHover = this._lastHover;
\r
42899 var api = this._api;
\r
42900 // Dispatch downplay action
\r
42901 if (lastHover.payloadBatch && !contentNotChange) {
\r
42902 api.dispatchAction({
\r
42903 type: 'downplay',
\r
42904 batch: lastHover.payloadBatch
\r
42907 // Dispatch highlight action
\r
42908 if (!contentNotChange) {
\r
42909 api.dispatchAction({
\r
42910 type: 'highlight',
\r
42911 batch: payloadBatch
\r
42913 lastHover.payloadBatch = payloadBatch;
\r
42915 // Dispatch showTip action
\r
42916 api.dispatchAction({
\r
42918 dataIndex: payloadBatch[0].dataIndex,
\r
42919 seriesIndex: payloadBatch[0].seriesIndex,
\r
42923 if (baseAxis && rootTooltipModel.get('showContent')) {
\r
42925 var formatter = rootTooltipModel.get('formatter');
\r
42926 var positionExpr = rootTooltipModel.get('position');
\r
42929 var paramsList = zrUtil.map(seriesList, function (series, index) {
\r
42930 return series.getDataParams(payloadBatch[index].dataIndex);
\r
42932 // If only one series
\r
42934 // if (paramsList.length === 1) {
\r
42935 // paramsList = paramsList[0];
\r
42938 tooltipContent.show(rootTooltipModel);
\r
42940 // Update html content
\r
42941 var firstDataIndex = payloadBatch[0].dataIndex;
\r
42942 if (!contentNotChange) {
\r
42944 this._ticket = '';
\r
42945 if (!formatter) {
\r
42946 // Default tooltip content
\r
42948 // (1) shold be the first data which has name?
\r
42949 // (2) themeRiver, firstDataIndex is array, and first line is unnecessary.
\r
42950 var firstLine = seriesList[0].getData().getName(firstDataIndex);
\r
42951 html = (firstLine ? firstLine + '<br />' : '')
\r
42952 + zrUtil.map(seriesList, function (series, index) {
\r
42953 return series.formatTooltip(payloadBatch[index].dataIndex, true);
\r
42954 }).join('<br />');
\r
42957 if (typeof formatter === 'string') {
\r
42958 html = formatUtil.formatTpl(formatter, paramsList);
\r
42960 else if (typeof formatter === 'function') {
\r
42962 var ticket = 'axis_' + coordSys.name + '_' + firstDataIndex;
\r
42963 var callback = function (cbTicket, html) {
\r
42964 if (cbTicket === self._ticket) {
\r
42965 tooltipContent.setContent(html);
\r
42968 positionExpr, point[0], point[1],
\r
42969 tooltipContent, paramsList, null, api
\r
42973 self._ticket = ticket;
\r
42974 html = formatter(paramsList, ticket, callback);
\r
42978 tooltipContent.setContent(html);
\r
42982 positionExpr, point[0], point[1],
\r
42983 tooltipContent, paramsList, null, api
\r
42989 * Show tooltip on item
\r
42990 * @param {module:echarts/model/Series} seriesModel
\r
42991 * @param {number} dataIndex
\r
42992 * @param {Object} e
\r
42994 _showItemTooltipContent: function (seriesModel, dataIndex, e) {
\r
42995 // FIXME Graph data
\r
42996 var api = this._api;
\r
42997 var data = seriesModel.getData();
\r
42998 var itemModel = data.getItemModel(dataIndex);
\r
43000 var rootTooltipModel = this._tooltipModel;
\r
43002 var tooltipContent = this._tooltipContent;
\r
43004 var tooltipModel = itemModel.getModel('tooltip');
\r
43006 // If series model
\r
43007 if (tooltipModel.parentModel) {
\r
43008 tooltipModel.parentModel.parentModel = rootTooltipModel;
\r
43011 tooltipModel.parentModel = this._tooltipModel;
\r
43014 if (tooltipModel.get('showContent')) {
\r
43015 var formatter = tooltipModel.get('formatter');
\r
43016 var positionExpr = tooltipModel.get('position');
\r
43017 var params = seriesModel.getDataParams(dataIndex);
\r
43019 if (!formatter) {
\r
43020 html = seriesModel.formatTooltip(dataIndex);
\r
43023 if (typeof formatter === 'string') {
\r
43024 html = formatUtil.formatTpl(formatter, params);
\r
43026 else if (typeof formatter === 'function') {
\r
43028 var ticket = 'item_' + seriesModel.name + '_' + dataIndex;
\r
43029 var callback = function (cbTicket, html) {
\r
43030 if (cbTicket === self._ticket) {
\r
43031 tooltipContent.setContent(html);
\r
43034 positionExpr, e.offsetX, e.offsetY,
\r
43035 tooltipContent, params, e.target, api
\r
43039 self._ticket = ticket;
\r
43040 html = formatter(params, ticket, callback);
\r
43044 tooltipContent.show(tooltipModel);
\r
43045 tooltipContent.setContent(html);
\r
43048 positionExpr, e.offsetX, e.offsetY,
\r
43049 tooltipContent, params, e.target, api
\r
43055 * Show axis pointer
\r
43056 * @param {string} [coordSysName]
\r
43058 _showAxisPointer: function (coordSysName) {
\r
43059 if (coordSysName) {
\r
43060 var axisPointers = this._axisPointers[coordSysName];
\r
43061 axisPointers && zrUtil.each(axisPointers, function (el) {
\r
43066 this.group.eachChild(function (child) {
\r
43069 this.group.show();
\r
43073 _resetLastHover: function () {
\r
43074 var lastHover = this._lastHover;
\r
43075 if (lastHover.payloadBatch) {
\r
43076 this._api.dispatchAction({
\r
43077 type: 'downplay',
\r
43078 batch: lastHover.payloadBatch
\r
43081 // Reset lastHover
\r
43082 this._lastHover = {};
\r
43085 * Hide axis pointer
\r
43086 * @param {string} [coordSysName]
\r
43088 _hideAxisPointer: function (coordSysName) {
\r
43089 if (coordSysName) {
\r
43090 var axisPointers = this._axisPointers[coordSysName];
\r
43091 axisPointers && zrUtil.each(axisPointers, function (el) {
\r
43096 this.group.hide();
\r
43100 _hide: function () {
\r
43101 this._hideAxisPointer();
\r
43102 this._resetLastHover();
\r
43103 if (!this._alwaysShowContent) {
\r
43104 this._tooltipContent.hideLater(this._tooltipModel.get('hideDelay'));
\r
43107 this._api.dispatchAction({
\r
43113 dispose: function (ecModel, api) {
\r
43117 var zr = api.getZr();
\r
43118 this._tooltipContent.hide();
\r
43120 zr.off('click', this._tryShow);
\r
43121 zr.off('mousemove', this._tryShow);
\r
43122 zr.off('mouseout', this._hide);
\r
43124 api.off('showTip', this._manuallyShowTip);
\r
43125 api.off('hideTip', this._manuallyHideTip);
\r
43132 /***/ function(module, exports, __webpack_require__) {
\r
43135 * @module echarts/component/tooltip/TooltipContent
\r
43139 var zrUtil = __webpack_require__(3);
\r
43140 var zrColor = __webpack_require__(38);
\r
43141 var eventUtil = __webpack_require__(80);
\r
43142 var formatUtil = __webpack_require__(6);
\r
43143 var each = zrUtil.each;
\r
43144 var toCamelCase = formatUtil.toCamelCase;
\r
43146 var vendors = ['', '-webkit-', '-moz-', '-o-'];
\r
43148 var gCssText = 'position:absolute;display:block;border-style:solid;white-space:nowrap;z-index:9999999;';
\r
43151 * @param {number} duration
\r
43152 * @return {string}
\r
43155 function assembleTransition(duration) {
\r
43156 var transitionCurve = 'cubic-bezier(0.23, 1, 0.32, 1)';
\r
43157 var transitionText = 'left ' + duration + 's ' + transitionCurve + ','
\r
43158 + 'top ' + duration + 's ' + transitionCurve;
\r
43159 return zrUtil.map(vendors, function (vendorPrefix) {
\r
43160 return vendorPrefix + 'transition:' + transitionText;
\r
43165 * @param {Object} textStyle
\r
43166 * @return {string}
\r
43169 function assembleFont(textStyleModel) {
\r
43170 var cssText = [];
\r
43172 var fontSize = textStyleModel.get('fontSize');
\r
43173 var color = textStyleModel.getTextColor();
\r
43175 color && cssText.push('color:' + color);
\r
43177 cssText.push('font:' + textStyleModel.getFont());
\r
43180 cssText.push('line-height:' + Math.round(fontSize * 3 / 2) + 'px');
\r
43182 each(['decoration', 'align'], function (name) {
\r
43183 var val = textStyleModel.get(name);
\r
43184 val && cssText.push('text-' + name + ':' + val);
\r
43187 return cssText.join(';');
\r
43191 * @param {Object} tooltipModel
\r
43192 * @return {string}
\r
43195 function assembleCssText(tooltipModel) {
\r
43197 tooltipModel = tooltipModel;
\r
43199 var cssText = [];
\r
43201 var transitionDuration = tooltipModel.get('transitionDuration');
\r
43202 var backgroundColor = tooltipModel.get('backgroundColor');
\r
43203 var textStyleModel = tooltipModel.getModel('textStyle');
\r
43204 var padding = tooltipModel.get('padding');
\r
43206 // Animation transition
\r
43207 transitionDuration &&
\r
43208 cssText.push(assembleTransition(transitionDuration));
\r
43210 if (backgroundColor) {
\r
43213 'background-Color:' + zrColor.toHex(backgroundColor)
\r
43215 cssText.push('filter:alpha(opacity=70)');
\r
43216 cssText.push('background-Color:' + backgroundColor);
\r
43220 each(['width', 'color', 'radius'], function (name) {
\r
43221 var borderName = 'border-' + name;
\r
43222 var camelCase = toCamelCase(borderName);
\r
43223 var val = tooltipModel.get(camelCase);
\r
43225 cssText.push(borderName + ':' + val + (name === 'color' ? '' : 'px'));
\r
43229 cssText.push(assembleFont(textStyleModel));
\r
43232 if (padding != null) {
\r
43233 cssText.push('padding:' + formatUtil.normalizeCssArray(padding).join('px ') + 'px');
\r
43236 return cssText.join(';') + ';';
\r
43240 * @alias module:echarts/component/tooltip/TooltipContent
\r
43243 function TooltipContent(container, api) {
\r
43244 var el = document.createElement('div');
\r
43245 var zr = api.getZr();
\r
43249 this._x = api.getWidth() / 2;
\r
43250 this._y = api.getHeight() / 2;
\r
43252 container.appendChild(el);
\r
43254 this._container = container;
\r
43256 this._show = false;
\r
43261 this._hideTimeout;
\r
43264 el.onmouseenter = function () {
\r
43265 // clear the timeout in hideLater and keep showing tooltip
\r
43266 if (self.enterable) {
\r
43267 clearTimeout(self._hideTimeout);
\r
43268 self._show = true;
\r
43270 self._inContent = true;
\r
43272 el.onmousemove = function (e) {
\r
43273 if (!self.enterable) {
\r
43274 // Try trigger zrender event to avoid mouse
\r
43275 // in and out shape too frequently
\r
43276 var handler = zr.handler;
\r
43277 eventUtil.normalizeEvent(container, e);
\r
43278 handler.dispatch('mousemove', e);
\r
43281 el.onmouseleave = function () {
\r
43282 if (self.enterable) {
\r
43283 if (self._show) {
\r
43284 self.hideLater(self._hideDelay);
\r
43287 self._inContent = false;
\r
43290 compromiseMobile(el, container);
\r
43293 function compromiseMobile(tooltipContentEl, container) {
\r
43294 // Prevent default behavior on mobile. For example,
\r
43295 // defuault pinch gesture will cause browser zoom.
\r
43296 // We do not preventing event on tooltip contnet el,
\r
43297 // because user may need customization in tooltip el.
\r
43298 eventUtil.addEventListener(container, 'touchstart', preventDefault);
\r
43299 eventUtil.addEventListener(container, 'touchmove', preventDefault);
\r
43300 eventUtil.addEventListener(container, 'touchend', preventDefault);
\r
43302 function preventDefault(e) {
\r
43303 if (contains(e.target)) {
\r
43304 e.preventDefault();
\r
43308 function contains(targetEl) {
\r
43309 while (targetEl && targetEl !== container) {
\r
43310 if (targetEl === tooltipContentEl) {
\r
43313 targetEl = targetEl.parentNode;
\r
43318 TooltipContent.prototype = {
\r
43320 constructor: TooltipContent,
\r
43325 * Update when tooltip is rendered
\r
43327 update: function () {
\r
43328 var container = this._container;
\r
43329 var stl = container.currentStyle
\r
43330 || document.defaultView.getComputedStyle(container);
\r
43331 var domStyle = container.style;
\r
43332 if (domStyle.position !== 'absolute' && stl.position !== 'absolute') {
\r
43333 domStyle.position = 'relative';
\r
43335 // Hide the tooltip
\r
43340 show: function (tooltipModel) {
\r
43341 clearTimeout(this._hideTimeout);
\r
43343 this.el.style.cssText = gCssText + assembleCssText(tooltipModel)
\r
43344 // http://stackoverflow.com/questions/21125587/css3-transition-not-working-in-chrome-anymore
\r
43345 + ';left:' + this._x + 'px;top:' + this._y + 'px;'
\r
43346 + (tooltipModel.get('extraCssText') || '');
\r
43348 this._show = true;
\r
43351 setContent: function (content) {
\r
43352 var el = this.el;
\r
43353 el.innerHTML = content;
\r
43354 el.style.display = content ? 'block' : 'none';
\r
43357 moveTo: function (x, y) {
\r
43358 var style = this.el.style;
\r
43359 style.left = x + 'px';
\r
43360 style.top = y + 'px';
\r
43366 hide: function () {
\r
43367 this.el.style.display = 'none';
\r
43368 this._show = false;
\r
43371 // showLater: function ()
\r
43373 hideLater: function (time) {
\r
43374 if (this._show && !(this._inContent && this.enterable)) {
\r
43376 this._hideDelay = time;
\r
43377 // Set show false to avoid invoke hideLater mutiple times
\r
43378 this._show = false;
\r
43379 this._hideTimeout = setTimeout(zrUtil.bind(this.hide, this), time);
\r
43387 isShow: function () {
\r
43388 return this._show;
\r
43392 module.exports = TooltipContent;
\r
43397 /***/ function(module, exports, __webpack_require__) {
\r
43402 __webpack_require__(273);
\r
43403 __webpack_require__(279);
\r
43404 __webpack_require__(281);
\r
43407 __webpack_require__(1).extendComponentView({
\r
43414 /***/ function(module, exports, __webpack_require__) {
\r
43416 // TODO Axis scale
\r
43419 var Polar = __webpack_require__(274);
\r
43420 var numberUtil = __webpack_require__(7);
\r
43422 var axisHelper = __webpack_require__(108);
\r
43423 var niceScaleExtent = axisHelper.niceScaleExtent;
\r
43425 // 依赖 PolarModel 做预处理
\r
43426 __webpack_require__(277);
\r
43429 * Resize method bound to the polar
\r
43430 * @param {module:echarts/coord/polar/PolarModel} polarModel
\r
43431 * @param {module:echarts/ExtensionAPI} api
\r
43433 function resizePolar(polarModel, api) {
\r
43434 var center = polarModel.get('center');
\r
43435 var radius = polarModel.get('radius');
\r
43436 var width = api.getWidth();
\r
43437 var height = api.getHeight();
\r
43438 var parsePercent = numberUtil.parsePercent;
\r
43440 this.cx = parsePercent(center[0], width);
\r
43441 this.cy = parsePercent(center[1], height);
\r
43443 var radiusAxis = this.getRadiusAxis();
\r
43444 var size = Math.min(width, height) / 2;
\r
43445 // var idx = radiusAxis.inverse ? 1 : 0;
\r
43446 radiusAxis.setExtent(0, parsePercent(radius, size));
\r
43452 function updatePolarScale(ecModel, api) {
\r
43453 var polar = this;
\r
43454 var angleAxis = polar.getAngleAxis();
\r
43455 var radiusAxis = polar.getRadiusAxis();
\r
43457 angleAxis.scale.setExtent(Infinity, -Infinity);
\r
43458 radiusAxis.scale.setExtent(Infinity, -Infinity);
\r
43460 ecModel.eachSeries(function (seriesModel) {
\r
43461 if (seriesModel.coordinateSystem === polar) {
\r
43462 var data = seriesModel.getData();
\r
43463 radiusAxis.scale.unionExtent(
\r
43464 data.getDataExtent('radius', radiusAxis.type !== 'category')
\r
43466 angleAxis.scale.unionExtent(
\r
43467 data.getDataExtent('angle', angleAxis.type !== 'category')
\r
43472 niceScaleExtent(angleAxis, angleAxis.model);
\r
43473 niceScaleExtent(radiusAxis, radiusAxis.model);
\r
43475 // Fix extent of category angle axis
\r
43476 if (angleAxis.type === 'category' && !angleAxis.onBand) {
\r
43477 var extent = angleAxis.getExtent();
\r
43478 var diff = 360 / angleAxis.scale.count();
\r
43479 angleAxis.inverse ? (extent[1] += diff) : (extent[1] -= diff);
\r
43480 angleAxis.setExtent(extent[0], extent[1]);
\r
43485 * Set common axis properties
\r
43486 * @param {module:echarts/coord/polar/AngleAxis|module:echarts/coord/polar/RadiusAxis}
\r
43487 * @param {module:echarts/coord/polar/AxisModel}
\r
43490 function setAxis(axis, axisModel) {
\r
43491 axis.type = axisModel.get('type');
\r
43492 axis.scale = axisHelper.createScaleByModel(axisModel);
\r
43493 axis.onBand = axisModel.get('boundaryGap') && axis.type === 'category';
\r
43495 // FIXME Radius axis not support inverse axis
\r
43496 if (axisModel.mainType === 'angleAxis') {
\r
43497 var startAngle = axisModel.get('startAngle');
\r
43498 axis.inverse = axisModel.get('inverse') ^ axisModel.get('clockwise');
\r
43499 axis.setExtent(startAngle, startAngle + (axis.inverse ? -360 : 360));
\r
43502 // Inject axis instance
\r
43503 axisModel.axis = axis;
\r
43504 axis.model = axisModel;
\r
43508 var polarCreator = {
\r
43510 dimensions: Polar.prototype.dimensions,
\r
43512 create: function (ecModel, api) {
\r
43513 var polarList = [];
\r
43514 ecModel.eachComponent('polar', function (polarModel, idx) {
\r
43515 var polar = new Polar(idx);
\r
43516 // Inject resize and update method
\r
43517 polar.resize = resizePolar;
\r
43518 polar.update = updatePolarScale;
\r
43520 var radiusAxis = polar.getRadiusAxis();
\r
43521 var angleAxis = polar.getAngleAxis();
\r
43523 var radiusAxisModel = polarModel.findAxisModel('radiusAxis');
\r
43524 var angleAxisModel = polarModel.findAxisModel('angleAxis');
\r
43526 setAxis(radiusAxis, radiusAxisModel);
\r
43527 setAxis(angleAxis, angleAxisModel);
\r
43529 polar.resize(polarModel, api);
\r
43530 polarList.push(polar);
\r
43532 polarModel.coordinateSystem = polar;
\r
43534 // Inject coordinateSystem to series
\r
43535 ecModel.eachSeries(function (seriesModel) {
\r
43536 if (seriesModel.get('coordinateSystem') === 'polar') {
\r
43537 seriesModel.coordinateSystem = polarList[seriesModel.get('polarIndex')];
\r
43541 return polarList;
\r
43545 __webpack_require__(25).register('polar', polarCreator);
\r
43550 /***/ function(module, exports, __webpack_require__) {
\r
43554 * @module echarts/coord/polar/Polar
\r
43558 var RadiusAxis = __webpack_require__(275);
\r
43559 var AngleAxis = __webpack_require__(276);
\r
43562 * @alias {module:echarts/coord/polar/Polar}
\r
43564 * @param {string} name
\r
43566 var Polar = function (name) {
\r
43571 this.name = name || '';
\r
43574 * x of polar center
\r
43580 * y of polar center
\r
43586 * @type {module:echarts/coord/polar/RadiusAxis}
\r
43589 this._radiusAxis = new RadiusAxis();
\r
43592 * @type {module:echarts/coord/polar/AngleAxis}
\r
43595 this._angleAxis = new AngleAxis();
\r
43598 Polar.prototype = {
\r
43600 constructor: Polar,
\r
43605 * @param {Array.<string>}
\r
43608 dimensions: ['radius', 'angle'],
\r
43611 * If contain coord
\r
43612 * @param {Array.<number>} point
\r
43613 * @return {boolean}
\r
43615 containPoint: function (point) {
\r
43616 var coord = this.pointToCoord(point);
\r
43617 return this._radiusAxis.contain(coord[0])
\r
43618 && this._angleAxis.contain(coord[1]);
\r
43622 * If contain data
\r
43623 * @param {Array.<number>} data
\r
43624 * @return {boolean}
\r
43626 containData: function (data) {
\r
43627 return this._radiusAxis.containData(data[0])
\r
43628 && this._angleAxis.containData(data[1]);
\r
43632 * @param {string} axisType
\r
43633 * @return {module:echarts/coord/polar/AngleAxis|module:echarts/coord/polar/RadiusAxis}
\r
43635 getAxis: function (axisType) {
\r
43636 return this['_' + axisType + 'Axis'];
\r
43640 * Get axes by type of scale
\r
43641 * @param {string} scaleType
\r
43642 * @return {module:echarts/coord/polar/AngleAxis|module:echarts/coord/polar/RadiusAxis}
\r
43644 getAxesByScale: function (scaleType) {
\r
43646 var angleAxis = this._angleAxis;
\r
43647 var radiusAxis = this._radiusAxis;
\r
43648 angleAxis.scale.type === scaleType && axes.push(angleAxis);
\r
43649 radiusAxis.scale.type === scaleType && axes.push(radiusAxis);
\r
43655 * @return {module:echarts/coord/polar/AngleAxis}
\r
43657 getAngleAxis: function () {
\r
43658 return this._angleAxis;
\r
43662 * @return {module:echarts/coord/polar/RadiusAxis}
\r
43664 getRadiusAxis: function () {
\r
43665 return this._radiusAxis;
\r
43669 * @param {module:echarts/coord/polar/Axis}
\r
43670 * @return {module:echarts/coord/polar/Axis}
\r
43672 getOtherAxis: function (axis) {
\r
43673 var angleAxis = this._angleAxis;
\r
43674 return axis === angleAxis ? this._radiusAxis : angleAxis;
\r
43678 * Base axis will be used on stacking.
\r
43680 * @return {module:echarts/coord/polar/Axis}
\r
43682 getBaseAxis: function () {
\r
43683 return this.getAxesByScale('ordinal')[0]
\r
43684 || this.getAxesByScale('time')[0]
\r
43685 || this.getAngleAxis();
\r
43689 * Convert series data to a list of (x, y) points
\r
43690 * @param {module:echarts/data/List} data
\r
43691 * @return {Array}
\r
43692 * Return list of coordinates. For example:
\r
43693 * `[[10, 10], [20, 20], [30, 30]]`
\r
43695 dataToPoints: function (data) {
\r
43696 return data.mapArray(this.dimensions, function (radius, angle) {
\r
43697 return this.dataToPoint([radius, angle]);
\r
43702 * Convert a single data item to (x, y) point.
\r
43703 * Parameter data is an array which the first element is radius and the second is angle
\r
43704 * @param {Array.<number>} data
\r
43705 * @param {boolean} [clamp=false]
\r
43706 * @return {Array.<number>}
\r
43708 dataToPoint: function (data, clamp) {
\r
43709 return this.coordToPoint([
\r
43710 this._radiusAxis.dataToRadius(data[0], clamp),
\r
43711 this._angleAxis.dataToAngle(data[1], clamp)
\r
43716 * Convert a (x, y) point to data
\r
43717 * @param {Array.<number>} point
\r
43718 * @param {boolean} [clamp=false]
\r
43719 * @return {Array.<number>}
\r
43721 pointToData: function (point, clamp) {
\r
43722 var coord = this.pointToCoord(point);
\r
43724 this._radiusAxis.radiusToData(coord[0], clamp),
\r
43725 this._angleAxis.angleToData(coord[1], clamp)
\r
43730 * Convert a (x, y) point to (radius, angle) coord
\r
43731 * @param {Array.<number>} point
\r
43732 * @return {Array.<number>}
\r
43734 pointToCoord: function (point) {
\r
43735 var dx = point[0] - this.cx;
\r
43736 var dy = point[1] - this.cy;
\r
43737 var angleAxis = this.getAngleAxis();
\r
43738 var extent = angleAxis.getExtent();
\r
43739 var minAngle = Math.min(extent[0], extent[1]);
\r
43740 var maxAngle = Math.max(extent[0], extent[1]);
\r
43741 // Fix fixed extent in polarCreator
\r
43743 angleAxis.inverse
\r
43744 ? (minAngle = maxAngle - 360)
\r
43745 : (maxAngle = minAngle + 360);
\r
43747 var radius = Math.sqrt(dx * dx + dy * dy);
\r
43751 var radian = Math.atan2(-dy, dx) / Math.PI * 180;
\r
43753 // move to angleExtent
\r
43754 var dir = radian < minAngle ? 1 : -1;
\r
43755 while (radian < minAngle || radian > maxAngle) {
\r
43756 radian += dir * 360;
\r
43759 return [radius, radian];
\r
43763 * Convert a (radius, angle) coord to (x, y) point
\r
43764 * @param {Array.<number>} coord
\r
43765 * @return {Array.<number>}
\r
43767 coordToPoint: function (coord) {
\r
43768 var radius = coord[0];
\r
43769 var radian = coord[1] / 180 * Math.PI;
\r
43770 var x = Math.cos(radian) * radius + this.cx;
\r
43772 var y = -Math.sin(radian) * radius + this.cy;
\r
43778 module.exports = Polar;
\r
43783 /***/ function(module, exports, __webpack_require__) {
\r
43788 var zrUtil = __webpack_require__(3);
\r
43789 var Axis = __webpack_require__(117);
\r
43791 function RadiusAxis(scale, radiusExtent) {
\r
43793 Axis.call(this, 'radius', scale, radiusExtent);
\r
43803 this.type = 'category';
\r
43806 RadiusAxis.prototype = {
\r
43808 constructor: RadiusAxis,
\r
43810 dataToRadius: Axis.prototype.dataToCoord,
\r
43812 radiusToData: Axis.prototype.coordToData
\r
43815 zrUtil.inherits(RadiusAxis, Axis);
\r
43817 module.exports = RadiusAxis;
\r
43822 /***/ function(module, exports, __webpack_require__) {
\r
43827 var zrUtil = __webpack_require__(3);
\r
43828 var Axis = __webpack_require__(117);
\r
43830 function AngleAxis(scale, angleExtent) {
\r
43832 angleExtent = angleExtent || [0, 360];
\r
43834 Axis.call(this, 'angle', scale, angleExtent);
\r
43844 this.type = 'category';
\r
43847 AngleAxis.prototype = {
\r
43849 constructor: AngleAxis,
\r
43851 dataToAngle: Axis.prototype.dataToCoord,
\r
43853 angleToData: Axis.prototype.coordToData
\r
43856 zrUtil.inherits(AngleAxis, Axis);
\r
43858 module.exports = AngleAxis;
\r
43863 /***/ function(module, exports, __webpack_require__) {
\r
43868 __webpack_require__(278);
\r
43870 __webpack_require__(1).extendComponentModel({
\r
43874 dependencies: ['polarAxis', 'angleAxis'],
\r
43877 * @type {module:echarts/coord/polar/Polar}
\r
43879 coordinateSystem: null,
\r
43882 * @param {string} axisType
\r
43883 * @return {module:echarts/coord/polar/AxisModel}
\r
43885 findAxisModel: function (axisType) {
\r
43886 var angleAxisModel;
\r
43887 var ecModel = this.ecModel;
\r
43888 ecModel.eachComponent(axisType, function (axisModel) {
\r
43889 if (ecModel.getComponent(
\r
43890 'polar', axisModel.getShallow('polarIndex')
\r
43892 angleAxisModel = axisModel;
\r
43895 return angleAxisModel;
\r
43904 center: ['50%', '50%'],
\r
43913 /***/ function(module, exports, __webpack_require__) {
\r
43918 var zrUtil = __webpack_require__(3);
\r
43919 var ComponentModel = __webpack_require__(19);
\r
43920 var axisModelCreator = __webpack_require__(121);
\r
43922 var PolarAxisModel = ComponentModel.extend({
\r
43923 type: 'polarAxis',
\r
43925 * @type {module:echarts/coord/polar/AngleAxis|module:echarts/coord/polar/RadiusAxis}
\r
43930 zrUtil.merge(PolarAxisModel.prototype, __webpack_require__(123));
\r
43932 var polarAxisDefaultExtendedOption = {
\r
43953 function getAxisType(axisDim, option) {
\r
43954 // Default axis with data is category axis
\r
43955 return option.type || (option.data ? 'category' : 'value');
\r
43958 axisModelCreator('angle', PolarAxisModel, getAxisType, polarAxisDefaultExtendedOption.angle);
\r
43959 axisModelCreator('radius', PolarAxisModel, getAxisType, polarAxisDefaultExtendedOption.radius);
\r
43965 /***/ function(module, exports, __webpack_require__) {
\r
43970 __webpack_require__(273);
\r
43972 __webpack_require__(280);
\r
43977 /***/ function(module, exports, __webpack_require__) {
\r
43982 var zrUtil = __webpack_require__(3);
\r
43983 var graphic = __webpack_require__(42);
\r
43984 var Model = __webpack_require__(8);
\r
43986 var elementList = ['axisLine', 'axisLabel', 'axisTick', 'splitLine', 'splitArea'];
\r
43988 function getAxisLineShape(polar, r0, r, angle) {
\r
43989 var start = polar.coordToPoint([r0, angle]);
\r
43990 var end = polar.coordToPoint([r, angle]);
\r
43999 __webpack_require__(1).extendComponentView({
\r
44001 type: 'angleAxis',
\r
44003 render: function (angleAxisModel, ecModel) {
\r
44004 this.group.removeAll();
\r
44005 if (!angleAxisModel.get('show')) {
\r
44009 var polarModel = ecModel.getComponent('polar', angleAxisModel.get('polarIndex'));
\r
44010 var angleAxis = angleAxisModel.axis;
\r
44011 var polar = polarModel.coordinateSystem;
\r
44012 var radiusExtent = polar.getRadiusAxis().getExtent();
\r
44013 var ticksAngles = angleAxis.getTicksCoords();
\r
44015 if (angleAxis.type !== 'category') {
\r
44016 // Remove the last tick which will overlap the first tick
\r
44017 ticksAngles.pop();
\r
44020 zrUtil.each(elementList, function (name) {
\r
44021 if (angleAxisModel.get(name +'.show')) {
\r
44022 this['_' + name](angleAxisModel, polar, ticksAngles, radiusExtent);
\r
44030 _axisLine: function (angleAxisModel, polar, ticksAngles, radiusExtent) {
\r
44031 var lineStyleModel = angleAxisModel.getModel('axisLine.lineStyle');
\r
44033 var circle = new graphic.Circle({
\r
44037 r: radiusExtent[1]
\r
44039 style: lineStyleModel.getLineStyle(),
\r
44043 circle.style.fill = null;
\r
44045 this.group.add(circle);
\r
44051 _axisTick: function (angleAxisModel, polar, ticksAngles, radiusExtent) {
\r
44052 var tickModel = angleAxisModel.getModel('axisTick');
\r
44054 var tickLen = (tickModel.get('inside') ? -1 : 1) * tickModel.get('length');
\r
44056 var lines = zrUtil.map(ticksAngles, function (tickAngle) {
\r
44057 return new graphic.Line({
\r
44058 shape: getAxisLineShape(polar, radiusExtent[1], radiusExtent[1] + tickLen, tickAngle)
\r
44061 this.group.add(graphic.mergePath(
\r
44063 style: tickModel.getModel('lineStyle').getLineStyle()
\r
44071 _axisLabel: function (angleAxisModel, polar, ticksAngles, radiusExtent) {
\r
44072 var axis = angleAxisModel.axis;
\r
44074 var categoryData = angleAxisModel.get('data');
\r
44076 var labelModel = angleAxisModel.getModel('axisLabel');
\r
44077 var axisTextStyleModel = labelModel.getModel('textStyle');
\r
44079 var labels = angleAxisModel.getFormattedLabels();
\r
44081 var labelMargin = labelModel.get('margin');
\r
44082 var labelsAngles = axis.getLabelsCoords();
\r
44084 // Use length of ticksAngles because it may remove the last tick to avoid overlapping
\r
44085 for (var i = 0; i < ticksAngles.length; i++) {
\r
44086 var r = radiusExtent[1];
\r
44087 var p = polar.coordToPoint([r + labelMargin, labelsAngles[i]]);
\r
44088 var cx = polar.cx;
\r
44089 var cy = polar.cy;
\r
44091 var labelTextAlign = Math.abs(p[0] - cx) / r < 0.3
\r
44092 ? 'center' : (p[0] > cx ? 'left' : 'right');
\r
44093 var labelTextBaseline = Math.abs(p[1] - cy) / r < 0.3
\r
44094 ? 'middle' : (p[1] > cy ? 'top' : 'bottom');
\r
44096 var textStyleModel = axisTextStyleModel;
\r
44097 if (categoryData && categoryData[i] && categoryData[i].textStyle) {
\r
44098 textStyleModel = new Model(
\r
44099 categoryData[i].textStyle, axisTextStyleModel
\r
44102 this.group.add(new graphic.Text({
\r
44106 fill: textStyleModel.getTextColor(),
\r
44108 textAlign: labelTextAlign,
\r
44109 textVerticalAlign: labelTextBaseline,
\r
44110 textFont: textStyleModel.getFont()
\r
44120 _splitLine: function (angleAxisModel, polar, ticksAngles, radiusExtent) {
\r
44121 var splitLineModel = angleAxisModel.getModel('splitLine');
\r
44122 var lineStyleModel = splitLineModel.getModel('lineStyle');
\r
44123 var lineColors = lineStyleModel.get('color');
\r
44124 var lineCount = 0;
\r
44126 lineColors = lineColors instanceof Array ? lineColors : [lineColors];
\r
44128 var splitLines = [];
\r
44130 for (var i = 0; i < ticksAngles.length; i++) {
\r
44131 var colorIndex = (lineCount++) % lineColors.length;
\r
44132 splitLines[colorIndex] = splitLines[colorIndex] || [];
\r
44133 splitLines[colorIndex].push(new graphic.Line({
\r
44134 shape: getAxisLineShape(polar, radiusExtent[0], radiusExtent[1], ticksAngles[i])
\r
44138 // Simple optimization
\r
44139 // Batching the lines if color are the same
\r
44140 for (var i = 0; i < splitLines.length; i++) {
\r
44141 this.group.add(graphic.mergePath(splitLines[i], {
\r
44142 style: zrUtil.defaults({
\r
44143 stroke: lineColors[i % lineColors.length]
\r
44144 }, lineStyleModel.getLineStyle()),
\r
44146 z: angleAxisModel.get('z')
\r
44154 _splitArea: function (angleAxisModel, polar, ticksAngles, radiusExtent) {
\r
44156 var splitAreaModel = angleAxisModel.getModel('splitArea');
\r
44157 var areaStyleModel = splitAreaModel.getModel('areaStyle');
\r
44158 var areaColors = areaStyleModel.get('color');
\r
44159 var lineCount = 0;
\r
44161 areaColors = areaColors instanceof Array ? areaColors : [areaColors];
\r
44163 var splitAreas = [];
\r
44165 var RADIAN = Math.PI / 180;
\r
44166 var prevAngle = -ticksAngles[0] * RADIAN;
\r
44167 var r0 = Math.min(radiusExtent[0], radiusExtent[1]);
\r
44168 var r1 = Math.max(radiusExtent[0], radiusExtent[1]);
\r
44170 var clockwise = angleAxisModel.get('clockwise');
\r
44172 for (var i = 1; i < ticksAngles.length; i++) {
\r
44173 var colorIndex = (lineCount++) % areaColors.length;
\r
44174 splitAreas[colorIndex] = splitAreas[colorIndex] || [];
\r
44175 splitAreas[colorIndex].push(new graphic.Sector({
\r
44181 startAngle: prevAngle,
\r
44182 endAngle: -ticksAngles[i] * RADIAN,
\r
44183 clockwise: clockwise
\r
44187 prevAngle = -ticksAngles[i] * RADIAN;
\r
44190 // Simple optimization
\r
44191 // Batching the lines if color are the same
\r
44192 for (var i = 0; i < splitAreas.length; i++) {
\r
44193 this.group.add(graphic.mergePath(splitAreas[i], {
\r
44194 style: zrUtil.defaults({
\r
44195 fill: areaColors[i % areaColors.length]
\r
44196 }, areaStyleModel.getAreaStyle()),
\r
44206 /***/ function(module, exports, __webpack_require__) {
\r
44210 __webpack_require__(273);
\r
44212 __webpack_require__(282);
\r
44217 /***/ function(module, exports, __webpack_require__) {
\r
44222 var zrUtil = __webpack_require__(3);
\r
44223 var graphic = __webpack_require__(42);
\r
44224 var AxisBuilder = __webpack_require__(126);
\r
44226 var axisBuilderAttrs = [
\r
44227 'axisLine', 'axisLabel', 'axisTick', 'axisName'
\r
44229 var selfBuilderAttrs = [
\r
44230 'splitLine', 'splitArea'
\r
44233 __webpack_require__(1).extendComponentView({
\r
44235 type: 'radiusAxis',
\r
44237 render: function (radiusAxisModel, ecModel) {
\r
44238 this.group.removeAll();
\r
44239 if (!radiusAxisModel.get('show')) {
\r
44242 var polarModel = ecModel.getComponent('polar', radiusAxisModel.get('polarIndex'));
\r
44243 var angleAxis = polarModel.coordinateSystem.getAngleAxis();
\r
44244 var radiusAxis = radiusAxisModel.axis;
\r
44245 var polar = polarModel.coordinateSystem;
\r
44246 var ticksCoords = radiusAxis.getTicksCoords();
\r
44247 var axisAngle = angleAxis.getExtent()[0];
\r
44248 var radiusExtent = radiusAxis.getExtent();
\r
44250 var layout = layoutAxis(polar, radiusAxisModel, axisAngle);
\r
44251 var axisBuilder = new AxisBuilder(radiusAxisModel, layout);
\r
44252 zrUtil.each(axisBuilderAttrs, axisBuilder.add, axisBuilder);
\r
44253 this.group.add(axisBuilder.getGroup());
\r
44255 zrUtil.each(selfBuilderAttrs, function (name) {
\r
44256 if (radiusAxisModel.get(name +'.show')) {
\r
44257 this['_' + name](radiusAxisModel, polar, axisAngle, radiusExtent, ticksCoords);
\r
44265 _splitLine: function (radiusAxisModel, polar, axisAngle, radiusExtent, ticksCoords) {
\r
44266 var splitLineModel = radiusAxisModel.getModel('splitLine');
\r
44267 var lineStyleModel = splitLineModel.getModel('lineStyle');
\r
44268 var lineColors = lineStyleModel.get('color');
\r
44269 var lineCount = 0;
\r
44271 lineColors = lineColors instanceof Array ? lineColors : [lineColors];
\r
44273 var splitLines = [];
\r
44275 for (var i = 0; i < ticksCoords.length; i++) {
\r
44276 var colorIndex = (lineCount++) % lineColors.length;
\r
44277 splitLines[colorIndex] = splitLines[colorIndex] || [];
\r
44278 splitLines[colorIndex].push(new graphic.Circle({
\r
44282 r: ticksCoords[i]
\r
44288 // Simple optimization
\r
44289 // Batching the lines if color are the same
\r
44290 for (var i = 0; i < splitLines.length; i++) {
\r
44291 this.group.add(graphic.mergePath(splitLines[i], {
\r
44292 style: zrUtil.defaults({
\r
44293 stroke: lineColors[i % lineColors.length],
\r
44295 }, lineStyleModel.getLineStyle()),
\r
44304 _splitArea: function (radiusAxisModel, polar, axisAngle, radiusExtent, ticksCoords) {
\r
44306 var splitAreaModel = radiusAxisModel.getModel('splitArea');
\r
44307 var areaStyleModel = splitAreaModel.getModel('areaStyle');
\r
44308 var areaColors = areaStyleModel.get('color');
\r
44309 var lineCount = 0;
\r
44311 areaColors = areaColors instanceof Array ? areaColors : [areaColors];
\r
44313 var splitAreas = [];
\r
44315 var prevRadius = ticksCoords[0];
\r
44316 for (var i = 1; i < ticksCoords.length; i++) {
\r
44317 var colorIndex = (lineCount++) % areaColors.length;
\r
44318 splitAreas[colorIndex] = splitAreas[colorIndex] || [];
\r
44319 splitAreas[colorIndex].push(new graphic.Sector({
\r
44324 r: ticksCoords[i],
\r
44326 endAngle: Math.PI * 2
\r
44330 prevRadius = ticksCoords[i];
\r
44333 // Simple optimization
\r
44334 // Batching the lines if color are the same
\r
44335 for (var i = 0; i < splitAreas.length; i++) {
\r
44336 this.group.add(graphic.mergePath(splitAreas[i], {
\r
44337 style: zrUtil.defaults({
\r
44338 fill: areaColors[i % areaColors.length]
\r
44339 }, areaStyleModel.getAreaStyle()),
\r
44349 function layoutAxis(polar, radiusAxisModel, axisAngle) {
\r
44351 position: [polar.cx, polar.cy],
\r
44352 rotation: axisAngle / 180 * Math.PI,
\r
44353 labelDirection: -1,
\r
44354 tickDirection: -1,
\r
44355 nameDirection: 1,
\r
44356 labelRotation: radiusAxisModel.getModel('axisLabel').get('rotate'),
\r
44357 // Over splitLine and splitArea
\r
44365 /***/ function(module, exports, __webpack_require__) {
\r
44369 __webpack_require__(163);
\r
44371 __webpack_require__(284);
\r
44373 __webpack_require__(161);
\r
44378 /***/ function(module, exports, __webpack_require__) {
\r
44383 var MapDraw = __webpack_require__(158);
\r
44385 module.exports = __webpack_require__(1).extendComponentView({
\r
44389 init: function (ecModel, api) {
\r
44390 var mapDraw = new MapDraw(api, true);
\r
44391 this._mapDraw = mapDraw;
\r
44393 this.group.add(mapDraw.group);
\r
44396 render: function (geoModel, ecModel, api) {
\r
44397 geoModel.get('show') &&
\r
44398 this._mapDraw.draw(geoModel, ecModel, api);
\r
44405 /***/ function(module, exports, __webpack_require__) {
\r
44410 var echarts = __webpack_require__(1);
\r
44411 var graphic = __webpack_require__(42);
\r
44412 var layout = __webpack_require__(21);
\r
44415 echarts.extendComponentModel({
\r
44419 layoutMode: {type: 'box', ignoreSize: true},
\r
44431 // 仅支持self | blank
\r
44436 // sublink: null,
\r
44437 // 仅支持self | blank
\r
44438 subtarget: 'blank',
\r
44440 // 'center' ¦ 'left' ¦ 'right'
\r
44441 // ¦ {number}(x坐标,单位px)
\r
44443 // 'top' ¦ 'bottom' ¦ 'center'
\r
44444 // ¦ {number}(y坐标,单位px)
\r
44448 // 'auto' | 'left' | 'right'
\r
44449 // 默认根据 x 的位置判断是左对齐还是右对齐
\r
44450 //textAlign: null
\r
44452 backgroundColor: 'rgba(0,0,0,0)',
\r
44455 borderColor: '#ccc',
\r
44457 // 标题边框线宽,单位px,默认为0(无边框)
\r
44460 // 标题内边距,单位px,默认各方向内边距为5,
\r
44461 // 接受数组分别设定上右下左边距,同css
\r
44464 // 主副标题纵向间隔,单位px,默认为10,
\r
44468 fontWeight: 'bolder',
\r
44480 echarts.extendComponentView({
\r
44484 render: function (titleModel, ecModel, api) {
\r
44485 this.group.removeAll();
\r
44487 if (!titleModel.get('show')) {
\r
44491 var group = this.group;
\r
44493 var textStyleModel = titleModel.getModel('textStyle');
\r
44494 var subtextStyleModel = titleModel.getModel('subtextStyle');
\r
44496 var textAlign = titleModel.get('textAlign');
\r
44498 var textEl = new graphic.Text({
\r
44500 text: titleModel.get('text'),
\r
44501 textFont: textStyleModel.getFont(),
\r
44502 fill: textStyleModel.getTextColor(),
\r
44503 textBaseline: 'top'
\r
44508 var textRect = textEl.getBoundingRect();
\r
44510 var subText = titleModel.get('subtext');
\r
44511 var subTextEl = new graphic.Text({
\r
44514 textFont: subtextStyleModel.getFont(),
\r
44515 fill: subtextStyleModel.getTextColor(),
\r
44516 y: textRect.height + titleModel.get('itemGap'),
\r
44517 textBaseline: 'top'
\r
44522 var link = titleModel.get('link');
\r
44523 var sublink = titleModel.get('sublink');
\r
44525 textEl.silent = !link;
\r
44526 subTextEl.silent = !sublink;
\r
44529 textEl.on('click', function () {
\r
44530 window.open(link, titleModel.get('target'));
\r
44534 subTextEl.on('click', function () {
\r
44535 window.open(sublink, titleModel.get('subtarget'));
\r
44539 group.add(textEl);
\r
44540 subText && group.add(subTextEl);
\r
44541 // If no subText, but add subTextEl, there will be an empty line.
\r
44543 var groupRect = group.getBoundingRect();
\r
44544 var layoutOption = titleModel.getBoxLayoutParams();
\r
44545 layoutOption.width = groupRect.width;
\r
44546 layoutOption.height = groupRect.height;
\r
44547 var layoutRect = layout.getLayoutRect(
\r
44549 width: api.getWidth(),
\r
44550 height: api.getHeight()
\r
44551 }, titleModel.get('padding')
\r
44553 // Adjust text align based on position
\r
44554 if (!textAlign) {
\r
44555 // Align left if title is on the left. center and right is same
\r
44556 textAlign = titleModel.get('left') || titleModel.get('right');
\r
44557 if (textAlign === 'middle') {
\r
44558 textAlign = 'center';
\r
44560 // Adjust layout by text align
\r
44561 if (textAlign === 'right') {
\r
44562 layoutRect.x += layoutRect.width;
\r
44564 else if (textAlign === 'center') {
\r
44565 layoutRect.x += layoutRect.width / 2;
\r
44568 group.position = [layoutRect.x, layoutRect.y];
\r
44569 textEl.setStyle('textAlign', textAlign);
\r
44570 subTextEl.setStyle('textAlign', textAlign);
\r
44572 // Render background
\r
44573 // Get groupRect again because textAlign has been changed
\r
44574 groupRect = group.getBoundingRect();
\r
44575 var padding = layoutRect.margin;
\r
44576 var style = titleModel.getItemStyle(['color', 'opacity']);
\r
44577 style.fill = titleModel.get('backgroundColor');
\r
44578 var rect = new graphic.Rect({
\r
44580 x: groupRect.x - padding[3],
\r
44581 y: groupRect.y - padding[0],
\r
44582 width: groupRect.width + padding[1] + padding[3],
\r
44583 height: groupRect.height + padding[0] + padding[2]
\r
44588 graphic.subPixelOptimizeRect(rect);
\r
44597 /***/ function(module, exports, __webpack_require__) {
\r
44600 * DataZoom component entry
\r
44604 __webpack_require__(287);
\r
44606 __webpack_require__(288);
\r
44607 __webpack_require__(290);
\r
44609 __webpack_require__(291);
\r
44610 __webpack_require__(292);
\r
44612 __webpack_require__(295);
\r
44613 __webpack_require__(296);
\r
44615 __webpack_require__(298);
\r
44616 __webpack_require__(299);
\r
44622 /***/ function(module, exports, __webpack_require__) {
\r
44626 __webpack_require__(19).registerSubTypeDefaulter('dataZoom', function (option) {
\r
44627 // Default 'slider' when no type specified.
\r
44635 /***/ function(module, exports, __webpack_require__) {
\r
44638 * @file Data zoom model
\r
44642 var zrUtil = __webpack_require__(3);
\r
44643 var env = __webpack_require__(78);
\r
44644 var echarts = __webpack_require__(1);
\r
44645 var modelUtil = __webpack_require__(5);
\r
44646 var AxisProxy = __webpack_require__(289);
\r
44647 var each = zrUtil.each;
\r
44648 var eachAxisDim = modelUtil.eachAxisDim;
\r
44650 var DataZoomModel = echarts.extendComponentModel({
\r
44652 type: 'dataZoom',
\r
44655 'xAxis', 'yAxis', 'zAxis', 'radiusAxis', 'angleAxis', 'series'
\r
44663 z: 4, // Higher than normal component (z: 2).
\r
44664 orient: null, // Default auto by axisIndex. Possible value: 'horizontal', 'vertical'.
\r
44665 xAxisIndex: null, // Default all horizontal category axis.
\r
44666 yAxisIndex: null, // Default all vertical category axis.
\r
44667 angleAxisIndex: null,
\r
44668 radiusAxisIndex: null,
\r
44669 filterMode: 'filter', // Possible values: 'filter' or 'empty'.
\r
44670 // 'filter': data items which are out of window will be removed.
\r
44671 // This option is applicable when filtering outliers.
\r
44672 // 'empty': data items which are out of window will be set to empty.
\r
44673 // This option is applicable when user should not neglect
\r
44674 // that there are some data items out of window.
\r
44675 // Taking line chart as an example, line will be broken in
\r
44676 // the filtered points when filterModel is set to 'empty', but
\r
44677 // be connected when set to 'filter'.
\r
44679 throttle: 100, // Dispatch action by the fixed rate, avoid frequency.
\r
44680 // default 100. Do not throttle when use null/undefined.
\r
44681 start: 0, // Start percent. 0 ~ 100
\r
44682 end: 100, // End percent. 0 ~ 100
\r
44683 startValue: null, // Start value. If startValue specified, start is ignored.
\r
44684 endValue: null // End value. If endValue specified, end is ignored.
\r
44690 init: function (option, parentModel, ecModel) {
\r
44693 * key like x_0, y_1
\r
44697 this._dataIntervalByAxis = {};
\r
44702 this._dataInfo = {};
\r
44705 * key like x_0, y_1
\r
44708 this._axisProxies = {};
\r
44713 this.textStyleModel;
\r
44715 var rawOption = retrieveRaw(option);
\r
44717 this.mergeDefaultAndTheme(option, ecModel);
\r
44719 this.doInit(rawOption);
\r
44725 mergeOption: function (newOption) {
\r
44726 var rawOption = retrieveRaw(newOption);
\r
44729 zrUtil.merge(this.option, newOption, true);
\r
44731 this.doInit(rawOption);
\r
44737 doInit: function (rawOption) {
\r
44738 var thisOption = this.option;
\r
44740 // Disable realtime view update if canvas is not supported.
\r
44741 if (!env.canvasSupported) {
\r
44742 thisOption.realtime = false;
\r
44745 processRangeProp('start', 'startValue', rawOption, thisOption);
\r
44746 processRangeProp('end', 'endValue', rawOption, thisOption);
\r
44748 this.textStyleModel = this.getModel('textStyle');
\r
44750 this._resetTarget();
\r
44752 this._giveAxisProxies();
\r
44758 _giveAxisProxies: function () {
\r
44759 var axisProxies = this._axisProxies;
\r
44761 this.eachTargetAxis(function (dimNames, axisIndex, dataZoomModel, ecModel) {
\r
44762 var axisModel = this.dependentModels[dimNames.axis][axisIndex];
\r
44764 // If exists, share axisProxy with other dataZoomModels.
\r
44765 var axisProxy = axisModel.__dzAxisProxy || (
\r
44766 // Use the first dataZoomModel as the main model of axisProxy.
\r
44767 axisModel.__dzAxisProxy = new AxisProxy(
\r
44768 dimNames.name, axisIndex, this, ecModel
\r
44772 // dispose __dzAxisProxy
\r
44774 axisProxies[dimNames.name + '_' + axisIndex] = axisProxy;
\r
44781 _resetTarget: function () {
\r
44782 var thisOption = this.option;
\r
44784 var autoMode = this._judgeAutoMode();
\r
44786 eachAxisDim(function (dimNames) {
\r
44787 var axisIndexName = dimNames.axisIndex;
\r
44788 thisOption[axisIndexName] = modelUtil.normalizeToArray(
\r
44789 thisOption[axisIndexName]
\r
44793 if (autoMode === 'axisIndex') {
\r
44794 this._autoSetAxisIndex();
\r
44796 else if (autoMode === 'orient') {
\r
44797 this._autoSetOrient();
\r
44804 _judgeAutoMode: function () {
\r
44805 // Auto set only works for setOption at the first time.
\r
44806 // The following is user's reponsibility. So using merged
\r
44808 var thisOption = this.option;
\r
44810 var hasIndexSpecified = false;
\r
44811 eachAxisDim(function (dimNames) {
\r
44812 // When user set axisIndex as a empty array, we think that user specify axisIndex
\r
44813 // but do not want use auto mode. Because empty array may be encountered when
\r
44814 // some error occured.
\r
44815 if (thisOption[dimNames.axisIndex] != null) {
\r
44816 hasIndexSpecified = true;
\r
44820 var orient = thisOption.orient;
\r
44822 if (orient == null && hasIndexSpecified) {
\r
44825 else if (!hasIndexSpecified) {
\r
44826 if (orient == null) {
\r
44827 thisOption.orient = 'horizontal';
\r
44829 return 'axisIndex';
\r
44836 _autoSetAxisIndex: function () {
\r
44837 var autoAxisIndex = true;
\r
44838 var orient = this.get('orient', true);
\r
44839 var thisOption = this.option;
\r
44841 if (autoAxisIndex) {
\r
44842 // Find axis that parallel to dataZoom as default.
\r
44843 var dimNames = orient === 'vertical'
\r
44844 ? {dim: 'y', axisIndex: 'yAxisIndex', axis: 'yAxis'}
\r
44845 : {dim: 'x', axisIndex: 'xAxisIndex', axis: 'xAxis'};
\r
44847 if (this.dependentModels[dimNames.axis].length) {
\r
44848 thisOption[dimNames.axisIndex] = [0];
\r
44849 autoAxisIndex = false;
\r
44853 if (autoAxisIndex) {
\r
44854 // Find the first category axis as default. (consider polar)
\r
44855 eachAxisDim(function (dimNames) {
\r
44856 if (!autoAxisIndex) {
\r
44859 var axisIndices = [];
\r
44860 var axisModels = this.dependentModels[dimNames.axis];
\r
44861 if (axisModels.length && !axisIndices.length) {
\r
44862 for (var i = 0, len = axisModels.length; i < len; i++) {
\r
44863 if (axisModels[i].get('type') === 'category') {
\r
44864 axisIndices.push(i);
\r
44868 thisOption[dimNames.axisIndex] = axisIndices;
\r
44869 if (axisIndices.length) {
\r
44870 autoAxisIndex = false;
\r
44875 if (autoAxisIndex) {
\r
44877 // 这里是兼容ec2的写法(没指定xAxisIndex和yAxisIndex时把scatter和双数值轴折柱纳入dataZoom控制),
\r
44878 // 但是实际是否需要Grid.js#getScaleByOption来判断(考虑time,log等axis type)?
\r
44880 // If both dataZoom.xAxisIndex and dataZoom.yAxisIndex is not specified,
\r
44881 // dataZoom component auto adopts series that reference to
\r
44882 // both xAxis and yAxis which type is 'value'.
\r
44883 this.ecModel.eachSeries(function (seriesModel) {
\r
44884 if (this._isSeriesHasAllAxesTypeOf(seriesModel, 'value')) {
\r
44885 eachAxisDim(function (dimNames) {
\r
44886 var axisIndices = thisOption[dimNames.axisIndex];
\r
44887 var axisIndex = seriesModel.get(dimNames.axisIndex);
\r
44888 if (zrUtil.indexOf(axisIndices, axisIndex) < 0) {
\r
44889 axisIndices.push(axisIndex);
\r
44900 _autoSetOrient: function () {
\r
44903 // Find the first axis
\r
44904 this.eachTargetAxis(function (dimNames) {
\r
44905 !dim && (dim = dimNames.name);
\r
44908 this.option.orient = dim === 'y' ? 'vertical' : 'horizontal';
\r
44914 _isSeriesHasAllAxesTypeOf: function (seriesModel, axisType) {
\r
44916 // 需要series的xAxisIndex和yAxisIndex都首先自动设置上。
\r
44917 // 例如series.type === scatter时。
\r
44920 eachAxisDim(function (dimNames) {
\r
44921 var seriesAxisIndex = seriesModel.get(dimNames.axisIndex);
\r
44922 var axisModel = this.dependentModels[dimNames.axis][seriesAxisIndex];
\r
44924 if (!axisModel || axisModel.get('type') !== axisType) {
\r
44934 getFirstTargetAxisModel: function () {
\r
44935 var firstAxisModel;
\r
44936 eachAxisDim(function (dimNames) {
\r
44937 if (firstAxisModel == null) {
\r
44938 var indices = this.get(dimNames.axisIndex);
\r
44939 if (indices.length) {
\r
44940 firstAxisModel = this.dependentModels[dimNames.axis][indices[0]];
\r
44945 return firstAxisModel;
\r
44950 * @param {Function} callback param: axisModel, dimNames, axisIndex, dataZoomModel, ecModel
\r
44952 eachTargetAxis: function (callback, context) {
\r
44953 var ecModel = this.ecModel;
\r
44954 eachAxisDim(function (dimNames) {
\r
44956 this.get(dimNames.axisIndex),
\r
44957 function (axisIndex) {
\r
44958 callback.call(context, dimNames, axisIndex, this, ecModel);
\r
44965 getAxisProxy: function (dimName, axisIndex) {
\r
44966 return this._axisProxies[dimName + '_' + axisIndex];
\r
44970 * If not specified, set to undefined.
\r
44973 * @param {Object} opt
\r
44974 * @param {number} [opt.start]
\r
44975 * @param {number} [opt.end]
\r
44976 * @param {number} [opt.startValue]
\r
44977 * @param {number} [opt.endValue]
\r
44979 setRawRange: function (opt) {
\r
44980 each(['start', 'end', 'startValue', 'endValue'], function (name) {
\r
44981 // If any of those prop is null/undefined, we should alos set
\r
44982 // them, because only one pair between start/end and
\r
44983 // startValue/endValue can work.
\r
44984 this.option[name] = opt[name];
\r
44990 * @return {Array.<number>} [startPercent, endPercent]
\r
44992 getPercentRange: function () {
\r
44993 var axisProxy = this.findRepresentativeAxisProxy();
\r
44995 return axisProxy.getDataPercentWindow();
\r
45001 * For example, chart.getModel().getComponent('dataZoom').getValueRange('y', 0);
\r
45003 * @param {string} [axisDimName]
\r
45004 * @param {number} [axisIndex]
\r
45005 * @return {Array.<number>} [startValue, endValue]
\r
45007 getValueRange: function (axisDimName, axisIndex) {
\r
45008 if (axisDimName == null && axisIndex == null) {
\r
45009 var axisProxy = this.findRepresentativeAxisProxy();
\r
45011 return axisProxy.getDataValueWindow();
\r
45015 return this.getAxisProxy(axisDimName, axisIndex).getDataValueWindow();
\r
45021 * @return {module:echarts/component/dataZoom/AxisProxy}
\r
45023 findRepresentativeAxisProxy: function () {
\r
45024 // Find the first hosted axisProxy
\r
45025 var axisProxies = this._axisProxies;
\r
45026 for (var key in axisProxies) {
\r
45027 if (axisProxies.hasOwnProperty(key) && axisProxies[key].hostedBy(this)) {
\r
45028 return axisProxies[key];
\r
45032 // If no hosted axis find not hosted axisProxy.
\r
45033 // Consider this case: dataZoomModel1 and dataZoomModel2 control the same axis,
\r
45034 // and the option.start or option.end settings are different. The percentRange
\r
45035 // should follow axisProxy.
\r
45036 // (We encounter this problem in toolbox data zoom.)
\r
45037 for (var key in axisProxies) {
\r
45038 if (axisProxies.hasOwnProperty(key) && !axisProxies[key].hostedBy(this)) {
\r
45039 return axisProxies[key];
\r
45046 function retrieveRaw(option) {
\r
45049 ['start', 'end', 'startValue', 'endValue'],
\r
45050 function (name) {
\r
45051 ret[name] = option[name];
\r
45057 function processRangeProp(percentProp, valueProp, rawOption, thisOption) {
\r
45058 // start/end has higher priority over startValue/endValue,
\r
45059 // but we should make chart.setOption({endValue: 1000}) effective,
\r
45060 // rather than chart.setOption({endValue: 1000, end: null}).
\r
45061 if (rawOption[valueProp] != null && rawOption[percentProp] == null) {
\r
45062 thisOption[percentProp] = null;
\r
45064 // Otherwise do nothing and use the merge result.
\r
45067 module.exports = DataZoomModel;
\r
45073 /***/ function(module, exports, __webpack_require__) {
\r
45076 * @file Axis operator
\r
45080 var zrUtil = __webpack_require__(3);
\r
45081 var numberUtil = __webpack_require__(7);
\r
45082 var each = zrUtil.each;
\r
45083 var asc = numberUtil.asc;
\r
45086 * Operate single axis.
\r
45087 * One axis can only operated by one axis operator.
\r
45088 * Different dataZoomModels may be defined to operate the same axis.
\r
45089 * (i.e. 'inside' data zoom and 'slider' data zoom components)
\r
45090 * So dataZoomModels share one axisProxy in that case.
\r
45094 var AxisProxy = function (dimName, axisIndex, dataZoomModel, ecModel) {
\r
45100 this._dimName = dimName;
\r
45105 this._axisIndex = axisIndex;
\r
45109 * @type {Array.<number>}
\r
45111 this._valueWindow;
\r
45115 * @type {Array.<number>}
\r
45117 this._percentWindow;
\r
45121 * @type {Array.<number>}
\r
45123 this._dataExtent;
\r
45127 * @type {module: echarts/model/Global}
\r
45129 this.ecModel = ecModel;
\r
45133 * @type {module: echarts/component/dataZoom/DataZoomModel}
\r
45135 this._dataZoomModel = dataZoomModel;
\r
45138 AxisProxy.prototype = {
\r
45140 constructor: AxisProxy,
\r
45143 * Whether the axisProxy is hosted by dataZoomModel.
\r
45146 * @param {module: echarts/component/dataZoom/DataZoomModel} dataZoomModel
\r
45147 * @return {boolean}
\r
45149 hostedBy: function (dataZoomModel) {
\r
45150 return this._dataZoomModel === dataZoomModel;
\r
45154 * @return {Array.<number>}
\r
45156 getDataExtent: function () {
\r
45157 return this._dataExtent.slice();
\r
45161 * @return {Array.<number>}
\r
45163 getDataValueWindow: function () {
\r
45164 return this._valueWindow.slice();
\r
45168 * @return {Array.<number>}
\r
45170 getDataPercentWindow: function () {
\r
45171 return this._percentWindow.slice();
\r
45176 * @param {number} axisIndex
\r
45177 * @return {Array} seriesModels
\r
45179 getTargetSeriesModels: function () {
\r
45180 var seriesModels = [];
\r
45182 this.ecModel.eachSeries(function (seriesModel) {
\r
45183 if (this._axisIndex === seriesModel.get(this._dimName + 'AxisIndex')) {
\r
45184 seriesModels.push(seriesModel);
\r
45188 return seriesModels;
\r
45191 getAxisModel: function () {
\r
45192 return this.ecModel.getComponent(this._dimName + 'Axis', this._axisIndex);
\r
45195 getOtherAxisModel: function () {
\r
45196 var axisDim = this._dimName;
\r
45197 var ecModel = this.ecModel;
\r
45198 var axisModel = this.getAxisModel();
\r
45199 var isCartesian = axisDim === 'x' || axisDim === 'y';
\r
45200 var otherAxisDim;
\r
45201 var coordSysIndexName;
\r
45202 if (isCartesian) {
\r
45203 coordSysIndexName = 'gridIndex';
\r
45204 otherAxisDim = axisDim === 'x' ? 'y' : 'x';
\r
45207 coordSysIndexName = 'polarIndex';
\r
45208 otherAxisDim = axisDim === 'angle' ? 'radius' : 'angle';
\r
45210 var foundOtherAxisModel;
\r
45211 ecModel.eachComponent(otherAxisDim + 'Axis', function (otherAxisModel) {
\r
45212 if ((otherAxisModel.get(coordSysIndexName) || 0)
\r
45213 === (axisModel.get(coordSysIndexName) || 0)) {
\r
45214 foundOtherAxisModel = otherAxisModel;
\r
45217 return foundOtherAxisModel;
\r
45221 * Notice: reset should not be called before series.restoreData() called,
\r
45222 * so it is recommanded to be called in "process stage" but not "model init
\r
45225 * @param {module: echarts/component/dataZoom/DataZoomModel} dataZoomModel
\r
45227 reset: function (dataZoomModel) {
\r
45228 if (dataZoomModel !== this._dataZoomModel) {
\r
45232 // Culculate data window and data extent, and record them.
\r
45233 var dataExtent = this._dataExtent = calculateDataExtent(
\r
45234 this._dimName, this.getTargetSeriesModels()
\r
45236 var dataWindow = calculateDataWindow(
\r
45237 dataZoomModel.option, dataExtent, this
\r
45239 this._valueWindow = dataWindow.valueWindow;
\r
45240 this._percentWindow = dataWindow.percentWindow;
\r
45242 // Update axis setting then.
\r
45243 setAxisModel(this);
\r
45247 * @param {module: echarts/component/dataZoom/DataZoomModel} dataZoomModel
\r
45249 restore: function (dataZoomModel) {
\r
45250 if (dataZoomModel !== this._dataZoomModel) {
\r
45254 this._valueWindow = this._percentWindow = null;
\r
45255 setAxisModel(this, true);
\r
45259 * @param {module: echarts/component/dataZoom/DataZoomModel} dataZoomModel
\r
45261 filterData: function (dataZoomModel) {
\r
45262 if (dataZoomModel !== this._dataZoomModel) {
\r
45266 var axisDim = this._dimName;
\r
45267 var seriesModels = this.getTargetSeriesModels();
\r
45268 var filterMode = dataZoomModel.get('filterMode');
\r
45269 var valueWindow = this._valueWindow;
\r
45272 // Toolbox may has dataZoom injected. And if there are stacked bar chart
\r
45273 // with NaN data. NaN will be filtered and stack will be wrong.
\r
45274 // So we need to force the mode to be set empty
\r
45275 var otherAxisModel = this.getOtherAxisModel();
\r
45276 if (dataZoomModel.get('$fromToolbox')
\r
45277 && otherAxisModel && otherAxisModel.get('type') === 'category') {
\r
45278 filterMode = 'empty';
\r
45280 // Process series data
\r
45281 each(seriesModels, function (seriesModel) {
\r
45282 var seriesData = seriesModel.getData();
\r
45283 if (!seriesData) {
\r
45287 each(seriesModel.coordDimToDataDim(axisDim), function (dim) {
\r
45288 if (filterMode === 'empty') {
\r
45289 seriesModel.setData(
\r
45290 seriesData.map(dim, function (value) {
\r
45291 return !isInWindow(value) ? NaN : value;
\r
45296 seriesData.filterSelf(dim, isInWindow);
\r
45301 function isInWindow(value) {
\r
45302 return value >= valueWindow[0] && value <= valueWindow[1];
\r
45307 function calculateDataExtent(axisDim, seriesModels) {
\r
45308 var dataExtent = [Infinity, -Infinity];
\r
45310 each(seriesModels, function (seriesModel) {
\r
45311 var seriesData = seriesModel.getData();
\r
45312 if (seriesData) {
\r
45313 each(seriesModel.coordDimToDataDim(axisDim), function (dim) {
\r
45314 var seriesExtent = seriesData.getDataExtent(dim);
\r
45315 seriesExtent[0] < dataExtent[0] && (dataExtent[0] = seriesExtent[0]);
\r
45316 seriesExtent[1] > dataExtent[1] && (dataExtent[1] = seriesExtent[1]);
\r
45321 return dataExtent;
\r
45324 function calculateDataWindow(opt, dataExtent, axisProxy) {
\r
45325 var axisModel = axisProxy.getAxisModel();
\r
45326 var scale = axisModel.axis.scale;
\r
45327 var percentExtent = [0, 100];
\r
45328 var percentWindow = [
\r
45332 var valueWindow = [];
\r
45334 // In percent range is used and axis min/max/scale is set,
\r
45335 // window should be based on min/max/0, but should not be
\r
45336 // based on the extent of filtered data.
\r
45337 dataExtent = dataExtent.slice();
\r
45338 fixExtendByAxis(dataExtent, axisModel, scale);
\r
45340 each(['startValue', 'endValue'], function (prop) {
\r
45341 valueWindow.push(
\r
45342 opt[prop] != null
\r
45343 ? scale.parse(opt[prop])
\r
45348 // Normalize bound.
\r
45349 each([0, 1], function (idx) {
\r
45350 var boundValue = valueWindow[idx];
\r
45351 var boundPercent = percentWindow[idx];
\r
45353 // start/end has higher priority over startValue/endValue,
\r
45354 // because start/end can be consistent among different type
\r
45355 // of axis but startValue/endValue not.
\r
45357 if (boundPercent != null || boundValue == null) {
\r
45358 if (boundPercent == null) {
\r
45359 boundPercent = percentExtent[idx];
\r
45361 // Use scale.parse to math round for category or time axis.
\r
45362 boundValue = scale.parse(numberUtil.linearMap(
\r
45363 boundPercent, percentExtent, dataExtent, true
\r
45366 else { // boundPercent == null && boundValue != null
\r
45367 boundPercent = numberUtil.linearMap(
\r
45368 boundValue, dataExtent, percentExtent, true
\r
45371 // Avoid rounding error
\r
45372 valueWindow[idx] = numberUtil.round(boundValue);
\r
45373 percentWindow[idx] = numberUtil.round(boundPercent);
\r
45377 valueWindow: asc(valueWindow),
\r
45378 percentWindow: asc(percentWindow)
\r
45382 function fixExtendByAxis(dataExtent, axisModel, scale) {
\r
45383 each(['min', 'max'], function (minMax, index) {
\r
45384 var axisMax = axisModel.get(minMax, true);
\r
45385 // Consider 'dataMin', 'dataMax'
\r
45386 if (axisMax != null && (axisMax + '').toLowerCase() !== 'data' + minMax) {
\r
45387 dataExtent[index] = scale.parse(axisMax);
\r
45391 if (!axisModel.get('scale', true)) {
\r
45392 dataExtent[0] > 0 && (dataExtent[0] = 0);
\r
45393 dataExtent[1] < 0 && (dataExtent[1] = 0);
\r
45396 return dataExtent;
\r
45399 function setAxisModel(axisProxy, isRestore) {
\r
45400 var axisModel = axisProxy.getAxisModel();
\r
45402 var percentWindow = axisProxy._percentWindow;
\r
45403 var valueWindow = axisProxy._valueWindow;
\r
45405 if (!percentWindow) {
\r
45409 var isFull = isRestore || (percentWindow[0] === 0 && percentWindow[1] === 100);
\r
45410 // [0, 500]: arbitrary value, guess axis extent.
\r
45411 var precision = !isRestore && numberUtil.getPixelPrecision(valueWindow, [0, 500]);
\r
45412 // toFixed() digits argument must be between 0 and 20
\r
45413 var invalidPrecision = !isRestore && !(precision < 20 && precision >= 0);
\r
45415 var useOrigin = isRestore || isFull || invalidPrecision;
\r
45417 axisModel.setRange && axisModel.setRange(
\r
45418 useOrigin ? null : +valueWindow[0].toFixed(precision),
\r
45419 useOrigin ? null : +valueWindow[1].toFixed(precision)
\r
45423 module.exports = AxisProxy;
\r
45429 /***/ function(module, exports, __webpack_require__) {
\r
45433 var ComponentView = __webpack_require__(28);
\r
45435 module.exports = ComponentView.extend({
\r
45437 type: 'dataZoom',
\r
45439 render: function (dataZoomModel, ecModel, api, payload) {
\r
45440 this.dataZoomModel = dataZoomModel;
\r
45441 this.ecModel = ecModel;
\r
45446 * Find the first target coordinate system.
\r
45449 * @return {Object} {
\r
45451 * {model: coord0, axisModels: [axis1, axis3], coordIndex: 1},
\r
45452 * {model: coord1, axisModels: [axis0, axis2], coordIndex: 0},
\r
45454 * ], // cartesians must not be null/undefined.
\r
45456 * {model: coord0, axisModels: [axis4], coordIndex: 0},
\r
45458 * ], // polars must not be null/undefined.
\r
45459 * axisModels: [axis0, axis1, axis2, axis3, axis4]
\r
45460 * // axisModels must not be null/undefined.
\r
45463 getTargetInfo: function () {
\r
45464 var dataZoomModel = this.dataZoomModel;
\r
45465 var ecModel = this.ecModel;
\r
45466 var cartesians = [];
\r
45468 var axisModels = [];
\r
45470 dataZoomModel.eachTargetAxis(function (dimNames, axisIndex) {
\r
45471 var axisModel = ecModel.getComponent(dimNames.axis, axisIndex);
\r
45473 axisModels.push(axisModel);
\r
45475 var gridIndex = axisModel.get('gridIndex');
\r
45476 var polarIndex = axisModel.get('polarIndex');
\r
45478 if (gridIndex != null) {
\r
45479 var coordModel = ecModel.getComponent('grid', gridIndex);
\r
45480 save(coordModel, axisModel, cartesians, gridIndex);
\r
45482 else if (polarIndex != null) {
\r
45483 var coordModel = ecModel.getComponent('polar', polarIndex);
\r
45484 save(coordModel, axisModel, polars, polarIndex);
\r
45489 function save(coordModel, axisModel, store, coordIndex) {
\r
45491 for (var i = 0; i < store.length; i++) {
\r
45492 if (store[i].model === coordModel) {
\r
45498 store.push(item = {
\r
45499 model: coordModel, axisModels: [], coordIndex: coordIndex
\r
45502 item.axisModels.push(axisModel);
\r
45506 cartesians: cartesians,
\r
45508 axisModels: axisModels
\r
45518 /***/ function(module, exports, __webpack_require__) {
\r
45521 * @file Data zoom model
\r
45525 var DataZoomModel = __webpack_require__(288);
\r
45526 var layout = __webpack_require__(21);
\r
45527 var zrUtil = __webpack_require__(3);
\r
45529 var SliderZoomModel = DataZoomModel.extend({
\r
45531 type: 'dataZoom.slider',
\r
45533 layoutMode: 'box',
\r
45541 // ph => placeholder. Using placehoder here because
\r
45542 // deault value can only be drived in view stage.
\r
45543 right: 'ph', // Default align to grid rect.
\r
45544 top: 'ph', // Default align to grid rect.
\r
45545 width: 'ph', // Default align to grid rect.
\r
45546 height: 'ph', // Default align to grid rect.
\r
45547 left: null, // Default align to grid rect.
\r
45548 bottom: null, // Default align to grid rect.
\r
45550 backgroundColor: 'rgba(47,69,84,0)', // Background of slider zoom component.
\r
45551 dataBackgroundColor: '#ddd', // Background of data shadow.
\r
45552 fillerColor: 'rgba(47,69,84,0.15)', // Color of selected area.
\r
45553 handleColor: 'rgba(148,164,165,0.95)', // Color of handle.
\r
45556 labelPrecision: null,
\r
45557 labelFormatter: null,
\r
45558 showDetail: true,
\r
45559 showDataShadow: 'auto', // Default auto decision.
\r
45561 zoomLock: false, // Whether disable zoom.
\r
45570 mergeOption: function (option) {
\r
45571 SliderZoomModel.superApply(this, 'mergeOption', arguments);
\r
45576 module.exports = SliderZoomModel;
\r
45582 /***/ function(module, exports, __webpack_require__) {
\r
45586 var zrUtil = __webpack_require__(3);
\r
45587 var graphic = __webpack_require__(42);
\r
45588 var throttle = __webpack_require__(293);
\r
45589 var DataZoomView = __webpack_require__(290);
\r
45590 var Rect = graphic.Rect;
\r
45591 var numberUtil = __webpack_require__(7);
\r
45592 var linearMap = numberUtil.linearMap;
\r
45593 var layout = __webpack_require__(21);
\r
45594 var sliderMove = __webpack_require__(294);
\r
45595 var asc = numberUtil.asc;
\r
45596 var bind = zrUtil.bind;
\r
45597 var mathRound = Math.round;
\r
45598 var mathMax = Math.max;
\r
45599 var each = zrUtil.each;
\r
45602 var DEFAULT_LOCATION_EDGE_GAP = 7;
\r
45603 var DEFAULT_FRAME_BORDER_WIDTH = 1;
\r
45604 var DEFAULT_FILLER_SIZE = 30;
\r
45605 var HORIZONTAL = 'horizontal';
\r
45606 var VERTICAL = 'vertical';
\r
45607 var LABEL_GAP = 5;
\r
45608 var SHOW_DATA_SHADOW_SERIES_TYPE = ['line', 'bar', 'candlestick', 'scatter'];
\r
45610 var SliderZoomView = DataZoomView.extend({
\r
45612 type: 'dataZoom.slider',
\r
45614 init: function (ecModel, api) {
\r
45620 this._displayables = {};
\r
45635 * [coord of the first handle, coord of the second handle]
\r
45638 this._handleEnds;
\r
45641 * [length, thick]
\r
45643 * @type {Array.<number>}
\r
45651 this._halfHandleSize;
\r
45666 this._dataShadowInfo;
\r
45674 render: function (dataZoomModel, ecModel, api, payload) {
\r
45675 SliderZoomView.superApply(this, 'render', arguments);
\r
45677 throttle.createOrUpdate(
\r
45679 '_dispatchZoomAction',
\r
45680 this.dataZoomModel.get('throttle'),
\r
45684 this._orient = dataZoomModel.get('orient');
\r
45685 this._halfHandleSize = mathRound(dataZoomModel.get('handleSize') / 2);
\r
45687 if (this.dataZoomModel.get('show') === false) {
\r
45688 this.group.removeAll();
\r
45692 // Notice: this._resetInterval() should not be executed when payload.type
\r
45693 // is 'dataZoom', origin this._range should be maintained, otherwise 'pan'
\r
45694 // or 'zoom' info will be missed because of 'throttle' of this.dispatchAction,
\r
45695 if (!payload || payload.type !== 'dataZoom' || payload.from !== this.uid) {
\r
45696 this._buildView();
\r
45699 this._updateView();
\r
45705 remove: function () {
\r
45706 SliderZoomView.superApply(this, 'remove', arguments);
\r
45707 throttle.clear(this, '_dispatchZoomAction');
\r
45713 dispose: function () {
\r
45714 SliderZoomView.superApply(this, 'dispose', arguments);
\r
45715 throttle.clear(this, '_dispatchZoomAction');
\r
45718 _buildView: function () {
\r
45719 var thisGroup = this.group;
\r
45721 thisGroup.removeAll();
\r
45723 this._resetLocation();
\r
45724 this._resetInterval();
\r
45726 var barGroup = this._displayables.barGroup = new graphic.Group();
\r
45728 this._renderBackground();
\r
45729 this._renderDataShadow();
\r
45730 this._renderHandle();
\r
45732 thisGroup.add(barGroup);
\r
45734 this._positionGroup();
\r
45740 _resetLocation: function () {
\r
45741 var dataZoomModel = this.dataZoomModel;
\r
45742 var api = this.api;
\r
45744 // If some of x/y/width/height are not specified,
\r
45745 // auto-adapt according to target grid.
\r
45746 var coordRect = this._findCoordRect();
\r
45747 var ecSize = {width: api.getWidth(), height: api.getHeight()};
\r
45748 // Default align by coordinate system rect.
\r
45749 var positionInfo = this._orient === HORIZONTAL
\r
45751 // Why using 'right', because right should be used in vertical,
\r
45752 // and it is better to be consistent for dealing with position param merge.
\r
45753 right: ecSize.width - coordRect.x - coordRect.width,
\r
45754 top: (ecSize.height - DEFAULT_FILLER_SIZE - DEFAULT_LOCATION_EDGE_GAP),
\r
45755 width: coordRect.width,
\r
45756 height: DEFAULT_FILLER_SIZE
\r
45759 right: DEFAULT_LOCATION_EDGE_GAP,
\r
45760 top: coordRect.y,
\r
45761 width: DEFAULT_FILLER_SIZE,
\r
45762 height: coordRect.height
\r
45765 // Do not write back to option and replace value 'ph', because
\r
45766 // the 'ph' value should be recalculated when resize.
\r
45767 var layoutParams = layout.getLayoutParams(dataZoomModel.option);
\r
45769 // Replace the placeholder value.
\r
45770 zrUtil.each(['right', 'top', 'width', 'height'], function (name) {
\r
45771 if (layoutParams[name] === 'ph') {
\r
45772 layoutParams[name] = positionInfo[name];
\r
45776 var layoutRect = layout.getLayoutRect(
\r
45779 dataZoomModel.padding
\r
45782 this._location = {x: layoutRect.x, y: layoutRect.y};
\r
45783 this._size = [layoutRect.width, layoutRect.height];
\r
45784 this._orient === VERTICAL && this._size.reverse();
\r
45790 _positionGroup: function () {
\r
45791 var thisGroup = this.group;
\r
45792 var location = this._location;
\r
45793 var orient = this._orient;
\r
45795 // Just use the first axis to determine mapping.
\r
45796 var targetAxisModel = this.dataZoomModel.getFirstTargetAxisModel();
\r
45797 var inverse = targetAxisModel && targetAxisModel.get('inverse');
\r
45799 var barGroup = this._displayables.barGroup;
\r
45800 var otherAxisInverse = (this._dataShadowInfo || {}).otherAxisInverse;
\r
45802 // Transform barGroup.
\r
45804 (orient === HORIZONTAL && !inverse)
\r
45805 ? {scale: otherAxisInverse ? [1, 1] : [1, -1]}
\r
45806 : (orient === HORIZONTAL && inverse)
\r
45807 ? {scale: otherAxisInverse ? [-1, 1] : [-1, -1]}
\r
45808 : (orient === VERTICAL && !inverse)
\r
45809 ? {scale: otherAxisInverse ? [1, -1] : [1, 1], rotation: Math.PI / 2}
\r
45810 // Dont use Math.PI, considering shadow direction.
\r
45811 : {scale: otherAxisInverse ? [-1, -1] : [-1, 1], rotation: Math.PI / 2}
\r
45814 // Position barGroup
\r
45815 var rect = thisGroup.getBoundingRect([barGroup]);
\r
45816 thisGroup.position[0] = location.x - rect.x;
\r
45817 thisGroup.position[1] = location.y - rect.y;
\r
45823 _getViewExtent: function () {
\r
45824 // View total length.
\r
45825 var halfHandleSize = this._halfHandleSize;
\r
45826 var totalLength = mathMax(this._size[0], halfHandleSize * 4);
\r
45827 var extent = [halfHandleSize, totalLength - halfHandleSize];
\r
45832 _renderBackground : function () {
\r
45833 var dataZoomModel = this.dataZoomModel;
\r
45834 var size = this._size;
\r
45836 this._displayables.barGroup.add(new Rect({
\r
45839 x: 0, y: 0, width: size[0], height: size[1]
\r
45842 fill: dataZoomModel.get('backgroundColor')
\r
45847 _renderDataShadow: function () {
\r
45848 var info = this._dataShadowInfo = this._prepareDataShadowInfo();
\r
45854 var size = this._size;
\r
45855 var seriesModel = info.series;
\r
45856 var data = seriesModel.getRawData();
\r
45857 var otherDim = seriesModel.getShadowDim
\r
45858 ? seriesModel.getShadowDim() // @see candlestick
\r
45861 var otherDataExtent = data.getDataExtent(otherDim);
\r
45863 var otherOffset = (otherDataExtent[1] - otherDataExtent[0]) * 0.3;
\r
45864 otherDataExtent = [
\r
45865 otherDataExtent[0] - otherOffset,
\r
45866 otherDataExtent[1] + otherOffset
\r
45868 var otherShadowExtent = [0, size[1]];
\r
45870 var thisShadowExtent = [0, size[0]];
\r
45872 var points = [[size[0], 0], [0, 0]];
\r
45873 var step = thisShadowExtent[1] / (data.count() - 1);
\r
45874 var thisCoord = 0;
\r
45876 // Optimize for large data shadow
\r
45877 var stride = Math.round(data.count() / size[0]);
\r
45878 data.each([otherDim], function (value, index) {
\r
45879 if (stride > 0 && (index % stride)) {
\r
45880 thisCoord += step;
\r
45884 // 应该使用统计的空判断?还是在list里进行空判断?
\r
45885 var otherCoord = (value == null || isNaN(value) || value === '')
\r
45887 : linearMap(value, otherDataExtent, otherShadowExtent, true);
\r
45888 otherCoord != null && points.push([thisCoord, otherCoord]);
\r
45890 thisCoord += step;
\r
45893 this._displayables.barGroup.add(new graphic.Polyline({
\r
45894 shape: {points: points},
\r
45895 style: {fill: this.dataZoomModel.get('dataBackgroundColor'), lineWidth: 0},
\r
45901 _prepareDataShadowInfo: function () {
\r
45902 var dataZoomModel = this.dataZoomModel;
\r
45903 var showDataShadow = dataZoomModel.get('showDataShadow');
\r
45905 if (showDataShadow === false) {
\r
45909 // Find a representative series.
\r
45911 var ecModel = this.ecModel;
\r
45913 dataZoomModel.eachTargetAxis(function (dimNames, axisIndex) {
\r
45914 var seriesModels = dataZoomModel
\r
45915 .getAxisProxy(dimNames.name, axisIndex)
\r
45916 .getTargetSeriesModels();
\r
45918 zrUtil.each(seriesModels, function (seriesModel) {
\r
45923 if (showDataShadow !== true && zrUtil.indexOf(
\r
45924 SHOW_DATA_SHADOW_SERIES_TYPE, seriesModel.get('type')
\r
45930 var otherDim = getOtherDim(dimNames.name);
\r
45932 var thisAxis = ecModel.getComponent(dimNames.axis, axisIndex).axis;
\r
45935 thisAxis: thisAxis,
\r
45936 series: seriesModel,
\r
45937 thisDim: dimNames.name,
\r
45938 otherDim: otherDim,
\r
45939 otherAxisInverse: seriesModel
\r
45940 .coordinateSystem.getOtherAxis(thisAxis).inverse
\r
45950 _renderHandle: function () {
\r
45951 var displaybles = this._displayables;
\r
45952 var handles = displaybles.handles = [];
\r
45953 var handleLabels = displaybles.handleLabels = [];
\r
45954 var barGroup = this._displayables.barGroup;
\r
45955 var size = this._size;
\r
45957 barGroup.add(displaybles.filler = new Rect({
\r
45960 drift: bind(this._onDragMove, this, 'all'),
\r
45961 ondragend: bind(this._onDragEnd, this),
\r
45962 onmouseover: bind(this._showDataInfo, this, true),
\r
45963 onmouseout: bind(this._showDataInfo, this, false),
\r
45965 fill: this.dataZoomModel.get('fillerColor'),
\r
45967 textPosition : 'inside'
\r
45972 barGroup.add(new Rect(graphic.subPixelOptimizeRect({
\r
45981 stroke: this.dataZoomModel.get('dataBackgroundColor'),
\r
45982 lineWidth: DEFAULT_FRAME_BORDER_WIDTH,
\r
45983 fill: 'rgba(0,0,0,0)'
\r
45987 each([0, 1], function (handleIndex) {
\r
45989 barGroup.add(handles[handleIndex] = new Rect({
\r
45991 fill: this.dataZoomModel.get('handleColor')
\r
45995 drift: bind(this._onDragMove, this, handleIndex),
\r
45996 ondragend: bind(this._onDragEnd, this),
\r
45997 onmouseover: bind(this._showDataInfo, this, true),
\r
45998 onmouseout: bind(this._showDataInfo, this, false)
\r
46001 var textStyleModel = this.dataZoomModel.textStyleModel;
\r
46004 handleLabels[handleIndex] = new graphic.Text({
\r
46008 x: 0, y: 0, text: '',
\r
46009 textVerticalAlign: 'middle',
\r
46010 textAlign: 'center',
\r
46011 fill: textStyleModel.getTextColor(),
\r
46012 textFont: textStyleModel.getFont()
\r
46022 _resetInterval: function () {
\r
46023 var range = this._range = this.dataZoomModel.getPercentRange();
\r
46024 var viewExtent = this._getViewExtent();
\r
46026 this._handleEnds = [
\r
46027 linearMap(range[0], [0, 100], viewExtent, true),
\r
46028 linearMap(range[1], [0, 100], viewExtent, true)
\r
46034 * @param {(number|string)} handleIndex 0 or 1 or 'all'
\r
46035 * @param {number} dx
\r
46036 * @param {number} dy
\r
46038 _updateInterval: function (handleIndex, delta) {
\r
46039 var handleEnds = this._handleEnds;
\r
46040 var viewExtend = this._getViewExtent();
\r
46046 (handleIndex === 'all' || this.dataZoomModel.get('zoomLock'))
\r
46047 ? 'rigid' : 'cross',
\r
46051 this._range = asc([
\r
46052 linearMap(handleEnds[0], viewExtend, [0, 100], true),
\r
46053 linearMap(handleEnds[1], viewExtend, [0, 100], true)
\r
46060 _updateView: function () {
\r
46061 var displaybles = this._displayables;
\r
46062 var handleEnds = this._handleEnds;
\r
46063 var handleInterval = asc(handleEnds.slice());
\r
46064 var size = this._size;
\r
46065 var halfHandleSize = this._halfHandleSize;
\r
46067 each([0, 1], function (handleIndex) {
\r
46070 var handle = displaybles.handles[handleIndex];
\r
46071 handle.setShape({
\r
46072 x: handleEnds[handleIndex] - halfHandleSize,
\r
46074 width: halfHandleSize * 2,
\r
46075 height: size[1] + 2,
\r
46082 displaybles.filler.setShape({
\r
46083 x: handleInterval[0],
\r
46085 width: handleInterval[1] - handleInterval[0],
\r
46086 height: this._size[1]
\r
46089 this._updateDataInfo();
\r
46095 _updateDataInfo: function () {
\r
46096 var dataZoomModel = this.dataZoomModel;
\r
46097 var displaybles = this._displayables;
\r
46098 var handleLabels = displaybles.handleLabels;
\r
46099 var orient = this._orient;
\r
46100 var labelTexts = ['', ''];
\r
46103 // date型,支持formatter,autoformatter(ec2 date.getAutoFormatter)
\r
46104 if (dataZoomModel.get('showDetail')) {
\r
46105 var dataInterval;
\r
46107 dataZoomModel.eachTargetAxis(function (dimNames, axisIndex) {
\r
46108 // Using dataInterval of the first axis.
\r
46109 if (!dataInterval) {
\r
46110 dataInterval = dataZoomModel
\r
46111 .getAxisProxy(dimNames.name, axisIndex)
\r
46112 .getDataValueWindow();
\r
46113 axis = this.ecModel.getComponent(dimNames.axis, axisIndex).axis;
\r
46117 if (dataInterval) {
\r
46119 this._formatLabel(dataInterval[0], axis),
\r
46120 this._formatLabel(dataInterval[1], axis)
\r
46125 var orderedHandleEnds = asc(this._handleEnds.slice());
\r
46127 setLabel.call(this, 0);
\r
46128 setLabel.call(this, 1);
\r
46130 function setLabel(handleIndex) {
\r
46132 // Text should not transform by barGroup.
\r
46133 var barTransform = graphic.getTransform(
\r
46134 displaybles.handles[handleIndex], this.group
\r
46136 var direction = graphic.transformDirection(
\r
46137 handleIndex === 0 ? 'right' : 'left', barTransform
\r
46139 var offset = this._halfHandleSize + LABEL_GAP;
\r
46140 var textPoint = graphic.applyTransform(
\r
46142 orderedHandleEnds[handleIndex] + (handleIndex === 0 ? -offset : offset),
\r
46143 this._size[1] / 2
\r
46147 handleLabels[handleIndex].setStyle({
\r
46150 textVerticalAlign: orient === HORIZONTAL ? 'middle' : direction,
\r
46151 textAlign: orient === HORIZONTAL ? direction : 'center',
\r
46152 text: labelTexts[handleIndex]
\r
46160 _formatLabel: function (value, axis) {
\r
46161 var dataZoomModel = this.dataZoomModel;
\r
46162 var labelFormatter = dataZoomModel.get('labelFormatter');
\r
46163 if (zrUtil.isFunction(labelFormatter)) {
\r
46164 return labelFormatter(value);
\r
46167 var labelPrecision = dataZoomModel.get('labelPrecision');
\r
46168 if (labelPrecision == null || labelPrecision === 'auto') {
\r
46169 labelPrecision = axis.getPixelPrecision();
\r
46172 value = (value == null && isNaN(value))
\r
46174 // FIXME Glue code
\r
46175 : (axis.type === 'category' || axis.type === 'time')
\r
46176 ? axis.scale.getLabel(Math.round(value))
\r
46177 // param of toFixed should less then 20.
\r
46178 : value.toFixed(Math.min(labelPrecision, 20));
\r
46180 if (zrUtil.isString(labelFormatter)) {
\r
46181 value = labelFormatter.replace('{value}', value);
\r
46189 * @param {boolean} showOrHide true: show, false: hide
\r
46191 _showDataInfo: function (showOrHide) {
\r
46192 // Always show when drgging.
\r
46193 showOrHide = this._dragging || showOrHide;
\r
46195 var handleLabels = this._displayables.handleLabels;
\r
46196 handleLabels[0].attr('invisible', !showOrHide);
\r
46197 handleLabels[1].attr('invisible', !showOrHide);
\r
46200 _onDragMove: function (handleIndex, dx, dy) {
\r
46201 this._dragging = true;
\r
46203 // Transform dx, dy to bar coordination.
\r
46204 var vertex = this._applyBarTransform([dx, dy], true);
\r
46206 this._updateInterval(handleIndex, vertex[0]);
\r
46207 this._updateView();
\r
46209 if (this.dataZoomModel.get('realtime')) {
\r
46210 this._dispatchZoomAction();
\r
46214 _onDragEnd: function () {
\r
46215 this._dragging = false;
\r
46216 this._showDataInfo(false);
\r
46217 this._dispatchZoomAction();
\r
46221 * This action will be throttled.
\r
46224 _dispatchZoomAction: function () {
\r
46225 var range = this._range;
\r
46227 this.api.dispatchAction({
\r
46228 type: 'dataZoom',
\r
46230 dataZoomId: this.dataZoomModel.id,
\r
46239 _applyBarTransform: function (vertex, inverse) {
\r
46240 var barTransform = this._displayables.barGroup.getLocalTransform();
\r
46241 return graphic.applyTransform(vertex, barTransform, inverse);
\r
46247 _findCoordRect: function () {
\r
46248 // Find the grid coresponding to the first axis referred by dataZoom.
\r
46249 var targetInfo = this.getTargetInfo();
\r
46252 // 判断是catesian还是polar
\r
46254 if (targetInfo.cartesians.length) {
\r
46255 rect = targetInfo.cartesians[0].model.coordinateSystem.getRect();
\r
46260 var width = this.api.getWidth();
\r
46261 var height = this.api.getHeight();
\r
46265 width: width * 0.6,
\r
46266 height: height * 0.6
\r
46275 function getOtherDim(thisDim) {
\r
46277 // 这个逻辑和getOtherAxis里一致,但是写在这里是否不好
\r
46278 return thisDim === 'x' ? 'y' : 'x';
\r
46281 module.exports = SliderZoomView;
\r
46287 /***/ function(module, exports) {
\r
46293 var ORIGIN_METHOD = '\0__throttleOriginMethod';
\r
46294 var RATE = '\0__throttleRate';
\r
46297 * 频率控制 返回函数连续调用时,fn 执行频率限定为每多少时间执行一次
\r
46299 * notifyWhenChangesStop
\r
46300 * 频繁调用时,只保证最后一次执行
\r
46301 * 配成:trailing:true;debounce:true 即可
\r
46302 * notifyAtFixRate
\r
46304 * 配成:trailing:true;debounce:false 即可
\r
46306 * 根据model更新view的时候,可以使用throttle,
\r
46307 * 但是根据view更新model的时候,避免使用这种延迟更新的方式。
\r
46308 * 因为这可能导致model和server同步出现问题。
\r
46311 * @param {(Function|Array.<Function>)} fn 需要调用的函数
\r
46312 * 如果fn为array,则表示可以对多个函数进行throttle。
\r
46314 * @param {number} delay 延迟时间,单位毫秒
\r
46315 * @param {bool} trailing 是否保证最后一次触发的执行
\r
46316 * true:表示保证最后一次调用会触发执行。
\r
46317 * 但任何调用后不可能立即执行,总会delay。
\r
46318 * false:表示不保证最后一次调用会触发执行。
\r
46319 * 但只要间隔大于delay,调用就会立即执行。
\r
46320 * @param {bool} debounce 节流
\r
46321 * true:表示:频繁调用(间隔小于delay)时,根本不执行
\r
46322 * false:表示:频繁调用(间隔小于delay)时,按规律心跳执行
\r
46323 * @return {(Function|Array.<Function>)} 实际调用函数。
\r
46324 * 当输入的fn为array时,返回值也为array。
\r
46327 lib.throttle = function (fn, delay, trailing, debounce) {
\r
46329 var currCall = (new Date()).getTime();
\r
46330 var lastCall = 0;
\r
46331 var lastExec = 0;
\r
46332 var timer = null;
\r
46336 var isSingle = typeof fn === 'function';
\r
46337 delay = delay || 0;
\r
46340 return createCallback();
\r
46344 for (var i = 0; i < fn.length; i++) {
\r
46345 ret[i] = createCallback(i);
\r
46350 function createCallback(index) {
\r
46352 function exec() {
\r
46353 lastExec = (new Date()).getTime();
\r
46355 (isSingle ? fn : fn[index]).apply(scope, args || []);
\r
46358 var cb = function () {
\r
46359 currCall = (new Date()).getTime();
\r
46361 args = arguments;
\r
46362 diff = currCall - (debounce ? lastCall : lastExec) - delay;
\r
46364 clearTimeout(timer);
\r
46368 timer = setTimeout(exec, delay);
\r
46370 else if (diff >= 0) {
\r
46378 else if (trailing) {
\r
46379 timer = setTimeout(exec, -diff);
\r
46383 lastCall = currCall;
\r
46387 * Clear throttle.
\r
46390 cb.clear = function () {
\r
46392 clearTimeout(timer);
\r
46402 * 按一定频率执行,最后一次调用总归会执行
\r
46406 lib.fixRate = function (fn, delay) {
\r
46407 return delay != null
\r
46408 ? lib.throttle(fn, delay, true, false)
\r
46413 * 直到不频繁调用了才会执行,最后一次调用总归会执行
\r
46417 lib.debounce = function (fn, delay) {
\r
46418 return delay != null
\r
46419 ? lib.throttle(fn, delay, true, true)
\r
46425 * Create throttle method or update throttle rate.
\r
46428 * ComponentView.prototype.render = function () {
\r
46430 * throttle.createOrUpdate(
\r
46432 * '_dispatchAction',
\r
46433 * this.model.get('throttle'),
\r
46437 * ComponentView.prototype.remove = function () {
\r
46438 * throttle.clear(this, '_dispatchAction');
\r
46440 * ComponentView.prototype.dispose = function () {
\r
46441 * throttle.clear(this, '_dispatchAction');
\r
46445 * @param {Object} obj
\r
46446 * @param {string} fnAttr
\r
46447 * @param {number} rate
\r
46448 * @param {string} throttleType 'fixRate' or 'debounce'
\r
46450 lib.createOrUpdate = function (obj, fnAttr, rate, throttleType) {
\r
46451 var fn = obj[fnAttr];
\r
46453 if (!fn || rate == null || !throttleType) {
\r
46457 var originFn = fn[ORIGIN_METHOD] || fn;
\r
46458 var lastRate = fn[RATE];
\r
46460 if (lastRate !== rate) {
\r
46461 fn = obj[fnAttr] = lib[throttleType](originFn, rate);
\r
46462 fn[ORIGIN_METHOD] = originFn;
\r
46468 * Clear throttle. Example see throttle.createOrUpdate.
\r
46471 * @param {Object} obj
\r
46472 * @param {string} fnAttr
\r
46474 lib.clear = function (obj, fnAttr) {
\r
46475 var fn = obj[fnAttr];
\r
46476 if (fn && fn[ORIGIN_METHOD]) {
\r
46477 obj[fnAttr] = fn[ORIGIN_METHOD];
\r
46481 module.exports = lib;
\r
46487 /***/ function(module, exports) {
\r
46492 * Calculate slider move result.
\r
46494 * @param {number} delta Move length.
\r
46495 * @param {Array.<number>} handleEnds handleEnds[0] and be bigger then handleEnds[1].
\r
46496 * handleEnds will be modified in this method.
\r
46497 * @param {Array.<number>} extent handleEnds is restricted by extent.
\r
46498 * extent[0] should less or equals than extent[1].
\r
46499 * @param {string} mode 'rigid': Math.abs(handleEnds[0] - handleEnds[1]) remain unchanged,
\r
46500 * 'cross' handleEnds[0] can be bigger then handleEnds[1],
\r
46501 * 'push' handleEnds[0] can not be bigger then handleEnds[1],
\r
46502 * when they touch, one push other.
\r
46503 * @param {number} handleIndex If mode is 'rigid', handleIndex is not required.
\r
46504 * @param {Array.<number>} The input handleEnds.
\r
46506 module.exports = function (delta, handleEnds, extent, mode, handleIndex) {
\r
46508 return handleEnds;
\r
46511 if (mode === 'rigid') {
\r
46512 delta = getRealDelta(delta, handleEnds, extent);
\r
46513 handleEnds[0] += delta;
\r
46514 handleEnds[1] += delta;
\r
46517 delta = getRealDelta(delta, handleEnds[handleIndex], extent);
\r
46518 handleEnds[handleIndex] += delta;
\r
46520 if (mode === 'push' && handleEnds[0] > handleEnds[1]) {
\r
46521 handleEnds[1 - handleIndex] = handleEnds[handleIndex];
\r
46525 return handleEnds;
\r
46527 function getRealDelta(delta, handleEnds, extent) {
\r
46528 var handleMinMax = !handleEnds.length
\r
46529 ? [handleEnds, handleEnds]
\r
46530 : handleEnds.slice();
\r
46531 handleEnds[0] > handleEnds[1] && handleMinMax.reverse();
\r
46533 if (delta < 0 && handleMinMax[0] + delta < extent[0]) {
\r
46534 delta = extent[0] - handleMinMax[0];
\r
46536 if (delta > 0 && handleMinMax[1] + delta > extent[1]) {
\r
46537 delta = extent[1] - handleMinMax[1];
\r
46546 /***/ function(module, exports, __webpack_require__) {
\r
46549 * @file Data zoom model
\r
46553 module.exports = __webpack_require__(288).extend({
\r
46555 type: 'dataZoom.inside',
\r
46561 zoomLock: false // Whether disable zoom but only pan.
\r
46568 /***/ function(module, exports, __webpack_require__) {
\r
46572 var DataZoomView = __webpack_require__(290);
\r
46573 var zrUtil = __webpack_require__(3);
\r
46574 var sliderMove = __webpack_require__(294);
\r
46575 var roams = __webpack_require__(297);
\r
46576 var bind = zrUtil.bind;
\r
46578 var InsideZoomView = DataZoomView.extend({
\r
46580 type: 'dataZoom.inside',
\r
46585 init: function (ecModel, api) {
\r
46587 * 'throttle' is used in this.dispatchAction, so we save range
\r
46588 * to avoid missing some 'pan' info.
\r
46590 * @type {Array.<number>}
\r
46598 render: function (dataZoomModel, ecModel, api, payload) {
\r
46599 InsideZoomView.superApply(this, 'render', arguments);
\r
46601 // Notice: origin this._range should be maintained, and should not be re-fetched
\r
46602 // from dataZoomModel when payload.type is 'dataZoom', otherwise 'pan' or 'zoom'
\r
46603 // info will be missed because of 'throttle' of this.dispatchAction.
\r
46604 if (roams.shouldRecordRange(payload, dataZoomModel.id)) {
\r
46605 this._range = dataZoomModel.getPercentRange();
\r
46608 // Reset controllers.
\r
46609 var coordInfoList = this.getTargetInfo().cartesians;
\r
46610 var allCoordIds = zrUtil.map(coordInfoList, function (coordInfo) {
\r
46611 return roams.generateCoordId(coordInfo.model);
\r
46613 zrUtil.each(coordInfoList, function (coordInfo) {
\r
46614 var coordModel = coordInfo.model;
\r
46618 coordId: roams.generateCoordId(coordModel),
\r
46619 allCoordIds: allCoordIds,
\r
46620 coordinateSystem: coordModel.coordinateSystem,
\r
46621 dataZoomId: dataZoomModel.id,
\r
46622 throttleRage: dataZoomModel.get('throttle', true),
\r
46623 panGetRange: bind(this._onPan, this, coordInfo),
\r
46624 zoomGetRange: bind(this._onZoom, this, coordInfo)
\r
46636 remove: function () {
\r
46637 roams.unregister(this.api, this.dataZoomModel.id);
\r
46638 InsideZoomView.superApply(this, 'remove', arguments);
\r
46639 this._range = null;
\r
46645 dispose: function () {
\r
46646 roams.unregister(this.api, this.dataZoomModel.id);
\r
46647 InsideZoomView.superApply(this, 'dispose', arguments);
\r
46648 this._range = null;
\r
46654 _onPan: function (coordInfo, controller, dx, dy) {
\r
46656 this._range = panCartesian(
\r
46657 [dx, dy], this._range, controller, coordInfo
\r
46665 _onZoom: function (coordInfo, controller, scale, mouseX, mouseY) {
\r
46666 var dataZoomModel = this.dataZoomModel;
\r
46668 if (dataZoomModel.option.zoomLock) {
\r
46669 return this._range;
\r
46673 this._range = scaleCartesian(
\r
46674 1 / scale, [mouseX, mouseY], this._range,
\r
46675 controller, coordInfo, dataZoomModel
\r
46682 function panCartesian(pixelDeltas, range, controller, coordInfo) {
\r
46683 range = range.slice();
\r
46685 // Calculate transform by the first axis.
\r
46686 var axisModel = coordInfo.axisModels[0];
\r
46687 if (!axisModel) {
\r
46691 var directionInfo = getDirectionInfo(pixelDeltas, axisModel, controller);
\r
46693 var percentDelta = directionInfo.signal
\r
46694 * (range[1] - range[0])
\r
46695 * directionInfo.pixel / directionInfo.pixelLength;
\r
46707 function scaleCartesian(scale, mousePoint, range, controller, coordInfo, dataZoomModel) {
\r
46708 range = range.slice();
\r
46710 // Calculate transform by the first axis.
\r
46711 var axisModel = coordInfo.axisModels[0];
\r
46712 if (!axisModel) {
\r
46716 var directionInfo = getDirectionInfo(mousePoint, axisModel, controller);
\r
46718 var mouse = directionInfo.pixel - directionInfo.pixelStart;
\r
46719 var percentPoint = mouse / directionInfo.pixelLength * (range[1] - range[0]) + range[0];
\r
46721 scale = Math.max(scale, 0);
\r
46722 range[0] = (range[0] - percentPoint) * scale + percentPoint;
\r
46723 range[1] = (range[1] - percentPoint) * scale + percentPoint;
\r
46725 return fixRange(range);
\r
46728 function getDirectionInfo(xy, axisModel, controller) {
\r
46729 var axis = axisModel.axis;
\r
46730 var rect = controller.rect;
\r
46733 if (axis.dim === 'x') {
\r
46734 ret.pixel = xy[0];
\r
46735 ret.pixelLength = rect.width;
\r
46736 ret.pixelStart = rect.x;
\r
46737 ret.signal = axis.inverse ? 1 : -1;
\r
46739 else { // axis.dim === 'y'
\r
46740 ret.pixel = xy[1];
\r
46741 ret.pixelLength = rect.height;
\r
46742 ret.pixelStart = rect.y;
\r
46743 ret.signal = axis.inverse ? -1 : 1;
\r
46749 function fixRange(range) {
\r
46750 // Clamp, using !(<= or >=) to handle NaN.
\r
46751 // jshint ignore:start
\r
46752 var bound = [0, 100];
\r
46753 !(range[0] <= bound[1]) && (range[0] = bound[1]);
\r
46754 !(range[1] <= bound[1]) && (range[1] = bound[1]);
\r
46755 !(range[0] >= bound[0]) && (range[0] = bound[0]);
\r
46756 !(range[1] >= bound[0]) && (range[1] = bound[0]);
\r
46757 // jshint ignore:end
\r
46762 module.exports = InsideZoomView;
\r
46767 /***/ function(module, exports, __webpack_require__) {
\r
46770 * @file Roam controller manager.
\r
46774 // Only create one roam controller for each coordinate system.
\r
46775 // one roam controller might be refered by two inside data zoom
\r
46776 // components (for example, one for x and one for y). When user
\r
46777 // pan or zoom, only dispatch one action for those data zoom
\r
46780 var zrUtil = __webpack_require__(3);
\r
46781 var RoamController = __webpack_require__(159);
\r
46782 var throttle = __webpack_require__(293);
\r
46783 var curry = zrUtil.curry;
\r
46785 var ATTR = '\0_ec_dataZoom_roams';
\r
46791 * @param {module:echarts/ExtensionAPI} api
\r
46792 * @param {Object} dataZoomInfo
\r
46793 * @param {string} dataZoomInfo.coordId
\r
46794 * @param {Object} dataZoomInfo.coordinateSystem
\r
46795 * @param {Array.<string>} dataZoomInfo.allCoordIds
\r
46796 * @param {string} dataZoomInfo.dataZoomId
\r
46797 * @param {number} dataZoomInfo.throttleRate
\r
46798 * @param {Function} dataZoomInfo.panGetRange
\r
46799 * @param {Function} dataZoomInfo.zoomGetRange
\r
46801 register: function (api, dataZoomInfo) {
\r
46802 var store = giveStore(api);
\r
46803 var theDataZoomId = dataZoomInfo.dataZoomId;
\r
46804 var theCoordId = dataZoomInfo.coordId;
\r
46806 // Do clean when a dataZoom changes its target coordnate system.
\r
46807 zrUtil.each(store, function (record, coordId) {
\r
46808 var dataZoomInfos = record.dataZoomInfos;
\r
46809 if (dataZoomInfos[theDataZoomId]
\r
46810 && zrUtil.indexOf(dataZoomInfo.allCoordIds, theCoordId) < 0
\r
46812 delete dataZoomInfos[theDataZoomId];
\r
46817 cleanStore(store);
\r
46819 var record = store[theCoordId];
\r
46821 // Create if needed.
\r
46823 record = store[theCoordId] = {
\r
46824 coordId: theCoordId,
\r
46825 dataZoomInfos: {},
\r
46828 record.controller = createController(api, dataZoomInfo, record);
\r
46829 record.dispatchAction = zrUtil.curry(dispatchAction, api);
\r
46832 // Consider resize, area should be always updated.
\r
46833 record.controller.rect = dataZoomInfo.coordinateSystem.getRect().clone();
\r
46835 // Update throttle.
\r
46836 throttle.createOrUpdate(
\r
46838 'dispatchAction',
\r
46839 dataZoomInfo.throttleRate,
\r
46843 // Update reference of dataZoom.
\r
46844 !(record.dataZoomInfos[theDataZoomId]) && record.count++;
\r
46845 record.dataZoomInfos[theDataZoomId] = dataZoomInfo;
\r
46850 * @param {module:echarts/ExtensionAPI} api
\r
46851 * @param {string} dataZoomId
\r
46853 unregister: function (api, dataZoomId) {
\r
46854 var store = giveStore(api);
\r
46856 zrUtil.each(store, function (record) {
\r
46857 var dataZoomInfos = record.dataZoomInfos;
\r
46858 if (dataZoomInfos[dataZoomId]) {
\r
46859 delete dataZoomInfos[dataZoomId];
\r
46864 cleanStore(store);
\r
46870 shouldRecordRange: function (payload, dataZoomId) {
\r
46871 if (payload && payload.type === 'dataZoom' && payload.batch) {
\r
46872 for (var i = 0, len = payload.batch.length; i < len; i++) {
\r
46873 if (payload.batch[i].dataZoomId === dataZoomId) {
\r
46884 generateCoordId: function (coordModel) {
\r
46885 return coordModel.type + '\0_' + coordModel.id;
\r
46890 * Key: coordId, value: {dataZoomInfos: [], count, controller}
\r
46891 * @type {Array.<Object>}
\r
46893 function giveStore(api) {
\r
46894 // Mount store on zrender instance, so that we do not
\r
46895 // need to worry about dispose.
\r
46896 var zr = api.getZr();
\r
46897 return zr[ATTR] || (zr[ATTR] = {});
\r
46900 function createController(api, dataZoomInfo, newRecord) {
\r
46901 var controller = new RoamController(api.getZr());
\r
46902 controller.enable();
\r
46903 controller.on('pan', curry(onPan, newRecord));
\r
46904 controller.on('zoom', curry(onZoom, newRecord));
\r
46906 return controller;
\r
46909 function cleanStore(store) {
\r
46910 zrUtil.each(store, function (record, coordId) {
\r
46911 if (!record.count) {
\r
46912 record.controller.off('pan').off('zoom');
\r
46913 delete store[coordId];
\r
46918 function onPan(record, dx, dy) {
\r
46919 wrapAndDispatch(record, function (info) {
\r
46920 return info.panGetRange(record.controller, dx, dy);
\r
46924 function onZoom(record, scale, mouseX, mouseY) {
\r
46925 wrapAndDispatch(record, function (info) {
\r
46926 return info.zoomGetRange(record.controller, scale, mouseX, mouseY);
\r
46930 function wrapAndDispatch(record, getRange) {
\r
46933 zrUtil.each(record.dataZoomInfos, function (info) {
\r
46934 var range = getRange(info);
\r
46935 range && batch.push({
\r
46936 dataZoomId: info.dataZoomId,
\r
46942 record.dispatchAction(batch);
\r
46946 * This action will be throttled.
\r
46948 function dispatchAction(api, batch) {
\r
46949 api.dispatchAction({
\r
46950 type: 'dataZoom',
\r
46955 module.exports = roams;
\r
46961 /***/ function(module, exports, __webpack_require__) {
\r
46964 * @file Data zoom processor
\r
46968 var echarts = __webpack_require__(1);
\r
46970 echarts.registerProcessor('filter', function (ecModel, api) {
\r
46972 ecModel.eachComponent('dataZoom', function (dataZoomModel) {
\r
46973 // We calculate window and reset axis here but not in model
\r
46974 // init stage and not after action dispatch handler, because
\r
46975 // reset should be called after seriesData.restoreData.
\r
46976 dataZoomModel.eachTargetAxis(resetSingleAxis);
\r
46978 // Caution: data zoom filtering is order sensitive when using
\r
46979 // percent range and no min/max/scale set on axis.
\r
46980 // For example, we have dataZoom definition:
\r
46982 // {xAxisIndex: 0, start: 30, end: 70},
\r
46983 // {yAxisIndex: 0, start: 20, end: 80}
\r
46985 // In this case, [20, 80] of y-dataZoom should be based on data
\r
46986 // that have filtered by x-dataZoom using range of [30, 70],
\r
46987 // but should not be based on full raw data. Thus sliding
\r
46988 // x-dataZoom will change both ranges of xAxis and yAxis,
\r
46989 // while sliding y-dataZoom will only change the range of yAxis.
\r
46990 // So we should filter x-axis after reset x-axis immediately,
\r
46991 // and then reset y-axis and filter y-axis.
\r
46992 dataZoomModel.eachTargetAxis(filterSingleAxis);
\r
46995 ecModel.eachComponent('dataZoom', function (dataZoomModel) {
\r
46996 // Fullfill all of the range props so that user
\r
46997 // is able to get them from chart.getOption().
\r
46998 var axisProxy = dataZoomModel.findRepresentativeAxisProxy();
\r
46999 var percentRange = axisProxy.getDataPercentWindow();
\r
47000 var valueRange = axisProxy.getDataValueWindow();
\r
47001 dataZoomModel.setRawRange({
\r
47002 start: percentRange[0],
\r
47003 end: percentRange[1],
\r
47004 startValue: valueRange[0],
\r
47005 endValue: valueRange[1]
\r
47010 function resetSingleAxis(dimNames, axisIndex, dataZoomModel) {
\r
47011 dataZoomModel.getAxisProxy(dimNames.name, axisIndex).reset(dataZoomModel);
\r
47014 function filterSingleAxis(dimNames, axisIndex, dataZoomModel) {
\r
47015 dataZoomModel.getAxisProxy(dimNames.name, axisIndex).filterData(dataZoomModel);
\r
47023 /***/ function(module, exports, __webpack_require__) {
\r
47026 * @file Data zoom action
\r
47030 var zrUtil = __webpack_require__(3);
\r
47031 var modelUtil = __webpack_require__(5);
\r
47032 var echarts = __webpack_require__(1);
\r
47035 echarts.registerAction('dataZoom', function (payload, ecModel) {
\r
47037 var linkedNodesFinder = modelUtil.createLinkedNodesFinder(
\r
47038 zrUtil.bind(ecModel.eachComponent, ecModel, 'dataZoom'),
\r
47039 modelUtil.eachAxisDim,
\r
47040 function (model, dimNames) {
\r
47041 return model.get(dimNames.axisIndex);
\r
47045 var effectedModels = [];
\r
47047 ecModel.eachComponent(
\r
47048 {mainType: 'dataZoom', query: payload},
\r
47049 function (model, index) {
\r
47050 effectedModels.push.apply(
\r
47051 effectedModels, linkedNodesFinder(model).nodes
\r
47056 zrUtil.each(effectedModels, function (dataZoomModel, index) {
\r
47057 dataZoomModel.setRawRange({
\r
47058 start: payload.start,
\r
47059 end: payload.end,
\r
47060 startValue: payload.startValue,
\r
47061 endValue: payload.endValue
\r
47071 /***/ function(module, exports, __webpack_require__) {
\r
47074 * visualMap component entry
\r
47078 __webpack_require__(301);
\r
47079 __webpack_require__(312);
\r
47085 /***/ function(module, exports, __webpack_require__) {
\r
47088 * DataZoom component entry
\r
47092 __webpack_require__(1).registerPreprocessor(
\r
47093 __webpack_require__(302)
\r
47096 __webpack_require__(303);
\r
47097 __webpack_require__(304);
\r
47098 __webpack_require__(305);
\r
47099 __webpack_require__(308);
\r
47100 __webpack_require__(311);
\r
47106 /***/ function(module, exports, __webpack_require__) {
\r
47109 * @file VisualMap preprocessor
\r
47113 var zrUtil = __webpack_require__(3);
\r
47114 var each = zrUtil.each;
\r
47116 module.exports = function (option) {
\r
47117 var visualMap = option && option.visualMap;
\r
47119 if (!zrUtil.isArray(visualMap)) {
\r
47120 visualMap = visualMap ? [visualMap] : [];
\r
47123 each(visualMap, function (opt) {
\r
47128 // rename splitList to pieces
\r
47129 if (has(opt, 'splitList') && !has(opt, 'pieces')) {
\r
47130 opt.pieces = opt.splitList;
\r
47131 delete opt.splitList;
\r
47134 var pieces = opt.pieces;
\r
47135 if (pieces && zrUtil.isArray(pieces)) {
\r
47136 each(pieces, function (piece) {
\r
47137 if (zrUtil.isObject(piece)) {
\r
47138 if (has(piece, 'start') && !has(piece, 'min')) {
\r
47139 piece.min = piece.start;
\r
47141 if (has(piece, 'end') && !has(piece, 'max')) {
\r
47142 piece.max = piece.end;
\r
47150 function has(obj, name) {
\r
47151 return obj && obj.hasOwnProperty && obj.hasOwnProperty(name);
\r
47158 /***/ function(module, exports, __webpack_require__) {
\r
47162 __webpack_require__(19).registerSubTypeDefaulter('visualMap', function (option) {
\r
47163 // Compatible with ec2, when splitNumber === 0, continuous visualMap will be used.
\r
47165 !option.categories
\r
47169 ? option.pieces.length > 0
\r
47170 : option.splitNumber > 0
\r
47172 || option.calculable
\r
47175 ? 'continuous' : 'piecewise';
\r
47182 /***/ function(module, exports, __webpack_require__) {
\r
47185 * @file Data range visual coding.
\r
47189 var echarts = __webpack_require__(1);
\r
47190 var VisualMapping = __webpack_require__(187);
\r
47191 var zrUtil = __webpack_require__(3);
\r
47193 echarts.registerVisualCoding('component', function (ecModel) {
\r
47194 ecModel.eachComponent('visualMap', function (visualMapModel) {
\r
47195 processSingleVisualMap(visualMapModel, ecModel);
\r
47199 function processSingleVisualMap(visualMapModel, ecModel) {
\r
47200 var visualMappings = visualMapModel.targetVisuals;
\r
47201 var visualTypesMap = {};
\r
47202 zrUtil.each(['inRange', 'outOfRange'], function (state) {
\r
47203 var visualTypes = VisualMapping.prepareVisualTypes(visualMappings[state]);
\r
47204 visualTypesMap[state] = visualTypes;
\r
47207 visualMapModel.eachTargetSeries(function (seriesModel) {
\r
47208 var data = seriesModel.getData();
\r
47209 var dimension = visualMapModel.getDataDimension(data);
\r
47212 function getVisual(key) {
\r
47213 return data.getItemVisual(dataIndex, key);
\r
47216 function setVisual(key, value) {
\r
47217 data.setItemVisual(dataIndex, key, value);
\r
47220 data.each([dimension], function (value, index) {
\r
47221 // For performance consideration, do not use curry.
\r
47222 dataIndex = index;
\r
47223 var valueState = visualMapModel.getValueState(value);
\r
47224 var mappings = visualMappings[valueState];
\r
47225 var visualTypes = visualTypesMap[valueState];
\r
47226 for (var i = 0, len = visualTypes.length; i < len; i++) {
\r
47227 var type = visualTypes[i];
\r
47228 mappings[type] && mappings[type].applyVisual(value, getVisual, setVisual);
\r
47239 /***/ function(module, exports, __webpack_require__) {
\r
47243 * @file Data zoom model
\r
47247 var VisualMapModel = __webpack_require__(306);
\r
47248 var zrUtil = __webpack_require__(3);
\r
47249 var numberUtil = __webpack_require__(7);
\r
47252 var DEFAULT_BAR_BOUND = [20, 140];
\r
47254 var ContinuousModel = VisualMapModel.extend({
\r
47256 type: 'visualMap.continuous',
\r
47262 handlePosition: 'auto', // 'auto', 'left', 'right', 'top', 'bottom'
\r
47263 calculable: false, // 是否值域漫游,启用后无视splitNumber和pieces,线性渐变
\r
47264 range: [-Infinity, Infinity], // 当前选中范围
\r
47267 itemWidth: null, // 值域图形宽度
\r
47268 itemHeight: null // 值域图形高度
\r
47274 doMergeOption: function (newOption, isInit) {
\r
47275 ContinuousModel.superApply(this, 'doMergeOption', arguments);
\r
47277 this.resetTargetSeries(newOption, isInit);
\r
47278 this.resetExtent();
\r
47280 this.resetVisual(function (mappingOption) {
\r
47281 mappingOption.mappingMethod = 'linear';
\r
47284 this._resetRange();
\r
47291 resetItemSize: function () {
\r
47292 VisualMapModel.prototype.resetItemSize.apply(this, arguments);
\r
47294 var itemSize = this.itemSize;
\r
47296 this._orient === 'horizontal' && itemSize.reverse();
\r
47298 (itemSize[0] == null || isNaN(itemSize[0])) && (itemSize[0] = DEFAULT_BAR_BOUND[0]);
\r
47299 (itemSize[1] == null || isNaN(itemSize[1])) && (itemSize[1] = DEFAULT_BAR_BOUND[1]);
\r
47305 _resetRange: function () {
\r
47306 var dataExtent = this.getExtent();
\r
47307 var range = this.option.range;
\r
47308 if (range[0] > range[1]) {
\r
47311 range[0] = Math.max(range[0], dataExtent[0]);
\r
47312 range[1] = Math.min(range[1], dataExtent[1]);
\r
47319 completeVisualOption: function () {
\r
47320 VisualMapModel.prototype.completeVisualOption.apply(this, arguments);
\r
47322 zrUtil.each(this.stateList, function (state) {
\r
47323 var symbolSize = this.option.controller[state].symbolSize;
\r
47324 if (symbolSize && symbolSize[0] !== symbolSize[1]) {
\r
47325 symbolSize[0] = 0; // For good looking.
\r
47334 setSelected: function (selected) {
\r
47335 this.option.range = selected.slice();
\r
47336 this._resetRange();
\r
47342 getSelected: function () {
\r
47343 var dataExtent = this.getExtent();
\r
47345 var dataInterval = numberUtil.asc(
\r
47346 (this.get('range') || []).slice()
\r
47350 dataInterval[0] > dataExtent[1] && (dataInterval[0] = dataExtent[1]);
\r
47351 dataInterval[1] > dataExtent[1] && (dataInterval[1] = dataExtent[1]);
\r
47352 dataInterval[0] < dataExtent[0] && (dataInterval[0] = dataExtent[0]);
\r
47353 dataInterval[1] < dataExtent[0] && (dataInterval[1] = dataExtent[0]);
\r
47355 return dataInterval;
\r
47362 getValueState: function (value) {
\r
47363 var range = this.option.range;
\r
47364 var dataExtent = this.getExtent();
\r
47366 // When range[0] === dataExtent[0], any value larger than dataExtent[0] maps to 'inRange'.
\r
47367 // range[1] is processed likewise.
\r
47369 (range[0] <= dataExtent[0] || range[0] <= value)
\r
47370 && (range[1] >= dataExtent[1] || value <= range[1])
\r
47371 ) ? 'inRange' : 'outOfRange';
\r
47376 module.exports = ContinuousModel;
\r
47382 /***/ function(module, exports, __webpack_require__) {
\r
47385 * @file Data zoom model
\r
47389 var zrUtil = __webpack_require__(3);
\r
47390 var env = __webpack_require__(78);
\r
47391 var echarts = __webpack_require__(1);
\r
47392 var modelUtil = __webpack_require__(5);
\r
47393 var visualDefault = __webpack_require__(307);
\r
47394 var VisualMapping = __webpack_require__(187);
\r
47395 var mapVisual = VisualMapping.mapVisual;
\r
47396 var eachVisual = VisualMapping.eachVisual;
\r
47397 var numberUtil = __webpack_require__(7);
\r
47398 var isArray = zrUtil.isArray;
\r
47399 var each = zrUtil.each;
\r
47400 var asc = numberUtil.asc;
\r
47401 var linearMap = numberUtil.linearMap;
\r
47403 var VisualMapModel = echarts.extendComponentModel({
\r
47405 type: 'visualMap',
\r
47407 dependencies: ['series'],
\r
47410 * [lowerBound, upperBound]
\r
47413 * @type {Array.<number>}
\r
47415 dataBound: [-Infinity, Infinity],
\r
47419 * @type {Array.<string>}
\r
47421 stateList: ['inRange', 'outOfRange'],
\r
47425 * @type {string|Object}
\r
47427 layoutMode: {type: 'box', ignoreSize: true},
\r
47438 // set min: 0, max: 200, only for campatible with ec2.
\r
47439 // In fact min max should not have default value.
\r
47440 min: 0, // min value, must specified if pieces is not specified.
\r
47441 max: 200, // max value, must specified if pieces is not specified.
\r
47444 inRange: null, // 'color', 'colorHue', 'colorSaturation', 'colorLightness', 'colorAlpha',
\r
47445 // 'symbol', 'symbolSize'
\r
47446 outOfRange: null, // 'color', 'colorHue', 'colorSaturation',
\r
47447 // 'colorLightness', 'colorAlpha',
\r
47448 // 'symbol', 'symbolSize'
\r
47450 left: 0, // 'center' ¦ 'left' ¦ 'right' ¦ {number} (px)
\r
47451 right: null, // The same as left.
\r
47452 top: null, // 'top' ¦ 'bottom' ¦ 'center' ¦ {number} (px)
\r
47453 bottom: 0, // The same as top.
\r
47456 itemHeight: null,
\r
47458 orient: 'vertical', // 'horizontal' ¦ 'vertical'
\r
47460 seriesIndex: null, // 所控制的series indices,默认所有有value的series.
\r
47461 backgroundColor: 'rgba(0,0,0,0)',
\r
47462 borderColor: '#ccc', // 值域边框颜色
\r
47463 contentColor: '#5793f3',
\r
47464 inactiveColor: '#aaa',
\r
47465 borderWidth: 0, // 值域边框线宽,单位px,默认为0(无边框)
\r
47466 padding: 5, // 值域内边距,单位px,默认各方向内边距为5,
\r
47467 // 接受数组分别设定上右下左边距,同css
\r
47469 precision: 0, // 小数精度,默认为0,无小数点
\r
47470 color: ['#bf444c', '#d88273', '#f6efa6'], //颜色(deprecated,兼容ec2,顺序同pieces,不同于inRange/outOfRange)
\r
47473 text: null, // 文本,如['高', '低'],兼容ec2,text[0]对应高值,text[1]对应低值
\r
47475 color: '#333' // 值域文字颜色
\r
47482 init: function (option, parentModel, ecModel) {
\r
47485 * @type {boolean}
\r
47487 this._autoSeriesIndex = false;
\r
47491 * @type {Array.<number>}
\r
47493 this._dataExtent;
\r
47498 this.controllerVisuals = {};
\r
47503 this.targetVisuals = {};
\r
47508 this.textStyleModel;
\r
47511 * [width, height]
\r
47513 * @type {Array.<number>}
\r
47517 this.mergeDefaultAndTheme(option, ecModel);
\r
47519 this.doMergeOption({}, true);
\r
47525 mergeOption: function (option) {
\r
47526 VisualMapModel.superApply(this, 'mergeOption', arguments);
\r
47527 this.doMergeOption(option, false);
\r
47533 doMergeOption: function (newOption, isInit) {
\r
47534 var thisOption = this.option;
\r
47536 // Visual attributes merge is not supported, otherwise it
\r
47537 // brings overcomplicated merge logic. See #2853.
\r
47538 !isInit && replaceVisualOption(thisOption, newOption);
\r
47542 // Disable realtime view update if canvas is not supported.
\r
47543 if (!env.canvasSupported) {
\r
47544 thisOption.realtime = false;
\r
47547 this.textStyleModel = this.getModel('textStyle');
\r
47549 this.resetItemSize();
\r
47551 this.completeVisualOption();
\r
47556 * this.formatValueText(someVal); // format single numeric value to text.
\r
47557 * this.formatValueText(someVal, true); // format single category value to text.
\r
47558 * this.formatValueText([min, max]); // format numeric min-max to text.
\r
47559 * this.formatValueText([this.dataBound[0], max]); // using data lower bound.
\r
47560 * this.formatValueText([min, this.dataBound[1]]); // using data upper bound.
\r
47562 * @param {number|Array.<number>} value Real value, or this.dataBound[0 or 1].
\r
47563 * @param {boolean} [isCategory=false] Only available when value is number.
\r
47564 * @return {string}
\r
47567 formatValueText: function(value, isCategory) {
\r
47568 var option = this.option;
\r
47569 var precision = option.precision;
\r
47570 var dataBound = this.dataBound;
\r
47571 var formatter = option.formatter;
\r
47575 if (zrUtil.isArray(value)) {
\r
47576 value = value.slice();
\r
47580 textValue = isCategory
\r
47583 ? [toFixed(value[0]), toFixed(value[1])]
\r
47587 if (zrUtil.isString(formatter)) {
\r
47589 .replace('{value}', isMinMax ? textValue[0] : textValue)
\r
47590 .replace('{value2}', isMinMax ? textValue[1] : textValue);
\r
47592 else if (zrUtil.isFunction(formatter)) {
\r
47594 ? formatter(value[0], value[1])
\r
47595 : formatter(value);
\r
47599 if (value[0] === dataBound[0]) {
\r
47600 return '< ' + textValue[1];
\r
47602 else if (value[1] === dataBound[1]) {
\r
47603 return '> ' + textValue[0];
\r
47606 return textValue[0] + ' - ' + textValue[1];
\r
47609 else { // Format single value (includes category case).
\r
47610 return textValue;
\r
47613 function toFixed(val) {
\r
47614 return val === dataBound[0]
\r
47616 : val === dataBound[1]
\r
47618 : (+val).toFixed(precision);
\r
47625 resetTargetSeries: function (newOption, isInit) {
\r
47626 var thisOption = this.option;
\r
47627 var autoSeriesIndex = this._autoSeriesIndex =
\r
47628 (isInit ? thisOption : newOption).seriesIndex == null;
\r
47629 thisOption.seriesIndex = autoSeriesIndex
\r
47630 ? [] : modelUtil.normalizeToArray(thisOption.seriesIndex);
\r
47632 autoSeriesIndex && this.ecModel.eachSeries(function (seriesModel, index) {
\r
47633 var data = seriesModel.getData();
\r
47635 // 只考虑了list,还没有考虑map等。
\r
47638 // 这里可能应该这么判断:data.dimensions中有超出其所属coordSystem的量。
\r
47639 if (data.type === 'list') {
\r
47640 thisOption.seriesIndex.push(index);
\r
47648 resetExtent: function () {
\r
47649 var thisOption = this.option;
\r
47651 // Can not calculate data extent by data here.
\r
47652 // Because series and data may be modified in processing stage.
\r
47653 // So we do not support the feature "auto min/max".
\r
47655 var extent = asc([thisOption.min, thisOption.max]);
\r
47657 this._dataExtent = extent;
\r
47663 getDataDimension: function (list) {
\r
47664 var optDim = this.option.dimension;
\r
47665 return optDim != null
\r
47666 ? optDim : list.dimensions.length - 1;
\r
47673 getExtent: function () {
\r
47674 return this._dataExtent.slice();
\r
47680 resetVisual: function (fillVisualOption) {
\r
47681 var dataExtent = this.getExtent();
\r
47683 doReset.call(this, 'controller', this.controllerVisuals);
\r
47684 doReset.call(this, 'target', this.targetVisuals);
\r
47686 function doReset(baseAttr, visualMappings) {
\r
47687 each(this.stateList, function (state) {
\r
47688 var mappings = visualMappings[state] || (visualMappings[state] = {});
\r
47689 var visaulOption = this.option[baseAttr][state] || {};
\r
47690 each(visaulOption, function (visualData, visualType) {
\r
47691 if (!VisualMapping.isValidType(visualType)) {
\r
47694 var mappingOption = {
\r
47695 type: visualType,
\r
47696 dataExtent: dataExtent,
\r
47697 visual: visualData
\r
47699 fillVisualOption && fillVisualOption.call(this, mappingOption, state);
\r
47700 mappings[visualType] = new VisualMapping(mappingOption);
\r
47709 completeVisualOption: function () {
\r
47710 var thisOption = this.option;
\r
47711 var base = {inRange: thisOption.inRange, outOfRange: thisOption.outOfRange};
\r
47713 var target = thisOption.target || (thisOption.target = {});
\r
47714 var controller = thisOption.controller || (thisOption.controller = {});
\r
47716 zrUtil.merge(target, base); // Do not override
\r
47717 zrUtil.merge(controller, base); // Do not override
\r
47719 var isCategory = this.isCategory();
\r
47721 completeSingle.call(this, target);
\r
47722 completeSingle.call(this, controller);
\r
47723 completeInactive.call(this, target, 'inRange', 'outOfRange');
\r
47724 completeInactive.call(this, target, 'outOfRange', 'inRange');
\r
47725 completeController.call(this, controller);
\r
47727 function completeSingle(base) {
\r
47728 // Compatible with ec2 dataRange.color.
\r
47729 // The mapping order of dataRange.color is: [high value, ..., low value]
\r
47730 // whereas inRange.color and outOfRange.color is [low value, ..., high value]
\r
47731 // Notice: ec2 has no inverse.
\r
47732 if (isArray(thisOption.color)
\r
47733 // If there has been inRange: {symbol: ...}, adding color is a mistake.
\r
47734 // So adding color only when no inRange defined.
\r
47737 base.inRange = {color: thisOption.color.slice().reverse()};
\r
47740 // If using shortcut like: {inRange: 'symbol'}, complete default value.
\r
47741 each(this.stateList, function (state) {
\r
47742 var visualType = base[state];
\r
47744 if (zrUtil.isString(visualType)) {
\r
47745 var defa = visualDefault.get(visualType, 'active', isCategory);
\r
47747 base[state] = {};
\r
47748 base[state][visualType] = defa;
\r
47751 // Mark as not specified.
\r
47752 delete base[state];
\r
47758 function completeInactive(base, stateExist, stateAbsent) {
\r
47759 var optExist = base[stateExist];
\r
47760 var optAbsent = base[stateAbsent];
\r
47762 if (optExist && !optAbsent) {
\r
47763 optAbsent = base[stateAbsent] = {};
\r
47764 each(optExist, function (visualData, visualType) {
\r
47765 var defa = visualDefault.get(visualType, 'inactive', isCategory);
\r
47766 if (VisualMapping.isValidType(visualType) && defa) {
\r
47767 optAbsent[visualType] = defa;
\r
47773 function completeController(controller) {
\r
47774 var symbolExists = (controller.inRange || {}).symbol
\r
47775 || (controller.outOfRange || {}).symbol;
\r
47776 var symbolSizeExists = (controller.inRange || {}).symbolSize
\r
47777 || (controller.outOfRange || {}).symbolSize;
\r
47778 var inactiveColor = this.get('inactiveColor');
\r
47780 each(this.stateList, function (state) {
\r
47782 var itemSize = this.itemSize;
\r
47783 var visuals = controller[state];
\r
47785 // Set inactive color for controller if no other color attr (like colorAlpha) specified.
\r
47787 visuals = controller[state] = {
\r
47788 color: isCategory ? inactiveColor : [inactiveColor]
\r
47792 // Consistent symbol and symbolSize if not specified.
\r
47793 if (!visuals.symbol) {
\r
47794 visuals.symbol = symbolExists
\r
47795 && zrUtil.clone(symbolExists)
\r
47796 || (isCategory ? 'roundRect' : ['roundRect']);
\r
47798 if (!visuals.symbolSize) {
\r
47799 visuals.symbolSize = symbolSizeExists
\r
47800 && zrUtil.clone(symbolSizeExists)
\r
47801 || (isCategory ? itemSize[0] : [itemSize[0], itemSize[0]]);
\r
47804 // Filter square and none.
\r
47805 visuals.symbol = mapVisual(visuals.symbol, function (symbol) {
\r
47806 return (symbol === 'none' || symbol === 'square') ? 'roundRect' : symbol;
\r
47809 // Normalize symbolSize
\r
47810 var symbolSize = visuals.symbolSize;
\r
47812 if (symbolSize) {
\r
47813 var max = -Infinity;
\r
47814 // symbolSize can be object when categories defined.
\r
47815 eachVisual(symbolSize, function (value) {
\r
47816 value > max && (max = value);
\r
47818 visuals.symbolSize = mapVisual(symbolSize, function (value) {
\r
47819 return linearMap(value, [0, max], [0, itemSize[0]], true);
\r
47830 eachTargetSeries: function (callback, context) {
\r
47831 zrUtil.each(this.option.seriesIndex, function (seriesIndex) {
\r
47832 callback.call(context, this.ecModel.getSeriesByIndex(seriesIndex));
\r
47839 isCategory: function () {
\r
47840 return !!this.option.categories;
\r
47846 resetItemSize: function () {
\r
47847 this.itemSize = [
\r
47848 parseFloat(this.get('itemWidth')),
\r
47849 parseFloat(this.get('itemHeight'))
\r
47857 setSelected: zrUtil.noop,
\r
47863 getValueState: zrUtil.noop
\r
47867 function replaceVisualOption(targetOption, sourceOption) {
\r
47869 ['inRange', 'outOfRange', 'target', 'controller', 'color'],
\r
47871 if (sourceOption.hasOwnProperty(key)) {
\r
47872 targetOption[key] = zrUtil.clone(sourceOption[key]);
\r
47875 delete targetOption[key];
\r
47881 module.exports = VisualMapModel;
\r
47887 /***/ function(module, exports, __webpack_require__) {
\r
47890 * @file Visual mapping.
\r
47894 var zrUtil = __webpack_require__(3);
\r
47896 var visualDefault = {
\r
47901 get: function (visualType, key, isCategory) {
\r
47902 var value = zrUtil.clone(
\r
47903 (defaultOption[visualType] || {})[key]
\r
47906 return isCategory
\r
47907 ? (zrUtil.isArray(value) ? value[value.length - 1] : value)
\r
47913 var defaultOption = {
\r
47916 active: ['#006edd', '#e0ffff'],
\r
47917 inactive: ['rgba(0,0,0,0)']
\r
47921 active: [0, 360],
\r
47925 colorSaturation: {
\r
47926 active: [0.3, 1],
\r
47930 colorLightness: {
\r
47931 active: [0.9, 0.5],
\r
47936 active: [0.3, 1],
\r
47941 active: ['circle', 'roundRect', 'diamond'],
\r
47942 inactive: ['none']
\r
47946 active: [10, 50],
\r
47951 module.exports = visualDefault;
\r
47958 /***/ function(module, exports, __webpack_require__) {
\r
47962 var VisualMapView = __webpack_require__(309);
\r
47963 var graphic = __webpack_require__(42);
\r
47964 var zrUtil = __webpack_require__(3);
\r
47965 var numberUtil = __webpack_require__(7);
\r
47966 var sliderMove = __webpack_require__(294);
\r
47967 var linearMap = numberUtil.linearMap;
\r
47968 var LinearGradient = __webpack_require__(75);
\r
47969 var helper = __webpack_require__(310);
\r
47970 var each = zrUtil.each;
\r
47973 // Any "interval" should be by the order of [low, high].
\r
47974 // "handle0" (handleIndex === 0) maps to
\r
47975 // low data value: this._dataInterval[0] and has low coord.
\r
47976 // "handle1" (handleIndex === 1) maps to
\r
47977 // high data value: this._dataInterval[1] and has high coord.
\r
47978 // The logic of transform is implemented in this._createBarGroup.
\r
47980 var ContinuousVisualMapView = VisualMapView.extend({
\r
47982 type: 'visualMap.continuous',
\r
47987 init: function () {
\r
47989 VisualMapView.prototype.init.apply(this, arguments);
\r
47994 this._shapes = {};
\r
47999 this._dataInterval = [];
\r
48004 this._handleEnds = [];
\r
48021 doRender: function (visualMapModel, ecModel, api, payload) {
\r
48022 if (!payload || payload.type !== 'selectDataRange' || payload.from !== this.uid) {
\r
48023 this._buildView();
\r
48026 this._updateView();
\r
48033 _buildView: function () {
\r
48034 this.group.removeAll();
\r
48036 var visualMapModel = this.visualMapModel;
\r
48037 var thisGroup = this.group;
\r
48039 this._orient = visualMapModel.get('orient');
\r
48040 this._useHandle = visualMapModel.get('calculable');
\r
48042 this._resetInterval();
\r
48044 this._renderBar(thisGroup);
\r
48046 var dataRangeText = visualMapModel.get('text');
\r
48047 this._renderEndsText(thisGroup, dataRangeText, 0);
\r
48048 this._renderEndsText(thisGroup, dataRangeText, 1);
\r
48050 // Do this for background size calculation.
\r
48051 this._updateView(true);
\r
48053 // After updating view, inner shapes is built completely,
\r
48054 // and then background can be rendered.
\r
48055 this.renderBackground(thisGroup);
\r
48057 // Real update view
\r
48058 this._updateView();
\r
48060 this.positionGroup(thisGroup);
\r
48066 _renderEndsText: function (group, dataRangeText, endsIndex) {
\r
48067 if (!dataRangeText) {
\r
48071 // Compatible with ec2, text[0] map to high value, text[1] map low value.
\r
48072 var text = dataRangeText[1 - endsIndex];
\r
48073 text = text != null ? text + '' : '';
\r
48075 var visualMapModel = this.visualMapModel;
\r
48076 var textGap = visualMapModel.get('textGap');
\r
48077 var itemSize = visualMapModel.itemSize;
\r
48079 var barGroup = this._shapes.barGroup;
\r
48080 var position = this._applyTransform(
\r
48083 endsIndex === 0 ? -textGap : itemSize[1] + textGap
\r
48087 var align = this._applyTransform(
\r
48088 endsIndex === 0 ? 'bottom' : 'top',
\r
48091 var orient = this._orient;
\r
48092 var textStyleModel = this.visualMapModel.textStyleModel;
\r
48094 this.group.add(new graphic.Text({
\r
48098 textVerticalAlign: orient === 'horizontal' ? 'middle' : align,
\r
48099 textAlign: orient === 'horizontal' ? align : 'center',
\r
48101 textFont: textStyleModel.getFont(),
\r
48102 fill: textStyleModel.getTextColor()
\r
48110 _renderBar: function (targetGroup) {
\r
48111 var visualMapModel = this.visualMapModel;
\r
48112 var shapes = this._shapes;
\r
48113 var itemSize = visualMapModel.itemSize;
\r
48114 var orient = this._orient;
\r
48115 var useHandle = this._useHandle;
\r
48116 var itemAlign = helper.getItemAlign(visualMapModel, this.api, itemSize);
\r
48117 var barGroup = shapes.barGroup = this._createBarGroup(itemAlign);
\r
48120 barGroup.add(shapes.outOfRange = createPolygon());
\r
48121 barGroup.add(shapes.inRange = createPolygon(
\r
48123 zrUtil.bind(this._modifyHandle, this, 'all'),
\r
48124 useHandle ? 'move' : null
\r
48127 var textRect = visualMapModel.textStyleModel.getTextRect('国');
\r
48128 var textSize = Math.max(textRect.width, textRect.height);
\r
48132 shapes.handleGroups = [];
\r
48133 shapes.handleThumbs = [];
\r
48134 shapes.handleLabels = [];
\r
48135 shapes.handleLabelPoints = [];
\r
48137 this._createHandle(barGroup, 0, itemSize, textSize, orient, itemAlign);
\r
48138 this._createHandle(barGroup, 1, itemSize, textSize, orient, itemAlign);
\r
48144 targetGroup.add(barGroup);
\r
48150 _createHandle: function (barGroup, handleIndex, itemSize, textSize, orient) {
\r
48151 var handleGroup = new graphic.Group({position: [itemSize[0], 0]});
\r
48152 var handleThumb = createPolygon(
\r
48153 createHandlePoints(handleIndex, textSize),
\r
48154 zrUtil.bind(this._modifyHandle, this, handleIndex),
\r
48157 handleGroup.add(handleThumb);
\r
48159 // For text locating. Text is always horizontal layout
\r
48160 // but should not be effected by transform.
\r
48161 var handleLabelPoint = {
\r
48162 x: orient === 'horizontal'
\r
48164 : textSize * 1.5,
\r
48165 y: orient === 'horizontal'
\r
48166 ? (handleIndex === 0 ? -(textSize * 1.5) : (textSize * 1.5))
\r
48167 : (handleIndex === 0 ? -textSize / 2 : textSize / 2)
\r
48170 var textStyleModel = this.visualMapModel.textStyleModel;
\r
48171 var handleLabel = new graphic.Text({
\r
48174 x: 0, y: 0, text: '',
\r
48175 textVerticalAlign: 'middle',
\r
48176 textFont: textStyleModel.getFont(),
\r
48177 fill: textStyleModel.getTextColor()
\r
48181 this.group.add(handleLabel); // Text do not transform
\r
48183 var shapes = this._shapes;
\r
48184 shapes.handleThumbs[handleIndex] = handleThumb;
\r
48185 shapes.handleGroups[handleIndex] = handleGroup;
\r
48186 shapes.handleLabelPoints[handleIndex] = handleLabelPoint;
\r
48187 shapes.handleLabels[handleIndex] = handleLabel;
\r
48189 barGroup.add(handleGroup);
\r
48195 _modifyHandle: function (handleIndex, dx, dy) {
\r
48196 if (!this._useHandle) {
\r
48200 // Transform dx, dy to bar coordination.
\r
48201 var vertex = this._applyTransform([dx, dy], this._shapes.barGroup, true);
\r
48202 this._updateInterval(handleIndex, vertex[1]);
\r
48204 this.api.dispatchAction({
\r
48205 type: 'selectDataRange',
\r
48207 visualMapId: this.visualMapModel.id,
\r
48208 selected: this._dataInterval.slice()
\r
48215 _resetInterval: function () {
\r
48216 var visualMapModel = this.visualMapModel;
\r
48218 var dataInterval = this._dataInterval = visualMapModel.getSelected();
\r
48219 var dataExtent = visualMapModel.getExtent();
\r
48220 var sizeExtent = [0, visualMapModel.itemSize[1]];
\r
48222 this._handleEnds = [
\r
48223 linearMap(dataInterval[0], dataExtent, sizeExtent,true),
\r
48224 linearMap(dataInterval[1], dataExtent, sizeExtent,true)
\r
48230 * @param {(number|string)} handleIndex 0 or 1 or 'all'
\r
48231 * @param {number} dx
\r
48232 * @param {number} dy
\r
48234 _updateInterval: function (handleIndex, delta) {
\r
48235 delta = delta || 0;
\r
48236 var visualMapModel = this.visualMapModel;
\r
48237 var handleEnds = this._handleEnds;
\r
48242 [0, visualMapModel.itemSize[1]],
\r
48243 handleIndex === 'all' ? 'rigid' : 'push',
\r
48246 var dataExtent = visualMapModel.getExtent();
\r
48247 var sizeExtent = [0, visualMapModel.itemSize[1]];
\r
48248 // Update data interval.
\r
48249 this._dataInterval = [
\r
48250 linearMap(handleEnds[0], sizeExtent, dataExtent, true),
\r
48251 linearMap(handleEnds[1], sizeExtent, dataExtent, true)
\r
48258 _updateView: function (forSketch) {
\r
48259 var visualMapModel = this.visualMapModel;
\r
48260 var dataExtent = visualMapModel.getExtent();
\r
48261 var shapes = this._shapes;
\r
48262 var dataInterval = this._dataInterval;
\r
48264 var outOfRangeHandleEnds = [0, visualMapModel.itemSize[1]];
\r
48265 var inRangeHandleEnds = forSketch ? outOfRangeHandleEnds : this._handleEnds;
\r
48267 var visualInRange = this._createBarVisual(
\r
48268 dataInterval, dataExtent, inRangeHandleEnds, 'inRange'
\r
48270 var visualOutOfRange = this._createBarVisual(
\r
48271 dataExtent, dataExtent, outOfRangeHandleEnds, 'outOfRange'
\r
48275 .setStyle('fill', visualInRange.barColor)
\r
48276 .setShape('points', visualInRange.barPoints);
\r
48277 shapes.outOfRange
\r
48278 .setStyle('fill', visualOutOfRange.barColor)
\r
48279 .setShape('points', visualOutOfRange.barPoints);
\r
48281 this._useHandle && each([0, 1], function (handleIndex) {
\r
48283 shapes.handleThumbs[handleIndex].setStyle(
\r
48284 'fill', visualInRange.handlesColor[handleIndex]
\r
48287 shapes.handleLabels[handleIndex].setStyle({
\r
48288 text: visualMapModel.formatValueText(dataInterval[handleIndex]),
\r
48289 textAlign: this._applyTransform(
\r
48290 this._orient === 'horizontal'
\r
48291 ? (handleIndex === 0 ? 'bottom' : 'top')
\r
48299 this._updateHandlePosition(inRangeHandleEnds);
\r
48305 _createBarVisual: function (dataInterval, dataExtent, handleEnds, forceState) {
\r
48306 var colorStops = this.getControllerVisual(dataInterval, forceState, 'color').color;
\r
48308 var symbolSizes = [
\r
48309 this.getControllerVisual(dataInterval[0], forceState, 'symbolSize').symbolSize,
\r
48310 this.getControllerVisual(dataInterval[1], forceState, 'symbolSize').symbolSize
\r
48312 var barPoints = this._createBarPoints(handleEnds, symbolSizes);
\r
48315 barColor: new LinearGradient(0, 0, 1, 1, colorStops),
\r
48316 barPoints: barPoints,
\r
48318 colorStops[0].color,
\r
48319 colorStops[colorStops.length - 1].color
\r
48327 _createBarPoints: function (handleEnds, symbolSizes) {
\r
48328 var itemSize = this.visualMapModel.itemSize;
\r
48331 [itemSize[0] - symbolSizes[0], handleEnds[0]],
\r
48332 [itemSize[0], handleEnds[0]],
\r
48333 [itemSize[0], handleEnds[1]],
\r
48334 [itemSize[0] - symbolSizes[1], handleEnds[1]]
\r
48341 _createBarGroup: function (itemAlign) {
\r
48342 var orient = this._orient;
\r
48343 var inverse = this.visualMapModel.get('inverse');
\r
48345 return new graphic.Group(
\r
48346 (orient === 'horizontal' && !inverse)
\r
48347 ? {scale: itemAlign === 'bottom' ? [1, 1] : [-1, 1], rotation: Math.PI / 2}
\r
48348 : (orient === 'horizontal' && inverse)
\r
48349 ? {scale: itemAlign === 'bottom' ? [-1, 1] : [1, 1], rotation: -Math.PI / 2}
\r
48350 : (orient === 'vertical' && !inverse)
\r
48351 ? {scale: itemAlign === 'left' ? [1, -1] : [-1, -1]}
\r
48352 : {scale: itemAlign === 'left' ? [1, 1] : [-1, 1]}
\r
48359 _updateHandlePosition: function (handleEnds) {
\r
48360 if (!this._useHandle) {
\r
48364 var shapes = this._shapes;
\r
48366 each([0, 1], function (handleIndex) {
\r
48367 var handleGroup = shapes.handleGroups[handleIndex];
\r
48368 handleGroup.position[1] = handleEnds[handleIndex];
\r
48370 // Update handle label position.
\r
48371 var labelPoint = shapes.handleLabelPoints[handleIndex];
\r
48372 var textPoint = graphic.applyTransform(
\r
48373 [labelPoint.x, labelPoint.y],
\r
48374 graphic.getTransform(handleGroup, this.group)
\r
48377 shapes.handleLabels[handleIndex].setStyle({
\r
48378 x: textPoint[0], y: textPoint[1]
\r
48386 _applyTransform: function (vertex, element, inverse) {
\r
48387 var transform = graphic.getTransform(element, this.group);
\r
48390 zrUtil.isArray(vertex)
\r
48391 ? 'applyTransform' : 'transformDirection'
\r
48392 ](vertex, transform, inverse);
\r
48397 function createPolygon(points, onDrift, cursor) {
\r
48398 return new graphic.Polygon({
\r
48399 shape: {points: points},
\r
48400 draggable: !!onDrift,
\r
48406 function createHandlePoints(handleIndex, textSize) {
\r
48407 return handleIndex === 0
\r
48408 ? [[0, 0], [textSize, 0], [textSize, -textSize]]
\r
48409 : [[0, 0], [textSize, 0], [textSize, textSize]];
\r
48412 module.exports = ContinuousVisualMapView;
\r
48418 /***/ function(module, exports, __webpack_require__) {
\r
48422 var echarts = __webpack_require__(1);
\r
48423 var zrUtil = __webpack_require__(3);
\r
48424 var graphic = __webpack_require__(42);
\r
48425 var formatUtil = __webpack_require__(6);
\r
48426 var layout = __webpack_require__(21);
\r
48427 var VisualMapping = __webpack_require__(187);
\r
48429 module.exports = echarts.extendComponentView({
\r
48431 type: 'visualMap',
\r
48437 autoPositionValues: {left: 1, right: 1, top: 1, bottom: 1},
\r
48439 init: function (ecModel, api) {
\r
48442 * @type {module:echarts/model/Global}
\r
48444 this.ecModel = ecModel;
\r
48448 * @type {module:echarts/ExtensionAPI}
\r
48454 * @type {module:echarts/component/visualMap/visualMapModel}
\r
48456 this.visualMapModel;
\r
48462 this._updatableShapes = {};
\r
48468 render: function (visualMapModel, ecModel, api, payload) {
\r
48469 this.visualMapModel = visualMapModel;
\r
48471 if (visualMapModel.get('show') === false) {
\r
48472 this.group.removeAll();
\r
48476 this.doRender.apply(this, arguments);
\r
48482 renderBackground: function (group) {
\r
48483 var visualMapModel = this.visualMapModel;
\r
48484 var padding = formatUtil.normalizeCssArray(visualMapModel.get('padding') || 0);
\r
48485 var rect = group.getBoundingRect();
\r
48487 group.add(new graphic.Rect({
\r
48488 z2: -1, // Lay background rect on the lowest layer.
\r
48491 x: rect.x - padding[3],
\r
48492 y: rect.y - padding[0],
\r
48493 width: rect.width + padding[3] + padding[1],
\r
48494 height: rect.height + padding[0] + padding[2]
\r
48497 fill: visualMapModel.get('backgroundColor'),
\r
48498 stroke: visualMapModel.get('borderColor'),
\r
48499 lineWidth: visualMapModel.get('borderWidth')
\r
48506 * @param {(number|Array)} targetValue
\r
48507 * @param {string=} forceState Specify state, instead of using getValueState method.
\r
48508 * @param {string=} visualCluster Specify visual type, defualt all available visualClusters.
\r
48510 getControllerVisual: function (targetValue, forceState, visualCluster) {
\r
48511 var visualMapModel = this.visualMapModel;
\r
48512 var targetIsArray = zrUtil.isArray(targetValue);
\r
48514 // targetValue is array when caculate gradient color,
\r
48515 // where forceState is required.
\r
48516 if (targetIsArray && (!forceState || visualCluster !== 'color')) {
\r
48517 throw new Error(targetValue);
\r
48520 var mappings = visualMapModel.controllerVisuals[
\r
48521 forceState || visualMapModel.getValueState(targetValue)
\r
48523 var defaultColor = visualMapModel.get('contentColor');
\r
48524 var visualObj = {
\r
48525 symbol: visualMapModel.get('itemSymbol'),
\r
48526 color: targetIsArray
\r
48527 ? [{color: defaultColor, offset: 0}, {color: defaultColor, offset: 1}]
\r
48531 function getter(key) {
\r
48532 return visualObj[key];
\r
48535 function setter(key, value) {
\r
48536 visualObj[key] = value;
\r
48539 var visualTypes = VisualMapping.prepareVisualTypes(mappings);
\r
48541 zrUtil.each(visualTypes, function (type) {
\r
48542 var visualMapping = mappings[type];
\r
48543 if (!visualCluster || VisualMapping.isInVisualCluster(type, visualCluster)) {
\r
48544 visualMapping && visualMapping.applyVisual(targetValue, getter, setter);
\r
48548 return visualObj;
\r
48554 positionGroup: function (group) {
\r
48555 var model = this.visualMapModel;
\r
48556 var api = this.api;
\r
48558 layout.positionGroup(
\r
48560 model.getBoxLayoutParams(),
\r
48561 {width: api.getWidth(), height: api.getHeight()}
\r
48569 doRender: zrUtil.noop
\r
48576 /***/ function(module, exports, __webpack_require__) {
\r
48580 var layout = __webpack_require__(21);
\r
48585 * @param {module:echarts/component/visualMap/VisualMapModel} visualMapModel\
\r
48586 * @param {module:echarts/ExtensionAPI} api
\r
48587 * @param {Array.<number>} itemSize always [short, long]
\r
48588 * @return {string} 'left' or 'right' or 'top' or 'bottom'
\r
48590 getItemAlign: function (visualMapModel, api, itemSize) {
\r
48591 var modelOption = visualMapModel.option;
\r
48592 var itemAlign = modelOption.align;
\r
48594 if (itemAlign != null && itemAlign !== 'auto') {
\r
48595 return itemAlign;
\r
48598 // Auto decision align.
\r
48599 var ecSize = {width: api.getWidth(), height: api.getHeight()};
\r
48600 var realIndex = modelOption.orient === 'horizontal' ? 1 : 0;
\r
48602 var paramsSet = [
\r
48603 ['left', 'right', 'width'],
\r
48604 ['top', 'bottom', 'height']
\r
48606 var reals = paramsSet[realIndex];
\r
48607 var fakeValue = [0, null, 10];
\r
48609 var layoutInput = {};
\r
48610 for (var i = 0; i < 3; i++) {
\r
48611 layoutInput[paramsSet[1 - realIndex][i]] = fakeValue[i];
\r
48612 layoutInput[reals[i]] = i === 2 ? itemSize[0] : modelOption[reals[i]];
\r
48615 var rParam = [['x', 'width', 3], ['y', 'height', 0]][realIndex];
\r
48616 var rect = layout.getLayoutRect(layoutInput, ecSize, modelOption.padding);
\r
48619 (rect.margin[rParam[2]] || 0) + rect[rParam[0]] + rect[rParam[1]] * 0.5
\r
48620 < ecSize[rParam[1]] * 0.5 ? 0 : 1
\r
48625 module.exports = helper;
\r
48631 /***/ function(module, exports, __webpack_require__) {
\r
48634 * @file Data range action
\r
48638 var echarts = __webpack_require__(1);
\r
48640 var actionInfo = {
\r
48641 type: 'selectDataRange',
\r
48642 event: 'dataRangeSelected',
\r
48643 // FIXME use updateView appears wrong
\r
48647 echarts.registerAction(actionInfo, function (payload, ecModel) {
\r
48649 ecModel.eachComponent({mainType: 'visualMap', query: payload}, function (model) {
\r
48650 model.setSelected(payload.selected);
\r
48659 /***/ function(module, exports, __webpack_require__) {
\r
48662 * DataZoom component entry
\r
48666 __webpack_require__(1).registerPreprocessor(
\r
48667 __webpack_require__(302)
\r
48670 __webpack_require__(303);
\r
48671 __webpack_require__(304);
\r
48672 __webpack_require__(313);
\r
48673 __webpack_require__(314);
\r
48674 __webpack_require__(311);
\r
48680 /***/ function(module, exports, __webpack_require__) {
\r
48684 var VisualMapModel = __webpack_require__(306);
\r
48685 var zrUtil = __webpack_require__(3);
\r
48686 var VisualMapping = __webpack_require__(187);
\r
48688 var PiecewiseModel = VisualMapModel.extend({
\r
48690 type: 'visualMap.piecewise',
\r
48695 * option.categories / option.pieces / option.text / option.selected:
\r
48696 * If !option.inverse,
\r
48697 * Order when vertical: ['top', ..., 'bottom'].
\r
48698 * Order when horizontal: ['left', ..., 'right'].
\r
48699 * If option.inverse, the meaning of
\r
48700 * the order should be reversed.
\r
48702 * this._pieceList:
\r
48703 * The order is always [low, ..., high].
\r
48705 * Mapping from location to low-high:
\r
48706 * If !option.inverse
\r
48707 * When vertical, top is high.
\r
48708 * When horizontal, right is high.
\r
48709 * If option.inverse, reverse.
\r
48716 selected: null, // Object. If not specified, means selected.
\r
48717 // When pieces and splitNumber: {'0': true, '5': true}
\r
48718 // When categories: {'cate1': false, 'cate3': true}
\r
48719 // When selected === false, means all unselected.
\r
48720 align: 'auto', // 'auto', 'left', 'right'
\r
48721 itemWidth: 20, // 值域图形宽度
\r
48722 itemHeight: 14, // 值域图形高度
\r
48723 itemSymbol: 'roundRect',
\r
48724 pieceList: null, // 值顺序:由高到低, item can be:
\r
48725 // {min, max, value, color, colorSaturation, colorAlpha, symbol, symbolSize}
\r
48726 categories: null, // 描述 category 数据。如:['some1', 'some2', 'some3'],设置后,min max失效。
\r
48727 splitNumber: 5, // 分割段数,默认为5,为0时为线性渐变 (continous)
\r
48728 selectedMode: 'multiple',
\r
48729 itemGap: 10 // 各个item之间的间隔,单位px,默认为10,
\r
48730 // 横向布局时为水平间隔,纵向布局时为纵向间隔
\r
48736 doMergeOption: function (newOption, isInit) {
\r
48737 PiecewiseModel.superApply(this, 'doMergeOption', arguments);
\r
48740 * The order is always [low, ..., high].
\r
48741 * [{text: string, interval: Array.<number>}, ...]
\r
48743 * @type {Array.<Object>}
\r
48745 this._pieceList = [];
\r
48747 this.resetTargetSeries(newOption, isInit);
\r
48748 this.resetExtent();
\r
48751 * 'pieces', 'categories', 'splitNumber'
\r
48754 var mode = this._mode = this._decideMode();
\r
48756 resetMethods[this._mode].call(this);
\r
48758 this._resetSelected(newOption, isInit);
\r
48760 var categories = this.option.categories;
\r
48761 this.resetVisual(function (mappingOption, state) {
\r
48762 if (mode === 'categories') {
\r
48763 mappingOption.mappingMethod = 'category';
\r
48764 mappingOption.categories = zrUtil.clone(categories);
\r
48767 mappingOption.mappingMethod = 'piecewise';
\r
48768 mappingOption.pieceList = zrUtil.map(this._pieceList, function (piece) {
\r
48769 var piece = zrUtil.clone(piece);
\r
48770 if (state !== 'inRange') {
\r
48771 piece.visual = null;
\r
48779 _resetSelected: function (newOption, isInit) {
\r
48780 var thisOption = this.option;
\r
48781 var pieceList = this._pieceList;
\r
48783 // Selected do not merge but all override.
\r
48784 var selected = (isInit ? thisOption : newOption).selected || {};
\r
48785 thisOption.selected = selected;
\r
48787 // Consider 'not specified' means true.
\r
48788 zrUtil.each(pieceList, function (piece, index) {
\r
48789 var key = this.getSelectedMapKey(piece);
\r
48790 if (!(key in selected)) {
\r
48791 selected[key] = true;
\r
48795 if (thisOption.selectedMode === 'single') {
\r
48796 // Ensure there is only one selected.
\r
48797 var hasSel = false;
\r
48799 zrUtil.each(pieceList, function (piece, index) {
\r
48800 var key = this.getSelectedMapKey(piece);
\r
48801 if (selected[key]) {
\r
48803 ? (selected[key] = false)
\r
48804 : (hasSel = true);
\r
48808 // thisOption.selectedMode === 'multiple', default: all selected.
\r
48814 getSelectedMapKey: function (piece) {
\r
48815 return this._mode === 'categories'
\r
48816 ? piece.value + '' : piece.index + '';
\r
48822 getPieceList: function () {
\r
48823 return this._pieceList;
\r
48828 * @return {string}
\r
48830 _decideMode: function () {
\r
48831 var option = this.option;
\r
48833 return option.pieces && option.pieces.length > 0
\r
48835 : this.option.categories
\r
48844 setSelected: function (selected) {
\r
48845 this.option.selected = zrUtil.clone(selected);
\r
48852 getValueState: function (value) {
\r
48853 var pieceList = this._pieceList;
\r
48854 var index = VisualMapping.findPieceIndex(value, pieceList);
\r
48856 return index != null
\r
48857 ? (this.option.selected[this.getSelectedMapKey(pieceList[index])]
\r
48858 ? 'inRange' : 'outOfRange'
\r
48866 * Key is this._mode
\r
48868 * @this {module:echarts/component/viusalMap/PiecewiseMode}
\r
48870 var resetMethods = {
\r
48872 splitNumber: function () {
\r
48873 var thisOption = this.option;
\r
48874 var precision = thisOption.precision;
\r
48875 var dataExtent = this.getExtent();
\r
48876 var splitNumber = thisOption.splitNumber;
\r
48877 splitNumber = Math.max(parseInt(splitNumber, 10), 1);
\r
48878 thisOption.splitNumber = splitNumber;
\r
48880 var splitStep = (dataExtent[1] - dataExtent[0]) / splitNumber;
\r
48881 // Precision auto-adaption
\r
48882 while (+splitStep.toFixed(precision) !== splitStep && precision < 5) {
\r
48885 thisOption.precision = precision;
\r
48886 splitStep = +splitStep.toFixed(precision);
\r
48888 for (var i = 0, curr = dataExtent[0]; i < splitNumber; i++, curr += splitStep) {
\r
48889 var max = i === splitNumber - 1 ? dataExtent[1] : (curr + splitStep);
\r
48891 this._pieceList.push({
\r
48892 text: this.formatValueText([curr, max]),
\r
48894 interval: [curr, max]
\r
48899 categories: function () {
\r
48900 var thisOption = this.option;
\r
48901 zrUtil.each(thisOption.categories, function (cate) {
\r
48902 // FIXME category模式也使用pieceList,但在visualMapping中不是使用pieceList。
\r
48904 this._pieceList.push({
\r
48905 text: this.formatValueText(cate, true),
\r
48910 // See "Order Rule".
\r
48911 normalizeReverse(thisOption, this._pieceList);
\r
48914 pieces: function () {
\r
48915 var thisOption = this.option;
\r
48916 zrUtil.each(thisOption.pieces, function (pieceListItem, index) {
\r
48918 if (!zrUtil.isObject(pieceListItem)) {
\r
48919 pieceListItem = {value: pieceListItem};
\r
48922 var item = {text: '', index: index};
\r
48925 if (pieceListItem.label != null) {
\r
48926 item.text = pieceListItem.label;
\r
48930 if (pieceListItem.hasOwnProperty('value')) {
\r
48931 item.value = pieceListItem.value;
\r
48934 item.text = this.formatValueText(item.value);
\r
48938 var min = pieceListItem.min;
\r
48939 var max = pieceListItem.max;
\r
48940 min == null && (min = -Infinity);
\r
48941 max == null && (max = Infinity);
\r
48942 if (min === max) {
\r
48943 // Consider: [{min: 5, max: 5, visual: {...}}, {min: 0, max: 5}],
\r
48944 // we use value to lift the priority when min === max
\r
48945 item.value = min;
\r
48947 item.interval = [min, max];
\r
48950 item.text = this.formatValueText([min, max]);
\r
48954 item.visual = VisualMapping.retrieveVisuals(pieceListItem);
\r
48956 this._pieceList.push(item);
\r
48960 // See "Order Rule".
\r
48961 normalizeReverse(thisOption, this._pieceList);
\r
48965 function normalizeReverse(thisOption, arr) {
\r
48966 var inverse = thisOption.inverse;
\r
48967 if (thisOption.orient === 'vertical' ? !inverse : inverse) {
\r
48972 module.exports = PiecewiseModel;
\r
48978 /***/ function(module, exports, __webpack_require__) {
\r
48982 var VisualMapView = __webpack_require__(309);
\r
48983 var zrUtil = __webpack_require__(3);
\r
48984 var graphic = __webpack_require__(42);
\r
48985 var symbolCreators = __webpack_require__(100);
\r
48986 var layout = __webpack_require__(21);
\r
48987 var helper = __webpack_require__(310);
\r
48989 var PiecewiseVisualMapView = VisualMapView.extend({
\r
48991 type: 'visualMap.piecewise',
\r
48997 doRender: function () {
\r
48998 var thisGroup = this.group;
\r
49000 thisGroup.removeAll();
\r
49002 var visualMapModel = this.visualMapModel;
\r
49003 var textGap = visualMapModel.get('textGap');
\r
49004 var textStyleModel = visualMapModel.textStyleModel;
\r
49005 var textFont = textStyleModel.getFont();
\r
49006 var textFill = textStyleModel.getTextColor();
\r
49007 var itemAlign = this._getItemAlign();
\r
49008 var itemSize = visualMapModel.itemSize;
\r
49010 var viewData = this._getViewData();
\r
49011 var showLabel = !viewData.endsText;
\r
49012 var showEndsText = !showLabel;
\r
49014 showEndsText && this._renderEndsText(thisGroup, viewData.endsText[0], itemSize);
\r
49016 zrUtil.each(viewData.pieceList, renderItem, this);
\r
49018 showEndsText && this._renderEndsText(thisGroup, viewData.endsText[1], itemSize);
\r
49021 visualMapModel.get('orient'), thisGroup, visualMapModel.get('itemGap')
\r
49024 this.renderBackground(thisGroup);
\r
49026 this.positionGroup(thisGroup);
\r
49028 function renderItem(item) {
\r
49029 var itemGroup = new graphic.Group();
\r
49030 itemGroup.onclick = zrUtil.bind(this._onItemClick, this, item.piece);
\r
49032 this._createItemSymbol(itemGroup, item.piece, [0, 0, itemSize[0], itemSize[1]]);
\r
49035 itemGroup.add(new graphic.Text({
\r
49037 x: itemAlign === 'right' ? -textGap : itemSize[0] + textGap,
\r
49038 y: itemSize[1] / 2,
\r
49039 text: item.piece.text,
\r
49040 textVerticalAlign: 'middle',
\r
49041 textAlign: itemAlign,
\r
49042 textFont: textFont,
\r
49048 thisGroup.add(itemGroup);
\r
49055 _getItemAlign: function () {
\r
49056 var visualMapModel = this.visualMapModel;
\r
49057 var modelOption = visualMapModel.option;
\r
49058 if (modelOption.orient === 'vertical') {
\r
49059 return helper.getItemAlign(
\r
49060 visualMapModel, this.api, visualMapModel.itemSize
\r
49063 else { // horizontal, most case left unless specifying right.
\r
49064 var align = modelOption.align;
\r
49065 if (!align || align === 'auto') {
\r
49075 _renderEndsText: function (group, text, itemSize) {
\r
49079 var itemGroup = new graphic.Group();
\r
49080 var textStyleModel = this.visualMapModel.textStyleModel;
\r
49081 itemGroup.add(new graphic.Text({
\r
49083 x: itemSize[0] / 2,
\r
49084 y: itemSize[1] / 2,
\r
49085 textVerticalAlign: 'middle',
\r
49086 textAlign: 'center',
\r
49088 textFont: textStyleModel.getFont(),
\r
49089 fill: textStyleModel.getTextColor()
\r
49093 group.add(itemGroup);
\r
49098 * @return {Object} {peiceList, endsText} The order is the same as screen pixel order.
\r
49100 _getViewData: function () {
\r
49101 var visualMapModel = this.visualMapModel;
\r
49103 var pieceList = zrUtil.map(visualMapModel.getPieceList(), function (piece, index) {
\r
49104 return {piece: piece, index: index};
\r
49106 var endsText = visualMapModel.get('text');
\r
49108 // Consider orient and inverse.
\r
49109 var orient = visualMapModel.get('orient');
\r
49110 var inverse = visualMapModel.get('inverse');
\r
49112 // Order of pieceList is always [low, ..., high]
\r
49113 if (orient === 'horizontal' ? inverse : !inverse) {
\r
49114 pieceList.reverse();
\r
49116 // Origin order of endsText is [high, low]
\r
49117 else if (endsText) {
\r
49118 endsText = endsText.slice().reverse();
\r
49121 return {pieceList: pieceList, endsText: endsText};
\r
49127 _createItemSymbol: function (group, piece, shapeParam) {
\r
49128 var representValue;
\r
49129 if (this.visualMapModel.isCategory()) {
\r
49130 representValue = piece.value;
\r
49133 if (piece.value != null) {
\r
49134 representValue = piece.value;
\r
49137 var pieceInterval = piece.interval || [];
\r
49138 representValue = (pieceInterval[0] + pieceInterval[1]) / 2;
\r
49142 var visualObj = this.getControllerVisual(representValue);
\r
49144 group.add(symbolCreators.createSymbol(
\r
49145 visualObj.symbol,
\r
49146 shapeParam[0], shapeParam[1], shapeParam[2], shapeParam[3],
\r
49154 _onItemClick: function (piece) {
\r
49155 var visualMapModel = this.visualMapModel;
\r
49156 var option = visualMapModel.option;
\r
49157 var selected = zrUtil.clone(option.selected);
\r
49158 var newKey = visualMapModel.getSelectedMapKey(piece);
\r
49160 if (option.selectedMode === 'single') {
\r
49161 selected[newKey] = true;
\r
49162 zrUtil.each(selected, function (o, key) {
\r
49163 selected[key] = key === newKey;
\r
49167 selected[newKey] = !selected[newKey];
\r
49170 this.api.dispatchAction({
\r
49171 type: 'selectDataRange',
\r
49173 visualMapId: this.visualMapModel.id,
\r
49174 selected: selected
\r
49179 module.exports = PiecewiseVisualMapView;
\r
49185 /***/ function(module, exports, __webpack_require__) {
\r
49187 // HINT Markpoint can't be used too much
\r
49190 __webpack_require__(316);
\r
49191 __webpack_require__(317);
\r
49193 __webpack_require__(1).registerPreprocessor(function (opt) {
\r
49194 // Make sure markPoint component is enabled
\r
49195 opt.markPoint = opt.markPoint || {};
\r
49201 /***/ function(module, exports, __webpack_require__) {
\r
49204 // Default enable markPoint
\r
49205 // var globalDefault = require('../../model/globalDefault');
\r
49206 var modelUtil = __webpack_require__(5);
\r
49207 // // Force to load markPoint component
\r
49208 // globalDefault.markPoint = {};
\r
49210 var MarkPointModel = __webpack_require__(1).extendComponentModel({
\r
49212 type: 'markPoint',
\r
49214 dependencies: ['series', 'grid', 'polar'],
\r
49218 init: function (option, parentModel, ecModel, extraOpt) {
\r
49219 this.mergeDefaultAndTheme(option, ecModel);
\r
49220 this.mergeOption(option, ecModel, extraOpt.createdBySelf, true);
\r
49223 mergeOption: function (newOpt, ecModel, createdBySelf, isInit) {
\r
49224 if (!createdBySelf) {
\r
49225 ecModel.eachSeries(function (seriesModel) {
\r
49226 var markPointOpt = seriesModel.get('markPoint');
\r
49227 var mpModel = seriesModel.markPointModel;
\r
49228 if (!markPointOpt || !markPointOpt.data) {
\r
49229 seriesModel.markPointModel = null;
\r
49234 // Default label emphasis `position` and `show`
\r
49235 modelUtil.defaultEmphasis(
\r
49236 markPointOpt.label,
\r
49237 ['position', 'show', 'textStyle', 'distance', 'formatter']
\r
49241 // Use the same series index and name
\r
49242 seriesIndex: seriesModel.seriesIndex,
\r
49243 name: seriesModel.name,
\r
49244 createdBySelf: true
\r
49246 mpModel = new MarkPointModel(
\r
49247 markPointOpt, this, ecModel, opt
\r
49251 mpModel.mergeOption(markPointOpt, ecModel, true);
\r
49253 seriesModel.markPointModel = mpModel;
\r
49261 symbol: 'pin', // 标注类型
\r
49262 symbolSize: 50, // 标注大小
\r
49263 // symbolRotate: null, // 标注旋转控制
\r
49270 // 标签文本格式器,同Tooltip.formatter,不支持回调
\r
49271 // formatter: null,
\r
49272 // 可选为'left'|'right'|'top'|'bottom'
\r
49273 position: 'inside'
\r
49274 // 默认使用全局文本样式,详见TEXTSTYLE
\r
49275 // textStyle: null
\r
49279 // 标签文本格式器,同Tooltip.formatter,不支持回调
\r
49280 // formatter: null,
\r
49281 // position: 'inside' // 'left'|'right'|'top'|'bottom'
\r
49282 // textStyle: null // 默认使用全局文本样式,详见TEXTSTYLE
\r
49288 // 标注边线颜色,优先于color
\r
49289 // borderColor: 各异,
\r
49290 // 标注边线线宽,单位px,默认为1
\r
49300 module.exports = MarkPointModel;
\r
49305 /***/ function(module, exports, __webpack_require__) {
\r
49309 var SymbolDraw = __webpack_require__(98);
\r
49310 var zrUtil = __webpack_require__(3);
\r
49311 var formatUtil = __webpack_require__(6);
\r
49312 var modelUtil = __webpack_require__(5);
\r
49313 var numberUtil = __webpack_require__(7);
\r
49315 var addCommas = formatUtil.addCommas;
\r
49316 var encodeHTML = formatUtil.encodeHTML;
\r
49318 var List = __webpack_require__(94);
\r
49320 var markerHelper = __webpack_require__(318);
\r
49322 function updateMarkerLayout(mpData, seriesModel, api) {
\r
49323 var coordSys = seriesModel.coordinateSystem;
\r
49324 mpData.each(function (idx) {
\r
49325 var itemModel = mpData.getItemModel(idx);
\r
49327 var xPx = itemModel.getShallow('x');
\r
49328 var yPx = itemModel.getShallow('y');
\r
49329 if (xPx != null && yPx != null) {
\r
49331 numberUtil.parsePercent(xPx, api.getWidth()),
\r
49332 numberUtil.parsePercent(yPx, api.getHeight())
\r
49335 // Chart like bar may have there own marker positioning logic
\r
49336 else if (seriesModel.getMarkerPosition) {
\r
49337 // Use the getMarkerPoisition
\r
49338 point = seriesModel.getMarkerPosition(
\r
49339 mpData.getValues(mpData.dimensions, idx)
\r
49342 else if (coordSys) {
\r
49343 var x = mpData.get(coordSys.dimensions[0], idx);
\r
49344 var y = mpData.get(coordSys.dimensions[1], idx);
\r
49345 point = coordSys.dataToPoint([x, y]);
\r
49348 mpData.setItemLayout(idx, point);
\r
49353 var markPointFormatMixin = {
\r
49354 getRawDataArray: function () {
\r
49355 return this.option.data;
\r
49358 formatTooltip: function (dataIndex) {
\r
49359 var data = this.getData();
\r
49360 var value = this.getRawValue(dataIndex);
\r
49361 var formattedValue = zrUtil.isArray(value)
\r
49362 ? zrUtil.map(value, addCommas).join(', ') : addCommas(value);
\r
49363 var name = data.getName(dataIndex);
\r
49364 return this.name + '<br />'
\r
49365 + ((name ? encodeHTML(name) + ' : ' : '') + formattedValue);
\r
49368 getData: function () {
\r
49369 return this._data;
\r
49372 setData: function (data) {
\r
49373 this._data = data;
\r
49377 zrUtil.defaults(markPointFormatMixin, modelUtil.dataFormatMixin);
\r
49379 __webpack_require__(1).extendComponentView({
\r
49381 type: 'markPoint',
\r
49383 init: function () {
\r
49384 this._symbolDrawMap = {};
\r
49387 render: function (markPointModel, ecModel, api) {
\r
49388 var symbolDrawMap = this._symbolDrawMap;
\r
49389 for (var name in symbolDrawMap) {
\r
49390 symbolDrawMap[name].__keep = false;
\r
49393 ecModel.eachSeries(function (seriesModel) {
\r
49394 var mpModel = seriesModel.markPointModel;
\r
49395 mpModel && this._renderSeriesMP(seriesModel, mpModel, api);
\r
49398 for (var name in symbolDrawMap) {
\r
49399 if (!symbolDrawMap[name].__keep) {
\r
49400 symbolDrawMap[name].remove();
\r
49401 this.group.remove(symbolDrawMap[name].group);
\r
49406 updateLayout: function (markPointModel, ecModel, api) {
\r
49407 ecModel.eachSeries(function (seriesModel) {
\r
49408 var mpModel = seriesModel.markPointModel;
\r
49410 updateMarkerLayout(mpModel.getData(), seriesModel, api);
\r
49411 this._symbolDrawMap[seriesModel.name].updateLayout(mpModel);
\r
49416 _renderSeriesMP: function (seriesModel, mpModel, api) {
\r
49417 var coordSys = seriesModel.coordinateSystem;
\r
49418 var seriesName = seriesModel.name;
\r
49419 var seriesData = seriesModel.getData();
\r
49421 var symbolDrawMap = this._symbolDrawMap;
\r
49422 var symbolDraw = symbolDrawMap[seriesName];
\r
49423 if (!symbolDraw) {
\r
49424 symbolDraw = symbolDrawMap[seriesName] = new SymbolDraw();
\r
49427 var mpData = createList(coordSys, seriesModel, mpModel);
\r
49430 zrUtil.mixin(mpModel, markPointFormatMixin);
\r
49431 mpModel.setData(mpData);
\r
49433 updateMarkerLayout(mpModel.getData(), seriesModel, api);
\r
49435 mpData.each(function (idx) {
\r
49436 var itemModel = mpData.getItemModel(idx);
\r
49437 var symbolSize = itemModel.getShallow('symbolSize');
\r
49438 if (typeof symbolSize === 'function') {
\r
49439 // FIXME 这里不兼容 ECharts 2.x,2.x 貌似参数是整个数据?
\r
49440 symbolSize = symbolSize(
\r
49441 mpModel.getRawValue(idx), mpModel.getDataParams(idx)
\r
49444 mpData.setItemVisual(idx, {
\r
49445 symbolSize: symbolSize,
\r
49446 color: itemModel.get('itemStyle.normal.color')
\r
49447 || seriesData.getVisual('color'),
\r
49448 symbol: itemModel.getShallow('symbol')
\r
49452 // TODO Text are wrong
\r
49453 symbolDraw.updateData(mpData);
\r
49454 this.group.add(symbolDraw.group);
\r
49456 // Set host model for tooltip
\r
49458 mpData.eachItemGraphicEl(function (el) {
\r
49459 el.traverse(function (child) {
\r
49460 child.dataModel = mpModel;
\r
49464 symbolDraw.__keep = true;
\r
49470 * @param {module:echarts/coord/*} [coordSys]
\r
49471 * @param {module:echarts/model/Series} seriesModel
\r
49472 * @param {module:echarts/model/Model} mpModel
\r
49474 function createList(coordSys, seriesModel, mpModel) {
\r
49475 var coordDimsInfos;
\r
49477 coordDimsInfos = zrUtil.map(coordSys && coordSys.dimensions, function (coordDim) {
\r
49478 var info = seriesModel.getData().getDimensionInfo(
\r
49479 seriesModel.coordDimToDataDim(coordDim)[0]
\r
49480 ) || {}; // In map series data don't have lng and lat dimension. Fallback to same with coordSys
\r
49481 info.name = coordDim;
\r
49486 coordDimsInfos =[{
\r
49492 var mpData = new List(coordDimsInfos, mpModel);
\r
49493 var dataOpt = zrUtil.map(mpModel.get('data'), zrUtil.curry(
\r
49494 markerHelper.dataTransform, seriesModel
\r
49497 dataOpt = zrUtil.filter(
\r
49498 dataOpt, zrUtil.curry(markerHelper.dataFilter, coordSys)
\r
49502 mpData.initData(dataOpt, null,
\r
49503 coordSys ? markerHelper.dimValueGetter : function (item) {
\r
49504 return item.value;
\r
49514 /***/ function(module, exports, __webpack_require__) {
\r
49518 var zrUtil = __webpack_require__(3);
\r
49519 var numberUtil = __webpack_require__(7);
\r
49520 var indexOf = zrUtil.indexOf;
\r
49522 function getPrecision(data, valueAxisDim, dataIndex) {
\r
49523 var precision = -1;
\r
49525 precision = Math.max(
\r
49526 numberUtil.getPrecision(data.get(
\r
49527 valueAxisDim, dataIndex
\r
49531 data = data.stackedOn;
\r
49534 return precision;
\r
49537 function markerTypeCalculatorWithExtent(
\r
49538 mlType, data, baseDataDim, valueDataDim, baseCoordIndex, valueCoordIndex
\r
49540 var coordArr = [];
\r
49541 var value = numCalculate(data, valueDataDim, mlType);
\r
49543 var dataIndex = data.indexOfNearest(valueDataDim, value, true);
\r
49544 coordArr[baseCoordIndex] = data.get(baseDataDim, dataIndex, true);
\r
49545 coordArr[valueCoordIndex] = data.get(valueDataDim, dataIndex, true);
\r
49547 var precision = getPrecision(data, valueDataDim, dataIndex);
\r
49548 if (precision >= 0) {
\r
49549 coordArr[valueCoordIndex] = +coordArr[valueCoordIndex].toFixed(precision);
\r
49555 var curry = zrUtil.curry;
\r
49556 // TODO Specified percent
\r
49557 var markerTypeCalculator = {
\r
49560 * @param {module:echarts/data/List} data
\r
49561 * @param {string} baseAxisDim
\r
49562 * @param {string} valueAxisDim
\r
49564 min: curry(markerTypeCalculatorWithExtent, 'min'),
\r
49567 * @param {module:echarts/data/List} data
\r
49568 * @param {string} baseAxisDim
\r
49569 * @param {string} valueAxisDim
\r
49571 max: curry(markerTypeCalculatorWithExtent, 'max'),
\r
49574 * @param {module:echarts/data/List} data
\r
49575 * @param {string} baseAxisDim
\r
49576 * @param {string} valueAxisDim
\r
49578 average: curry(markerTypeCalculatorWithExtent, 'average')
\r
49582 * Transform markPoint data item to format used in List by do the following
\r
49583 * 1. Calculate statistic like `max`, `min`, `average`
\r
49584 * 2. Convert `item.xAxis`, `item.yAxis` to `item.coord` array
\r
49585 * @param {module:echarts/model/Series} seriesModel
\r
49586 * @param {module:echarts/coord/*} [coordSys]
\r
49587 * @param {Object} item
\r
49588 * @return {Object}
\r
49590 var dataTransform = function (seriesModel, item) {
\r
49591 var data = seriesModel.getData();
\r
49592 var coordSys = seriesModel.coordinateSystem;
\r
49594 // 1. If not specify the position with pixel directly
\r
49595 // 2. If `coord` is not a data array. Which uses `xAxis`,
\r
49596 // `yAxis` to specify the coord on each dimension
\r
49597 if ((isNaN(item.x) || isNaN(item.y))
\r
49598 && !zrUtil.isArray(item.coord)
\r
49601 var axisInfo = getAxisInfo(item, data, coordSys, seriesModel);
\r
49603 // Clone the option
\r
49604 // Transform the properties xAxis, yAxis, radiusAxis, angleAxis, geoCoord to value
\r
49605 item = zrUtil.clone(item);
\r
49608 && markerTypeCalculator[item.type]
\r
49609 && axisInfo.baseAxis && axisInfo.valueAxis
\r
49611 var dims = coordSys.dimensions;
\r
49612 var baseCoordIndex = indexOf(dims, axisInfo.baseAxis.dim);
\r
49613 var valueCoordIndex = indexOf(dims, axisInfo.valueAxis.dim);
\r
49615 item.coord = markerTypeCalculator[item.type](
\r
49616 data, axisInfo.baseDataDim, axisInfo.valueDataDim,
\r
49617 baseCoordIndex, valueCoordIndex
\r
49619 // Force to use the value of calculated value.
\r
49620 item.value = item.coord[valueCoordIndex];
\r
49623 // FIXME Only has one of xAxis and yAxis.
\r
49625 item.xAxis != null ? item.xAxis : item.radiusAxis,
\r
49626 item.yAxis != null ? item.yAxis : item.angleAxis
\r
49633 var getAxisInfo = function (item, data, coordSys, seriesModel) {
\r
49636 if (item.valueIndex != null || item.valueDim != null) {
\r
49637 ret.valueDataDim = item.valueIndex != null
\r
49638 ? data.getDimension(item.valueIndex) : item.valueDim;
\r
49639 ret.valueAxis = coordSys.getAxis(seriesModel.dataDimToCoordDim(ret.valueDataDim));
\r
49640 ret.baseAxis = coordSys.getOtherAxis(ret.valueAxis);
\r
49641 ret.baseDataDim = seriesModel.coordDimToDataDim(ret.baseAxis.dim)[0];
\r
49644 ret.baseAxis = seriesModel.getBaseAxis();
\r
49645 ret.valueAxis = coordSys.getOtherAxis(ret.baseAxis);
\r
49646 ret.baseDataDim = seriesModel.coordDimToDataDim(ret.baseAxis.dim)[0];
\r
49647 ret.valueDataDim = seriesModel.coordDimToDataDim(ret.valueAxis.dim)[0];
\r
49654 * Filter data which is out of coordinateSystem range
\r
49655 * [dataFilter description]
\r
49656 * @param {module:echarts/coord/*} [coordSys]
\r
49657 * @param {Object} item
\r
49658 * @return {boolean}
\r
49660 var dataFilter = function (coordSys, item) {
\r
49661 // Alwalys return true if there is no coordSys
\r
49662 return (coordSys && coordSys.containData && item.coord && (item.x == null || item.y == null))
\r
49663 ? coordSys.containData(item.coord) : true;
\r
49666 var dimValueGetter = function (item, dimName, dataIndex, dimIndex) {
\r
49667 // x, y, radius, angle
\r
49668 if (dimIndex < 2) {
\r
49669 return item.coord && item.coord[dimIndex];
\r
49672 return item.value;
\r
49676 var numCalculate = function (data, valueDataDim, mlType) {
\r
49677 return mlType === 'average'
\r
49678 ? data.getSum(valueDataDim, true) / data.count()
\r
49679 : data.getDataExtent(valueDataDim, true)[mlType === 'max' ? 1 : 0];
\r
49682 module.exports = {
\r
49683 dataTransform: dataTransform,
\r
49684 dataFilter: dataFilter,
\r
49685 dimValueGetter: dimValueGetter,
\r
49686 getAxisInfo: getAxisInfo,
\r
49687 numCalculate: numCalculate
\r
49693 /***/ function(module, exports, __webpack_require__) {
\r
49697 __webpack_require__(320);
\r
49698 __webpack_require__(321);
\r
49700 __webpack_require__(1).registerPreprocessor(function (opt) {
\r
49701 // Make sure markLine component is enabled
\r
49702 opt.markLine = opt.markLine || {};
\r
49708 /***/ function(module, exports, __webpack_require__) {
\r
49712 // Default enable markLine
\r
49713 // var globalDefault = require('../../model/globalDefault');
\r
49714 var modelUtil = __webpack_require__(5);
\r
49716 // // Force to load markLine component
\r
49717 // globalDefault.markLine = {};
\r
49719 var MarkLineModel = __webpack_require__(1).extendComponentModel({
\r
49721 type: 'markLine',
\r
49723 dependencies: ['series', 'grid', 'polar'],
\r
49727 init: function (option, parentModel, ecModel, extraOpt) {
\r
49728 this.mergeDefaultAndTheme(option, ecModel);
\r
49729 this.mergeOption(option, ecModel, extraOpt.createdBySelf, true);
\r
49732 mergeOption: function (newOpt, ecModel, createdBySelf, isInit) {
\r
49733 if (!createdBySelf) {
\r
49734 ecModel.eachSeries(function (seriesModel) {
\r
49735 var markLineOpt = seriesModel.get('markLine');
\r
49736 var mlModel = seriesModel.markLineModel;
\r
49737 if (!markLineOpt || !markLineOpt.data) {
\r
49738 seriesModel.markLineModel = null;
\r
49743 // Default label emphasis `position` and `show`
\r
49744 modelUtil.defaultEmphasis(
\r
49745 markLineOpt.label,
\r
49746 ['position', 'show', 'textStyle', 'distance', 'formatter']
\r
49750 // Use the same series index and name
\r
49751 seriesIndex: seriesModel.seriesIndex,
\r
49752 name: seriesModel.name,
\r
49753 createdBySelf: true
\r
49755 mlModel = new MarkLineModel(
\r
49756 markLineOpt, this, ecModel, opt
\r
49760 mlModel.mergeOption(markLineOpt, ecModel, true);
\r
49762 seriesModel.markLineModel = mlModel;
\r
49770 // 标线起始和结束的symbol介绍类型,如果都一样,可以直接传string
\r
49771 symbol: ['circle', 'arrow'],
\r
49772 // 标线起始和结束的symbol大小,半宽(半径)参数,当图形为方向或菱形则总宽度为symbolSize * 2
\r
49773 symbolSize: [8, 16],
\r
49774 // 标线起始和结束的symbol旋转控制
\r
49775 //symbolRotate: null,
\r
49784 // 标签文本格式器,同Tooltip.formatter,不支持回调
\r
49785 // formatter: null,
\r
49786 // 可选为 'start'|'end'|'left'|'right'|'top'|'bottom'
\r
49788 // 默认使用全局文本样式,详见TEXTSTYLE
\r
49789 // textStyle: null
\r
49800 // shadowColor: 'rgba(0,0,0,0)',
\r
49801 // shadowBlur: 0,
\r
49802 // shadowOffsetX: 0,
\r
49803 // shadowOffsetY: 0
\r
49809 animationEasing: 'linear'
\r
49813 module.exports = MarkLineModel;
\r
49818 /***/ function(module, exports, __webpack_require__) {
\r
49822 var zrUtil = __webpack_require__(3);
\r
49823 var List = __webpack_require__(94);
\r
49824 var formatUtil = __webpack_require__(6);
\r
49825 var modelUtil = __webpack_require__(5);
\r
49826 var numberUtil = __webpack_require__(7);
\r
49828 var addCommas = formatUtil.addCommas;
\r
49829 var encodeHTML = formatUtil.encodeHTML;
\r
49831 var markerHelper = __webpack_require__(318);
\r
49833 var LineDraw = __webpack_require__(194);
\r
49835 var markLineTransform = function (seriesModel, coordSys, mlModel, item) {
\r
49836 var data = seriesModel.getData();
\r
49837 // Special type markLine like 'min', 'max', 'average'
\r
49838 var mlType = item.type;
\r
49840 if (!zrUtil.isArray(item)
\r
49841 && (mlType === 'min' || mlType === 'max' || mlType === 'average')
\r
49843 var axisInfo = markerHelper.getAxisInfo(item, data, coordSys, seriesModel);
\r
49845 var baseAxisKey = axisInfo.baseAxis.dim + 'Axis';
\r
49846 var valueAxisKey = axisInfo.valueAxis.dim + 'Axis';
\r
49847 var baseScaleExtent = axisInfo.baseAxis.scale.getExtent();
\r
49849 var mlFrom = zrUtil.clone(item);
\r
49852 mlFrom.type = null;
\r
49854 // FIXME Polar should use circle
\r
49855 mlFrom[baseAxisKey] = baseScaleExtent[0];
\r
49856 mlTo[baseAxisKey] = baseScaleExtent[1];
\r
49858 var value = markerHelper.numCalculate(data, axisInfo.valueDataDim, mlType);
\r
49860 // Round if axis is cateogry
\r
49861 value = axisInfo.valueAxis.coordToData(axisInfo.valueAxis.dataToCoord(value));
\r
49863 var precision = mlModel.get('precision');
\r
49864 if (precision >= 0) {
\r
49865 value = +value.toFixed(precision);
\r
49868 mlFrom[valueAxisKey] = mlTo[valueAxisKey] = value;
\r
49870 item = [mlFrom, mlTo, { // Extra option for tooltip and label
\r
49872 valueIndex: item.valueIndex,
\r
49873 // Force to use the value of calculated value.
\r
49879 markerHelper.dataTransform(seriesModel, item[0]),
\r
49880 markerHelper.dataTransform(seriesModel, item[1]),
\r
49881 zrUtil.extend({}, item[2])
\r
49884 // Avoid line data type is extended by from(to) data type
\r
49885 item[2].type = item[2].type || '';
\r
49887 // Merge from option and to option into line option
\r
49888 zrUtil.merge(item[2], item[0]);
\r
49889 zrUtil.merge(item[2], item[1]);
\r
49894 function markLineFilter(coordSys, item) {
\r
49895 return markerHelper.dataFilter(coordSys, item[0])
\r
49896 && markerHelper.dataFilter(coordSys, item[1]);
\r
49899 function updateSingleMarkerEndLayout(
\r
49900 data, idx, isFrom, mlType, valueIndex, seriesModel, api
\r
49902 var coordSys = seriesModel.coordinateSystem;
\r
49903 var itemModel = data.getItemModel(idx);
\r
49906 var xPx = itemModel.get('x');
\r
49907 var yPx = itemModel.get('y');
\r
49908 if (xPx != null && yPx != null) {
\r
49910 numberUtil.parsePercent(xPx, api.getWidth()),
\r
49911 numberUtil.parsePercent(yPx, api.getHeight())
\r
49915 // Chart like bar may have there own marker positioning logic
\r
49916 if (seriesModel.getMarkerPosition) {
\r
49917 // Use the getMarkerPoisition
\r
49918 point = seriesModel.getMarkerPosition(
\r
49919 data.getValues(data.dimensions, idx)
\r
49923 var dims = coordSys.dimensions;
\r
49924 var x = data.get(dims[0], idx);
\r
49925 var y = data.get(dims[1], idx);
\r
49926 point = coordSys.dataToPoint([x, y]);
\r
49928 // Expand min, max, average line to the edge of grid
\r
49929 // FIXME Glue code
\r
49930 if (mlType && coordSys.type === 'cartesian2d') {
\r
49931 var mlOnAxis = valueIndex != null
\r
49932 ? coordSys.getAxis(valueIndex === 1 ? 'x' : 'y')
\r
49933 : coordSys.getAxesByScale('ordinal')[0];
\r
49934 if (mlOnAxis && mlOnAxis.onBand) {
\r
49935 point[mlOnAxis.dim === 'x' ? 0 : 1] =
\r
49936 mlOnAxis.toGlobalCoord(mlOnAxis.getExtent()[isFrom ? 0 : 1]);
\r
49941 data.setItemLayout(idx, point);
\r
49944 var markLineFormatMixin = {
\r
49945 formatTooltip: function (dataIndex) {
\r
49946 var data = this._data;
\r
49947 var value = this.getRawValue(dataIndex);
\r
49948 var formattedValue = zrUtil.isArray(value)
\r
49949 ? zrUtil.map(value, addCommas).join(', ') : addCommas(value);
\r
49950 var name = data.getName(dataIndex);
\r
49951 return this.name + '<br />'
\r
49952 + ((name ? encodeHTML(name) + ' : ' : '') + formattedValue);
\r
49955 getRawDataArray: function () {
\r
49956 return this.option.data;
\r
49959 getData: function () {
\r
49960 return this._data;
\r
49963 setData: function (data) {
\r
49964 this._data = data;
\r
49968 zrUtil.defaults(markLineFormatMixin, modelUtil.dataFormatMixin);
\r
49970 __webpack_require__(1).extendComponentView({
\r
49972 type: 'markLine',
\r
49974 init: function () {
\r
49976 * Markline grouped by series
\r
49980 this._markLineMap = {};
\r
49983 render: function (markLineModel, ecModel, api) {
\r
49984 var lineDrawMap = this._markLineMap;
\r
49985 for (var name in lineDrawMap) {
\r
49986 lineDrawMap[name].__keep = false;
\r
49989 ecModel.eachSeries(function (seriesModel) {
\r
49990 var mlModel = seriesModel.markLineModel;
\r
49991 mlModel && this._renderSeriesML(seriesModel, mlModel, ecModel, api);
\r
49994 for (var name in lineDrawMap) {
\r
49995 if (!lineDrawMap[name].__keep) {
\r
49996 this.group.remove(lineDrawMap[name].group);
\r
50001 updateLayout: function (markLineModel, ecModel, api) {
\r
50002 ecModel.eachSeries(function (seriesModel) {
\r
50003 var mlModel = seriesModel.markLineModel;
\r
50005 var mlData = mlModel.getData();
\r
50006 var fromData = mlModel.__from;
\r
50007 var toData = mlModel.__to;
\r
50008 // Update visual and layout of from symbol and to symbol
\r
50009 fromData.each(function (idx) {
\r
50010 var lineModel = mlData.getItemModel(idx);
\r
50011 var mlType = lineModel.get('type');
\r
50012 var valueIndex = lineModel.get('valueIndex');
\r
50013 updateSingleMarkerEndLayout(fromData, idx, true, mlType, valueIndex, seriesModel, api);
\r
50014 updateSingleMarkerEndLayout(toData, idx, false, mlType, valueIndex, seriesModel, api);
\r
50016 // Update layout of line
\r
50017 mlData.each(function (idx) {
\r
50018 mlData.setItemLayout(idx, [
\r
50019 fromData.getItemLayout(idx),
\r
50020 toData.getItemLayout(idx)
\r
50024 this._markLineMap[seriesModel.name].updateLayout();
\r
50029 _renderSeriesML: function (seriesModel, mlModel, ecModel, api) {
\r
50030 var coordSys = seriesModel.coordinateSystem;
\r
50031 var seriesName = seriesModel.name;
\r
50032 var seriesData = seriesModel.getData();
\r
50034 var lineDrawMap = this._markLineMap;
\r
50035 var lineDraw = lineDrawMap[seriesName];
\r
50037 lineDraw = lineDrawMap[seriesName] = new LineDraw();
\r
50039 this.group.add(lineDraw.group);
\r
50041 var mlData = createList(coordSys, seriesModel, mlModel);
\r
50043 var fromData = mlData.from;
\r
50044 var toData = mlData.to;
\r
50045 var lineData = mlData.line;
\r
50047 mlModel.__from = fromData;
\r
50048 mlModel.__to = toData;
\r
50049 // Line data for tooltip and formatter
\r
50050 zrUtil.extend(mlModel, markLineFormatMixin);
\r
50051 mlModel.setData(lineData);
\r
50053 var symbolType = mlModel.get('symbol');
\r
50054 var symbolSize = mlModel.get('symbolSize');
\r
50055 if (!zrUtil.isArray(symbolType)) {
\r
50056 symbolType = [symbolType, symbolType];
\r
50058 if (typeof symbolSize === 'number') {
\r
50059 symbolSize = [symbolSize, symbolSize];
\r
50062 // Update visual and layout of from symbol and to symbol
\r
50063 mlData.from.each(function (idx) {
\r
50064 var lineModel = lineData.getItemModel(idx);
\r
50065 var mlType = lineModel.get('type');
\r
50066 var valueIndex = lineModel.get('valueIndex');
\r
50067 updateDataVisualAndLayout(fromData, idx, true, mlType, valueIndex);
\r
50068 updateDataVisualAndLayout(toData, idx, false, mlType, valueIndex);
\r
50071 // Update visual and layout of line
\r
50072 lineData.each(function (idx) {
\r
50073 var lineColor = lineData.getItemModel(idx).get('lineStyle.normal.color');
\r
50074 lineData.setItemVisual(idx, {
\r
50075 color: lineColor || fromData.getItemVisual(idx, 'color')
\r
50077 lineData.setItemLayout(idx, [
\r
50078 fromData.getItemLayout(idx),
\r
50079 toData.getItemLayout(idx)
\r
50083 lineDraw.updateData(lineData, fromData, toData);
\r
50085 // Set host model for tooltip
\r
50087 mlData.line.eachItemGraphicEl(function (el, idx) {
\r
50088 el.traverse(function (child) {
\r
50089 child.dataModel = mlModel;
\r
50093 function updateDataVisualAndLayout(data, idx, isFrom, mlType, valueIndex) {
\r
50094 var itemModel = data.getItemModel(idx);
\r
50096 updateSingleMarkerEndLayout(
\r
50097 data, idx, isFrom, mlType, valueIndex, seriesModel, api
\r
50100 data.setItemVisual(idx, {
\r
50101 symbolSize: itemModel.get('symbolSize')
\r
50102 || symbolSize[isFrom ? 0 : 1],
\r
50103 symbol: itemModel.get('symbol', true)
\r
50104 || symbolType[isFrom ? 0 : 1],
\r
50105 color: itemModel.get('itemStyle.normal.color')
\r
50106 || seriesData.getVisual('color')
\r
50110 lineDraw.__keep = true;
\r
50116 * @param {module:echarts/coord/*} coordSys
\r
50117 * @param {module:echarts/model/Series} seriesModel
\r
50118 * @param {module:echarts/model/Model} mpModel
\r
50120 function createList(coordSys, seriesModel, mlModel) {
\r
50122 var coordDimsInfos;
\r
50124 coordDimsInfos = zrUtil.map(coordSys && coordSys.dimensions, function (coordDim) {
\r
50125 var info = seriesModel.getData().getDimensionInfo(
\r
50126 seriesModel.coordDimToDataDim(coordDim)[0]
\r
50127 ) || {}; // In map series data don't have lng and lat dimension. Fallback to same with coordSys
\r
50128 info.name = coordDim;
\r
50133 coordDimsInfos =[{
\r
50139 var fromData = new List(coordDimsInfos, mlModel);
\r
50140 var toData = new List(coordDimsInfos, mlModel);
\r
50142 var lineData = new List([], mlModel);
\r
50144 var optData = zrUtil.map(mlModel.get('data'), zrUtil.curry(
\r
50145 markLineTransform, seriesModel, coordSys, mlModel
\r
50148 optData = zrUtil.filter(
\r
50149 optData, zrUtil.curry(markLineFilter, coordSys)
\r
50152 var dimValueGetter = coordSys ? markerHelper.dimValueGetter : function (item) {
\r
50153 return item.value;
\r
50155 fromData.initData(
\r
50156 zrUtil.map(optData, function (item) { return item[0]; }),
\r
50157 null, dimValueGetter
\r
50160 zrUtil.map(optData, function (item) { return item[1]; }),
\r
50161 null, dimValueGetter
\r
50163 lineData.initData(
\r
50164 zrUtil.map(optData, function (item) { return item[2]; })
\r
50176 /***/ function(module, exports, __webpack_require__) {
\r
50179 * DataZoom component entry
\r
50183 var echarts = __webpack_require__(1);
\r
50185 echarts.registerPreprocessor(__webpack_require__(323));
\r
50187 __webpack_require__(324);
\r
50188 __webpack_require__(325);
\r
50189 __webpack_require__(326);
\r
50190 __webpack_require__(328);
\r
50196 /***/ function(module, exports, __webpack_require__) {
\r
50199 * @file Timeline preprocessor
\r
50203 var zrUtil = __webpack_require__(3);
\r
50205 module.exports = function (option) {
\r
50206 var timelineOpt = option && option.timeline;
\r
50208 if (!zrUtil.isArray(timelineOpt)) {
\r
50209 timelineOpt = timelineOpt ? [timelineOpt] : [];
\r
50212 zrUtil.each(timelineOpt, function (opt) {
\r
50217 compatibleEC2(opt);
\r
50221 function compatibleEC2(opt) {
\r
50222 var type = opt.type;
\r
50224 var ec2Types = {'number': 'value', 'time': 'time'};
\r
50226 // Compatible with ec2
\r
50227 if (ec2Types[type]) {
\r
50228 opt.axisType = ec2Types[type];
\r
50232 transferItem(opt);
\r
50234 if (has(opt, 'controlPosition')) {
\r
50235 var controlStyle = opt.controlStyle || (opt.controlStyle = {});
\r
50236 if (!has(controlStyle, 'position')) {
\r
50237 controlStyle.position = opt.controlPosition;
\r
50239 if (controlStyle.position === 'none' && !has(controlStyle, 'show')) {
\r
50240 controlStyle.show = false;
\r
50241 delete controlStyle.position;
\r
50243 delete opt.controlPosition;
\r
50246 zrUtil.each(opt.data || [], function (dataItem) {
\r
50247 if (zrUtil.isObject(dataItem) && !zrUtil.isArray(dataItem)) {
\r
50248 if (!has(dataItem, 'value') && has(dataItem, 'name')) {
\r
50249 // In ec2, using name as value.
\r
50250 dataItem.value = dataItem.name;
\r
50252 transferItem(dataItem);
\r
50257 function transferItem(opt) {
\r
50258 var itemStyle = opt.itemStyle || (opt.itemStyle = {});
\r
50260 var itemStyleEmphasis = itemStyle.emphasis || (itemStyle.emphasis = {});
\r
50262 // Transfer label out
\r
50263 var label = opt.label || (opt.label || {});
\r
50264 var labelNormal = label.normal || (label.normal = {});
\r
50265 var excludeLabelAttr = {normal: 1, emphasis: 1};
\r
50267 zrUtil.each(label, function (value, name) {
\r
50268 if (!excludeLabelAttr[name] && !has(labelNormal, name)) {
\r
50269 labelNormal[name] = value;
\r
50273 if (itemStyleEmphasis.label && !has(label, 'emphasis')) {
\r
50274 label.emphasis = itemStyleEmphasis.label;
\r
50275 delete itemStyleEmphasis.label;
\r
50279 function has(obj, attr) {
\r
50280 return obj.hasOwnProperty(attr);
\r
50287 /***/ function(module, exports, __webpack_require__) {
\r
50291 __webpack_require__(19).registerSubTypeDefaulter('timeline', function () {
\r
50292 // Only slider now.
\r
50300 /***/ function(module, exports, __webpack_require__) {
\r
50303 * @file Timeilne action
\r
50307 var echarts = __webpack_require__(1);
\r
50309 echarts.registerAction(
\r
50311 {type: 'timelineChange', event: 'timelineChanged', update: 'prepareAndUpdate'},
\r
50313 function (payload, ecModel) {
\r
50315 var timelineModel = ecModel.getComponent('timeline');
\r
50316 if (timelineModel && payload.currentIndex != null) {
\r
50317 timelineModel.setCurrentIndex(payload.currentIndex);
\r
50319 if (!timelineModel.get('loop', true) && timelineModel.isIndexMax()) {
\r
50320 timelineModel.setPlayState(false);
\r
50324 ecModel.resetOption('timeline');
\r
50328 echarts.registerAction(
\r
50330 {type: 'timelinePlayChange', event: 'timelinePlayChanged', update: 'update'},
\r
50332 function (payload, ecModel) {
\r
50333 var timelineModel = ecModel.getComponent('timeline');
\r
50334 if (timelineModel && payload.playState != null) {
\r
50335 timelineModel.setPlayState(payload.playState);
\r
50344 /***/ function(module, exports, __webpack_require__) {
\r
50347 * @file Silder timeline model
\r
50351 var TimelineModel = __webpack_require__(327);
\r
50353 module.exports = TimelineModel.extend({
\r
50355 type: 'timeline.slider',
\r
50362 backgroundColor: 'rgba(0,0,0,0)', // 时间轴背景颜色
\r
50363 borderColor: '#ccc', // 时间轴边框颜色
\r
50364 borderWidth: 0, // 时间轴边框线宽,单位px,默认为0(无边框)
\r
50366 orient: 'horizontal', // 'vertical'
\r
50369 tooltip: { // boolean or Object
\r
50370 trigger: 'item' // data item may also have tootip attr.
\r
50373 symbol: 'emptyCircle',
\r
50382 position: 'auto', // auto left right top bottom
\r
50383 // When using number, label position is not
\r
50384 // restricted by viewRect.
\r
50385 // positive: right/bottom, negative: left/top
\r
50388 interval: 'auto',
\r
50390 // formatter: null,
\r
50391 textStyle: { // 其余属性默认使用全局文本样式,详见TEXTSTYLE
\r
50397 textStyle: { // 其余属性默认使用全局文本样式,详见TEXTSTYLE
\r
50404 color: '#304654',
\r
50412 checkpointStyle: {
\r
50413 symbol: 'circle',
\r
50415 color: '#c23531',
\r
50417 borderColor: 'rgba(194,53,49, 0.5)',
\r
50419 animationDuration: 300,
\r
50420 animationEasing: 'quinticInOut'
\r
50425 showPlayBtn: true,
\r
50426 showPrevBtn: true,
\r
50427 showNextBtn: true,
\r
50430 position: 'left', // 'left' 'right' 'top' 'bottom'
\r
50431 playIcon: 'path://M31.6,53C17.5,53,6,41.5,6,27.4S17.5,1.8,31.6,1.8C45.7,1.8,57.2,13.3,57.2,27.4S45.7,53,31.6,53z M31.6,3.3 C18.4,3.3,7.5,14.1,7.5,27.4c0,13.3,10.8,24.1,24.1,24.1C44.9,51.5,55.7,40.7,55.7,27.4C55.7,14.1,44.9,3.3,31.6,3.3z M24.9,21.3 c0-2.2,1.6-3.1,3.5-2l10.5,6.1c1.899,1.1,1.899,2.9,0,4l-10.5,6.1c-1.9,1.1-3.5,0.2-3.5-2V21.3z', // jshint ignore:line
\r
50432 stopIcon: 'path://M30.9,53.2C16.8,53.2,5.3,41.7,5.3,27.6S16.8,2,30.9,2C45,2,56.4,13.5,56.4,27.6S45,53.2,30.9,53.2z M30.9,3.5C17.6,3.5,6.8,14.4,6.8,27.6c0,13.3,10.8,24.1,24.101,24.1C44.2,51.7,55,40.9,55,27.6C54.9,14.4,44.1,3.5,30.9,3.5z M36.9,35.8c0,0.601-0.4,1-0.9,1h-1.3c-0.5,0-0.9-0.399-0.9-1V19.5c0-0.6,0.4-1,0.9-1H36c0.5,0,0.9,0.4,0.9,1V35.8z M27.8,35.8 c0,0.601-0.4,1-0.9,1h-1.3c-0.5,0-0.9-0.399-0.9-1V19.5c0-0.6,0.4-1,0.9-1H27c0.5,0,0.9,0.4,0.9,1L27.8,35.8L27.8,35.8z', // jshint ignore:line
\r
50433 nextIcon: 'path://M18.6,50.8l22.5-22.5c0.2-0.2,0.3-0.4,0.3-0.7c0-0.3-0.1-0.5-0.3-0.7L18.7,4.4c-0.1-0.1-0.2-0.3-0.2-0.5 c0-0.4,0.3-0.8,0.8-0.8c0.2,0,0.5,0.1,0.6,0.3l23.5,23.5l0,0c0.2,0.2,0.3,0.4,0.3,0.7c0,0.3-0.1,0.5-0.3,0.7l-0.1,0.1L19.7,52 c-0.1,0.1-0.3,0.2-0.5,0.2c-0.4,0-0.8-0.3-0.8-0.8C18.4,51.2,18.5,51,18.6,50.8z', // jshint ignore:line
\r
50434 prevIcon: 'path://M43,52.8L20.4,30.3c-0.2-0.2-0.3-0.4-0.3-0.7c0-0.3,0.1-0.5,0.3-0.7L42.9,6.4c0.1-0.1,0.2-0.3,0.2-0.5 c0-0.4-0.3-0.8-0.8-0.8c-0.2,0-0.5,0.1-0.6,0.3L18.3,28.8l0,0c-0.2,0.2-0.3,0.4-0.3,0.7c0,0.3,0.1,0.5,0.3,0.7l0.1,0.1L41.9,54 c0.1,0.1,0.3,0.2,0.5,0.2c0.4,0,0.8-0.3,0.8-0.8C43.2,53.2,43.1,53,43,52.8z', // jshint ignore:line
\r
50436 color: '#304654',
\r
50437 borderColor: '#304654',
\r
50441 color: '#c23531',
\r
50442 borderColor: '#c23531',
\r
50455 /***/ function(module, exports, __webpack_require__) {
\r
50458 * @file Timeline model
\r
50462 var ComponentModel = __webpack_require__(19);
\r
50463 var List = __webpack_require__(94);
\r
50464 var zrUtil = __webpack_require__(3);
\r
50465 var modelUtil = __webpack_require__(5);
\r
50467 var TimelineModel = ComponentModel.extend({
\r
50469 type: 'timeline',
\r
50471 layoutMode: 'box',
\r
50478 zlevel: 0, // 一级层叠
\r
50482 axisType: 'time', // 模式是时间类型,支持 value, category
\r
50494 controlPosition: 'left', // 'left' 'right' 'top' 'bottom' 'none'
\r
50496 rewind: false, // 反向播放
\r
50498 playInterval: 2000, // 播放时间间隔,单位ms
\r
50521 init: function (option, parentModel, ecModel) {
\r
50525 * @type {module:echarts/data/List}
\r
50531 * @type {Array.<string>}
\r
50535 this.mergeDefaultAndTheme(option, ecModel);
\r
50536 this._initData();
\r
50542 mergeOption: function (option) {
\r
50543 TimelineModel.superApply(this, 'mergeOption', arguments);
\r
50544 this._initData();
\r
50548 * @param {number} [currentIndex]
\r
50550 setCurrentIndex: function (currentIndex) {
\r
50551 if (currentIndex == null) {
\r
50552 currentIndex = this.option.currentIndex;
\r
50554 var count = this._data.count();
\r
50556 if (this.option.loop) {
\r
50557 currentIndex = (currentIndex % count + count) % count;
\r
50560 currentIndex >= count && (currentIndex = count - 1);
\r
50561 currentIndex < 0 && (currentIndex = 0);
\r
50564 this.option.currentIndex = currentIndex;
\r
50568 * @return {number} currentIndex
\r
50570 getCurrentIndex: function () {
\r
50571 return this.option.currentIndex;
\r
50575 * @return {boolean}
\r
50577 isIndexMax: function () {
\r
50578 return this.getCurrentIndex() >= this._data.count() - 1;
\r
50582 * @param {boolean} state true: play, false: stop
\r
50584 setPlayState: function (state) {
\r
50585 this.option.autoPlay = !!state;
\r
50589 * @return {boolean} true: play, false: stop
\r
50591 getPlayState: function () {
\r
50592 return !!this.option.autoPlay;
\r
50598 _initData: function () {
\r
50599 var thisOption = this.option;
\r
50600 var dataArr = thisOption.data || [];
\r
50601 var axisType = thisOption.axisType;
\r
50602 var names = this._names = [];
\r
50604 if (axisType === 'category') {
\r
50606 zrUtil.each(dataArr, function (item, index) {
\r
50607 var value = modelUtil.getDataItemValue(item);
\r
50610 if (zrUtil.isObject(item)) {
\r
50611 newItem = zrUtil.clone(item);
\r
50612 newItem.value = index;
\r
50618 idxArr.push(newItem);
\r
50620 if (!zrUtil.isString(value) && (value == null || isNaN(value))) {
\r
50624 names.push(value + '');
\r
50626 dataArr = idxArr;
\r
50629 var dimType = ({category: 'ordinal', time: 'time'})[axisType] || 'number';
\r
50631 var data = this._data = new List([{name: 'value', type: dimType}], this);
\r
50633 data.initData(dataArr, names);
\r
50636 getData: function () {
\r
50637 return this._data;
\r
50642 * @return {Array.<string>} categoreis
\r
50644 getCategories: function () {
\r
50645 if (this.get('axisType') === 'category') {
\r
50646 return this._names.slice();
\r
50652 module.exports = TimelineModel;
\r
50657 /***/ function(module, exports, __webpack_require__) {
\r
50660 * @file Silder timeline view
\r
50664 var zrUtil = __webpack_require__(3);
\r
50665 var graphic = __webpack_require__(42);
\r
50666 var layout = __webpack_require__(21);
\r
50667 var TimelineView = __webpack_require__(329);
\r
50668 var TimelineAxis = __webpack_require__(330);
\r
50669 var symbolUtil = __webpack_require__(100);
\r
50670 var axisHelper = __webpack_require__(108);
\r
50671 var BoundingRect = __webpack_require__(15);
\r
50672 var matrix = __webpack_require__(17);
\r
50673 var numberUtil = __webpack_require__(7);
\r
50674 var modelUtil = __webpack_require__(5);
\r
50675 var formatUtil = __webpack_require__(6);
\r
50676 var encodeHTML = formatUtil.encodeHTML;
\r
50678 var bind = zrUtil.bind;
\r
50679 var each = zrUtil.each;
\r
50681 var PI = Math.PI;
\r
50683 module.exports = TimelineView.extend({
\r
50685 type: 'timeline.slider',
\r
50687 init: function (ecModel, api) {
\r
50693 * @type {module:echarts/component/timeline/TimelineAxis}
\r
50699 * @type {module:zrender/core/BoundingRect}
\r
50709 * @type {module:zrende/Element}
\r
50711 this._currentPointer;
\r
50714 * @type {module:zrender/container/Group}
\r
50719 * @type {module:zrender/container/Group}
\r
50721 this._labelGroup;
\r
50727 render: function (timelineModel, ecModel, api, payload) {
\r
50728 this.model = timelineModel;
\r
50730 this.ecModel = ecModel;
\r
50732 this.group.removeAll();
\r
50734 if (timelineModel.get('show', true)) {
\r
50736 var layoutInfo = this._layout(timelineModel, api);
\r
50737 var mainGroup = this._createGroup('mainGroup');
\r
50738 var labelGroup = this._createGroup('labelGroup');
\r
50742 * @type {module:echarts/component/timeline/TimelineAxis}
\r
50744 var axis = this._axis = this._createAxis(layoutInfo, timelineModel);
\r
50747 ['AxisLine', 'AxisTick', 'Control', 'CurrentPointer'],
\r
50748 function (name) {
\r
50749 this['_render' + name](layoutInfo, mainGroup, axis, timelineModel);
\r
50754 this._renderAxisLabel(layoutInfo, labelGroup, axis, timelineModel);
\r
50756 this._position(layoutInfo, timelineModel);
\r
50759 this._doPlayStop();
\r
50765 remove: function () {
\r
50766 this._clearTimer();
\r
50767 this.group.removeAll();
\r
50773 dispose: function () {
\r
50774 this._clearTimer();
\r
50777 _layout: function (timelineModel, api) {
\r
50778 var labelPosOpt = timelineModel.get('label.normal.position');
\r
50779 var orient = timelineModel.get('orient');
\r
50780 var viewRect = getViewRect(timelineModel, api);
\r
50781 // Auto label offset.
\r
50782 if (labelPosOpt == null || labelPosOpt === 'auto') {
\r
50783 labelPosOpt = orient === 'horizontal'
\r
50784 ? ((viewRect.y + viewRect.height / 2) < api.getHeight() / 2 ? '-' : '+')
\r
50785 : ((viewRect.x + viewRect.width / 2) < api.getWidth() / 2 ? '+' : '-');
\r
50787 else if (isNaN(labelPosOpt)) {
\r
50789 horizontal: {top: '-', bottom: '+'},
\r
50790 vertical: {left: '-', right: '+'}
\r
50791 })[orient][labelPosOpt];
\r
50796 // var labelAlign = timelineModel.get('label.normal.textStyle.align');
\r
50797 // var labelBaseline = timelineModel.get('label.normal.textStyle.baseline');
\r
50798 var labelAlignMap = {
\r
50799 horizontal: 'center',
\r
50800 vertical: (labelPosOpt >= 0 || labelPosOpt === '+') ? 'left' : 'right'
\r
50803 var labelBaselineMap = {
\r
50804 horizontal: (labelPosOpt >= 0 || labelPosOpt === '+') ? 'top' : 'bottom',
\r
50805 vertical: 'middle'
\r
50807 var rotationMap = {
\r
50813 var mainLength = orient === 'vertical' ? viewRect.height : viewRect.width;
\r
50815 var controlModel = timelineModel.getModel('controlStyle');
\r
50816 var showControl = controlModel.get('show');
\r
50817 var controlSize = showControl ? controlModel.get('itemSize') : 0;
\r
50818 var controlGap = showControl ? controlModel.get('itemGap') : 0;
\r
50819 var sizePlusGap = controlSize + controlGap;
\r
50821 // Special label rotate.
\r
50822 var labelRotation = timelineModel.get('label.normal.rotate') || 0;
\r
50823 labelRotation = labelRotation * PI / 180; // To radian.
\r
50825 var playPosition;
\r
50826 var prevBtnPosition;
\r
50827 var nextBtnPosition;
\r
50829 var controlPosition = controlModel.get('position', true);
\r
50830 var showControl = controlModel.get('show', true);
\r
50831 var showPlayBtn = showControl && controlModel.get('showPlayBtn', true);
\r
50832 var showPrevBtn = showControl && controlModel.get('showPrevBtn', true);
\r
50833 var showNextBtn = showControl && controlModel.get('showNextBtn', true);
\r
50835 var xRight = mainLength;
\r
50837 // position[0] means left, position[1] means middle.
\r
50838 if (controlPosition === 'left' || controlPosition === 'bottom') {
\r
50839 showPlayBtn && (playPosition = [0, 0], xLeft += sizePlusGap);
\r
50840 showPrevBtn && (prevBtnPosition = [xLeft, 0], xLeft += sizePlusGap);
\r
50841 showNextBtn && (nextBtnPosition = [xRight - controlSize, 0], xRight -= sizePlusGap);
\r
50843 else { // 'top' 'right'
\r
50844 showPlayBtn && (playPosition = [xRight - controlSize, 0], xRight -= sizePlusGap);
\r
50845 showPrevBtn && (prevBtnPosition = [0, 0], xLeft += sizePlusGap);
\r
50846 showNextBtn && (nextBtnPosition = [xRight - controlSize, 0], xRight -= sizePlusGap);
\r
50848 axisExtent = [xLeft, xRight];
\r
50850 if (timelineModel.get('inverse')) {
\r
50851 axisExtent.reverse();
\r
50855 viewRect: viewRect,
\r
50856 mainLength: mainLength,
\r
50859 rotation: rotationMap[orient],
\r
50860 labelRotation: labelRotation,
\r
50861 labelPosOpt: labelPosOpt,
\r
50862 labelAlign: labelAlignMap[orient],
\r
50863 labelBaseline: labelBaselineMap[orient],
\r
50865 // Based on mainGroup.
\r
50866 playPosition: playPosition,
\r
50867 prevBtnPosition: prevBtnPosition,
\r
50868 nextBtnPosition: nextBtnPosition,
\r
50869 axisExtent: axisExtent,
\r
50871 controlSize: controlSize,
\r
50872 controlGap: controlGap
\r
50876 _position: function (layoutInfo, timelineModel) {
\r
50877 // Position is be called finally, because bounding rect is needed for
\r
50878 // adapt content to fill viewRect (auto adapt offset).
\r
50880 // Timeline may be not all in the viewRect when 'offset' is specified
\r
50881 // as a number, because it is more appropriate that label aligns at
\r
50882 // 'offset' but not the other edge defined by viewRect.
\r
50884 var mainGroup = this._mainGroup;
\r
50885 var labelGroup = this._labelGroup;
\r
50887 var viewRect = layoutInfo.viewRect;
\r
50888 if (layoutInfo.orient === 'vertical') {
\r
50889 // transfrom to horizontal, inverse rotate by left-top point.
\r
50890 var m = matrix.create();
\r
50891 var rotateOriginX = viewRect.x;
\r
50892 var rotateOriginY = viewRect.y + viewRect.height;
\r
50893 matrix.translate(m, m, [-rotateOriginX, -rotateOriginY]);
\r
50894 matrix.rotate(m, m, -PI / 2);
\r
50895 matrix.translate(m, m, [rotateOriginX, rotateOriginY]);
\r
50896 viewRect = viewRect.clone();
\r
50897 viewRect.applyTransform(m);
\r
50900 var viewBound = getBound(viewRect);
\r
50901 var mainBound = getBound(mainGroup.getBoundingRect());
\r
50902 var labelBound = getBound(labelGroup.getBoundingRect());
\r
50904 var mainPosition = mainGroup.position;
\r
50905 var labelsPosition = labelGroup.position;
\r
50907 labelsPosition[0] = mainPosition[0] = viewBound[0][0];
\r
50909 var labelPosOpt = layoutInfo.labelPosOpt;
\r
50911 if (isNaN(labelPosOpt)) { // '+' or '-'
\r
50912 var mainBoundIdx = labelPosOpt === '+' ? 0 : 1;
\r
50913 toBound(mainPosition, mainBound, viewBound, 1, mainBoundIdx);
\r
50914 toBound(labelsPosition, labelBound, viewBound, 1, 1 - mainBoundIdx);
\r
50917 var mainBoundIdx = labelPosOpt >= 0 ? 0 : 1;
\r
50918 toBound(mainPosition, mainBound, viewBound, 1, mainBoundIdx);
\r
50919 labelsPosition[1] = mainPosition[1] + labelPosOpt;
\r
50922 mainGroup.position = mainPosition;
\r
50923 labelGroup.position = labelsPosition;
\r
50924 mainGroup.rotation = labelGroup.rotation = layoutInfo.rotation;
\r
50926 setOrigin(mainGroup);
\r
50927 setOrigin(labelGroup);
\r
50929 function setOrigin(targetGroup) {
\r
50930 var pos = targetGroup.position;
\r
50931 targetGroup.origin = [
\r
50932 viewBound[0][0] - pos[0],
\r
50933 viewBound[1][0] - pos[1]
\r
50937 function getBound(rect) {
\r
50938 // [[xmin, xmax], [ymin, ymax]]
\r
50940 [rect.x, rect.x + rect.width],
\r
50941 [rect.y, rect.y + rect.height]
\r
50945 function toBound(fromPos, from, to, dimIdx, boundIdx) {
\r
50946 fromPos[dimIdx] += to[dimIdx][boundIdx] - from[dimIdx][boundIdx];
\r
50950 _createAxis: function (layoutInfo, timelineModel) {
\r
50951 var data = timelineModel.getData();
\r
50952 var axisType = timelineModel.get('axisType');
\r
50954 var scale = axisHelper.createScaleByModel(timelineModel, axisType);
\r
50955 var dataExtent = data.getDataExtent('value');
\r
50956 scale.setExtent(dataExtent[0], dataExtent[1]);
\r
50957 this._customizeScale(scale, data);
\r
50958 scale.niceTicks();
\r
50960 var axis = new TimelineAxis('value', scale, layoutInfo.axisExtent, axisType);
\r
50961 axis.model = timelineModel;
\r
50966 _customizeScale: function (scale, data) {
\r
50968 scale.getTicks = function () {
\r
50969 return data.mapArray(['value'], function (value) {
\r
50974 scale.getTicksLabels = function () {
\r
50975 return zrUtil.map(this.getTicks(), scale.getLabel, scale);
\r
50979 _createGroup: function (name) {
\r
50980 var newGroup = this['_' + name] = new graphic.Group();
\r
50981 this.group.add(newGroup);
\r
50985 _renderAxisLine: function (layoutInfo, group, axis, timelineModel) {
\r
50986 var axisExtent = axis.getExtent();
\r
50988 if (!timelineModel.get('lineStyle.show')) {
\r
50992 group.add(new graphic.Line({
\r
50994 x1: axisExtent[0], y1: 0,
\r
50995 x2: axisExtent[1], y2: 0
\r
50997 style: zrUtil.extend(
\r
50998 {lineCap: 'round'},
\r
50999 timelineModel.getModel('lineStyle').getLineStyle()
\r
51009 _renderAxisTick: function (layoutInfo, group, axis, timelineModel) {
\r
51010 var data = timelineModel.getData();
\r
51011 var ticks = axis.scale.getTicks();
\r
51012 var tooltipHostModel = this._prepareTooltipHostModel(data, timelineModel);
\r
51014 each(ticks, function (value, dataIndex) {
\r
51016 var tickCoord = axis.dataToCoord(value);
\r
51017 var itemModel = data.getItemModel(dataIndex);
\r
51018 var itemStyleModel = itemModel.getModel('itemStyle.normal');
\r
51019 var hoverStyleModel = itemModel.getModel('itemStyle.emphasis');
\r
51020 var symbolOpt = {
\r
51021 position: [tickCoord, 0],
\r
51022 onclick: bind(this._changeTimeline, this, dataIndex)
\r
51024 var el = giveSymbol(itemModel, itemStyleModel, group, symbolOpt);
\r
51025 graphic.setHoverStyle(el, hoverStyleModel.getItemStyle());
\r
51027 if (itemModel.get('tooltip')) {
\r
51028 el.dataIndex = dataIndex;
\r
51029 el.dataModel = tooltipHostModel;
\r
51032 el.dataIndex = el.dataModel = null;
\r
51041 _prepareTooltipHostModel: function (data, timelineModel) {
\r
51042 var tooltipHostModel = modelUtil.createDataFormatModel(
\r
51043 {}, data, timelineModel.get('data')
\r
51047 tooltipHostModel.formatTooltip = function (dataIndex) {
\r
51048 return encodeHTML(me._axis.scale.getLabel(dataIndex));
\r
51051 return tooltipHostModel;
\r
51057 _renderAxisLabel: function (layoutInfo, group, axis, timelineModel) {
\r
51058 var labelModel = timelineModel.getModel('label.normal');
\r
51060 if (!labelModel.get('show')) {
\r
51064 var data = timelineModel.getData();
\r
51065 var ticks = axis.scale.getTicks();
\r
51066 var labels = axisHelper.getFormattedLabels(
\r
51067 axis, labelModel.get('formatter')
\r
51069 var labelInterval = axis.getLabelInterval();
\r
51071 each(ticks, function (tick, dataIndex) {
\r
51072 if (axis.isLabelIgnored(dataIndex, labelInterval)) {
\r
51076 var itemModel = data.getItemModel(dataIndex);
\r
51077 var itemTextStyleModel = itemModel.getModel('label.normal.textStyle');
\r
51078 var hoverTextStyleModel = itemModel.getModel('label.emphasis.textStyle');
\r
51079 var tickCoord = axis.dataToCoord(tick);
\r
51080 var textEl = new graphic.Text({
\r
51082 text: labels[dataIndex],
\r
51083 textAlign: layoutInfo.labelAlign,
\r
51084 textVerticalAlign: layoutInfo.labelBaseline,
\r
51085 textFont: itemTextStyleModel.getFont(),
\r
51086 fill: itemTextStyleModel.getTextColor()
\r
51088 position: [tickCoord, 0],
\r
51089 rotation: layoutInfo.labelRotation - layoutInfo.rotation,
\r
51090 onclick: bind(this._changeTimeline, this, dataIndex),
\r
51094 group.add(textEl);
\r
51095 graphic.setHoverStyle(textEl, hoverTextStyleModel.getItemStyle());
\r
51103 _renderControl: function (layoutInfo, group, axis, timelineModel) {
\r
51104 var controlSize = layoutInfo.controlSize;
\r
51105 var rotation = layoutInfo.rotation;
\r
51107 var itemStyle = timelineModel.getModel('controlStyle.normal').getItemStyle();
\r
51108 var hoverStyle = timelineModel.getModel('controlStyle.emphasis').getItemStyle();
\r
51109 var rect = [0, -controlSize / 2, controlSize, controlSize];
\r
51110 var playState = timelineModel.getPlayState();
\r
51111 var inverse = timelineModel.get('inverse', true);
\r
51114 layoutInfo.nextBtnPosition,
\r
51115 'controlStyle.nextIcon',
\r
51116 bind(this._changeTimeline, this, inverse ? '-' : '+')
\r
51119 layoutInfo.prevBtnPosition,
\r
51120 'controlStyle.prevIcon',
\r
51121 bind(this._changeTimeline, this, inverse ? '+' : '-')
\r
51124 layoutInfo.playPosition,
\r
51125 'controlStyle.' + (playState ? 'stopIcon' : 'playIcon'),
\r
51126 bind(this._handlePlayClick, this, !playState),
\r
51130 function makeBtn(position, iconPath, onclick, willRotate) {
\r
51135 position: position,
\r
51136 origin: [controlSize / 2, 0],
\r
51137 rotation: willRotate ? -rotation : 0,
\r
51139 style: itemStyle,
\r
51142 var btn = makeIcon(timelineModel, iconPath, rect, opt);
\r
51144 graphic.setHoverStyle(btn, hoverStyle);
\r
51148 _renderCurrentPointer: function (layoutInfo, group, axis, timelineModel) {
\r
51149 var data = timelineModel.getData();
\r
51150 var currentIndex = timelineModel.getCurrentIndex();
\r
51151 var pointerModel = data.getItemModel(currentIndex).getModel('checkpointStyle');
\r
51155 onCreate: function (pointer) {
\r
51156 pointer.draggable = true;
\r
51157 pointer.drift = bind(me._handlePointerDrag, me);
\r
51158 pointer.ondragend = bind(me._handlePointerDragend, me);
\r
51159 pointerMoveTo(pointer, currentIndex, axis, timelineModel, true);
\r
51161 onUpdate: function (pointer) {
\r
51162 pointerMoveTo(pointer, currentIndex, axis, timelineModel);
\r
51166 // Reuse when exists, for animation and drag.
\r
51167 this._currentPointer = giveSymbol(
\r
51168 pointerModel, pointerModel, this._mainGroup, {}, this._currentPointer, callback
\r
51172 _handlePlayClick: function (nextState) {
\r
51173 this._clearTimer();
\r
51174 this.api.dispatchAction({
\r
51175 type: 'timelinePlayChange',
\r
51176 playState: nextState,
\r
51181 _handlePointerDrag: function (dx, dy, e) {
\r
51182 this._clearTimer();
\r
51183 this._pointerChangeTimeline([e.offsetX, e.offsetY]);
\r
51186 _handlePointerDragend: function (e) {
\r
51187 this._pointerChangeTimeline([e.offsetX, e.offsetY], true);
\r
51190 _pointerChangeTimeline: function (mousePos, trigger) {
\r
51191 var toCoord = this._toAxisCoord(mousePos)[0];
\r
51193 var axis = this._axis;
\r
51194 var axisExtent = numberUtil.asc(axis.getExtent().slice());
\r
51196 toCoord > axisExtent[1] && (toCoord = axisExtent[1]);
\r
51197 toCoord < axisExtent[0] && (toCoord = axisExtent[0]);
\r
51199 this._currentPointer.position[0] = toCoord;
\r
51200 this._currentPointer.dirty();
\r
51202 var targetDataIndex = this._findNearestTick(toCoord);
\r
51203 var timelineModel = this.model;
\r
51206 targetDataIndex !== timelineModel.getCurrentIndex()
\r
51207 && timelineModel.get('realtime')
\r
51209 this._changeTimeline(targetDataIndex);
\r
51213 _doPlayStop: function () {
\r
51214 this._clearTimer();
\r
51216 if (this.model.getPlayState()) {
\r
51217 this._timer = setTimeout(
\r
51218 bind(handleFrame, this),
\r
51219 this.model.get('playInterval')
\r
51223 function handleFrame() {
\r
51225 var timelineModel = this.model;
\r
51226 this._changeTimeline(
\r
51227 timelineModel.getCurrentIndex()
\r
51228 + (timelineModel.get('rewind', true) ? -1 : 1)
\r
51233 _toAxisCoord: function (vertex) {
\r
51234 var trans = this._mainGroup.getLocalTransform();
\r
51235 return graphic.applyTransform(vertex, trans, true);
\r
51238 _findNearestTick: function (axisCoord) {
\r
51239 var data = this.model.getData();
\r
51240 var dist = Infinity;
\r
51241 var targetDataIndex;
\r
51242 var axis = this._axis;
\r
51244 data.each(['value'], function (value, dataIndex) {
\r
51245 var coord = axis.dataToCoord(value);
\r
51246 var d = Math.abs(coord - axisCoord);
\r
51249 targetDataIndex = dataIndex;
\r
51253 return targetDataIndex;
\r
51256 _clearTimer: function () {
\r
51257 if (this._timer) {
\r
51258 clearTimeout(this._timer);
\r
51259 this._timer = null;
\r
51263 _changeTimeline: function (nextIndex) {
\r
51264 var currentIndex = this.model.getCurrentIndex();
\r
51266 if (nextIndex === '+') {
\r
51267 nextIndex = currentIndex + 1;
\r
51269 else if (nextIndex === '-') {
\r
51270 nextIndex = currentIndex - 1;
\r
51273 this.api.dispatchAction({
\r
51274 type: 'timelineChange',
\r
51275 currentIndex: nextIndex,
\r
51282 function getViewRect(model, api) {
\r
51283 return layout.getLayoutRect(
\r
51284 model.getBoxLayoutParams(),
\r
51286 width: api.getWidth(),
\r
51287 height: api.getHeight()
\r
51289 model.get('padding')
\r
51293 function makeIcon(timelineModel, objPath, rect, opts) {
\r
51294 var icon = graphic.makePath(
\r
51295 timelineModel.get(objPath).replace(/^path:\/\//, ''),
\r
51296 zrUtil.clone(opts || {}),
\r
51297 new BoundingRect(rect[0], rect[1], rect[2], rect[3]),
\r
51305 * Create symbol or update symbol
\r
51307 function giveSymbol(hostModel, itemStyleModel, group, opt, symbol, callback) {
\r
51308 var symbolType = hostModel.get('symbol');
\r
51309 var color = itemStyleModel.get('color');
\r
51310 var symbolSize = hostModel.get('symbolSize');
\r
51311 var halfSymbolSize = symbolSize / 2;
\r
51312 var itemStyle = itemStyleModel.getItemStyle(['color', 'symbol', 'symbolSize']);
\r
51315 symbol = symbolUtil.createSymbol(
\r
51316 symbolType, -halfSymbolSize, -halfSymbolSize, symbolSize, symbolSize, color
\r
51318 group.add(symbol);
\r
51319 callback && callback.onCreate(symbol);
\r
51322 symbol.setStyle(itemStyle);
\r
51323 symbol.setColor(color);
\r
51324 group.add(symbol); // Group may be new, also need to add.
\r
51325 callback && callback.onUpdate(symbol);
\r
51328 opt = zrUtil.merge({
\r
51330 style: itemStyle,
\r
51334 symbol.attr(opt);
\r
51339 function pointerMoveTo(pointer, dataIndex, axis, timelineModel, noAnimation) {
\r
51340 if (pointer.dragging) {
\r
51344 var pointerModel = timelineModel.getModel('checkpointStyle');
\r
51345 var toCoord = axis.dataToCoord(timelineModel.getData().get(['value'], dataIndex));
\r
51347 if (noAnimation || !pointerModel.get('animation', true)) {
\r
51348 pointer.attr({position: [toCoord, 0]});
\r
51351 pointer.stopAnimation(true);
\r
51352 pointer.animateTo(
\r
51353 {position: [toCoord, 0]},
\r
51354 pointerModel.get('animationDuration', true),
\r
51355 pointerModel.get('animationEasing', true)
\r
51364 /***/ function(module, exports, __webpack_require__) {
\r
51367 * @file Timeline view
\r
51371 // var zrUtil = require('zrender/lib/core/util');
\r
51372 // var graphic = require('../../util/graphic');
\r
51373 var ComponentView = __webpack_require__(28);
\r
51375 module.exports = ComponentView.extend({
\r
51384 /***/ function(module, exports, __webpack_require__) {
\r
51388 var zrUtil = __webpack_require__(3);
\r
51389 var Axis = __webpack_require__(117);
\r
51390 var axisHelper = __webpack_require__(108);
\r
51394 * @constructor module:echarts/coord/cartesian/Axis2D
\r
51395 * @extends {module:echarts/coord/cartesian/Axis}
\r
51396 * @param {string} dim
\r
51397 * @param {*} scale
\r
51398 * @param {Array.<number>} coordExtent
\r
51399 * @param {string} axisType
\r
51400 * @param {string} position
\r
51402 var TimelineAxis = function (dim, scale, coordExtent, axisType) {
\r
51404 Axis.call(this, dim, scale, coordExtent);
\r
51414 this.type = axisType || 'value';
\r
51420 this._autoLabelInterval;
\r
51424 * @param {module:echarts/component/TimelineModel}
\r
51426 this.model = null;
\r
51429 TimelineAxis.prototype = {
\r
51431 constructor: TimelineAxis,
\r
51435 * @return {number}
\r
51437 getLabelInterval: function () {
\r
51438 var timelineModel = this.model;
\r
51439 var labelModel = timelineModel.getModel('label.normal');
\r
51440 var labelInterval = labelModel.get('interval');
\r
51442 if (labelInterval != null && labelInterval != 'auto') {
\r
51443 return labelInterval;
\r
51446 var labelInterval = this._autoLabelInterval;
\r
51448 if (!labelInterval) {
\r
51449 labelInterval = this._autoLabelInterval = axisHelper.getAxisLabelInterval(
\r
51450 zrUtil.map(this.scale.getTicks(), this.dataToCoord, this),
\r
51451 axisHelper.getFormattedLabels(this, labelModel.get('formatter')),
\r
51452 labelModel.getModel('textStyle').getFont(),
\r
51453 timelineModel.get('orient') === 'horizontal'
\r
51457 return labelInterval;
\r
51461 * If label is ignored.
\r
51462 * Automatically used when axis is category and label can not be all shown
\r
51464 * @param {number} idx
\r
51465 * @return {boolean}
\r
51467 isLabelIgnored: function (idx) {
\r
51468 if (this.type === 'category') {
\r
51469 var labelInterval = this.getLabelInterval();
\r
51470 return ((typeof labelInterval === 'function')
\r
51471 && !labelInterval(idx, this.scale.getLabel(idx)))
\r
51472 || idx % (labelInterval + 1);
\r
51478 zrUtil.inherits(TimelineAxis, Axis);
\r
51480 module.exports = TimelineAxis;
\r
51485 /***/ function(module, exports, __webpack_require__) {
\r
51489 __webpack_require__(332);
\r
51490 __webpack_require__(334);
\r
51492 __webpack_require__(336);
\r
51493 __webpack_require__(337);
\r
51494 __webpack_require__(338);
\r
51495 __webpack_require__(339);
\r
51496 __webpack_require__(344);
\r
51501 /***/ function(module, exports, __webpack_require__) {
\r
51505 var featureManager = __webpack_require__(333);
\r
51506 var zrUtil = __webpack_require__(3);
\r
51508 var ToolboxModel = __webpack_require__(1).extendComponentModel({
\r
51517 mergeDefaultAndTheme: function (option) {
\r
51518 ToolboxModel.superApply(this, 'mergeDefaultAndTheme', arguments);
\r
51520 zrUtil.each(this.option.feature, function (featureOpt, featureName) {
\r
51521 var Feature = featureManager.get(featureName);
\r
51522 Feature && zrUtil.merge(featureOpt, Feature.defaultOption);
\r
51534 orient: 'horizontal',
\r
51543 backgroundColor: 'transparent',
\r
51545 borderColor: '#ccc',
\r
51559 borderColor: '#666',
\r
51563 borderColor: '#3E98C5'
\r
51566 // textStyle: {},
\r
51572 module.exports = ToolboxModel;
\r
51577 /***/ function(module, exports) {
\r
51582 var features = {};
\r
51584 module.exports = {
\r
51585 register: function (name, ctor) {
\r
51586 features[name] = ctor;
\r
51589 get: function (name) {
\r
51590 return features[name];
\r
51597 /***/ function(module, exports, __webpack_require__) {
\r
51599 /* WEBPACK VAR INJECTION */(function(process) {
\r
51601 var featureManager = __webpack_require__(333);
\r
51602 var zrUtil = __webpack_require__(3);
\r
51603 var graphic = __webpack_require__(42);
\r
51604 var Model = __webpack_require__(8);
\r
51605 var DataDiffer = __webpack_require__(95);
\r
51606 var listComponentHelper = __webpack_require__(266);
\r
51607 var textContain = __webpack_require__(14);
\r
51609 module.exports = __webpack_require__(1).extendComponentView({
\r
51613 render: function (toolboxModel, ecModel, api) {
\r
51614 var group = this.group;
\r
51615 group.removeAll();
\r
51617 if (!toolboxModel.get('show')) {
\r
51621 var itemSize = +toolboxModel.get('itemSize');
\r
51622 var featureOpts = toolboxModel.get('feature') || {};
\r
51623 var features = this._features || (this._features = {});
\r
51625 var featureNames = [];
\r
51626 zrUtil.each(featureOpts, function (opt, name) {
\r
51627 featureNames.push(name);
\r
51630 (new DataDiffer(this._featureNames || [], featureNames))
\r
51633 .remove(zrUtil.curry(process, null))
\r
51636 // Keep for diff.
\r
51637 this._featureNames = featureNames;
\r
51639 function process(newIndex, oldIndex) {
\r
51640 var featureName = featureNames[newIndex];
\r
51641 var oldName = featureNames[oldIndex];
\r
51642 var featureOpt = featureOpts[featureName];
\r
51643 var featureModel = new Model(featureOpt, toolboxModel, toolboxModel.ecModel);
\r
51646 if (featureName && !oldName) { // Create
\r
51647 if (isUserFeatureName(featureName)) {
\r
51649 model: featureModel,
\r
51650 onclick: featureModel.option.onclick,
\r
51651 featureName: featureName
\r
51655 var Feature = featureManager.get(featureName);
\r
51659 feature = new Feature(featureModel);
\r
51661 features[featureName] = feature;
\r
51664 feature = features[oldName];
\r
51665 // If feature does not exsit.
\r
51669 feature.model = featureModel;
\r
51672 if (!featureName && oldName) {
\r
51673 feature.dispose && feature.dispose(ecModel, api);
\r
51677 if (!featureModel.get('show') || feature.unusable) {
\r
51678 feature.remove && feature.remove(ecModel, api);
\r
51682 createIconPaths(featureModel, feature, featureName);
\r
51684 featureModel.setIconStatus = function (iconName, status) {
\r
51685 var option = this.option;
\r
51686 var iconPaths = this.iconPaths;
\r
51687 option.iconStatus = option.iconStatus || {};
\r
51688 option.iconStatus[iconName] = status;
\r
51690 iconPaths[iconName] && iconPaths[iconName].trigger(status);
\r
51693 if (feature.render) {
\r
51694 feature.render(featureModel, ecModel, api);
\r
51698 function createIconPaths(featureModel, feature, featureName) {
\r
51699 var iconStyleModel = featureModel.getModel('iconStyle');
\r
51701 // If one feature has mutiple icon. they are orginaized as
\r
51712 var icons = feature.getIcons ? feature.getIcons() : featureModel.get('icon');
\r
51713 var titles = featureModel.get('title') || {};
\r
51714 if (typeof icons === 'string') {
\r
51715 var icon = icons;
\r
51716 var title = titles;
\r
51719 icons[featureName] = icon;
\r
51720 titles[featureName] = title;
\r
51722 var iconPaths = featureModel.iconPaths = {};
\r
51723 zrUtil.each(icons, function (icon, iconName) {
\r
51724 var normalStyle = iconStyleModel.getModel('normal').getItemStyle();
\r
51725 var hoverStyle = iconStyleModel.getModel('emphasis').getItemStyle();
\r
51728 x: -itemSize / 2,
\r
51729 y: -itemSize / 2,
\r
51733 var path = icon.indexOf('image://') === 0
\r
51735 style.image = icon.slice(8),
\r
51736 new graphic.Image({style: style})
\r
51738 : graphic.makePath(
\r
51739 icon.replace('path://', ''),
\r
51741 style: normalStyle,
\r
51742 hoverStyle: hoverStyle,
\r
51749 graphic.setHoverStyle(path);
\r
51751 if (toolboxModel.get('showTitle')) {
\r
51752 path.__title = titles[iconName];
\r
51753 path.on('mouseover', function () {
\r
51755 text: titles[iconName],
\r
51756 textPosition: hoverStyle.textPosition || 'bottom',
\r
51757 textFill: hoverStyle.fill || hoverStyle.stroke || '#000',
\r
51758 textAlign: hoverStyle.textAlign || 'center'
\r
51761 .on('mouseout', function () {
\r
51767 path.trigger(featureModel.get('iconStatus.' + iconName) || 'normal');
\r
51770 path.on('click', zrUtil.bind(
\r
51771 feature.onclick, feature, ecModel, api, iconName
\r
51774 iconPaths[iconName] = path;
\r
51778 listComponentHelper.layout(group, toolboxModel, api);
\r
51779 // Render background after group is layout
\r
51781 listComponentHelper.addBackground(group, toolboxModel);
\r
51783 // Adjust icon title positions to avoid them out of screen
\r
51784 group.eachChild(function (icon) {
\r
51785 var titleText = icon.__title;
\r
51786 var hoverStyle = icon.hoverStyle;
\r
51787 // May be background element
\r
51788 if (hoverStyle && titleText) {
\r
51789 var rect = textContain.getBoundingRect(
\r
51790 titleText, hoverStyle.font
\r
51792 var offsetX = icon.position[0] + group.position[0];
\r
51793 var offsetY = icon.position[1] + group.position[1] + itemSize;
\r
51795 var needPutOnTop = false;
\r
51796 if (offsetY + rect.height > api.getHeight()) {
\r
51797 hoverStyle.textPosition = 'top';
\r
51798 needPutOnTop = true;
\r
51800 var topOffset = needPutOnTop ? (-5 - rect.height) : (itemSize + 8);
\r
51801 if (offsetX + rect.width / 2 > api.getWidth()) {
\r
51802 hoverStyle.textPosition = ['100%', topOffset];
\r
51803 hoverStyle.textAlign = 'right';
\r
51805 else if (offsetX - rect.width / 2 < 0) {
\r
51806 hoverStyle.textPosition = [0, topOffset];
\r
51807 hoverStyle.textAlign = 'left';
\r
51813 remove: function (ecModel, api) {
\r
51814 zrUtil.each(this._features, function (feature) {
\r
51815 feature.remove && feature.remove(ecModel, api);
\r
51817 this.group.removeAll();
\r
51820 dispose: function (ecModel, api) {
\r
51821 zrUtil.each(this._features, function (feature) {
\r
51822 feature.dispose && feature.dispose(ecModel, api);
\r
51827 function isUserFeatureName(featureName) {
\r
51828 return featureName.indexOf('my') === 0;
\r
51832 /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(335)))
\r
51836 /***/ function(module, exports) {
\r
51838 // shim for using process in browser
\r
51840 var process = module.exports = {};
\r
51842 var draining = false;
\r
51843 var currentQueue;
\r
51844 var queueIndex = -1;
\r
51846 function cleanUpNextTick() {
\r
51847 draining = false;
\r
51848 if (currentQueue.length) {
\r
51849 queue = currentQueue.concat(queue);
\r
51853 if (queue.length) {
\r
51858 function drainQueue() {
\r
51862 var timeout = setTimeout(cleanUpNextTick);
\r
51865 var len = queue.length;
\r
51867 currentQueue = queue;
\r
51869 while (++queueIndex < len) {
\r
51870 if (currentQueue) {
\r
51871 currentQueue[queueIndex].run();
\r
51875 len = queue.length;
\r
51877 currentQueue = null;
\r
51878 draining = false;
\r
51879 clearTimeout(timeout);
\r
51882 process.nextTick = function (fun) {
\r
51883 var args = new Array(arguments.length - 1);
\r
51884 if (arguments.length > 1) {
\r
51885 for (var i = 1; i < arguments.length; i++) {
\r
51886 args[i - 1] = arguments[i];
\r
51889 queue.push(new Item(fun, args));
\r
51890 if (queue.length === 1 && !draining) {
\r
51891 setTimeout(drainQueue, 0);
\r
51895 // v8 likes predictible objects
\r
51896 function Item(fun, array) {
\r
51898 this.array = array;
\r
51900 Item.prototype.run = function () {
\r
51901 this.fun.apply(null, this.array);
\r
51903 process.title = 'browser';
\r
51904 process.browser = true;
\r
51905 process.env = {};
\r
51906 process.argv = [];
\r
51907 process.version = ''; // empty string to avoid regexp issues
\r
51908 process.versions = {};
\r
51910 function noop() {}
\r
51912 process.on = noop;
\r
51913 process.addListener = noop;
\r
51914 process.once = noop;
\r
51915 process.off = noop;
\r
51916 process.removeListener = noop;
\r
51917 process.removeAllListeners = noop;
\r
51918 process.emit = noop;
\r
51920 process.binding = function (name) {
\r
51921 throw new Error('process.binding is not supported');
\r
51924 process.cwd = function () { return '/' };
\r
51925 process.chdir = function (dir) {
\r
51926 throw new Error('process.chdir is not supported');
\r
51928 process.umask = function() { return 0; };
\r
51933 /***/ function(module, exports, __webpack_require__) {
\r
51937 var env = __webpack_require__(78);
\r
51939 function SaveAsImage (model) {
\r
51940 this.model = model;
\r
51943 SaveAsImage.defaultOption = {
\r
51945 icon: 'M4.7,22.9L29.3,45.5L54.7,23.4M4.6,43.6L4.6,58L53.8,58L53.8,43.6M29.2,45.1L29.2,0',
\r
51948 // Default use option.backgroundColor
\r
51949 // backgroundColor: '#fff',
\r
51951 excludeComponents: ['toolbox'],
\r
51953 lang: ['右键另存为图片']
\r
51956 SaveAsImage.prototype.unusable = !env.canvasSupported;
\r
51958 var proto = SaveAsImage.prototype;
\r
51960 proto.onclick = function (ecModel, api) {
\r
51961 var model = this.model;
\r
51962 var title = model.get('name') || ecModel.get('title.0.text') || 'echarts';
\r
51963 var $a = document.createElement('a');
\r
51964 var type = model.get('type', true) || 'png';
\r
51965 $a.download = title + '.' + type;
\r
51966 $a.target = '_blank';
\r
51967 var url = api.getConnectedDataURL({
\r
51969 backgroundColor: model.get('backgroundColor', true)
\r
51970 || ecModel.get('backgroundColor') || '#fff',
\r
51971 excludeComponents: model.get('excludeComponents'),
\r
51972 pixelRatio: model.get('pixelRatio')
\r
51975 // Chrome and Firefox
\r
51976 if (typeof MouseEvent === 'function') {
\r
51977 var evt = new MouseEvent('click', {
\r
51980 cancelable: false
\r
51982 $a.dispatchEvent(evt);
\r
51986 var lang = model.get('lang');
\r
51988 + '<body style="margin:0;">'
\r
51989 + '<img src="' + url + '" style="max-width:100%;" title="' + ((lang && lang[0]) || '') + '" />'
\r
51991 var tab = window.open();
\r
51992 tab.document.write(html);
\r
51996 __webpack_require__(333).register(
\r
51997 'saveAsImage', SaveAsImage
\r
52000 module.exports = SaveAsImage;
\r
52005 /***/ function(module, exports, __webpack_require__) {
\r
52010 var zrUtil = __webpack_require__(3);
\r
52012 function MagicType(model) {
\r
52013 this.model = model;
\r
52016 MagicType.defaultOption = {
\r
52021 line: 'M4.1,28.9h7.1l9.3-22l7.4,38l9.7-19.7l3,12.8h14.9M4.1,58h51.4',
\r
52022 bar: 'M6.7,22.9h10V48h-10V22.9zM24.9,13h10v35h-10V13zM43.2,2h10v46h-10V2zM3.1,58h53.7',
\r
52023 stack: 'M8.2,38.4l-8.4,4.1l30.6,15.3L60,42.5l-8.1-4.1l-21.5,11L8.2,38.4z M51.9,30l-8.1,4.2l-13.4,6.9l-13.9-6.9L8.2,30l-8.4,4.2l8.4,4.2l22.2,11l21.5-11l8.1-4.2L51.9,30z M51.9,21.7l-8.1,4.2L35.7,30l-5.3,2.8L24.9,30l-8.4-4.1l-8.3-4.2l-8.4,4.2L8.2,30l8.3,4.2l13.9,6.9l13.4-6.9l8.1-4.2l8.1-4.1L51.9,21.7zM30.4,2.2L-0.2,17.5l8.4,4.1l8.3,4.2l8.4,4.2l5.5,2.7l5.3-2.7l8.1-4.2l8.1-4.2l8.1-4.1L30.4,2.2z', // jshint ignore:line
\r
52024 tiled: 'M2.3,2.2h22.8V25H2.3V2.2z M35,2.2h22.8V25H35V2.2zM2.3,35h22.8v22.8H2.3V35z M35,35h22.8v22.8H35V35z'
\r
52036 var proto = MagicType.prototype;
\r
52038 proto.getIcons = function () {
\r
52039 var model = this.model;
\r
52040 var availableIcons = model.get('icon');
\r
52042 zrUtil.each(model.get('type'), function (type) {
\r
52043 if (availableIcons[type]) {
\r
52044 icons[type] = availableIcons[type];
\r
52050 var seriesOptGenreator = {
\r
52051 'line': function (seriesType, seriesId, seriesModel, model) {
\r
52052 if (seriesType === 'bar') {
\r
52053 return zrUtil.merge({
\r
52056 // Preserve data related option
\r
52057 data: seriesModel.get('data'),
\r
52058 stack: seriesModel.get('stack'),
\r
52059 markPoint: seriesModel.get('markPoint'),
\r
52060 markLine: seriesModel.get('markLine')
\r
52061 }, model.get('option.line') || {}, true);
\r
52064 'bar': function (seriesType, seriesId, seriesModel, model) {
\r
52065 if (seriesType === 'line') {
\r
52066 return zrUtil.merge({
\r
52069 // Preserve data related option
\r
52070 data: seriesModel.get('data'),
\r
52071 stack: seriesModel.get('stack'),
\r
52072 markPoint: seriesModel.get('markPoint'),
\r
52073 markLine: seriesModel.get('markLine')
\r
52074 }, model.get('option.bar') || {}, true);
\r
52077 'stack': function (seriesType, seriesId, seriesModel, model) {
\r
52078 if (seriesType === 'line' || seriesType === 'bar') {
\r
52079 return zrUtil.merge({
\r
52081 stack: '__ec_magicType_stack__'
\r
52082 }, model.get('option.stack') || {}, true);
\r
52085 'tiled': function (seriesType, seriesId, seriesModel, model) {
\r
52086 if (seriesType === 'line' || seriesType === 'bar') {
\r
52087 return zrUtil.merge({
\r
52090 }, model.get('option.tiled') || {}, true);
\r
52095 var radioTypes = [
\r
52097 ['stack', 'tiled']
\r
52100 proto.onclick = function (ecModel, api, type) {
\r
52101 var model = this.model;
\r
52102 var seriesIndex = model.get('seriesIndex.' + type);
\r
52103 // Not supported magicType
\r
52104 if (!seriesOptGenreator[type]) {
\r
52107 var newOption = {
\r
52110 var generateNewSeriesTypes = function (seriesModel) {
\r
52111 var seriesType = seriesModel.subType;
\r
52112 var seriesId = seriesModel.id;
\r
52113 var newSeriesOpt = seriesOptGenreator[type](
\r
52114 seriesType, seriesId, seriesModel, model
\r
52116 if (newSeriesOpt) {
\r
52117 // PENDING If merge original option?
\r
52118 zrUtil.defaults(newSeriesOpt, seriesModel.option);
\r
52119 newOption.series.push(newSeriesOpt);
\r
52121 // Modify boundaryGap
\r
52122 var coordSys = seriesModel.coordinateSystem;
\r
52123 if (coordSys.type === 'cartesian2d') {
\r
52124 var categoryAxis = coordSys.getAxesByScale('ordinal')[0];
\r
52125 if (categoryAxis) {
\r
52126 var axisDim = categoryAxis.dim;
\r
52127 var axisIndex = seriesModel.get(axisDim + 'AxisIndex');
\r
52128 var axisKey = axisDim + 'Axis';
\r
52129 newOption[axisKey] = newOption[axisKey] || [];
\r
52130 for (var i = 0; i <= axisIndex; i++) {
\r
52131 newOption[axisKey][axisIndex] = newOption[axisKey][axisIndex] || {};
\r
52133 newOption[axisKey][axisIndex].boundaryGap = type === 'bar' ? true : false;
\r
52138 zrUtil.each(radioTypes, function (radio) {
\r
52139 if (zrUtil.indexOf(radio, type) >= 0) {
\r
52140 zrUtil.each(radio, function (item) {
\r
52141 model.setIconStatus(item, 'normal');
\r
52146 model.setIconStatus(type, 'emphasis');
\r
52148 ecModel.eachComponent(
\r
52150 mainType: 'series',
\r
52151 query: seriesIndex == null ? null : {
\r
52152 seriesIndex: seriesIndex
\r
52154 }, generateNewSeriesTypes
\r
52156 api.dispatchAction({
\r
52157 type: 'changeMagicType',
\r
52158 currentType: type,
\r
52159 newOption: newOption
\r
52163 var echarts = __webpack_require__(1);
\r
52164 echarts.registerAction({
\r
52165 type: 'changeMagicType',
\r
52166 event: 'magicTypeChanged',
\r
52167 update: 'prepareAndUpdate'
\r
52168 }, function (payload, ecModel) {
\r
52169 ecModel.mergeOption(payload.newOption);
\r
52172 __webpack_require__(333).register('magicType', MagicType);
\r
52174 module.exports = MagicType;
\r
52179 /***/ function(module, exports, __webpack_require__) {
\r
52182 * @module echarts/component/toolbox/feature/DataView
\r
52187 var zrUtil = __webpack_require__(3);
\r
52188 var eventTool = __webpack_require__(80);
\r
52191 var BLOCK_SPLITER = new Array(60).join('-');
\r
52192 var ITEM_SPLITER = '\t';
\r
52194 * Group series into two types
\r
52195 * 1. on category axis, like line, bar
\r
52196 * 2. others, like scatter, pie
\r
52197 * @param {module:echarts/model/Global} ecModel
\r
52198 * @return {Object}
\r
52201 function groupSeries(ecModel) {
\r
52202 var seriesGroupByCategoryAxis = {};
\r
52203 var otherSeries = [];
\r
52205 ecModel.eachRawSeries(function (seriesModel) {
\r
52206 var coordSys = seriesModel.coordinateSystem;
\r
52208 if (coordSys && (coordSys.type === 'cartesian2d' || coordSys.type === 'polar')) {
\r
52209 var baseAxis = coordSys.getBaseAxis();
\r
52210 if (baseAxis.type === 'category') {
\r
52211 var key = baseAxis.dim + '_' + baseAxis.index;
\r
52212 if (!seriesGroupByCategoryAxis[key]) {
\r
52213 seriesGroupByCategoryAxis[key] = {
\r
52214 categoryAxis: baseAxis,
\r
52215 valueAxis: coordSys.getOtherAxis(baseAxis),
\r
52219 axisDim: baseAxis.dim,
\r
52220 axisIndex: baseAxis.index
\r
52223 seriesGroupByCategoryAxis[key].series.push(seriesModel);
\r
52226 otherSeries.push(seriesModel);
\r
52230 otherSeries.push(seriesModel);
\r
52235 seriesGroupByCategoryAxis: seriesGroupByCategoryAxis,
\r
52236 other: otherSeries,
\r
52242 * Assemble content of series on cateogory axis
\r
52243 * @param {Array.<module:echarts/model/Series>} series
\r
52244 * @return {string}
\r
52247 function assembleSeriesWithCategoryAxis(series) {
\r
52249 zrUtil.each(series, function (group, key) {
\r
52250 var categoryAxis = group.categoryAxis;
\r
52251 var valueAxis = group.valueAxis;
\r
52252 var valueAxisDim = valueAxis.dim;
\r
52254 var headers = [' '].concat(zrUtil.map(group.series, function (series) {
\r
52255 return series.name;
\r
52257 var columns = [categoryAxis.model.getCategories()];
\r
52258 zrUtil.each(group.series, function (series) {
\r
52259 columns.push(series.getRawData().mapArray(valueAxisDim, function (val) {
\r
52263 // Assemble table content
\r
52264 var lines = [headers.join(ITEM_SPLITER)];
\r
52265 for (var i = 0; i < columns[0].length; i++) {
\r
52267 for (var j = 0; j < columns.length; j++) {
\r
52268 items.push(columns[j][i]);
\r
52270 lines.push(items.join(ITEM_SPLITER));
\r
52272 tables.push(lines.join('\n'));
\r
52274 return tables.join('\n\n' + BLOCK_SPLITER + '\n\n');
\r
52278 * Assemble content of other series
\r
52279 * @param {Array.<module:echarts/model/Series>} series
\r
52280 * @return {string}
\r
52283 function assembleOtherSeries(series) {
\r
52284 return zrUtil.map(series, function (series) {
\r
52285 var data = series.getRawData();
\r
52286 var lines = [series.name];
\r
52288 data.each(data.dimensions, function () {
\r
52289 var argLen = arguments.length;
\r
52290 var dataIndex = arguments[argLen - 1];
\r
52291 var name = data.getName(dataIndex);
\r
52292 for (var i = 0; i < argLen - 1; i++) {
\r
52293 vals[i] = arguments[i];
\r
52295 lines.push((name ? (name + ITEM_SPLITER) : '') + vals.join(ITEM_SPLITER));
\r
52297 return lines.join('\n');
\r
52298 }).join('\n\n' + BLOCK_SPLITER + '\n\n');
\r
52302 * @param {module:echarts/model/Global}
\r
52303 * @return {string}
\r
52306 function getContentFromModel(ecModel) {
\r
52308 var result = groupSeries(ecModel);
\r
52311 value: zrUtil.filter([
\r
52312 assembleSeriesWithCategoryAxis(result.seriesGroupByCategoryAxis),
\r
52313 assembleOtherSeries(result.other)
\r
52314 ], function (str) {
\r
52315 return str.replace(/[\n\t\s]/g, '');
\r
52316 }).join('\n\n' + BLOCK_SPLITER + '\n\n'),
\r
52318 meta: result.meta
\r
52323 function trim(str) {
\r
52324 return str.replace(/^\s\s*/, '').replace(/\s\s*$/, '');
\r
52327 * If a block is tsv format
\r
52329 function isTSVFormat(block) {
\r
52330 // Simple method to find out if a block is tsv format
\r
52331 var firstLine = block.slice(0, block.indexOf('\n'));
\r
52332 if (firstLine.indexOf(ITEM_SPLITER) >= 0) {
\r
52337 var itemSplitRegex = new RegExp('[' + ITEM_SPLITER + ']+', 'g');
\r
52339 * @param {string} tsv
\r
52340 * @return {Array.<Object>}
\r
52342 function parseTSVContents(tsv) {
\r
52343 var tsvLines = tsv.split(/\n+/g);
\r
52344 var headers = trim(tsvLines.shift()).split(itemSplitRegex);
\r
52346 var categories = [];
\r
52347 var series = zrUtil.map(headers, function (header) {
\r
52353 for (var i = 0; i < tsvLines.length; i++) {
\r
52354 var items = trim(tsvLines[i]).split(itemSplitRegex);
\r
52355 categories.push(items.shift());
\r
52356 for (var j = 0; j < items.length; j++) {
\r
52357 series[j] && (series[j].data[i] = items[j]);
\r
52362 categories: categories
\r
52367 * @param {string} str
\r
52368 * @return {Array.<Object>}
\r
52371 function parseListContents(str) {
\r
52372 var lines = str.split(/\n+/g);
\r
52373 var seriesName = trim(lines.shift());
\r
52376 for (var i = 0; i < lines.length; i++) {
\r
52377 var items = trim(lines[i]).split(itemSplitRegex);
\r
52380 var hasName = false;
\r
52381 if (isNaN(items[0])) { // First item is name
\r
52384 items = items.slice(1);
\r
52389 value = data[i].value;
\r
52392 value = data[i] = [];
\r
52394 for (var j = 0; j < items.length; j++) {
\r
52395 value.push(+items[j]);
\r
52397 if (value.length === 1) {
\r
52398 hasName ? (data[i].value = value[0]) : (data[i] = value[0]);
\r
52403 name: seriesName,
\r
52409 * @param {string} str
\r
52410 * @param {Array.<Object>} blockMetaList
\r
52411 * @return {Object}
\r
52414 function parseContents(str, blockMetaList) {
\r
52415 var blocks = str.split(new RegExp('\n*' + BLOCK_SPLITER + '\n*', 'g'));
\r
52416 var newOption = {
\r
52419 zrUtil.each(blocks, function (block, idx) {
\r
52420 if (isTSVFormat(block)) {
\r
52421 var result = parseTSVContents(block);
\r
52422 var blockMeta = blockMetaList[idx];
\r
52423 var axisKey = blockMeta.axisDim + 'Axis';
\r
52426 newOption[axisKey] = newOption[axisKey] || [];
\r
52427 newOption[axisKey][blockMeta.axisIndex] = {
\r
52428 data: result.categories
\r
52430 newOption.series = newOption.series.concat(result.series);
\r
52434 var result = parseListContents(block);
\r
52435 newOption.series.push(result);
\r
52438 return newOption;
\r
52442 * @alias {module:echarts/component/toolbox/feature/DataView}
\r
52444 * @param {module:echarts/model/Model} model
\r
52446 function DataView(model) {
\r
52448 this._dom = null;
\r
52450 this.model = model;
\r
52453 DataView.defaultOption = {
\r
52456 optionToContent: null,
\r
52457 contentToOption: null,
\r
52459 icon: 'M17.5,17.3H33 M17.5,17.3H33 M45.4,29.5h-28 M11.5,2v56H51V14.8L38.4,2H11.5z M38.4,2.2v12.7H51 M45.4,41.7h-28',
\r
52461 lang: ['数据视图', '关闭', '刷新'],
\r
52462 backgroundColor: '#fff',
\r
52463 textColor: '#000',
\r
52464 textareaColor: '#fff',
\r
52465 textareaBorderColor: '#333',
\r
52466 buttonColor: '#c23531',
\r
52467 buttonTextColor: '#fff'
\r
52470 DataView.prototype.onclick = function (ecModel, api) {
\r
52471 var container = api.getDom();
\r
52472 var model = this.model;
\r
52474 container.removeChild(this._dom);
\r
52476 var root = document.createElement('div');
\r
52477 root.style.cssText = 'position:absolute;left:5px;top:5px;bottom:5px;right:5px;';
\r
52478 root.style.backgroundColor = model.get('backgroundColor') || '#fff';
\r
52480 // Create elements
\r
52481 var header = document.createElement('h4');
\r
52482 var lang = model.get('lang') || [];
\r
52483 header.innerHTML = lang[0] || model.get('title');
\r
52484 header.style.cssText = 'margin: 10px 20px;';
\r
52485 header.style.color = model.get('textColor');
\r
52487 var viewMain = document.createElement('div');
\r
52488 var textarea = document.createElement('textarea');
\r
52489 viewMain.style.cssText = 'display:block;width:100%;overflow:hidden;';
\r
52491 var optionToContent = model.get('optionToContent');
\r
52492 var contentToOption = model.get('contentToOption');
\r
52493 var result = getContentFromModel(ecModel);
\r
52494 if (typeof optionToContent === 'function') {
\r
52495 var htmlOrDom = optionToContent(api.getOption());
\r
52496 if (typeof htmlOrDom === 'string') {
\r
52497 viewMain.innerHTML = htmlOrDom;
\r
52499 else if (zrUtil.isDom(htmlOrDom)) {
\r
52500 viewMain.appendChild(htmlOrDom);
\r
52504 // Use default textarea
\r
52505 viewMain.appendChild(textarea);
\r
52506 textarea.readOnly = model.get('readOnly');
\r
52507 textarea.style.cssText = 'width:100%;height:100%;font-family:monospace;font-size:14px;line-height:1.6rem;';
\r
52508 textarea.style.color = model.get('textColor');
\r
52509 textarea.style.borderColor = model.get('textareaBorderColor');
\r
52510 textarea.style.backgroundColor = model.get('textareaColor');
\r
52511 textarea.value = result.value;
\r
52514 var blockMetaList = result.meta;
\r
52516 var buttonContainer = document.createElement('div');
\r
52517 buttonContainer.style.cssText = 'position:absolute;bottom:0;left:0;right:0;';
\r
52519 var buttonStyle = 'float:right;margin-right:20px;border:none;'
\r
52520 + 'cursor:pointer;padding:2px 5px;font-size:12px;border-radius:3px';
\r
52521 var closeButton = document.createElement('div');
\r
52522 var refreshButton = document.createElement('div');
\r
52524 buttonStyle += ';background-color:' + model.get('buttonColor');
\r
52525 buttonStyle += ';color:' + model.get('buttonTextColor');
\r
52529 function close() {
\r
52530 container.removeChild(root);
\r
52531 self._dom = null;
\r
52533 eventTool.addEventListener(closeButton, 'click', close);
\r
52535 eventTool.addEventListener(refreshButton, 'click', function () {
\r
52538 if (typeof contentToOption === 'function') {
\r
52539 newOption = contentToOption(viewMain, api.getOption());
\r
52542 newOption = parseContents(textarea.value, blockMetaList);
\r
52547 throw new Error('Data view format error ' + e);
\r
52550 api.dispatchAction({
\r
52551 type: 'changeDataView',
\r
52552 newOption: newOption
\r
52559 closeButton.innerHTML = lang[1];
\r
52560 refreshButton.innerHTML = lang[2];
\r
52561 refreshButton.style.cssText = buttonStyle;
\r
52562 closeButton.style.cssText = buttonStyle;
\r
52564 !model.get('readOnly') && buttonContainer.appendChild(refreshButton);
\r
52565 buttonContainer.appendChild(closeButton);
\r
52567 // http://stackoverflow.com/questions/6637341/use-tab-to-indent-in-textarea
\r
52568 eventTool.addEventListener(textarea, 'keydown', function (e) {
\r
52569 if ((e.keyCode || e.which) === 9) {
\r
52570 // get caret position/selection
\r
52571 var val = this.value;
\r
52572 var start = this.selectionStart;
\r
52573 var end = this.selectionEnd;
\r
52575 // set textarea value to: text before caret + tab + text after caret
\r
52576 this.value = val.substring(0, start) + ITEM_SPLITER + val.substring(end);
\r
52578 // put caret at right position again
\r
52579 this.selectionStart = this.selectionEnd = start + 1;
\r
52581 // prevent the focus lose
\r
52582 eventTool.stop(e);
\r
52586 root.appendChild(header);
\r
52587 root.appendChild(viewMain);
\r
52588 root.appendChild(buttonContainer);
\r
52590 viewMain.style.height = (container.clientHeight - 80) + 'px';
\r
52592 container.appendChild(root);
\r
52593 this._dom = root;
\r
52596 DataView.prototype.remove = function (ecModel, api) {
\r
52597 this._dom && api.getDom().removeChild(this._dom);
\r
52600 DataView.prototype.dispose = function (ecModel, api) {
\r
52601 this.remove(ecModel, api);
\r
52607 function tryMergeDataOption(newData, originalData) {
\r
52608 return zrUtil.map(newData, function (newVal, idx) {
\r
52609 var original = originalData && originalData[idx];
\r
52610 if (zrUtil.isObject(original) && !zrUtil.isArray(original)) {
\r
52611 if (zrUtil.isObject(newVal) && !zrUtil.isArray(newVal)) {
\r
52612 newVal = newVal.value;
\r
52614 // Original data has option
\r
52615 return zrUtil.defaults({
\r
52625 __webpack_require__(333).register('dataView', DataView);
\r
52627 __webpack_require__(1).registerAction({
\r
52628 type: 'changeDataView',
\r
52629 event: 'dataViewChanged',
\r
52630 update: 'prepareAndUpdate'
\r
52631 }, function (payload, ecModel) {
\r
52632 var newSeriesOptList = [];
\r
52633 zrUtil.each(payload.newOption.series, function (seriesOpt) {
\r
52634 var seriesModel = ecModel.getSeriesByName(seriesOpt.name)[0];
\r
52635 if (!seriesModel) {
\r
52636 // New created series
\r
52637 // Geuss the series type
\r
52638 newSeriesOptList.push(zrUtil.extend({
\r
52639 // Default is scatter
\r
52644 var originalData = seriesModel.get('data');
\r
52645 newSeriesOptList.push({
\r
52646 name: seriesOpt.name,
\r
52647 data: tryMergeDataOption(seriesOpt.data, originalData)
\r
52652 ecModel.mergeOption(zrUtil.defaults({
\r
52653 series: newSeriesOptList
\r
52654 }, payload.newOption));
\r
52657 module.exports = DataView;
\r
52662 /***/ function(module, exports, __webpack_require__) {
\r
52667 var zrUtil = __webpack_require__(3);
\r
52668 var numberUtil = __webpack_require__(7);
\r
52669 var SelectController = __webpack_require__(225);
\r
52670 var BoundingRect = __webpack_require__(15);
\r
52671 var Group = __webpack_require__(29);
\r
52672 var history = __webpack_require__(340);
\r
52673 var interactionMutex = __webpack_require__(160);
\r
52675 var each = zrUtil.each;
\r
52676 var asc = numberUtil.asc;
\r
52678 // Use dataZoomSelect
\r
52679 __webpack_require__(341);
\r
52681 // Spectial component id start with \0ec\0, see echarts/model/Global.js~hasInnerId
\r
52682 var DATA_ZOOM_ID_BASE = '\0_ec_\0toolbox-dataZoom_';
\r
52684 function DataZoom(model) {
\r
52685 this.model = model;
\r
52689 * @type {module:zrender/container/Group}
\r
52691 this._controllerGroup;
\r
52695 * @type {module:echarts/component/helper/SelectController}
\r
52697 this._controller;
\r
52700 * Is zoom active.
\r
52704 this._isZoomActive;
\r
52707 DataZoom.defaultOption = {
\r
52711 zoom: 'M0,13.5h26.9 M13.5,26.9V0 M32.1,13.5H58V58H13.5 V32.1',
\r
52712 back: 'M22,1.4L9.9,13.5l12.3,12.3 M10.3,13.5H54.9v44.6 H10.3v-26'
\r
52720 var proto = DataZoom.prototype;
\r
52722 proto.render = function (featureModel, ecModel, api) {
\r
52723 updateBackBtnStatus(featureModel, ecModel);
\r
52726 proto.onclick = function (ecModel, api, type) {
\r
52727 var controllerGroup = this._controllerGroup;
\r
52728 if (!this._controllerGroup) {
\r
52729 controllerGroup = this._controllerGroup = new Group();
\r
52730 api.getZr().add(controllerGroup);
\r
52733 handlers[type].call(this, controllerGroup, this.model, ecModel, api);
\r
52736 proto.remove = function (ecModel, api) {
\r
52737 this._disposeController();
\r
52738 interactionMutex.release('globalPan', api.getZr());
\r
52741 proto.dispose = function (ecModel, api) {
\r
52742 var zr = api.getZr();
\r
52743 interactionMutex.release('globalPan', zr);
\r
52744 this._disposeController();
\r
52745 this._controllerGroup && zr.remove(this._controllerGroup);
\r
52753 zoom: function (controllerGroup, featureModel, ecModel, api) {
\r
52754 var isZoomActive = this._isZoomActive = !this._isZoomActive;
\r
52755 var zr = api.getZr();
\r
52757 interactionMutex[isZoomActive ? 'take' : 'release']('globalPan', zr);
\r
52759 featureModel.setIconStatus('zoom', isZoomActive ? 'emphasis' : 'normal');
\r
52761 if (isZoomActive) {
\r
52762 zr.setDefaultCursorStyle('crosshair');
\r
52764 this._createController(
\r
52765 controllerGroup, featureModel, ecModel, api
\r
52769 zr.setDefaultCursorStyle('default');
\r
52770 this._disposeController();
\r
52774 back: function (controllerGroup, featureModel, ecModel, api) {
\r
52775 this._dispatchAction(history.pop(ecModel), api);
\r
52782 proto._createController = function (
\r
52783 controllerGroup, featureModel, ecModel, api
\r
52785 var controller = this._controller = new SelectController(
\r
52792 fill: 'rgba(0,0,0,0.2)'
\r
52798 this._onSelected, this, controller,
\r
52799 featureModel, ecModel, api
\r
52802 controller.enable(controllerGroup, false);
\r
52805 proto._disposeController = function () {
\r
52806 var controller = this._controller;
\r
52807 if (controller) {
\r
52808 controller.off('selected');
\r
52809 controller.dispose();
\r
52813 function prepareCoordInfo(grid, ecModel) {
\r
52814 // Default use the first axis.
\r
52816 var coordInfo = [
\r
52817 {axisModel: grid.getAxis('x').model, axisIndex: 0}, // x
\r
52818 {axisModel: grid.getAxis('y').model, axisIndex: 0} // y
\r
52820 coordInfo.grid = grid;
\r
52822 ecModel.eachComponent(
\r
52823 {mainType: 'dataZoom', subType: 'select'},
\r
52824 function (dzModel, dataZoomIndex) {
\r
52825 if (isTheAxis('xAxis', coordInfo[0].axisModel, dzModel, ecModel)) {
\r
52826 coordInfo[0].dataZoomModel = dzModel;
\r
52828 if (isTheAxis('yAxis', coordInfo[1].axisModel, dzModel, ecModel)) {
\r
52829 coordInfo[1].dataZoomModel = dzModel;
\r
52834 return coordInfo;
\r
52837 function isTheAxis(axisName, axisModel, dataZoomModel, ecModel) {
\r
52838 var axisIndex = dataZoomModel.get(axisName + 'Index');
\r
52839 return axisIndex != null
\r
52840 && ecModel.getComponent(axisName, axisIndex) === axisModel;
\r
52846 proto._onSelected = function (controller, featureModel, ecModel, api, selRanges) {
\r
52847 if (!selRanges.length) {
\r
52850 var selRange = selRanges[0];
\r
52852 controller.update(); // remove cover
\r
52854 var snapshot = {};
\r
52859 ecModel.eachComponent('grid', function (gridModel, gridIndex) {
\r
52860 var grid = gridModel.coordinateSystem;
\r
52861 var coordInfo = prepareCoordInfo(grid, ecModel);
\r
52862 var selDataRange = pointToDataInCartesian(selRange, coordInfo);
\r
52864 if (selDataRange) {
\r
52865 var xBatchItem = scaleCartesianAxis(selDataRange, coordInfo, 0, 'x');
\r
52866 var yBatchItem = scaleCartesianAxis(selDataRange, coordInfo, 1, 'y');
\r
52868 xBatchItem && (snapshot[xBatchItem.dataZoomId] = xBatchItem);
\r
52869 yBatchItem && (snapshot[yBatchItem.dataZoomId] = yBatchItem);
\r
52873 history.push(ecModel, snapshot);
\r
52875 this._dispatchAction(snapshot, api);
\r
52878 function pointToDataInCartesian(selRange, coordInfo) {
\r
52879 var grid = coordInfo.grid;
\r
52881 var selRect = new BoundingRect(
\r
52884 selRange[0][1] - selRange[0][0],
\r
52885 selRange[1][1] - selRange[1][0]
\r
52887 if (!selRect.intersect(grid.getRect())) {
\r
52890 var cartesian = grid.getCartesian(coordInfo[0].axisIndex, coordInfo[1].axisIndex);
\r
52891 var dataLeftTop = cartesian.pointToData([selRange[0][0], selRange[1][0]], true);
\r
52892 var dataRightBottom = cartesian.pointToData([selRange[0][1], selRange[1][1]], true);
\r
52895 asc([dataLeftTop[0], dataRightBottom[0]]), // x, using asc to handle inverse
\r
52896 asc([dataLeftTop[1], dataRightBottom[1]]) // y, using asc to handle inverse
\r
52900 function scaleCartesianAxis(selDataRange, coordInfo, dimIdx, dimName) {
\r
52901 var dimCoordInfo = coordInfo[dimIdx];
\r
52902 var dataZoomModel = dimCoordInfo.dataZoomModel;
\r
52904 if (dataZoomModel) {
\r
52906 dataZoomId: dataZoomModel.id,
\r
52907 startValue: selDataRange[dimIdx][0],
\r
52908 endValue: selDataRange[dimIdx][1]
\r
52916 proto._dispatchAction = function (snapshot, api) {
\r
52919 each(snapshot, function (batchItem) {
\r
52920 batch.push(batchItem);
\r
52923 batch.length && api.dispatchAction({
\r
52924 type: 'dataZoom',
\r
52926 batch: zrUtil.clone(batch, true)
\r
52930 function updateBackBtnStatus(featureModel, ecModel) {
\r
52931 featureModel.setIconStatus(
\r
52933 history.count(ecModel) > 1 ? 'emphasis' : 'normal'
\r
52938 __webpack_require__(333).register('dataZoom', DataZoom);
\r
52941 // Create special dataZoom option for select
\r
52942 __webpack_require__(1).registerPreprocessor(function (option) {
\r
52947 var dataZoomOpts = option.dataZoom || (option.dataZoom = []);
\r
52948 if (!zrUtil.isArray(dataZoomOpts)) {
\r
52949 dataZoomOpts = [dataZoomOpts];
\r
52952 var toolboxOpt = option.toolbox;
\r
52953 if (toolboxOpt) {
\r
52954 // Assume there is only one toolbox
\r
52955 if (zrUtil.isArray(toolboxOpt)) {
\r
52956 toolboxOpt = toolboxOpt[0];
\r
52959 if (toolboxOpt && toolboxOpt.feature) {
\r
52960 var dataZoomOpt = toolboxOpt.feature.dataZoom;
\r
52961 addForAxis('xAxis', dataZoomOpt);
\r
52962 addForAxis('yAxis', dataZoomOpt);
\r
52966 function addForAxis(axisName, dataZoomOpt) {
\r
52967 if (!dataZoomOpt) {
\r
52971 var axisIndicesName = axisName + 'Index';
\r
52972 var givenAxisIndices = dataZoomOpt[axisIndicesName];
\r
52973 if (givenAxisIndices != null && !zrUtil.isArray(givenAxisIndices)) {
\r
52974 givenAxisIndices = givenAxisIndices === false ? [] : [givenAxisIndices];
\r
52977 forEachComponent(axisName, function (axisOpt, axisIndex) {
\r
52978 if (givenAxisIndices != null
\r
52979 && zrUtil.indexOf(givenAxisIndices, axisIndex) === -1
\r
52985 $fromToolbox: true,
\r
52986 // Id for merge mapping.
\r
52987 id: DATA_ZOOM_ID_BASE + axisName + axisIndex
\r
52990 // Only support one axis now.
\r
52991 newOpt[axisIndicesName] = axisIndex;
\r
52992 dataZoomOpts.push(newOpt);
\r
52996 function forEachComponent(mainType, cb) {
\r
52997 var opts = option[mainType];
\r
52998 if (!zrUtil.isArray(opts)) {
\r
52999 opts = opts ? [opts] : [];
\r
53005 module.exports = DataZoom;
\r
53010 /***/ function(module, exports, __webpack_require__) {
\r
53013 * @file History manager.
\r
53017 var zrUtil = __webpack_require__(3);
\r
53018 var each = zrUtil.each;
\r
53020 var ATTR = '\0_ec_hist_store';
\r
53026 * @param {module:echarts/model/Global} ecModel
\r
53027 * @param {Object} newSnapshot {dataZoomId, batch: [payloadInfo, ...]}
\r
53029 push: function (ecModel, newSnapshot) {
\r
53030 var store = giveStore(ecModel);
\r
53032 // If previous dataZoom can not be found,
\r
53033 // complete an range with current range.
\r
53034 each(newSnapshot, function (batchItem, dataZoomId) {
\r
53035 var i = store.length - 1;
\r
53036 for (; i >= 0; i--) {
\r
53037 var snapshot = store[i];
\r
53038 if (snapshot[dataZoomId]) {
\r
53043 // No origin range set, create one by current range.
\r
53044 var dataZoomModel = ecModel.queryComponents(
\r
53045 {mainType: 'dataZoom', subType: 'select', id: dataZoomId}
\r
53047 if (dataZoomModel) {
\r
53048 var percentRange = dataZoomModel.getPercentRange();
\r
53049 store[0][dataZoomId] = {
\r
53050 dataZoomId: dataZoomId,
\r
53051 start: percentRange[0],
\r
53052 end: percentRange[1]
\r
53058 store.push(newSnapshot);
\r
53063 * @param {module:echarts/model/Global} ecModel
\r
53064 * @return {Object} snapshot
\r
53066 pop: function (ecModel) {
\r
53067 var store = giveStore(ecModel);
\r
53068 var head = store[store.length - 1];
\r
53069 store.length > 1 && store.pop();
\r
53071 // Find top for all dataZoom.
\r
53072 var snapshot = {};
\r
53073 each(head, function (batchItem, dataZoomId) {
\r
53074 for (var i = store.length - 1; i >= 0; i--) {
\r
53075 var batchItem = store[i][dataZoomId];
\r
53077 snapshot[dataZoomId] = batchItem;
\r
53089 clear: function (ecModel) {
\r
53090 ecModel[ATTR] = null;
\r
53095 * @param {module:echarts/model/Global} ecModel
\r
53096 * @return {number} records. always >= 1.
\r
53098 count: function (ecModel) {
\r
53099 return giveStore(ecModel).length;
\r
53105 * [{key: dataZoomId, value: {dataZoomId, range}}, ...]
\r
53106 * History length of each dataZoom may be different.
\r
53107 * this._history[0] is used to store origin range.
\r
53108 * @type {Array.<Object>}
\r
53110 function giveStore(ecModel) {
\r
53111 var store = ecModel[ATTR];
\r
53113 store = ecModel[ATTR] = [{}];
\r
53118 module.exports = history;
\r
53124 /***/ function(module, exports, __webpack_require__) {
\r
53127 * DataZoom component entry
\r
53131 __webpack_require__(287);
\r
53133 __webpack_require__(288);
\r
53134 __webpack_require__(290);
\r
53136 __webpack_require__(342);
\r
53137 __webpack_require__(343);
\r
53139 __webpack_require__(298);
\r
53140 __webpack_require__(299);
\r
53146 /***/ function(module, exports, __webpack_require__) {
\r
53149 * @file Data zoom model
\r
53153 var DataZoomModel = __webpack_require__(288);
\r
53155 module.exports = DataZoomModel.extend({
\r
53157 type: 'dataZoom.select'
\r
53165 /***/ function(module, exports, __webpack_require__) {
\r
53169 module.exports = __webpack_require__(290).extend({
\r
53171 type: 'dataZoom.select'
\r
53179 /***/ function(module, exports, __webpack_require__) {
\r
53184 var history = __webpack_require__(340);
\r
53186 function Restore(model) {
\r
53187 this.model = model;
\r
53190 Restore.defaultOption = {
\r
53192 icon: 'M3.8,33.4 M47,18.9h9.8V8.7 M56.3,20.1 C52.1,9,40.5,0.6,26.8,2.1C12.6,3.7,1.6,16.2,2.1,30.6 M13,41.1H3.1v10.2 M3.7,39.9c4.2,11.1,15.8,19.5,29.5,18 c14.2-1.6,25.2-14.1,24.7-28.5',
\r
53196 var proto = Restore.prototype;
\r
53198 proto.onclick = function (ecModel, api, type) {
\r
53199 history.clear(ecModel);
\r
53201 api.dispatchAction({
\r
53208 __webpack_require__(333).register('restore', Restore);
\r
53211 __webpack_require__(1).registerAction(
\r
53212 {type: 'restore', event: 'restore', update: 'prepareAndUpdate'},
\r
53213 function (payload, ecModel) {
\r
53214 ecModel.resetOption('recreate');
\r
53218 module.exports = Restore;
\r
53223 /***/ function(module, exports, __webpack_require__) {
\r
53226 __webpack_require__(346);
\r
53227 __webpack_require__(77).registerPainter('vml', __webpack_require__(348));
\r
53232 /***/ function(module, exports, __webpack_require__) {
\r
53234 // http://www.w3.org/TR/NOTE-VML
\r
53235 // TODO Use proxy like svg instead of overwrite brush methods
\r
53238 if (!__webpack_require__(78).canvasSupported) {
\r
53239 var vec2 = __webpack_require__(16);
\r
53240 var BoundingRect = __webpack_require__(15);
\r
53241 var CMD = __webpack_require__(48).CMD;
\r
53242 var colorTool = __webpack_require__(38);
\r
53243 var textContain = __webpack_require__(14);
\r
53244 var RectText = __webpack_require__(47);
\r
53245 var Displayable = __webpack_require__(45);
\r
53246 var ZImage = __webpack_require__(59);
\r
53247 var Text = __webpack_require__(62);
\r
53248 var Path = __webpack_require__(44);
\r
53250 var Gradient = __webpack_require__(4);
\r
53252 var vmlCore = __webpack_require__(347);
\r
53254 var round = Math.round;
\r
53255 var sqrt = Math.sqrt;
\r
53256 var abs = Math.abs;
\r
53257 var cos = Math.cos;
\r
53258 var sin = Math.sin;
\r
53259 var mathMax = Math.max;
\r
53261 var applyTransform = vec2.applyTransform;
\r
53264 var imageTransformPrefix = 'progid:DXImageTransform.Microsoft';
\r
53269 var ZLEVEL_BASE = 100000;
\r
53270 var Z_BASE = 1000;
\r
53272 var initRootElStyle = function (el) {
\r
53273 el.style.cssText = 'position:absolute;left:0;top:0;width:1px;height:1px;';
\r
53274 el.coordsize = Z + ',' + Z;
\r
53275 el.coordorigin = '0,0';
\r
53278 var encodeHtmlAttribute = function (s) {
\r
53279 return String(s).replace(/&/g, '&').replace(/"/g, '"');
\r
53282 var rgb2Str = function (r, g, b) {
\r
53283 return 'rgb(' + [r, g, b].join(',') + ')';
\r
53286 var append = function (parent, child) {
\r
53287 if (child && parent && child.parentNode !== parent) {
\r
53288 parent.appendChild(child);
\r
53292 var remove = function (parent, child) {
\r
53293 if (child && parent && child.parentNode === parent) {
\r
53294 parent.removeChild(child);
\r
53298 var getZIndex = function (zlevel, z, z2) {
\r
53299 // z 的取值范围为 [0, 1000]
\r
53300 return (parseFloat(zlevel) || 0) * ZLEVEL_BASE + (parseFloat(z) || 0) * Z_BASE + z2;
\r
53303 var parsePercent = function (value, maxValue) {
\r
53304 if (typeof value === 'string') {
\r
53305 if (value.lastIndexOf('%') >= 0) {
\r
53306 return parseFloat(value) / 100 * maxValue;
\r
53308 return parseFloat(value);
\r
53313 /***************************************************
\r
53315 **************************************************/
\r
53317 var setColorAndOpacity = function (el, color, opacity) {
\r
53318 var colorArr = colorTool.parse(color);
\r
53319 opacity = +opacity;
\r
53320 if (isNaN(opacity)) {
\r
53324 el.color = rgb2Str(colorArr[0], colorArr[1], colorArr[2]);
\r
53325 el.opacity = opacity * colorArr[3];
\r
53329 var getColorAndAlpha = function (color) {
\r
53330 var colorArr = colorTool.parse(color);
\r
53332 rgb2Str(colorArr[0], colorArr[1], colorArr[2]),
\r
53337 var updateFillNode = function (el, style, zrEl) {
\r
53339 var fill = style.fill;
\r
53340 if (fill != null) {
\r
53341 // Modified from excanvas
\r
53342 if (fill instanceof Gradient) {
\r
53343 var gradientType;
\r
53345 var focus = [0, 0];
\r
53346 // additional offset
\r
53348 // scale factor for offset
\r
53349 var expansion = 1;
\r
53350 var rect = zrEl.getBoundingRect();
\r
53351 var rectWidth = rect.width;
\r
53352 var rectHeight = rect.height;
\r
53353 if (fill.type === 'linear') {
\r
53354 gradientType = 'gradient';
\r
53355 var transform = zrEl.transform;
\r
53356 var p0 = [fill.x * rectWidth, fill.y * rectHeight];
\r
53357 var p1 = [fill.x2 * rectWidth, fill.y2 * rectHeight];
\r
53359 applyTransform(p0, p0, transform);
\r
53360 applyTransform(p1, p1, transform);
\r
53362 var dx = p1[0] - p0[0];
\r
53363 var dy = p1[1] - p0[1];
\r
53364 angle = Math.atan2(dx, dy) * 180 / Math.PI;
\r
53365 // The angle should be a non-negative number.
\r
53370 // Very small angles produce an unexpected result because they are
\r
53371 // converted to a scientific notation string.
\r
53372 if (angle < 1e-6) {
\r
53377 gradientType = 'gradientradial';
\r
53378 var p0 = [fill.x * rectWidth, fill.y * rectHeight];
\r
53379 var transform = zrEl.transform;
\r
53380 var scale = zrEl.scale;
\r
53381 var width = rectWidth;
\r
53382 var height = rectHeight;
\r
53384 // Percent in bounding rect
\r
53385 (p0[0] - rect.x) / width,
\r
53386 (p0[1] - rect.y) / height
\r
53389 applyTransform(p0, p0, transform);
\r
53392 width /= scale[0] * Z;
\r
53393 height /= scale[1] * Z;
\r
53394 var dimension = mathMax(width, height);
\r
53395 shift = 2 * 0 / dimension;
\r
53396 expansion = 2 * fill.r / dimension - shift;
\r
53399 // We need to sort the color stops in ascending order by offset,
\r
53400 // otherwise IE won't interpret it correctly.
\r
53401 var stops = fill.colorStops.slice();
\r
53402 stops.sort(function(cs1, cs2) {
\r
53403 return cs1.offset - cs2.offset;
\r
53406 var length = stops.length;
\r
53407 // Color and alpha list of first and last stop
\r
53408 var colorAndAlphaList = [];
\r
53410 for (var i = 0; i < length; i++) {
\r
53411 var stop = stops[i];
\r
53412 var colorAndAlpha = getColorAndAlpha(stop.color);
\r
53413 colors.push(stop.offset * expansion + shift + ' ' + colorAndAlpha[0]);
\r
53414 if (i === 0 || i === length - 1) {
\r
53415 colorAndAlphaList.push(colorAndAlpha);
\r
53419 if (length >= 2) {
\r
53420 var color1 = colorAndAlphaList[0][0];
\r
53421 var color2 = colorAndAlphaList[1][0];
\r
53422 var opacity1 = colorAndAlphaList[0][1] * style.opacity;
\r
53423 var opacity2 = colorAndAlphaList[1][1] * style.opacity;
\r
53425 el.type = gradientType;
\r
53426 el.method = 'none';
\r
53427 el.focus = '100%';
\r
53428 el.angle = angle;
\r
53429 el.color = color1;
\r
53430 el.color2 = color2;
\r
53431 el.colors = colors.join(',');
\r
53432 // When colors attribute is used, the meanings of opacity and o:opacity2
\r
53434 el.opacity = opacity2;
\r
53435 // FIXME g_o_:opacity ?
\r
53436 el.opacity2 = opacity1;
\r
53438 if (gradientType === 'radial') {
\r
53439 el.focusposition = focus.join(',');
\r
53443 // FIXME Change from Gradient fill to color fill
\r
53444 setColorAndOpacity(el, fill, style.opacity);
\r
53449 var updateStrokeNode = function (el, style) {
\r
53450 if (style.lineJoin != null) {
\r
53451 el.joinstyle = style.lineJoin;
\r
53453 if (style.miterLimit != null) {
\r
53454 el.miterlimit = style.miterLimit * Z;
\r
53456 if (style.lineCap != null) {
\r
53457 el.endcap = style.lineCap;
\r
53459 if (style.lineDash != null) {
\r
53460 el.dashstyle = style.lineDash.join(' ');
\r
53462 if (style.stroke != null && !(style.stroke instanceof Gradient)) {
\r
53463 setColorAndOpacity(el, style.stroke, style.opacity);
\r
53467 var updateFillAndStroke = function (vmlEl, type, style, zrEl) {
\r
53468 var isFill = type == 'fill';
\r
53469 var el = vmlEl.getElementsByTagName(type)[0];
\r
53470 // Stroke must have lineWidth
\r
53471 if (style[type] != null && style[type] !== 'none' && (isFill || (!isFill && style.lineWidth))) {
\r
53472 vmlEl[isFill ? 'filled' : 'stroked'] = 'true';
\r
53473 // FIXME Remove before updating, or set `colors` will throw error
\r
53474 if (style[type] instanceof Gradient) {
\r
53475 remove(vmlEl, el);
\r
53478 el = vmlCore.createNode(type);
\r
53481 isFill ? updateFillNode(el, style, zrEl) : updateStrokeNode(el, style);
\r
53482 append(vmlEl, el);
\r
53485 vmlEl[isFill ? 'filled' : 'stroked'] = 'false';
\r
53486 remove(vmlEl, el);
\r
53490 var points = [[], [], []];
\r
53491 var pathDataToString = function (data, m) {
\r
53505 for (i = 0; i < data.length;) {
\r
53515 points[0][0] = xi;
\r
53516 points[0][1] = yi;
\r
53523 points[0][0] = xi;
\r
53524 points[0][1] = yi;
\r
53530 var x1 = data[i++];
\r
53531 var y1 = data[i++];
\r
53532 var x2 = data[i++];
\r
53533 var y2 = data[i++];
\r
53537 // Convert quadratic to cubic using degree elevation
\r
53540 x2 = (x2 + 2 * x1) / 3;
\r
53541 y2 = (y2 + 2 * y1) / 3;
\r
53542 x1 = (xi + 2 * x1) / 3;
\r
53543 y1 = (yi + 2 * y1) / 3;
\r
53549 points[0][0] = x1;
\r
53550 points[0][1] = y1;
\r
53551 points[1][0] = x2;
\r
53552 points[1][1] = y2;
\r
53553 points[2][0] = x3;
\r
53554 points[2][1] = y3;
\r
53566 // Extract SRT from matrix
\r
53569 sx = sqrt(m[0] * m[0] + m[1] * m[1]);
\r
53570 sy = sqrt(m[2] * m[2] + m[3] * m[3]);
\r
53571 angle = Math.atan2(-m[1] / sy, m[0] / sx);
\r
53574 var cx = data[i++];
\r
53575 var cy = data[i++];
\r
53576 var rx = data[i++];
\r
53577 var ry = data[i++];
\r
53578 var startAngle = data[i++] + angle;
\r
53579 var endAngle = data[i++] + startAngle + angle;
\r
53581 // var psi = data[i++];
\r
53583 var clockwise = data[i++];
\r
53585 var x0 = cx + cos(startAngle) * rx;
\r
53586 var y0 = cy + sin(startAngle) * ry;
\r
53588 var x1 = cx + cos(endAngle) * rx;
\r
53589 var y1 = cy + sin(endAngle) * ry;
\r
53591 var type = clockwise ? ' wa ' : ' at ';
\r
53595 round(((cx - rx) * sx + x) * Z - Z2), comma,
\r
53596 round(((cy - ry) * sy + y) * Z - Z2), comma,
\r
53597 round(((cx + rx) * sx + x) * Z - Z2), comma,
\r
53598 round(((cy + ry) * sy + y) * Z - Z2), comma,
\r
53599 round((x0 * sx + x) * Z - Z2), comma,
\r
53600 round((y0 * sy + y) * Z - Z2), comma,
\r
53601 round((x1 * sx + x) * Z - Z2), comma,
\r
53602 round((y1 * sy + y) * Z - Z2)
\r
53609 var p0 = points[0];
\r
53610 var p1 = points[1];
\r
53612 p0[0] = data[i++];
\r
53613 p0[1] = data[i++];
\r
53615 p1[0] = p0[0] + data[i++];
\r
53616 p1[1] = p0[1] + data[i++];
\r
53619 applyTransform(p0, p0, m);
\r
53620 applyTransform(p1, p1, m);
\r
53623 p0[0] = round(p0[0] * Z - Z2);
\r
53624 p1[0] = round(p1[0] * Z - Z2);
\r
53625 p0[1] = round(p0[1] * Z - Z2);
\r
53626 p1[1] = round(p1[1] * Z - Z2);
\r
53629 ' m ', p0[0], comma, p0[1],
\r
53631 ' l ', p1[0], comma, p0[1],
\r
53633 ' l ', p1[0], comma, p1[1],
\r
53635 ' l ', p0[0], comma, p1[1]
\r
53639 // FIXME Update xi, yi
\r
53643 if (nPoint > 0) {
\r
53644 str.push(cmdStr);
\r
53645 for (var k = 0; k < nPoint; k++) {
\r
53646 var p = points[k];
\r
53648 m && applyTransform(p, p, m);
\r
53651 round(p[0] * Z - Z2), comma, round(p[1] * Z - Z2),
\r
53652 k < nPoint - 1 ? comma : ''
\r
53657 return str.join('');
\r
53660 // Rewrite the original path method
\r
53661 Path.prototype.brushVML = function (vmlRoot) {
\r
53662 var style = this.style;
\r
53664 var vmlEl = this._vmlEl;
\r
53666 vmlEl = vmlCore.createNode('shape');
\r
53667 initRootElStyle(vmlEl);
\r
53669 this._vmlEl = vmlEl;
\r
53672 updateFillAndStroke(vmlEl, 'fill', style, this);
\r
53673 updateFillAndStroke(vmlEl, 'stroke', style, this);
\r
53675 var m = this.transform;
\r
53676 var needTransform = m != null;
\r
53677 var strokeEl = vmlEl.getElementsByTagName('stroke')[0];
\r
53679 var lineWidth = style.lineWidth;
\r
53680 // Get the line scale.
\r
53681 // Determinant of this.m_ means how much the area is enlarged by the
\r
53682 // transformation. So its square root can be used as a scale factor
\r
53684 if (needTransform && !style.strokeNoScale) {
\r
53685 var det = m[0] * m[3] - m[1] * m[2];
\r
53686 lineWidth *= sqrt(abs(det));
\r
53688 strokeEl.weight = lineWidth + 'px';
\r
53691 var path = this.path;
\r
53692 if (this.__dirtyPath) {
\r
53693 path.beginPath();
\r
53694 this.buildPath(path, this.shape);
\r
53695 this.__dirtyPath = false;
\r
53698 vmlEl.path = pathDataToString(path.data, this.transform);
\r
53700 vmlEl.style.zIndex = getZIndex(this.zlevel, this.z, this.z2);
\r
53702 // Append to root
\r
53703 append(vmlRoot, vmlEl);
\r
53706 if (style.text) {
\r
53707 this.drawRectText(vmlRoot, this.getBoundingRect());
\r
53711 Path.prototype.onRemove = function (vmlRoot) {
\r
53712 remove(vmlRoot, this._vmlEl);
\r
53713 this.removeRectText(vmlRoot);
\r
53716 Path.prototype.onAdd = function (vmlRoot) {
\r
53717 append(vmlRoot, this._vmlEl);
\r
53718 this.appendRectText(vmlRoot);
\r
53721 /***************************************************
\r
53723 **************************************************/
\r
53724 var isImage = function (img) {
\r
53725 // FIXME img instanceof Image 如果 img 是一个字符串的时候,IE8 下会报错
\r
53726 return (typeof img === 'object') && img.tagName && img.tagName.toUpperCase() === 'IMG';
\r
53727 // return img instanceof Image;
\r
53730 // Rewrite the original path method
\r
53731 ZImage.prototype.brushVML = function (vmlRoot) {
\r
53732 var style = this.style;
\r
53733 var image = style.image;
\r
53735 // Image original width, height
\r
53739 if (isImage(image)) {
\r
53740 var src = image.src;
\r
53741 if (src === this._imageSrc) {
\r
53742 ow = this._imageWidth;
\r
53743 oh = this._imageHeight;
\r
53746 var imageRuntimeStyle = image.runtimeStyle;
\r
53747 var oldRuntimeWidth = imageRuntimeStyle.width;
\r
53748 var oldRuntimeHeight = imageRuntimeStyle.height;
\r
53749 imageRuntimeStyle.width = 'auto';
\r
53750 imageRuntimeStyle.height = 'auto';
\r
53752 // get the original size
\r
53753 ow = image.width;
\r
53754 oh = image.height;
\r
53756 // and remove overides
\r
53757 imageRuntimeStyle.width = oldRuntimeWidth;
\r
53758 imageRuntimeStyle.height = oldRuntimeHeight;
\r
53760 // Caching image original width, height and src
\r
53761 this._imageSrc = src;
\r
53762 this._imageWidth = ow;
\r
53763 this._imageHeight = oh;
\r
53768 if (image === this._imageSrc) {
\r
53769 ow = this._imageWidth;
\r
53770 oh = this._imageHeight;
\r
53777 var x = style.x || 0;
\r
53778 var y = style.y || 0;
\r
53780 var dw = style.width;
\r
53781 var dh = style.height;
\r
53783 var sw = style.sWidth;
\r
53784 var sh = style.sHeight;
\r
53785 var sx = style.sx || 0;
\r
53786 var sy = style.sy || 0;
\r
53788 var hasCrop = sw && sh;
\r
53790 var vmlEl = this._vmlEl;
\r
53792 // FIXME 使用 group 在 left, top 都不是 0 的时候就无法显示了。
\r
53793 // vmlEl = vmlCore.createNode('group');
\r
53794 vmlEl = vmlCore.doc.createElement('div');
\r
53795 initRootElStyle(vmlEl);
\r
53797 this._vmlEl = vmlEl;
\r
53800 var vmlElStyle = vmlEl.style;
\r
53801 var hasRotation = false;
\r
53805 if (this.transform) {
\r
53806 m = this.transform;
\r
53807 scaleX = sqrt(m[0] * m[0] + m[1] * m[1]);
\r
53808 scaleY = sqrt(m[2] * m[2] + m[3] * m[3]);
\r
53810 hasRotation = m[1] || m[2];
\r
53812 if (hasRotation) {
\r
53813 // If filters are necessary (rotation exists), create them
\r
53814 // filters are bog-slow, so only create them if abbsolutely necessary
\r
53815 // The following check doesn't account for skews (which don't exist
\r
53816 // in the canvas spec (yet) anyway.
\r
53819 var p1 = [x + dw, y];
\r
53820 var p2 = [x, y + dh];
\r
53821 var p3 = [x + dw, y + dh];
\r
53822 applyTransform(p0, p0, m);
\r
53823 applyTransform(p1, p1, m);
\r
53824 applyTransform(p2, p2, m);
\r
53825 applyTransform(p3, p3, m);
\r
53827 var maxX = mathMax(p0[0], p1[0], p2[0], p3[0]);
\r
53828 var maxY = mathMax(p0[1], p1[1], p2[1], p3[1]);
\r
53830 var transformFilter = [];
\r
53831 transformFilter.push('M11=', m[0] / scaleX, comma,
\r
53832 'M12=', m[2] / scaleY, comma,
\r
53833 'M21=', m[1] / scaleX, comma,
\r
53834 'M22=', m[3] / scaleY, comma,
\r
53835 'Dx=', round(x * scaleX + m[4]), comma,
\r
53836 'Dy=', round(y * scaleY + m[5]));
\r
53838 vmlElStyle.padding = '0 ' + round(maxX) + 'px ' + round(maxY) + 'px 0';
\r
53839 // FIXME DXImageTransform 在 IE11 的兼容模式下不起作用
\r
53840 vmlElStyle.filter = imageTransformPrefix + '.Matrix('
\r
53841 + transformFilter.join('') + ', SizingMethod=clip)';
\r
53846 x = x * scaleX + m[4];
\r
53847 y = y * scaleY + m[5];
\r
53849 vmlElStyle.filter = '';
\r
53850 vmlElStyle.left = round(x) + 'px';
\r
53851 vmlElStyle.top = round(y) + 'px';
\r
53854 var imageEl = this._imageEl;
\r
53855 var cropEl = this._cropEl;
\r
53858 imageEl = vmlCore.doc.createElement('div');
\r
53859 this._imageEl = imageEl;
\r
53861 var imageELStyle = imageEl.style;
\r
53863 // Needs know image original width and height
\r
53864 if (! (ow && oh)) {
\r
53865 var tmpImage = new Image();
\r
53867 tmpImage.onload = function () {
\r
53868 tmpImage.onload = null;
\r
53869 ow = tmpImage.width;
\r
53870 oh = tmpImage.height;
\r
53871 // Adjust image width and height to fit the ratio destinationSize / sourceSize
\r
53872 imageELStyle.width = round(scaleX * ow * dw / sw) + 'px';
\r
53873 imageELStyle.height = round(scaleY * oh * dh / sh) + 'px';
\r
53875 // Caching image original width, height and src
\r
53876 self._imageWidth = ow;
\r
53877 self._imageHeight = oh;
\r
53878 self._imageSrc = image;
\r
53880 tmpImage.src = image;
\r
53883 imageELStyle.width = round(scaleX * ow * dw / sw) + 'px';
\r
53884 imageELStyle.height = round(scaleY * oh * dh / sh) + 'px';
\r
53888 cropEl = vmlCore.doc.createElement('div');
\r
53889 cropEl.style.overflow = 'hidden';
\r
53890 this._cropEl = cropEl;
\r
53892 var cropElStyle = cropEl.style;
\r
53893 cropElStyle.width = round((dw + sx * dw / sw) * scaleX);
\r
53894 cropElStyle.height = round((dh + sy * dh / sh) * scaleY);
\r
53895 cropElStyle.filter = imageTransformPrefix + '.Matrix(Dx='
\r
53896 + (-sx * dw / sw * scaleX) + ',Dy=' + (-sy * dh / sh * scaleY) + ')';
\r
53898 if (! cropEl.parentNode) {
\r
53899 vmlEl.appendChild(cropEl);
\r
53901 if (imageEl.parentNode != cropEl) {
\r
53902 cropEl.appendChild(imageEl);
\r
53906 imageELStyle.width = round(scaleX * dw) + 'px';
\r
53907 imageELStyle.height = round(scaleY * dh) + 'px';
\r
53909 vmlEl.appendChild(imageEl);
\r
53911 if (cropEl && cropEl.parentNode) {
\r
53912 vmlEl.removeChild(cropEl);
\r
53913 this._cropEl = null;
\r
53917 var filterStr = '';
\r
53918 var alpha = style.opacity;
\r
53920 filterStr += '.Alpha(opacity=' + round(alpha * 100) + ') ';
\r
53922 filterStr += imageTransformPrefix + '.AlphaImageLoader(src=' + image + ', SizingMethod=scale)';
\r
53924 imageELStyle.filter = filterStr;
\r
53926 vmlEl.style.zIndex = getZIndex(this.zlevel, this.z, this.z2);
\r
53928 // Append to root
\r
53929 append(vmlRoot, vmlEl);
\r
53932 if (style.text) {
\r
53933 this.drawRectText(vmlRoot, this.getBoundingRect());
\r
53937 ZImage.prototype.onRemove = function (vmlRoot) {
\r
53938 remove(vmlRoot, this._vmlEl);
\r
53940 this._vmlEl = null;
\r
53941 this._cropEl = null;
\r
53942 this._imageEl = null;
\r
53944 this.removeRectText(vmlRoot);
\r
53947 ZImage.prototype.onAdd = function (vmlRoot) {
\r
53948 append(vmlRoot, this._vmlEl);
\r
53949 this.appendRectText(vmlRoot);
\r
53953 /***************************************************
\r
53955 **************************************************/
\r
53957 var DEFAULT_STYLE_NORMAL = 'normal';
\r
53959 var fontStyleCache = {};
\r
53960 var fontStyleCacheCount = 0;
\r
53961 var MAX_FONT_CACHE_SIZE = 100;
\r
53962 var fontEl = document.createElement('div');
\r
53964 var getFontStyle = function (fontString) {
\r
53965 var fontStyle = fontStyleCache[fontString];
\r
53966 if (!fontStyle) {
\r
53968 if (fontStyleCacheCount > MAX_FONT_CACHE_SIZE) {
\r
53969 fontStyleCacheCount = 0;
\r
53970 fontStyleCache = {};
\r
53973 var style = fontEl.style;
\r
53976 style.font = fontString;
\r
53977 fontFamily = style.fontFamily.split(',')[0];
\r
53983 style: style.fontStyle || DEFAULT_STYLE_NORMAL,
\r
53984 variant: style.fontVariant || DEFAULT_STYLE_NORMAL,
\r
53985 weight: style.fontWeight || DEFAULT_STYLE_NORMAL,
\r
53986 size: parseFloat(style.fontSize || 12) | 0,
\r
53987 family: fontFamily || 'Microsoft YaHei'
\r
53990 fontStyleCache[fontString] = fontStyle;
\r
53991 fontStyleCacheCount++;
\r
53993 return fontStyle;
\r
53996 var textMeasureEl;
\r
53997 // Overwrite measure text method
\r
53998 textContain.measureText = function (text, textFont) {
\r
53999 var doc = vmlCore.doc;
\r
54000 if (!textMeasureEl) {
\r
54001 textMeasureEl = doc.createElement('div');
\r
54002 textMeasureEl.style.cssText = 'position:absolute;top:-20000px;left:0;'
\r
54003 + 'padding:0;margin:0;border:none;white-space:pre;';
\r
54004 vmlCore.doc.body.appendChild(textMeasureEl);
\r
54008 textMeasureEl.style.font = textFont;
\r
54010 // Ignore failures to set to invalid font.
\r
54012 textMeasureEl.innerHTML = '';
\r
54013 // Don't use innerHTML or innerText because they allow markup/whitespace.
\r
54014 textMeasureEl.appendChild(doc.createTextNode(text));
\r
54016 width: textMeasureEl.offsetWidth
\r
54020 var tmpRect = new BoundingRect();
\r
54022 var drawRectText = function (vmlRoot, rect, textRect, fromTextEl) {
\r
54024 var style = this.style;
\r
54025 var text = style.text;
\r
54032 var align = style.textAlign;
\r
54033 var fontStyle = getFontStyle(style.textFont);
\r
54034 // FIXME encodeHtmlAttribute ?
\r
54035 var font = fontStyle.style + ' ' + fontStyle.variant + ' ' + fontStyle.weight + ' '
\r
54036 + fontStyle.size + 'px "' + fontStyle.family + '"';
\r
54037 var baseline = style.textBaseline;
\r
54038 var verticalAlign = style.textVerticalAlign;
\r
54040 textRect = textRect || textContain.getBoundingRect(text, font, align, baseline);
\r
54042 // Transform rect to view space
\r
54043 var m = this.transform;
\r
54044 // Ignore transform for text in other element
\r
54045 if (m && !fromTextEl) {
\r
54046 tmpRect.copy(rect);
\r
54047 tmpRect.applyTransform(m);
\r
54051 if (!fromTextEl) {
\r
54052 var textPosition = style.textPosition;
\r
54053 var distance = style.textDistance;
\r
54054 // Text position represented by coord
\r
54055 if (textPosition instanceof Array) {
\r
54056 x = rect.x + parsePercent(textPosition[0], rect.width);
\r
54057 y = rect.y + parsePercent(textPosition[1], rect.height);
\r
54059 align = align || 'left';
\r
54060 baseline = baseline || 'top';
\r
54063 var res = textContain.adjustTextPositionOnRect(
\r
54064 textPosition, rect, textRect, distance
\r
54069 // Default align and baseline when has textPosition
\r
54070 align = align || res.textAlign;
\r
54071 baseline = baseline || res.textBaseline;
\r
54078 if (verticalAlign) {
\r
54079 switch (verticalAlign) {
\r
54081 y -= textRect.height / 2;
\r
54084 y -= textRect.height;
\r
54088 // Ignore baseline
\r
54089 baseline = 'top';
\r
54092 var fontSize = fontStyle.size;
\r
54093 // 1.75 is an arbitrary number, as there is no info about the text baseline
\r
54094 switch (baseline) {
\r
54097 y += fontSize / 1.75;
\r
54103 // case 'alphabetic':
\r
54104 // case 'ideographic':
\r
54105 // case 'bottom':
\r
54106 y -= fontSize / 2.25;
\r
54113 x -= textRect.width / 2;
\r
54116 x -= textRect.width;
\r
54119 // align = elementStyle.direction == 'ltr' ? 'right' : 'left';
\r
54122 // align = elementStyle.direction == 'rtl' ? 'right' : 'left';
\r
54125 // align = 'left';
\r
54128 var createNode = vmlCore.createNode;
\r
54130 var textVmlEl = this._textVmlEl;
\r
54134 if (!textVmlEl) {
\r
54135 textVmlEl = createNode('line');
\r
54136 pathEl = createNode('path');
\r
54137 textPathEl = createNode('textpath');
\r
54138 skewEl = createNode('skew');
\r
54140 // FIXME Why here is not cammel case
\r
54141 // Align 'center' seems wrong
\r
54142 textPathEl.style['v-text-align'] = 'left';
\r
54144 initRootElStyle(textVmlEl);
\r
54146 pathEl.textpathok = true;
\r
54147 textPathEl.on = true;
\r
54149 textVmlEl.from = '0 0';
\r
54150 textVmlEl.to = '1000 0.05';
\r
54152 append(textVmlEl, skewEl);
\r
54153 append(textVmlEl, pathEl);
\r
54154 append(textVmlEl, textPathEl);
\r
54156 this._textVmlEl = textVmlEl;
\r
54159 // 这里是在前面 appendChild 保证顺序的前提下
\r
54160 skewEl = textVmlEl.firstChild;
\r
54161 pathEl = skewEl.nextSibling;
\r
54162 textPathEl = pathEl.nextSibling;
\r
54165 var coords = [x, y];
\r
54166 var textVmlElStyle = textVmlEl.style;
\r
54167 // Ignore transform for text in other element
\r
54168 if (m && fromTextEl) {
\r
54169 applyTransform(coords, coords, m);
\r
54171 skewEl.on = true;
\r
54173 skewEl.matrix = m[0].toFixed(3) + comma + m[2].toFixed(3) + comma +
\r
54174 m[1].toFixed(3) + comma + m[3].toFixed(3) + ',0,0';
\r
54177 skewEl.offset = (round(coords[0]) || 0) + ',' + (round(coords[1]) || 0);
\r
54178 // Left top point as origin
\r
54179 skewEl.origin = '0 0';
\r
54181 textVmlElStyle.left = '0px';
\r
54182 textVmlElStyle.top = '0px';
\r
54185 skewEl.on = false;
\r
54186 textVmlElStyle.left = round(x) + 'px';
\r
54187 textVmlElStyle.top = round(y) + 'px';
\r
54190 textPathEl.string = encodeHtmlAttribute(text);
\r
54193 textPathEl.style.font = font;
\r
54195 // Error font format
\r
54198 updateFillAndStroke(textVmlEl, 'fill', {
\r
54199 fill: fromTextEl ? style.fill : style.textFill,
\r
54200 opacity: style.opacity
\r
54202 updateFillAndStroke(textVmlEl, 'stroke', {
\r
54203 stroke: fromTextEl ? style.stroke : style.textStroke,
\r
54204 opacity: style.opacity,
\r
54205 lineDash: style.lineDash
\r
54208 textVmlEl.style.zIndex = getZIndex(this.zlevel, this.z, this.z2);
\r
54210 // Attached to root
\r
54211 append(vmlRoot, textVmlEl);
\r
54214 var removeRectText = function (vmlRoot) {
\r
54215 remove(vmlRoot, this._textVmlEl);
\r
54216 this._textVmlEl = null;
\r
54219 var appendRectText = function (vmlRoot) {
\r
54220 append(vmlRoot, this._textVmlEl);
\r
54223 var list = [RectText, Displayable, ZImage, Path, Text];
\r
54225 // In case Displayable has been mixed in RectText
\r
54226 for (var i = 0; i < list.length; i++) {
\r
54227 var proto = list[i].prototype;
\r
54228 proto.drawRectText = drawRectText;
\r
54229 proto.removeRectText = removeRectText;
\r
54230 proto.appendRectText = appendRectText;
\r
54233 Text.prototype.brushVML = function (root) {
\r
54234 var style = this.style;
\r
54235 if (style.text) {
\r
54236 this.drawRectText(root, {
\r
54237 x: style.x || 0, y: style.y || 0,
\r
54238 width: 0, height: 0
\r
54239 }, this.getBoundingRect(), true);
\r
54243 Text.prototype.onRemove = function (vmlRoot) {
\r
54244 this.removeRectText(vmlRoot);
\r
54247 Text.prototype.onAdd = function (vmlRoot) {
\r
54248 this.appendRectText(vmlRoot);
\r
54255 /***/ function(module, exports, __webpack_require__) {
\r
54259 if (!__webpack_require__(78).canvasSupported) {
\r
54260 var urn = 'urn:schemas-microsoft-com:vml';
\r
54263 var win = window;
\r
54264 var doc = win.document;
\r
54266 var vmlInited = false;
\r
54269 !doc.namespaces.zrvml && doc.namespaces.add('zrvml', urn);
\r
54270 createNode = function (tagName) {
\r
54271 return doc.createElement('<zrvml:' + tagName + ' class="zrvml">');
\r
54275 createNode = function (tagName) {
\r
54276 return doc.createElement('<' + tagName + ' xmlns="' + urn + '" class="zrvml">');
\r
54281 var initVML = function () {
\r
54285 vmlInited = true;
\r
54287 var styleSheets = doc.styleSheets;
\r
54288 if (styleSheets.length < 31) {
\r
54289 doc.createStyleSheet().addRule('.zrvml', 'behavior:url(#default#VML)');
\r
54292 // http://msdn.microsoft.com/en-us/library/ms531194%28VS.85%29.aspx
\r
54293 styleSheets[0].addRule('.zrvml', 'behavior:url(#default#VML)');
\r
54297 // Not useing return to avoid error when converting to CommonJS module
\r
54298 module.exports = {
\r
54300 initVML: initVML,
\r
54301 createNode: createNode
\r
54308 /***/ function(module, exports, __webpack_require__) {
\r
54313 * @module zrender/vml/Painter
\r
54318 var zrLog = __webpack_require__(39);
\r
54319 var vmlCore = __webpack_require__(347);
\r
54321 function parseInt10(val) {
\r
54322 return parseInt(val, 10);
\r
54326 * @alias module:zrender/vml/Painter
\r
54328 function VMLPainter(root, storage) {
\r
54330 vmlCore.initVML();
\r
54332 this.root = root;
\r
54334 this.storage = storage;
\r
54336 var vmlViewport = document.createElement('div');
\r
54338 var vmlRoot = document.createElement('div');
\r
54340 vmlViewport.style.cssText = 'display:inline-block;overflow:hidden;position:relative;width:300px;height:150px;';
\r
54342 vmlRoot.style.cssText = 'position:absolute;left:0;top:0;';
\r
54344 root.appendChild(vmlViewport);
\r
54346 this._vmlRoot = vmlRoot;
\r
54347 this._vmlViewport = vmlViewport;
\r
54351 // Modify storage
\r
54352 var oldDelFromMap = storage.delFromMap;
\r
54353 var oldAddToMap = storage.addToMap;
\r
54354 storage.delFromMap = function (elId) {
\r
54355 var el = storage.get(elId);
\r
54357 oldDelFromMap.call(storage, elId);
\r
54360 el.onRemove && el.onRemove(vmlRoot);
\r
54364 storage.addToMap = function (el) {
\r
54365 // Displayable already has a vml node
\r
54366 el.onAdd && el.onAdd(vmlRoot);
\r
54368 oldAddToMap.call(storage, el);
\r
54371 this._firstPaint = true;
\r
54374 VMLPainter.prototype = {
\r
54376 constructor: VMLPainter,
\r
54379 * @return {HTMLDivElement}
\r
54381 getViewportRoot: function () {
\r
54382 return this._vmlViewport;
\r
54388 refresh: function () {
\r
54390 var list = this.storage.getDisplayList(true, true);
\r
54392 this._paintList(list);
\r
54395 _paintList: function (list) {
\r
54396 var vmlRoot = this._vmlRoot;
\r
54397 for (var i = 0; i < list.length; i++) {
\r
54398 var el = list[i];
\r
54399 if (el.invisible || el.ignore) {
\r
54400 if (!el.__alreadyNotVisible) {
\r
54401 el.onRemove(vmlRoot);
\r
54403 // Set as already invisible
\r
54404 el.__alreadyNotVisible = true;
\r
54407 if (el.__alreadyNotVisible) {
\r
54408 el.onAdd(vmlRoot);
\r
54410 el.__alreadyNotVisible = false;
\r
54411 if (el.__dirty) {
\r
54412 el.beforeBrush && el.beforeBrush();
\r
54413 (el.brushVML || el.brush).call(el, vmlRoot);
\r
54414 el.afterBrush && el.afterBrush();
\r
54417 el.__dirty = false;
\r
54420 if (this._firstPaint) {
\r
54421 // Detached from document at first time
\r
54422 // to avoid page refreshing too many times
\r
54424 // FIXME 如果每次都先 removeChild 可能会导致一些填充和描边的效果改变
\r
54425 this._vmlViewport.appendChild(vmlRoot);
\r
54426 this._firstPaint = false;
\r
54430 resize: function () {
\r
54431 var width = this._getWidth();
\r
54432 var height = this._getHeight();
\r
54434 if (this._width != width && this._height != height) {
\r
54435 this._width = width;
\r
54436 this._height = height;
\r
54438 var vmlViewportStyle = this._vmlViewport.style;
\r
54439 vmlViewportStyle.width = width + 'px';
\r
54440 vmlViewportStyle.height = height + 'px';
\r
54444 dispose: function () {
\r
54445 this.root.innerHTML = '';
\r
54448 this._vmlViewport =
\r
54449 this.storage = null;
\r
54452 getWidth: function () {
\r
54453 return this._width;
\r
54456 getHeight: function () {
\r
54457 return this._height;
\r
54460 _getWidth: function () {
\r
54461 var root = this.root;
\r
54462 var stl = root.currentStyle;
\r
54464 return ((root.clientWidth || parseInt10(stl.width))
\r
54465 - parseInt10(stl.paddingLeft)
\r
54466 - parseInt10(stl.paddingRight)) | 0;
\r
54469 _getHeight: function () {
\r
54470 var root = this.root;
\r
54471 var stl = root.currentStyle;
\r
54473 return ((root.clientHeight || parseInt10(stl.height))
\r
54474 - parseInt10(stl.paddingTop)
\r
54475 - parseInt10(stl.paddingBottom)) | 0;
\r
54479 // Not supported methods
\r
54480 function createMethodNotSupport(method) {
\r
54481 return function () {
\r
54482 zrLog('In IE8.0 VML mode painter not support method "' + method + '"');
\r
54486 var notSupportedMethods = [
\r
54487 'getLayer', 'insertLayer', 'eachLayer', 'eachBuildinLayer', 'eachOtherLayer', 'getLayers',
\r
54488 'modLayer', 'delLayer', 'clearLayer', 'toDataURL', 'pathToImage'
\r
54491 for (var i = 0; i < notSupportedMethods.length; i++) {
\r
54492 var name = notSupportedMethods[i];
\r
54493 VMLPainter.prototype[name] = createMethodNotSupport(name);
\r
54496 module.exports = VMLPainter;
\r