(function webpackUniversalModuleDefinition(root, factory) { if(typeof exports === 'object' && typeof module === 'object') module.exports = factory(); else if(typeof define === 'function' && define.amd) define([], factory); else if(typeof exports === 'object') exports["echarts"] = factory(); else root["echarts"] = factory(); })(this, function() { return /******/ (function(modules) { // webpackBootstrap /******/ // The module cache /******/ var installedModules = {}; /******/ // The require function /******/ function __webpack_require__(moduleId) { /******/ // Check if module is in cache /******/ if(installedModules[moduleId]) /******/ return installedModules[moduleId].exports; /******/ // Create a new module (and put it into the cache) /******/ var module = installedModules[moduleId] = { /******/ exports: {}, /******/ id: moduleId, /******/ loaded: false /******/ }; /******/ // Execute the module function /******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); /******/ // Flag the module as loaded /******/ module.loaded = true; /******/ // Return the exports of the module /******/ return module.exports; /******/ } /******/ // expose the modules object (__webpack_modules__) /******/ __webpack_require__.m = modules; /******/ // expose the module cache /******/ __webpack_require__.c = installedModules; /******/ // __webpack_public_path__ /******/ __webpack_require__.p = ""; /******/ // Load entry module and return exports /******/ return __webpack_require__(0); /******/ }) /************************************************************************/ /******/ ([ /* 0 */ /***/ function(module, exports, __webpack_require__) { /** * Export echarts as CommonJS module */ module.exports = __webpack_require__(1); // Import all charts and components __webpack_require__(100); __webpack_require__(135); __webpack_require__(140); __webpack_require__(149); __webpack_require__(153); __webpack_require__(163); __webpack_require__(184); __webpack_require__(196); __webpack_require__(217); __webpack_require__(221); __webpack_require__(225); __webpack_require__(240); __webpack_require__(246); __webpack_require__(253); __webpack_require__(259); __webpack_require__(263); __webpack_require__(271); __webpack_require__(275); __webpack_require__(113); __webpack_require__(276); __webpack_require__(282); __webpack_require__(286); __webpack_require__(297); __webpack_require__(226); __webpack_require__(300); __webpack_require__(306); __webpack_require__(317); __webpack_require__(318); __webpack_require__(332); __webpack_require__(347); __webpack_require__(353); __webpack_require__(356); __webpack_require__(359); __webpack_require__(368); __webpack_require__(381); /***/ }, /* 1 */ /***/ function(module, exports, __webpack_require__) { // Enable DEV mode when using source code without build. which has no __DEV__ variable // In build process 'typeof __DEV__' will be replace with 'boolean' // So this code will be removed or disabled anyway after built. if (false) { // In browser if (typeof window !== 'undefined') { window.__DEV__ = true; } // In node else if (typeof global !== 'undefined') { global.__DEV__ = true; } } /*! * ECharts, a javascript interactive chart library. * * Copyright (c) 2015, Baidu Inc. * All rights reserved. * * LICENSE * https://github.com/ecomfe/echarts/blob/master/LICENSE.txt */ /** * @module echarts */ var env = __webpack_require__(2); var GlobalModel = __webpack_require__(3); var ExtensionAPI = __webpack_require__(25); var CoordinateSystemManager = __webpack_require__(26); var OptionManager = __webpack_require__(27); var ComponentModel = __webpack_require__(19); var SeriesModel = __webpack_require__(28); var ComponentView = __webpack_require__(29); var ChartView = __webpack_require__(42); var graphic = __webpack_require__(43); var modelUtil = __webpack_require__(5); var throttle = __webpack_require__(81); var zrender = __webpack_require__(82); var zrUtil = __webpack_require__(4); var colorTool = __webpack_require__(39); var Eventful = __webpack_require__(33); var timsort = __webpack_require__(86); var each = zrUtil.each; var PRIORITY_PROCESSOR_FILTER = 1000; var PRIORITY_PROCESSOR_STATISTIC = 5000; var PRIORITY_VISUAL_LAYOUT = 1000; var PRIORITY_VISUAL_GLOBAL = 2000; var PRIORITY_VISUAL_CHART = 3000; var PRIORITY_VISUAL_COMPONENT = 4000; var PRIORITY_VISUAL_BRUSH = 5000; // Main process have three entries: `setOption`, `dispatchAction` and `resize`, // where they must not be invoked nestedly, except the only case: invoke // dispatchAction with updateMethod "none" in main process. // This flag is used to carry out this rule. // All events will be triggered out side main process (i.e. when !this[IN_MAIN_PROCESS]). var IN_MAIN_PROCESS = '__flagInMainProcess'; var HAS_GRADIENT_OR_PATTERN_BG = '__hasGradientOrPatternBg'; var OPTION_UPDATED = '__optionUpdated'; function createRegisterEventWithLowercaseName(method) { return function (eventName, handler, context) { // Event name is all lowercase eventName = eventName && eventName.toLowerCase(); Eventful.prototype[method].call(this, eventName, handler, context); }; } /** * @module echarts~MessageCenter */ function MessageCenter() { Eventful.call(this); } MessageCenter.prototype.on = createRegisterEventWithLowercaseName('on'); MessageCenter.prototype.off = createRegisterEventWithLowercaseName('off'); MessageCenter.prototype.one = createRegisterEventWithLowercaseName('one'); zrUtil.mixin(MessageCenter, Eventful); /** * @module echarts~ECharts */ function ECharts (dom, theme, opts) { opts = opts || {}; // Get theme by name if (typeof theme === 'string') { theme = themeStorage[theme]; } /** * @type {string} */ this.id; /** * Group id * @type {string} */ this.group; /** * @type {HTMLDomElement} * @private */ this._dom = dom; /** * @type {module:zrender/ZRender} * @private */ var zr = this._zr = zrender.init(dom, { renderer: opts.renderer || 'canvas', devicePixelRatio: opts.devicePixelRatio, width: opts.width, height: opts.height }); /** * Expect 60 pfs. * @type {Function} * @private */ this._throttledZrFlush = throttle.throttle(zrUtil.bind(zr.flush, zr), 17); /** * @type {Object} * @private */ this._theme = zrUtil.clone(theme); /** * @type {Array.} * @private */ this._chartsViews = []; /** * @type {Object.} * @private */ this._chartsMap = {}; /** * @type {Array.} * @private */ this._componentsViews = []; /** * @type {Object.} * @private */ this._componentsMap = {}; /** * @type {module:echarts/ExtensionAPI} * @private */ this._api = new ExtensionAPI(this); /** * @type {module:echarts/CoordinateSystem} * @private */ this._coordSysMgr = new CoordinateSystemManager(); Eventful.call(this); /** * @type {module:echarts~MessageCenter} * @private */ this._messageCenter = new MessageCenter(); // Init mouse events this._initEvents(); // In case some people write `window.onresize = chart.resize` this.resize = zrUtil.bind(this.resize, this); // Can't dispatch action during rendering procedure this._pendingActions = []; // Sort on demand function prioritySortFunc(a, b) { return a.prio - b.prio; } timsort(visualFuncs, prioritySortFunc); timsort(dataProcessorFuncs, prioritySortFunc); zr.animation.on('frame', this._onframe, this); } var echartsProto = ECharts.prototype; echartsProto._onframe = function () { // Lazy update if (this[OPTION_UPDATED]) { this[IN_MAIN_PROCESS] = true; updateMethods.prepareAndUpdate.call(this); this[IN_MAIN_PROCESS] = false; this[OPTION_UPDATED] = false; } }; /** * @return {HTMLDomElement} */ echartsProto.getDom = function () { return this._dom; }; /** * @return {module:zrender~ZRender} */ echartsProto.getZr = function () { return this._zr; }; /** * @param {Object} option * @param {boolean} notMerge * @param {boolean} [lazyUpdate=false] Useful when setOption frequently. */ echartsProto.setOption = function (option, notMerge, lazyUpdate) { if (true) { zrUtil.assert(!this[IN_MAIN_PROCESS], '`setOption` should not be called during main process.'); } this[IN_MAIN_PROCESS] = true; if (!this._model || notMerge) { var optionManager = new OptionManager(this._api); var theme = this._theme; var ecModel = this._model = new GlobalModel(null, null, theme, optionManager); ecModel.init(null, null, theme, optionManager); } // FIXME // ugly this.__lastOnlyGraphic = !!(option && option.graphic); zrUtil.each(option, function (o, mainType) { mainType !== 'graphic' && (this.__lastOnlyGraphic = false); }, this); this._model.setOption(option, optionPreprocessorFuncs); if (lazyUpdate) { this[OPTION_UPDATED] = true; } else { updateMethods.prepareAndUpdate.call(this); // Ensure zr refresh sychronously, and then pixel in canvas can be // fetched after `setOption`. this._zr.flush(); this[OPTION_UPDATED] = false; } this[IN_MAIN_PROCESS] = false; flushPendingActions.call(this, false); }; /** * @DEPRECATED */ echartsProto.setTheme = function () { console.log('ECharts#setTheme() is DEPRECATED in ECharts 3.0'); }; /** * @return {module:echarts/model/Global} */ echartsProto.getModel = function () { return this._model; }; /** * @return {Object} */ echartsProto.getOption = function () { return this._model && this._model.getOption(); }; /** * @return {number} */ echartsProto.getWidth = function () { return this._zr.getWidth(); }; /** * @return {number} */ echartsProto.getHeight = function () { return this._zr.getHeight(); }; /** * Get canvas which has all thing rendered * @param {Object} opts * @param {string} [opts.backgroundColor] */ echartsProto.getRenderedCanvas = function (opts) { if (!env.canvasSupported) { return; } opts = opts || {}; opts.pixelRatio = opts.pixelRatio || 1; opts.backgroundColor = opts.backgroundColor || this._model.get('backgroundColor'); var zr = this._zr; var list = zr.storage.getDisplayList(); // Stop animations zrUtil.each(list, function (el) { el.stopAnimation(true); }); return zr.painter.getRenderedCanvas(opts); }; /** * @return {string} * @param {Object} opts * @param {string} [opts.type='png'] * @param {string} [opts.pixelRatio=1] * @param {string} [opts.backgroundColor] * @param {string} [opts.excludeComponents] */ echartsProto.getDataURL = function (opts) { opts = opts || {}; var excludeComponents = opts.excludeComponents; var ecModel = this._model; var excludesComponentViews = []; var self = this; each(excludeComponents, function (componentType) { ecModel.eachComponent({ mainType: componentType }, function (component) { var view = self._componentsMap[component.__viewId]; if (!view.group.ignore) { excludesComponentViews.push(view); view.group.ignore = true; } }); }); var url = this.getRenderedCanvas(opts).toDataURL( 'image/' + (opts && opts.type || 'png') ); each(excludesComponentViews, function (view) { view.group.ignore = false; }); return url; }; /** * @return {string} * @param {Object} opts * @param {string} [opts.type='png'] * @param {string} [opts.pixelRatio=1] * @param {string} [opts.backgroundColor] */ echartsProto.getConnectedDataURL = function (opts) { if (!env.canvasSupported) { return; } var groupId = this.group; var mathMin = Math.min; var mathMax = Math.max; var MAX_NUMBER = Infinity; if (connectedGroups[groupId]) { var left = MAX_NUMBER; var top = MAX_NUMBER; var right = -MAX_NUMBER; var bottom = -MAX_NUMBER; var canvasList = []; var dpr = (opts && opts.pixelRatio) || 1; zrUtil.each(instances, function (chart, id) { if (chart.group === groupId) { var canvas = chart.getRenderedCanvas( zrUtil.clone(opts) ); var boundingRect = chart.getDom().getBoundingClientRect(); left = mathMin(boundingRect.left, left); top = mathMin(boundingRect.top, top); right = mathMax(boundingRect.right, right); bottom = mathMax(boundingRect.bottom, bottom); canvasList.push({ dom: canvas, left: boundingRect.left, top: boundingRect.top }); } }); left *= dpr; top *= dpr; right *= dpr; bottom *= dpr; var width = right - left; var height = bottom - top; var targetCanvas = zrUtil.createCanvas(); targetCanvas.width = width; targetCanvas.height = height; var zr = zrender.init(targetCanvas); each(canvasList, function (item) { var img = new graphic.Image({ style: { x: item.left * dpr - left, y: item.top * dpr - top, image: item.dom } }); zr.add(img); }); zr.refreshImmediately(); return targetCanvas.toDataURL('image/' + (opts && opts.type || 'png')); } else { return this.getDataURL(opts); } }; /** * Convert from logical coordinate system to pixel coordinate system. * See CoordinateSystem#convertToPixel. * @param {string|Object} finder * If string, e.g., 'geo', means {geoIndex: 0}. * If Object, could contain some of these properties below: * { * seriesIndex / seriesId / seriesName, * geoIndex / geoId, geoName, * bmapIndex / bmapId / bmapName, * xAxisIndex / xAxisId / xAxisName, * yAxisIndex / yAxisId / yAxisName, * gridIndex / gridId / gridName, * ... (can be extended) * } * @param {Array|number} value * @return {Array|number} result */ echartsProto.convertToPixel = zrUtil.curry(doConvertPixel, 'convertToPixel'); /** * Convert from pixel coordinate system to logical coordinate system. * See CoordinateSystem#convertFromPixel. * @param {string|Object} finder * If string, e.g., 'geo', means {geoIndex: 0}. * If Object, could contain some of these properties below: * { * seriesIndex / seriesId / seriesName, * geoIndex / geoId / geoName, * bmapIndex / bmapId / bmapName, * xAxisIndex / xAxisId / xAxisName, * yAxisIndex / yAxisId / yAxisName * gridIndex / gridId / gridName, * ... (can be extended) * } * @param {Array|number} value * @return {Array|number} result */ echartsProto.convertFromPixel = zrUtil.curry(doConvertPixel, 'convertFromPixel'); function doConvertPixel(methodName, finder, value) { var ecModel = this._model; var coordSysList = this._coordSysMgr.getCoordinateSystems(); var result; finder = modelUtil.parseFinder(ecModel, finder); for (var i = 0; i < coordSysList.length; i++) { var coordSys = coordSysList[i]; if (coordSys[methodName] && (result = coordSys[methodName](ecModel, finder, value)) != null ) { return result; } } if (true) { console.warn( 'No coordinate system that supports ' + methodName + ' found by the given finder.' ); } } /** * Is the specified coordinate systems or components contain the given pixel point. * @param {string|Object} finder * If string, e.g., 'geo', means {geoIndex: 0}. * If Object, could contain some of these properties below: * { * seriesIndex / seriesId / seriesName, * geoIndex / geoId / geoName, * bmapIndex / bmapId / bmapName, * xAxisIndex / xAxisId / xAxisName, * yAxisIndex / yAxisId / yAxisName * gridIndex / gridId / gridName, * ... (can be extended) * } * @param {Array|number} value * @return {boolean} result */ echartsProto.containPixel = function (finder, value) { var ecModel = this._model; var result; finder = modelUtil.parseFinder(ecModel, finder); zrUtil.each(finder, function (models, key) { key.indexOf('Models') >= 0 && zrUtil.each(models, function (model) { var coordSys = model.coordinateSystem; if (coordSys && coordSys.containPoint) { result |= !!coordSys.containPoint(value); } else if (key === 'seriesModels') { var view = this._chartsMap[model.__viewId]; if (view && view.containPoint) { result |= view.containPoint(value, model); } else { if (true) { console.warn(key + ': ' + (view ? 'The found component do not support containPoint.' : 'No view mapping to the found component.' )); } } } else { if (true) { console.warn(key + ': containPoint is not supported'); } } }, this); }, this); return !!result; }; /** * Get visual from series or data. * @param {string|Object} finder * If string, e.g., 'series', means {seriesIndex: 0}. * If Object, could contain some of these properties below: * { * seriesIndex / seriesId / seriesName, * dataIndex / dataIndexInside * } * If dataIndex is not specified, series visual will be fetched, * but not data item visual. * If all of seriesIndex, seriesId, seriesName are not specified, * visual will be fetched from first series. * @param {string} visualType 'color', 'symbol', 'symbolSize' */ echartsProto.getVisual = function (finder, visualType) { var ecModel = this._model; finder = modelUtil.parseFinder(ecModel, finder, {defaultMainType: 'series'}); var seriesModel = finder.seriesModel; if (true) { if (!seriesModel) { console.warn('There is no specified seires model'); } } var data = seriesModel.getData(); var dataIndexInside = finder.hasOwnProperty('dataIndexInside') ? finder.dataIndexInside : finder.hasOwnProperty('dataIndex') ? data.indexOfRawIndex(finder.dataIndex) : null; return dataIndexInside != null ? data.getItemVisual(dataIndexInside, visualType) : data.getVisual(visualType); }; var updateMethods = { /** * @param {Object} payload * @private */ update: function (payload) { // console.time && console.time('update'); var ecModel = this._model; var api = this._api; var coordSysMgr = this._coordSysMgr; var zr = this._zr; // update before setOption if (!ecModel) { return; } // Fixme First time update ? ecModel.restoreData(); // TODO // Save total ecModel here for undo/redo (after restoring data and before processing data). // Undo (restoration of total ecModel) can be carried out in 'action' or outside API call. // Create new coordinate system each update // In LineView may save the old coordinate system and use it to get the orignal point coordSysMgr.create(this._model, this._api); processData.call(this, ecModel, api); stackSeriesData.call(this, ecModel); coordSysMgr.update(ecModel, api); doVisualEncoding.call(this, ecModel, payload); doRender.call(this, ecModel, payload); // Set background var backgroundColor = ecModel.get('backgroundColor') || 'transparent'; var painter = zr.painter; // TODO all use clearColor ? if (painter.isSingleCanvas && painter.isSingleCanvas()) { zr.configLayer(0, { clearColor: backgroundColor }); } else { // In IE8 if (!env.canvasSupported) { var colorArr = colorTool.parse(backgroundColor); backgroundColor = colorTool.stringify(colorArr, 'rgb'); if (colorArr[3] === 0) { backgroundColor = 'transparent'; } } if (backgroundColor.colorStops || backgroundColor.image) { // Gradient background // FIXME Fixed layer? zr.configLayer(0, { clearColor: backgroundColor }); this[HAS_GRADIENT_OR_PATTERN_BG] = true; this._dom.style.background = 'transparent'; } else { if (this[HAS_GRADIENT_OR_PATTERN_BG]) { zr.configLayer(0, { clearColor: null }); } this[HAS_GRADIENT_OR_PATTERN_BG] = false; this._dom.style.background = backgroundColor; } } // console.time && console.timeEnd('update'); }, // PENDING /** * @param {Object} payload * @private */ updateView: function (payload) { var ecModel = this._model; // update before setOption if (!ecModel) { return; } ecModel.eachSeries(function (seriesModel) { seriesModel.getData().clearAllVisual(); }); doVisualEncoding.call(this, ecModel, payload); invokeUpdateMethod.call(this, 'updateView', ecModel, payload); }, /** * @param {Object} payload * @private */ updateVisual: function (payload) { var ecModel = this._model; // update before setOption if (!ecModel) { return; } ecModel.eachSeries(function (seriesModel) { seriesModel.getData().clearAllVisual(); }); doVisualEncoding.call(this, ecModel, payload); invokeUpdateMethod.call(this, 'updateVisual', ecModel, payload); }, /** * @param {Object} payload * @private */ updateLayout: function (payload) { var ecModel = this._model; // update before setOption if (!ecModel) { return; } doLayout.call(this, ecModel, payload); invokeUpdateMethod.call(this, 'updateLayout', ecModel, payload); }, /** * @param {Object} payload * @private */ highlight: function (payload) { toggleHighlight.call(this, 'highlight', payload); }, /** * @param {Object} payload * @private */ downplay: function (payload) { toggleHighlight.call(this, 'downplay', payload); }, /** * @param {Object} payload * @private */ prepareAndUpdate: function (payload) { var ecModel = this._model; prepareView.call(this, 'component', ecModel); prepareView.call(this, 'chart', ecModel); // FIXME // ugly if (this.__lastOnlyGraphic) { each(this._componentsViews, function (componentView) { var componentModel = componentView.__model; if (componentModel && componentModel.mainType === 'graphic') { componentView.render(componentModel, ecModel, this._api, payload); updateZ(componentModel, componentView); } }, this); this.__lastOnlyGraphic = false; } else { updateMethods.update.call(this, payload); } } }; /** * @param {Object} payload * @private */ function toggleHighlight(method, payload) { var ecModel = this._model; // dispatchAction before setOption if (!ecModel) { return; } ecModel.eachComponent( {mainType: 'series', query: payload}, function (seriesModel, index) { var chartView = this._chartsMap[seriesModel.__viewId]; if (chartView && chartView.__alive) { chartView[method]( seriesModel, ecModel, this._api, payload ); } }, this ); } /** * Resize the chart * @param {Object} opts * @param {number} [opts.width] Can be 'auto' (the same as null/undefined) * @param {number} [opts.height] Can be 'auto' (the same as null/undefined) */ echartsProto.resize = function (opts) { if (true) { zrUtil.assert(!this[IN_MAIN_PROCESS], '`resize` should not be called during main process.'); } this[IN_MAIN_PROCESS] = true; this._zr.resize(opts); var optionChanged = this._model && this._model.resetOption('media'); updateMethods[optionChanged ? 'prepareAndUpdate' : 'update'].call(this); // Resize loading effect this._loadingFX && this._loadingFX.resize(); this[IN_MAIN_PROCESS] = false; flushPendingActions.call(this); }; /** * Show loading effect * @param {string} [name='default'] * @param {Object} [cfg] */ echartsProto.showLoading = function (name, cfg) { if (zrUtil.isObject(name)) { cfg = name; name = ''; } name = name || 'default'; this.hideLoading(); if (!loadingEffects[name]) { if (true) { console.warn('Loading effects ' + name + ' not exists.'); } return; } var el = loadingEffects[name](this._api, cfg); var zr = this._zr; this._loadingFX = el; zr.add(el); }; /** * Hide loading effect */ echartsProto.hideLoading = function () { this._loadingFX && this._zr.remove(this._loadingFX); this._loadingFX = null; }; /** * @param {Object} eventObj * @return {Object} */ echartsProto.makeActionFromEvent = function (eventObj) { var payload = zrUtil.extend({}, eventObj); payload.type = eventActionMap[eventObj.type]; return payload; }; /** * @pubilc * @param {Object} payload * @param {string} [payload.type] Action type * @param {Object|boolean} [opt] If pass boolean, means opt.silent * @param {boolean} [opt.silent=false] Whether trigger events. * @param {boolean} [opt.flush=undefined] * true: Flush immediately, and then pixel in canvas can be fetched * immediately. Caution: it might affect performance. * false: Not not flush. * undefined: Auto decide whether perform flush. */ echartsProto.dispatchAction = function (payload, opt) { if (!zrUtil.isObject(opt)) { opt = {silent: !!opt}; } if (!actions[payload.type]) { return; } // if (__DEV__) { // zrUtil.assert( // !this[IN_MAIN_PROCESS], // '`dispatchAction` should not be called during main process.' // + 'unless updateMathod is "none".' // ); // } // May dispatchAction in rendering procedure if (this[IN_MAIN_PROCESS]) { this._pendingActions.push(payload); return; } doDispatchAction.call(this, payload, opt.silent); if (opt.flush) { this._zr.flush(true); } else if (opt.flush !== false && env.browser.weChat) { // In WeChat embeded browser, `requestAnimationFrame` and `setInterval` // hang when sliding page (on touch event), which cause that zr does not // refresh util user interaction finished, which is not expected. // But `dispatchAction` may be called too frequently when pan on touch // screen, which impacts performance if do not throttle them. this._throttledZrFlush(); } flushPendingActions.call(this, opt.silent); }; function doDispatchAction(payload, silent) { var actionWrap = actions[payload.type]; var actionInfo = actionWrap.actionInfo; var updateMethod = actionInfo.update || 'update'; this[IN_MAIN_PROCESS] = true; var payloads = [payload]; var batched = false; // Batch action if (payload.batch) { batched = true; payloads = zrUtil.map(payload.batch, function (item) { item = zrUtil.defaults(zrUtil.extend({}, item), payload); item.batch = null; return item; }); } var eventObjBatch = []; var eventObj; var isHighlightOrDownplay = payload.type === 'highlight' || payload.type === 'downplay'; for (var i = 0; i < payloads.length; i++) { var batchItem = payloads[i]; // Action can specify the event by return it. eventObj = actionWrap.action(batchItem, this._model); // Emit event outside eventObj = eventObj || zrUtil.extend({}, batchItem); // Convert type to eventType eventObj.type = actionInfo.event || eventObj.type; eventObjBatch.push(eventObj); // Highlight and downplay are special. isHighlightOrDownplay && updateMethods[updateMethod].call(this, batchItem); } if (updateMethod !== 'none' && !isHighlightOrDownplay) { // Still dirty if (this[OPTION_UPDATED]) { // FIXME Pass payload ? updateMethods.prepareAndUpdate.call(this, payload); this[OPTION_UPDATED] = false; } else { updateMethods[updateMethod].call(this, payload); } } // Follow the rule of action batch if (batched) { eventObj = { type: actionInfo.event || payload.type, batch: eventObjBatch }; } else { eventObj = eventObjBatch[0]; } this[IN_MAIN_PROCESS] = false; !silent && this._messageCenter.trigger(eventObj.type, eventObj); } function flushPendingActions(silent) { var pendingActions = this._pendingActions; while (pendingActions.length) { var payload = pendingActions.shift(); doDispatchAction.call(this, payload, silent); } } /** * Register event * @method */ echartsProto.on = createRegisterEventWithLowercaseName('on'); echartsProto.off = createRegisterEventWithLowercaseName('off'); echartsProto.one = createRegisterEventWithLowercaseName('one'); /** * @param {string} methodName * @private */ function invokeUpdateMethod(methodName, ecModel, payload) { var api = this._api; // Update all components each(this._componentsViews, function (component) { var componentModel = component.__model; component[methodName](componentModel, ecModel, api, payload); updateZ(componentModel, component); }, this); // Upate all charts ecModel.eachSeries(function (seriesModel, idx) { var chart = this._chartsMap[seriesModel.__viewId]; chart[methodName](seriesModel, ecModel, api, payload); updateZ(seriesModel, chart); updateProgressiveAndBlend(seriesModel, chart); }, this); // If use hover layer updateHoverLayerStatus(this._zr, ecModel); } /** * Prepare view instances of charts and components * @param {module:echarts/model/Global} ecModel * @private */ function prepareView(type, ecModel) { var isComponent = type === 'component'; var viewList = isComponent ? this._componentsViews : this._chartsViews; var viewMap = isComponent ? this._componentsMap : this._chartsMap; var zr = this._zr; for (var i = 0; i < viewList.length; i++) { viewList[i].__alive = false; } ecModel[isComponent ? 'eachComponent' : 'eachSeries'](function (componentType, model) { if (isComponent) { if (componentType === 'series') { return; } } else { model = componentType; } // Consider: id same and type changed. var viewId = model.id + '_' + model.type; var view = viewMap[viewId]; if (!view) { var classType = ComponentModel.parseClassType(model.type); var Clazz = isComponent ? ComponentView.getClass(classType.main, classType.sub) : ChartView.getClass(classType.sub); if (Clazz) { view = new Clazz(); view.init(ecModel, this._api); viewMap[viewId] = view; viewList.push(view); zr.add(view.group); } else { // Error return; } } model.__viewId = viewId; view.__alive = true; view.__id = viewId; view.__model = model; }, this); for (var i = 0; i < viewList.length;) { var view = viewList[i]; if (!view.__alive) { zr.remove(view.group); view.dispose(ecModel, this._api); viewList.splice(i, 1); delete viewMap[view.__id]; } else { i++; } } } /** * Processor data in each series * * @param {module:echarts/model/Global} ecModel * @private */ function processData(ecModel, api) { each(dataProcessorFuncs, function (process) { process.func(ecModel, api); }); } /** * @private */ function stackSeriesData(ecModel) { var stackedDataMap = {}; ecModel.eachSeries(function (series) { var stack = series.get('stack'); var data = series.getData(); if (stack && data.type === 'list') { var previousStack = stackedDataMap[stack]; if (previousStack) { data.stackedOn = previousStack; } stackedDataMap[stack] = data; } }); } /** * Layout before each chart render there series, special visual encoding stage * * @param {module:echarts/model/Global} ecModel * @private */ function doLayout(ecModel, payload) { var api = this._api; each(visualFuncs, function (visual) { if (visual.isLayout) { visual.func(ecModel, api, payload); } }); } /** * Encode visual infomation from data after data processing * * @param {module:echarts/model/Global} ecModel * @private */ function doVisualEncoding(ecModel, payload) { var api = this._api; ecModel.clearColorPalette(); ecModel.eachSeries(function (seriesModel) { seriesModel.clearColorPalette(); }); each(visualFuncs, function (visual) { visual.func(ecModel, api, payload); }); } /** * Render each chart and component * @private */ function doRender(ecModel, payload) { var api = this._api; // Render all components each(this._componentsViews, function (componentView) { var componentModel = componentView.__model; componentView.render(componentModel, ecModel, api, payload); updateZ(componentModel, componentView); }, this); each(this._chartsViews, function (chart) { chart.__alive = false; }, this); // Render all charts ecModel.eachSeries(function (seriesModel, idx) { var chartView = this._chartsMap[seriesModel.__viewId]; chartView.__alive = true; chartView.render(seriesModel, ecModel, api, payload); chartView.group.silent = !!seriesModel.get('silent'); updateZ(seriesModel, chartView); updateProgressiveAndBlend(seriesModel, chartView); }, this); // If use hover layer updateHoverLayerStatus(this._zr, ecModel); // Remove groups of unrendered charts each(this._chartsViews, function (chart) { if (!chart.__alive) { chart.remove(ecModel, api); } }, this); } var MOUSE_EVENT_NAMES = [ 'click', 'dblclick', 'mouseover', 'mouseout', 'mousemove', 'mousedown', 'mouseup', 'globalout', 'contextmenu' ]; /** * @private */ echartsProto._initEvents = function () { each(MOUSE_EVENT_NAMES, function (eveName) { this._zr.on(eveName, function (e) { var ecModel = this.getModel(); var el = e.target; var params; // no e.target when 'globalout'. if (eveName === 'globalout') { params = {}; } else if (el && el.dataIndex != null) { var dataModel = el.dataModel || ecModel.getSeriesByIndex(el.seriesIndex); params = dataModel && dataModel.getDataParams(el.dataIndex, el.dataType) || {}; } // If element has custom eventData of components else if (el && el.eventData) { params = zrUtil.extend({}, el.eventData); } if (params) { params.event = e; params.type = eveName; this.trigger(eveName, params); } }, this); }, this); each(eventActionMap, function (actionType, eventType) { this._messageCenter.on(eventType, function (event) { this.trigger(eventType, event); }, this); }, this); }; /** * @return {boolean} */ echartsProto.isDisposed = function () { return this._disposed; }; /** * Clear */ echartsProto.clear = function () { this.setOption({ series: [] }, true); }; /** * Dispose instance */ echartsProto.dispose = function () { if (this._disposed) { if (true) { console.warn('Instance ' + this.id + ' has been disposed'); } return; } this._disposed = true; var api = this._api; var ecModel = this._model; each(this._componentsViews, function (component) { component.dispose(ecModel, api); }); each(this._chartsViews, function (chart) { chart.dispose(ecModel, api); }); // Dispose after all views disposed this._zr.dispose(); delete instances[this.id]; }; zrUtil.mixin(ECharts, Eventful); function updateHoverLayerStatus(zr, ecModel) { var storage = zr.storage; var elCount = 0; storage.traverse(function (el) { if (!el.isGroup) { elCount++; } }); if (elCount > ecModel.get('hoverLayerThreshold') && !env.node) { storage.traverse(function (el) { if (!el.isGroup) { el.useHoverLayer = true; } }); } } /** * Update chart progressive and blend. * @param {module:echarts/model/Series|module:echarts/model/Component} model * @param {module:echarts/view/Component|module:echarts/view/Chart} view */ function updateProgressiveAndBlend(seriesModel, chartView) { // Progressive configuration var elCount = 0; chartView.group.traverse(function (el) { if (el.type !== 'group' && !el.ignore) { elCount++; } }); var frameDrawNum = +seriesModel.get('progressive'); var needProgressive = elCount > seriesModel.get('progressiveThreshold') && frameDrawNum && !env.node; if (needProgressive) { chartView.group.traverse(function (el) { // FIXME marker and other components if (!el.isGroup) { el.progressive = needProgressive ? Math.floor(elCount++ / frameDrawNum) : -1; if (needProgressive) { el.stopAnimation(true); } } }); } // Blend configration var blendMode = seriesModel.get('blendMode') || null; if (true) { if (!env.canvasSupported && blendMode && blendMode !== 'source-over') { console.warn('Only canvas support blendMode'); } } chartView.group.traverse(function (el) { // FIXME marker and other components if (!el.isGroup) { el.setStyle('blend', blendMode); } }); } /** * @param {module:echarts/model/Series|module:echarts/model/Component} model * @param {module:echarts/view/Component|module:echarts/view/Chart} view */ function updateZ(model, view) { var z = model.get('z'); var zlevel = model.get('zlevel'); // Set z and zlevel view.group.traverse(function (el) { if (el.type !== 'group') { z != null && (el.z = z); zlevel != null && (el.zlevel = zlevel); } }); } /** * @type {Array.} * @inner */ var actions = []; /** * Map eventType to actionType * @type {Object} */ var eventActionMap = {}; /** * Data processor functions of each stage * @type {Array.>} * @inner */ var dataProcessorFuncs = []; /** * @type {Array.} * @inner */ var optionPreprocessorFuncs = []; /** * Visual encoding functions of each stage * @type {Array.>} * @inner */ var visualFuncs = []; /** * Theme storage * @type {Object.} */ var themeStorage = {}; /** * Loading effects */ var loadingEffects = {}; var instances = {}; var connectedGroups = {}; var idBase = new Date() - 0; var groupIdBase = new Date() - 0; var DOM_ATTRIBUTE_KEY = '_echarts_instance_'; /** * @alias module:echarts */ var echarts = { /** * @type {number} */ version: '3.3.2', dependencies: { zrender: '3.2.2' } }; function enableConnect(chart) { var STATUS_PENDING = 0; var STATUS_UPDATING = 1; var STATUS_UPDATED = 2; var STATUS_KEY = '__connectUpdateStatus'; function updateConnectedChartsStatus(charts, status) { for (var i = 0; i < charts.length; i++) { var otherChart = charts[i]; otherChart[STATUS_KEY] = status; } } zrUtil.each(eventActionMap, function (actionType, eventType) { chart._messageCenter.on(eventType, function (event) { if (connectedGroups[chart.group] && chart[STATUS_KEY] !== STATUS_PENDING) { var action = chart.makeActionFromEvent(event); var otherCharts = []; zrUtil.each(instances, function (otherChart) { if (otherChart !== chart && otherChart.group === chart.group) { otherCharts.push(otherChart); } }); updateConnectedChartsStatus(otherCharts, STATUS_PENDING); each(otherCharts, function (otherChart) { if (otherChart[STATUS_KEY] !== STATUS_UPDATING) { otherChart.dispatchAction(action); } }); updateConnectedChartsStatus(otherCharts, STATUS_UPDATED); } }); }); } /** * @param {HTMLDomElement} dom * @param {Object} [theme] * @param {Object} opts * @param {number} [opts.devicePixelRatio] Use window.devicePixelRatio by default * @param {string} [opts.renderer] Currently only 'canvas' is supported. * @param {number} [opts.width] Use clientWidth of the input `dom` by default. * Can be 'auto' (the same as null/undefined) * @param {number} [opts.height] Use clientHeight of the input `dom` by default. * Can be 'auto' (the same as null/undefined) */ echarts.init = function (dom, theme, opts) { if (true) { // Check version if ((zrender.version.replace('.', '') - 0) < (echarts.dependencies.zrender.replace('.', '') - 0)) { throw new Error( 'ZRender ' + zrender.version + ' is too old for ECharts ' + echarts.version + '. Current version need ZRender ' + echarts.dependencies.zrender + '+' ); } if (!dom) { throw new Error('Initialize failed: invalid dom.'); } if (zrUtil.isDom(dom) && dom.nodeName.toUpperCase() !== 'CANVAS' && (!dom.clientWidth || !dom.clientHeight)) { console.warn('Can\'t get dom width or height'); } } var chart = new ECharts(dom, theme, opts); chart.id = 'ec_' + idBase++; instances[chart.id] = chart; dom.setAttribute && dom.setAttribute(DOM_ATTRIBUTE_KEY, chart.id); enableConnect(chart); return chart; }; /** * @return {string|Array.} groupId */ echarts.connect = function (groupId) { // Is array of charts if (zrUtil.isArray(groupId)) { var charts = groupId; groupId = null; // If any chart has group zrUtil.each(charts, function (chart) { if (chart.group != null) { groupId = chart.group; } }); groupId = groupId || ('g_' + groupIdBase++); zrUtil.each(charts, function (chart) { chart.group = groupId; }); } connectedGroups[groupId] = true; return groupId; }; /** * @return {string} groupId */ echarts.disConnect = function (groupId) { connectedGroups[groupId] = false; }; /** * Dispose a chart instance * @param {module:echarts~ECharts|HTMLDomElement|string} chart */ echarts.dispose = function (chart) { if (zrUtil.isDom(chart)) { chart = echarts.getInstanceByDom(chart); } else if (typeof chart === 'string') { chart = instances[chart]; } if ((chart instanceof ECharts) && !chart.isDisposed()) { chart.dispose(); } }; /** * @param {HTMLDomElement} dom * @return {echarts~ECharts} */ echarts.getInstanceByDom = function (dom) { var key = dom.getAttribute(DOM_ATTRIBUTE_KEY); return instances[key]; }; /** * @param {string} key * @return {echarts~ECharts} */ echarts.getInstanceById = function (key) { return instances[key]; }; /** * Register theme */ echarts.registerTheme = function (name, theme) { themeStorage[name] = theme; }; /** * Register option preprocessor * @param {Function} preprocessorFunc */ echarts.registerPreprocessor = function (preprocessorFunc) { optionPreprocessorFuncs.push(preprocessorFunc); }; /** * @param {number} [priority=1000] * @param {Function} processorFunc */ echarts.registerProcessor = function (priority, processorFunc) { if (typeof priority === 'function') { processorFunc = priority; priority = PRIORITY_PROCESSOR_FILTER; } if (true) { if (isNaN(priority)) { throw new Error('Unkown processor priority'); } } dataProcessorFuncs.push({ prio: priority, func: processorFunc }); }; /** * Usage: * registerAction('someAction', 'someEvent', function () { ... }); * registerAction('someAction', function () { ... }); * registerAction( * {type: 'someAction', event: 'someEvent', update: 'updateView'}, * function () { ... } * ); * * @param {(string|Object)} actionInfo * @param {string} actionInfo.type * @param {string} [actionInfo.event] * @param {string} [actionInfo.update] * @param {string} [eventName] * @param {Function} action */ echarts.registerAction = function (actionInfo, eventName, action) { if (typeof eventName === 'function') { action = eventName; eventName = ''; } var actionType = zrUtil.isObject(actionInfo) ? actionInfo.type : ([actionInfo, actionInfo = { event: eventName }][0]); // Event name is all lowercase actionInfo.event = (actionInfo.event || actionType).toLowerCase(); eventName = actionInfo.event; if (!actions[actionType]) { actions[actionType] = {action: action, actionInfo: actionInfo}; } eventActionMap[eventName] = actionType; }; /** * @param {string} type * @param {*} CoordinateSystem */ echarts.registerCoordinateSystem = function (type, CoordinateSystem) { CoordinateSystemManager.register(type, CoordinateSystem); }; /** * Layout is a special stage of visual encoding * Most visual encoding like color are common for different chart * But each chart has it's own layout algorithm * * @param {number} [priority=1000] * @param {Function} layoutFunc */ echarts.registerLayout = function (priority, layoutFunc) { if (typeof priority === 'function') { layoutFunc = priority; priority = PRIORITY_VISUAL_LAYOUT; } if (true) { if (isNaN(priority)) { throw new Error('Unkown layout priority'); } } visualFuncs.push({ prio: priority, func: layoutFunc, isLayout: true }); }; /** * @param {number} [priority=3000] * @param {Function} visualFunc */ echarts.registerVisual = function (priority, visualFunc) { if (typeof priority === 'function') { visualFunc = priority; priority = PRIORITY_VISUAL_CHART; } if (true) { if (isNaN(priority)) { throw new Error('Unkown visual priority'); } } visualFuncs.push({ prio: priority, func: visualFunc }); }; /** * @param {string} name */ echarts.registerLoading = function (name, loadingFx) { loadingEffects[name] = loadingFx; }; var parseClassType = ComponentModel.parseClassType; /** * @param {Object} opts * @param {string} [superClass] */ echarts.extendComponentModel = function (opts, superClass) { var Clazz = ComponentModel; if (superClass) { var classType = parseClassType(superClass); Clazz = ComponentModel.getClass(classType.main, classType.sub, true); } return Clazz.extend(opts); }; /** * @param {Object} opts * @param {string} [superClass] */ echarts.extendComponentView = function (opts, superClass) { var Clazz = ComponentView; if (superClass) { var classType = parseClassType(superClass); Clazz = ComponentView.getClass(classType.main, classType.sub, true); } return Clazz.extend(opts); }; /** * @param {Object} opts * @param {string} [superClass] */ echarts.extendSeriesModel = function (opts, superClass) { var Clazz = SeriesModel; if (superClass) { superClass = 'series.' + superClass.replace('series.', ''); var classType = parseClassType(superClass); Clazz = ComponentModel.getClass(classType.main, classType.sub, true); } return Clazz.extend(opts); }; /** * @param {Object} opts * @param {string} [superClass] */ echarts.extendChartView = function (opts, superClass) { var Clazz = ChartView; if (superClass) { superClass.replace('series.', ''); var classType = parseClassType(superClass); Clazz = ChartView.getClass(classType.main, true); } return Clazz.extend(opts); }; /** * ZRender need a canvas context to do measureText. * But in node environment canvas may be created by node-canvas. * So we need to specify how to create a canvas instead of using document.createElement('canvas') * * Be careful of using it in the browser. * * @param {Function} creator * @example * var Canvas = require('canvas'); * var echarts = require('echarts'); * echarts.setCanvasCreator(function () { * // Small size is enough. * return new Canvas(32, 32); * }); */ echarts.setCanvasCreator = function (creator) { zrUtil.createCanvas = creator; }; echarts.registerVisual(PRIORITY_VISUAL_GLOBAL, __webpack_require__(94)); echarts.registerPreprocessor(__webpack_require__(95)); echarts.registerLoading('default', __webpack_require__(97)); // Default action echarts.registerAction({ type: 'highlight', event: 'highlight', update: 'highlight' }, zrUtil.noop); echarts.registerAction({ type: 'downplay', event: 'downplay', update: 'downplay' }, zrUtil.noop); // -------- // Exports // -------- // echarts.List = __webpack_require__(98); echarts.Model = __webpack_require__(12); echarts.graphic = __webpack_require__(43); echarts.number = __webpack_require__(7); echarts.format = __webpack_require__(6); echarts.matrix = __webpack_require__(11); echarts.vector = __webpack_require__(10); echarts.color = __webpack_require__(39); echarts.util = {}; each([ 'map', 'each', 'filter', 'indexOf', 'inherits', 'reduce', 'filter', 'bind', 'curry', 'isArray', 'isString', 'isObject', 'isFunction', 'extend', 'defaults', 'clone' ], function (name) { echarts.util[name] = zrUtil[name]; } ); // PRIORITY echarts.PRIORITY = { PROCESSOR: { FILTER: PRIORITY_PROCESSOR_FILTER, STATISTIC: PRIORITY_PROCESSOR_STATISTIC }, VISUAL: { LAYOUT: PRIORITY_VISUAL_LAYOUT, GLOBAL: PRIORITY_VISUAL_GLOBAL, CHART: PRIORITY_VISUAL_CHART, COMPONENT: PRIORITY_VISUAL_COMPONENT, BRUSH: PRIORITY_VISUAL_BRUSH } }; module.exports = echarts; /***/ }, /* 2 */ /***/ function(module, exports) { /** * echarts设备环境识别 * * @desc echarts基于Canvas,纯Javascript图表库,提供直观,生动,可交互,可个性化定制的数据统计图表。 * @author firede[firede@firede.us] * @desc thanks zepto. */ var env = {}; if (typeof navigator === 'undefined') { // In node env = { browser: {}, os: {}, node: true, // Assume canvas is supported canvasSupported: true }; } else { env = detect(navigator.userAgent); } module.exports = env; // Zepto.js // (c) 2010-2013 Thomas Fuchs // Zepto.js may be freely distributed under the MIT license. function detect(ua) { var os = {}; var browser = {}; // var webkit = ua.match(/Web[kK]it[\/]{0,1}([\d.]+)/); // var android = ua.match(/(Android);?[\s\/]+([\d.]+)?/); // var ipad = ua.match(/(iPad).*OS\s([\d_]+)/); // var ipod = ua.match(/(iPod)(.*OS\s([\d_]+))?/); // var iphone = !ipad && ua.match(/(iPhone\sOS)\s([\d_]+)/); // var webos = ua.match(/(webOS|hpwOS)[\s\/]([\d.]+)/); // var touchpad = webos && ua.match(/TouchPad/); // var kindle = ua.match(/Kindle\/([\d.]+)/); // var silk = ua.match(/Silk\/([\d._]+)/); // var blackberry = ua.match(/(BlackBerry).*Version\/([\d.]+)/); // var bb10 = ua.match(/(BB10).*Version\/([\d.]+)/); // var rimtabletos = ua.match(/(RIM\sTablet\sOS)\s([\d.]+)/); // var playbook = ua.match(/PlayBook/); // var chrome = ua.match(/Chrome\/([\d.]+)/) || ua.match(/CriOS\/([\d.]+)/); var firefox = ua.match(/Firefox\/([\d.]+)/); // var safari = webkit && ua.match(/Mobile\//) && !chrome; // var webview = ua.match(/(iPhone|iPod|iPad).*AppleWebKit(?!.*Safari)/) && !chrome; var ie = ua.match(/MSIE\s([\d.]+)/) // IE 11 Trident/7.0; rv:11.0 || ua.match(/Trident\/.+?rv:(([\d.]+))/); var edge = ua.match(/Edge\/([\d.]+)/); // IE 12 and 12+ var weChat = (/micromessenger/i).test(ua); // Todo: clean this up with a better OS/browser seperation: // - discern (more) between multiple browsers on android // - decide if kindle fire in silk mode is android or not // - Firefox on Android doesn't specify the Android version // - possibly devide in os, device and browser hashes // if (browser.webkit = !!webkit) browser.version = webkit[1]; // if (android) os.android = true, os.version = android[2]; // if (iphone && !ipod) os.ios = os.iphone = true, os.version = iphone[2].replace(/_/g, '.'); // if (ipad) os.ios = os.ipad = true, os.version = ipad[2].replace(/_/g, '.'); // if (ipod) os.ios = os.ipod = true, os.version = ipod[3] ? ipod[3].replace(/_/g, '.') : null; // if (webos) os.webos = true, os.version = webos[2]; // if (touchpad) os.touchpad = true; // if (blackberry) os.blackberry = true, os.version = blackberry[2]; // if (bb10) os.bb10 = true, os.version = bb10[2]; // if (rimtabletos) os.rimtabletos = true, os.version = rimtabletos[2]; // if (playbook) browser.playbook = true; // if (kindle) os.kindle = true, os.version = kindle[1]; // if (silk) browser.silk = true, browser.version = silk[1]; // if (!silk && os.android && ua.match(/Kindle Fire/)) browser.silk = true; // if (chrome) browser.chrome = true, browser.version = chrome[1]; if (firefox) { browser.firefox = true; browser.version = firefox[1]; } // if (safari && (ua.match(/Safari/) || !!os.ios)) browser.safari = true; // if (webview) browser.webview = true; if (ie) { browser.ie = true; browser.version = ie[1]; } if (edge) { browser.edge = true; browser.version = edge[1]; } // It is difficult to detect WeChat in Win Phone precisely, because ua can // not be set on win phone. So we do not consider Win Phone. if (weChat) { browser.weChat = true; } // os.tablet = !!(ipad || playbook || (android && !ua.match(/Mobile/)) || // (firefox && ua.match(/Tablet/)) || (ie && !ua.match(/Phone/) && ua.match(/Touch/))); // os.phone = !!(!os.tablet && !os.ipod && (android || iphone || webos || // (chrome && ua.match(/Android/)) || (chrome && ua.match(/CriOS\/([\d.]+)/)) || // (firefox && ua.match(/Mobile/)) || (ie && ua.match(/Touch/)))); return { browser: browser, os: os, node: false, // 原生canvas支持,改极端点了 // canvasSupported : !(browser.ie && parseFloat(browser.version) < 9) canvasSupported : document.createElement('canvas').getContext ? true : false, // @see // works on most browsers // IE10/11 does not support touch event, and MS Edge supports them but not by // default, so we dont check navigator.maxTouchPoints for them here. touchEventsSupported: 'ontouchstart' in window && !browser.ie && !browser.edge, // . pointerEventsSupported: 'onpointerdown' in window // Firefox supports pointer but not by default, // only MS browsers are reliable on pointer events currently. && (browser.edge || (browser.ie && browser.version >= 10)) }; } /***/ }, /* 3 */ /***/ function(module, exports, __webpack_require__) { /** * ECharts global model * * @module {echarts/model/Global} */ /** * Caution: If the mechanism should be changed some day, these cases * should be considered: * * (1) In `merge option` mode, if using the same option to call `setOption` * many times, the result should be the same (try our best to ensure that). * (2) In `merge option` mode, if a component has no id/name specified, it * will be merged by index, and the result sequence of the components is * consistent to the original sequence. * (3) `reset` feature (in toolbox). Find detailed info in comments about * `mergeOption` in module:echarts/model/OptionManager. */ var zrUtil = __webpack_require__(4); var modelUtil = __webpack_require__(5); var Model = __webpack_require__(12); var each = zrUtil.each; var filter = zrUtil.filter; var map = zrUtil.map; var isArray = zrUtil.isArray; var indexOf = zrUtil.indexOf; var isObject = zrUtil.isObject; var ComponentModel = __webpack_require__(19); var globalDefault = __webpack_require__(23); var OPTION_INNER_KEY = '\0_ec_inner'; /** * @alias module:echarts/model/Global * * @param {Object} option * @param {module:echarts/model/Model} parentModel * @param {Object} theme */ var GlobalModel = Model.extend({ constructor: GlobalModel, init: function (option, parentModel, theme, optionManager) { theme = theme || {}; this.option = null; // Mark as not initialized. /** * @type {module:echarts/model/Model} * @private */ this._theme = new Model(theme); /** * @type {module:echarts/model/OptionManager} */ this._optionManager = optionManager; }, setOption: function (option, optionPreprocessorFuncs) { zrUtil.assert( !(OPTION_INNER_KEY in option), 'please use chart.getOption()' ); this._optionManager.setOption(option, optionPreprocessorFuncs); this.resetOption(); }, /** * @param {string} type null/undefined: reset all. * 'recreate': force recreate all. * 'timeline': only reset timeline option * 'media': only reset media query option * @return {boolean} Whether option changed. */ resetOption: function (type) { var optionChanged = false; var optionManager = this._optionManager; if (!type || type === 'recreate') { var baseOption = optionManager.mountOption(type === 'recreate'); if (!this.option || type === 'recreate') { initBase.call(this, baseOption); } else { this.restoreData(); this.mergeOption(baseOption); } optionChanged = true; } if (type === 'timeline' || type === 'media') { this.restoreData(); } if (!type || type === 'recreate' || type === 'timeline') { var timelineOption = optionManager.getTimelineOption(this); timelineOption && (this.mergeOption(timelineOption), optionChanged = true); } if (!type || type === 'recreate' || type === 'media') { var mediaOptions = optionManager.getMediaOption(this, this._api); if (mediaOptions.length) { each(mediaOptions, function (mediaOption) { this.mergeOption(mediaOption, optionChanged = true); }, this); } } return optionChanged; }, /** * @protected */ mergeOption: function (newOption) { var option = this.option; var componentsMap = this._componentsMap; var newCptTypes = []; // 如果不存在对应的 component model 则直接 merge each(newOption, function (componentOption, mainType) { if (componentOption == null) { return; } if (!ComponentModel.hasClass(mainType)) { option[mainType] = option[mainType] == null ? zrUtil.clone(componentOption) : zrUtil.merge(option[mainType], componentOption, true); } else { newCptTypes.push(mainType); } }); // FIXME OPTION 同步是否要改回原来的 ComponentModel.topologicalTravel( newCptTypes, ComponentModel.getAllClassMainTypes(), visitComponent, this ); this._seriesIndices = this._seriesIndices || []; function visitComponent(mainType, dependencies) { var newCptOptionList = modelUtil.normalizeToArray(newOption[mainType]); var mapResult = modelUtil.mappingToExists( componentsMap[mainType], newCptOptionList ); modelUtil.makeIdAndName(mapResult); // Set mainType and complete subType. each(mapResult, function (item, index) { var opt = item.option; if (isObject(opt)) { item.keyInfo.mainType = mainType; item.keyInfo.subType = determineSubType(mainType, opt, item.exist); } }); var dependentModels = getComponentsByTypes( componentsMap, dependencies ); option[mainType] = []; componentsMap[mainType] = []; each(mapResult, function (resultItem, index) { var componentModel = resultItem.exist; var newCptOption = resultItem.option; zrUtil.assert( isObject(newCptOption) || componentModel, 'Empty component definition' ); // Consider where is no new option and should be merged using {}, // see removeEdgeAndAdd in topologicalTravel and // ComponentModel.getAllClassMainTypes. if (!newCptOption) { componentModel.mergeOption({}, this); componentModel.optionUpdated({}, false); } else { var ComponentModelClass = ComponentModel.getClass( mainType, resultItem.keyInfo.subType, true ); if (componentModel && componentModel instanceof ComponentModelClass) { componentModel.name = resultItem.keyInfo.name; componentModel.mergeOption(newCptOption, this); componentModel.optionUpdated(newCptOption, false); } else { // PENDING Global as parent ? var extraOpt = zrUtil.extend( { dependentModels: dependentModels, componentIndex: index }, resultItem.keyInfo ); componentModel = new ComponentModelClass( newCptOption, this, this, extraOpt ); zrUtil.extend(componentModel, extraOpt); componentModel.init(newCptOption, this, this, extraOpt); // Call optionUpdated after init. // newCptOption has been used as componentModel.option // and may be merged with theme and default, so pass null // to avoid confusion. componentModel.optionUpdated(null, true); } } componentsMap[mainType][index] = componentModel; option[mainType][index] = componentModel.option; }, this); // Backup series for filtering. if (mainType === 'series') { this._seriesIndices = createSeriesIndices(componentsMap.series); } } }, /** * Get option for output (cloned option and inner info removed) * @public * @return {Object} */ getOption: function () { var option = zrUtil.clone(this.option); each(option, function (opts, mainType) { if (ComponentModel.hasClass(mainType)) { var opts = modelUtil.normalizeToArray(opts); for (var i = opts.length - 1; i >= 0; i--) { // Remove options with inner id. if (modelUtil.isIdInner(opts[i])) { opts.splice(i, 1); } } option[mainType] = opts; } }); delete option[OPTION_INNER_KEY]; return option; }, /** * @return {module:echarts/model/Model} */ getTheme: function () { return this._theme; }, /** * @param {string} mainType * @param {number} [idx=0] * @return {module:echarts/model/Component} */ getComponent: function (mainType, idx) { var list = this._componentsMap[mainType]; if (list) { return list[idx || 0]; } }, /** * @param {Object} condition * @param {string} condition.mainType * @param {string} [condition.subType] If ignore, only query by mainType * @param {number|Array.} [condition.index] Either input index or id or name. * @param {string|Array.} [condition.id] Either input index or id or name. * @param {string|Array.} [condition.name] Either input index or id or name. * @return {Array.} */ queryComponents: function (condition) { var mainType = condition.mainType; if (!mainType) { return []; } var index = condition.index; var id = condition.id; var name = condition.name; var cpts = this._componentsMap[mainType]; if (!cpts || !cpts.length) { return []; } var result; if (index != null) { if (!isArray(index)) { index = [index]; } result = filter(map(index, function (idx) { return cpts[idx]; }), function (val) { return !!val; }); } else if (id != null) { var isIdArray = isArray(id); result = filter(cpts, function (cpt) { return (isIdArray && indexOf(id, cpt.id) >= 0) || (!isIdArray && cpt.id === id); }); } else if (name != null) { var isNameArray = isArray(name); result = filter(cpts, function (cpt) { return (isNameArray && indexOf(name, cpt.name) >= 0) || (!isNameArray && cpt.name === name); }); } else { // Return all components with mainType result = cpts; } return filterBySubType(result, condition); }, /** * The interface is different from queryComponents, * which is convenient for inner usage. * * @usage * var result = findComponents( * {mainType: 'dataZoom', query: {dataZoomId: 'abc'}} * ); * var result = findComponents( * {mainType: 'series', subType: 'pie', query: {seriesName: 'uio'}} * ); * var result = findComponents( * {mainType: 'series'}, * function (model, index) {...} * ); * // result like [component0, componnet1, ...] * * @param {Object} condition * @param {string} condition.mainType Mandatory. * @param {string} [condition.subType] Optional. * @param {Object} [condition.query] like {xxxIndex, xxxId, xxxName}, * where xxx is mainType. * If query attribute is null/undefined or has no index/id/name, * do not filtering by query conditions, which is convenient for * no-payload situations or when target of action is global. * @param {Function} [condition.filter] parameter: component, return boolean. * @return {Array.} */ findComponents: function (condition) { var query = condition.query; var mainType = condition.mainType; var queryCond = getQueryCond(query); var result = queryCond ? this.queryComponents(queryCond) : this._componentsMap[mainType]; return doFilter(filterBySubType(result, condition)); function getQueryCond(q) { var indexAttr = mainType + 'Index'; var idAttr = mainType + 'Id'; var nameAttr = mainType + 'Name'; return q && ( q.hasOwnProperty(indexAttr) || q.hasOwnProperty(idAttr) || q.hasOwnProperty(nameAttr) ) ? { mainType: mainType, // subType will be filtered finally. index: q[indexAttr], id: q[idAttr], name: q[nameAttr] } : null; } function doFilter(res) { return condition.filter ? filter(res, condition.filter) : res; } }, /** * @usage * eachComponent('legend', function (legendModel, index) { * ... * }); * eachComponent(function (componentType, model, index) { * // componentType does not include subType * // (componentType is 'xxx' but not 'xxx.aa') * }); * eachComponent( * {mainType: 'dataZoom', query: {dataZoomId: 'abc'}}, * function (model, index) {...} * ); * eachComponent( * {mainType: 'series', subType: 'pie', query: {seriesName: 'uio'}}, * function (model, index) {...} * ); * * @param {string|Object=} mainType When mainType is object, the definition * is the same as the method 'findComponents'. * @param {Function} cb * @param {*} context */ eachComponent: function (mainType, cb, context) { var componentsMap = this._componentsMap; if (typeof mainType === 'function') { context = cb; cb = mainType; each(componentsMap, function (components, componentType) { each(components, function (component, index) { cb.call(context, componentType, component, index); }); }); } else if (zrUtil.isString(mainType)) { each(componentsMap[mainType], cb, context); } else if (isObject(mainType)) { var queryResult = this.findComponents(mainType); each(queryResult, cb, context); } }, /** * @param {string} name * @return {Array.} */ getSeriesByName: function (name) { var series = this._componentsMap.series; return filter(series, function (oneSeries) { return oneSeries.name === name; }); }, /** * @param {number} seriesIndex * @return {module:echarts/model/Series} */ getSeriesByIndex: function (seriesIndex) { return this._componentsMap.series[seriesIndex]; }, /** * @param {string} subType * @return {Array.} */ getSeriesByType: function (subType) { var series = this._componentsMap.series; return filter(series, function (oneSeries) { return oneSeries.subType === subType; }); }, /** * @return {Array.} */ getSeries: function () { return this._componentsMap.series.slice(); }, /** * After filtering, series may be different * frome raw series. * * @param {Function} cb * @param {*} context */ eachSeries: function (cb, context) { assertSeriesInitialized(this); each(this._seriesIndices, function (rawSeriesIndex) { var series = this._componentsMap.series[rawSeriesIndex]; cb.call(context, series, rawSeriesIndex); }, this); }, /** * Iterate raw series before filtered. * * @param {Function} cb * @param {*} context */ eachRawSeries: function (cb, context) { each(this._componentsMap.series, cb, context); }, /** * After filtering, series may be different. * frome raw series. * * @parma {string} subType * @param {Function} cb * @param {*} context */ eachSeriesByType: function (subType, cb, context) { assertSeriesInitialized(this); each(this._seriesIndices, function (rawSeriesIndex) { var series = this._componentsMap.series[rawSeriesIndex]; if (series.subType === subType) { cb.call(context, series, rawSeriesIndex); } }, this); }, /** * Iterate raw series before filtered of given type. * * @parma {string} subType * @param {Function} cb * @param {*} context */ eachRawSeriesByType: function (subType, cb, context) { return each(this.getSeriesByType(subType), cb, context); }, /** * @param {module:echarts/model/Series} seriesModel */ isSeriesFiltered: function (seriesModel) { assertSeriesInitialized(this); return zrUtil.indexOf(this._seriesIndices, seriesModel.componentIndex) < 0; }, /** * @param {Function} cb * @param {*} context */ filterSeries: function (cb, context) { assertSeriesInitialized(this); var filteredSeries = filter( this._componentsMap.series, cb, context ); this._seriesIndices = createSeriesIndices(filteredSeries); }, restoreData: function () { var componentsMap = this._componentsMap; this._seriesIndices = createSeriesIndices(componentsMap.series); var componentTypes = []; each(componentsMap, function (components, componentType) { componentTypes.push(componentType); }); ComponentModel.topologicalTravel( componentTypes, ComponentModel.getAllClassMainTypes(), function (componentType, dependencies) { each(componentsMap[componentType], function (component) { component.restoreData(); }); } ); } }); /** * @inner */ function mergeTheme(option, theme) { zrUtil.each(theme, function (themeItem, name) { // 如果有 component model 则把具体的 merge 逻辑交给该 model 处理 if (!ComponentModel.hasClass(name)) { if (typeof themeItem === 'object') { option[name] = !option[name] ? zrUtil.clone(themeItem) : zrUtil.merge(option[name], themeItem, false); } else { if (option[name] == null) { option[name] = themeItem; } } } }); } function initBase(baseOption) { baseOption = baseOption; // Using OPTION_INNER_KEY to mark that this option can not be used outside, // i.e. `chart.setOption(chart.getModel().option);` is forbiden. this.option = {}; this.option[OPTION_INNER_KEY] = 1; /** * @type {Object.>} * @private */ this._componentsMap = {}; /** * Mapping between filtered series list and raw series list. * key: filtered series indices, value: raw series indices. * @type {Array.} * @private */ this._seriesIndices = null; mergeTheme(baseOption, this._theme.option); // TODO Needs clone when merging to the unexisted property zrUtil.merge(baseOption, globalDefault, false); this.mergeOption(baseOption); } /** * @inner * @param {Array.|string} types model types * @return {Object} key: {string} type, value: {Array.} models */ function getComponentsByTypes(componentsMap, types) { if (!zrUtil.isArray(types)) { types = types ? [types] : []; } var ret = {}; each(types, function (type) { ret[type] = (componentsMap[type] || []).slice(); }); return ret; } /** * @inner */ function determineSubType(mainType, newCptOption, existComponent) { var subType = newCptOption.type ? newCptOption.type : existComponent ? existComponent.subType // Use determineSubType only when there is no existComponent. : ComponentModel.determineSubType(mainType, newCptOption); // tooltip, markline, markpoint may always has no subType return subType; } /** * @inner */ function createSeriesIndices(seriesModels) { return map(seriesModels, function (series) { return series.componentIndex; }) || []; } /** * @inner */ function filterBySubType(components, condition) { // Using hasOwnProperty for restrict. Consider // subType is undefined in user payload. return condition.hasOwnProperty('subType') ? filter(components, function (cpt) { return cpt.subType === condition.subType; }) : components; } /** * @inner */ function assertSeriesInitialized(ecModel) { // Components that use _seriesIndices should depends on series component, // which make sure that their initialization is after series. if (true) { if (!ecModel._seriesIndices) { throw new Error('Series has not been initialized yet.'); } } } zrUtil.mixin(GlobalModel, __webpack_require__(24)); module.exports = GlobalModel; /***/ }, /* 4 */ /***/ function(module, exports) { /** * @module zrender/core/util */ // 用于处理merge时无法遍历Date等对象的问题 var BUILTIN_OBJECT = { '[object Function]': 1, '[object RegExp]': 1, '[object Date]': 1, '[object Error]': 1, '[object CanvasGradient]': 1, '[object CanvasPattern]': 1, // For node-canvas '[object Image]': 1, '[object Canvas]': 1 }; var TYPED_ARRAY = { '[object Int8Array]': 1, '[object Uint8Array]': 1, '[object Uint8ClampedArray]': 1, '[object Int16Array]': 1, '[object Uint16Array]': 1, '[object Int32Array]': 1, '[object Uint32Array]': 1, '[object Float32Array]': 1, '[object Float64Array]': 1 }; var objToString = Object.prototype.toString; var arrayProto = Array.prototype; var nativeForEach = arrayProto.forEach; var nativeFilter = arrayProto.filter; var nativeSlice = arrayProto.slice; var nativeMap = arrayProto.map; var nativeReduce = arrayProto.reduce; /** * Those data types can be cloned: * Plain object, Array, TypedArray, number, string, null, undefined. * Those data types will be assgined using the orginal data: * BUILTIN_OBJECT * Instance of user defined class will be cloned to a plain object, without * properties in prototype. * Other data types is not supported (not sure what will happen). * * Caution: do not support clone Date, for performance consideration. * (There might be a large number of date in `series.data`). * So date should not be modified in and out of echarts. * * @param {*} source * @return {*} new */ function clone(source) { if (source == null || typeof source != 'object') { return source; } var result = source; var typeStr = objToString.call(source); if (typeStr === '[object Array]') { result = []; for (var i = 0, len = source.length; i < len; i++) { result[i] = clone(source[i]); } } else if (TYPED_ARRAY[typeStr]) { result = source.constructor.from(source); } else if (!BUILTIN_OBJECT[typeStr] && !isDom(source)) { result = {}; for (var key in source) { if (source.hasOwnProperty(key)) { result[key] = clone(source[key]); } } } return result; } /** * @memberOf module:zrender/core/util * @param {*} target * @param {*} source * @param {boolean} [overwrite=false] */ function merge(target, source, overwrite) { // We should escapse that source is string // and enter for ... in ... if (!isObject(source) || !isObject(target)) { return overwrite ? clone(source) : target; } for (var key in source) { if (source.hasOwnProperty(key)) { var targetProp = target[key]; var sourceProp = source[key]; if (isObject(sourceProp) && isObject(targetProp) && !isArray(sourceProp) && !isArray(targetProp) && !isDom(sourceProp) && !isDom(targetProp) && !isBuildInObject(sourceProp) && !isBuildInObject(targetProp) ) { // 如果需要递归覆盖,就递归调用merge merge(targetProp, sourceProp, overwrite); } else if (overwrite || !(key in target)) { // 否则只处理overwrite为true,或者在目标对象中没有此属性的情况 // NOTE,在 target[key] 不存在的时候也是直接覆盖 target[key] = clone(source[key], true); } } } return target; } /** * @param {Array} targetAndSources The first item is target, and the rests are source. * @param {boolean} [overwrite=false] * @return {*} target */ function mergeAll(targetAndSources, overwrite) { var result = targetAndSources[0]; for (var i = 1, len = targetAndSources.length; i < len; i++) { result = merge(result, targetAndSources[i], overwrite); } return result; } /** * @param {*} target * @param {*} source * @memberOf module:zrender/core/util */ function extend(target, source) { for (var key in source) { if (source.hasOwnProperty(key)) { target[key] = source[key]; } } return target; } /** * @param {*} target * @param {*} source * @param {boolen} [overlay=false] * @memberOf module:zrender/core/util */ function defaults(target, source, overlay) { for (var key in source) { if (source.hasOwnProperty(key) && (overlay ? source[key] != null : target[key] == null) ) { target[key] = source[key]; } } return target; } function createCanvas() { return document.createElement('canvas'); } // FIXME var _ctx; function getContext() { if (!_ctx) { // Use util.createCanvas instead of createCanvas // because createCanvas may be overwritten in different environment _ctx = util.createCanvas().getContext('2d'); } return _ctx; } /** * 查询数组中元素的index * @memberOf module:zrender/core/util */ function indexOf(array, value) { if (array) { if (array.indexOf) { return array.indexOf(value); } for (var i = 0, len = array.length; i < len; i++) { if (array[i] === value) { return i; } } } return -1; } /** * 构造类继承关系 * * @memberOf module:zrender/core/util * @param {Function} clazz 源类 * @param {Function} baseClazz 基类 */ function inherits(clazz, baseClazz) { var clazzPrototype = clazz.prototype; function F() {} F.prototype = baseClazz.prototype; clazz.prototype = new F(); for (var prop in clazzPrototype) { clazz.prototype[prop] = clazzPrototype[prop]; } clazz.prototype.constructor = clazz; clazz.superClass = baseClazz; } /** * @memberOf module:zrender/core/util * @param {Object|Function} target * @param {Object|Function} sorce * @param {boolean} overlay */ function mixin(target, source, overlay) { target = 'prototype' in target ? target.prototype : target; source = 'prototype' in source ? source.prototype : source; defaults(target, source, overlay); } /** * @param {Array|TypedArray} data */ function isArrayLike(data) { if (! data) { return; } if (typeof data == 'string') { return false; } return typeof data.length == 'number'; } /** * 数组或对象遍历 * @memberOf module:zrender/core/util * @param {Object|Array} obj * @param {Function} cb * @param {*} [context] */ function each(obj, cb, context) { if (!(obj && cb)) { return; } if (obj.forEach && obj.forEach === nativeForEach) { obj.forEach(cb, context); } else if (obj.length === +obj.length) { for (var i = 0, len = obj.length; i < len; i++) { cb.call(context, obj[i], i, obj); } } else { for (var key in obj) { if (obj.hasOwnProperty(key)) { cb.call(context, obj[key], key, obj); } } } } /** * 数组映射 * @memberOf module:zrender/core/util * @param {Array} obj * @param {Function} cb * @param {*} [context] * @return {Array} */ function map(obj, cb, context) { if (!(obj && cb)) { return; } if (obj.map && obj.map === nativeMap) { return obj.map(cb, context); } else { var result = []; for (var i = 0, len = obj.length; i < len; i++) { result.push(cb.call(context, obj[i], i, obj)); } return result; } } /** * @memberOf module:zrender/core/util * @param {Array} obj * @param {Function} cb * @param {Object} [memo] * @param {*} [context] * @return {Array} */ function reduce(obj, cb, memo, context) { if (!(obj && cb)) { return; } if (obj.reduce && obj.reduce === nativeReduce) { return obj.reduce(cb, memo, context); } else { for (var i = 0, len = obj.length; i < len; i++) { memo = cb.call(context, memo, obj[i], i, obj); } return memo; } } /** * 数组过滤 * @memberOf module:zrender/core/util * @param {Array} obj * @param {Function} cb * @param {*} [context] * @return {Array} */ function filter(obj, cb, context) { if (!(obj && cb)) { return; } if (obj.filter && obj.filter === nativeFilter) { return obj.filter(cb, context); } else { var result = []; for (var i = 0, len = obj.length; i < len; i++) { if (cb.call(context, obj[i], i, obj)) { result.push(obj[i]); } } return result; } } /** * 数组项查找 * @memberOf module:zrender/core/util * @param {Array} obj * @param {Function} cb * @param {*} [context] * @return {Array} */ function find(obj, cb, context) { if (!(obj && cb)) { return; } for (var i = 0, len = obj.length; i < len; i++) { if (cb.call(context, obj[i], i, obj)) { return obj[i]; } } } /** * @memberOf module:zrender/core/util * @param {Function} func * @param {*} context * @return {Function} */ function bind(func, context) { var args = nativeSlice.call(arguments, 2); return function () { return func.apply(context, args.concat(nativeSlice.call(arguments))); }; } /** * @memberOf module:zrender/core/util * @param {Function} func * @return {Function} */ function curry(func) { var args = nativeSlice.call(arguments, 1); return function () { return func.apply(this, args.concat(nativeSlice.call(arguments))); }; } /** * @memberOf module:zrender/core/util * @param {*} value * @return {boolean} */ function isArray(value) { return objToString.call(value) === '[object Array]'; } /** * @memberOf module:zrender/core/util * @param {*} value * @return {boolean} */ function isFunction(value) { return typeof value === 'function'; } /** * @memberOf module:zrender/core/util * @param {*} value * @return {boolean} */ function isString(value) { return objToString.call(value) === '[object String]'; } /** * @memberOf module:zrender/core/util * @param {*} value * @return {boolean} */ function isObject(value) { // Avoid a V8 JIT bug in Chrome 19-20. // See https://code.google.com/p/v8/issues/detail?id=2291 for more details. var type = typeof value; return type === 'function' || (!!value && type == 'object'); } /** * @memberOf module:zrender/core/util * @param {*} value * @return {boolean} */ function isBuildInObject(value) { return !!BUILTIN_OBJECT[objToString.call(value)]; } /** * @memberOf module:zrender/core/util * @param {*} value * @return {boolean} */ function isDom(value) { return typeof value === 'object' && typeof value.nodeType === 'number' && typeof value.ownerDocument === 'object'; } /** * If value1 is not null, then return value1, otherwise judget rest of values. * @memberOf module:zrender/core/util * @return {*} Final value */ function retrieve(values) { for (var i = 0, len = arguments.length; i < len; i++) { if (arguments[i] != null) { return arguments[i]; } } } /** * @memberOf module:zrender/core/util * @param {Array} arr * @param {number} startIndex * @param {number} endIndex * @return {Array} */ function slice() { return Function.call.apply(nativeSlice, arguments); } /** * @memberOf module:zrender/core/util * @param {boolean} condition * @param {string} message */ function assert(condition, message) { if (!condition) { throw new Error(message); } } var util = { inherits: inherits, mixin: mixin, clone: clone, merge: merge, mergeAll: mergeAll, extend: extend, defaults: defaults, getContext: getContext, createCanvas: createCanvas, indexOf: indexOf, slice: slice, find: find, isArrayLike: isArrayLike, each: each, map: map, reduce: reduce, filter: filter, bind: bind, curry: curry, isArray: isArray, isString: isString, isObject: isObject, isFunction: isFunction, isBuildInObject: isBuildInObject, isDom: isDom, retrieve: retrieve, assert: assert, noop: function () {} }; module.exports = util; /***/ }, /* 5 */ /***/ function(module, exports, __webpack_require__) { var formatUtil = __webpack_require__(6); var nubmerUtil = __webpack_require__(7); var Model = __webpack_require__(12); var zrUtil = __webpack_require__(4); var each = zrUtil.each; var isObject = zrUtil.isObject; var modelUtil = {}; /** * If value is not array, then translate it to array. * @param {*} value * @return {Array} [value] or value */ modelUtil.normalizeToArray = function (value) { return value instanceof Array ? value : value == null ? [] : [value]; }; /** * Sync default option between normal and emphasis like `position` and `show` * In case some one will write code like * label: { * normal: { * show: false, * position: 'outside', * textStyle: { * fontSize: 18 * } * }, * emphasis: { * show: true * } * } * @param {Object} opt * @param {Array.} subOpts */ modelUtil.defaultEmphasis = function (opt, subOpts) { if (opt) { var emphasisOpt = opt.emphasis = opt.emphasis || {}; var normalOpt = opt.normal = opt.normal || {}; // Default emphasis option from normal each(subOpts, function (subOptName) { var val = zrUtil.retrieve(emphasisOpt[subOptName], normalOpt[subOptName]); if (val != null) { emphasisOpt[subOptName] = val; } }); } }; modelUtil.LABEL_OPTIONS = ['position', 'show', 'textStyle', 'distance', 'formatter']; /** * data could be [12, 2323, {value: 223}, [1221, 23], {value: [2, 23]}] * This helper method retieves value from data. * @param {string|number|Date|Array|Object} dataItem * @return {number|string|Date|Array.} */ modelUtil.getDataItemValue = function (dataItem) { // Performance sensitive. return dataItem && (dataItem.value == null ? dataItem : dataItem.value); }; /** * data could be [12, 2323, {value: 223}, [1221, 23], {value: [2, 23]}] * This helper method determine if dataItem has extra option besides value * @param {string|number|Date|Array|Object} dataItem */ modelUtil.isDataItemOption = function (dataItem) { return isObject(dataItem) && !(dataItem instanceof Array); // // markLine data can be array // && !(dataItem[0] && isObject(dataItem[0]) && !(dataItem[0] instanceof Array)); }; /** * This helper method convert value in data. * @param {string|number|Date} value * @param {Object|string} [dimInfo] If string (like 'x'), dimType defaults 'number'. */ modelUtil.converDataValue = function (value, dimInfo) { // Performance sensitive. var dimType = dimInfo && dimInfo.type; if (dimType === 'ordinal') { return value; } if (dimType === 'time' && !isFinite(value) && value != null && value !== '-') { value = +nubmerUtil.parseDate(value); } // dimType defaults 'number'. // If dimType is not ordinal and value is null or undefined or NaN or '-', // parse to NaN. return (value == null || value === '') ? NaN : +value; // If string (like '-'), using '+' parse to NaN }; /** * Create a model proxy to be used in tooltip for edge data, markLine data, markPoint data. * @param {module:echarts/data/List} data * @param {Object} opt * @param {string} [opt.seriesIndex] * @param {Object} [opt.name] * @param {Object} [opt.mainType] * @param {Object} [opt.subType] */ modelUtil.createDataFormatModel = function (data, opt) { var model = new Model(); zrUtil.mixin(model, modelUtil.dataFormatMixin); model.seriesIndex = opt.seriesIndex; model.name = opt.name || ''; model.mainType = opt.mainType; model.subType = opt.subType; model.getData = function () { return data; }; return model; }; // PENDING A little ugly modelUtil.dataFormatMixin = { /** * Get params for formatter * @param {number} dataIndex * @param {string} [dataType] * @return {Object} */ getDataParams: function (dataIndex, dataType) { var data = this.getData(dataType); var seriesIndex = this.seriesIndex; var seriesName = this.name; var rawValue = this.getRawValue(dataIndex, dataType); var rawDataIndex = data.getRawIndex(dataIndex); var name = data.getName(dataIndex, true); var itemOpt = data.getRawDataItem(dataIndex); return { componentType: this.mainType, componentSubType: this.subType, seriesType: this.mainType === 'series' ? this.subType : null, seriesIndex: seriesIndex, seriesName: seriesName, name: name, dataIndex: rawDataIndex, data: itemOpt, dataType: dataType, value: rawValue, color: data.getItemVisual(dataIndex, 'color'), // Param name list for mapping `a`, `b`, `c`, `d`, `e` $vars: ['seriesName', 'name', 'value'] }; }, /** * Format label * @param {number} dataIndex * @param {string} [status='normal'] 'normal' or 'emphasis' * @param {string} [dataType] * @param {number} [dimIndex] * @return {string} */ getFormattedLabel: function (dataIndex, status, dataType, dimIndex) { status = status || 'normal'; var data = this.getData(dataType); var itemModel = data.getItemModel(dataIndex); var params = this.getDataParams(dataIndex, dataType); if (dimIndex != null && (params.value instanceof Array)) { params.value = params.value[dimIndex]; } var formatter = itemModel.get(['label', status, 'formatter']); if (typeof formatter === 'function') { params.status = status; return formatter(params); } else if (typeof formatter === 'string') { return formatUtil.formatTpl(formatter, params); } }, /** * Get raw value in option * @param {number} idx * @param {string} [dataType] * @return {Object} */ getRawValue: function (idx, dataType) { var data = this.getData(dataType); var dataItem = data.getRawDataItem(idx); if (dataItem != null) { return (isObject(dataItem) && !(dataItem instanceof Array)) ? dataItem.value : dataItem; } }, /** * Should be implemented. * @param {number} dataIndex * @param {boolean} [multipleSeries=false] * @param {number} [dataType] * @return {string} tooltip string */ formatTooltip: zrUtil.noop }; /** * Mapping to exists for merge. * * @public * @param {Array.|Array.} exists * @param {Object|Array.} newCptOptions * @return {Array.} Result, like [{exist: ..., option: ...}, {}], * index of which is the same as exists. */ modelUtil.mappingToExists = function (exists, newCptOptions) { // Mapping by the order by original option (but not order of // new option) in merge mode. Because we should ensure // some specified index (like xAxisIndex) is consistent with // original option, which is easy to understand, espatially in // media query. And in most case, merge option is used to // update partial option but not be expected to change order. newCptOptions = (newCptOptions || []).slice(); var result = zrUtil.map(exists || [], function (obj, index) { return {exist: obj}; }); // Mapping by id or name if specified. each(newCptOptions, function (cptOption, index) { if (!isObject(cptOption)) { return; } // id has highest priority. for (var i = 0; i < result.length; i++) { if (!result[i].option // Consider name: two map to one. && cptOption.id != null && result[i].exist.id === cptOption.id + '' ) { result[i].option = cptOption; newCptOptions[index] = null; return; } } for (var i = 0; i < result.length; i++) { var exist = result[i].exist; if (!result[i].option // Consider name: two map to one. // Can not match when both ids exist but different. && (exist.id == null || cptOption.id == null) && cptOption.name != null && !modelUtil.isIdInner(cptOption) && !modelUtil.isIdInner(exist) && exist.name === cptOption.name + '' ) { result[i].option = cptOption; newCptOptions[index] = null; return; } } }); // Otherwise mapping by index. each(newCptOptions, function (cptOption, index) { if (!isObject(cptOption)) { return; } var i = 0; for (; i < result.length; i++) { var exist = result[i].exist; if (!result[i].option // Existing model that already has id should be able to // mapped to (because after mapping performed model may // be assigned with a id, whish should not affect next // mapping), except those has inner id. && !modelUtil.isIdInner(exist) // Caution: // Do not overwrite id. But name can be overwritten, // because axis use name as 'show label text'. // 'exist' always has id and name and we dont // need to check it. && cptOption.id == null ) { result[i].option = cptOption; break; } } if (i >= result.length) { result.push({option: cptOption}); } }); return result; }; /** * Make id and name for mapping result (result of mappingToExists) * into `keyInfo` field. * * @public * @param {Array.} Result, like [{exist: ..., option: ...}, {}], * which order is the same as exists. * @return {Array.} The input. */ modelUtil.makeIdAndName = function (mapResult) { // We use this id to hash component models and view instances // in echarts. id can be specified by user, or auto generated. // The id generation rule ensures new view instance are able // to mapped to old instance when setOption are called in // no-merge mode. So we generate model id by name and plus // type in view id. // name can be duplicated among components, which is convenient // to specify multi components (like series) by one name. // Ensure that each id is distinct. var idMap = {}; each(mapResult, function (item, index) { var existCpt = item.exist; existCpt && (idMap[existCpt.id] = item); }); each(mapResult, function (item, index) { var opt = item.option; zrUtil.assert( !opt || opt.id == null || !idMap[opt.id] || idMap[opt.id] === item, 'id duplicates: ' + (opt && opt.id) ); opt && opt.id != null && (idMap[opt.id] = item); !item.keyInfo && (item.keyInfo = {}); }); // Make name and id. each(mapResult, function (item, index) { var existCpt = item.exist; var opt = item.option; var keyInfo = item.keyInfo; if (!isObject(opt)) { return; } // name can be overwitten. Consider case: axis.name = '20km'. // But id generated by name will not be changed, which affect // only in that case: setOption with 'not merge mode' and view // instance will be recreated, which can be accepted. keyInfo.name = opt.name != null ? opt.name + '' : existCpt ? existCpt.name : '\0-'; if (existCpt) { keyInfo.id = existCpt.id; } else if (opt.id != null) { keyInfo.id = opt.id + ''; } else { // Consider this situatoin: // optionA: [{name: 'a'}, {name: 'a'}, {..}] // optionB [{..}, {name: 'a'}, {name: 'a'}] // Series with the same name between optionA and optionB // should be mapped. var idNum = 0; do { keyInfo.id = '\0' + keyInfo.name + '\0' + idNum++; } while (idMap[keyInfo.id]); } idMap[keyInfo.id] = item; }); }; /** * @public * @param {Object} cptOption * @return {boolean} */ modelUtil.isIdInner = function (cptOption) { return isObject(cptOption) && cptOption.id && (cptOption.id + '').indexOf('\0_ec_\0') === 0; }; /** * A helper for removing duplicate items between batchA and batchB, * and in themselves, and categorize by series. * * @param {Array.} batchA Like: [{seriesId: 2, dataIndex: [32, 4, 5]}, ...] * @param {Array.} batchB Like: [{seriesId: 2, dataIndex: [32, 4, 5]}, ...] * @return {Array., Array.>} result: [resultBatchA, resultBatchB] */ modelUtil.compressBatches = function (batchA, batchB) { var mapA = {}; var mapB = {}; makeMap(batchA || [], mapA); makeMap(batchB || [], mapB, mapA); return [mapToArray(mapA), mapToArray(mapB)]; function makeMap(sourceBatch, map, otherMap) { for (var i = 0, len = sourceBatch.length; i < len; i++) { var seriesId = sourceBatch[i].seriesId; var dataIndices = modelUtil.normalizeToArray(sourceBatch[i].dataIndex); var otherDataIndices = otherMap && otherMap[seriesId]; for (var j = 0, lenj = dataIndices.length; j < lenj; j++) { var dataIndex = dataIndices[j]; if (otherDataIndices && otherDataIndices[dataIndex]) { otherDataIndices[dataIndex] = null; } else { (map[seriesId] || (map[seriesId] = {}))[dataIndex] = 1; } } } } function mapToArray(map, isData) { var result = []; for (var i in map) { if (map.hasOwnProperty(i) && map[i] != null) { if (isData) { result.push(+i); } else { var dataIndices = mapToArray(map[i], true); dataIndices.length && result.push({seriesId: i, dataIndex: dataIndices}); } } } return result; } }; /** * @param {module:echarts/data/List} data * @param {Object} payload Contains dataIndex (means rawIndex) / dataIndexInside / name * each of which can be Array or primary type. * @return {number|Array.} dataIndex If not found, return undefined/null. */ modelUtil.queryDataIndex = function (data, payload) { if (payload.dataIndexInside != null) { return payload.dataIndexInside; } else if (payload.dataIndex != null) { return zrUtil.isArray(payload.dataIndex) ? zrUtil.map(payload.dataIndex, function (value) { return data.indexOfRawIndex(value); }) : data.indexOfRawIndex(payload.dataIndex); } else if (payload.name != null) { return zrUtil.isArray(payload.name) ? zrUtil.map(payload.name, function (value) { return data.indexOfName(value); }) : data.indexOfName(payload.name); } }; /** * @param {module:echarts/model/Global} ecModel * @param {string|Object} finder * If string, e.g., 'geo', means {geoIndex: 0}. * If Object, could contain some of these properties below: * { * seriesIndex, seriesId, seriesName, * geoIndex, geoId, goeName, * bmapIndex, bmapId, bmapName, * xAxisIndex, xAxisId, xAxisName, * yAxisIndex, yAxisId, yAxisName, * gridIndex, gridId, gridName, * ... (can be extended) * } * Each properties can be number|string|Array.|Array. * For example, a finder could be * { * seriesIndex: 3, * geoId: ['aa', 'cc'], * gridName: ['xx', 'rr'] * } * @param {Object} [opt] * @param {string} [opt.defaultMainType] * @return {Object} result like: * { * seriesModels: [seriesModel1, seriesModel2], * seriesModel: seriesModel1, // The first model * geoModels: [geoModel1, geoModel2], * geoModel: geoModel1, // The first model * ... * } */ modelUtil.parseFinder = function (ecModel, finder, opt) { if (zrUtil.isString(finder)) { var obj = {}; obj[finder + 'Index'] = 0; finder = obj; } var defaultMainType = opt && opt.defaultMainType; if (defaultMainType && !has(finder, defaultMainType + 'Index') && !has(finder, defaultMainType + 'Id') && !has(finder, defaultMainType + 'Name') ) { finder[defaultMainType + 'Index'] = 0; } var result = {}; each(finder, function (value, key) { var value = finder[key]; // Exclude 'dataIndex' and other illgal keys. if (key === 'dataIndex' || key === 'dataIndexInside') { result[key] = value; return; } var parsedKey = key.match(/^(\w+)(Index|Id|Name)$/) || []; var mainType = parsedKey[1]; var queryType = parsedKey[2]; if (!mainType || !queryType) { return; } var queryParam = {mainType: mainType}; queryParam[queryType.toLowerCase()] = value; var models = ecModel.queryComponents(queryParam); result[mainType + 'Models'] = models; result[mainType + 'Model'] = models[0]; }); return result; }; function has(obj, prop) { return obj && obj.hasOwnProperty(prop); } module.exports = modelUtil; /***/ }, /* 6 */ /***/ function(module, exports, __webpack_require__) { var zrUtil = __webpack_require__(4); var numberUtil = __webpack_require__(7); var textContain = __webpack_require__(8); var formatUtil = {}; /** * 每三位默认加,格式化 * @type {string|number} x */ formatUtil.addCommas = function (x) { if (isNaN(x)) { return '-'; } x = (x + '').split('.'); return x[0].replace(/(\d{1,3})(?=(?:\d{3})+(?!\d))/g,'$1,') + (x.length > 1 ? ('.' + x[1]) : ''); }; /** * @param {string} str * @param {boolean} [upperCaseFirst=false] * @return {string} str */ formatUtil.toCamelCase = function (str, upperCaseFirst) { str = (str || '').toLowerCase().replace(/-(.)/g, function(match, group1) { return group1.toUpperCase(); }); if (upperCaseFirst && str) { str = str.charAt(0).toUpperCase() + str.slice(1); } return str; }; /** * Normalize css liked array configuration * e.g. * 3 => [3, 3, 3, 3] * [4, 2] => [4, 2, 4, 2] * [4, 3, 2] => [4, 3, 2, 3] * @param {number|Array.} val */ formatUtil.normalizeCssArray = function (val) { var len = val.length; if (typeof (val) === 'number') { return [val, val, val, val]; } else if (len === 2) { // vertical | horizontal return [val[0], val[1], val[0], val[1]]; } else if (len === 3) { // top | horizontal | bottom return [val[0], val[1], val[2], val[1]]; } return val; }; formatUtil.encodeHTML = function (source) { return String(source) .replace(/&/g, '&') .replace(//g, '>') .replace(/"/g, '"') .replace(/'/g, '''); }; var TPL_VAR_ALIAS = ['a', 'b', 'c', 'd', 'e', 'f', 'g']; var wrapVar = function (varName, seriesIdx) { return '{' + varName + (seriesIdx == null ? '' : seriesIdx) + '}'; }; /** * Template formatter * @param {string} tpl * @param {Array.|Object} paramsList * @return {string} */ formatUtil.formatTpl = function (tpl, paramsList) { if (!zrUtil.isArray(paramsList)) { paramsList = [paramsList]; } var seriesLen = paramsList.length; if (!seriesLen) { return ''; } var $vars = paramsList[0].$vars || []; for (var i = 0; i < $vars.length; i++) { var alias = TPL_VAR_ALIAS[i]; tpl = tpl.replace(wrapVar(alias), wrapVar(alias, 0)); } for (var seriesIdx = 0; seriesIdx < seriesLen; seriesIdx++) { for (var k = 0; k < $vars.length; k++) { tpl = tpl.replace( wrapVar(TPL_VAR_ALIAS[k], seriesIdx), paramsList[seriesIdx][$vars[k]] ); } } return tpl; }; /** * @param {string} str * @return {string} * @inner */ var s2d = function (str) { return str < 10 ? ('0' + str) : str; }; /** * ISO Date format * @param {string} tpl * @param {number} value * @inner */ formatUtil.formatTime = function (tpl, value) { if (tpl === 'week' || tpl === 'month' || tpl === 'quarter' || tpl === 'half-year' || tpl === 'year' ) { tpl = 'MM-dd\nyyyy'; } var date = numberUtil.parseDate(value); var y = date.getFullYear(); var M = date.getMonth() + 1; var d = date.getDate(); var h = date.getHours(); var m = date.getMinutes(); var s = date.getSeconds(); tpl = tpl.replace('MM', s2d(M)) .toLowerCase() .replace('yyyy', y) .replace('yy', y % 100) .replace('dd', s2d(d)) .replace('d', d) .replace('hh', s2d(h)) .replace('h', h) .replace('mm', s2d(m)) .replace('m', m) .replace('ss', s2d(s)) .replace('s', s); return tpl; }; /** * Capital first * @param {string} str * @return {string} */ formatUtil.capitalFirst = function (str) { return str ? str.charAt(0).toUpperCase() + str.substr(1) : str; }; formatUtil.truncateText = textContain.truncateText; module.exports = formatUtil; /***/ }, /* 7 */ /***/ function(module, exports) { /** * 数值处理模块 * @module echarts/util/number */ var number = {}; var RADIAN_EPSILON = 1e-4; function _trim(str) { return str.replace(/^\s+/, '').replace(/\s+$/, ''); } /** * Linear mapping a value from domain to range * @memberOf module:echarts/util/number * @param {(number|Array.)} val * @param {Array.} domain Domain extent domain[0] can be bigger than domain[1] * @param {Array.} range Range extent range[0] can be bigger than range[1] * @param {boolean} clamp * @return {(number|Array.} */ number.linearMap = function (val, domain, range, clamp) { var subDomain = domain[1] - domain[0]; var subRange = range[1] - range[0]; if (subDomain === 0) { return subRange === 0 ? range[0] : (range[0] + range[1]) / 2; } // Avoid accuracy problem in edge, such as // 146.39 - 62.83 === 83.55999999999999. // See echarts/test/ut/spec/util/number.js#linearMap#accuracyError // It is a little verbose for efficiency considering this method // is a hotspot. if (clamp) { if (subDomain > 0) { if (val <= domain[0]) { return range[0]; } else if (val >= domain[1]) { return range[1]; } } else { if (val >= domain[0]) { return range[0]; } else if (val <= domain[1]) { return range[1]; } } } else { if (val === domain[0]) { return range[0]; } if (val === domain[1]) { return range[1]; } } return (val - domain[0]) / subDomain * subRange + range[0]; }; /** * Convert a percent string to absolute number. * Returns NaN if percent is not a valid string or number * @memberOf module:echarts/util/number * @param {string|number} percent * @param {number} all * @return {number} */ number.parsePercent = function(percent, all) { switch (percent) { case 'center': case 'middle': percent = '50%'; break; case 'left': case 'top': percent = '0%'; break; case 'right': case 'bottom': percent = '100%'; break; } if (typeof percent === 'string') { if (_trim(percent).match(/%$/)) { return parseFloat(percent) / 100 * all; } return parseFloat(percent); } return percent == null ? NaN : +percent; }; /** * Fix rounding error of float numbers * @param {number} x * @return {number} */ number.round = function (x, precision) { if (precision == null) { precision = 10; } // Avoid range error precision = Math.min(Math.max(0, precision), 20); return +(+x).toFixed(precision); }; number.asc = function (arr) { arr.sort(function (a, b) { return a - b; }); return arr; }; /** * Get precision * @param {number} val */ number.getPrecision = function (val) { val = +val; if (isNaN(val)) { return 0; } // It is much faster than methods converting number to string as follows // var tmp = val.toString(); // return tmp.length - 1 - tmp.indexOf('.'); // especially when precision is low var e = 1; var count = 0; while (Math.round(val * e) / e !== val) { e *= 10; count++; } return count; }; number.getPrecisionSafe = function (val) { var str = val.toString(); var dotIndex = str.indexOf('.'); if (dotIndex < 0) { return 0; } return str.length - 1 - dotIndex; }; /** * @param {Array.} dataExtent * @param {Array.} pixelExtent * @return {number} precision */ number.getPixelPrecision = function (dataExtent, pixelExtent) { var log = Math.log; var LN10 = Math.LN10; var dataQuantity = Math.floor(log(dataExtent[1] - dataExtent[0]) / LN10); var sizeQuantity = Math.round(log(Math.abs(pixelExtent[1] - pixelExtent[0])) / LN10); return Math.max( -dataQuantity + sizeQuantity, 0 ); }; // Number.MAX_SAFE_INTEGER, ie do not support. number.MAX_SAFE_INTEGER = 9007199254740991; /** * To 0 - 2 * PI, considering negative radian. * @param {number} radian * @return {number} */ number.remRadian = function (radian) { var pi2 = Math.PI * 2; return (radian % pi2 + pi2) % pi2; }; /** * @param {type} radian * @return {boolean} */ number.isRadianAroundZero = function (val) { return val > -RADIAN_EPSILON && val < RADIAN_EPSILON; }; /** * @param {string|Date|number} value * @return {Date} date */ number.parseDate = function (value) { if (value instanceof Date) { return value; } else if (typeof value === 'string') { // Treat as ISO format. See issue #3623 var ret = new Date(value); if (isNaN(+ret)) { // FIXME new Date('1970-01-01') is UTC, new Date('1970/01/01') is local ret = new Date(new Date(value.replace(/-/g, '/')) - new Date('1970/01/01')); } return ret; } return new Date(Math.round(value)); }; /** * Quantity of a number. e.g. 0.1, 1, 10, 100 * @param {number} val * @return {number} */ number.quantity = function (val) { return Math.pow(10, Math.floor(Math.log(val) / Math.LN10)); }; // "Nice Numbers for Graph Labels" of Graphic Gems /** * find a “nice” number approximately equal to x. Round the number if round = true, take ceiling if round = false * The primary observation is that the “nicest” numbers in decimal are 1, 2, and 5, and all power-of-ten multiples of these numbers. * @param {number} val * @param {boolean} round * @return {number} */ number.nice = function (val, round) { var exp10 = number.quantity(val); var f = val / exp10; // between 1 and 10 var nf; if (round) { if (f < 1.5) { nf = 1; } else if (f < 2.5) { nf = 2; } else if (f < 4) { nf = 3; } else if (f < 7) { nf = 5; } else { nf = 10; } } else { if (f < 1) { nf = 1; } else if (f < 2) { nf = 2; } else if (f < 3) { nf = 3; } else if (f < 5) { nf = 5; } else { nf = 10; } } return nf * exp10; }; /** * Order intervals asc, and split them when overlap. * expect(numberUtil.reformIntervals([ * {interval: [18, 62], close: [1, 1]}, * {interval: [-Infinity, -70], close: [0, 0]}, * {interval: [-70, -26], close: [1, 1]}, * {interval: [-26, 18], close: [1, 1]}, * {interval: [62, 150], close: [1, 1]}, * {interval: [106, 150], close: [1, 1]}, * {interval: [150, Infinity], close: [0, 0]} * ])).toEqual([ * {interval: [-Infinity, -70], close: [0, 0]}, * {interval: [-70, -26], close: [1, 1]}, * {interval: [-26, 18], close: [0, 1]}, * {interval: [18, 62], close: [0, 1]}, * {interval: [62, 150], close: [0, 1]}, * {interval: [150, Infinity], close: [0, 0]} * ]); * @param {Array.} list, where `close` mean open or close * of the interval, and Infinity can be used. * @return {Array.} The origin list, which has been reformed. */ number.reformIntervals = function (list) { list.sort(function (a, b) { return littleThan(a, b, 0) ? -1 : 1; }); var curr = -Infinity; var currClose = 1; for (var i = 0; i < list.length;) { var interval = list[i].interval; var close = list[i].close; for (var lg = 0; lg < 2; lg++) { if (interval[lg] <= curr) { interval[lg] = curr; close[lg] = !lg ? 1 - currClose : 1; } curr = interval[lg]; currClose = close[lg]; } if (interval[0] === interval[1] && close[0] * close[1] !== 1) { list.splice(i, 1); } else { i++; } } return list; function littleThan(a, b, lg) { return a.interval[lg] < b.interval[lg] || ( a.interval[lg] === b.interval[lg] && ( (a.close[lg] - b.close[lg] === (!lg ? 1 : -1)) || (!lg && littleThan(a, b, 1)) ) ); } }; module.exports = number; /***/ }, /* 8 */ /***/ function(module, exports, __webpack_require__) { var textWidthCache = {}; var textWidthCacheCounter = 0; var TEXT_CACHE_MAX = 5000; var util = __webpack_require__(4); var BoundingRect = __webpack_require__(9); var retrieve = util.retrieve; function getTextWidth(text, textFont) { var key = text + ':' + textFont; if (textWidthCache[key]) { return textWidthCache[key]; } var textLines = (text + '').split('\n'); var width = 0; for (var i = 0, l = textLines.length; i < l; i++) { // measureText 可以被覆盖以兼容不支持 Canvas 的环境 width = Math.max(textContain.measureText(textLines[i], textFont).width, width); } if (textWidthCacheCounter > TEXT_CACHE_MAX) { textWidthCacheCounter = 0; textWidthCache = {}; } textWidthCacheCounter++; textWidthCache[key] = width; return width; } function getTextRect(text, textFont, textAlign, textBaseline) { var textLineLen = ((text || '') + '').split('\n').length; var width = getTextWidth(text, textFont); // FIXME 高度计算比较粗暴 var lineHeight = getTextWidth('国', textFont); var height = textLineLen * lineHeight; var rect = new BoundingRect(0, 0, width, height); // Text has a special line height property rect.lineHeight = lineHeight; switch (textBaseline) { case 'bottom': case 'alphabetic': rect.y -= lineHeight; break; case 'middle': rect.y -= lineHeight / 2; break; // case 'hanging': // case 'top': } // FIXME Right to left language switch (textAlign) { case 'end': case 'right': rect.x -= rect.width; break; case 'center': rect.x -= rect.width / 2; break; // case 'start': // case 'left': } return rect; } function adjustTextPositionOnRect(textPosition, rect, textRect, distance) { var x = rect.x; var y = rect.y; var height = rect.height; var width = rect.width; var textHeight = textRect.height; var halfHeight = height / 2 - textHeight / 2; var textAlign = 'left'; switch (textPosition) { case 'left': x -= distance; y += halfHeight; textAlign = 'right'; break; case 'right': x += distance + width; y += halfHeight; textAlign = 'left'; break; case 'top': x += width / 2; y -= distance + textHeight; textAlign = 'center'; break; case 'bottom': x += width / 2; y += height + distance; textAlign = 'center'; break; case 'inside': x += width / 2; y += halfHeight; textAlign = 'center'; break; case 'insideLeft': x += distance; y += halfHeight; textAlign = 'left'; break; case 'insideRight': x += width - distance; y += halfHeight; textAlign = 'right'; break; case 'insideTop': x += width / 2; y += distance; textAlign = 'center'; break; case 'insideBottom': x += width / 2; y += height - textHeight - distance; textAlign = 'center'; break; case 'insideTopLeft': x += distance; y += distance; textAlign = 'left'; break; case 'insideTopRight': x += width - distance; y += distance; textAlign = 'right'; break; case 'insideBottomLeft': x += distance; y += height - textHeight - distance; break; case 'insideBottomRight': x += width - distance; y += height - textHeight - distance; textAlign = 'right'; break; } return { x: x, y: y, textAlign: textAlign, textBaseline: 'top' }; } /** * Show ellipsis if overflow. * * @param {string} text * @param {string} containerWidth * @param {string} textFont * @param {number} [ellipsis='...'] * @param {Object} [options] * @param {number} [options.maxIterations=3] * @param {number} [options.minChar=0] If truncate result are less * then minChar, ellipsis will not show, which is * better for user hint in some cases. * @param {number} [options.placeholder=''] When all truncated, use the placeholder. * @return {string} */ function truncateText(text, containerWidth, textFont, ellipsis, options) { if (!containerWidth) { return ''; } options = options || {}; ellipsis = retrieve(ellipsis, '...'); var maxIterations = retrieve(options.maxIterations, 2); var minChar = retrieve(options.minChar, 0); // FIXME // Other languages? var cnCharWidth = getTextWidth('国', textFont); // FIXME // Consider proportional font? var ascCharWidth = getTextWidth('a', textFont); var placeholder = retrieve(options.placeholder, ''); // Example 1: minChar: 3, text: 'asdfzxcv', truncate result: 'asdf', but not: 'a...'. // Example 2: minChar: 3, text: '维度', truncate result: '维', but not: '...'. var contentWidth = containerWidth = Math.max(0, containerWidth - 1); // Reserve some gap. for (var i = 0; i < minChar && contentWidth >= ascCharWidth; i++) { contentWidth -= ascCharWidth; } var ellipsisWidth = getTextWidth(ellipsis); if (ellipsisWidth > contentWidth) { ellipsis = ''; ellipsisWidth = 0; } contentWidth = containerWidth - ellipsisWidth; var textLines = (text + '').split('\n'); for (var i = 0, len = textLines.length; i < len; i++) { var textLine = textLines[i]; var lineWidth = getTextWidth(textLine, textFont); if (lineWidth <= containerWidth) { continue; } for (var j = 0;; j++) { if (lineWidth <= contentWidth || j >= maxIterations) { textLine += ellipsis; break; } var subLength = j === 0 ? estimateLength(textLine, contentWidth, ascCharWidth, cnCharWidth) : lineWidth > 0 ? Math.floor(textLine.length * contentWidth / lineWidth) : 0; textLine = textLine.substr(0, subLength); lineWidth = getTextWidth(textLine, textFont); } if (textLine === '') { textLine = placeholder; } textLines[i] = textLine; } return textLines.join('\n'); } function estimateLength(text, contentWidth, ascCharWidth, cnCharWidth) { var width = 0; var i = 0; for (var len = text.length; i < len && width < contentWidth; i++) { var charCode = text.charCodeAt(i); width += (0 <= charCode && charCode <= 127) ? ascCharWidth : cnCharWidth; } return i; } var textContain = { getWidth: getTextWidth, getBoundingRect: getTextRect, adjustTextPositionOnRect: adjustTextPositionOnRect, truncateText: truncateText, measureText: function (text, textFont) { var ctx = util.getContext(); ctx.font = textFont || '12px sans-serif'; return ctx.measureText(text); } }; module.exports = textContain; /***/ }, /* 9 */ /***/ function(module, exports, __webpack_require__) { 'use strict'; /** * @module echarts/core/BoundingRect */ var vec2 = __webpack_require__(10); var matrix = __webpack_require__(11); var v2ApplyTransform = vec2.applyTransform; var mathMin = Math.min; var mathMax = Math.max; /** * @alias module:echarts/core/BoundingRect */ function BoundingRect(x, y, width, height) { if (width < 0) { x = x + width; width = -width; } if (height < 0) { y = y + height; height = -height; } /** * @type {number} */ this.x = x; /** * @type {number} */ this.y = y; /** * @type {number} */ this.width = width; /** * @type {number} */ this.height = height; } BoundingRect.prototype = { constructor: BoundingRect, /** * @param {module:echarts/core/BoundingRect} other */ union: function (other) { var x = mathMin(other.x, this.x); var y = mathMin(other.y, this.y); this.width = mathMax( other.x + other.width, this.x + this.width ) - x; this.height = mathMax( other.y + other.height, this.y + this.height ) - y; this.x = x; this.y = y; }, /** * @param {Array.} m * @methods */ applyTransform: (function () { var lt = []; var rb = []; var lb = []; var rt = []; return function (m) { // In case usage like this // el.getBoundingRect().applyTransform(el.transform) // And element has no transform if (!m) { return; } lt[0] = lb[0] = this.x; lt[1] = rt[1] = this.y; rb[0] = rt[0] = this.x + this.width; rb[1] = lb[1] = this.y + this.height; v2ApplyTransform(lt, lt, m); v2ApplyTransform(rb, rb, m); v2ApplyTransform(lb, lb, m); v2ApplyTransform(rt, rt, m); this.x = mathMin(lt[0], rb[0], lb[0], rt[0]); this.y = mathMin(lt[1], rb[1], lb[1], rt[1]); var maxX = mathMax(lt[0], rb[0], lb[0], rt[0]); var maxY = mathMax(lt[1], rb[1], lb[1], rt[1]); this.width = maxX - this.x; this.height = maxY - this.y; }; })(), /** * Calculate matrix of transforming from self to target rect * @param {module:zrender/core/BoundingRect} b * @return {Array.} */ calculateTransform: function (b) { var a = this; var sx = b.width / a.width; var sy = b.height / a.height; var m = matrix.create(); // 矩阵右乘 matrix.translate(m, m, [-a.x, -a.y]); matrix.scale(m, m, [sx, sy]); matrix.translate(m, m, [b.x, b.y]); return m; }, /** * @param {(module:echarts/core/BoundingRect|Object)} b * @return {boolean} */ intersect: function (b) { if (!b) { return false; } if (!(b instanceof BoundingRect)) { // Normalize negative width/height. b = BoundingRect.create(b); } var a = this; var ax0 = a.x; var ax1 = a.x + a.width; var ay0 = a.y; var ay1 = a.y + a.height; var bx0 = b.x; var bx1 = b.x + b.width; var by0 = b.y; var by1 = b.y + b.height; return ! (ax1 < bx0 || bx1 < ax0 || ay1 < by0 || by1 < ay0); }, contain: function (x, y) { var rect = this; return x >= rect.x && x <= (rect.x + rect.width) && y >= rect.y && y <= (rect.y + rect.height); }, /** * @return {module:echarts/core/BoundingRect} */ clone: function () { return new BoundingRect(this.x, this.y, this.width, this.height); }, /** * Copy from another rect */ copy: function (other) { this.x = other.x; this.y = other.y; this.width = other.width; this.height = other.height; }, plain: function () { return { x: this.x, y: this.y, width: this.width, height: this.height }; } }; /** * @param {Object|module:zrender/core/BoundingRect} rect * @param {number} rect.x * @param {number} rect.y * @param {number} rect.width * @param {number} rect.height * @return {module:zrender/core/BoundingRect} */ BoundingRect.create = function (rect) { return new BoundingRect(rect.x, rect.y, rect.width, rect.height); }; module.exports = BoundingRect; /***/ }, /* 10 */ /***/ function(module, exports) { var ArrayCtor = typeof Float32Array === 'undefined' ? Array : Float32Array; /** * @typedef {Float32Array|Array.} Vector2 */ /** * 二维向量类 * @exports zrender/tool/vector */ var vector = { /** * 创建一个向量 * @param {number} [x=0] * @param {number} [y=0] * @return {Vector2} */ create: function (x, y) { var out = new ArrayCtor(2); if (x == null) { x = 0; } if (y == null) { y = 0; } out[0] = x; out[1] = y; return out; }, /** * 复制向量数据 * @param {Vector2} out * @param {Vector2} v * @return {Vector2} */ copy: function (out, v) { out[0] = v[0]; out[1] = v[1]; return out; }, /** * 克隆一个向量 * @param {Vector2} v * @return {Vector2} */ clone: function (v) { var out = new ArrayCtor(2); out[0] = v[0]; out[1] = v[1]; return out; }, /** * 设置向量的两个项 * @param {Vector2} out * @param {number} a * @param {number} b * @return {Vector2} 结果 */ set: function (out, a, b) { out[0] = a; out[1] = b; return out; }, /** * 向量相加 * @param {Vector2} out * @param {Vector2} v1 * @param {Vector2} v2 */ add: function (out, v1, v2) { out[0] = v1[0] + v2[0]; out[1] = v1[1] + v2[1]; return out; }, /** * 向量缩放后相加 * @param {Vector2} out * @param {Vector2} v1 * @param {Vector2} v2 * @param {number} a */ scaleAndAdd: function (out, v1, v2, a) { out[0] = v1[0] + v2[0] * a; out[1] = v1[1] + v2[1] * a; return out; }, /** * 向量相减 * @param {Vector2} out * @param {Vector2} v1 * @param {Vector2} v2 */ sub: function (out, v1, v2) { out[0] = v1[0] - v2[0]; out[1] = v1[1] - v2[1]; return out; }, /** * 向量长度 * @param {Vector2} v * @return {number} */ len: function (v) { return Math.sqrt(this.lenSquare(v)); }, /** * 向量长度平方 * @param {Vector2} v * @return {number} */ lenSquare: function (v) { return v[0] * v[0] + v[1] * v[1]; }, /** * 向量乘法 * @param {Vector2} out * @param {Vector2} v1 * @param {Vector2} v2 */ mul: function (out, v1, v2) { out[0] = v1[0] * v2[0]; out[1] = v1[1] * v2[1]; return out; }, /** * 向量除法 * @param {Vector2} out * @param {Vector2} v1 * @param {Vector2} v2 */ div: function (out, v1, v2) { out[0] = v1[0] / v2[0]; out[1] = v1[1] / v2[1]; return out; }, /** * 向量点乘 * @param {Vector2} v1 * @param {Vector2} v2 * @return {number} */ dot: function (v1, v2) { return v1[0] * v2[0] + v1[1] * v2[1]; }, /** * 向量缩放 * @param {Vector2} out * @param {Vector2} v * @param {number} s */ scale: function (out, v, s) { out[0] = v[0] * s; out[1] = v[1] * s; return out; }, /** * 向量归一化 * @param {Vector2} out * @param {Vector2} v */ normalize: function (out, v) { var d = vector.len(v); if (d === 0) { out[0] = 0; out[1] = 0; } else { out[0] = v[0] / d; out[1] = v[1] / d; } return out; }, /** * 计算向量间距离 * @param {Vector2} v1 * @param {Vector2} v2 * @return {number} */ distance: function (v1, v2) { return Math.sqrt( (v1[0] - v2[0]) * (v1[0] - v2[0]) + (v1[1] - v2[1]) * (v1[1] - v2[1]) ); }, /** * 向量距离平方 * @param {Vector2} v1 * @param {Vector2} v2 * @return {number} */ distanceSquare: function (v1, v2) { return (v1[0] - v2[0]) * (v1[0] - v2[0]) + (v1[1] - v2[1]) * (v1[1] - v2[1]); }, /** * 求负向量 * @param {Vector2} out * @param {Vector2} v */ negate: function (out, v) { out[0] = -v[0]; out[1] = -v[1]; return out; }, /** * 插值两个点 * @param {Vector2} out * @param {Vector2} v1 * @param {Vector2} v2 * @param {number} t */ lerp: function (out, v1, v2, t) { out[0] = v1[0] + t * (v2[0] - v1[0]); out[1] = v1[1] + t * (v2[1] - v1[1]); return out; }, /** * 矩阵左乘向量 * @param {Vector2} out * @param {Vector2} v * @param {Vector2} m */ applyTransform: function (out, v, m) { var x = v[0]; var y = v[1]; out[0] = m[0] * x + m[2] * y + m[4]; out[1] = m[1] * x + m[3] * y + m[5]; return out; }, /** * 求两个向量最小值 * @param {Vector2} out * @param {Vector2} v1 * @param {Vector2} v2 */ min: function (out, v1, v2) { out[0] = Math.min(v1[0], v2[0]); out[1] = Math.min(v1[1], v2[1]); return out; }, /** * 求两个向量最大值 * @param {Vector2} out * @param {Vector2} v1 * @param {Vector2} v2 */ max: function (out, v1, v2) { out[0] = Math.max(v1[0], v2[0]); out[1] = Math.max(v1[1], v2[1]); return out; } }; vector.length = vector.len; vector.lengthSquare = vector.lenSquare; vector.dist = vector.distance; vector.distSquare = vector.distanceSquare; module.exports = vector; /***/ }, /* 11 */ /***/ function(module, exports) { var ArrayCtor = typeof Float32Array === 'undefined' ? Array : Float32Array; /** * 3x2矩阵操作类 * @exports zrender/tool/matrix */ var matrix = { /** * 创建一个单位矩阵 * @return {Float32Array|Array.} */ create : function() { var out = new ArrayCtor(6); matrix.identity(out); return out; }, /** * 设置矩阵为单位矩阵 * @param {Float32Array|Array.} out */ identity : function(out) { out[0] = 1; out[1] = 0; out[2] = 0; out[3] = 1; out[4] = 0; out[5] = 0; return out; }, /** * 复制矩阵 * @param {Float32Array|Array.} out * @param {Float32Array|Array.} m */ copy: function(out, m) { out[0] = m[0]; out[1] = m[1]; out[2] = m[2]; out[3] = m[3]; out[4] = m[4]; out[5] = m[5]; return out; }, /** * 矩阵相乘 * @param {Float32Array|Array.} out * @param {Float32Array|Array.} m1 * @param {Float32Array|Array.} m2 */ mul : function (out, m1, m2) { // Consider matrix.mul(m, m2, m); // where out is the same as m2. // So use temp variable to escape error. var out0 = m1[0] * m2[0] + m1[2] * m2[1]; var out1 = m1[1] * m2[0] + m1[3] * m2[1]; var out2 = m1[0] * m2[2] + m1[2] * m2[3]; var out3 = m1[1] * m2[2] + m1[3] * m2[3]; var out4 = m1[0] * m2[4] + m1[2] * m2[5] + m1[4]; var out5 = m1[1] * m2[4] + m1[3] * m2[5] + m1[5]; out[0] = out0; out[1] = out1; out[2] = out2; out[3] = out3; out[4] = out4; out[5] = out5; return out; }, /** * 平移变换 * @param {Float32Array|Array.} out * @param {Float32Array|Array.} a * @param {Float32Array|Array.} v */ translate : function(out, a, v) { out[0] = a[0]; out[1] = a[1]; out[2] = a[2]; out[3] = a[3]; out[4] = a[4] + v[0]; out[5] = a[5] + v[1]; return out; }, /** * 旋转变换 * @param {Float32Array|Array.} out * @param {Float32Array|Array.} a * @param {number} rad */ rotate : function(out, a, rad) { var aa = a[0]; var ac = a[2]; var atx = a[4]; var ab = a[1]; var ad = a[3]; var aty = a[5]; var st = Math.sin(rad); var ct = Math.cos(rad); out[0] = aa * ct + ab * st; out[1] = -aa * st + ab * ct; out[2] = ac * ct + ad * st; out[3] = -ac * st + ct * ad; out[4] = ct * atx + st * aty; out[5] = ct * aty - st * atx; return out; }, /** * 缩放变换 * @param {Float32Array|Array.} out * @param {Float32Array|Array.} a * @param {Float32Array|Array.} v */ scale : function(out, a, v) { var vx = v[0]; var vy = v[1]; out[0] = a[0] * vx; out[1] = a[1] * vy; out[2] = a[2] * vx; out[3] = a[3] * vy; out[4] = a[4] * vx; out[5] = a[5] * vy; return out; }, /** * 求逆矩阵 * @param {Float32Array|Array.} out * @param {Float32Array|Array.} a */ invert : function(out, a) { var aa = a[0]; var ac = a[2]; var atx = a[4]; var ab = a[1]; var ad = a[3]; var aty = a[5]; var det = aa * ad - ab * ac; if (!det) { return null; } det = 1.0 / det; out[0] = ad * det; out[1] = -ab * det; out[2] = -ac * det; out[3] = aa * det; out[4] = (ac * aty - ad * atx) * det; out[5] = (ab * atx - aa * aty) * det; return out; } }; module.exports = matrix; /***/ }, /* 12 */ /***/ function(module, exports, __webpack_require__) { /** * @module echarts/model/Model */ var zrUtil = __webpack_require__(4); var clazzUtil = __webpack_require__(13); /** * @alias module:echarts/model/Model * @constructor * @param {Object} option * @param {module:echarts/model/Model} [parentModel] * @param {module:echarts/model/Global} [ecModel] */ function Model(option, parentModel, ecModel) { /** * @type {module:echarts/model/Model} * @readOnly */ this.parentModel = parentModel; /** * @type {module:echarts/model/Global} * @readOnly */ this.ecModel = ecModel; /** * @type {Object} * @protected */ this.option = option; // Simple optimization // if (this.init) { // if (arguments.length <= 4) { // this.init(option, parentModel, ecModel, extraOpt); // } // else { // this.init.apply(this, arguments); // } // } } Model.prototype = { constructor: Model, /** * Model 的初始化函数 * @param {Object} option */ init: null, /** * 从新的 Option merge */ mergeOption: function (option) { zrUtil.merge(this.option, option, true); }, /** * @param {string} path * @param {boolean} [ignoreParent=false] * @return {*} */ get: function (path, ignoreParent) { if (!path) { return this.option; } if (typeof path === 'string') { path = path.split('.'); } var obj = this.option; var parentModel = this.parentModel; for (var i = 0; i < path.length; i++) { // Ignore empty if (!path[i]) { continue; } // obj could be number/string/... (like 0) obj = (obj && typeof obj === 'object') ? obj[path[i]] : null; if (obj == null) { break; } } if (obj == null && parentModel && !ignoreParent) { obj = parentModel.get(path); } return obj; }, /** * @param {string} key * @param {boolean} [ignoreParent=false] * @return {*} */ getShallow: function (key, ignoreParent) { var option = this.option; var val = option == null ? option : option[key]; var parentModel = this.parentModel; if (val == null && parentModel && !ignoreParent) { val = parentModel.getShallow(key); } return val; }, /** * @param {string} path * @param {module:echarts/model/Model} [parentModel] * @return {module:echarts/model/Model} */ getModel: function (path, parentModel) { var obj = this.get(path, true); var thisParentModel = this.parentModel; var model = new Model( obj, parentModel || (thisParentModel && thisParentModel.getModel(path)), this.ecModel ); return model; }, /** * If model has option */ isEmpty: function () { return this.option == null; }, restoreData: function () {}, // Pending clone: function () { var Ctor = this.constructor; return new Ctor(zrUtil.clone(this.option)); }, setReadOnly: function (properties) { clazzUtil.setReadOnly(this, properties); } }; // Enable Model.extend. clazzUtil.enableClassExtend(Model); var mixin = zrUtil.mixin; mixin(Model, __webpack_require__(14)); mixin(Model, __webpack_require__(16)); mixin(Model, __webpack_require__(17)); mixin(Model, __webpack_require__(18)); module.exports = Model; /***/ }, /* 13 */ /***/ function(module, exports, __webpack_require__) { var zrUtil = __webpack_require__(4); var clazz = {}; var TYPE_DELIMITER = '.'; var IS_CONTAINER = '___EC__COMPONENT__CONTAINER___'; /** * @public */ var parseClassType = clazz.parseClassType = function (componentType) { var ret = {main: '', sub: ''}; if (componentType) { componentType = componentType.split(TYPE_DELIMITER); ret.main = componentType[0] || ''; ret.sub = componentType[1] || ''; } return ret; }; /** * @public */ clazz.enableClassExtend = function (RootClass, mandatoryMethods) { RootClass.$constructor = RootClass; RootClass.extend = function (proto) { if (true) { zrUtil.each(mandatoryMethods, function (method) { if (!proto[method]) { console.warn( 'Method `' + method + '` should be implemented' + (proto.type ? ' in ' + proto.type : '') + '.' ); } }); } var superClass = this; var ExtendedClass = function () { if (!proto.$constructor) { superClass.apply(this, arguments); } else { proto.$constructor.apply(this, arguments); } }; zrUtil.extend(ExtendedClass.prototype, proto); ExtendedClass.extend = this.extend; ExtendedClass.superCall = superCall; ExtendedClass.superApply = superApply; zrUtil.inherits(ExtendedClass, this); ExtendedClass.superClass = superClass; return ExtendedClass; }; }; // superCall should have class info, which can not be fetch from 'this'. // Consider this case: // class A has method f, // class B inherits class A, overrides method f, f call superApply('f'), // class C inherits class B, do not overrides method f, // then when method of class C is called, dead loop occured. function superCall(context, methodName) { var args = zrUtil.slice(arguments, 2); return this.superClass.prototype[methodName].apply(context, args); } function superApply(context, methodName, args) { return this.superClass.prototype[methodName].apply(context, args); } /** * @param {Object} entity * @param {Object} options * @param {boolean} [options.registerWhenExtend] * @public */ clazz.enableClassManagement = function (entity, options) { options = options || {}; /** * Component model classes * key: componentType, * value: * componentClass, when componentType is 'xxx' * or Object., when componentType is 'xxx.yy' * @type {Object} */ var storage = {}; entity.registerClass = function (Clazz, componentType) { if (componentType) { componentType = parseClassType(componentType); if (!componentType.sub) { if (true) { if (storage[componentType.main]) { console.warn(componentType.main + ' exists.'); } } storage[componentType.main] = Clazz; } else if (componentType.sub !== IS_CONTAINER) { var container = makeContainer(componentType); container[componentType.sub] = Clazz; } } return Clazz; }; entity.getClass = function (componentTypeMain, subType, throwWhenNotFound) { var Clazz = storage[componentTypeMain]; if (Clazz && Clazz[IS_CONTAINER]) { Clazz = subType ? Clazz[subType] : null; } if (throwWhenNotFound && !Clazz) { throw new Error( 'Component ' + componentTypeMain + '.' + (subType || '') + ' not exists. Load it first.' ); } return Clazz; }; entity.getClassesByMainType = function (componentType) { componentType = parseClassType(componentType); var result = []; var obj = storage[componentType.main]; if (obj && obj[IS_CONTAINER]) { zrUtil.each(obj, function (o, type) { type !== IS_CONTAINER && result.push(o); }); } else { result.push(obj); } return result; }; entity.hasClass = function (componentType) { // Just consider componentType.main. componentType = parseClassType(componentType); return !!storage[componentType.main]; }; /** * @return {Array.} Like ['aa', 'bb'], but can not be ['aa.xx'] */ entity.getAllClassMainTypes = function () { var types = []; zrUtil.each(storage, function (obj, type) { types.push(type); }); return types; }; /** * If a main type is container and has sub types * @param {string} mainType * @return {boolean} */ entity.hasSubTypes = function (componentType) { componentType = parseClassType(componentType); var obj = storage[componentType.main]; return obj && obj[IS_CONTAINER]; }; entity.parseClassType = parseClassType; function makeContainer(componentType) { var container = storage[componentType.main]; if (!container || !container[IS_CONTAINER]) { container = storage[componentType.main] = {}; container[IS_CONTAINER] = true; } return container; } if (options.registerWhenExtend) { var originalExtend = entity.extend; if (originalExtend) { entity.extend = function (proto) { var ExtendedClass = originalExtend.call(this, proto); return entity.registerClass(ExtendedClass, proto.type); }; } } return entity; }; /** * @param {string|Array.} properties */ clazz.setReadOnly = function (obj, properties) { // FIXME It seems broken in IE8 simulation of IE11 // if (!zrUtil.isArray(properties)) { // properties = properties != null ? [properties] : []; // } // zrUtil.each(properties, function (prop) { // var value = obj[prop]; // Object.defineProperty // && Object.defineProperty(obj, prop, { // value: value, writable: false // }); // zrUtil.isArray(obj[prop]) // && Object.freeze // && Object.freeze(obj[prop]); // }); }; module.exports = clazz; /***/ }, /* 14 */ /***/ function(module, exports, __webpack_require__) { var getLineStyle = __webpack_require__(15)( [ ['lineWidth', 'width'], ['stroke', 'color'], ['opacity'], ['shadowBlur'], ['shadowOffsetX'], ['shadowOffsetY'], ['shadowColor'] ] ); module.exports = { getLineStyle: function (excludes) { var style = getLineStyle.call(this, excludes); var lineDash = this.getLineDash(style.lineWidth); lineDash && (style.lineDash = lineDash); return style; }, getLineDash: function (lineWidth) { if (lineWidth == null) { lineWidth = 1; } var lineType = this.get('type'); var dotSize = Math.max(lineWidth, 2); var dashSize = lineWidth * 4; return (lineType === 'solid' || lineType == null) ? null : (lineType === 'dashed' ? [dashSize, dashSize] : [dotSize, dotSize]); } }; /***/ }, /* 15 */ /***/ function(module, exports, __webpack_require__) { // TODO Parse shadow style // TODO Only shallow path support var zrUtil = __webpack_require__(4); module.exports = function (properties) { // Normalize for (var i = 0; i < properties.length; i++) { if (!properties[i][1]) { properties[i][1] = properties[i][0]; } } return function (excludes) { var style = {}; for (var i = 0; i < properties.length; i++) { var propName = properties[i][1]; if (excludes && zrUtil.indexOf(excludes, propName) >= 0) { continue; } var val = this.getShallow(propName); if (val != null) { style[properties[i][0]] = val; } } return style; }; }; /***/ }, /* 16 */ /***/ function(module, exports, __webpack_require__) { module.exports = { getAreaStyle: __webpack_require__(15)( [ ['fill', 'color'], ['shadowBlur'], ['shadowOffsetX'], ['shadowOffsetY'], ['opacity'], ['shadowColor'] ] ) }; /***/ }, /* 17 */ /***/ function(module, exports, __webpack_require__) { var textContain = __webpack_require__(8); function getShallow(model, path) { return model && model.getShallow(path); } module.exports = { /** * Get color property or get color from option.textStyle.color * @return {string} */ getTextColor: function () { var ecModel = this.ecModel; return this.getShallow('color') || (ecModel && ecModel.get('textStyle.color')); }, /** * Create font string from fontStyle, fontWeight, fontSize, fontFamily * @return {string} */ getFont: function () { var ecModel = this.ecModel; var gTextStyleModel = ecModel && ecModel.getModel('textStyle'); return [ // FIXME in node-canvas fontWeight is before fontStyle this.getShallow('fontStyle') || getShallow(gTextStyleModel, 'fontStyle'), this.getShallow('fontWeight') || getShallow(gTextStyleModel, 'fontWeight'), (this.getShallow('fontSize') || getShallow(gTextStyleModel, 'fontSize') || 12) + 'px', this.getShallow('fontFamily') || getShallow(gTextStyleModel, 'fontFamily') || 'sans-serif' ].join(' '); }, getTextRect: function (text) { return textContain.getBoundingRect( text, this.getFont(), this.getShallow('align'), this.getShallow('baseline') ); }, truncateText: function (text, containerWidth, ellipsis, options) { return textContain.truncateText( text, containerWidth, this.getFont(), ellipsis, options ); } }; /***/ }, /* 18 */ /***/ function(module, exports, __webpack_require__) { var getItemStyle = __webpack_require__(15)( [ ['fill', 'color'], ['stroke', 'borderColor'], ['lineWidth', 'borderWidth'], ['opacity'], ['shadowBlur'], ['shadowOffsetX'], ['shadowOffsetY'], ['shadowColor'], ['textPosition'], ['textAlign'] ] ); module.exports = { getItemStyle: function (excludes) { var style = getItemStyle.call(this, excludes); var lineDash = this.getBorderLineDash(); lineDash && (style.lineDash = lineDash); return style; }, getBorderLineDash: function () { var lineType = this.get('borderType'); return (lineType === 'solid' || lineType == null) ? null : (lineType === 'dashed' ? [5, 5] : [1, 1]); } }; /***/ }, /* 19 */ /***/ function(module, exports, __webpack_require__) { /** * Component model * * @module echarts/model/Component */ var Model = __webpack_require__(12); var zrUtil = __webpack_require__(4); var arrayPush = Array.prototype.push; var componentUtil = __webpack_require__(20); var clazzUtil = __webpack_require__(13); var layout = __webpack_require__(21); /** * @alias module:echarts/model/Component * @constructor * @param {Object} option * @param {module:echarts/model/Model} parentModel * @param {module:echarts/model/Model} ecModel */ var ComponentModel = Model.extend({ type: 'component', /** * @readOnly * @type {string} */ id: '', /** * @readOnly */ name: '', /** * @readOnly * @type {string} */ mainType: '', /** * @readOnly * @type {string} */ subType: '', /** * @readOnly * @type {number} */ componentIndex: 0, /** * @type {Object} * @protected */ defaultOption: null, /** * @type {module:echarts/model/Global} * @readOnly */ ecModel: null, /** * key: componentType * value: Component model list, can not be null. * @type {Object.>} * @readOnly */ dependentModels: [], /** * @type {string} * @readOnly */ uid: null, /** * Support merge layout params. * Only support 'box' now (left/right/top/bottom/width/height). * @type {string|Object} Object can be {ignoreSize: true} * @readOnly */ layoutMode: null, $constructor: function (option, parentModel, ecModel, extraOpt) { Model.call(this, option, parentModel, ecModel, extraOpt); this.uid = componentUtil.getUID('componentModel'); }, init: function (option, parentModel, ecModel, extraOpt) { this.mergeDefaultAndTheme(option, ecModel); }, mergeDefaultAndTheme: function (option, ecModel) { var layoutMode = this.layoutMode; var inputPositionParams = layoutMode ? layout.getLayoutParams(option) : {}; var themeModel = ecModel.getTheme(); zrUtil.merge(option, themeModel.get(this.mainType)); zrUtil.merge(option, this.getDefaultOption()); if (layoutMode) { layout.mergeLayoutParam(option, inputPositionParams, layoutMode); } }, mergeOption: function (option, extraOpt) { zrUtil.merge(this.option, option, true); var layoutMode = this.layoutMode; if (layoutMode) { layout.mergeLayoutParam(this.option, option, layoutMode); } }, // Hooker after init or mergeOption optionUpdated: function (newCptOption, isInit) {}, getDefaultOption: function () { if (!this.hasOwnProperty('__defaultOption')) { var optList = []; var Class = this.constructor; while (Class) { var opt = Class.prototype.defaultOption; opt && optList.push(opt); Class = Class.superClass; } var defaultOption = {}; for (var i = optList.length - 1; i >= 0; i--) { defaultOption = zrUtil.merge(defaultOption, optList[i], true); } this.__defaultOption = defaultOption; } return this.__defaultOption; }, getReferringComponents: function (mainType) { return this.ecModel.queryComponents({ mainType: mainType, index: this.get(mainType + 'Index', true), id: this.get(mainType + 'Id', true) }); } }); // Reset ComponentModel.extend, add preConstruct. // clazzUtil.enableClassExtend( // ComponentModel, // function (option, parentModel, ecModel, extraOpt) { // // Set dependentModels, componentIndex, name, id, mainType, subType. // zrUtil.extend(this, extraOpt); // this.uid = componentUtil.getUID('componentModel'); // // this.setReadOnly([ // // 'type', 'id', 'uid', 'name', 'mainType', 'subType', // // 'dependentModels', 'componentIndex' // // ]); // } // ); // Add capability of registerClass, getClass, hasClass, registerSubTypeDefaulter and so on. clazzUtil.enableClassManagement( ComponentModel, {registerWhenExtend: true} ); componentUtil.enableSubTypeDefaulter(ComponentModel); // Add capability of ComponentModel.topologicalTravel. componentUtil.enableTopologicalTravel(ComponentModel, getDependencies); function getDependencies(componentType) { var deps = []; zrUtil.each(ComponentModel.getClassesByMainType(componentType), function (Clazz) { arrayPush.apply(deps, Clazz.prototype.dependencies || []); }); // Ensure main type return zrUtil.map(deps, function (type) { return clazzUtil.parseClassType(type).main; }); } zrUtil.mixin(ComponentModel, __webpack_require__(22)); module.exports = ComponentModel; /***/ }, /* 20 */ /***/ function(module, exports, __webpack_require__) { var zrUtil = __webpack_require__(4); var clazz = __webpack_require__(13); var parseClassType = clazz.parseClassType; var base = 0; var componentUtil = {}; var DELIMITER = '_'; /** * @public * @param {string} type * @return {string} */ componentUtil.getUID = function (type) { // Considering the case of crossing js context, // use Math.random to make id as unique as possible. return [(type || ''), base++, Math.random()].join(DELIMITER); }; /** * @inner */ componentUtil.enableSubTypeDefaulter = function (entity) { var subTypeDefaulters = {}; entity.registerSubTypeDefaulter = function (componentType, defaulter) { componentType = parseClassType(componentType); subTypeDefaulters[componentType.main] = defaulter; }; entity.determineSubType = function (componentType, option) { var type = option.type; if (!type) { var componentTypeMain = parseClassType(componentType).main; if (entity.hasSubTypes(componentType) && subTypeDefaulters[componentTypeMain]) { type = subTypeDefaulters[componentTypeMain](option); } } return type; }; return entity; }; /** * Topological travel on Activity Network (Activity On Vertices). * Dependencies is defined in Model.prototype.dependencies, like ['xAxis', 'yAxis']. * * If 'xAxis' or 'yAxis' is absent in componentTypeList, just ignore it in topology. * * If there is circle dependencey, Error will be thrown. * */ componentUtil.enableTopologicalTravel = function (entity, dependencyGetter) { /** * @public * @param {Array.} targetNameList Target Component type list. * Can be ['aa', 'bb', 'aa.xx'] * @param {Array.} fullNameList By which we can build dependency graph. * @param {Function} callback Params: componentType, dependencies. * @param {Object} context Scope of callback. */ entity.topologicalTravel = function (targetNameList, fullNameList, callback, context) { if (!targetNameList.length) { return; } var result = makeDepndencyGraph(fullNameList); var graph = result.graph; var stack = result.noEntryList; var targetNameSet = {}; zrUtil.each(targetNameList, function (name) { targetNameSet[name] = true; }); while (stack.length) { var currComponentType = stack.pop(); var currVertex = graph[currComponentType]; var isInTargetNameSet = !!targetNameSet[currComponentType]; if (isInTargetNameSet) { callback.call(context, currComponentType, currVertex.originalDeps.slice()); delete targetNameSet[currComponentType]; } zrUtil.each( currVertex.successor, isInTargetNameSet ? removeEdgeAndAdd : removeEdge ); } zrUtil.each(targetNameSet, function () { throw new Error('Circle dependency may exists'); }); function removeEdge(succComponentType) { graph[succComponentType].entryCount--; if (graph[succComponentType].entryCount === 0) { stack.push(succComponentType); } } // Consider this case: legend depends on series, and we call // chart.setOption({series: [...]}), where only series is in option. // If we do not have 'removeEdgeAndAdd', legendModel.mergeOption will // not be called, but only sereis.mergeOption is called. Thus legend // have no chance to update its local record about series (like which // name of series is available in legend). function removeEdgeAndAdd(succComponentType) { targetNameSet[succComponentType] = true; removeEdge(succComponentType); } }; /** * DepndencyGraph: {Object} * key: conponentType, * value: { * successor: [conponentTypes...], * originalDeps: [conponentTypes...], * entryCount: {number} * } */ function makeDepndencyGraph(fullNameList) { var graph = {}; var noEntryList = []; zrUtil.each(fullNameList, function (name) { var thisItem = createDependencyGraphItem(graph, name); var originalDeps = thisItem.originalDeps = dependencyGetter(name); var availableDeps = getAvailableDependencies(originalDeps, fullNameList); thisItem.entryCount = availableDeps.length; if (thisItem.entryCount === 0) { noEntryList.push(name); } zrUtil.each(availableDeps, function (dependentName) { if (zrUtil.indexOf(thisItem.predecessor, dependentName) < 0) { thisItem.predecessor.push(dependentName); } var thatItem = createDependencyGraphItem(graph, dependentName); if (zrUtil.indexOf(thatItem.successor, dependentName) < 0) { thatItem.successor.push(name); } }); }); return {graph: graph, noEntryList: noEntryList}; } function createDependencyGraphItem(graph, name) { if (!graph[name]) { graph[name] = {predecessor: [], successor: []}; } return graph[name]; } function getAvailableDependencies(originalDeps, fullNameList) { var availableDeps = []; zrUtil.each(originalDeps, function (dep) { zrUtil.indexOf(fullNameList, dep) >= 0 && availableDeps.push(dep); }); return availableDeps; } }; module.exports = componentUtil; /***/ }, /* 21 */ /***/ function(module, exports, __webpack_require__) { 'use strict'; // Layout helpers for each component positioning var zrUtil = __webpack_require__(4); var BoundingRect = __webpack_require__(9); var numberUtil = __webpack_require__(7); var formatUtil = __webpack_require__(6); var parsePercent = numberUtil.parsePercent; var each = zrUtil.each; var layout = {}; var LOCATION_PARAMS = layout.LOCATION_PARAMS = [ 'left', 'right', 'top', 'bottom', 'width', 'height' ]; function boxLayout(orient, group, gap, maxWidth, maxHeight) { var x = 0; var y = 0; if (maxWidth == null) { maxWidth = Infinity; } if (maxHeight == null) { maxHeight = Infinity; } var currentLineMaxSize = 0; group.eachChild(function (child, idx) { var position = child.position; var rect = child.getBoundingRect(); var nextChild = group.childAt(idx + 1); var nextChildRect = nextChild && nextChild.getBoundingRect(); var nextX; var nextY; if (orient === 'horizontal') { var moveX = rect.width + (nextChildRect ? (-nextChildRect.x + rect.x) : 0); nextX = x + moveX; // Wrap when width exceeds maxWidth or meet a `newline` group if (nextX > maxWidth || child.newline) { x = 0; nextX = moveX; y += currentLineMaxSize + gap; currentLineMaxSize = rect.height; } else { currentLineMaxSize = Math.max(currentLineMaxSize, rect.height); } } else { var moveY = rect.height + (nextChildRect ? (-nextChildRect.y + rect.y) : 0); nextY = y + moveY; // Wrap when width exceeds maxHeight or meet a `newline` group if (nextY > maxHeight || child.newline) { x += currentLineMaxSize + gap; y = 0; nextY = moveY; currentLineMaxSize = rect.width; } else { currentLineMaxSize = Math.max(currentLineMaxSize, rect.width); } } if (child.newline) { return; } position[0] = x; position[1] = y; orient === 'horizontal' ? (x = nextX + gap) : (y = nextY + gap); }); } /** * VBox or HBox layouting * @param {string} orient * @param {module:zrender/container/Group} group * @param {number} gap * @param {number} [width=Infinity] * @param {number} [height=Infinity] */ layout.box = boxLayout; /** * VBox layouting * @param {module:zrender/container/Group} group * @param {number} gap * @param {number} [width=Infinity] * @param {number} [height=Infinity] */ layout.vbox = zrUtil.curry(boxLayout, 'vertical'); /** * HBox layouting * @param {module:zrender/container/Group} group * @param {number} gap * @param {number} [width=Infinity] * @param {number} [height=Infinity] */ layout.hbox = zrUtil.curry(boxLayout, 'horizontal'); /** * If x or x2 is not specified or 'center' 'left' 'right', * the width would be as long as possible. * If y or y2 is not specified or 'middle' 'top' 'bottom', * the height would be as long as possible. * * @param {Object} positionInfo * @param {number|string} [positionInfo.x] * @param {number|string} [positionInfo.y] * @param {number|string} [positionInfo.x2] * @param {number|string} [positionInfo.y2] * @param {Object} containerRect * @param {string|number} margin * @return {Object} {width, height} */ layout.getAvailableSize = function (positionInfo, containerRect, margin) { var containerWidth = containerRect.width; var containerHeight = containerRect.height; var x = parsePercent(positionInfo.x, containerWidth); var y = parsePercent(positionInfo.y, containerHeight); var x2 = parsePercent(positionInfo.x2, containerWidth); var y2 = parsePercent(positionInfo.y2, containerHeight); (isNaN(x) || isNaN(parseFloat(positionInfo.x))) && (x = 0); (isNaN(x2) || isNaN(parseFloat(positionInfo.x2))) && (x2 = containerWidth); (isNaN(y) || isNaN(parseFloat(positionInfo.y))) && (y = 0); (isNaN(y2) || isNaN(parseFloat(positionInfo.y2))) && (y2 = containerHeight); margin = formatUtil.normalizeCssArray(margin || 0); return { width: Math.max(x2 - x - margin[1] - margin[3], 0), height: Math.max(y2 - y - margin[0] - margin[2], 0) }; }; /** * Parse position info. * * @param {Object} positionInfo * @param {number|string} [positionInfo.left] * @param {number|string} [positionInfo.top] * @param {number|string} [positionInfo.right] * @param {number|string} [positionInfo.bottom] * @param {number|string} [positionInfo.width] * @param {number|string} [positionInfo.height] * @param {number|string} [positionInfo.aspect] Aspect is width / height * @param {Object} containerRect * @param {string|number} [margin] * * @return {module:zrender/core/BoundingRect} */ layout.getLayoutRect = function ( positionInfo, containerRect, margin ) { margin = formatUtil.normalizeCssArray(margin || 0); var containerWidth = containerRect.width; var containerHeight = containerRect.height; var left = parsePercent(positionInfo.left, containerWidth); var top = parsePercent(positionInfo.top, containerHeight); var right = parsePercent(positionInfo.right, containerWidth); var bottom = parsePercent(positionInfo.bottom, containerHeight); var width = parsePercent(positionInfo.width, containerWidth); var height = parsePercent(positionInfo.height, containerHeight); var verticalMargin = margin[2] + margin[0]; var horizontalMargin = margin[1] + margin[3]; var aspect = positionInfo.aspect; // If width is not specified, calculate width from left and right if (isNaN(width)) { width = containerWidth - right - horizontalMargin - left; } if (isNaN(height)) { height = containerHeight - bottom - verticalMargin - top; } // If width and height are not given // 1. Graph should not exceeds the container // 2. Aspect must be keeped // 3. Graph should take the space as more as possible if (isNaN(width) && isNaN(height)) { if (aspect > containerWidth / containerHeight) { width = containerWidth * 0.8; } else { height = containerHeight * 0.8; } } if (aspect != null) { // Calculate width or height with given aspect if (isNaN(width)) { width = aspect * height; } if (isNaN(height)) { height = width / aspect; } } // If left is not specified, calculate left from right and width if (isNaN(left)) { left = containerWidth - right - width - horizontalMargin; } if (isNaN(top)) { top = containerHeight - bottom - height - verticalMargin; } // Align left and top switch (positionInfo.left || positionInfo.right) { case 'center': left = containerWidth / 2 - width / 2 - margin[3]; break; case 'right': left = containerWidth - width - horizontalMargin; break; } switch (positionInfo.top || positionInfo.bottom) { case 'middle': case 'center': top = containerHeight / 2 - height / 2 - margin[0]; break; case 'bottom': top = containerHeight - height - verticalMargin; break; } // If something is wrong and left, top, width, height are calculated as NaN left = left || 0; top = top || 0; if (isNaN(width)) { // Width may be NaN if only one value is given except width width = containerWidth - left - (right || 0); } if (isNaN(height)) { // Height may be NaN if only one value is given except height height = containerHeight - top - (bottom || 0); } var rect = new BoundingRect(left + margin[3], top + margin[0], width, height); rect.margin = margin; return rect; }; /** * Position a zr element in viewport * Group position is specified by either * {left, top}, {right, bottom} * If all properties exists, right and bottom will be igonred. * * Logic: * 1. Scale (against origin point in parent coord) * 2. Rotate (against origin point in parent coord) * 3. Traslate (with el.position by this method) * So this method only fixes the last step 'Traslate', which does not affect * scaling and rotating. * * If be called repeatly with the same input el, the same result will be gotten. * * @param {module:zrender/Element} el Should have `getBoundingRect` method. * @param {Object} positionInfo * @param {number|string} [positionInfo.left] * @param {number|string} [positionInfo.top] * @param {number|string} [positionInfo.right] * @param {number|string} [positionInfo.bottom] * @param {Object} containerRect * @param {string|number} margin * @param {Object} [opt] * @param {Array.} [opt.hv=[1,1]] Only horizontal or only vertical. * @param {Array.} [opt.boundingMode='all'] * Specify how to calculate boundingRect when locating. * 'all': Position the boundingRect that is transformed and uioned * both itself and its descendants. * This mode simplies confine the elements in the bounding * of their container (e.g., using 'right: 0'). * 'raw': Position the boundingRect that is not transformed and only itself. * This mode is useful when you want a element can overflow its * container. (Consider a rotated circle needs to be located in a corner.) * In this mode positionInfo.width/height can only be number. */ layout.positionElement = function (el, positionInfo, containerRect, margin, opt) { var h = !opt || !opt.hv || opt.hv[0]; var v = !opt || !opt.hv || opt.hv[1]; var boundingMode = opt && opt.boundingMode || 'all'; if (!h && !v) { return; } var rect; if (boundingMode === 'raw') { rect = el.type === 'group' ? new BoundingRect(0, 0, +positionInfo.width || 0, +positionInfo.height || 0) : el.getBoundingRect(); } else { rect = el.getBoundingRect(); if (el.needLocalTransform()) { var transform = el.getLocalTransform(); // Notice: raw rect may be inner object of el, // which should not be modified. rect = rect.clone(); rect.applyTransform(transform); } } positionInfo = layout.getLayoutRect( zrUtil.defaults( {width: rect.width, height: rect.height}, positionInfo ), containerRect, margin ); // Because 'tranlate' is the last step in transform // (see zrender/core/Transformable#getLocalTransfrom), // we can just only modify el.position to get final result. var elPos = el.position; var dx = h ? positionInfo.x - rect.x : 0; var dy = v ? positionInfo.y - rect.y : 0; el.attr('position', boundingMode === 'raw' ? [dx, dy] : [elPos[0] + dx, elPos[1] + dy]); }; /** * Consider Case: * When defulat option has {left: 0, width: 100}, and we set {right: 0} * through setOption or media query, using normal zrUtil.merge will cause * {right: 0} does not take effect. * * @example * ComponentModel.extend({ * init: function () { * ... * var inputPositionParams = layout.getLayoutParams(option); * this.mergeOption(inputPositionParams); * }, * mergeOption: function (newOption) { * newOption && zrUtil.merge(thisOption, newOption, true); * layout.mergeLayoutParam(thisOption, newOption); * } * }); * * @param {Object} targetOption * @param {Object} newOption * @param {Object|string} [opt] * @param {boolean} [opt.ignoreSize=false] Some component must has width and height. */ layout.mergeLayoutParam = function (targetOption, newOption, opt) { !zrUtil.isObject(opt) && (opt = {}); var hNames = ['width', 'left', 'right']; // Order by priority. var vNames = ['height', 'top', 'bottom']; // Order by priority. var hResult = merge(hNames); var vResult = merge(vNames); copy(hNames, targetOption, hResult); copy(vNames, targetOption, vResult); function merge(names) { var newParams = {}; var newValueCount = 0; var merged = {}; var mergedValueCount = 0; var enoughParamNumber = opt.ignoreSize ? 1 : 2; each(names, function (name) { merged[name] = targetOption[name]; }); each(names, function (name) { // Consider case: newOption.width is null, which is // set by user for removing width setting. hasProp(newOption, name) && (newParams[name] = merged[name] = newOption[name]); hasValue(newParams, name) && newValueCount++; hasValue(merged, name) && mergedValueCount++; }); // Case: newOption: {width: ..., right: ...}, // or targetOption: {right: ...} and newOption: {width: ...}, // There is no conflict when merged only has params count // little than enoughParamNumber. if (mergedValueCount === enoughParamNumber || !newValueCount) { return merged; } // Case: newOption: {width: ..., right: ...}, // Than we can make sure user only want those two, and ignore // all origin params in targetOption. else if (newValueCount >= enoughParamNumber) { return newParams; } else { // Chose another param from targetOption by priority. // When 'ignoreSize', enoughParamNumber is 1 and those will not happen. for (var i = 0; i < names.length; i++) { var name = names[i]; if (!hasProp(newParams, name) && hasProp(targetOption, name)) { newParams[name] = targetOption[name]; break; } } return newParams; } } function hasProp(obj, name) { return obj.hasOwnProperty(name); } function hasValue(obj, name) { return obj[name] != null && obj[name] !== 'auto'; } function copy(names, target, source) { each(names, function (name) { target[name] = source[name]; }); } }; /** * Retrieve 'left', 'right', 'top', 'bottom', 'width', 'height' from object. * @param {Object} source * @return {Object} Result contains those props. */ layout.getLayoutParams = function (source) { return layout.copyLayoutParams({}, source); }; /** * Retrieve 'left', 'right', 'top', 'bottom', 'width', 'height' from object. * @param {Object} source * @return {Object} Result contains those props. */ layout.copyLayoutParams = function (target, source) { source && target && each(LOCATION_PARAMS, function (name) { source.hasOwnProperty(name) && (target[name] = source[name]); }); return target; }; module.exports = layout; /***/ }, /* 22 */ /***/ function(module, exports) { module.exports = { getBoxLayoutParams: function () { return { left: this.get('left'), top: this.get('top'), right: this.get('right'), bottom: this.get('bottom'), width: this.get('width'), height: this.get('height') }; } }; /***/ }, /* 23 */ /***/ function(module, exports) { var platform = ''; // Navigator not exists in node if (typeof navigator !== 'undefined') { platform = navigator.platform || ''; } module.exports = { // 全图默认背景 // backgroundColor: 'rgba(0,0,0,0)', // https://dribbble.com/shots/1065960-Infographic-Pie-chart-visualization // color: ['#5793f3', '#d14a61', '#fd9c35', '#675bba', '#fec42c', '#dd4444', '#d4df5a', '#cd4870'], // 浅色 // color: ['#bcd3bb', '#e88f70', '#edc1a5', '#9dc5c8', '#e1e8c8', '#7b7c68', '#e5b5b5', '#f0b489', '#928ea8', '#bda29a'], // color: ['#cc5664', '#9bd6ec', '#ea946e', '#8acaaa', '#f1ec64', '#ee8686', '#a48dc1', '#5da6bc', '#b9dcae'], // 深色 color: ['#c23531','#2f4554', '#61a0a8', '#d48265', '#91c7ae','#749f83', '#ca8622', '#bda29a','#6e7074', '#546570', '#c4ccd3'], // 默认需要 Grid 配置项 // grid: {}, // 主题,主题 textStyle: { // color: '#000', // decoration: 'none', // PENDING fontFamily: platform.match(/^Win/) ? 'Microsoft YaHei' : 'sans-serif', // fontFamily: 'Arial, Verdana, sans-serif', fontSize: 12, fontStyle: 'normal', fontWeight: 'normal' }, // http://blogs.adobe.com/webplatform/2014/02/24/using-blend-modes-in-html-canvas/ // https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/globalCompositeOperation // Default is source-over blendMode: null, animation: true, animationDuration: 1000, animationDurationUpdate: 300, animationEasing: 'exponentialOut', animationEasingUpdate: 'cubicOut', animationThreshold: 2000, // Configuration for progressive/incremental rendering progressiveThreshold: 3000, progressive: 400, // Threshold of if use single hover layer to optimize. // It is recommended that `hoverLayerThreshold` is equivalent to or less than // `progressiveThreshold`, otherwise hover will cause restart of progressive, // which is unexpected. // see example . hoverLayerThreshold: 3000 }; /***/ }, /* 24 */ /***/ function(module, exports) { module.exports = { clearColorPalette: function () { this._colorIdx = 0; this._colorNameMap = {}; }, getColorFromPalette: function (name, scope) { scope = scope || this; var colorIdx = scope._colorIdx || 0; var colorNameMap = scope._colorNameMap || (scope._colorNameMap = {}); if (colorNameMap[name]) { return colorNameMap[name]; } var colorPalette = this.get('color', true) || []; if (!colorPalette.length) { return; } var color = colorPalette[colorIdx]; if (name) { colorNameMap[name] = color; } scope._colorIdx = (colorIdx + 1) % colorPalette.length; return color; } }; /***/ }, /* 25 */ /***/ function(module, exports, __webpack_require__) { 'use strict'; var zrUtil = __webpack_require__(4); var echartsAPIList = [ 'getDom', 'getZr', 'getWidth', 'getHeight', 'dispatchAction', 'isDisposed', 'on', 'off', 'getDataURL', 'getConnectedDataURL', 'getModel', 'getOption' ]; function ExtensionAPI(chartInstance) { zrUtil.each(echartsAPIList, function (name) { this[name] = zrUtil.bind(chartInstance[name], chartInstance); }, this); } module.exports = ExtensionAPI; /***/ }, /* 26 */ /***/ function(module, exports, __webpack_require__) { 'use strict'; var zrUtil = __webpack_require__(4); /** * Interface of Coordinate System Class * * create: * @param {module:echarts/model/Global} ecModel * @param {module:echarts/ExtensionAPI} api * @return {Object} coordinate system instance * * update: * @param {module:echarts/model/Global} ecModel * @param {module:echarts/ExtensionAPI} api * * convertToPixel: * convertFromPixel: * These two methods is also responsible for determine whether this * coodinate system is applicable to the given `finder`. * Each coordinate system will be tried, util one returns none * null/undefined value. * @param {module:echarts/model/Global} ecModel * @param {Object} finder * @param {Array|number} value * @return {Array|number} convert result. * * containPoint: * @param {Array.} point In pixel coordinate system. * @return {boolean} */ var coordinateSystemCreators = {}; function CoordinateSystemManager() { this._coordinateSystems = []; } CoordinateSystemManager.prototype = { constructor: CoordinateSystemManager, create: function (ecModel, api) { var coordinateSystems = []; zrUtil.each(coordinateSystemCreators, function (creater, type) { var list = creater.create(ecModel, api); coordinateSystems = coordinateSystems.concat(list || []); }); this._coordinateSystems = coordinateSystems; }, update: function (ecModel, api) { zrUtil.each(this._coordinateSystems, function (coordSys) { // FIXME MUST have coordSys.update && coordSys.update(ecModel, api); }); }, getCoordinateSystems: function () { return this._coordinateSystems.slice(); } }; CoordinateSystemManager.register = function (type, coordinateSystemCreator) { coordinateSystemCreators[type] = coordinateSystemCreator; }; CoordinateSystemManager.get = function (type) { return coordinateSystemCreators[type]; }; module.exports = CoordinateSystemManager; /***/ }, /* 27 */ /***/ function(module, exports, __webpack_require__) { /** * ECharts option manager * * @module {echarts/model/OptionManager} */ var zrUtil = __webpack_require__(4); var modelUtil = __webpack_require__(5); var ComponentModel = __webpack_require__(19); var each = zrUtil.each; var clone = zrUtil.clone; var map = zrUtil.map; var merge = zrUtil.merge; var QUERY_REG = /^(min|max)?(.+)$/; /** * TERM EXPLANATIONS: * * [option]: * * An object that contains definitions of components. For example: * var option = { * title: {...}, * legend: {...}, * visualMap: {...}, * series: [ * {data: [...]}, * {data: [...]}, * ... * ] * }; * * [rawOption]: * * An object input to echarts.setOption. 'rawOption' may be an * 'option', or may be an object contains multi-options. For example: * var option = { * baseOption: { * title: {...}, * legend: {...}, * series: [ * {data: [...]}, * {data: [...]}, * ... * ] * }, * timeline: {...}, * options: [ * {title: {...}, series: {data: [...]}}, * {title: {...}, series: {data: [...]}}, * ... * ], * media: [ * { * query: {maxWidth: 320}, * option: {series: {x: 20}, visualMap: {show: false}} * }, * { * query: {minWidth: 320, maxWidth: 720}, * option: {series: {x: 500}, visualMap: {show: true}} * }, * { * option: {series: {x: 1200}, visualMap: {show: true}} * } * ] * }; * * @alias module:echarts/model/OptionManager * @param {module:echarts/ExtensionAPI} api */ function OptionManager(api) { /** * @private * @type {module:echarts/ExtensionAPI} */ this._api = api; /** * @private * @type {Array.} */ this._timelineOptions = []; /** * @private * @type {Array.} */ this._mediaList = []; /** * @private * @type {Object} */ this._mediaDefault; /** * -1, means default. * empty means no media. * @private * @type {Array.} */ this._currentMediaIndices = []; /** * @private * @type {Object} */ this._optionBackup; /** * @private * @type {Object} */ this._newBaseOption; } // timeline.notMerge is not supported in ec3. Firstly there is rearly // case that notMerge is needed. Secondly supporting 'notMerge' requires // rawOption cloned and backuped when timeline changed, which does no // good to performance. What's more, that both timeline and setOption // method supply 'notMerge' brings complex and some problems. // Consider this case: // (step1) chart.setOption({timeline: {notMerge: false}, ...}, false); // (step2) chart.setOption({timeline: {notMerge: true}, ...}, false); OptionManager.prototype = { constructor: OptionManager, /** * @public * @param {Object} rawOption Raw option. * @param {module:echarts/model/Global} ecModel * @param {Array.} optionPreprocessorFuncs * @return {Object} Init option */ setOption: function (rawOption, optionPreprocessorFuncs) { rawOption = clone(rawOption, true); // FIXME // 如果 timeline options 或者 media 中设置了某个属性,而baseOption中没有设置,则进行警告。 var oldOptionBackup = this._optionBackup; var newParsedOption = parseRawOption.call( this, rawOption, optionPreprocessorFuncs, !oldOptionBackup ); this._newBaseOption = newParsedOption.baseOption; // For setOption at second time (using merge mode); if (oldOptionBackup) { // Only baseOption can be merged. mergeOption(oldOptionBackup.baseOption, newParsedOption.baseOption); // For simplicity, timeline options and media options do not support merge, // that is, if you `setOption` twice and both has timeline options, the latter // timeline opitons will not be merged to the formers, but just substitude them. if (newParsedOption.timelineOptions.length) { oldOptionBackup.timelineOptions = newParsedOption.timelineOptions; } if (newParsedOption.mediaList.length) { oldOptionBackup.mediaList = newParsedOption.mediaList; } if (newParsedOption.mediaDefault) { oldOptionBackup.mediaDefault = newParsedOption.mediaDefault; } } else { this._optionBackup = newParsedOption; } }, /** * @param {boolean} isRecreate * @return {Object} */ mountOption: function (isRecreate) { var optionBackup = this._optionBackup; // TODO // 如果没有reset功能则不clone。 this._timelineOptions = map(optionBackup.timelineOptions, clone); this._mediaList = map(optionBackup.mediaList, clone); this._mediaDefault = clone(optionBackup.mediaDefault); this._currentMediaIndices = []; return clone(isRecreate // this._optionBackup.baseOption, which is created at the first `setOption` // called, and is merged into every new option by inner method `mergeOption` // each time `setOption` called, can be only used in `isRecreate`, because // its reliability is under suspicion. In other cases option merge is // performed by `model.mergeOption`. ? optionBackup.baseOption : this._newBaseOption ); }, /** * @param {module:echarts/model/Global} ecModel * @return {Object} */ getTimelineOption: function (ecModel) { var option; var timelineOptions = this._timelineOptions; if (timelineOptions.length) { // getTimelineOption can only be called after ecModel inited, // so we can get currentIndex from timelineModel. var timelineModel = ecModel.getComponent('timeline'); if (timelineModel) { option = clone( timelineOptions[timelineModel.getCurrentIndex()], true ); } } return option; }, /** * @param {module:echarts/model/Global} ecModel * @return {Array.} */ getMediaOption: function (ecModel) { var ecWidth = this._api.getWidth(); var ecHeight = this._api.getHeight(); var mediaList = this._mediaList; var mediaDefault = this._mediaDefault; var indices = []; var result = []; // No media defined. if (!mediaList.length && !mediaDefault) { return result; } // Multi media may be applied, the latter defined media has higher priority. for (var i = 0, len = mediaList.length; i < len; i++) { if (applyMediaQuery(mediaList[i].query, ecWidth, ecHeight)) { indices.push(i); } } // FIXME // 是否mediaDefault应该强制用户设置,否则可能修改不能回归。 if (!indices.length && mediaDefault) { indices = [-1]; } if (indices.length && !indicesEquals(indices, this._currentMediaIndices)) { result = map(indices, function (index) { return clone( index === -1 ? mediaDefault.option : mediaList[index].option ); }); } // Otherwise return nothing. this._currentMediaIndices = indices; return result; } }; function parseRawOption(rawOption, optionPreprocessorFuncs, isNew) { var timelineOptions = []; var mediaList = []; var mediaDefault; var baseOption; // Compatible with ec2. var timelineOpt = rawOption.timeline; if (rawOption.baseOption) { baseOption = rawOption.baseOption; } // For timeline if (timelineOpt || rawOption.options) { baseOption = baseOption || {}; timelineOptions = (rawOption.options || []).slice(); } // For media query if (rawOption.media) { baseOption = baseOption || {}; var media = rawOption.media; each(media, function (singleMedia) { if (singleMedia && singleMedia.option) { if (singleMedia.query) { mediaList.push(singleMedia); } else if (!mediaDefault) { // Use the first media default. mediaDefault = singleMedia; } } }); } // For normal option if (!baseOption) { baseOption = rawOption; } // Set timelineOpt to baseOption in ec3, // which is convenient for merge option. if (!baseOption.timeline) { baseOption.timeline = timelineOpt; } // Preprocess. each([baseOption].concat(timelineOptions) .concat(zrUtil.map(mediaList, function (media) { return media.option; })), function (option) { each(optionPreprocessorFuncs, function (preProcess) { preProcess(option, isNew); }); } ); return { baseOption: baseOption, timelineOptions: timelineOptions, mediaDefault: mediaDefault, mediaList: mediaList }; } /** * @see * Support: width, height, aspectRatio * Can use max or min as prefix. */ function applyMediaQuery(query, ecWidth, ecHeight) { var realMap = { width: ecWidth, height: ecHeight, aspectratio: ecWidth / ecHeight // lowser case for convenientce. }; var applicatable = true; zrUtil.each(query, function (value, attr) { var matched = attr.match(QUERY_REG); if (!matched || !matched[1] || !matched[2]) { return; } var operator = matched[1]; var realAttr = matched[2].toLowerCase(); if (!compare(realMap[realAttr], value, operator)) { applicatable = false; } }); return applicatable; } function compare(real, expect, operator) { if (operator === 'min') { return real >= expect; } else if (operator === 'max') { return real <= expect; } else { // Equals return real === expect; } } function indicesEquals(indices1, indices2) { // indices is always order by asc and has only finite number. return indices1.join(',') === indices2.join(','); } /** * Consider case: * `chart.setOption(opt1);` * Then user do some interaction like dataZoom, dataView changing. * `chart.setOption(opt2);` * Then user press 'reset button' in toolbox. * * After doing that all of the interaction effects should be reset, the * chart should be the same as the result of invoke * `chart.setOption(opt1); chart.setOption(opt2);`. * * Although it is not able ensure that * `chart.setOption(opt1); chart.setOption(opt2);` is equivalents to * `chart.setOption(merge(opt1, opt2));` exactly, * this might be the only simple way to implement that feature. * * MEMO: We've considered some other approaches: * 1. Each model handle its self restoration but not uniform treatment. * (Too complex in logic and error-prone) * 2. Use a shadow ecModel. (Performace expensive) */ function mergeOption(oldOption, newOption) { newOption = newOption || {}; each(newOption, function (newCptOpt, mainType) { if (newCptOpt == null) { return; } var oldCptOpt = oldOption[mainType]; if (!ComponentModel.hasClass(mainType)) { oldOption[mainType] = merge(oldCptOpt, newCptOpt, true); } else { newCptOpt = modelUtil.normalizeToArray(newCptOpt); oldCptOpt = modelUtil.normalizeToArray(oldCptOpt); var mapResult = modelUtil.mappingToExists(oldCptOpt, newCptOpt); oldOption[mainType] = map(mapResult, function (item) { return (item.option && item.exist) ? merge(item.exist, item.option, true) : (item.exist || item.option); }); } }); } module.exports = OptionManager; /***/ }, /* 28 */ /***/ function(module, exports, __webpack_require__) { 'use strict'; var zrUtil = __webpack_require__(4); var formatUtil = __webpack_require__(6); var modelUtil = __webpack_require__(5); var ComponentModel = __webpack_require__(19); var colorPaletteMixin = __webpack_require__(24); var env = __webpack_require__(2); var layout = __webpack_require__(21); var encodeHTML = formatUtil.encodeHTML; var addCommas = formatUtil.addCommas; var SeriesModel = ComponentModel.extend({ type: 'series.__base__', /** * @readOnly */ seriesIndex: 0, // coodinateSystem will be injected in the echarts/CoordinateSystem coordinateSystem: null, /** * @type {Object} * @protected */ defaultOption: null, /** * Data provided for legend * @type {Function} */ // PENDING legendDataProvider: null, /** * Access path of color for visual */ visualColorAccessPath: 'itemStyle.normal.color', /** * Support merge layout params. * Only support 'box' now (left/right/top/bottom/width/height). * @type {string|Object} Object can be {ignoreSize: true} * @readOnly */ layoutMode: null, init: function (option, parentModel, ecModel, extraOpt) { /** * @type {number} * @readOnly */ this.seriesIndex = this.componentIndex; this.mergeDefaultAndTheme(option, ecModel); /** * @type {module:echarts/data/List|module:echarts/data/Tree|module:echarts/data/Graph} * @private */ this._dataBeforeProcessed = this.getInitialData(option, ecModel); // If we reverse the order (make this._data firstly, and then make // this._dataBeforeProcessed by cloneShallow), cloneShallow will // cause this._data.graph.data !== this._data when using // module:echarts/data/Graph or module:echarts/data/Tree. // See module:echarts/data/helper/linkList this._data = this._dataBeforeProcessed.cloneShallow(); }, /** * Util for merge default and theme to option * @param {Object} option * @param {module:echarts/model/Global} ecModel */ mergeDefaultAndTheme: function (option, ecModel) { var layoutMode = this.layoutMode; var inputPositionParams = layoutMode ? layout.getLayoutParams(option) : {}; zrUtil.merge( option, ecModel.getTheme().get(this.subType) ); zrUtil.merge(option, this.getDefaultOption()); // Default label emphasis `position` and `show` // FIXME Set label in mergeOption modelUtil.defaultEmphasis(option.label, modelUtil.LABEL_OPTIONS); this.fillDataTextStyle(option.data); if (layoutMode) { layout.mergeLayoutParam(option, inputPositionParams, layoutMode); } }, mergeOption: function (newSeriesOption, ecModel) { newSeriesOption = zrUtil.merge(this.option, newSeriesOption, true); this.fillDataTextStyle(newSeriesOption.data); var layoutMode = this.layoutMode; if (layoutMode) { layout.mergeLayoutParam(this.option, newSeriesOption, layoutMode); } var data = this.getInitialData(newSeriesOption, ecModel); // TODO Merge data? if (data) { this._data = data; this._dataBeforeProcessed = data.cloneShallow(); } }, fillDataTextStyle: function (data) { // Default data label emphasis `position` and `show` // FIXME Tree structure data ? // FIXME Performance ? if (data) { for (var i = 0; i < data.length; i++) { if (data[i] && data[i].label) { modelUtil.defaultEmphasis(data[i].label, modelUtil.LABEL_OPTIONS); } } } }, /** * Init a data structure from data related option in series * Must be overwritten */ getInitialData: function () {}, /** * @param {string} [dataType] * @return {module:echarts/data/List} */ getData: function (dataType) { return dataType == null ? this._data : this._data.getLinkedData(dataType); }, /** * @param {module:echarts/data/List} data */ setData: function (data) { this._data = data; }, /** * Get data before processed * @return {module:echarts/data/List} */ getRawData: function () { return this._dataBeforeProcessed; }, /** * Coord dimension to data dimension. * * By default the result is the same as dimensions of series data. * But in some series data dimensions are different from coord dimensions (i.e. * candlestick and boxplot). Override this method to handle those cases. * * Coord dimension to data dimension can be one-to-many * * @param {string} coordDim * @return {Array.} dimensions on the axis. */ coordDimToDataDim: function (coordDim) { return [coordDim]; }, /** * Convert data dimension to coord dimension. * * @param {string|number} dataDim * @return {string} */ dataDimToCoordDim: function (dataDim) { return dataDim; }, /** * Get base axis if has coordinate system and has axis. * By default use coordSys.getBaseAxis(); * Can be overrided for some chart. * @return {type} description */ getBaseAxis: function () { var coordSys = this.coordinateSystem; return coordSys && coordSys.getBaseAxis && coordSys.getBaseAxis(); }, // FIXME /** * Default tooltip formatter * * @param {number} dataIndex * @param {boolean} [multipleSeries=false] * @param {number} [dataType] */ formatTooltip: function (dataIndex, multipleSeries, dataType) { function formatArrayValue(value) { var result = []; zrUtil.each(value, function (val, idx) { var dimInfo = data.getDimensionInfo(idx); var dimType = dimInfo && dimInfo.type; var valStr; if (dimType === 'ordinal') { valStr = val + ''; } else if (dimType === 'time') { valStr = multipleSeries ? '' : formatUtil.formatTime('yyyy/MM/dd hh:mm:ss', val); } else { valStr = addCommas(val); } valStr && result.push(valStr); }); return result.join(', '); } var data = this._data; var value = this.getRawValue(dataIndex); var formattedValue = zrUtil.isArray(value) ? formatArrayValue(value) : addCommas(value); var name = data.getName(dataIndex); var color = data.getItemVisual(dataIndex, 'color'); if (zrUtil.isObject(color) && color.colorStops) { color = (color.colorStops[0] || {}).color; } color = color || 'transparent'; var colorEl = ''; var seriesName = this.name; // FIXME if (seriesName === '\0-') { // Not show '-' seriesName = ''; } return !multipleSeries ? ((seriesName && encodeHTML(seriesName) + '
') + colorEl + (name ? encodeHTML(name) + ' : ' + formattedValue : formattedValue) ) : (colorEl + encodeHTML(this.name) + ' : ' + formattedValue); }, /** * @return {boolean} */ ifEnableAnimation: function () { if (env.node) { return false; } var animationEnabled = this.getShallow('animation'); if (animationEnabled) { if (this.getData().count() > this.getShallow('animationThreshold')) { animationEnabled = false; } } return animationEnabled; }, restoreData: function () { this._data = this._dataBeforeProcessed.cloneShallow(); }, getColorFromPalette: function (name, scope) { var ecModel = this.ecModel; // PENDING var color = colorPaletteMixin.getColorFromPalette.call(this, name, scope); if (!color) { color = ecModel.getColorFromPalette(name, scope); } return color; }, /** * Get data indices for show tooltip content. See tooltip. * @abstract * @param {Array.|string} dim * @param {Array.} value * @param {module:echarts/coord/single/SingleAxis} baseAxis * @return {Array.} data indices. */ getAxisTooltipDataIndex: null, /** * See tooltip. * @abstract * @param {number} dataIndex * @return {Array.} Point of tooltip. null/undefined can be returned. */ getTooltipPosition: null }); zrUtil.mixin(SeriesModel, modelUtil.dataFormatMixin); zrUtil.mixin(SeriesModel, colorPaletteMixin); module.exports = SeriesModel; /***/ }, /* 29 */ /***/ function(module, exports, __webpack_require__) { var Group = __webpack_require__(30); var componentUtil = __webpack_require__(20); var clazzUtil = __webpack_require__(13); var Component = function () { /** * @type {module:zrender/container/Group} * @readOnly */ this.group = new Group(); /** * @type {string} * @readOnly */ this.uid = componentUtil.getUID('viewComponent'); }; Component.prototype = { constructor: Component, init: function (ecModel, api) {}, render: function (componentModel, ecModel, api, payload) {}, dispose: function () {} }; var componentProto = Component.prototype; componentProto.updateView = componentProto.updateLayout = componentProto.updateVisual = function (seriesModel, ecModel, api, payload) { // Do nothing; }; // Enable Component.extend. clazzUtil.enableClassExtend(Component); // Enable capability of registerClass, getClass, hasClass, registerSubTypeDefaulter and so on. clazzUtil.enableClassManagement(Component, {registerWhenExtend: true}); module.exports = Component; /***/ }, /* 30 */ /***/ function(module, exports, __webpack_require__) { /** * Group是一个容器,可以插入子节点,Group的变换也会被应用到子节点上 * @module zrender/graphic/Group * @example * var Group = require('zrender/lib/container/Group'); * var Circle = require('zrender/lib/graphic/shape/Circle'); * var g = new Group(); * g.position[0] = 100; * g.position[1] = 100; * g.add(new Circle({ * style: { * x: 100, * y: 100, * r: 20, * } * })); * zr.add(g); */ var zrUtil = __webpack_require__(4); var Element = __webpack_require__(31); var BoundingRect = __webpack_require__(9); /** * @alias module:zrender/graphic/Group * @constructor * @extends module:zrender/mixin/Transformable * @extends module:zrender/mixin/Eventful */ var Group = function (opts) { opts = opts || {}; Element.call(this, opts); for (var key in opts) { if (opts.hasOwnProperty(key)) { this[key] = opts[key]; } } this._children = []; this.__storage = null; this.__dirty = true; }; Group.prototype = { constructor: Group, isGroup: true, /** * @type {string} */ type: 'group', /** * 所有子孙元素是否响应鼠标事件 * @name module:/zrender/container/Group#silent * @type {boolean} * @default false */ silent: false, /** * @return {Array.} */ children: function () { return this._children.slice(); }, /** * 获取指定 index 的儿子节点 * @param {number} idx * @return {module:zrender/Element} */ childAt: function (idx) { return this._children[idx]; }, /** * 获取指定名字的儿子节点 * @param {string} name * @return {module:zrender/Element} */ childOfName: function (name) { var children = this._children; for (var i = 0; i < children.length; i++) { if (children[i].name === name) { return children[i]; } } }, /** * @return {number} */ childCount: function () { return this._children.length; }, /** * 添加子节点到最后 * @param {module:zrender/Element} child */ add: function (child) { if (child && child !== this && child.parent !== this) { this._children.push(child); this._doAdd(child); } return this; }, /** * 添加子节点在 nextSibling 之前 * @param {module:zrender/Element} child * @param {module:zrender/Element} nextSibling */ addBefore: function (child, nextSibling) { if (child && child !== this && child.parent !== this && nextSibling && nextSibling.parent === this) { var children = this._children; var idx = children.indexOf(nextSibling); if (idx >= 0) { children.splice(idx, 0, child); this._doAdd(child); } } return this; }, _doAdd: function (child) { if (child.parent) { child.parent.remove(child); } child.parent = this; var storage = this.__storage; var zr = this.__zr; if (storage && storage !== child.__storage) { storage.addToMap(child); if (child instanceof Group) { child.addChildrenToStorage(storage); } } zr && zr.refresh(); }, /** * 移除子节点 * @param {module:zrender/Element} child */ remove: function (child) { var zr = this.__zr; var storage = this.__storage; var children = this._children; var idx = zrUtil.indexOf(children, child); if (idx < 0) { return this; } children.splice(idx, 1); child.parent = null; if (storage) { storage.delFromMap(child.id); if (child instanceof Group) { child.delChildrenFromStorage(storage); } } zr && zr.refresh(); return this; }, /** * 移除所有子节点 */ removeAll: function () { var children = this._children; var storage = this.__storage; var child; var i; for (i = 0; i < children.length; i++) { child = children[i]; if (storage) { storage.delFromMap(child.id); if (child instanceof Group) { child.delChildrenFromStorage(storage); } } child.parent = null; } children.length = 0; return this; }, /** * 遍历所有子节点 * @param {Function} cb * @param {} context */ eachChild: function (cb, context) { var children = this._children; for (var i = 0; i < children.length; i++) { var child = children[i]; cb.call(context, child, i); } return this; }, /** * 深度优先遍历所有子孙节点 * @param {Function} cb * @param {} context */ traverse: function (cb, context) { for (var i = 0; i < this._children.length; i++) { var child = this._children[i]; cb.call(context, child); if (child.type === 'group') { child.traverse(cb, context); } } return this; }, addChildrenToStorage: function (storage) { for (var i = 0; i < this._children.length; i++) { var child = this._children[i]; storage.addToMap(child); if (child instanceof Group) { child.addChildrenToStorage(storage); } } }, delChildrenFromStorage: function (storage) { for (var i = 0; i < this._children.length; i++) { var child = this._children[i]; storage.delFromMap(child.id); if (child instanceof Group) { child.delChildrenFromStorage(storage); } } }, dirty: function () { this.__dirty = true; this.__zr && this.__zr.refresh(); return this; }, /** * @return {module:zrender/core/BoundingRect} */ getBoundingRect: function (includeChildren) { // TODO Caching var rect = null; var tmpRect = new BoundingRect(0, 0, 0, 0); var children = includeChildren || this._children; var tmpMat = []; for (var i = 0; i < children.length; i++) { var child = children[i]; if (child.ignore || child.invisible) { continue; } var childRect = child.getBoundingRect(); var transform = child.getLocalTransform(tmpMat); // TODO // The boundingRect cacluated by transforming original // rect may be bigger than the actual bundingRect when rotation // is used. (Consider a circle rotated aginst its center, where // the actual boundingRect should be the same as that not be // rotated.) But we can not find better approach to calculate // actual boundingRect yet, considering performance. if (transform) { tmpRect.copy(childRect); tmpRect.applyTransform(transform); rect = rect || tmpRect.clone(); rect.union(tmpRect); } else { rect = rect || childRect.clone(); rect.union(childRect); } } return rect || tmpRect; } }; zrUtil.inherits(Group, Element); module.exports = Group; /***/ }, /* 31 */ /***/ function(module, exports, __webpack_require__) { 'use strict'; /** * @module zrender/Element */ var guid = __webpack_require__(32); var Eventful = __webpack_require__(33); var Transformable = __webpack_require__(34); var Animatable = __webpack_require__(35); var zrUtil = __webpack_require__(4); /** * @alias module:zrender/Element * @constructor * @extends {module:zrender/mixin/Animatable} * @extends {module:zrender/mixin/Transformable} * @extends {module:zrender/mixin/Eventful} */ var Element = function (opts) { Transformable.call(this, opts); Eventful.call(this, opts); Animatable.call(this, opts); /** * 画布元素ID * @type {string} */ this.id = opts.id || guid(); }; Element.prototype = { /** * 元素类型 * Element type * @type {string} */ type: 'element', /** * 元素名字 * Element name * @type {string} */ name: '', /** * ZRender 实例对象,会在 element 添加到 zrender 实例中后自动赋值 * ZRender instance will be assigned when element is associated with zrender * @name module:/zrender/Element#__zr * @type {module:zrender/ZRender} */ __zr: null, /** * 图形是否忽略,为true时忽略图形的绘制以及事件触发 * If ignore drawing and events of the element object * @name module:/zrender/Element#ignore * @type {boolean} * @default false */ ignore: false, /** * 用于裁剪的路径(shape),所有 Group 内的路径在绘制时都会被这个路径裁剪 * 该路径会继承被裁减对象的变换 * @type {module:zrender/graphic/Path} * @see http://www.w3.org/TR/2dcontext/#clipping-region * @readOnly */ clipPath: null, /** * Drift element * @param {number} dx dx on the global space * @param {number} dy dy on the global space */ drift: function (dx, dy) { switch (this.draggable) { case 'horizontal': dy = 0; break; case 'vertical': dx = 0; break; } var m = this.transform; if (!m) { m = this.transform = [1, 0, 0, 1, 0, 0]; } m[4] += dx; m[5] += dy; this.decomposeTransform(); this.dirty(false); }, /** * Hook before update */ beforeUpdate: function () {}, /** * Hook after update */ afterUpdate: function () {}, /** * Update each frame */ update: function () { this.updateTransform(); }, /** * @param {Function} cb * @param {} context */ traverse: function (cb, context) {}, /** * @protected */ attrKV: function (key, value) { if (key === 'position' || key === 'scale' || key === 'origin') { // Copy the array if (value) { var target = this[key]; if (!target) { target = this[key] = []; } target[0] = value[0]; target[1] = value[1]; } } else { this[key] = value; } }, /** * Hide the element */ hide: function () { this.ignore = true; this.__zr && this.__zr.refresh(); }, /** * Show the element */ show: function () { this.ignore = false; this.__zr && this.__zr.refresh(); }, /** * @param {string|Object} key * @param {*} value */ attr: function (key, value) { if (typeof key === 'string') { this.attrKV(key, value); } else if (zrUtil.isObject(key)) { for (var name in key) { if (key.hasOwnProperty(name)) { this.attrKV(name, key[name]); } } } this.dirty(false); return this; }, /** * @param {module:zrender/graphic/Path} clipPath */ setClipPath: function (clipPath) { var zr = this.__zr; if (zr) { clipPath.addSelfToZr(zr); } // Remove previous clip path if (this.clipPath && this.clipPath !== clipPath) { this.removeClipPath(); } this.clipPath = clipPath; clipPath.__zr = zr; clipPath.__clipTarget = this; this.dirty(false); }, /** */ removeClipPath: function () { var clipPath = this.clipPath; if (clipPath) { if (clipPath.__zr) { clipPath.removeSelfFromZr(clipPath.__zr); } clipPath.__zr = null; clipPath.__clipTarget = null; this.clipPath = null; this.dirty(false); } }, /** * Add self from zrender instance. * Not recursively because it will be invoked when element added to storage. * @param {module:zrender/ZRender} zr */ addSelfToZr: function (zr) { this.__zr = zr; // 添加动画 var animators = this.animators; if (animators) { for (var i = 0; i < animators.length; i++) { zr.animation.addAnimator(animators[i]); } } if (this.clipPath) { this.clipPath.addSelfToZr(zr); } }, /** * Remove self from zrender instance. * Not recursively because it will be invoked when element added to storage. * @param {module:zrender/ZRender} zr */ removeSelfFromZr: function (zr) { this.__zr = null; // 移除动画 var animators = this.animators; if (animators) { for (var i = 0; i < animators.length; i++) { zr.animation.removeAnimator(animators[i]); } } if (this.clipPath) { this.clipPath.removeSelfFromZr(zr); } } }; zrUtil.mixin(Element, Animatable); zrUtil.mixin(Element, Transformable); zrUtil.mixin(Element, Eventful); module.exports = Element; /***/ }, /* 32 */ /***/ function(module, exports) { /** * zrender: 生成唯一id * * @author errorrik (errorrik@gmail.com) */ var idStart = 0x0907; module.exports = function () { return idStart++; }; /***/ }, /* 33 */ /***/ function(module, exports) { /** * 事件扩展 * @module zrender/mixin/Eventful * @author Kener (@Kener-林峰, kener.linfeng@gmail.com) * pissang (https://www.github.com/pissang) */ var arrySlice = Array.prototype.slice; /** * 事件分发器 * @alias module:zrender/mixin/Eventful * @constructor */ var Eventful = function () { this._$handlers = {}; }; Eventful.prototype = { constructor: Eventful, /** * 单次触发绑定,trigger后销毁 * * @param {string} event 事件名 * @param {Function} handler 响应函数 * @param {Object} context */ one: function (event, handler, context) { var _h = this._$handlers; if (!handler || !event) { return this; } if (!_h[event]) { _h[event] = []; } for (var i = 0; i < _h[event].length; i++) { if (_h[event][i].h === handler) { return this; } } _h[event].push({ h: handler, one: true, ctx: context || this }); return this; }, /** * 绑定事件 * @param {string} event 事件名 * @param {Function} handler 事件处理函数 * @param {Object} [context] */ on: function (event, handler, context) { var _h = this._$handlers; if (!handler || !event) { return this; } if (!_h[event]) { _h[event] = []; } for (var i = 0; i < _h[event].length; i++) { if (_h[event][i].h === handler) { return this; } } _h[event].push({ h: handler, one: false, ctx: context || this }); return this; }, /** * 是否绑定了事件 * @param {string} event * @return {boolean} */ isSilent: function (event) { var _h = this._$handlers; return _h[event] && _h[event].length; }, /** * 解绑事件 * @param {string} event 事件名 * @param {Function} [handler] 事件处理函数 */ off: function (event, handler) { var _h = this._$handlers; if (!event) { this._$handlers = {}; return this; } if (handler) { if (_h[event]) { var newList = []; for (var i = 0, l = _h[event].length; i < l; i++) { if (_h[event][i]['h'] != handler) { newList.push(_h[event][i]); } } _h[event] = newList; } if (_h[event] && _h[event].length === 0) { delete _h[event]; } } else { delete _h[event]; } return this; }, /** * 事件分发 * * @param {string} type 事件类型 */ trigger: function (type) { if (this._$handlers[type]) { var args = arguments; var argLen = args.length; if (argLen > 3) { args = arrySlice.call(args, 1); } var _h = this._$handlers[type]; var len = _h.length; for (var i = 0; i < len;) { // Optimize advise from backbone switch (argLen) { case 1: _h[i]['h'].call(_h[i]['ctx']); break; case 2: _h[i]['h'].call(_h[i]['ctx'], args[1]); break; case 3: _h[i]['h'].call(_h[i]['ctx'], args[1], args[2]); break; default: // have more than 2 given arguments _h[i]['h'].apply(_h[i]['ctx'], args); break; } if (_h[i]['one']) { _h.splice(i, 1); len--; } else { i++; } } } return this; }, /** * 带有context的事件分发, 最后一个参数是事件回调的context * @param {string} type 事件类型 */ triggerWithContext: function (type) { if (this._$handlers[type]) { var args = arguments; var argLen = args.length; if (argLen > 4) { args = arrySlice.call(args, 1, args.length - 1); } var ctx = args[args.length - 1]; var _h = this._$handlers[type]; var len = _h.length; for (var i = 0; i < len;) { // Optimize advise from backbone switch (argLen) { case 1: _h[i]['h'].call(ctx); break; case 2: _h[i]['h'].call(ctx, args[1]); break; case 3: _h[i]['h'].call(ctx, args[1], args[2]); break; default: // have more than 2 given arguments _h[i]['h'].apply(ctx, args); break; } if (_h[i]['one']) { _h.splice(i, 1); len--; } else { i++; } } } return this; } }; // 对象可以通过 onxxxx 绑定事件 /** * @event module:zrender/mixin/Eventful#onclick * @type {Function} * @default null */ /** * @event module:zrender/mixin/Eventful#onmouseover * @type {Function} * @default null */ /** * @event module:zrender/mixin/Eventful#onmouseout * @type {Function} * @default null */ /** * @event module:zrender/mixin/Eventful#onmousemove * @type {Function} * @default null */ /** * @event module:zrender/mixin/Eventful#onmousewheel * @type {Function} * @default null */ /** * @event module:zrender/mixin/Eventful#onmousedown * @type {Function} * @default null */ /** * @event module:zrender/mixin/Eventful#onmouseup * @type {Function} * @default null */ /** * @event module:zrender/mixin/Eventful#ondrag * @type {Function} * @default null */ /** * @event module:zrender/mixin/Eventful#ondragstart * @type {Function} * @default null */ /** * @event module:zrender/mixin/Eventful#ondragend * @type {Function} * @default null */ /** * @event module:zrender/mixin/Eventful#ondragenter * @type {Function} * @default null */ /** * @event module:zrender/mixin/Eventful#ondragleave * @type {Function} * @default null */ /** * @event module:zrender/mixin/Eventful#ondragover * @type {Function} * @default null */ /** * @event module:zrender/mixin/Eventful#ondrop * @type {Function} * @default null */ module.exports = Eventful; /***/ }, /* 34 */ /***/ function(module, exports, __webpack_require__) { 'use strict'; /** * 提供变换扩展 * @module zrender/mixin/Transformable * @author pissang (https://www.github.com/pissang) */ var matrix = __webpack_require__(11); var vector = __webpack_require__(10); var mIdentity = matrix.identity; var EPSILON = 5e-5; function isNotAroundZero(val) { return val > EPSILON || val < -EPSILON; } /** * @alias module:zrender/mixin/Transformable * @constructor */ var Transformable = function (opts) { opts = opts || {}; // If there are no given position, rotation, scale if (!opts.position) { /** * 平移 * @type {Array.} * @default [0, 0] */ this.position = [0, 0]; } if (opts.rotation == null) { /** * 旋转 * @type {Array.} * @default 0 */ this.rotation = 0; } if (!opts.scale) { /** * 缩放 * @type {Array.} * @default [1, 1] */ this.scale = [1, 1]; } /** * 旋转和缩放的原点 * @type {Array.} * @default null */ this.origin = this.origin || null; }; var transformableProto = Transformable.prototype; transformableProto.transform = null; /** * 判断是否需要有坐标变换 * 如果有坐标变换, 则从position, rotation, scale以及父节点的transform计算出自身的transform矩阵 */ transformableProto.needLocalTransform = function () { return isNotAroundZero(this.rotation) || isNotAroundZero(this.position[0]) || isNotAroundZero(this.position[1]) || isNotAroundZero(this.scale[0] - 1) || isNotAroundZero(this.scale[1] - 1); }; transformableProto.updateTransform = function () { var parent = this.parent; var parentHasTransform = parent && parent.transform; var needLocalTransform = this.needLocalTransform(); var m = this.transform; if (!(needLocalTransform || parentHasTransform)) { m && mIdentity(m); return; } m = m || matrix.create(); if (needLocalTransform) { this.getLocalTransform(m); } else { mIdentity(m); } // 应用父节点变换 if (parentHasTransform) { if (needLocalTransform) { matrix.mul(m, parent.transform, m); } else { matrix.copy(m, parent.transform); } } // 保存这个变换矩阵 this.transform = m; this.invTransform = this.invTransform || matrix.create(); matrix.invert(this.invTransform, m); }; transformableProto.getLocalTransform = function (m) { m = m || []; mIdentity(m); var origin = this.origin; var scale = this.scale; var rotation = this.rotation; var position = this.position; if (origin) { // Translate to origin m[4] -= origin[0]; m[5] -= origin[1]; } matrix.scale(m, m, scale); if (rotation) { matrix.rotate(m, m, rotation); } if (origin) { // Translate back from origin m[4] += origin[0]; m[5] += origin[1]; } m[4] += position[0]; m[5] += position[1]; return m; }; /** * 将自己的transform应用到context上 * @param {Context2D} ctx */ transformableProto.setTransform = function (ctx) { var m = this.transform; var dpr = ctx.dpr || 1; if (m) { ctx.setTransform(dpr * m[0], dpr * m[1], dpr * m[2], dpr * m[3], dpr * m[4], dpr * m[5]); } else { ctx.setTransform(dpr, 0, 0, dpr, 0, 0); } }; transformableProto.restoreTransform = function (ctx) { var m = this.transform; var dpr = ctx.dpr || 1; ctx.setTransform(dpr, 0, 0, dpr, 0, 0); } var tmpTransform = []; /** * 分解`transform`矩阵到`position`, `rotation`, `scale` */ transformableProto.decomposeTransform = function () { if (!this.transform) { return; } var parent = this.parent; var m = this.transform; if (parent && parent.transform) { // Get local transform and decompose them to position, scale, rotation matrix.mul(tmpTransform, parent.invTransform, m); m = tmpTransform; } var sx = m[0] * m[0] + m[1] * m[1]; var sy = m[2] * m[2] + m[3] * m[3]; var position = this.position; var scale = this.scale; if (isNotAroundZero(sx - 1)) { sx = Math.sqrt(sx); } if (isNotAroundZero(sy - 1)) { sy = Math.sqrt(sy); } if (m[0] < 0) { sx = -sx; } if (m[3] < 0) { sy = -sy; } position[0] = m[4]; position[1] = m[5]; scale[0] = sx; scale[1] = sy; this.rotation = Math.atan2(-m[1] / sy, m[0] / sx); }; /** * Get global scale * @return {Array.} */ transformableProto.getGlobalScale = function () { var m = this.transform; if (!m) { return [1, 1]; } var sx = Math.sqrt(m[0] * m[0] + m[1] * m[1]); var sy = Math.sqrt(m[2] * m[2] + m[3] * m[3]); if (m[0] < 0) { sx = -sx; } if (m[3] < 0) { sy = -sy; } return [sx, sy]; }; /** * 变换坐标位置到 shape 的局部坐标空间 * @method * @param {number} x * @param {number} y * @return {Array.} */ transformableProto.transformCoordToLocal = function (x, y) { var v2 = [x, y]; var invTransform = this.invTransform; if (invTransform) { vector.applyTransform(v2, v2, invTransform); } return v2; }; /** * 变换局部坐标位置到全局坐标空间 * @method * @param {number} x * @param {number} y * @return {Array.} */ transformableProto.transformCoordToGlobal = function (x, y) { var v2 = [x, y]; var transform = this.transform; if (transform) { vector.applyTransform(v2, v2, transform); } return v2; }; module.exports = Transformable; /***/ }, /* 35 */ /***/ function(module, exports, __webpack_require__) { 'use strict'; /** * @module zrender/mixin/Animatable */ var Animator = __webpack_require__(36); var util = __webpack_require__(4); var isString = util.isString; var isFunction = util.isFunction; var isObject = util.isObject; var log = __webpack_require__(40); /** * @alias modue:zrender/mixin/Animatable * @constructor */ var Animatable = function () { /** * @type {Array.} * @readOnly */ this.animators = []; }; Animatable.prototype = { constructor: Animatable, /** * 动画 * * @param {string} path 需要添加动画的属性获取路径,可以通过a.b.c来获取深层的属性 * @param {boolean} [loop] 动画是否循环 * @return {module:zrender/animation/Animator} * @example: * el.animate('style', false) * .when(1000, {x: 10} ) * .done(function(){ // Animation done }) * .start() */ animate: function (path, loop) { var target; var animatingShape = false; var el = this; var zr = this.__zr; if (path) { var pathSplitted = path.split('.'); var prop = el; // If animating shape animatingShape = pathSplitted[0] === 'shape'; for (var i = 0, l = pathSplitted.length; i < l; i++) { if (!prop) { continue; } prop = prop[pathSplitted[i]]; } if (prop) { target = prop; } } else { target = el; } if (!target) { log( 'Property "' + path + '" is not existed in element ' + el.id ); return; } var animators = el.animators; var animator = new Animator(target, loop); animator.during(function (target) { el.dirty(animatingShape); }) .done(function () { // FIXME Animator will not be removed if use `Animator#stop` to stop animation animators.splice(util.indexOf(animators, animator), 1); }); animators.push(animator); // If animate after added to the zrender if (zr) { zr.animation.addAnimator(animator); } return animator; }, /** * 停止动画 * @param {boolean} forwardToLast If move to last frame before stop */ stopAnimation: function (forwardToLast) { var animators = this.animators; var len = animators.length; for (var i = 0; i < len; i++) { animators[i].stop(forwardToLast); } animators.length = 0; return this; }, /** * @param {Object} target * @param {number} [time=500] Time in ms * @param {string} [easing='linear'] * @param {number} [delay=0] * @param {Function} [callback] * * @example * // Animate position * el.animateTo({ * position: [10, 10] * }, function () { // done }) * * // Animate shape, style and position in 100ms, delayed 100ms, with cubicOut easing * el.animateTo({ * shape: { * width: 500 * }, * style: { * fill: 'red' * } * position: [10, 10] * }, 100, 100, 'cubicOut', function () { // done }) */ // TODO Return animation key animateTo: function (target, time, delay, easing, callback) { // animateTo(target, time, easing, callback); if (isString(delay)) { callback = easing; easing = delay; delay = 0; } // animateTo(target, time, delay, callback); else if (isFunction(easing)) { callback = easing; easing = 'linear'; delay = 0; } // animateTo(target, time, callback); else if (isFunction(delay)) { callback = delay; delay = 0; } // animateTo(target, callback) else if (isFunction(time)) { callback = time; time = 500; } // animateTo(target) else if (!time) { time = 500; } // Stop all previous animations this.stopAnimation(); this._animateToShallow('', this, target, time, delay, easing, callback); // Animators may be removed immediately after start // if there is nothing to animate var animators = this.animators.slice(); var count = animators.length; function done() { count--; if (!count) { callback && callback(); } } // No animators. This should be checked before animators[i].start(), // because 'done' may be executed immediately if no need to animate. if (!count) { callback && callback(); } // Start after all animators created // Incase any animator is done immediately when all animation properties are not changed for (var i = 0; i < animators.length; i++) { animators[i] .done(done) .start(easing); } }, /** * @private * @param {string} path='' * @param {Object} source=this * @param {Object} target * @param {number} [time=500] * @param {number} [delay=0] * * @example * // Animate position * el._animateToShallow({ * position: [10, 10] * }) * * // Animate shape, style and position in 100ms, delayed 100ms * el._animateToShallow({ * shape: { * width: 500 * }, * style: { * fill: 'red' * } * position: [10, 10] * }, 100, 100) */ _animateToShallow: function (path, source, target, time, delay) { var objShallow = {}; var propertyCount = 0; for (var name in target) { if (!target.hasOwnProperty(name)) { continue; } if (source[name] != null) { if (isObject(target[name]) && !util.isArrayLike(target[name])) { this._animateToShallow( path ? path + '.' + name : name, source[name], target[name], time, delay ); } else { objShallow[name] = target[name]; propertyCount++; } } else if (target[name] != null) { // Attr directly if not has property // FIXME, if some property not needed for element ? if (!path) { this.attr(name, target[name]); } else { // Shape or style var props = {}; props[path] = {}; props[path][name] = target[name]; this.attr(props); } } } if (propertyCount > 0) { this.animate(path, false) .when(time == null ? 500 : time, objShallow) .delay(delay || 0); } return this; } }; module.exports = Animatable; /***/ }, /* 36 */ /***/ function(module, exports, __webpack_require__) { /** * @module echarts/animation/Animator */ var Clip = __webpack_require__(37); var color = __webpack_require__(39); var util = __webpack_require__(4); var isArrayLike = util.isArrayLike; var arraySlice = Array.prototype.slice; function defaultGetter(target, key) { return target[key]; } function defaultSetter(target, key, value) { target[key] = value; } /** * @param {number} p0 * @param {number} p1 * @param {number} percent * @return {number} */ function interpolateNumber(p0, p1, percent) { return (p1 - p0) * percent + p0; } /** * @param {string} p0 * @param {string} p1 * @param {number} percent * @return {string} */ function interpolateString(p0, p1, percent) { return percent > 0.5 ? p1 : p0; } /** * @param {Array} p0 * @param {Array} p1 * @param {number} percent * @param {Array} out * @param {number} arrDim */ function interpolateArray(p0, p1, percent, out, arrDim) { var len = p0.length; if (arrDim == 1) { for (var i = 0; i < len; i++) { out[i] = interpolateNumber(p0[i], p1[i], percent); } } else { var len2 = p0[0].length; for (var i = 0; i < len; i++) { for (var j = 0; j < len2; j++) { out[i][j] = interpolateNumber( p0[i][j], p1[i][j], percent ); } } } } // arr0 is source array, arr1 is target array. // Do some preprocess to avoid error happened when interpolating from arr0 to arr1 function fillArr(arr0, arr1, arrDim) { var arr0Len = arr0.length; var arr1Len = arr1.length; if (arr0Len !== arr1Len) { // FIXME Not work for TypedArray var isPreviousLarger = arr0Len > arr1Len; if (isPreviousLarger) { // Cut the previous arr0.length = arr1Len; } else { // Fill the previous for (var i = arr0Len; i < arr1Len; i++) { arr0.push( arrDim === 1 ? arr1[i] : arraySlice.call(arr1[i]) ); } } } // Handling NaN value var len2 = arr0[0] && arr0[0].length; for (var i = 0; i < arr0.length; i++) { if (arrDim === 1) { if (isNaN(arr0[i])) { arr0[i] = arr1[i]; } } else { for (var j = 0; j < len2; j++) { if (isNaN(arr0[i][j])) { arr0[i][j] = arr1[i][j]; } } } } } /** * @param {Array} arr0 * @param {Array} arr1 * @param {number} arrDim * @return {boolean} */ function isArraySame(arr0, arr1, arrDim) { if (arr0 === arr1) { return true; } var len = arr0.length; if (len !== arr1.length) { return false; } if (arrDim === 1) { for (var i = 0; i < len; i++) { if (arr0[i] !== arr1[i]) { return false; } } } else { var len2 = arr0[0].length; for (var i = 0; i < len; i++) { for (var j = 0; j < len2; j++) { if (arr0[i][j] !== arr1[i][j]) { return false; } } } } return true; } /** * Catmull Rom interpolate array * @param {Array} p0 * @param {Array} p1 * @param {Array} p2 * @param {Array} p3 * @param {number} t * @param {number} t2 * @param {number} t3 * @param {Array} out * @param {number} arrDim */ function catmullRomInterpolateArray( p0, p1, p2, p3, t, t2, t3, out, arrDim ) { var len = p0.length; if (arrDim == 1) { for (var i = 0; i < len; i++) { out[i] = catmullRomInterpolate( p0[i], p1[i], p2[i], p3[i], t, t2, t3 ); } } else { var len2 = p0[0].length; for (var i = 0; i < len; i++) { for (var j = 0; j < len2; j++) { out[i][j] = catmullRomInterpolate( p0[i][j], p1[i][j], p2[i][j], p3[i][j], t, t2, t3 ); } } } } /** * Catmull Rom interpolate number * @param {number} p0 * @param {number} p1 * @param {number} p2 * @param {number} p3 * @param {number} t * @param {number} t2 * @param {number} t3 * @return {number} */ function catmullRomInterpolate(p0, p1, p2, p3, t, t2, t3) { var v0 = (p2 - p0) * 0.5; var v1 = (p3 - p1) * 0.5; return (2 * (p1 - p2) + v0 + v1) * t3 + (-3 * (p1 - p2) - 2 * v0 - v1) * t2 + v0 * t + p1; } function cloneValue(value) { if (isArrayLike(value)) { var len = value.length; if (isArrayLike(value[0])) { var ret = []; for (var i = 0; i < len; i++) { ret.push(arraySlice.call(value[i])); } return ret; } return arraySlice.call(value); } return value; } function rgba2String(rgba) { rgba[0] = Math.floor(rgba[0]); rgba[1] = Math.floor(rgba[1]); rgba[2] = Math.floor(rgba[2]); return 'rgba(' + rgba.join(',') + ')'; } function createTrackClip (animator, easing, oneTrackDone, keyframes, propName) { var getter = animator._getter; var setter = animator._setter; var useSpline = easing === 'spline'; var trackLen = keyframes.length; if (!trackLen) { return; } // Guess data type var firstVal = keyframes[0].value; var isValueArray = isArrayLike(firstVal); var isValueColor = false; var isValueString = false; // For vertices morphing var arrDim = ( isValueArray && isArrayLike(firstVal[0]) ) ? 2 : 1; var trackMaxTime; // Sort keyframe as ascending keyframes.sort(function(a, b) { return a.time - b.time; }); trackMaxTime = keyframes[trackLen - 1].time; // Percents of each keyframe var kfPercents = []; // Value of each keyframe var kfValues = []; var prevValue = keyframes[0].value; var isAllValueEqual = true; for (var i = 0; i < trackLen; i++) { kfPercents.push(keyframes[i].time / trackMaxTime); // Assume value is a color when it is a string var value = keyframes[i].value; // Check if value is equal, deep check if value is array if (!((isValueArray && isArraySame(value, prevValue, arrDim)) || (!isValueArray && value === prevValue))) { isAllValueEqual = false; } prevValue = value; // Try converting a string to a color array if (typeof value == 'string') { var colorArray = color.parse(value); if (colorArray) { value = colorArray; isValueColor = true; } else { isValueString = true; } } kfValues.push(value); } if (isAllValueEqual) { return; } var lastValue = kfValues[trackLen - 1]; // Polyfill array and NaN value for (var i = 0; i < trackLen - 1; i++) { if (isValueArray) { fillArr(kfValues[i], lastValue, arrDim); } else { if (isNaN(kfValues[i]) && !isNaN(lastValue) && !isValueString && !isValueColor) { kfValues[i] = lastValue; } } } isValueArray && fillArr(getter(animator._target, propName), lastValue, arrDim); // Cache the key of last frame to speed up when // animation playback is sequency var lastFrame = 0; var lastFramePercent = 0; var start; var w; var p0; var p1; var p2; var p3; if (isValueColor) { var rgba = [0, 0, 0, 0]; } var onframe = function (target, percent) { // Find the range keyframes // kf1-----kf2---------current--------kf3 // find kf2 and kf3 and do interpolation var frame; // In the easing function like elasticOut, percent may less than 0 if (percent < 0) { frame = 0; } else if (percent < lastFramePercent) { // Start from next key // PENDING start from lastFrame ? start = Math.min(lastFrame + 1, trackLen - 1); for (frame = start; frame >= 0; frame--) { if (kfPercents[frame] <= percent) { break; } } // PENDING really need to do this ? frame = Math.min(frame, trackLen - 2); } else { for (frame = lastFrame; frame < trackLen; frame++) { if (kfPercents[frame] > percent) { break; } } frame = Math.min(frame - 1, trackLen - 2); } lastFrame = frame; lastFramePercent = percent; var range = (kfPercents[frame + 1] - kfPercents[frame]); if (range === 0) { return; } else { w = (percent - kfPercents[frame]) / range; } if (useSpline) { p1 = kfValues[frame]; p0 = kfValues[frame === 0 ? frame : frame - 1]; p2 = kfValues[frame > trackLen - 2 ? trackLen - 1 : frame + 1]; p3 = kfValues[frame > trackLen - 3 ? trackLen - 1 : frame + 2]; if (isValueArray) { catmullRomInterpolateArray( p0, p1, p2, p3, w, w * w, w * w * w, getter(target, propName), arrDim ); } else { var value; if (isValueColor) { value = catmullRomInterpolateArray( p0, p1, p2, p3, w, w * w, w * w * w, rgba, 1 ); value = rgba2String(rgba); } else if (isValueString) { // String is step(0.5) return interpolateString(p1, p2, w); } else { value = catmullRomInterpolate( p0, p1, p2, p3, w, w * w, w * w * w ); } setter( target, propName, value ); } } else { if (isValueArray) { interpolateArray( kfValues[frame], kfValues[frame + 1], w, getter(target, propName), arrDim ); } else { var value; if (isValueColor) { interpolateArray( kfValues[frame], kfValues[frame + 1], w, rgba, 1 ); value = rgba2String(rgba); } else if (isValueString) { // String is step(0.5) return interpolateString(kfValues[frame], kfValues[frame + 1], w); } else { value = interpolateNumber(kfValues[frame], kfValues[frame + 1], w); } setter( target, propName, value ); } } }; var clip = new Clip({ target: animator._target, life: trackMaxTime, loop: animator._loop, delay: animator._delay, onframe: onframe, ondestroy: oneTrackDone }); if (easing && easing !== 'spline') { clip.easing = easing; } return clip; } /** * @alias module:zrender/animation/Animator * @constructor * @param {Object} target * @param {boolean} loop * @param {Function} getter * @param {Function} setter */ var Animator = function(target, loop, getter, setter) { this._tracks = {}; this._target = target; this._loop = loop || false; this._getter = getter || defaultGetter; this._setter = setter || defaultSetter; this._clipCount = 0; this._delay = 0; this._doneList = []; this._onframeList = []; this._clipList = []; }; Animator.prototype = { /** * 设置动画关键帧 * @param {number} time 关键帧时间,单位是ms * @param {Object} props 关键帧的属性值,key-value表示 * @return {module:zrender/animation/Animator} */ when: function(time /* ms */, props) { var tracks = this._tracks; for (var propName in props) { if (!props.hasOwnProperty(propName)) { continue; } if (!tracks[propName]) { tracks[propName] = []; // Invalid value var value = this._getter(this._target, propName); if (value == null) { // zrLog('Invalid property ' + propName); continue; } // If time is 0 // Then props is given initialize value // Else // Initialize value from current prop value if (time !== 0) { tracks[propName].push({ time: 0, value: cloneValue(value) }); } } tracks[propName].push({ time: time, value: props[propName] }); } return this; }, /** * 添加动画每一帧的回调函数 * @param {Function} callback * @return {module:zrender/animation/Animator} */ during: function (callback) { this._onframeList.push(callback); return this; }, _doneCallback: function () { // Clear all tracks this._tracks = {}; // Clear all clips this._clipList.length = 0; var doneList = this._doneList; var len = doneList.length; for (var i = 0; i < len; i++) { doneList[i].call(this); } }, /** * 开始执行动画 * @param {string|Function} easing * 动画缓动函数,详见{@link module:zrender/animation/easing} * @return {module:zrender/animation/Animator} */ start: function (easing) { var self = this; var clipCount = 0; var oneTrackDone = function() { clipCount--; if (!clipCount) { self._doneCallback(); } }; var lastClip; for (var propName in this._tracks) { if (!this._tracks.hasOwnProperty(propName)) { continue; } var clip = createTrackClip( this, easing, oneTrackDone, this._tracks[propName], propName ); if (clip) { this._clipList.push(clip); clipCount++; // If start after added to animation if (this.animation) { this.animation.addClip(clip); } lastClip = clip; } } // Add during callback on the last clip if (lastClip) { var oldOnFrame = lastClip.onframe; lastClip.onframe = function (target, percent) { oldOnFrame(target, percent); for (var i = 0; i < self._onframeList.length; i++) { self._onframeList[i](target, percent); } }; } if (!clipCount) { this._doneCallback(); } return this; }, /** * 停止动画 * @param {boolean} forwardToLast If move to last frame before stop */ stop: function (forwardToLast) { var clipList = this._clipList; var animation = this.animation; for (var i = 0; i < clipList.length; i++) { var clip = clipList[i]; if (forwardToLast) { // Move to last frame before stop clip.onframe(this._target, 1); } animation && animation.removeClip(clip); } clipList.length = 0; }, /** * 设置动画延迟开始的时间 * @param {number} time 单位ms * @return {module:zrender/animation/Animator} */ delay: function (time) { this._delay = time; return this; }, /** * 添加动画结束的回调 * @param {Function} cb * @return {module:zrender/animation/Animator} */ done: function(cb) { if (cb) { this._doneList.push(cb); } return this; }, /** * @return {Array.} */ getClips: function () { return this._clipList; } }; module.exports = Animator; /***/ }, /* 37 */ /***/ function(module, exports, __webpack_require__) { /** * 动画主控制器 * @config target 动画对象,可以是数组,如果是数组的话会批量分发onframe等事件 * @config life(1000) 动画时长 * @config delay(0) 动画延迟时间 * @config loop(true) * @config gap(0) 循环的间隔时间 * @config onframe * @config easing(optional) * @config ondestroy(optional) * @config onrestart(optional) * * TODO pause */ var easingFuncs = __webpack_require__(38); function Clip(options) { this._target = options.target; // 生命周期 this._life = options.life || 1000; // 延时 this._delay = options.delay || 0; // 开始时间 // this._startTime = new Date().getTime() + this._delay;// 单位毫秒 this._initialized = false; // 是否循环 this.loop = options.loop == null ? false : options.loop; this.gap = options.gap || 0; this.easing = options.easing || 'Linear'; this.onframe = options.onframe; this.ondestroy = options.ondestroy; this.onrestart = options.onrestart; } Clip.prototype = { constructor: Clip, step: function (globalTime) { // Set startTime on first step, or _startTime may has milleseconds different between clips // PENDING if (!this._initialized) { this._startTime = globalTime + this._delay; this._initialized = true; } var percent = (globalTime - this._startTime) / this._life; // 还没开始 if (percent < 0) { return; } percent = Math.min(percent, 1); var easing = this.easing; var easingFunc = typeof easing == 'string' ? easingFuncs[easing] : easing; var schedule = typeof easingFunc === 'function' ? easingFunc(percent) : percent; this.fire('frame', schedule); // 结束 if (percent == 1) { if (this.loop) { this.restart (globalTime); // 重新开始周期 // 抛出而不是直接调用事件直到 stage.update 后再统一调用这些事件 return 'restart'; } // 动画完成将这个控制器标识为待删除 // 在Animation.update中进行批量删除 this._needsRemove = true; return 'destroy'; } return null; }, restart: function (globalTime) { var remainder = (globalTime - this._startTime) % this._life; this._startTime = globalTime - remainder + this.gap; this._needsRemove = false; }, fire: function(eventType, arg) { eventType = 'on' + eventType; if (this[eventType]) { this[eventType](this._target, arg); } } }; module.exports = Clip; /***/ }, /* 38 */ /***/ function(module, exports) { /** * 缓动代码来自 https://github.com/sole/tween.js/blob/master/src/Tween.js * @see http://sole.github.io/tween.js/examples/03_graphs.html * @exports zrender/animation/easing */ var easing = { /** * @param {number} k * @return {number} */ linear: function (k) { return k; }, /** * @param {number} k * @return {number} */ quadraticIn: function (k) { return k * k; }, /** * @param {number} k * @return {number} */ quadraticOut: function (k) { return k * (2 - k); }, /** * @param {number} k * @return {number} */ quadraticInOut: function (k) { if ((k *= 2) < 1) { return 0.5 * k * k; } return -0.5 * (--k * (k - 2) - 1); }, // 三次方的缓动(t^3) /** * @param {number} k * @return {number} */ cubicIn: function (k) { return k * k * k; }, /** * @param {number} k * @return {number} */ cubicOut: function (k) { return --k * k * k + 1; }, /** * @param {number} k * @return {number} */ cubicInOut: function (k) { if ((k *= 2) < 1) { return 0.5 * k * k * k; } return 0.5 * ((k -= 2) * k * k + 2); }, // 四次方的缓动(t^4) /** * @param {number} k * @return {number} */ quarticIn: function (k) { return k * k * k * k; }, /** * @param {number} k * @return {number} */ quarticOut: function (k) { return 1 - (--k * k * k * k); }, /** * @param {number} k * @return {number} */ quarticInOut: function (k) { if ((k *= 2) < 1) { return 0.5 * k * k * k * k; } return -0.5 * ((k -= 2) * k * k * k - 2); }, // 五次方的缓动(t^5) /** * @param {number} k * @return {number} */ quinticIn: function (k) { return k * k * k * k * k; }, /** * @param {number} k * @return {number} */ quinticOut: function (k) { return --k * k * k * k * k + 1; }, /** * @param {number} k * @return {number} */ quinticInOut: function (k) { if ((k *= 2) < 1) { return 0.5 * k * k * k * k * k; } return 0.5 * ((k -= 2) * k * k * k * k + 2); }, // 正弦曲线的缓动(sin(t)) /** * @param {number} k * @return {number} */ sinusoidalIn: function (k) { return 1 - Math.cos(k * Math.PI / 2); }, /** * @param {number} k * @return {number} */ sinusoidalOut: function (k) { return Math.sin(k * Math.PI / 2); }, /** * @param {number} k * @return {number} */ sinusoidalInOut: function (k) { return 0.5 * (1 - Math.cos(Math.PI * k)); }, // 指数曲线的缓动(2^t) /** * @param {number} k * @return {number} */ exponentialIn: function (k) { return k === 0 ? 0 : Math.pow(1024, k - 1); }, /** * @param {number} k * @return {number} */ exponentialOut: function (k) { return k === 1 ? 1 : 1 - Math.pow(2, -10 * k); }, /** * @param {number} k * @return {number} */ exponentialInOut: function (k) { if (k === 0) { return 0; } if (k === 1) { return 1; } if ((k *= 2) < 1) { return 0.5 * Math.pow(1024, k - 1); } return 0.5 * (-Math.pow(2, -10 * (k - 1)) + 2); }, // 圆形曲线的缓动(sqrt(1-t^2)) /** * @param {number} k * @return {number} */ circularIn: function (k) { return 1 - Math.sqrt(1 - k * k); }, /** * @param {number} k * @return {number} */ circularOut: function (k) { return Math.sqrt(1 - (--k * k)); }, /** * @param {number} k * @return {number} */ circularInOut: function (k) { if ((k *= 2) < 1) { return -0.5 * (Math.sqrt(1 - k * k) - 1); } return 0.5 * (Math.sqrt(1 - (k -= 2) * k) + 1); }, // 创建类似于弹簧在停止前来回振荡的动画 /** * @param {number} k * @return {number} */ elasticIn: function (k) { var s; var a = 0.1; var p = 0.4; if (k === 0) { return 0; } if (k === 1) { return 1; } if (!a || a < 1) { a = 1; s = p / 4; } else { s = p * Math.asin(1 / a) / (2 * Math.PI); } return -(a * Math.pow(2, 10 * (k -= 1)) * Math.sin((k - s) * (2 * Math.PI) / p)); }, /** * @param {number} k * @return {number} */ elasticOut: function (k) { var s; var a = 0.1; var p = 0.4; if (k === 0) { return 0; } if (k === 1) { return 1; } if (!a || a < 1) { a = 1; s = p / 4; } else { s = p * Math.asin(1 / a) / (2 * Math.PI); } return (a * Math.pow(2, -10 * k) * Math.sin((k - s) * (2 * Math.PI) / p) + 1); }, /** * @param {number} k * @return {number} */ elasticInOut: function (k) { var s; var a = 0.1; var p = 0.4; if (k === 0) { return 0; } if (k === 1) { return 1; } if (!a || a < 1) { a = 1; s = p / 4; } else { s = p * Math.asin(1 / a) / (2 * Math.PI); } if ((k *= 2) < 1) { return -0.5 * (a * Math.pow(2, 10 * (k -= 1)) * Math.sin((k - s) * (2 * Math.PI) / p)); } return a * Math.pow(2, -10 * (k -= 1)) * Math.sin((k - s) * (2 * Math.PI) / p) * 0.5 + 1; }, // 在某一动画开始沿指示的路径进行动画处理前稍稍收回该动画的移动 /** * @param {number} k * @return {number} */ backIn: function (k) { var s = 1.70158; return k * k * ((s + 1) * k - s); }, /** * @param {number} k * @return {number} */ backOut: function (k) { var s = 1.70158; return --k * k * ((s + 1) * k + s) + 1; }, /** * @param {number} k * @return {number} */ backInOut: function (k) { var s = 1.70158 * 1.525; if ((k *= 2) < 1) { return 0.5 * (k * k * ((s + 1) * k - s)); } return 0.5 * ((k -= 2) * k * ((s + 1) * k + s) + 2); }, // 创建弹跳效果 /** * @param {number} k * @return {number} */ bounceIn: function (k) { return 1 - easing.bounceOut(1 - k); }, /** * @param {number} k * @return {number} */ bounceOut: function (k) { if (k < (1 / 2.75)) { return 7.5625 * k * k; } else if (k < (2 / 2.75)) { return 7.5625 * (k -= (1.5 / 2.75)) * k + 0.75; } else if (k < (2.5 / 2.75)) { return 7.5625 * (k -= (2.25 / 2.75)) * k + 0.9375; } else { return 7.5625 * (k -= (2.625 / 2.75)) * k + 0.984375; } }, /** * @param {number} k * @return {number} */ bounceInOut: function (k) { if (k < 0.5) { return easing.bounceIn(k * 2) * 0.5; } return easing.bounceOut(k * 2 - 1) * 0.5 + 0.5; } }; module.exports = easing; /***/ }, /* 39 */ /***/ function(module, exports) { /** * @module zrender/tool/color */ var kCSSColorTable = { 'transparent': [0,0,0,0], 'aliceblue': [240,248,255,1], 'antiquewhite': [250,235,215,1], 'aqua': [0,255,255,1], 'aquamarine': [127,255,212,1], 'azure': [240,255,255,1], 'beige': [245,245,220,1], 'bisque': [255,228,196,1], 'black': [0,0,0,1], 'blanchedalmond': [255,235,205,1], 'blue': [0,0,255,1], 'blueviolet': [138,43,226,1], 'brown': [165,42,42,1], 'burlywood': [222,184,135,1], 'cadetblue': [95,158,160,1], 'chartreuse': [127,255,0,1], 'chocolate': [210,105,30,1], 'coral': [255,127,80,1], 'cornflowerblue': [100,149,237,1], 'cornsilk': [255,248,220,1], 'crimson': [220,20,60,1], 'cyan': [0,255,255,1], 'darkblue': [0,0,139,1], 'darkcyan': [0,139,139,1], 'darkgoldenrod': [184,134,11,1], 'darkgray': [169,169,169,1], 'darkgreen': [0,100,0,1], 'darkgrey': [169,169,169,1], 'darkkhaki': [189,183,107,1], 'darkmagenta': [139,0,139,1], 'darkolivegreen': [85,107,47,1], 'darkorange': [255,140,0,1], 'darkorchid': [153,50,204,1], 'darkred': [139,0,0,1], 'darksalmon': [233,150,122,1], 'darkseagreen': [143,188,143,1], 'darkslateblue': [72,61,139,1], 'darkslategray': [47,79,79,1], 'darkslategrey': [47,79,79,1], 'darkturquoise': [0,206,209,1], 'darkviolet': [148,0,211,1], 'deeppink': [255,20,147,1], 'deepskyblue': [0,191,255,1], 'dimgray': [105,105,105,1], 'dimgrey': [105,105,105,1], 'dodgerblue': [30,144,255,1], 'firebrick': [178,34,34,1], 'floralwhite': [255,250,240,1], 'forestgreen': [34,139,34,1], 'fuchsia': [255,0,255,1], 'gainsboro': [220,220,220,1], 'ghostwhite': [248,248,255,1], 'gold': [255,215,0,1], 'goldenrod': [218,165,32,1], 'gray': [128,128,128,1], 'green': [0,128,0,1], 'greenyellow': [173,255,47,1], 'grey': [128,128,128,1], 'honeydew': [240,255,240,1], 'hotpink': [255,105,180,1], 'indianred': [205,92,92,1], 'indigo': [75,0,130,1], 'ivory': [255,255,240,1], 'khaki': [240,230,140,1], 'lavender': [230,230,250,1], 'lavenderblush': [255,240,245,1], 'lawngreen': [124,252,0,1], 'lemonchiffon': [255,250,205,1], 'lightblue': [173,216,230,1], 'lightcoral': [240,128,128,1], 'lightcyan': [224,255,255,1], 'lightgoldenrodyellow': [250,250,210,1], 'lightgray': [211,211,211,1], 'lightgreen': [144,238,144,1], 'lightgrey': [211,211,211,1], 'lightpink': [255,182,193,1], 'lightsalmon': [255,160,122,1], 'lightseagreen': [32,178,170,1], 'lightskyblue': [135,206,250,1], 'lightslategray': [119,136,153,1], 'lightslategrey': [119,136,153,1], 'lightsteelblue': [176,196,222,1], 'lightyellow': [255,255,224,1], 'lime': [0,255,0,1], 'limegreen': [50,205,50,1], 'linen': [250,240,230,1], 'magenta': [255,0,255,1], 'maroon': [128,0,0,1], 'mediumaquamarine': [102,205,170,1], 'mediumblue': [0,0,205,1], 'mediumorchid': [186,85,211,1], 'mediumpurple': [147,112,219,1], 'mediumseagreen': [60,179,113,1], 'mediumslateblue': [123,104,238,1], 'mediumspringgreen': [0,250,154,1], 'mediumturquoise': [72,209,204,1], 'mediumvioletred': [199,21,133,1], 'midnightblue': [25,25,112,1], 'mintcream': [245,255,250,1], 'mistyrose': [255,228,225,1], 'moccasin': [255,228,181,1], 'navajowhite': [255,222,173,1], 'navy': [0,0,128,1], 'oldlace': [253,245,230,1], 'olive': [128,128,0,1], 'olivedrab': [107,142,35,1], 'orange': [255,165,0,1], 'orangered': [255,69,0,1], 'orchid': [218,112,214,1], 'palegoldenrod': [238,232,170,1], 'palegreen': [152,251,152,1], 'paleturquoise': [175,238,238,1], 'palevioletred': [219,112,147,1], 'papayawhip': [255,239,213,1], 'peachpuff': [255,218,185,1], 'peru': [205,133,63,1], 'pink': [255,192,203,1], 'plum': [221,160,221,1], 'powderblue': [176,224,230,1], 'purple': [128,0,128,1], 'red': [255,0,0,1], 'rosybrown': [188,143,143,1], 'royalblue': [65,105,225,1], 'saddlebrown': [139,69,19,1], 'salmon': [250,128,114,1], 'sandybrown': [244,164,96,1], 'seagreen': [46,139,87,1], 'seashell': [255,245,238,1], 'sienna': [160,82,45,1], 'silver': [192,192,192,1], 'skyblue': [135,206,235,1], 'slateblue': [106,90,205,1], 'slategray': [112,128,144,1], 'slategrey': [112,128,144,1], 'snow': [255,250,250,1], 'springgreen': [0,255,127,1], 'steelblue': [70,130,180,1], 'tan': [210,180,140,1], 'teal': [0,128,128,1], 'thistle': [216,191,216,1], 'tomato': [255,99,71,1], 'turquoise': [64,224,208,1], 'violet': [238,130,238,1], 'wheat': [245,222,179,1], 'white': [255,255,255,1], 'whitesmoke': [245,245,245,1], 'yellow': [255,255,0,1], 'yellowgreen': [154,205,50,1] }; function clampCssByte(i) { // Clamp to integer 0 .. 255. i = Math.round(i); // Seems to be what Chrome does (vs truncation). return i < 0 ? 0 : i > 255 ? 255 : i; } function clampCssAngle(i) { // Clamp to integer 0 .. 360. i = Math.round(i); // Seems to be what Chrome does (vs truncation). return i < 0 ? 0 : i > 360 ? 360 : i; } function clampCssFloat(f) { // Clamp to float 0.0 .. 1.0. return f < 0 ? 0 : f > 1 ? 1 : f; } function parseCssInt(str) { // int or percentage. if (str.length && str.charAt(str.length - 1) === '%') { return clampCssByte(parseFloat(str) / 100 * 255); } return clampCssByte(parseInt(str, 10)); } function parseCssFloat(str) { // float or percentage. if (str.length && str.charAt(str.length - 1) === '%') { return clampCssFloat(parseFloat(str) / 100); } return clampCssFloat(parseFloat(str)); } function cssHueToRgb(m1, m2, h) { if (h < 0) { h += 1; } else if (h > 1) { h -= 1; } if (h * 6 < 1) { return m1 + (m2 - m1) * h * 6; } if (h * 2 < 1) { return m2; } if (h * 3 < 2) { return m1 + (m2 - m1) * (2/3 - h) * 6; } return m1; } function lerp(a, b, p) { return a + (b - a) * p; } /** * @param {string} colorStr * @return {Array.} * @memberOf module:zrender/util/color */ function parse(colorStr) { if (!colorStr) { return; } // colorStr may be not string colorStr = colorStr + ''; // Remove all whitespace, not compliant, but should just be more accepting. var str = colorStr.replace(/ /g, '').toLowerCase(); // Color keywords (and transparent) lookup. if (str in kCSSColorTable) { return kCSSColorTable[str].slice(); // dup. } // #abc and #abc123 syntax. if (str.charAt(0) === '#') { if (str.length === 4) { var iv = parseInt(str.substr(1), 16); // TODO(deanm): Stricter parsing. if (!(iv >= 0 && iv <= 0xfff)) { return; // Covers NaN. } return [ ((iv & 0xf00) >> 4) | ((iv & 0xf00) >> 8), (iv & 0xf0) | ((iv & 0xf0) >> 4), (iv & 0xf) | ((iv & 0xf) << 4), 1 ]; } else if (str.length === 7) { var iv = parseInt(str.substr(1), 16); // TODO(deanm): Stricter parsing. if (!(iv >= 0 && iv <= 0xffffff)) { return; // Covers NaN. } return [ (iv & 0xff0000) >> 16, (iv & 0xff00) >> 8, iv & 0xff, 1 ]; } return; } var op = str.indexOf('('), ep = str.indexOf(')'); if (op !== -1 && ep + 1 === str.length) { var fname = str.substr(0, op); var params = str.substr(op + 1, ep - (op + 1)).split(','); var alpha = 1; // To allow case fallthrough. switch (fname) { case 'rgba': if (params.length !== 4) { return; } alpha = parseCssFloat(params.pop()); // jshint ignore:line // Fall through. case 'rgb': if (params.length !== 3) { return; } return [ parseCssInt(params[0]), parseCssInt(params[1]), parseCssInt(params[2]), alpha ]; case 'hsla': if (params.length !== 4) { return; } params[3] = parseCssFloat(params[3]); return hsla2rgba(params); case 'hsl': if (params.length !== 3) { return; } return hsla2rgba(params); default: return; } } return; } /** * @param {Array.} hsla * @return {Array.} rgba */ function hsla2rgba(hsla) { var h = (((parseFloat(hsla[0]) % 360) + 360) % 360) / 360; // 0 .. 1 // NOTE(deanm): According to the CSS spec s/l should only be // percentages, but we don't bother and let float or percentage. var s = parseCssFloat(hsla[1]); var l = parseCssFloat(hsla[2]); var m2 = l <= 0.5 ? l * (s + 1) : l + s - l * s; var m1 = l * 2 - m2; var rgba = [ clampCssByte(cssHueToRgb(m1, m2, h + 1 / 3) * 255), clampCssByte(cssHueToRgb(m1, m2, h) * 255), clampCssByte(cssHueToRgb(m1, m2, h - 1 / 3) * 255) ]; if (hsla.length === 4) { rgba[3] = hsla[3]; } return rgba; } /** * @param {Array.} rgba * @return {Array.} hsla */ function rgba2hsla(rgba) { if (!rgba) { return; } // RGB from 0 to 255 var R = rgba[0] / 255; var G = rgba[1] / 255; var B = rgba[2] / 255; var vMin = Math.min(R, G, B); // Min. value of RGB var vMax = Math.max(R, G, B); // Max. value of RGB var delta = vMax - vMin; // Delta RGB value var L = (vMax + vMin) / 2; var H; var S; // HSL results from 0 to 1 if (delta === 0) { H = 0; S = 0; } else { if (L < 0.5) { S = delta / (vMax + vMin); } else { S = delta / (2 - vMax - vMin); } var deltaR = (((vMax - R) / 6) + (delta / 2)) / delta; var deltaG = (((vMax - G) / 6) + (delta / 2)) / delta; var deltaB = (((vMax - B) / 6) + (delta / 2)) / delta; if (R === vMax) { H = deltaB - deltaG; } else if (G === vMax) { H = (1 / 3) + deltaR - deltaB; } else if (B === vMax) { H = (2 / 3) + deltaG - deltaR; } if (H < 0) { H += 1; } if (H > 1) { H -= 1; } } var hsla = [H * 360, S, L]; if (rgba[3] != null) { hsla.push(rgba[3]); } return hsla; } /** * @param {string} color * @param {number} level * @return {string} * @memberOf module:zrender/util/color */ function lift(color, level) { var colorArr = parse(color); if (colorArr) { for (var i = 0; i < 3; i++) { if (level < 0) { colorArr[i] = colorArr[i] * (1 - level) | 0; } else { colorArr[i] = ((255 - colorArr[i]) * level + colorArr[i]) | 0; } } return stringify(colorArr, colorArr.length === 4 ? 'rgba' : 'rgb'); } } /** * @param {string} color * @return {string} * @memberOf module:zrender/util/color */ function toHex(color, level) { var colorArr = parse(color); if (colorArr) { return ((1 << 24) + (colorArr[0] << 16) + (colorArr[1] << 8) + (+colorArr[2])).toString(16).slice(1); } } /** * Map value to color. Faster than mapToColor methods because color is represented by rgba array * @param {number} normalizedValue A float between 0 and 1. * @param {Array.>} colors List of rgba color array * @param {Array.} [out] Mapped gba color array * @return {Array.} */ function fastMapToColor(normalizedValue, colors, out) { if (!(colors && colors.length) || !(normalizedValue >= 0 && normalizedValue <= 1) ) { return; } out = out || [0, 0, 0, 0]; var value = normalizedValue * (colors.length - 1); var leftIndex = Math.floor(value); var rightIndex = Math.ceil(value); var leftColor = colors[leftIndex]; var rightColor = colors[rightIndex]; var dv = value - leftIndex; out[0] = clampCssByte(lerp(leftColor[0], rightColor[0], dv)); out[1] = clampCssByte(lerp(leftColor[1], rightColor[1], dv)); out[2] = clampCssByte(lerp(leftColor[2], rightColor[2], dv)); out[3] = clampCssByte(lerp(leftColor[3], rightColor[3], dv)); return out; } /** * @param {number} normalizedValue A float between 0 and 1. * @param {Array.} colors Color list. * @param {boolean=} fullOutput Default false. * @return {(string|Object)} Result color. If fullOutput, * return {color: ..., leftIndex: ..., rightIndex: ..., value: ...}, * @memberOf module:zrender/util/color */ function mapToColor(normalizedValue, colors, fullOutput) { if (!(colors && colors.length) || !(normalizedValue >= 0 && normalizedValue <= 1) ) { return; } var value = normalizedValue * (colors.length - 1); var leftIndex = Math.floor(value); var rightIndex = Math.ceil(value); var leftColor = parse(colors[leftIndex]); var rightColor = parse(colors[rightIndex]); var dv = value - leftIndex; var color = stringify( [ clampCssByte(lerp(leftColor[0], rightColor[0], dv)), clampCssByte(lerp(leftColor[1], rightColor[1], dv)), clampCssByte(lerp(leftColor[2], rightColor[2], dv)), clampCssFloat(lerp(leftColor[3], rightColor[3], dv)) ], 'rgba' ); return fullOutput ? { color: color, leftIndex: leftIndex, rightIndex: rightIndex, value: value } : color; } /** * @param {string} color * @param {number=} h 0 ~ 360, ignore when null. * @param {number=} s 0 ~ 1, ignore when null. * @param {number=} l 0 ~ 1, ignore when null. * @return {string} Color string in rgba format. * @memberOf module:zrender/util/color */ function modifyHSL(color, h, s, l) { color = parse(color); if (color) { color = rgba2hsla(color); h != null && (color[0] = clampCssAngle(h)); s != null && (color[1] = parseCssFloat(s)); l != null && (color[2] = parseCssFloat(l)); return stringify(hsla2rgba(color), 'rgba'); } } /** * @param {string} color * @param {number=} alpha 0 ~ 1 * @return {string} Color string in rgba format. * @memberOf module:zrender/util/color */ function modifyAlpha(color, alpha) { color = parse(color); if (color && alpha != null) { color[3] = clampCssFloat(alpha); return stringify(color, 'rgba'); } } /** * @param {Array.} colors Color list. * @param {string} type 'rgba', 'hsva', ... * @return {string} Result color. */ function stringify(arrColor, type) { var colorStr = arrColor[0] + ',' + arrColor[1] + ',' + arrColor[2]; if (type === 'rgba' || type === 'hsva' || type === 'hsla') { colorStr += ',' + arrColor[3]; } return type + '(' + colorStr + ')'; } module.exports = { parse: parse, lift: lift, toHex: toHex, fastMapToColor: fastMapToColor, mapToColor: mapToColor, modifyHSL: modifyHSL, modifyAlpha: modifyAlpha, stringify: stringify }; /***/ }, /* 40 */ /***/ function(module, exports, __webpack_require__) { var config = __webpack_require__(41); /** * @exports zrender/tool/log * @author Kener (@Kener-林峰, kener.linfeng@gmail.com) */ module.exports = function() { if (config.debugMode === 0) { return; } else if (config.debugMode == 1) { for (var k in arguments) { throw new Error(arguments[k]); } } else if (config.debugMode > 1) { for (var k in arguments) { console.log(arguments[k]); } } }; /* for debug return function(mes) { document.getElementById('wrong-message').innerHTML = mes + ' ' + (new Date() - 0) + '
' + document.getElementById('wrong-message').innerHTML; }; */ /***/ }, /* 41 */ /***/ function(module, exports) { var dpr = 1; // If in browser environment if (typeof window !== 'undefined') { dpr = Math.max(window.devicePixelRatio || 1, 1); } /** * config默认配置项 * @exports zrender/config * @author Kener (@Kener-林峰, kener.linfeng@gmail.com) */ var config = { /** * debug日志选项:catchBrushException为true下有效 * 0 : 不生成debug数据,发布用 * 1 : 异常抛出,调试用 * 2 : 控制台输出,调试用 */ debugMode: 0, // retina 屏幕优化 devicePixelRatio: dpr }; module.exports = config; /***/ }, /* 42 */ /***/ function(module, exports, __webpack_require__) { var Group = __webpack_require__(30); var componentUtil = __webpack_require__(20); var clazzUtil = __webpack_require__(13); var modelUtil = __webpack_require__(5); var zrUtil = __webpack_require__(4); function Chart() { /** * @type {module:zrender/container/Group} * @readOnly */ this.group = new Group(); /** * @type {string} * @readOnly */ this.uid = componentUtil.getUID('viewChart'); } Chart.prototype = { type: 'chart', /** * Init the chart * @param {module:echarts/model/Global} ecModel * @param {module:echarts/ExtensionAPI} api */ init: function (ecModel, api) {}, /** * Render the chart * @param {module:echarts/model/Series} seriesModel * @param {module:echarts/model/Global} ecModel * @param {module:echarts/ExtensionAPI} api * @param {Object} payload */ render: function (seriesModel, ecModel, api, payload) {}, /** * Highlight series or specified data item * @param {module:echarts/model/Series} seriesModel * @param {module:echarts/model/Global} ecModel * @param {module:echarts/ExtensionAPI} api * @param {Object} payload */ highlight: function (seriesModel, ecModel, api, payload) { toggleHighlight(seriesModel.getData(), payload, 'emphasis'); }, /** * Downplay series or specified data item * @param {module:echarts/model/Series} seriesModel * @param {module:echarts/model/Global} ecModel * @param {module:echarts/ExtensionAPI} api * @param {Object} payload */ downplay: function (seriesModel, ecModel, api, payload) { toggleHighlight(seriesModel.getData(), payload, 'normal'); }, /** * Remove self * @param {module:echarts/model/Global} ecModel * @param {module:echarts/ExtensionAPI} api */ remove: function (ecModel, api) { this.group.removeAll(); }, /** * Dispose self * @param {module:echarts/model/Global} ecModel * @param {module:echarts/ExtensionAPI} api */ dispose: function () {} /** * The view contains the given point. * @interface * @param {Array.} point * @return {boolean} */ // containPoint: function () {} }; var chartProto = Chart.prototype; chartProto.updateView = chartProto.updateLayout = chartProto.updateVisual = function (seriesModel, ecModel, api, payload) { this.render(seriesModel, ecModel, api, payload); }; /** * Set state of single element * @param {module:zrender/Element} el * @param {string} state */ function elSetState(el, state) { if (el) { el.trigger(state); if (el.type === 'group') { for (var i = 0; i < el.childCount(); i++) { elSetState(el.childAt(i), state); } } } } /** * @param {module:echarts/data/List} data * @param {Object} payload * @param {string} state 'normal'|'emphasis' * @inner */ function toggleHighlight(data, payload, state) { var dataIndex = modelUtil.queryDataIndex(data, payload); if (dataIndex != null) { zrUtil.each(modelUtil.normalizeToArray(dataIndex), function (dataIdx) { elSetState(data.getItemGraphicEl(dataIdx), state); }); } else { data.eachItemGraphicEl(function (el) { elSetState(el, state); }); } } // Enable Chart.extend. clazzUtil.enableClassExtend(Chart, ['dispose']); // Add capability of registerClass, getClass, hasClass, registerSubTypeDefaulter and so on. clazzUtil.enableClassManagement(Chart, {registerWhenExtend: true}); module.exports = Chart; /***/ }, /* 43 */ /***/ function(module, exports, __webpack_require__) { 'use strict'; var zrUtil = __webpack_require__(4); var pathTool = __webpack_require__(44); var round = Math.round; var Path = __webpack_require__(45); var colorTool = __webpack_require__(39); var matrix = __webpack_require__(11); var vector = __webpack_require__(10); var graphic = {}; graphic.Group = __webpack_require__(30); graphic.Image = __webpack_require__(61); graphic.Text = __webpack_require__(63); graphic.Circle = __webpack_require__(64); graphic.Sector = __webpack_require__(65); graphic.Ring = __webpack_require__(66); graphic.Polygon = __webpack_require__(67); graphic.Polyline = __webpack_require__(71); graphic.Rect = __webpack_require__(72); graphic.Line = __webpack_require__(74); graphic.BezierCurve = __webpack_require__(75); graphic.Arc = __webpack_require__(76); graphic.CompoundPath = __webpack_require__(77); graphic.LinearGradient = __webpack_require__(78); graphic.RadialGradient = __webpack_require__(80); graphic.BoundingRect = __webpack_require__(9); /** * Extend shape with parameters */ graphic.extendShape = function (opts) { return Path.extend(opts); }; /** * Extend path */ graphic.extendPath = function (pathData, opts) { return pathTool.extendFromString(pathData, opts); }; /** * Create a path element from path data string * @param {string} pathData * @param {Object} opts * @param {module:zrender/core/BoundingRect} rect * @param {string} [layout=cover] 'center' or 'cover' */ graphic.makePath = function (pathData, opts, rect, layout) { var path = pathTool.createFromString(pathData, opts); var boundingRect = path.getBoundingRect(); if (rect) { var aspect = boundingRect.width / boundingRect.height; if (layout === 'center') { // Set rect to center, keep width / height ratio. var width = rect.height * aspect; var height; if (width <= rect.width) { height = rect.height; } else { width = rect.width; height = width / aspect; } var cx = rect.x + rect.width / 2; var cy = rect.y + rect.height / 2; rect.x = cx - width / 2; rect.y = cy - height / 2; rect.width = width; rect.height = height; } this.resizePath(path, rect); } return path; }; graphic.mergePath = pathTool.mergePath, /** * Resize a path to fit the rect * @param {module:zrender/graphic/Path} path * @param {Object} rect */ graphic.resizePath = function (path, rect) { if (!path.applyTransform) { return; } var pathRect = path.getBoundingRect(); var m = pathRect.calculateTransform(rect); path.applyTransform(m); }; /** * Sub pixel optimize line for canvas * * @param {Object} param * @param {Object} [param.shape] * @param {number} [param.shape.x1] * @param {number} [param.shape.y1] * @param {number} [param.shape.x2] * @param {number} [param.shape.y2] * @param {Object} [param.style] * @param {number} [param.style.lineWidth] * @return {Object} Modified param */ graphic.subPixelOptimizeLine = function (param) { var subPixelOptimize = graphic.subPixelOptimize; var shape = param.shape; var lineWidth = param.style.lineWidth; if (round(shape.x1 * 2) === round(shape.x2 * 2)) { shape.x1 = shape.x2 = subPixelOptimize(shape.x1, lineWidth, true); } if (round(shape.y1 * 2) === round(shape.y2 * 2)) { shape.y1 = shape.y2 = subPixelOptimize(shape.y1, lineWidth, true); } return param; }; /** * Sub pixel optimize rect for canvas * * @param {Object} param * @param {Object} [param.shape] * @param {number} [param.shape.x] * @param {number} [param.shape.y] * @param {number} [param.shape.width] * @param {number} [param.shape.height] * @param {Object} [param.style] * @param {number} [param.style.lineWidth] * @return {Object} Modified param */ graphic.subPixelOptimizeRect = function (param) { var subPixelOptimize = graphic.subPixelOptimize; var shape = param.shape; var lineWidth = param.style.lineWidth; var originX = shape.x; var originY = shape.y; var originWidth = shape.width; var originHeight = shape.height; shape.x = subPixelOptimize(shape.x, lineWidth, true); shape.y = subPixelOptimize(shape.y, lineWidth, true); shape.width = Math.max( subPixelOptimize(originX + originWidth, lineWidth, false) - shape.x, originWidth === 0 ? 0 : 1 ); shape.height = Math.max( subPixelOptimize(originY + originHeight, lineWidth, false) - shape.y, originHeight === 0 ? 0 : 1 ); return param; }; /** * Sub pixel optimize for canvas * * @param {number} position Coordinate, such as x, y * @param {number} lineWidth Should be nonnegative integer. * @param {boolean=} positiveOrNegative Default false (negative). * @return {number} Optimized position. */ graphic.subPixelOptimize = function (position, lineWidth, positiveOrNegative) { // Assure that (position + lineWidth / 2) is near integer edge, // otherwise line will be fuzzy in canvas. var doubledPosition = round(position * 2); return (doubledPosition + round(lineWidth)) % 2 === 0 ? doubledPosition / 2 : (doubledPosition + (positiveOrNegative ? 1 : -1)) / 2; }; function hasFillOrStroke(fillOrStroke) { return fillOrStroke != null && fillOrStroke != 'none'; } function liftColor(color) { return typeof color === 'string' ? colorTool.lift(color, -0.1) : color; } /** * @private */ function cacheElementStl(el) { if (el.__hoverStlDirty) { var stroke = el.style.stroke; var fill = el.style.fill; // Create hoverStyle on mouseover var hoverStyle = el.__hoverStl; hoverStyle.fill = hoverStyle.fill || (hasFillOrStroke(fill) ? liftColor(fill) : null); hoverStyle.stroke = hoverStyle.stroke || (hasFillOrStroke(stroke) ? liftColor(stroke) : null); var normalStyle = {}; for (var name in hoverStyle) { if (hoverStyle.hasOwnProperty(name)) { normalStyle[name] = el.style[name]; } } el.__normalStl = normalStyle; el.__hoverStlDirty = false; } } /** * @private */ function doSingleEnterHover(el) { if (el.__isHover) { return; } cacheElementStl(el); if (el.useHoverLayer) { el.__zr && el.__zr.addHover(el, el.__hoverStl); } else { el.setStyle(el.__hoverStl); el.z2 += 1; } el.__isHover = true; } /** * @inner */ function doSingleLeaveHover(el) { if (!el.__isHover) { return; } var normalStl = el.__normalStl; if (el.useHoverLayer) { el.__zr && el.__zr.removeHover(el); } else { normalStl && el.setStyle(normalStl); el.z2 -= 1; } el.__isHover = false; } /** * @inner */ function doEnterHover(el) { el.type === 'group' ? el.traverse(function (child) { if (child.type !== 'group') { doSingleEnterHover(child); } }) : doSingleEnterHover(el); } function doLeaveHover(el) { el.type === 'group' ? el.traverse(function (child) { if (child.type !== 'group') { doSingleLeaveHover(child); } }) : doSingleLeaveHover(el); } /** * @inner */ function setElementHoverStl(el, hoverStl) { // If element has sepcified hoverStyle, then use it instead of given hoverStyle // Often used when item group has a label element and it's hoverStyle is different el.__hoverStl = el.hoverStyle || hoverStl || {}; el.__hoverStlDirty = true; if (el.__isHover) { cacheElementStl(el); } } /** * @inner */ function onElementMouseOver(e) { if (this.__hoverSilentOnTouch && e.zrByTouch) { return; } // Only if element is not in emphasis status !this.__isEmphasis && doEnterHover(this); } /** * @inner */ function onElementMouseOut(e) { if (this.__hoverSilentOnTouch && e.zrByTouch) { return; } // Only if element is not in emphasis status !this.__isEmphasis && doLeaveHover(this); } /** * @inner */ function enterEmphasis() { this.__isEmphasis = true; doEnterHover(this); } /** * @inner */ function leaveEmphasis() { this.__isEmphasis = false; doLeaveHover(this); } /** * Set hover style of element * @param {module:zrender/Element} el * @param {Object} [hoverStyle] * @param {Object} [opt] * @param {boolean} [opt.hoverSilentOnTouch=false] * In touch device, mouseover event will be trigger on touchstart event * (see module:zrender/dom/HandlerProxy). By this mechanism, we can * conviniently use hoverStyle when tap on touch screen without additional * code for compatibility. * But if the chart/component has select feature, which usually also use * hoverStyle, there might be conflict between 'select-highlight' and * 'hover-highlight' especially when roam is enabled (see geo for example). * In this case, hoverSilentOnTouch should be used to disable hover-highlight * on touch device. */ graphic.setHoverStyle = function (el, hoverStyle, opt) { el.__hoverSilentOnTouch = opt && opt.hoverSilentOnTouch; el.type === 'group' ? el.traverse(function (child) { if (child.type !== 'group') { setElementHoverStl(child, hoverStyle); } }) : setElementHoverStl(el, hoverStyle); // Duplicated function will be auto-ignored, see Eventful.js. el.on('mouseover', onElementMouseOver) .on('mouseout', onElementMouseOut); // Emphasis, normal can be triggered manually el.on('emphasis', enterEmphasis) .on('normal', leaveEmphasis); }; /** * Set text option in the style * @param {Object} textStyle * @param {module:echarts/model/Model} labelModel * @param {string} color */ graphic.setText = function (textStyle, labelModel, color) { var labelPosition = labelModel.getShallow('position') || 'inside'; var labelColor = labelPosition.indexOf('inside') >= 0 ? 'white' : color; var textStyleModel = labelModel.getModel('textStyle'); zrUtil.extend(textStyle, { textDistance: labelModel.getShallow('distance') || 5, textFont: textStyleModel.getFont(), textPosition: labelPosition, textFill: textStyleModel.getTextColor() || labelColor }); }; function animateOrSetProps(isUpdate, el, props, animatableModel, dataIndex, cb) { if (typeof dataIndex === 'function') { cb = dataIndex; dataIndex = null; } var animationEnabled = animatableModel && ( animatableModel.ifEnableAnimation ? animatableModel.ifEnableAnimation() // Directly use animation property : animatableModel.getShallow('animation') ); if (animationEnabled) { var postfix = isUpdate ? 'Update' : ''; var duration = animatableModel && animatableModel.getShallow('animationDuration' + postfix); var animationEasing = animatableModel && animatableModel.getShallow('animationEasing' + postfix); var animationDelay = animatableModel && animatableModel.getShallow('animationDelay' + postfix); if (typeof animationDelay === 'function') { animationDelay = animationDelay(dataIndex); } duration > 0 ? el.animateTo(props, duration, animationDelay || 0, animationEasing, cb) : (el.attr(props), cb && cb()); } else { el.attr(props); cb && cb(); } } /** * Update graphic element properties with or without animation according to the configuration in series * @param {module:zrender/Element} el * @param {Object} props * @param {module:echarts/model/Model} [animatableModel] * @param {number} [dataIndex] * @param {Function} [cb] * @example * graphic.updateProps(el, { * position: [100, 100] * }, seriesModel, dataIndex, function () { console.log('Animation done!'); }); * // Or * graphic.updateProps(el, { * position: [100, 100] * }, seriesModel, function () { console.log('Animation done!'); }); */ graphic.updateProps = function (el, props, animatableModel, dataIndex, cb) { animateOrSetProps(true, el, props, animatableModel, dataIndex, cb); }; /** * Init graphic element properties with or without animation according to the configuration in series * @param {module:zrender/Element} el * @param {Object} props * @param {module:echarts/model/Model} [animatableModel] * @param {number} [dataIndex] * @param {Function} cb */ graphic.initProps = function (el, props, animatableModel, dataIndex, cb) { animateOrSetProps(false, el, props, animatableModel, dataIndex, cb); }; /** * Get transform matrix of target (param target), * in coordinate of its ancestor (param ancestor) * * @param {module:zrender/mixin/Transformable} target * @param {module:zrender/mixin/Transformable} [ancestor] */ graphic.getTransform = function (target, ancestor) { var mat = matrix.identity([]); while (target && target !== ancestor) { matrix.mul(mat, target.getLocalTransform(), mat); target = target.parent; } return mat; }; /** * Apply transform to an vertex. * @param {Array.} vertex [x, y] * @param {Array.} transform Transform matrix: like [1, 0, 0, 1, 0, 0] * @param {boolean=} invert Whether use invert matrix. * @return {Array.} [x, y] */ graphic.applyTransform = function (vertex, transform, invert) { if (invert) { transform = matrix.invert([], transform); } return vector.applyTransform([], vertex, transform); }; /** * @param {string} direction 'left' 'right' 'top' 'bottom' * @param {Array.} transform Transform matrix: like [1, 0, 0, 1, 0, 0] * @param {boolean=} invert Whether use invert matrix. * @return {string} Transformed direction. 'left' 'right' 'top' 'bottom' */ graphic.transformDirection = function (direction, transform, invert) { // Pick a base, ensure that transform result will not be (0, 0). var hBase = (transform[4] === 0 || transform[5] === 0 || transform[0] === 0) ? 1 : Math.abs(2 * transform[4] / transform[0]); var vBase = (transform[4] === 0 || transform[5] === 0 || transform[2] === 0) ? 1 : Math.abs(2 * transform[4] / transform[2]); var vertex = [ direction === 'left' ? -hBase : direction === 'right' ? hBase : 0, direction === 'top' ? -vBase : direction === 'bottom' ? vBase : 0 ]; vertex = graphic.applyTransform(vertex, transform, invert); return Math.abs(vertex[0]) > Math.abs(vertex[1]) ? (vertex[0] > 0 ? 'right' : 'left') : (vertex[1] > 0 ? 'bottom' : 'top'); }; /** * Apply group transition animation from g1 to g2 */ graphic.groupTransition = function (g1, g2, animatableModel, cb) { if (!g1 || !g2) { return; } function getElMap(g) { var elMap = {}; g.traverse(function (el) { if (!el.isGroup && el.anid) { elMap[el.anid] = el; } }); return elMap; } function getAnimatableProps(el) { var obj = { position: vector.clone(el.position), rotation: el.rotation }; if (el.shape) { obj.shape = zrUtil.extend({}, el.shape); } return obj; } var elMap1 = getElMap(g1); g2.traverse(function (el) { if (!el.isGroup && el.anid) { var oldEl = elMap1[el.anid]; if (oldEl) { var newProp = getAnimatableProps(el); el.attr(getAnimatableProps(oldEl)); graphic.updateProps(el, newProp, animatableModel, el.dataIndex); } // else { // if (el.previousProps) { // graphic.updateProps // } // } } }); }; module.exports = graphic; /***/ }, /* 44 */ /***/ function(module, exports, __webpack_require__) { var Path = __webpack_require__(45); var PathProxy = __webpack_require__(49); var transformPath = __webpack_require__(60); var matrix = __webpack_require__(11); // command chars var cc = [ 'm', 'M', 'l', 'L', 'v', 'V', 'h', 'H', 'z', 'Z', 'c', 'C', 'q', 'Q', 't', 'T', 's', 'S', 'a', 'A' ]; var mathSqrt = Math.sqrt; var mathSin = Math.sin; var mathCos = Math.cos; var PI = Math.PI; var vMag = function(v) { return Math.sqrt(v[0] * v[0] + v[1] * v[1]); }; var vRatio = function(u, v) { return (u[0] * v[0] + u[1] * v[1]) / (vMag(u) * vMag(v)); }; var vAngle = function(u, v) { return (u[0] * v[1] < u[1] * v[0] ? -1 : 1) * Math.acos(vRatio(u, v)); }; function processArc(x1, y1, x2, y2, fa, fs, rx, ry, psiDeg, cmd, path) { var psi = psiDeg * (PI / 180.0); var xp = mathCos(psi) * (x1 - x2) / 2.0 + mathSin(psi) * (y1 - y2) / 2.0; var yp = -1 * mathSin(psi) * (x1 - x2) / 2.0 + mathCos(psi) * (y1 - y2) / 2.0; var lambda = (xp * xp) / (rx * rx) + (yp * yp) / (ry * ry); if (lambda > 1) { rx *= mathSqrt(lambda); ry *= mathSqrt(lambda); } var f = (fa === fs ? -1 : 1) * mathSqrt((((rx * rx) * (ry * ry)) - ((rx * rx) * (yp * yp)) - ((ry * ry) * (xp * xp))) / ((rx * rx) * (yp * yp) + (ry * ry) * (xp * xp)) ) || 0; var cxp = f * rx * yp / ry; var cyp = f * -ry * xp / rx; var cx = (x1 + x2) / 2.0 + mathCos(psi) * cxp - mathSin(psi) * cyp; var cy = (y1 + y2) / 2.0 + mathSin(psi) * cxp + mathCos(psi) * cyp; var theta = vAngle([ 1, 0 ], [ (xp - cxp) / rx, (yp - cyp) / ry ]); var u = [ (xp - cxp) / rx, (yp - cyp) / ry ]; var v = [ (-1 * xp - cxp) / rx, (-1 * yp - cyp) / ry ]; var dTheta = vAngle(u, v); if (vRatio(u, v) <= -1) { dTheta = PI; } if (vRatio(u, v) >= 1) { dTheta = 0; } if (fs === 0 && dTheta > 0) { dTheta = dTheta - 2 * PI; } if (fs === 1 && dTheta < 0) { dTheta = dTheta + 2 * PI; } path.addData(cmd, cx, cy, rx, ry, theta, dTheta, psi, fs); } function createPathProxyFromString(data) { if (!data) { return []; } // command string var cs = data.replace(/-/g, ' -') .replace(/ /g, ' ') .replace(/ /g, ',') .replace(/,,/g, ','); var n; // create pipes so that we can split the data for (n = 0; n < cc.length; n++) { cs = cs.replace(new RegExp(cc[n], 'g'), '|' + cc[n]); } // create array var arr = cs.split('|'); // init context point var cpx = 0; var cpy = 0; var path = new PathProxy(); var CMD = PathProxy.CMD; var prevCmd; for (n = 1; n < arr.length; n++) { var str = arr[n]; var c = str.charAt(0); var off = 0; var p = str.slice(1).replace(/e,-/g, 'e-').split(','); var cmd; if (p.length > 0 && p[0] === '') { p.shift(); } for (var i = 0; i < p.length; i++) { p[i] = parseFloat(p[i]); } while (off < p.length && !isNaN(p[off])) { if (isNaN(p[0])) { break; } var ctlPtx; var ctlPty; var rx; var ry; var psi; var fa; var fs; var x1 = cpx; var y1 = cpy; // convert l, H, h, V, and v to L switch (c) { case 'l': cpx += p[off++]; cpy += p[off++]; cmd = CMD.L; path.addData(cmd, cpx, cpy); break; case 'L': cpx = p[off++]; cpy = p[off++]; cmd = CMD.L; path.addData(cmd, cpx, cpy); break; case 'm': cpx += p[off++]; cpy += p[off++]; cmd = CMD.M; path.addData(cmd, cpx, cpy); c = 'l'; break; case 'M': cpx = p[off++]; cpy = p[off++]; cmd = CMD.M; path.addData(cmd, cpx, cpy); c = 'L'; break; case 'h': cpx += p[off++]; cmd = CMD.L; path.addData(cmd, cpx, cpy); break; case 'H': cpx = p[off++]; cmd = CMD.L; path.addData(cmd, cpx, cpy); break; case 'v': cpy += p[off++]; cmd = CMD.L; path.addData(cmd, cpx, cpy); break; case 'V': cpy = p[off++]; cmd = CMD.L; path.addData(cmd, cpx, cpy); break; case 'C': cmd = CMD.C; path.addData( cmd, p[off++], p[off++], p[off++], p[off++], p[off++], p[off++] ); cpx = p[off - 2]; cpy = p[off - 1]; break; case 'c': cmd = CMD.C; path.addData( cmd, p[off++] + cpx, p[off++] + cpy, p[off++] + cpx, p[off++] + cpy, p[off++] + cpx, p[off++] + cpy ); cpx += p[off - 2]; cpy += p[off - 1]; break; case 'S': ctlPtx = cpx; ctlPty = cpy; var len = path.len(); var pathData = path.data; if (prevCmd === CMD.C) { ctlPtx += cpx - pathData[len - 4]; ctlPty += cpy - pathData[len - 3]; } cmd = CMD.C; x1 = p[off++]; y1 = p[off++]; cpx = p[off++]; cpy = p[off++]; path.addData(cmd, ctlPtx, ctlPty, x1, y1, cpx, cpy); break; case 's': ctlPtx = cpx; ctlPty = cpy; var len = path.len(); var pathData = path.data; if (prevCmd === CMD.C) { ctlPtx += cpx - pathData[len - 4]; ctlPty += cpy - pathData[len - 3]; } cmd = CMD.C; x1 = cpx + p[off++]; y1 = cpy + p[off++]; cpx += p[off++]; cpy += p[off++]; path.addData(cmd, ctlPtx, ctlPty, x1, y1, cpx, cpy); break; case 'Q': x1 = p[off++]; y1 = p[off++]; cpx = p[off++]; cpy = p[off++]; cmd = CMD.Q; path.addData(cmd, x1, y1, cpx, cpy); break; case 'q': x1 = p[off++] + cpx; y1 = p[off++] + cpy; cpx += p[off++]; cpy += p[off++]; cmd = CMD.Q; path.addData(cmd, x1, y1, cpx, cpy); break; case 'T': ctlPtx = cpx; ctlPty = cpy; var len = path.len(); var pathData = path.data; if (prevCmd === CMD.Q) { ctlPtx += cpx - pathData[len - 4]; ctlPty += cpy - pathData[len - 3]; } cpx = p[off++]; cpy = p[off++]; cmd = CMD.Q; path.addData(cmd, ctlPtx, ctlPty, cpx, cpy); break; case 't': ctlPtx = cpx; ctlPty = cpy; var len = path.len(); var pathData = path.data; if (prevCmd === CMD.Q) { ctlPtx += cpx - pathData[len - 4]; ctlPty += cpy - pathData[len - 3]; } cpx += p[off++]; cpy += p[off++]; cmd = CMD.Q; path.addData(cmd, ctlPtx, ctlPty, cpx, cpy); break; case 'A': rx = p[off++]; ry = p[off++]; psi = p[off++]; fa = p[off++]; fs = p[off++]; x1 = cpx, y1 = cpy; cpx = p[off++]; cpy = p[off++]; cmd = CMD.A; processArc( x1, y1, cpx, cpy, fa, fs, rx, ry, psi, cmd, path ); break; case 'a': rx = p[off++]; ry = p[off++]; psi = p[off++]; fa = p[off++]; fs = p[off++]; x1 = cpx, y1 = cpy; cpx += p[off++]; cpy += p[off++]; cmd = CMD.A; processArc( x1, y1, cpx, cpy, fa, fs, rx, ry, psi, cmd, path ); break; } } if (c === 'z' || c === 'Z') { cmd = CMD.Z; path.addData(cmd); } prevCmd = cmd; } path.toStatic(); return path; } // TODO Optimize double memory cost problem function createPathOptions(str, opts) { var pathProxy = createPathProxyFromString(str); var transform; opts = opts || {}; opts.buildPath = function (path) { path.setData(pathProxy.data); transform && transformPath(path, transform); // Svg and vml renderer don't have context var ctx = path.getContext(); if (ctx) { path.rebuildPath(ctx); } }; opts.applyTransform = function (m) { if (!transform) { transform = matrix.create(); } matrix.mul(transform, m, transform); this.dirty(true); }; return opts; } module.exports = { /** * Create a Path object from path string data * http://www.w3.org/TR/SVG/paths.html#PathData * @param {Object} opts Other options */ createFromString: function (str, opts) { return new Path(createPathOptions(str, opts)); }, /** * Create a Path class from path string data * @param {string} str * @param {Object} opts Other options */ extendFromString: function (str, opts) { return Path.extend(createPathOptions(str, opts)); }, /** * Merge multiple paths */ // TODO Apply transform // TODO stroke dash // TODO Optimize double memory cost problem mergePath: function (pathEls, opts) { var pathList = []; var len = pathEls.length; for (var i = 0; i < len; i++) { var pathEl = pathEls[i]; if (pathEl.__dirty) { pathEl.buildPath(pathEl.path, pathEl.shape, true); } pathList.push(pathEl.path); } var pathBundle = new Path(opts); pathBundle.buildPath = function (path) { path.appendPath(pathList); // Svg and vml renderer don't have context var ctx = path.getContext(); if (ctx) { path.rebuildPath(ctx); } }; return pathBundle; } }; /***/ }, /* 45 */ /***/ function(module, exports, __webpack_require__) { /** * Path element * @module zrender/graphic/Path */ var Displayable = __webpack_require__(46); var zrUtil = __webpack_require__(4); var PathProxy = __webpack_require__(49); var pathContain = __webpack_require__(52); var Pattern = __webpack_require__(59); var getCanvasPattern = Pattern.prototype.getCanvasPattern; var abs = Math.abs; /** * @alias module:zrender/graphic/Path * @extends module:zrender/graphic/Displayable * @constructor * @param {Object} opts */ function Path(opts) { Displayable.call(this, opts); /** * @type {module:zrender/core/PathProxy} * @readOnly */ this.path = new PathProxy(); } Path.prototype = { constructor: Path, type: 'path', __dirtyPath: true, strokeContainThreshold: 5, brush: function (ctx, prevEl) { var style = this.style; var path = this.path; var hasStroke = style.hasStroke(); var hasFill = style.hasFill(); var fill = style.fill; var stroke = style.stroke; var hasFillGradient = hasFill && !!(fill.colorStops); var hasStrokeGradient = hasStroke && !!(stroke.colorStops); var hasFillPattern = hasFill && !!(fill.image); var hasStrokePattern = hasStroke && !!(stroke.image); style.bind(ctx, this, prevEl); this.setTransform(ctx); if (this.__dirty) { var rect = this.getBoundingRect(); // Update gradient because bounding rect may changed if (hasFillGradient) { this._fillGradient = style.getGradient(ctx, fill, rect); } if (hasStrokeGradient) { this._strokeGradient = style.getGradient(ctx, stroke, rect); } } // Use the gradient or pattern if (hasFillGradient) { // PENDING If may have affect the state ctx.fillStyle = this._fillGradient; } else if (hasFillPattern) { ctx.fillStyle = getCanvasPattern.call(fill, ctx); } if (hasStrokeGradient) { ctx.strokeStyle = this._strokeGradient; } else if (hasStrokePattern) { ctx.strokeStyle = getCanvasPattern.call(stroke, ctx); } var lineDash = style.lineDash; var lineDashOffset = style.lineDashOffset; var ctxLineDash = !!ctx.setLineDash; // Update path sx, sy var scale = this.getGlobalScale(); path.setScale(scale[0], scale[1]); // Proxy context // Rebuild path in following 2 cases // 1. Path is dirty // 2. Path needs javascript implemented lineDash stroking. // In this case, lineDash information will not be saved in PathProxy if (this.__dirtyPath || ( lineDash && !ctxLineDash && hasStroke )) { path = this.path.beginPath(ctx); // Setting line dash before build path if (lineDash && !ctxLineDash) { path.setLineDash(lineDash); path.setLineDashOffset(lineDashOffset); } this.buildPath(path, this.shape, false); // Clear path dirty flag this.__dirtyPath = false; } else { // Replay path building ctx.beginPath(); this.path.rebuildPath(ctx); } hasFill && path.fill(ctx); if (lineDash && ctxLineDash) { ctx.setLineDash(lineDash); ctx.lineDashOffset = lineDashOffset; } hasStroke && path.stroke(ctx); if (lineDash && ctxLineDash) { // PENDING // Remove lineDash ctx.setLineDash([]); } this.restoreTransform(ctx); // Draw rect text if (style.text != null) { // var rect = this.getBoundingRect(); this.drawRectText(ctx, this.getBoundingRect()); } }, // When bundling path, some shape may decide if use moveTo to begin a new subpath or closePath // Like in circle buildPath: function (ctx, shapeCfg, inBundle) {}, getBoundingRect: function () { var rect = this._rect; var style = this.style; var needsUpdateRect = !rect; if (needsUpdateRect) { var path = this.path; if (this.__dirtyPath) { path.beginPath(); this.buildPath(path, this.shape, false); } rect = path.getBoundingRect(); } this._rect = rect; if (style.hasStroke()) { // Needs update rect with stroke lineWidth when // 1. Element changes scale or lineWidth // 2. Shape is changed var rectWithStroke = this._rectWithStroke || (this._rectWithStroke = rect.clone()); if (this.__dirty || needsUpdateRect) { rectWithStroke.copy(rect); // FIXME Must after updateTransform var w = style.lineWidth; // PENDING, Min line width is needed when line is horizontal or vertical var lineScale = style.strokeNoScale ? this.getLineScale() : 1; // Only add extra hover lineWidth when there are no fill if (!style.hasFill()) { w = Math.max(w, this.strokeContainThreshold || 4); } // Consider line width // Line scale can't be 0; if (lineScale > 1e-10) { rectWithStroke.width += w / lineScale; rectWithStroke.height += w / lineScale; rectWithStroke.x -= w / lineScale / 2; rectWithStroke.y -= w / lineScale / 2; } } // Return rect with stroke return rectWithStroke; } return rect; }, contain: function (x, y) { var localPos = this.transformCoordToLocal(x, y); var rect = this.getBoundingRect(); var style = this.style; x = localPos[0]; y = localPos[1]; if (rect.contain(x, y)) { var pathData = this.path.data; if (style.hasStroke()) { var lineWidth = style.lineWidth; var lineScale = style.strokeNoScale ? this.getLineScale() : 1; // Line scale can't be 0; if (lineScale > 1e-10) { // Only add extra hover lineWidth when there are no fill if (!style.hasFill()) { lineWidth = Math.max(lineWidth, this.strokeContainThreshold); } if (pathContain.containStroke( pathData, lineWidth / lineScale, x, y )) { return true; } } } if (style.hasFill()) { return pathContain.contain(pathData, x, y); } } return false; }, /** * @param {boolean} dirtyPath */ dirty: function (dirtyPath) { if (dirtyPath == null) { dirtyPath = true; } // Only mark dirty, not mark clean if (dirtyPath) { this.__dirtyPath = dirtyPath; this._rect = null; } this.__dirty = true; this.__zr && this.__zr.refresh(); // Used as a clipping path if (this.__clipTarget) { this.__clipTarget.dirty(); } }, /** * Alias for animate('shape') * @param {boolean} loop */ animateShape: function (loop) { return this.animate('shape', loop); }, // Overwrite attrKV attrKV: function (key, value) { // FIXME if (key === 'shape') { this.setShape(value); this.__dirtyPath = true; this._rect = null; } else { Displayable.prototype.attrKV.call(this, key, value); } }, /** * @param {Object|string} key * @param {*} value */ setShape: function (key, value) { var shape = this.shape; // Path from string may not have shape if (shape) { if (zrUtil.isObject(key)) { for (var name in key) { if (key.hasOwnProperty(name)) { shape[name] = key[name]; } } } else { shape[key] = value; } this.dirty(true); } return this; }, getLineScale: function () { var m = this.transform; // Get the line scale. // Determinant of `m` means how much the area is enlarged by the // transformation. So its square root can be used as a scale factor // for width. return m && abs(m[0] - 1) > 1e-10 && abs(m[3] - 1) > 1e-10 ? Math.sqrt(abs(m[0] * m[3] - m[2] * m[1])) : 1; } }; /** * 扩展一个 Path element, 比如星形,圆等。 * Extend a path element * @param {Object} props * @param {string} props.type Path type * @param {Function} props.init Initialize * @param {Function} props.buildPath Overwrite buildPath method * @param {Object} [props.style] Extended default style config * @param {Object} [props.shape] Extended default shape config */ Path.extend = function (defaults) { var Sub = function (opts) { Path.call(this, opts); if (defaults.style) { // Extend default style this.style.extendFrom(defaults.style, false); } // Extend default shape var defaultShape = defaults.shape; if (defaultShape) { this.shape = this.shape || {}; var thisShape = this.shape; for (var name in defaultShape) { if ( ! thisShape.hasOwnProperty(name) && defaultShape.hasOwnProperty(name) ) { thisShape[name] = defaultShape[name]; } } } defaults.init && defaults.init.call(this, opts); }; zrUtil.inherits(Sub, Path); // FIXME 不能 extend position, rotation 等引用对象 for (var name in defaults) { // Extending prototype values and methods if (name !== 'style' && name !== 'shape') { Sub.prototype[name] = defaults[name]; } } return Sub; }; zrUtil.inherits(Path, Displayable); module.exports = Path; /***/ }, /* 46 */ /***/ function(module, exports, __webpack_require__) { /** * 可绘制的图形基类 * Base class of all displayable graphic objects * @module zrender/graphic/Displayable */ var zrUtil = __webpack_require__(4); var Style = __webpack_require__(47); var Element = __webpack_require__(31); var RectText = __webpack_require__(48); // var Stateful = require('./mixin/Stateful'); /** * @alias module:zrender/graphic/Displayable * @extends module:zrender/Element * @extends module:zrender/graphic/mixin/RectText */ function Displayable(opts) { opts = opts || {}; Element.call(this, opts); // Extend properties for (var name in opts) { if ( opts.hasOwnProperty(name) && name !== 'style' ) { this[name] = opts[name]; } } /** * @type {module:zrender/graphic/Style} */ this.style = new Style(opts.style); this._rect = null; // Shapes for cascade clipping. this.__clipPaths = []; // FIXME Stateful must be mixined after style is setted // Stateful.call(this, opts); } Displayable.prototype = { constructor: Displayable, type: 'displayable', /** * Displayable 是否为脏,Painter 中会根据该标记判断是否需要是否需要重新绘制 * Dirty flag. From which painter will determine if this displayable object needs brush * @name module:zrender/graphic/Displayable#__dirty * @type {boolean} */ __dirty: true, /** * 图形是否可见,为true时不绘制图形,但是仍能触发鼠标事件 * If ignore drawing of the displayable object. Mouse event will still be triggered * @name module:/zrender/graphic/Displayable#invisible * @type {boolean} * @default false */ invisible: false, /** * @name module:/zrender/graphic/Displayable#z * @type {number} * @default 0 */ z: 0, /** * @name module:/zrender/graphic/Displayable#z * @type {number} * @default 0 */ z2: 0, /** * z层level,决定绘画在哪层canvas中 * @name module:/zrender/graphic/Displayable#zlevel * @type {number} * @default 0 */ zlevel: 0, /** * 是否可拖拽 * @name module:/zrender/graphic/Displayable#draggable * @type {boolean} * @default false */ draggable: false, /** * 是否正在拖拽 * @name module:/zrender/graphic/Displayable#draggable * @type {boolean} * @default false */ dragging: false, /** * 是否相应鼠标事件 * @name module:/zrender/graphic/Displayable#silent * @type {boolean} * @default false */ silent: false, /** * If enable culling * @type {boolean} * @default false */ culling: false, /** * Mouse cursor when hovered * @name module:/zrender/graphic/Displayable#cursor * @type {string} */ cursor: 'pointer', /** * If hover area is bounding rect * @name module:/zrender/graphic/Displayable#rectHover * @type {string} */ rectHover: false, /** * Render the element progressively when the value >= 0, * usefull for large data. * @type {number} */ progressive: -1, beforeBrush: function (ctx) {}, afterBrush: function (ctx) {}, /** * 图形绘制方法 * @param {Canvas2DRenderingContext} ctx */ // Interface brush: function (ctx, prevEl) {}, /** * 获取最小包围盒 * @return {module:zrender/core/BoundingRect} */ // Interface getBoundingRect: function () {}, /** * 判断坐标 x, y 是否在图形上 * If displayable element contain coord x, y * @param {number} x * @param {number} y * @return {boolean} */ contain: function (x, y) { return this.rectContain(x, y); }, /** * @param {Function} cb * @param {} context */ traverse: function (cb, context) { cb.call(context, this); }, /** * 判断坐标 x, y 是否在图形的包围盒上 * If bounding rect of element contain coord x, y * @param {number} x * @param {number} y * @return {boolean} */ rectContain: function (x, y) { var coord = this.transformCoordToLocal(x, y); var rect = this.getBoundingRect(); return rect.contain(coord[0], coord[1]); }, /** * 标记图形元素为脏,并且在下一帧重绘 * Mark displayable element dirty and refresh next frame */ dirty: function () { this.__dirty = true; this._rect = null; this.__zr && this.__zr.refresh(); }, /** * 图形是否会触发事件 * If displayable object binded any event * @return {boolean} */ // TODO, 通过 bind 绑定的事件 // isSilent: function () { // return !( // this.hoverable || this.draggable // || this.onmousemove || this.onmouseover || this.onmouseout // || this.onmousedown || this.onmouseup || this.onclick // || this.ondragenter || this.ondragover || this.ondragleave // || this.ondrop // ); // }, /** * Alias for animate('style') * @param {boolean} loop */ animateStyle: function (loop) { return this.animate('style', loop); }, attrKV: function (key, value) { if (key !== 'style') { Element.prototype.attrKV.call(this, key, value); } else { this.style.set(value); } }, /** * @param {Object|string} key * @param {*} value */ setStyle: function (key, value) { this.style.set(key, value); this.dirty(false); return this; }, /** * Use given style object * @param {Object} obj */ useStyle: function (obj) { this.style = new Style(obj); this.dirty(false); return this; } }; zrUtil.inherits(Displayable, Element); zrUtil.mixin(Displayable, RectText); // zrUtil.mixin(Displayable, Stateful); module.exports = Displayable; /***/ }, /* 47 */ /***/ function(module, exports) { /** * @module zrender/graphic/Style */ var STYLE_COMMON_PROPS = [ ['shadowBlur', 0], ['shadowOffsetX', 0], ['shadowOffsetY', 0], ['shadowColor', '#000'], ['lineCap', 'butt'], ['lineJoin', 'miter'], ['miterLimit', 10] ]; // var SHADOW_PROPS = STYLE_COMMON_PROPS.slice(0, 4); // var LINE_PROPS = STYLE_COMMON_PROPS.slice(4); var Style = function (opts) { this.extendFrom(opts); }; function createLinearGradient(ctx, obj, rect) { // var size = var x = obj.x; var x2 = obj.x2; var y = obj.y; var y2 = obj.y2; if (!obj.global) { x = x * rect.width + rect.x; x2 = x2 * rect.width + rect.x; y = y * rect.height + rect.y; y2 = y2 * rect.height + rect.y; } var canvasGradient = ctx.createLinearGradient(x, y, x2, y2); return canvasGradient; } function createRadialGradient(ctx, obj, rect) { var width = rect.width; var height = rect.height; var min = Math.min(width, height); var x = obj.x; var y = obj.y; var r = obj.r; if (!obj.global) { x = x * width + rect.x; y = y * height + rect.y; r = r * min; } var canvasGradient = ctx.createRadialGradient(x, y, 0, x, y, r); return canvasGradient; } Style.prototype = { constructor: Style, /** * @type {string} */ fill: '#000000', /** * @type {string} */ stroke: null, /** * @type {number} */ opacity: 1, /** * @type {Array.} */ lineDash: null, /** * @type {number} */ lineDashOffset: 0, /** * @type {number} */ shadowBlur: 0, /** * @type {number} */ shadowOffsetX: 0, /** * @type {number} */ shadowOffsetY: 0, /** * @type {number} */ lineWidth: 1, /** * If stroke ignore scale * @type {Boolean} */ strokeNoScale: false, // Bounding rect text configuration // Not affected by element transform /** * @type {string} */ text: null, /** * @type {string} */ textFill: '#000', /** * @type {string} */ textStroke: null, /** * 'inside', 'left', 'right', 'top', 'bottom' * [x, y] * @type {string|Array.} * @default 'inside' */ textPosition: 'inside', /** * @type {string} */ textBaseline: null, /** * @type {string} */ textAlign: null, /** * @type {string} */ textVerticalAlign: null, /** * Only useful in Path and Image element * @type {number} */ textDistance: 5, /** * Only useful in Path and Image element * @type {number} */ textShadowBlur: 0, /** * Only useful in Path and Image element * @type {number} */ textShadowOffsetX: 0, /** * Only useful in Path and Image element * @type {number} */ textShadowOffsetY: 0, /** * If transform text * Only useful in Path and Image element * @type {boolean} */ textTransform: false, /** * Text rotate around position of Path or Image * Only useful in Path and Image element and textTransform is false. */ textRotation: 0, /** * @type {string} * https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/globalCompositeOperation */ blend: null, /** * @param {CanvasRenderingContext2D} ctx */ bind: function (ctx, el, prevEl) { var style = this; var prevStyle = prevEl && prevEl.style; var firstDraw = !prevStyle; for (var i = 0; i < STYLE_COMMON_PROPS.length; i++) { var prop = STYLE_COMMON_PROPS[i]; var styleName = prop[0]; if (firstDraw || style[styleName] !== prevStyle[styleName]) { // FIXME Invalid property value will cause style leak from previous element. ctx[styleName] = style[styleName] || prop[1]; } } if ((firstDraw || style.fill !== prevStyle.fill)) { ctx.fillStyle = style.fill; } if ((firstDraw || style.stroke !== prevStyle.stroke)) { ctx.strokeStyle = style.stroke; } if ((firstDraw || style.opacity !== prevStyle.opacity)) { ctx.globalAlpha = style.opacity == null ? 1 : style.opacity; } if ((firstDraw || style.blend !== prevStyle.blend)) { ctx.globalCompositeOperation = style.blend || 'source-over'; } if (this.hasStroke()) { var lineWidth = style.lineWidth; ctx.lineWidth = lineWidth / ( (this.strokeNoScale && el && el.getLineScale) ? el.getLineScale() : 1 ); } }, hasFill: function () { var fill = this.fill; return fill != null && fill !== 'none'; }, hasStroke: function () { var stroke = this.stroke; return stroke != null && stroke !== 'none' && this.lineWidth > 0; }, /** * Extend from other style * @param {zrender/graphic/Style} otherStyle * @param {boolean} overwrite */ extendFrom: function (otherStyle, overwrite) { if (otherStyle) { var target = this; for (var name in otherStyle) { if (otherStyle.hasOwnProperty(name) && (overwrite || ! target.hasOwnProperty(name)) ) { target[name] = otherStyle[name]; } } } }, /** * Batch setting style with a given object * @param {Object|string} obj * @param {*} [obj] */ set: function (obj, value) { if (typeof obj === 'string') { this[obj] = value; } else { this.extendFrom(obj, true); } }, /** * Clone * @return {zrender/graphic/Style} [description] */ clone: function () { var newStyle = new this.constructor(); newStyle.extendFrom(this, true); return newStyle; }, getGradient: function (ctx, obj, rect) { var method = obj.type === 'radial' ? createRadialGradient : createLinearGradient; var canvasGradient = method(ctx, obj, rect); var colorStops = obj.colorStops; for (var i = 0; i < colorStops.length; i++) { canvasGradient.addColorStop( colorStops[i].offset, colorStops[i].color ); } return canvasGradient; } }; var styleProto = Style.prototype; for (var i = 0; i < STYLE_COMMON_PROPS.length; i++) { var prop = STYLE_COMMON_PROPS[i]; if (!(prop[0] in styleProto)) { styleProto[prop[0]] = prop[1]; } } // Provide for others Style.getGradient = styleProto.getGradient; module.exports = Style; /***/ }, /* 48 */ /***/ function(module, exports, __webpack_require__) { /** * Mixin for drawing text in a element bounding rect * @module zrender/mixin/RectText */ var textContain = __webpack_require__(8); var BoundingRect = __webpack_require__(9); var tmpRect = new BoundingRect(); var RectText = function () {}; function parsePercent(value, maxValue) { if (typeof value === 'string') { if (value.lastIndexOf('%') >= 0) { return parseFloat(value) / 100 * maxValue; } return parseFloat(value); } return value; } RectText.prototype = { constructor: RectText, /** * Draw text in a rect with specified position. * @param {CanvasRenderingContext} ctx * @param {Object} rect Displayable rect * @return {Object} textRect Alternative precalculated text bounding rect */ drawRectText: function (ctx, rect, textRect) { var style = this.style; var text = style.text; // Convert to string text != null && (text += ''); if (!text) { return; } // FIXME ctx.save(); var x; var y; var textPosition = style.textPosition; var distance = style.textDistance; var align = style.textAlign; var font = style.textFont || style.font; var baseline = style.textBaseline; var verticalAlign = style.textVerticalAlign; textRect = textRect || textContain.getBoundingRect(text, font, align, baseline); // Transform rect to view space var transform = this.transform; if (!style.textTransform) { if (transform) { tmpRect.copy(rect); tmpRect.applyTransform(transform); rect = tmpRect; } } else { this.setTransform(ctx); } // Text position represented by coord if (textPosition instanceof Array) { // Percent x = rect.x + parsePercent(textPosition[0], rect.width); y = rect.y + parsePercent(textPosition[1], rect.height); align = align || 'left'; baseline = baseline || 'top'; if (verticalAlign) { switch (verticalAlign) { case 'middle': y -= textRect.height / 2 - textRect.lineHeight / 2; break; case 'bottom': y -= textRect.height - textRect.lineHeight / 2; break; default: y += textRect.lineHeight / 2; } // Force bseline to be middle baseline = 'middle'; } } else { var res = textContain.adjustTextPositionOnRect( textPosition, rect, textRect, distance ); x = res.x; y = res.y; // Default align and baseline when has textPosition align = align || res.textAlign; baseline = baseline || res.textBaseline; } // Use canvas default left textAlign. Giving invalid value will cause state not change ctx.textAlign = align || 'left'; // Use canvas default alphabetic baseline ctx.textBaseline = baseline || 'alphabetic'; var textFill = style.textFill; var textStroke = style.textStroke; textFill && (ctx.fillStyle = textFill); textStroke && (ctx.strokeStyle = textStroke); // TODO Invalid font ctx.font = font || '12px sans-serif'; // Text shadow // Always set shadowBlur and shadowOffset to avoid leak from displayable ctx.shadowBlur = style.textShadowBlur; ctx.shadowColor = style.textShadowColor || 'transparent'; ctx.shadowOffsetX = style.textShadowOffsetX; ctx.shadowOffsetY = style.textShadowOffsetY; var textLines = text.split('\n'); if (style.textRotation) { transform && ctx.translate(transform[4], transform[5]); ctx.rotate(style.textRotation); transform && ctx.translate(-transform[4], -transform[5]); } for (var i = 0; i < textLines.length; i++) { textFill && ctx.fillText(textLines[i], x, y); textStroke && ctx.strokeText(textLines[i], x, y); y += textRect.lineHeight; } ctx.restore(); } }; module.exports = RectText; /***/ }, /* 49 */ /***/ function(module, exports, __webpack_require__) { 'use strict'; /** * Path 代理,可以在`buildPath`中用于替代`ctx`, 会保存每个path操作的命令到pathCommands属性中 * 可以用于 isInsidePath 判断以及获取boundingRect * * @module zrender/core/PathProxy * @author Yi Shen (http://www.github.com/pissang) */ // TODO getTotalLength, getPointAtLength var curve = __webpack_require__(50); var vec2 = __webpack_require__(10); var bbox = __webpack_require__(51); var BoundingRect = __webpack_require__(9); var dpr = __webpack_require__(41).devicePixelRatio; var CMD = { M: 1, L: 2, C: 3, Q: 4, A: 5, Z: 6, // Rect R: 7 }; var min = []; var max = []; var min2 = []; var max2 = []; var mathMin = Math.min; var mathMax = Math.max; var mathCos = Math.cos; var mathSin = Math.sin; var mathSqrt = Math.sqrt; var mathAbs = Math.abs; var hasTypedArray = typeof Float32Array != 'undefined'; /** * @alias module:zrender/core/PathProxy * @constructor */ var PathProxy = function () { /** * Path data. Stored as flat array * @type {Array.} */ this.data = []; this._len = 0; this._ctx = null; this._xi = 0; this._yi = 0; this._x0 = 0; this._y0 = 0; // Unit x, Unit y. Provide for avoiding drawing that too short line segment this._ux = 0; this._uy = 0; }; /** * 快速计算Path包围盒(并不是最小包围盒) * @return {Object} */ PathProxy.prototype = { constructor: PathProxy, _lineDash: null, _dashOffset: 0, _dashIdx: 0, _dashSum: 0, /** * @readOnly */ setScale: function (sx, sy) { this._ux = mathAbs(1 / dpr / sx) || 0; this._uy = mathAbs(1 / dpr / sy) || 0; }, getContext: function () { return this._ctx; }, /** * @param {CanvasRenderingContext2D} ctx * @return {module:zrender/core/PathProxy} */ beginPath: function (ctx) { this._ctx = ctx; ctx && ctx.beginPath(); ctx && (this.dpr = ctx.dpr); // Reset this._len = 0; if (this._lineDash) { this._lineDash = null; this._dashOffset = 0; } return this; }, /** * @param {number} x * @param {number} y * @return {module:zrender/core/PathProxy} */ moveTo: function (x, y) { this.addData(CMD.M, x, y); this._ctx && this._ctx.moveTo(x, y); // x0, y0, xi, yi 是记录在 _dashedXXXXTo 方法中使用 // xi, yi 记录当前点, x0, y0 在 closePath 的时候回到起始点。 // 有可能在 beginPath 之后直接调用 lineTo,这时候 x0, y0 需要 // 在 lineTo 方法中记录,这里先不考虑这种情况,dashed line 也只在 IE10- 中不支持 this._x0 = x; this._y0 = y; this._xi = x; this._yi = y; return this; }, /** * @param {number} x * @param {number} y * @return {module:zrender/core/PathProxy} */ lineTo: function (x, y) { var exceedUnit = mathAbs(x - this._xi) > this._ux || mathAbs(y - this._yi) > this._uy // Force draw the first segment || this._len < 5; this.addData(CMD.L, x, y); if (this._ctx && exceedUnit) { this._needsDash() ? this._dashedLineTo(x, y) : this._ctx.lineTo(x, y); } if (exceedUnit) { this._xi = x; this._yi = y; } return this; }, /** * @param {number} x1 * @param {number} y1 * @param {number} x2 * @param {number} y2 * @param {number} x3 * @param {number} y3 * @return {module:zrender/core/PathProxy} */ bezierCurveTo: function (x1, y1, x2, y2, x3, y3) { this.addData(CMD.C, x1, y1, x2, y2, x3, y3); if (this._ctx) { this._needsDash() ? this._dashedBezierTo(x1, y1, x2, y2, x3, y3) : this._ctx.bezierCurveTo(x1, y1, x2, y2, x3, y3); } this._xi = x3; this._yi = y3; return this; }, /** * @param {number} x1 * @param {number} y1 * @param {number} x2 * @param {number} y2 * @return {module:zrender/core/PathProxy} */ quadraticCurveTo: function (x1, y1, x2, y2) { this.addData(CMD.Q, x1, y1, x2, y2); if (this._ctx) { this._needsDash() ? this._dashedQuadraticTo(x1, y1, x2, y2) : this._ctx.quadraticCurveTo(x1, y1, x2, y2); } this._xi = x2; this._yi = y2; return this; }, /** * @param {number} cx * @param {number} cy * @param {number} r * @param {number} startAngle * @param {number} endAngle * @param {boolean} anticlockwise * @return {module:zrender/core/PathProxy} */ arc: function (cx, cy, r, startAngle, endAngle, anticlockwise) { this.addData( CMD.A, cx, cy, r, r, startAngle, endAngle - startAngle, 0, anticlockwise ? 0 : 1 ); this._ctx && this._ctx.arc(cx, cy, r, startAngle, endAngle, anticlockwise); this._xi = mathCos(endAngle) * r + cx; this._xi = mathSin(endAngle) * r + cx; return this; }, // TODO arcTo: function (x1, y1, x2, y2, radius) { if (this._ctx) { this._ctx.arcTo(x1, y1, x2, y2, radius); } return this; }, // TODO rect: function (x, y, w, h) { this._ctx && this._ctx.rect(x, y, w, h); this.addData(CMD.R, x, y, w, h); return this; }, /** * @return {module:zrender/core/PathProxy} */ closePath: function () { this.addData(CMD.Z); var ctx = this._ctx; var x0 = this._x0; var y0 = this._y0; if (ctx) { this._needsDash() && this._dashedLineTo(x0, y0); ctx.closePath(); } this._xi = x0; this._yi = y0; return this; }, /** * Context 从外部传入,因为有可能是 rebuildPath 完之后再 fill。 * stroke 同样 * @param {CanvasRenderingContext2D} ctx * @return {module:zrender/core/PathProxy} */ fill: function (ctx) { ctx && ctx.fill(); this.toStatic(); }, /** * @param {CanvasRenderingContext2D} ctx * @return {module:zrender/core/PathProxy} */ stroke: function (ctx) { ctx && ctx.stroke(); this.toStatic(); }, /** * 必须在其它绘制命令前调用 * Must be invoked before all other path drawing methods * @return {module:zrender/core/PathProxy} */ setLineDash: function (lineDash) { if (lineDash instanceof Array) { this._lineDash = lineDash; this._dashIdx = 0; var lineDashSum = 0; for (var i = 0; i < lineDash.length; i++) { lineDashSum += lineDash[i]; } this._dashSum = lineDashSum; } return this; }, /** * 必须在其它绘制命令前调用 * Must be invoked before all other path drawing methods * @return {module:zrender/core/PathProxy} */ setLineDashOffset: function (offset) { this._dashOffset = offset; return this; }, /** * * @return {boolean} */ len: function () { return this._len; }, /** * 直接设置 Path 数据 */ setData: function (data) { var len = data.length; if (! (this.data && this.data.length == len) && hasTypedArray) { this.data = new Float32Array(len); } for (var i = 0; i < len; i++) { this.data[i] = data[i]; } this._len = len; }, /** * 添加子路径 * @param {module:zrender/core/PathProxy|Array.} path */ appendPath: function (path) { if (!(path instanceof Array)) { path = [path]; } var len = path.length; var appendSize = 0; var offset = this._len; for (var i = 0; i < len; i++) { appendSize += path[i].len(); } if (hasTypedArray && (this.data instanceof Float32Array)) { this.data = new Float32Array(offset + appendSize); } for (var i = 0; i < len; i++) { var appendPathData = path[i].data; for (var k = 0; k < appendPathData.length; k++) { this.data[offset++] = appendPathData[k]; } } this._len = offset; }, /** * 填充 Path 数据。 * 尽量复用而不申明新的数组。大部分图形重绘的指令数据长度都是不变的。 */ addData: function (cmd) { var data = this.data; if (this._len + arguments.length > data.length) { // 因为之前的数组已经转换成静态的 Float32Array // 所以不够用时需要扩展一个新的动态数组 this._expandData(); data = this.data; } for (var i = 0; i < arguments.length; i++) { data[this._len++] = arguments[i]; } this._prevCmd = cmd; }, _expandData: function () { // Only if data is Float32Array if (!(this.data instanceof Array)) { var newData = []; for (var i = 0; i < this._len; i++) { newData[i] = this.data[i]; } this.data = newData; } }, /** * If needs js implemented dashed line * @return {boolean} * @private */ _needsDash: function () { return this._lineDash; }, _dashedLineTo: function (x1, y1) { var dashSum = this._dashSum; var offset = this._dashOffset; var lineDash = this._lineDash; var ctx = this._ctx; var x0 = this._xi; var y0 = this._yi; var dx = x1 - x0; var dy = y1 - y0; var dist = mathSqrt(dx * dx + dy * dy); var x = x0; var y = y0; var dash; var nDash = lineDash.length; var idx; dx /= dist; dy /= dist; if (offset < 0) { // Convert to positive offset offset = dashSum + offset; } offset %= dashSum; x -= offset * dx; y -= offset * dy; while ((dx > 0 && x <= x1) || (dx < 0 && x >= x1) || (dx == 0 && ((dy > 0 && y <= y1) || (dy < 0 && y >= y1)))) { idx = this._dashIdx; dash = lineDash[idx]; x += dx * dash; y += dy * dash; this._dashIdx = (idx + 1) % nDash; // Skip positive offset if ((dx > 0 && x < x0) || (dx < 0 && x > x0) || (dy > 0 && y < y0) || (dy < 0 && y > y0)) { continue; } ctx[idx % 2 ? 'moveTo' : 'lineTo']( dx >= 0 ? mathMin(x, x1) : mathMax(x, x1), dy >= 0 ? mathMin(y, y1) : mathMax(y, y1) ); } // Offset for next lineTo dx = x - x1; dy = y - y1; this._dashOffset = -mathSqrt(dx * dx + dy * dy); }, // Not accurate dashed line to _dashedBezierTo: function (x1, y1, x2, y2, x3, y3) { var dashSum = this._dashSum; var offset = this._dashOffset; var lineDash = this._lineDash; var ctx = this._ctx; var x0 = this._xi; var y0 = this._yi; var t; var dx; var dy; var cubicAt = curve.cubicAt; var bezierLen = 0; var idx = this._dashIdx; var nDash = lineDash.length; var x; var y; var tmpLen = 0; if (offset < 0) { // Convert to positive offset offset = dashSum + offset; } offset %= dashSum; // Bezier approx length for (t = 0; t < 1; t += 0.1) { dx = cubicAt(x0, x1, x2, x3, t + 0.1) - cubicAt(x0, x1, x2, x3, t); dy = cubicAt(y0, y1, y2, y3, t + 0.1) - cubicAt(y0, y1, y2, y3, t); bezierLen += mathSqrt(dx * dx + dy * dy); } // Find idx after add offset for (; idx < nDash; idx++) { tmpLen += lineDash[idx]; if (tmpLen > offset) { break; } } t = (tmpLen - offset) / bezierLen; while (t <= 1) { x = cubicAt(x0, x1, x2, x3, t); y = cubicAt(y0, y1, y2, y3, t); // Use line to approximate dashed bezier // Bad result if dash is long idx % 2 ? ctx.moveTo(x, y) : ctx.lineTo(x, y); t += lineDash[idx] / bezierLen; idx = (idx + 1) % nDash; } // Finish the last segment and calculate the new offset (idx % 2 !== 0) && ctx.lineTo(x3, y3); dx = x3 - x; dy = y3 - y; this._dashOffset = -mathSqrt(dx * dx + dy * dy); }, _dashedQuadraticTo: function (x1, y1, x2, y2) { // Convert quadratic to cubic using degree elevation var x3 = x2; var y3 = y2; x2 = (x2 + 2 * x1) / 3; y2 = (y2 + 2 * y1) / 3; x1 = (this._xi + 2 * x1) / 3; y1 = (this._yi + 2 * y1) / 3; this._dashedBezierTo(x1, y1, x2, y2, x3, y3); }, /** * 转成静态的 Float32Array 减少堆内存占用 * Convert dynamic array to static Float32Array */ toStatic: function () { var data = this.data; if (data instanceof Array) { data.length = this._len; if (hasTypedArray) { this.data = new Float32Array(data); } } }, /** * @return {module:zrender/core/BoundingRect} */ getBoundingRect: function () { min[0] = min[1] = min2[0] = min2[1] = Number.MAX_VALUE; max[0] = max[1] = max2[0] = max2[1] = -Number.MAX_VALUE; var data = this.data; var xi = 0; var yi = 0; var x0 = 0; var y0 = 0; for (var i = 0; i < data.length;) { var cmd = data[i++]; if (i == 1) { // 如果第一个命令是 L, C, Q // 则 previous point 同绘制命令的第一个 point // // 第一个命令为 Arc 的情况下会在后面特殊处理 xi = data[i]; yi = data[i + 1]; x0 = xi; y0 = yi; } switch (cmd) { case CMD.M: // moveTo 命令重新创建一个新的 subpath, 并且更新新的起点 // 在 closePath 的时候使用 x0 = data[i++]; y0 = data[i++]; xi = x0; yi = y0; min2[0] = x0; min2[1] = y0; max2[0] = x0; max2[1] = y0; break; case CMD.L: bbox.fromLine(xi, yi, data[i], data[i + 1], min2, max2); xi = data[i++]; yi = data[i++]; break; case CMD.C: bbox.fromCubic( xi, yi, data[i++], data[i++], data[i++], data[i++], data[i], data[i + 1], min2, max2 ); xi = data[i++]; yi = data[i++]; break; case CMD.Q: bbox.fromQuadratic( xi, yi, data[i++], data[i++], data[i], data[i + 1], min2, max2 ); xi = data[i++]; yi = data[i++]; break; case CMD.A: // TODO Arc 判断的开销比较大 var cx = data[i++]; var cy = data[i++]; var rx = data[i++]; var ry = data[i++]; var startAngle = data[i++]; var endAngle = data[i++] + startAngle; // TODO Arc 旋转 var psi = data[i++]; var anticlockwise = 1 - data[i++]; if (i == 1) { // 直接使用 arc 命令 // 第一个命令起点还未定义 x0 = mathCos(startAngle) * rx + cx; y0 = mathSin(startAngle) * ry + cy; } bbox.fromArc( cx, cy, rx, ry, startAngle, endAngle, anticlockwise, min2, max2 ); xi = mathCos(endAngle) * rx + cx; yi = mathSin(endAngle) * ry + cy; break; case CMD.R: x0 = xi = data[i++]; y0 = yi = data[i++]; var width = data[i++]; var height = data[i++]; // Use fromLine bbox.fromLine(x0, y0, x0 + width, y0 + height, min2, max2); break; case CMD.Z: xi = x0; yi = y0; break; } // Union vec2.min(min, min, min2); vec2.max(max, max, max2); } // No data if (i === 0) { min[0] = min[1] = max[0] = max[1] = 0; } return new BoundingRect( min[0], min[1], max[0] - min[0], max[1] - min[1] ); }, /** * Rebuild path from current data * Rebuild path will not consider javascript implemented line dash. * @param {CanvasRenderingContext} ctx */ rebuildPath: function (ctx) { var d = this.data; var x0, y0; var xi, yi; var x, y; var ux = this._ux; var uy = this._uy; var len = this._len; for (var i = 0; i < len;) { var cmd = d[i++]; if (i == 1) { // 如果第一个命令是 L, C, Q // 则 previous point 同绘制命令的第一个 point // // 第一个命令为 Arc 的情况下会在后面特殊处理 xi = d[i]; yi = d[i + 1]; x0 = xi; y0 = yi; } switch (cmd) { case CMD.M: x0 = xi = d[i++]; y0 = yi = d[i++]; ctx.moveTo(xi, yi); break; case CMD.L: x = d[i++]; y = d[i++]; // Not draw too small seg between if (mathAbs(x - xi) > ux || mathAbs(y - yi) > uy || i === len - 1) { ctx.lineTo(x, y); xi = x; yi = y; } break; case CMD.C: ctx.bezierCurveTo( d[i++], d[i++], d[i++], d[i++], d[i++], d[i++] ); xi = d[i - 2]; yi = d[i - 1]; break; case CMD.Q: ctx.quadraticCurveTo(d[i++], d[i++], d[i++], d[i++]); xi = d[i - 2]; yi = d[i - 1]; break; case CMD.A: var cx = d[i++]; var cy = d[i++]; var rx = d[i++]; var ry = d[i++]; var theta = d[i++]; var dTheta = d[i++]; var psi = d[i++]; var fs = d[i++]; var r = (rx > ry) ? rx : ry; var scaleX = (rx > ry) ? 1 : rx / ry; var scaleY = (rx > ry) ? ry / rx : 1; var isEllipse = Math.abs(rx - ry) > 1e-3; var endAngle = theta + dTheta; if (isEllipse) { ctx.translate(cx, cy); ctx.rotate(psi); ctx.scale(scaleX, scaleY); ctx.arc(0, 0, r, theta, endAngle, 1 - fs); ctx.scale(1 / scaleX, 1 / scaleY); ctx.rotate(-psi); ctx.translate(-cx, -cy); } else { ctx.arc(cx, cy, r, theta, endAngle, 1 - fs); } if (i == 1) { // 直接使用 arc 命令 // 第一个命令起点还未定义 x0 = mathCos(theta) * rx + cx; y0 = mathSin(theta) * ry + cy; } xi = mathCos(endAngle) * rx + cx; yi = mathSin(endAngle) * ry + cy; break; case CMD.R: x0 = xi = d[i]; y0 = yi = d[i + 1]; ctx.rect(d[i++], d[i++], d[i++], d[i++]); break; case CMD.Z: ctx.closePath(); xi = x0; yi = y0; } } } }; PathProxy.CMD = CMD; module.exports = PathProxy; /***/ }, /* 50 */ /***/ function(module, exports, __webpack_require__) { 'use strict'; /** * 曲线辅助模块 * @module zrender/core/curve * @author pissang(https://www.github.com/pissang) */ var vec2 = __webpack_require__(10); var v2Create = vec2.create; var v2DistSquare = vec2.distSquare; var mathPow = Math.pow; var mathSqrt = Math.sqrt; var EPSILON = 1e-8; var EPSILON_NUMERIC = 1e-4; var THREE_SQRT = mathSqrt(3); var ONE_THIRD = 1 / 3; // 临时变量 var _v0 = v2Create(); var _v1 = v2Create(); var _v2 = v2Create(); // var _v3 = vec2.create(); function isAroundZero(val) { return val > -EPSILON && val < EPSILON; } function isNotAroundZero(val) { return val > EPSILON || val < -EPSILON; } /** * 计算三次贝塞尔值 * @memberOf module:zrender/core/curve * @param {number} p0 * @param {number} p1 * @param {number} p2 * @param {number} p3 * @param {number} t * @return {number} */ function cubicAt(p0, p1, p2, p3, t) { var onet = 1 - t; return onet * onet * (onet * p0 + 3 * t * p1) + t * t * (t * p3 + 3 * onet * p2); } /** * 计算三次贝塞尔导数值 * @memberOf module:zrender/core/curve * @param {number} p0 * @param {number} p1 * @param {number} p2 * @param {number} p3 * @param {number} t * @return {number} */ function cubicDerivativeAt(p0, p1, p2, p3, t) { var onet = 1 - t; return 3 * ( ((p1 - p0) * onet + 2 * (p2 - p1) * t) * onet + (p3 - p2) * t * t ); } /** * 计算三次贝塞尔方程根,使用盛金公式 * @memberOf module:zrender/core/curve * @param {number} p0 * @param {number} p1 * @param {number} p2 * @param {number} p3 * @param {number} val * @param {Array.} roots * @return {number} 有效根数目 */ function cubicRootAt(p0, p1, p2, p3, val, roots) { // Evaluate roots of cubic functions var a = p3 + 3 * (p1 - p2) - p0; var b = 3 * (p2 - p1 * 2 + p0); var c = 3 * (p1 - p0); var d = p0 - val; var A = b * b - 3 * a * c; var B = b * c - 9 * a * d; var C = c * c - 3 * b * d; var n = 0; if (isAroundZero(A) && isAroundZero(B)) { if (isAroundZero(b)) { roots[0] = 0; } else { var t1 = -c / b; //t1, t2, t3, b is not zero if (t1 >= 0 && t1 <= 1) { roots[n++] = t1; } } } else { var disc = B * B - 4 * A * C; if (isAroundZero(disc)) { var K = B / A; var t1 = -b / a + K; // t1, a is not zero var t2 = -K / 2; // t2, t3 if (t1 >= 0 && t1 <= 1) { roots[n++] = t1; } if (t2 >= 0 && t2 <= 1) { roots[n++] = t2; } } else if (disc > 0) { var discSqrt = mathSqrt(disc); var Y1 = A * b + 1.5 * a * (-B + discSqrt); var Y2 = A * b + 1.5 * a * (-B - discSqrt); if (Y1 < 0) { Y1 = -mathPow(-Y1, ONE_THIRD); } else { Y1 = mathPow(Y1, ONE_THIRD); } if (Y2 < 0) { Y2 = -mathPow(-Y2, ONE_THIRD); } else { Y2 = mathPow(Y2, ONE_THIRD); } var t1 = (-b - (Y1 + Y2)) / (3 * a); if (t1 >= 0 && t1 <= 1) { roots[n++] = t1; } } else { var T = (2 * A * b - 3 * a * B) / (2 * mathSqrt(A * A * A)); var theta = Math.acos(T) / 3; var ASqrt = mathSqrt(A); var tmp = Math.cos(theta); var t1 = (-b - 2 * ASqrt * tmp) / (3 * a); var t2 = (-b + ASqrt * (tmp + THREE_SQRT * Math.sin(theta))) / (3 * a); var t3 = (-b + ASqrt * (tmp - THREE_SQRT * Math.sin(theta))) / (3 * a); if (t1 >= 0 && t1 <= 1) { roots[n++] = t1; } if (t2 >= 0 && t2 <= 1) { roots[n++] = t2; } if (t3 >= 0 && t3 <= 1) { roots[n++] = t3; } } } return n; } /** * 计算三次贝塞尔方程极限值的位置 * @memberOf module:zrender/core/curve * @param {number} p0 * @param {number} p1 * @param {number} p2 * @param {number} p3 * @param {Array.} extrema * @return {number} 有效数目 */ function cubicExtrema(p0, p1, p2, p3, extrema) { var b = 6 * p2 - 12 * p1 + 6 * p0; var a = 9 * p1 + 3 * p3 - 3 * p0 - 9 * p2; var c = 3 * p1 - 3 * p0; var n = 0; if (isAroundZero(a)) { if (isNotAroundZero(b)) { var t1 = -c / b; if (t1 >= 0 && t1 <=1) { extrema[n++] = t1; } } } else { var disc = b * b - 4 * a * c; if (isAroundZero(disc)) { extrema[0] = -b / (2 * a); } else if (disc > 0) { var discSqrt = mathSqrt(disc); var t1 = (-b + discSqrt) / (2 * a); var t2 = (-b - discSqrt) / (2 * a); if (t1 >= 0 && t1 <= 1) { extrema[n++] = t1; } if (t2 >= 0 && t2 <= 1) { extrema[n++] = t2; } } } return n; } /** * 细分三次贝塞尔曲线 * @memberOf module:zrender/core/curve * @param {number} p0 * @param {number} p1 * @param {number} p2 * @param {number} p3 * @param {number} t * @param {Array.} out */ function cubicSubdivide(p0, p1, p2, p3, t, out) { var p01 = (p1 - p0) * t + p0; var p12 = (p2 - p1) * t + p1; var p23 = (p3 - p2) * t + p2; var p012 = (p12 - p01) * t + p01; var p123 = (p23 - p12) * t + p12; var p0123 = (p123 - p012) * t + p012; // Seg0 out[0] = p0; out[1] = p01; out[2] = p012; out[3] = p0123; // Seg1 out[4] = p0123; out[5] = p123; out[6] = p23; out[7] = p3; } /** * 投射点到三次贝塞尔曲线上,返回投射距离。 * 投射点有可能会有一个或者多个,这里只返回其中距离最短的一个。 * @param {number} x0 * @param {number} y0 * @param {number} x1 * @param {number} y1 * @param {number} x2 * @param {number} y2 * @param {number} x3 * @param {number} y3 * @param {number} x * @param {number} y * @param {Array.} [out] 投射点 * @return {number} */ function cubicProjectPoint( x0, y0, x1, y1, x2, y2, x3, y3, x, y, out ) { // http://pomax.github.io/bezierinfo/#projections var t; var interval = 0.005; var d = Infinity; var prev; var next; var d1; var d2; _v0[0] = x; _v0[1] = y; // 先粗略估计一下可能的最小距离的 t 值 // PENDING for (var _t = 0; _t < 1; _t += 0.05) { _v1[0] = cubicAt(x0, x1, x2, x3, _t); _v1[1] = cubicAt(y0, y1, y2, y3, _t); d1 = v2DistSquare(_v0, _v1); if (d1 < d) { t = _t; d = d1; } } d = Infinity; // At most 32 iteration for (var i = 0; i < 32; i++) { if (interval < EPSILON_NUMERIC) { break; } prev = t - interval; next = t + interval; // t - interval _v1[0] = cubicAt(x0, x1, x2, x3, prev); _v1[1] = cubicAt(y0, y1, y2, y3, prev); d1 = v2DistSquare(_v1, _v0); if (prev >= 0 && d1 < d) { t = prev; d = d1; } else { // t + interval _v2[0] = cubicAt(x0, x1, x2, x3, next); _v2[1] = cubicAt(y0, y1, y2, y3, next); d2 = v2DistSquare(_v2, _v0); if (next <= 1 && d2 < d) { t = next; d = d2; } else { interval *= 0.5; } } } // t if (out) { out[0] = cubicAt(x0, x1, x2, x3, t); out[1] = cubicAt(y0, y1, y2, y3, t); } // console.log(interval, i); return mathSqrt(d); } /** * 计算二次方贝塞尔值 * @param {number} p0 * @param {number} p1 * @param {number} p2 * @param {number} t * @return {number} */ function quadraticAt(p0, p1, p2, t) { var onet = 1 - t; return onet * (onet * p0 + 2 * t * p1) + t * t * p2; } /** * 计算二次方贝塞尔导数值 * @param {number} p0 * @param {number} p1 * @param {number} p2 * @param {number} t * @return {number} */ function quadraticDerivativeAt(p0, p1, p2, t) { return 2 * ((1 - t) * (p1 - p0) + t * (p2 - p1)); } /** * 计算二次方贝塞尔方程根 * @param {number} p0 * @param {number} p1 * @param {number} p2 * @param {number} t * @param {Array.} roots * @return {number} 有效根数目 */ function quadraticRootAt(p0, p1, p2, val, roots) { var a = p0 - 2 * p1 + p2; var b = 2 * (p1 - p0); var c = p0 - val; var n = 0; if (isAroundZero(a)) { if (isNotAroundZero(b)) { var t1 = -c / b; if (t1 >= 0 && t1 <= 1) { roots[n++] = t1; } } } else { var disc = b * b - 4 * a * c; if (isAroundZero(disc)) { var t1 = -b / (2 * a); if (t1 >= 0 && t1 <= 1) { roots[n++] = t1; } } else if (disc > 0) { var discSqrt = mathSqrt(disc); var t1 = (-b + discSqrt) / (2 * a); var t2 = (-b - discSqrt) / (2 * a); if (t1 >= 0 && t1 <= 1) { roots[n++] = t1; } if (t2 >= 0 && t2 <= 1) { roots[n++] = t2; } } } return n; } /** * 计算二次贝塞尔方程极限值 * @memberOf module:zrender/core/curve * @param {number} p0 * @param {number} p1 * @param {number} p2 * @return {number} */ function quadraticExtremum(p0, p1, p2) { var divider = p0 + p2 - 2 * p1; if (divider === 0) { // p1 is center of p0 and p2 return 0.5; } else { return (p0 - p1) / divider; } } /** * 细分二次贝塞尔曲线 * @memberOf module:zrender/core/curve * @param {number} p0 * @param {number} p1 * @param {number} p2 * @param {number} t * @param {Array.} out */ function quadraticSubdivide(p0, p1, p2, t, out) { var p01 = (p1 - p0) * t + p0; var p12 = (p2 - p1) * t + p1; var p012 = (p12 - p01) * t + p01; // Seg0 out[0] = p0; out[1] = p01; out[2] = p012; // Seg1 out[3] = p012; out[4] = p12; out[5] = p2; } /** * 投射点到二次贝塞尔曲线上,返回投射距离。 * 投射点有可能会有一个或者多个,这里只返回其中距离最短的一个。 * @param {number} x0 * @param {number} y0 * @param {number} x1 * @param {number} y1 * @param {number} x2 * @param {number} y2 * @param {number} x * @param {number} y * @param {Array.} out 投射点 * @return {number} */ function quadraticProjectPoint( x0, y0, x1, y1, x2, y2, x, y, out ) { // http://pomax.github.io/bezierinfo/#projections var t; var interval = 0.005; var d = Infinity; _v0[0] = x; _v0[1] = y; // 先粗略估计一下可能的最小距离的 t 值 // PENDING for (var _t = 0; _t < 1; _t += 0.05) { _v1[0] = quadraticAt(x0, x1, x2, _t); _v1[1] = quadraticAt(y0, y1, y2, _t); var d1 = v2DistSquare(_v0, _v1); if (d1 < d) { t = _t; d = d1; } } d = Infinity; // At most 32 iteration for (var i = 0; i < 32; i++) { if (interval < EPSILON_NUMERIC) { break; } var prev = t - interval; var next = t + interval; // t - interval _v1[0] = quadraticAt(x0, x1, x2, prev); _v1[1] = quadraticAt(y0, y1, y2, prev); var d1 = v2DistSquare(_v1, _v0); if (prev >= 0 && d1 < d) { t = prev; d = d1; } else { // t + interval _v2[0] = quadraticAt(x0, x1, x2, next); _v2[1] = quadraticAt(y0, y1, y2, next); var d2 = v2DistSquare(_v2, _v0); if (next <= 1 && d2 < d) { t = next; d = d2; } else { interval *= 0.5; } } } // t if (out) { out[0] = quadraticAt(x0, x1, x2, t); out[1] = quadraticAt(y0, y1, y2, t); } // console.log(interval, i); return mathSqrt(d); } module.exports = { cubicAt: cubicAt, cubicDerivativeAt: cubicDerivativeAt, cubicRootAt: cubicRootAt, cubicExtrema: cubicExtrema, cubicSubdivide: cubicSubdivide, cubicProjectPoint: cubicProjectPoint, quadraticAt: quadraticAt, quadraticDerivativeAt: quadraticDerivativeAt, quadraticRootAt: quadraticRootAt, quadraticExtremum: quadraticExtremum, quadraticSubdivide: quadraticSubdivide, quadraticProjectPoint: quadraticProjectPoint }; /***/ }, /* 51 */ /***/ function(module, exports, __webpack_require__) { /** * @author Yi Shen(https://github.com/pissang) */ var vec2 = __webpack_require__(10); var curve = __webpack_require__(50); var bbox = {}; var mathMin = Math.min; var mathMax = Math.max; var mathSin = Math.sin; var mathCos = Math.cos; var start = vec2.create(); var end = vec2.create(); var extremity = vec2.create(); var PI2 = Math.PI * 2; /** * 从顶点数组中计算出最小包围盒,写入`min`和`max`中 * @module zrender/core/bbox * @param {Array} points 顶点数组 * @param {number} min * @param {number} max */ bbox.fromPoints = function(points, min, max) { if (points.length === 0) { return; } var p = points[0]; var left = p[0]; var right = p[0]; var top = p[1]; var bottom = p[1]; var i; for (i = 1; i < points.length; i++) { p = points[i]; left = mathMin(left, p[0]); right = mathMax(right, p[0]); top = mathMin(top, p[1]); bottom = mathMax(bottom, p[1]); } min[0] = left; min[1] = top; max[0] = right; max[1] = bottom; }; /** * @memberOf module:zrender/core/bbox * @param {number} x0 * @param {number} y0 * @param {number} x1 * @param {number} y1 * @param {Array.} min * @param {Array.} max */ bbox.fromLine = function (x0, y0, x1, y1, min, max) { min[0] = mathMin(x0, x1); min[1] = mathMin(y0, y1); max[0] = mathMax(x0, x1); max[1] = mathMax(y0, y1); }; var xDim = []; var yDim = []; /** * 从三阶贝塞尔曲线(p0, p1, p2, p3)中计算出最小包围盒,写入`min`和`max`中 * @memberOf module:zrender/core/bbox * @param {number} x0 * @param {number} y0 * @param {number} x1 * @param {number} y1 * @param {number} x2 * @param {number} y2 * @param {number} x3 * @param {number} y3 * @param {Array.} min * @param {Array.} max */ bbox.fromCubic = function( x0, y0, x1, y1, x2, y2, x3, y3, min, max ) { var cubicExtrema = curve.cubicExtrema; var cubicAt = curve.cubicAt; var i; var n = cubicExtrema(x0, x1, x2, x3, xDim); min[0] = Infinity; min[1] = Infinity; max[0] = -Infinity; max[1] = -Infinity; for (i = 0; i < n; i++) { var x = cubicAt(x0, x1, x2, x3, xDim[i]); min[0] = mathMin(x, min[0]); max[0] = mathMax(x, max[0]); } n = cubicExtrema(y0, y1, y2, y3, yDim); for (i = 0; i < n; i++) { var y = cubicAt(y0, y1, y2, y3, yDim[i]); min[1] = mathMin(y, min[1]); max[1] = mathMax(y, max[1]); } min[0] = mathMin(x0, min[0]); max[0] = mathMax(x0, max[0]); min[0] = mathMin(x3, min[0]); max[0] = mathMax(x3, max[0]); min[1] = mathMin(y0, min[1]); max[1] = mathMax(y0, max[1]); min[1] = mathMin(y3, min[1]); max[1] = mathMax(y3, max[1]); }; /** * 从二阶贝塞尔曲线(p0, p1, p2)中计算出最小包围盒,写入`min`和`max`中 * @memberOf module:zrender/core/bbox * @param {number} x0 * @param {number} y0 * @param {number} x1 * @param {number} y1 * @param {number} x2 * @param {number} y2 * @param {Array.} min * @param {Array.} max */ bbox.fromQuadratic = function(x0, y0, x1, y1, x2, y2, min, max) { var quadraticExtremum = curve.quadraticExtremum; var quadraticAt = curve.quadraticAt; // Find extremities, where derivative in x dim or y dim is zero var tx = mathMax( mathMin(quadraticExtremum(x0, x1, x2), 1), 0 ); var ty = mathMax( mathMin(quadraticExtremum(y0, y1, y2), 1), 0 ); var x = quadraticAt(x0, x1, x2, tx); var y = quadraticAt(y0, y1, y2, ty); min[0] = mathMin(x0, x2, x); min[1] = mathMin(y0, y2, y); max[0] = mathMax(x0, x2, x); max[1] = mathMax(y0, y2, y); }; /** * 从圆弧中计算出最小包围盒,写入`min`和`max`中 * @method * @memberOf module:zrender/core/bbox * @param {number} x * @param {number} y * @param {number} rx * @param {number} ry * @param {number} startAngle * @param {number} endAngle * @param {number} anticlockwise * @param {Array.} min * @param {Array.} max */ bbox.fromArc = function ( x, y, rx, ry, startAngle, endAngle, anticlockwise, min, max ) { var vec2Min = vec2.min; var vec2Max = vec2.max; var diff = Math.abs(startAngle - endAngle); if (diff % PI2 < 1e-4 && diff > 1e-4) { // Is a circle min[0] = x - rx; min[1] = y - ry; max[0] = x + rx; max[1] = y + ry; return; } start[0] = mathCos(startAngle) * rx + x; start[1] = mathSin(startAngle) * ry + y; end[0] = mathCos(endAngle) * rx + x; end[1] = mathSin(endAngle) * ry + y; vec2Min(min, start, end); vec2Max(max, start, end); // Thresh to [0, Math.PI * 2] startAngle = startAngle % (PI2); if (startAngle < 0) { startAngle = startAngle + PI2; } endAngle = endAngle % (PI2); if (endAngle < 0) { endAngle = endAngle + PI2; } if (startAngle > endAngle && !anticlockwise) { endAngle += PI2; } else if (startAngle < endAngle && anticlockwise) { startAngle += PI2; } if (anticlockwise) { var tmp = endAngle; endAngle = startAngle; startAngle = tmp; } // var number = 0; // var step = (anticlockwise ? -Math.PI : Math.PI) / 2; for (var angle = 0; angle < endAngle; angle += Math.PI / 2) { if (angle > startAngle) { extremity[0] = mathCos(angle) * rx + x; extremity[1] = mathSin(angle) * ry + y; vec2Min(min, extremity, min); vec2Max(max, extremity, max); } } }; module.exports = bbox; /***/ }, /* 52 */ /***/ function(module, exports, __webpack_require__) { 'use strict'; var CMD = __webpack_require__(49).CMD; var line = __webpack_require__(53); var cubic = __webpack_require__(54); var quadratic = __webpack_require__(55); var arc = __webpack_require__(56); var normalizeRadian = __webpack_require__(57).normalizeRadian; var curve = __webpack_require__(50); var windingLine = __webpack_require__(58); var containStroke = line.containStroke; var PI2 = Math.PI * 2; var EPSILON = 1e-4; function isAroundEqual(a, b) { return Math.abs(a - b) < EPSILON; } // 临时数组 var roots = [-1, -1, -1]; var extrema = [-1, -1]; function swapExtrema() { var tmp = extrema[0]; extrema[0] = extrema[1]; extrema[1] = tmp; } function windingCubic(x0, y0, x1, y1, x2, y2, x3, y3, x, y) { // Quick reject if ( (y > y0 && y > y1 && y > y2 && y > y3) || (y < y0 && y < y1 && y < y2 && y < y3) ) { return 0; } var nRoots = curve.cubicRootAt(y0, y1, y2, y3, y, roots); if (nRoots === 0) { return 0; } else { var w = 0; var nExtrema = -1; var y0_, y1_; for (var i = 0; i < nRoots; i++) { var t = roots[i]; // Avoid winding error when intersection point is the connect point of two line of polygon var unit = (t === 0 || t === 1) ? 0.5 : 1; var x_ = curve.cubicAt(x0, x1, x2, x3, t); if (x_ < x) { // Quick reject continue; } if (nExtrema < 0) { nExtrema = curve.cubicExtrema(y0, y1, y2, y3, extrema); if (extrema[1] < extrema[0] && nExtrema > 1) { swapExtrema(); } y0_ = curve.cubicAt(y0, y1, y2, y3, extrema[0]); if (nExtrema > 1) { y1_ = curve.cubicAt(y0, y1, y2, y3, extrema[1]); } } if (nExtrema == 2) { // 分成三段单调函数 if (t < extrema[0]) { w += y0_ < y0 ? unit : -unit; } else if (t < extrema[1]) { w += y1_ < y0_ ? unit : -unit; } else { w += y3 < y1_ ? unit : -unit; } } else { // 分成两段单调函数 if (t < extrema[0]) { w += y0_ < y0 ? unit : -unit; } else { w += y3 < y0_ ? unit : -unit; } } } return w; } } function windingQuadratic(x0, y0, x1, y1, x2, y2, x, y) { // Quick reject if ( (y > y0 && y > y1 && y > y2) || (y < y0 && y < y1 && y < y2) ) { return 0; } var nRoots = curve.quadraticRootAt(y0, y1, y2, y, roots); if (nRoots === 0) { return 0; } else { var t = curve.quadraticExtremum(y0, y1, y2); if (t >= 0 && t <= 1) { var w = 0; var y_ = curve.quadraticAt(y0, y1, y2, t); for (var i = 0; i < nRoots; i++) { // Remove one endpoint. var unit = (roots[i] === 0 || roots[i] === 1) ? 0.5 : 1; var x_ = curve.quadraticAt(x0, x1, x2, roots[i]); if (x_ < x) { // Quick reject continue; } if (roots[i] < t) { w += y_ < y0 ? unit : -unit; } else { w += y2 < y_ ? unit : -unit; } } return w; } else { // Remove one endpoint. var unit = (roots[0] === 0 || roots[0] === 1) ? 0.5 : 1; var x_ = curve.quadraticAt(x0, x1, x2, roots[0]); if (x_ < x) { // Quick reject return 0; } return y2 < y0 ? unit : -unit; } } } // TODO // Arc 旋转 function windingArc( cx, cy, r, startAngle, endAngle, anticlockwise, x, y ) { y -= cy; if (y > r || y < -r) { return 0; } var tmp = Math.sqrt(r * r - y * y); roots[0] = -tmp; roots[1] = tmp; var diff = Math.abs(startAngle - endAngle); if (diff < 1e-4) { return 0; } if (diff % PI2 < 1e-4) { // Is a circle startAngle = 0; endAngle = PI2; var dir = anticlockwise ? 1 : -1; if (x >= roots[0] + cx && x <= roots[1] + cx) { return dir; } else { return 0; } } if (anticlockwise) { var tmp = startAngle; startAngle = normalizeRadian(endAngle); endAngle = normalizeRadian(tmp); } else { startAngle = normalizeRadian(startAngle); endAngle = normalizeRadian(endAngle); } if (startAngle > endAngle) { endAngle += PI2; } var w = 0; for (var i = 0; i < 2; i++) { var x_ = roots[i]; if (x_ + cx > x) { var angle = Math.atan2(y, x_); var dir = anticlockwise ? 1 : -1; if (angle < 0) { angle = PI2 + angle; } if ( (angle >= startAngle && angle <= endAngle) || (angle + PI2 >= startAngle && angle + PI2 <= endAngle) ) { if (angle > Math.PI / 2 && angle < Math.PI * 1.5) { dir = -dir; } w += dir; } } } return w; } function containPath(data, lineWidth, isStroke, x, y) { var w = 0; var xi = 0; var yi = 0; var x0 = 0; var y0 = 0; for (var i = 0; i < data.length;) { var cmd = data[i++]; // Begin a new subpath if (cmd === CMD.M && i > 1) { // Close previous subpath if (!isStroke) { w += windingLine(xi, yi, x0, y0, x, y); } // 如果被任何一个 subpath 包含 // if (w !== 0) { // return true; // } } if (i == 1) { // 如果第一个命令是 L, C, Q // 则 previous point 同绘制命令的第一个 point // // 第一个命令为 Arc 的情况下会在后面特殊处理 xi = data[i]; yi = data[i + 1]; x0 = xi; y0 = yi; } switch (cmd) { case CMD.M: // moveTo 命令重新创建一个新的 subpath, 并且更新新的起点 // 在 closePath 的时候使用 x0 = data[i++]; y0 = data[i++]; xi = x0; yi = y0; break; case CMD.L: if (isStroke) { if (containStroke(xi, yi, data[i], data[i + 1], lineWidth, x, y)) { return true; } } else { // NOTE 在第一个命令为 L, C, Q 的时候会计算出 NaN w += windingLine(xi, yi, data[i], data[i + 1], x, y) || 0; } xi = data[i++]; yi = data[i++]; break; case CMD.C: if (isStroke) { if (cubic.containStroke(xi, yi, data[i++], data[i++], data[i++], data[i++], data[i], data[i + 1], lineWidth, x, y )) { return true; } } else { w += windingCubic( xi, yi, data[i++], data[i++], data[i++], data[i++], data[i], data[i + 1], x, y ) || 0; } xi = data[i++]; yi = data[i++]; break; case CMD.Q: if (isStroke) { if (quadratic.containStroke(xi, yi, data[i++], data[i++], data[i], data[i + 1], lineWidth, x, y )) { return true; } } else { w += windingQuadratic( xi, yi, data[i++], data[i++], data[i], data[i + 1], x, y ) || 0; } xi = data[i++]; yi = data[i++]; break; case CMD.A: // TODO Arc 判断的开销比较大 var cx = data[i++]; var cy = data[i++]; var rx = data[i++]; var ry = data[i++]; var theta = data[i++]; var dTheta = data[i++]; // TODO Arc 旋转 var psi = data[i++]; var anticlockwise = 1 - data[i++]; var x1 = Math.cos(theta) * rx + cx; var y1 = Math.sin(theta) * ry + cy; // 不是直接使用 arc 命令 if (i > 1) { w += windingLine(xi, yi, x1, y1, x, y); } else { // 第一个命令起点还未定义 x0 = x1; y0 = y1; } // zr 使用scale来模拟椭圆, 这里也对x做一定的缩放 var _x = (x - cx) * ry / rx + cx; if (isStroke) { if (arc.containStroke( cx, cy, ry, theta, theta + dTheta, anticlockwise, lineWidth, _x, y )) { return true; } } else { w += windingArc( cx, cy, ry, theta, theta + dTheta, anticlockwise, _x, y ); } xi = Math.cos(theta + dTheta) * rx + cx; yi = Math.sin(theta + dTheta) * ry + cy; break; case CMD.R: x0 = xi = data[i++]; y0 = yi = data[i++]; var width = data[i++]; var height = data[i++]; var x1 = x0 + width; var y1 = y0 + height; if (isStroke) { if (containStroke(x0, y0, x1, y0, lineWidth, x, y) || containStroke(x1, y0, x1, y1, lineWidth, x, y) || containStroke(x1, y1, x0, y1, lineWidth, x, y) || containStroke(x0, y1, x0, y0, lineWidth, x, y) ) { return true; } } else { // FIXME Clockwise ? w += windingLine(x1, y0, x1, y1, x, y); w += windingLine(x0, y1, x0, y0, x, y); } break; case CMD.Z: if (isStroke) { if (containStroke( xi, yi, x0, y0, lineWidth, x, y )) { return true; } } else { // Close a subpath w += windingLine(xi, yi, x0, y0, x, y); // 如果被任何一个 subpath 包含 // FIXME subpaths may overlap // if (w !== 0) { // return true; // } } xi = x0; yi = y0; break; } } if (!isStroke && !isAroundEqual(yi, y0)) { w += windingLine(xi, yi, x0, y0, x, y) || 0; } return w !== 0; } module.exports = { contain: function (pathData, x, y) { return containPath(pathData, 0, false, x, y); }, containStroke: function (pathData, lineWidth, x, y) { return containPath(pathData, lineWidth, true, x, y); } }; /***/ }, /* 53 */ /***/ function(module, exports) { module.exports = { /** * 线段包含判断 * @param {number} x0 * @param {number} y0 * @param {number} x1 * @param {number} y1 * @param {number} lineWidth * @param {number} x * @param {number} y * @return {boolean} */ containStroke: function (x0, y0, x1, y1, lineWidth, x, y) { if (lineWidth === 0) { return false; } var _l = lineWidth; var _a = 0; var _b = x0; // Quick reject if ( (y > y0 + _l && y > y1 + _l) || (y < y0 - _l && y < y1 - _l) || (x > x0 + _l && x > x1 + _l) || (x < x0 - _l && x < x1 - _l) ) { return false; } if (x0 !== x1) { _a = (y0 - y1) / (x0 - x1); _b = (x0 * y1 - x1 * y0) / (x0 - x1) ; } else { return Math.abs(x - x0) <= _l / 2; } var tmp = _a * x - y + _b; var _s = tmp * tmp / (_a * _a + 1); return _s <= _l / 2 * _l / 2; } }; /***/ }, /* 54 */ /***/ function(module, exports, __webpack_require__) { var curve = __webpack_require__(50); module.exports = { /** * 三次贝塞尔曲线描边包含判断 * @param {number} x0 * @param {number} y0 * @param {number} x1 * @param {number} y1 * @param {number} x2 * @param {number} y2 * @param {number} x3 * @param {number} y3 * @param {number} lineWidth * @param {number} x * @param {number} y * @return {boolean} */ containStroke: function(x0, y0, x1, y1, x2, y2, x3, y3, lineWidth, x, y) { if (lineWidth === 0) { return false; } var _l = lineWidth; // Quick reject if ( (y > y0 + _l && y > y1 + _l && y > y2 + _l && y > y3 + _l) || (y < y0 - _l && y < y1 - _l && y < y2 - _l && y < y3 - _l) || (x > x0 + _l && x > x1 + _l && x > x2 + _l && x > x3 + _l) || (x < x0 - _l && x < x1 - _l && x < x2 - _l && x < x3 - _l) ) { return false; } var d = curve.cubicProjectPoint( x0, y0, x1, y1, x2, y2, x3, y3, x, y, null ); return d <= _l / 2; } }; /***/ }, /* 55 */ /***/ function(module, exports, __webpack_require__) { var curve = __webpack_require__(50); module.exports = { /** * 二次贝塞尔曲线描边包含判断 * @param {number} x0 * @param {number} y0 * @param {number} x1 * @param {number} y1 * @param {number} x2 * @param {number} y2 * @param {number} lineWidth * @param {number} x * @param {number} y * @return {boolean} */ containStroke: function (x0, y0, x1, y1, x2, y2, lineWidth, x, y) { if (lineWidth === 0) { return false; } var _l = lineWidth; // Quick reject if ( (y > y0 + _l && y > y1 + _l && y > y2 + _l) || (y < y0 - _l && y < y1 - _l && y < y2 - _l) || (x > x0 + _l && x > x1 + _l && x > x2 + _l) || (x < x0 - _l && x < x1 - _l && x < x2 - _l) ) { return false; } var d = curve.quadraticProjectPoint( x0, y0, x1, y1, x2, y2, x, y, null ); return d <= _l / 2; } }; /***/ }, /* 56 */ /***/ function(module, exports, __webpack_require__) { var normalizeRadian = __webpack_require__(57).normalizeRadian; var PI2 = Math.PI * 2; module.exports = { /** * 圆弧描边包含判断 * @param {number} cx * @param {number} cy * @param {number} r * @param {number} startAngle * @param {number} endAngle * @param {boolean} anticlockwise * @param {number} lineWidth * @param {number} x * @param {number} y * @return {Boolean} */ containStroke: function ( cx, cy, r, startAngle, endAngle, anticlockwise, lineWidth, x, y ) { if (lineWidth === 0) { return false; } var _l = lineWidth; x -= cx; y -= cy; var d = Math.sqrt(x * x + y * y); if ((d - _l > r) || (d + _l < r)) { return false; } if (Math.abs(startAngle - endAngle) % PI2 < 1e-4) { // Is a circle return true; } if (anticlockwise) { var tmp = startAngle; startAngle = normalizeRadian(endAngle); endAngle = normalizeRadian(tmp); } else { startAngle = normalizeRadian(startAngle); endAngle = normalizeRadian(endAngle); } if (startAngle > endAngle) { endAngle += PI2; } var angle = Math.atan2(y, x); if (angle < 0) { angle += PI2; } return (angle >= startAngle && angle <= endAngle) || (angle + PI2 >= startAngle && angle + PI2 <= endAngle); } }; /***/ }, /* 57 */ /***/ function(module, exports) { var PI2 = Math.PI * 2; module.exports = { normalizeRadian: function(angle) { angle %= PI2; if (angle < 0) { angle += PI2; } return angle; } }; /***/ }, /* 58 */ /***/ function(module, exports) { module.exports = function windingLine(x0, y0, x1, y1, x, y) { if ((y > y0 && y > y1) || (y < y0 && y < y1)) { return 0; } // Ignore horizontal line if (y1 === y0) { return 0; } var dir = y1 < y0 ? 1 : -1; var t = (y - y0) / (y1 - y0); // Avoid winding error when intersection point is the connect point of two line of polygon if (t === 1 || t === 0) { dir = y1 < y0 ? 0.5 : -0.5; } var x_ = t * (x1 - x0) + x0; return x_ > x ? dir : 0; }; /***/ }, /* 59 */ /***/ function(module, exports) { var Pattern = function (image, repeat) { this.image = image; this.repeat = repeat; // Can be cloned this.type = 'pattern'; }; Pattern.prototype.getCanvasPattern = function (ctx) { return this._canvasPattern || (this._canvasPattern = ctx.createPattern(this.image, this.repeat)); }; module.exports = Pattern; /***/ }, /* 60 */ /***/ function(module, exports, __webpack_require__) { var CMD = __webpack_require__(49).CMD; var vec2 = __webpack_require__(10); var v2ApplyTransform = vec2.applyTransform; var points = [[], [], []]; var mathSqrt = Math.sqrt; var mathAtan2 = Math.atan2; function transformPath(path, m) { var data = path.data; var cmd; var nPoint; var i; var j; var k; var p; var M = CMD.M; var C = CMD.C; var L = CMD.L; var R = CMD.R; var A = CMD.A; var Q = CMD.Q; for (i = 0, j = 0; i < data.length;) { cmd = data[i++]; j = i; nPoint = 0; switch (cmd) { case M: nPoint = 1; break; case L: nPoint = 1; break; case C: nPoint = 3; break; case Q: nPoint = 2; break; case A: var x = m[4]; var y = m[5]; var sx = mathSqrt(m[0] * m[0] + m[1] * m[1]); var sy = mathSqrt(m[2] * m[2] + m[3] * m[3]); var angle = mathAtan2(-m[1] / sy, m[0] / sx); // cx data[i++] += x; // cy data[i++] += y; // Scale rx and ry // FIXME Assume psi is 0 here data[i++] *= sx; data[i++] *= sy; // Start angle data[i++] += angle; // end angle data[i++] += angle; // FIXME psi i += 2; j = i; break; case R: // x0, y0 p[0] = data[i++]; p[1] = data[i++]; v2ApplyTransform(p, p, m); data[j++] = p[0]; data[j++] = p[1]; // x1, y1 p[0] += data[i++]; p[1] += data[i++]; v2ApplyTransform(p, p, m); data[j++] = p[0]; data[j++] = p[1]; } for (k = 0; k < nPoint; k++) { var p = points[k]; p[0] = data[i++]; p[1] = data[i++]; v2ApplyTransform(p, p, m); // Write back data[j++] = p[0]; data[j++] = p[1]; } } } module.exports = transformPath; /***/ }, /* 61 */ /***/ function(module, exports, __webpack_require__) { /** * Image element * @module zrender/graphic/Image */ var Displayable = __webpack_require__(46); var BoundingRect = __webpack_require__(9); var zrUtil = __webpack_require__(4); var LRU = __webpack_require__(62); var globalImageCache = new LRU(50); /** * @alias zrender/graphic/Image * @extends module:zrender/graphic/Displayable * @constructor * @param {Object} opts */ function ZImage(opts) { Displayable.call(this, opts); } ZImage.prototype = { constructor: ZImage, type: 'image', brush: function (ctx, prevEl) { var style = this.style; var src = style.image; var image; // Must bind each time style.bind(ctx, this, prevEl); // style.image is a url string if (typeof src === 'string') { image = this._image; } // style.image is an HTMLImageElement or HTMLCanvasElement or Canvas else { image = src; } // FIXME Case create many images with src if (!image && src) { // Try get from global image cache var cachedImgObj = globalImageCache.get(src); if (!cachedImgObj) { // Create a new image image = new Image(); image.onload = function () { image.onload = null; for (var i = 0; i < cachedImgObj.pending.length; i++) { cachedImgObj.pending[i].dirty(); } }; cachedImgObj = { image: image, pending: [this] }; image.src = src; globalImageCache.put(src, cachedImgObj); this._image = image; return; } else { image = cachedImgObj.image; this._image = image; // Image is not complete finish, add to pending list if (!image.width || !image.height) { cachedImgObj.pending.push(this); return; } } } if (image) { // 图片已经加载完成 // if (image.nodeName.toUpperCase() == 'IMG') { // if (!image.complete) { // return; // } // } // Else is canvas var width = style.width || image.width; var height = style.height || image.height; var x = style.x || 0; var y = style.y || 0; // 图片加载失败 if (!image.width || !image.height) { return; } // 设置transform this.setTransform(ctx); if (style.sWidth && style.sHeight) { var sx = style.sx || 0; var sy = style.sy || 0; ctx.drawImage( image, sx, sy, style.sWidth, style.sHeight, x, y, width, height ); } else if (style.sx && style.sy) { var sx = style.sx; var sy = style.sy; var sWidth = width - sx; var sHeight = height - sy; ctx.drawImage( image, sx, sy, sWidth, sHeight, x, y, width, height ); } else { ctx.drawImage(image, x, y, width, height); } // 如果没设置宽和高的话自动根据图片宽高设置 if (style.width == null) { style.width = width; } if (style.height == null) { style.height = height; } this.restoreTransform(ctx); // Draw rect text if (style.text != null) { this.drawRectText(ctx, this.getBoundingRect()); } } }, getBoundingRect: function () { var style = this.style; if (! this._rect) { this._rect = new BoundingRect( style.x || 0, style.y || 0, style.width || 0, style.height || 0 ); } return this._rect; } }; zrUtil.inherits(ZImage, Displayable); module.exports = ZImage; /***/ }, /* 62 */ /***/ function(module, exports) { // Simple LRU cache use doubly linked list // @module zrender/core/LRU /** * Simple double linked list. Compared with array, it has O(1) remove operation. * @constructor */ var LinkedList = function() { /** * @type {module:zrender/core/LRU~Entry} */ this.head = null; /** * @type {module:zrender/core/LRU~Entry} */ this.tail = null; this._len = 0; }; var linkedListProto = LinkedList.prototype; /** * Insert a new value at the tail * @param {} val * @return {module:zrender/core/LRU~Entry} */ linkedListProto.insert = function(val) { var entry = new Entry(val); this.insertEntry(entry); return entry; }; /** * Insert an entry at the tail * @param {module:zrender/core/LRU~Entry} entry */ linkedListProto.insertEntry = function(entry) { if (!this.head) { this.head = this.tail = entry; } else { this.tail.next = entry; entry.prev = this.tail; this.tail = entry; } this._len++; }; /** * Remove entry. * @param {module:zrender/core/LRU~Entry} entry */ linkedListProto.remove = function(entry) { var prev = entry.prev; var next = entry.next; if (prev) { prev.next = next; } else { // Is head this.head = next; } if (next) { next.prev = prev; } else { // Is tail this.tail = prev; } entry.next = entry.prev = null; this._len--; }; /** * @return {number} */ linkedListProto.len = function() { return this._len; }; /** * @constructor * @param {} val */ var Entry = function(val) { /** * @type {} */ this.value = val; /** * @type {module:zrender/core/LRU~Entry} */ this.next; /** * @type {module:zrender/core/LRU~Entry} */ this.prev; }; /** * LRU Cache * @constructor * @alias module:zrender/core/LRU */ var LRU = function(maxSize) { this._list = new LinkedList(); this._map = {}; this._maxSize = maxSize || 10; }; var LRUProto = LRU.prototype; /** * @param {string} key * @param {} value */ LRUProto.put = function(key, value) { var list = this._list; var map = this._map; if (map[key] == null) { var len = list.len(); if (len >= this._maxSize && len > 0) { // Remove the least recently used var leastUsedEntry = list.head; list.remove(leastUsedEntry); delete map[leastUsedEntry.key]; } var entry = list.insert(value); entry.key = key; map[key] = entry; } }; /** * @param {string} key * @return {} */ LRUProto.get = function(key) { var entry = this._map[key]; var list = this._list; if (entry != null) { // Put the latest used entry in the tail if (entry !== list.tail) { list.remove(entry); list.insertEntry(entry); } return entry.value; } }; /** * Clear the cache */ LRUProto.clear = function() { this._list.clear(); this._map = {}; }; module.exports = LRU; /***/ }, /* 63 */ /***/ function(module, exports, __webpack_require__) { /** * Text element * @module zrender/graphic/Text * * TODO Wrapping * * Text not support gradient */ var Displayable = __webpack_require__(46); var zrUtil = __webpack_require__(4); var textContain = __webpack_require__(8); /** * @alias zrender/graphic/Text * @extends module:zrender/graphic/Displayable * @constructor * @param {Object} opts */ var Text = function (opts) { Displayable.call(this, opts); }; Text.prototype = { constructor: Text, type: 'text', brush: function (ctx, prevEl) { var style = this.style; var x = style.x || 0; var y = style.y || 0; // Convert to string var text = style.text; // Convert to string text != null && (text += ''); // Always bind style style.bind(ctx, this, prevEl); if (text) { this.setTransform(ctx); var textBaseline; var textAlign = style.textAlign; var font = style.textFont || style.font; if (style.textVerticalAlign) { var rect = textContain.getBoundingRect( text, font, style.textAlign, 'top' ); // Ignore textBaseline textBaseline = 'middle'; switch (style.textVerticalAlign) { case 'middle': y -= rect.height / 2 - rect.lineHeight / 2; break; case 'bottom': y -= rect.height - rect.lineHeight / 2; break; default: y += rect.lineHeight / 2; } } else { textBaseline = style.textBaseline; } // TODO Invalid font ctx.font = font || '12px sans-serif'; ctx.textAlign = textAlign || 'left'; // Use canvas default left textAlign. Giving invalid value will cause state not change if (ctx.textAlign !== textAlign) { ctx.textAlign = 'left'; } ctx.textBaseline = textBaseline || 'alphabetic'; // Use canvas default alphabetic baseline if (ctx.textBaseline !== textBaseline) { ctx.textBaseline = 'alphabetic'; } var lineHeight = textContain.measureText('国', ctx.font).width; var textLines = text.split('\n'); for (var i = 0; i < textLines.length; i++) { style.hasFill() && ctx.fillText(textLines[i], x, y); style.hasStroke() && ctx.strokeText(textLines[i], x, y); y += lineHeight; } this.restoreTransform(ctx); } }, getBoundingRect: function () { if (!this._rect) { var style = this.style; var textVerticalAlign = style.textVerticalAlign; var rect = textContain.getBoundingRect( style.text + '', style.textFont || style.font, style.textAlign, textVerticalAlign ? 'top' : style.textBaseline ); switch (textVerticalAlign) { case 'middle': rect.y -= rect.height / 2; break; case 'bottom': rect.y -= rect.height; break; } rect.x += style.x || 0; rect.y += style.y || 0; this._rect = rect; } return this._rect; } }; zrUtil.inherits(Text, Displayable); module.exports = Text; /***/ }, /* 64 */ /***/ function(module, exports, __webpack_require__) { 'use strict'; /** * 圆形 * @module zrender/shape/Circle */ module.exports = __webpack_require__(45).extend({ type: 'circle', shape: { cx: 0, cy: 0, r: 0 }, buildPath : function (ctx, shape, inBundle) { // Better stroking in ShapeBundle // Always do it may have performence issue ( fill may be 2x more cost) if (inBundle) { ctx.moveTo(shape.cx + shape.r, shape.cy); } // Better stroking in ShapeBundle // ctx.moveTo(shape.cx + shape.r, shape.cy); ctx.arc(shape.cx, shape.cy, shape.r, 0, Math.PI * 2, true); } }); /***/ }, /* 65 */ /***/ function(module, exports, __webpack_require__) { /** * 扇形 * @module zrender/graphic/shape/Sector */ module.exports = __webpack_require__(45).extend({ type: 'sector', shape: { cx: 0, cy: 0, r0: 0, r: 0, startAngle: 0, endAngle: Math.PI * 2, clockwise: true }, buildPath: function (ctx, shape) { var x = shape.cx; var y = shape.cy; var r0 = Math.max(shape.r0 || 0, 0); var r = Math.max(shape.r, 0); var startAngle = shape.startAngle; var endAngle = shape.endAngle; var clockwise = shape.clockwise; var unitX = Math.cos(startAngle); var unitY = Math.sin(startAngle); ctx.moveTo(unitX * r0 + x, unitY * r0 + y); ctx.lineTo(unitX * r + x, unitY * r + y); ctx.arc(x, y, r, startAngle, endAngle, !clockwise); ctx.lineTo( Math.cos(endAngle) * r0 + x, Math.sin(endAngle) * r0 + y ); if (r0 !== 0) { ctx.arc(x, y, r0, endAngle, startAngle, clockwise); } ctx.closePath(); } }); /***/ }, /* 66 */ /***/ function(module, exports, __webpack_require__) { /** * 圆环 * @module zrender/graphic/shape/Ring */ module.exports = __webpack_require__(45).extend({ type: 'ring', shape: { cx: 0, cy: 0, r: 0, r0: 0 }, buildPath: function (ctx, shape) { var x = shape.cx; var y = shape.cy; var PI2 = Math.PI * 2; ctx.moveTo(x + shape.r, y); ctx.arc(x, y, shape.r, 0, PI2, false); ctx.moveTo(x + shape.r0, y); ctx.arc(x, y, shape.r0, 0, PI2, true); } }); /***/ }, /* 67 */ /***/ function(module, exports, __webpack_require__) { /** * 多边形 * @module zrender/shape/Polygon */ var polyHelper = __webpack_require__(68); module.exports = __webpack_require__(45).extend({ type: 'polygon', shape: { points: null, smooth: false, smoothConstraint: null }, buildPath: function (ctx, shape) { polyHelper.buildPath(ctx, shape, true); } }); /***/ }, /* 68 */ /***/ function(module, exports, __webpack_require__) { var smoothSpline = __webpack_require__(69); var smoothBezier = __webpack_require__(70); module.exports = { buildPath: function (ctx, shape, closePath) { var points = shape.points; var smooth = shape.smooth; if (points && points.length >= 2) { if (smooth && smooth !== 'spline') { var controlPoints = smoothBezier( points, smooth, closePath, shape.smoothConstraint ); ctx.moveTo(points[0][0], points[0][1]); var len = points.length; for (var i = 0; i < (closePath ? len : len - 1); i++) { var cp1 = controlPoints[i * 2]; var cp2 = controlPoints[i * 2 + 1]; var p = points[(i + 1) % len]; ctx.bezierCurveTo( cp1[0], cp1[1], cp2[0], cp2[1], p[0], p[1] ); } } else { if (smooth === 'spline') { points = smoothSpline(points, closePath); } ctx.moveTo(points[0][0], points[0][1]); for (var i = 1, l = points.length; i < l; i++) { ctx.lineTo(points[i][0], points[i][1]); } } closePath && ctx.closePath(); } } }; /***/ }, /* 69 */ /***/ function(module, exports, __webpack_require__) { /** * Catmull-Rom spline 插值折线 * @module zrender/shape/util/smoothSpline * @author pissang (https://www.github.com/pissang) * Kener (@Kener-林峰, kener.linfeng@gmail.com) * errorrik (errorrik@gmail.com) */ var vec2 = __webpack_require__(10); /** * @inner */ function interpolate(p0, p1, p2, p3, t, t2, t3) { var v0 = (p2 - p0) * 0.5; var v1 = (p3 - p1) * 0.5; return (2 * (p1 - p2) + v0 + v1) * t3 + (-3 * (p1 - p2) - 2 * v0 - v1) * t2 + v0 * t + p1; } /** * @alias module:zrender/shape/util/smoothSpline * @param {Array} points 线段顶点数组 * @param {boolean} isLoop * @return {Array} */ module.exports = function (points, isLoop) { var len = points.length; var ret = []; var distance = 0; for (var i = 1; i < len; i++) { distance += vec2.distance(points[i - 1], points[i]); } var segs = distance / 2; segs = segs < len ? len : segs; for (var i = 0; i < segs; i++) { var pos = i / (segs - 1) * (isLoop ? len : len - 1); var idx = Math.floor(pos); var w = pos - idx; var p0; var p1 = points[idx % len]; var p2; var p3; if (!isLoop) { p0 = points[idx === 0 ? idx : idx - 1]; p2 = points[idx > len - 2 ? len - 1 : idx + 1]; p3 = points[idx > len - 3 ? len - 1 : idx + 2]; } else { p0 = points[(idx - 1 + len) % len]; p2 = points[(idx + 1) % len]; p3 = points[(idx + 2) % len]; } var w2 = w * w; var w3 = w * w2; ret.push([ interpolate(p0[0], p1[0], p2[0], p3[0], w, w2, w3), interpolate(p0[1], p1[1], p2[1], p3[1], w, w2, w3) ]); } return ret; }; /***/ }, /* 70 */ /***/ function(module, exports, __webpack_require__) { /** * 贝塞尔平滑曲线 * @module zrender/shape/util/smoothBezier * @author pissang (https://www.github.com/pissang) * Kener (@Kener-林峰, kener.linfeng@gmail.com) * errorrik (errorrik@gmail.com) */ var vec2 = __webpack_require__(10); var v2Min = vec2.min; var v2Max = vec2.max; var v2Scale = vec2.scale; var v2Distance = vec2.distance; var v2Add = vec2.add; /** * 贝塞尔平滑曲线 * @alias module:zrender/shape/util/smoothBezier * @param {Array} points 线段顶点数组 * @param {number} smooth 平滑等级, 0-1 * @param {boolean} isLoop * @param {Array} constraint 将计算出来的控制点约束在一个包围盒内 * 比如 [[0, 0], [100, 100]], 这个包围盒会与 * 整个折线的包围盒做一个并集用来约束控制点。 * @param {Array} 计算出来的控制点数组 */ module.exports = function (points, smooth, isLoop, constraint) { var cps = []; var v = []; var v1 = []; var v2 = []; var prevPoint; var nextPoint; var min, max; if (constraint) { min = [Infinity, Infinity]; max = [-Infinity, -Infinity]; for (var i = 0, len = points.length; i < len; i++) { v2Min(min, min, points[i]); v2Max(max, max, points[i]); } // 与指定的包围盒做并集 v2Min(min, min, constraint[0]); v2Max(max, max, constraint[1]); } for (var i = 0, len = points.length; i < len; i++) { var point = points[i]; if (isLoop) { prevPoint = points[i ? i - 1 : len - 1]; nextPoint = points[(i + 1) % len]; } else { if (i === 0 || i === len - 1) { cps.push(vec2.clone(points[i])); continue; } else { prevPoint = points[i - 1]; nextPoint = points[i + 1]; } } vec2.sub(v, nextPoint, prevPoint); // use degree to scale the handle length v2Scale(v, v, smooth); var d0 = v2Distance(point, prevPoint); var d1 = v2Distance(point, nextPoint); var sum = d0 + d1; if (sum !== 0) { d0 /= sum; d1 /= sum; } v2Scale(v1, v, -d0); v2Scale(v2, v, d1); var cp0 = v2Add([], point, v1); var cp1 = v2Add([], point, v2); if (constraint) { v2Max(cp0, cp0, min); v2Min(cp0, cp0, max); v2Max(cp1, cp1, min); v2Min(cp1, cp1, max); } cps.push(cp0); cps.push(cp1); } if (isLoop) { cps.push(cps.shift()); } return cps; }; /***/ }, /* 71 */ /***/ function(module, exports, __webpack_require__) { /** * @module zrender/graphic/shape/Polyline */ var polyHelper = __webpack_require__(68); module.exports = __webpack_require__(45).extend({ type: 'polyline', shape: { points: null, smooth: false, smoothConstraint: null }, style: { stroke: '#000', fill: null }, buildPath: function (ctx, shape) { polyHelper.buildPath(ctx, shape, false); } }); /***/ }, /* 72 */ /***/ function(module, exports, __webpack_require__) { /** * 矩形 * @module zrender/graphic/shape/Rect */ var roundRectHelper = __webpack_require__(73); module.exports = __webpack_require__(45).extend({ type: 'rect', shape: { // 左上、右上、右下、左下角的半径依次为r1、r2、r3、r4 // r缩写为1 相当于 [1, 1, 1, 1] // r缩写为[1] 相当于 [1, 1, 1, 1] // r缩写为[1, 2] 相当于 [1, 2, 1, 2] // r缩写为[1, 2, 3] 相当于 [1, 2, 3, 2] r: 0, x: 0, y: 0, width: 0, height: 0 }, buildPath: function (ctx, shape) { var x = shape.x; var y = shape.y; var width = shape.width; var height = shape.height; if (!shape.r) { ctx.rect(x, y, width, height); } else { roundRectHelper.buildPath(ctx, shape); } ctx.closePath(); return; } }); /***/ }, /* 73 */ /***/ function(module, exports) { module.exports = { buildPath: function (ctx, shape) { var x = shape.x; var y = shape.y; var width = shape.width; var height = shape.height; var r = shape.r; var r1; var r2; var r3; var r4; // Convert width and height to positive for better borderRadius if (width < 0) { x = x + width; width = -width; } if (height < 0) { y = y + height; height = -height; } if (typeof r === 'number') { r1 = r2 = r3 = r4 = r; } else if (r instanceof Array) { if (r.length === 1) { r1 = r2 = r3 = r4 = r[0]; } else if (r.length === 2) { r1 = r3 = r[0]; r2 = r4 = r[1]; } else if (r.length === 3) { r1 = r[0]; r2 = r4 = r[1]; r3 = r[2]; } else { r1 = r[0]; r2 = r[1]; r3 = r[2]; r4 = r[3]; } } else { r1 = r2 = r3 = r4 = 0; } var total; if (r1 + r2 > width) { total = r1 + r2; r1 *= width / total; r2 *= width / total; } if (r3 + r4 > width) { total = r3 + r4; r3 *= width / total; r4 *= width / total; } if (r2 + r3 > height) { total = r2 + r3; r2 *= height / total; r3 *= height / total; } if (r1 + r4 > height) { total = r1 + r4; r1 *= height / total; r4 *= height / total; } ctx.moveTo(x + r1, y); ctx.lineTo(x + width - r2, y); r2 !== 0 && ctx.quadraticCurveTo( x + width, y, x + width, y + r2 ); ctx.lineTo(x + width, y + height - r3); r3 !== 0 && ctx.quadraticCurveTo( x + width, y + height, x + width - r3, y + height ); ctx.lineTo(x + r4, y + height); r4 !== 0 && ctx.quadraticCurveTo( x, y + height, x, y + height - r4 ); ctx.lineTo(x, y + r1); r1 !== 0 && ctx.quadraticCurveTo(x, y, x + r1, y); } }; /***/ }, /* 74 */ /***/ function(module, exports, __webpack_require__) { /** * 直线 * @module zrender/graphic/shape/Line */ module.exports = __webpack_require__(45).extend({ type: 'line', shape: { // Start point x1: 0, y1: 0, // End point x2: 0, y2: 0, percent: 1 }, style: { stroke: '#000', fill: null }, buildPath: function (ctx, shape) { var x1 = shape.x1; var y1 = shape.y1; var x2 = shape.x2; var y2 = shape.y2; var percent = shape.percent; if (percent === 0) { return; } ctx.moveTo(x1, y1); if (percent < 1) { x2 = x1 * (1 - percent) + x2 * percent; y2 = y1 * (1 - percent) + y2 * percent; } ctx.lineTo(x2, y2); }, /** * Get point at percent * @param {number} percent * @return {Array.} */ pointAt: function (p) { var shape = this.shape; return [ shape.x1 * (1 - p) + shape.x2 * p, shape.y1 * (1 - p) + shape.y2 * p ]; } }); /***/ }, /* 75 */ /***/ function(module, exports, __webpack_require__) { 'use strict'; /** * 贝塞尔曲线 * @module zrender/shape/BezierCurve */ var curveTool = __webpack_require__(50); var vec2 = __webpack_require__(10); var quadraticSubdivide = curveTool.quadraticSubdivide; var cubicSubdivide = curveTool.cubicSubdivide; var quadraticAt = curveTool.quadraticAt; var cubicAt = curveTool.cubicAt; var quadraticDerivativeAt = curveTool.quadraticDerivativeAt; var cubicDerivativeAt = curveTool.cubicDerivativeAt; var out = []; function someVectorAt(shape, t, isTangent) { var cpx2 = shape.cpx2; var cpy2 = shape.cpy2; if (cpx2 === null || cpy2 === null) { return [ (isTangent ? cubicDerivativeAt : cubicAt)(shape.x1, shape.cpx1, shape.cpx2, shape.x2, t), (isTangent ? cubicDerivativeAt : cubicAt)(shape.y1, shape.cpy1, shape.cpy2, shape.y2, t) ]; } else { return [ (isTangent ? quadraticDerivativeAt : quadraticAt)(shape.x1, shape.cpx1, shape.x2, t), (isTangent ? quadraticDerivativeAt : quadraticAt)(shape.y1, shape.cpy1, shape.y2, t) ]; } } module.exports = __webpack_require__(45).extend({ type: 'bezier-curve', shape: { x1: 0, y1: 0, x2: 0, y2: 0, cpx1: 0, cpy1: 0, // cpx2: 0, // cpy2: 0 // Curve show percent, for animating percent: 1 }, style: { stroke: '#000', fill: null }, buildPath: function (ctx, shape) { var x1 = shape.x1; var y1 = shape.y1; var x2 = shape.x2; var y2 = shape.y2; var cpx1 = shape.cpx1; var cpy1 = shape.cpy1; var cpx2 = shape.cpx2; var cpy2 = shape.cpy2; var percent = shape.percent; if (percent === 0) { return; } ctx.moveTo(x1, y1); if (cpx2 == null || cpy2 == null) { if (percent < 1) { quadraticSubdivide( x1, cpx1, x2, percent, out ); cpx1 = out[1]; x2 = out[2]; quadraticSubdivide( y1, cpy1, y2, percent, out ); cpy1 = out[1]; y2 = out[2]; } ctx.quadraticCurveTo( cpx1, cpy1, x2, y2 ); } else { if (percent < 1) { cubicSubdivide( x1, cpx1, cpx2, x2, percent, out ); cpx1 = out[1]; cpx2 = out[2]; x2 = out[3]; cubicSubdivide( y1, cpy1, cpy2, y2, percent, out ); cpy1 = out[1]; cpy2 = out[2]; y2 = out[3]; } ctx.bezierCurveTo( cpx1, cpy1, cpx2, cpy2, x2, y2 ); } }, /** * Get point at percent * @param {number} t * @return {Array.} */ pointAt: function (t) { return someVectorAt(this.shape, t, false); }, /** * Get tangent at percent * @param {number} t * @return {Array.} */ tangentAt: function (t) { var p = someVectorAt(this.shape, t, true); return vec2.normalize(p, p); } }); /***/ }, /* 76 */ /***/ function(module, exports, __webpack_require__) { /** * 圆弧 * @module zrender/graphic/shape/Arc */ module.exports = __webpack_require__(45).extend({ type: 'arc', shape: { cx: 0, cy: 0, r: 0, startAngle: 0, endAngle: Math.PI * 2, clockwise: true }, style: { stroke: '#000', fill: null }, buildPath: function (ctx, shape) { var x = shape.cx; var y = shape.cy; var r = Math.max(shape.r, 0); var startAngle = shape.startAngle; var endAngle = shape.endAngle; var clockwise = shape.clockwise; var unitX = Math.cos(startAngle); var unitY = Math.sin(startAngle); ctx.moveTo(unitX * r + x, unitY * r + y); ctx.arc(x, y, r, startAngle, endAngle, !clockwise); } }); /***/ }, /* 77 */ /***/ function(module, exports, __webpack_require__) { // CompoundPath to improve performance var Path = __webpack_require__(45); module.exports = Path.extend({ type: 'compound', shape: { paths: null }, _updatePathDirty: function () { var dirtyPath = this.__dirtyPath; var paths = this.shape.paths; for (var i = 0; i < paths.length; i++) { // Mark as dirty if any subpath is dirty dirtyPath = dirtyPath || paths[i].__dirtyPath; } this.__dirtyPath = dirtyPath; this.__dirty = this.__dirty || dirtyPath; }, beforeBrush: function () { this._updatePathDirty(); var paths = this.shape.paths || []; var scale = this.getGlobalScale(); // Update path scale for (var i = 0; i < paths.length; i++) { paths[i].path.setScale(scale[0], scale[1]); } }, buildPath: function (ctx, shape) { var paths = shape.paths || []; for (var i = 0; i < paths.length; i++) { paths[i].buildPath(ctx, paths[i].shape, true); } }, afterBrush: function () { var paths = this.shape.paths; for (var i = 0; i < paths.length; i++) { paths[i].__dirtyPath = false; } }, getBoundingRect: function () { this._updatePathDirty(); return Path.prototype.getBoundingRect.call(this); } }); /***/ }, /* 78 */ /***/ function(module, exports, __webpack_require__) { 'use strict'; var zrUtil = __webpack_require__(4); var Gradient = __webpack_require__(79); /** * x, y, x2, y2 are all percent from 0 to 1 * @param {number} [x=0] * @param {number} [y=0] * @param {number} [x2=1] * @param {number} [y2=0] * @param {Array.} colorStops * @param {boolean} [globalCoord=false] */ var LinearGradient = function (x, y, x2, y2, colorStops, globalCoord) { this.x = x == null ? 0 : x; this.y = y == null ? 0 : y; this.x2 = x2 == null ? 1 : x2; this.y2 = y2 == null ? 0 : y2; // Can be cloned this.type = 'linear'; // If use global coord this.global = globalCoord || false; Gradient.call(this, colorStops); }; LinearGradient.prototype = { constructor: LinearGradient }; zrUtil.inherits(LinearGradient, Gradient); module.exports = LinearGradient; /***/ }, /* 79 */ /***/ function(module, exports) { /** * @param {Array.} colorStops */ var Gradient = function (colorStops) { this.colorStops = colorStops || []; }; Gradient.prototype = { constructor: Gradient, addColorStop: function (offset, color) { this.colorStops.push({ offset: offset, color: color }); } }; module.exports = Gradient; /***/ }, /* 80 */ /***/ function(module, exports, __webpack_require__) { 'use strict'; var zrUtil = __webpack_require__(4); var Gradient = __webpack_require__(79); /** * x, y, r are all percent from 0 to 1 * @param {number} [x=0.5] * @param {number} [y=0.5] * @param {number} [r=0.5] * @param {Array.} [colorStops] * @param {boolean} [globalCoord=false] */ var RadialGradient = function (x, y, r, colorStops, globalCoord) { this.x = x == null ? 0.5 : x; this.y = y == null ? 0.5 : y; this.r = r == null ? 0.5 : r; // Can be cloned this.type = 'radial'; // If use global coord this.global = globalCoord || false; Gradient.call(this, colorStops); }; RadialGradient.prototype = { constructor: RadialGradient }; zrUtil.inherits(RadialGradient, Gradient); module.exports = RadialGradient; /***/ }, /* 81 */ /***/ function(module, exports) { var lib = {}; var ORIGIN_METHOD = '\0__throttleOriginMethod'; var RATE = '\0__throttleRate'; var THROTTLE_TYPE = '\0__throttleType'; /** * @public * @param {(Function)} fn * @param {number} [delay=0] Unit: ms. * @param {boolean} [debounce=false] * true: If call interval less than `delay`, only the last call works. * false: If call interval less than `delay, call works on fixed rate. * @return {(Function)} throttled fn. */ lib.throttle = function (fn, delay, debounce) { var currCall; var lastCall = 0; var lastExec = 0; var timer = null; var diff; var scope; var args; delay = delay || 0; function exec() { lastExec = (new Date()).getTime(); timer = null; fn.apply(scope, args || []); } var cb = function () { currCall = (new Date()).getTime(); scope = this; args = arguments; diff = currCall - (debounce ? lastCall : lastExec) - delay; clearTimeout(timer); if (debounce) { timer = setTimeout(exec, delay); } else { if (diff >= 0) { exec(); } else { timer = setTimeout(exec, -diff); } } lastCall = currCall; }; /** * Clear throttle. * @public */ cb.clear = function () { if (timer) { clearTimeout(timer); timer = null; } }; return cb; }; /** * Create throttle method or update throttle rate. * * @example * ComponentView.prototype.render = function () { * ... * throttle.createOrUpdate( * this, * '_dispatchAction', * this.model.get('throttle'), * 'fixRate' * ); * }; * ComponentView.prototype.remove = function () { * throttle.clear(this, '_dispatchAction'); * }; * ComponentView.prototype.dispose = function () { * throttle.clear(this, '_dispatchAction'); * }; * * @public * @param {Object} obj * @param {string} fnAttr * @param {number} [rate] * @param {string} [throttleType='fixRate'] 'fixRate' or 'debounce' * @return {Function} throttled function. */ lib.createOrUpdate = function (obj, fnAttr, rate, throttleType) { var fn = obj[fnAttr]; if (!fn) { return; } var originFn = fn[ORIGIN_METHOD] || fn; var lastThrottleType = fn[THROTTLE_TYPE]; var lastRate = fn[RATE]; if (lastRate !== rate || lastThrottleType !== throttleType) { if (rate == null || !throttleType) { return (obj[fnAttr] = originFn); } fn = obj[fnAttr] = lib.throttle( originFn, rate, throttleType === 'debounce' ); fn[ORIGIN_METHOD] = originFn; fn[THROTTLE_TYPE] = throttleType; fn[RATE] = rate; } return fn; }; /** * Clear throttle. Example see throttle.createOrUpdate. * * @public * @param {Object} obj * @param {string} fnAttr */ lib.clear = function (obj, fnAttr) { var fn = obj[fnAttr]; if (fn && fn[ORIGIN_METHOD]) { obj[fnAttr] = fn[ORIGIN_METHOD]; } }; module.exports = lib; /***/ }, /* 82 */ /***/ function(module, exports, __webpack_require__) { /*! * ZRender, a high performance 2d drawing library. * * Copyright (c) 2013, Baidu Inc. * All rights reserved. * * LICENSE * https://github.com/ecomfe/zrender/blob/master/LICENSE.txt */ // Global defines var guid = __webpack_require__(32); var env = __webpack_require__(2); var zrUtil = __webpack_require__(4); var Handler = __webpack_require__(83); var Storage = __webpack_require__(85); var Animation = __webpack_require__(87); var HandlerProxy = __webpack_require__(90); var useVML = !env.canvasSupported; var painterCtors = { canvas: __webpack_require__(92) }; var instances = {}; // ZRender实例map索引 var zrender = {}; /** * @type {string} */ zrender.version = '3.2.2'; /** * Initializing a zrender instance * @param {HTMLElement} dom * @param {Object} opts * @param {string} [opts.renderer='canvas'] 'canvas' or 'svg' * @param {number} [opts.devicePixelRatio] * @param {number|string} [opts.width] Can be 'auto' (the same as null/undefined) * @param {number|string} [opts.height] Can be 'auto' (the same as null/undefined) * @return {module:zrender/ZRender} */ zrender.init = function(dom, opts) { var zr = new ZRender(guid(), dom, opts); instances[zr.id] = zr; return zr; }; /** * Dispose zrender instance * @param {module:zrender/ZRender} zr */ zrender.dispose = function (zr) { if (zr) { zr.dispose(); } else { for (var key in instances) { if (instances.hasOwnProperty(key)) { instances[key].dispose(); } } instances = {}; } return zrender; }; /** * Get zrender instance by id * @param {string} id zrender instance id * @return {module:zrender/ZRender} */ zrender.getInstance = function (id) { return instances[id]; }; zrender.registerPainter = function (name, Ctor) { painterCtors[name] = Ctor; }; function delInstance(id) { delete instances[id]; } /** * @module zrender/ZRender */ /** * @constructor * @alias module:zrender/ZRender * @param {string} id * @param {HTMLDomElement} dom * @param {Object} opts * @param {string} [opts.renderer='canvas'] 'canvas' or 'svg' * @param {number} [opts.devicePixelRatio] * @param {number} [opts.width] Can be 'auto' (the same as null/undefined) * @param {number} [opts.height] Can be 'auto' (the same as null/undefined) */ var ZRender = function(id, dom, opts) { opts = opts || {}; /** * @type {HTMLDomElement} */ this.dom = dom; /** * @type {string} */ this.id = id; var self = this; var storage = new Storage(); var rendererType = opts.renderer; if (useVML) { if (!painterCtors.vml) { throw new Error('You need to require \'zrender/vml/vml\' to support IE8'); } rendererType = 'vml'; } else if (!rendererType || !painterCtors[rendererType]) { rendererType = 'canvas'; } var painter = new painterCtors[rendererType](dom, storage, opts); this.storage = storage; this.painter = painter; var handerProxy = !env.node ? new HandlerProxy(painter.getViewportRoot()) : null; this.handler = new Handler(storage, painter, handerProxy, painter.root); /** * @type {module:zrender/animation/Animation} */ this.animation = new Animation({ stage: { update: zrUtil.bind(this.flush, this) } }); this.animation.start(); /** * @type {boolean} * @private */ this._needsRefresh; // 修改 storage.delFromMap, 每次删除元素之前删除动画 // FIXME 有点ugly var oldDelFromMap = storage.delFromMap; var oldAddToMap = storage.addToMap; storage.delFromMap = function (elId) { var el = storage.get(elId); oldDelFromMap.call(storage, elId); el && el.removeSelfFromZr(self); }; storage.addToMap = function (el) { oldAddToMap.call(storage, el); el.addSelfToZr(self); }; }; ZRender.prototype = { constructor: ZRender, /** * 获取实例唯一标识 * @return {string} */ getId: function () { return this.id; }, /** * 添加元素 * @param {module:zrender/Element} el */ add: function (el) { this.storage.addRoot(el); this._needsRefresh = true; }, /** * 删除元素 * @param {module:zrender/Element} el */ remove: function (el) { this.storage.delRoot(el); this._needsRefresh = true; }, /** * Change configuration of layer * @param {string} zLevel * @param {Object} config * @param {string} [config.clearColor=0] Clear color * @param {string} [config.motionBlur=false] If enable motion blur * @param {number} [config.lastFrameAlpha=0.7] Motion blur factor. Larger value cause longer trailer */ configLayer: function (zLevel, config) { this.painter.configLayer(zLevel, config); this._needsRefresh = true; }, /** * Repaint the canvas immediately */ refreshImmediately: function () { // Clear needsRefresh ahead to avoid something wrong happens in refresh // Or it will cause zrender refreshes again and again. this._needsRefresh = false; this.painter.refresh(); /** * Avoid trigger zr.refresh in Element#beforeUpdate hook */ this._needsRefresh = false; }, /** * Mark and repaint the canvas in the next frame of browser */ refresh: function() { this._needsRefresh = true; }, /** * Perform all refresh */ flush: function () { if (this._needsRefresh) { this.refreshImmediately(); } if (this._needsRefreshHover) { this.refreshHoverImmediately(); } }, /** * Add element to hover layer * @param {module:zrender/Element} el * @param {Object} style */ addHover: function (el, style) { if (this.painter.addHover) { this.painter.addHover(el, style); this.refreshHover(); } }, /** * Add element from hover layer * @param {module:zrender/Element} el */ removeHover: function (el) { if (this.painter.removeHover) { this.painter.removeHover(el); this.refreshHover(); } }, /** * Clear all hover elements in hover layer * @param {module:zrender/Element} el */ clearHover: function () { if (this.painter.clearHover) { this.painter.clearHover(); this.refreshHover(); } }, /** * Refresh hover in next frame */ refreshHover: function () { this._needsRefreshHover = true; }, /** * Refresh hover immediately */ refreshHoverImmediately: function () { this._needsRefreshHover = false; this.painter.refreshHover && this.painter.refreshHover(); }, /** * Resize the canvas. * Should be invoked when container size is changed * @param {Object} [opts] * @param {number|string} [opts.width] Can be 'auto' (the same as null/undefined) * @param {number|string} [opts.height] Can be 'auto' (the same as null/undefined) */ resize: function(opts) { opts = opts || {}; this.painter.resize(opts.width, opts.height); this.handler.resize(); }, /** * Stop and clear all animation immediately */ clearAnimation: function () { this.animation.clear(); }, /** * Get container width */ getWidth: function() { return this.painter.getWidth(); }, /** * Get container height */ getHeight: function() { return this.painter.getHeight(); }, /** * Export the canvas as Base64 URL * @param {string} type * @param {string} [backgroundColor='#fff'] * @return {string} Base64 URL */ // toDataURL: function(type, backgroundColor) { // return this.painter.getRenderedCanvas({ // backgroundColor: backgroundColor // }).toDataURL(type); // }, /** * Converting a path to image. * It has much better performance of drawing image rather than drawing a vector path. * @param {module:zrender/graphic/Path} e * @param {number} width * @param {number} height */ pathToImage: function(e, width, height) { var id = guid(); return this.painter.pathToImage(id, e, width, height); }, /** * Set default cursor * @param {string} [cursorStyle='default'] 例如 crosshair */ setCursorStyle: function (cursorStyle) { this.handler.setCursorStyle(cursorStyle); }, /** * Bind event * * @param {string} eventName Event name * @param {Function} eventHandler Handler function * @param {Object} [context] Context object */ on: function(eventName, eventHandler, context) { this.handler.on(eventName, eventHandler, context); }, /** * Unbind event * @param {string} eventName Event name * @param {Function} [eventHandler] Handler function */ off: function(eventName, eventHandler) { this.handler.off(eventName, eventHandler); }, /** * Trigger event manually * * @param {string} eventName Event name * @param {event=} event Event object */ trigger: function (eventName, event) { this.handler.trigger(eventName, event); }, /** * Clear all objects and the canvas. */ clear: function () { this.storage.delRoot(); this.painter.clear(); }, /** * Dispose self. */ dispose: function () { this.animation.stop(); this.clear(); this.storage.dispose(); this.painter.dispose(); this.handler.dispose(); this.animation = this.storage = this.painter = this.handler = null; delInstance(this.id); } }; module.exports = zrender; /***/ }, /* 83 */ /***/ function(module, exports, __webpack_require__) { 'use strict'; /** * Handler * @module zrender/Handler * @author Kener (@Kener-林峰, kener.linfeng@gmail.com) * errorrik (errorrik@gmail.com) * pissang (shenyi.914@gmail.com) */ var util = __webpack_require__(4); var Draggable = __webpack_require__(84); var Eventful = __webpack_require__(33); function makeEventPacket(eveType, target, event) { return { type: eveType, event: event, target: target, cancelBubble: false, offsetX: event.zrX, offsetY: event.zrY, gestureEvent: event.gestureEvent, pinchX: event.pinchX, pinchY: event.pinchY, pinchScale: event.pinchScale, wheelDelta: event.zrDelta, zrByTouch: event.zrByTouch }; } function EmptyProxy () {} EmptyProxy.prototype.dispose = function () {}; var handlerNames = [ 'click', 'dblclick', 'mousewheel', 'mouseout', 'mouseup', 'mousedown', 'mousemove', 'contextmenu' ]; /** * @alias module:zrender/Handler * @constructor * @extends module:zrender/mixin/Eventful * @param {module:zrender/Storage} storage Storage instance. * @param {module:zrender/Painter} painter Painter instance. * @param {module:zrender/dom/HandlerProxy} proxy HandlerProxy instance. * @param {HTMLElement} painterRoot painter.root (not painter.getViewportRoot()). */ var Handler = function(storage, painter, proxy, painterRoot) { Eventful.call(this); this.storage = storage; this.painter = painter; this.painterRoot = painterRoot; proxy = proxy || new EmptyProxy(); /** * Proxy of event. can be Dom, WebGLSurface, etc. */ this.proxy = proxy; // Attach handler proxy.handler = this; /** * @private * @type {boolean} */ this._hovered; /** * @private * @type {Date} */ this._lastTouchMoment; /** * @private * @type {number} */ this._lastX; /** * @private * @type {number} */ this._lastY; Draggable.call(this); util.each(handlerNames, function (name) { proxy.on && proxy.on(name, this[name], this); }, this); }; Handler.prototype = { constructor: Handler, mousemove: function (event) { var x = event.zrX; var y = event.zrY; var hovered = this.findHover(x, y, null); var lastHovered = this._hovered; var proxy = this.proxy; this._hovered = hovered; proxy.setCursor && proxy.setCursor(hovered ? hovered.cursor : 'default'); // Mouse out on previous hovered element if (lastHovered && hovered !== lastHovered && lastHovered.__zr) { this.dispatchToElement(lastHovered, 'mouseout', event); } // Mouse moving on one element this.dispatchToElement(hovered, 'mousemove', event); // Mouse over on a new element if (hovered && hovered !== lastHovered) { this.dispatchToElement(hovered, 'mouseover', event); } }, mouseout: function (event) { this.dispatchToElement(this._hovered, 'mouseout', event); // There might be some doms created by upper layer application // at the same level of painter.getViewportRoot() (e.g., tooltip // dom created by echarts), where 'globalout' event should not // be triggered when mouse enters these doms. (But 'mouseout' // should be triggered at the original hovered element as usual). var element = event.toElement || event.relatedTarget; var innerDom; do { element = element && element.parentNode; } while (element && element.nodeType != 9 && !( innerDom = element === this.painterRoot )); !innerDom && this.trigger('globalout', {event: event}); }, /** * Resize */ resize: function (event) { this._hovered = null; }, /** * Dispatch event * @param {string} eventName * @param {event=} eventArgs */ dispatch: function (eventName, eventArgs) { var handler = this[eventName]; handler && handler.call(this, eventArgs); }, /** * Dispose */ dispose: function () { this.proxy.dispose(); this.storage = this.proxy = this.painter = null; }, /** * 设置默认的cursor style * @param {string} [cursorStyle='default'] 例如 crosshair */ setCursorStyle: function (cursorStyle) { var proxy = this.proxy; proxy.setCursor && proxy.setCursor(cursorStyle); }, /** * 事件分发代理 * * @private * @param {Object} targetEl 目标图形元素 * @param {string} eventName 事件名称 * @param {Object} event 事件对象 */ dispatchToElement: function (targetEl, eventName, event) { var eventHandler = 'on' + eventName; var eventPacket = makeEventPacket(eventName, targetEl, event); var el = targetEl; while (el) { el[eventHandler] && (eventPacket.cancelBubble = el[eventHandler].call(el, eventPacket)); el.trigger(eventName, eventPacket); el = el.parent; if (eventPacket.cancelBubble) { break; } } if (!eventPacket.cancelBubble) { // 冒泡到顶级 zrender 对象 this.trigger(eventName, eventPacket); // 分发事件到用户自定义层 // 用户有可能在全局 click 事件中 dispose,所以需要判断下 painter 是否存在 this.painter && this.painter.eachOtherLayer(function (layer) { if (typeof(layer[eventHandler]) == 'function') { layer[eventHandler].call(layer, eventPacket); } if (layer.trigger) { layer.trigger(eventName, eventPacket); } }); } }, /** * @private * @param {number} x * @param {number} y * @param {module:zrender/graphic/Displayable} exclude * @method */ findHover: function(x, y, exclude) { var list = this.storage.getDisplayList(); for (var i = list.length - 1; i >= 0 ; i--) { if (!list[i].silent && list[i] !== exclude // getDisplayList may include ignored item in VML mode && !list[i].ignore && isHover(list[i], x, y)) { return list[i]; } } } }; // Common handlers util.each(['click', 'mousedown', 'mouseup', 'mousewheel', 'dblclick', 'contextmenu'], function (name) { Handler.prototype[name] = function (event) { // Find hover again to avoid click event is dispatched manually. Or click is triggered without mouseover var hovered = this.findHover(event.zrX, event.zrY, null); if (name === 'mousedown') { this._downel = hovered; // In case click triggered before mouseup this._upel = hovered; } else if (name === 'mosueup') { this._upel = hovered; } else if (name === 'click') { if (this._downel !== this._upel) { return; } } this.dispatchToElement(hovered, name, event); }; }); function isHover(displayable, x, y) { if (displayable[displayable.rectHover ? 'rectContain' : 'contain'](x, y)) { var el = displayable; while (el) { // If ancestor is silent or clipped by ancestor if (el.silent || (el.clipPath && !el.clipPath.contain(x, y))) { return false; } el = el.parent; } return true; } return false; } util.mixin(Handler, Eventful); util.mixin(Handler, Draggable); module.exports = Handler; /***/ }, /* 84 */ /***/ function(module, exports) { // TODO Draggable for group // FIXME Draggable on element which has parent rotation or scale function Draggable() { this.on('mousedown', this._dragStart, this); this.on('mousemove', this._drag, this); this.on('mouseup', this._dragEnd, this); this.on('globalout', this._dragEnd, this); // this._dropTarget = null; // this._draggingTarget = null; // this._x = 0; // this._y = 0; } Draggable.prototype = { constructor: Draggable, _dragStart: function (e) { var draggingTarget = e.target; if (draggingTarget && draggingTarget.draggable) { this._draggingTarget = draggingTarget; draggingTarget.dragging = true; this._x = e.offsetX; this._y = e.offsetY; this.dispatchToElement(draggingTarget, 'dragstart', e.event); } }, _drag: function (e) { var draggingTarget = this._draggingTarget; if (draggingTarget) { var x = e.offsetX; var y = e.offsetY; var dx = x - this._x; var dy = y - this._y; this._x = x; this._y = y; draggingTarget.drift(dx, dy, e); this.dispatchToElement(draggingTarget, 'drag', e.event); var dropTarget = this.findHover(x, y, draggingTarget); var lastDropTarget = this._dropTarget; this._dropTarget = dropTarget; if (draggingTarget !== dropTarget) { if (lastDropTarget && dropTarget !== lastDropTarget) { this.dispatchToElement(lastDropTarget, 'dragleave', e.event); } if (dropTarget && dropTarget !== lastDropTarget) { this.dispatchToElement(dropTarget, 'dragenter', e.event); } } } }, _dragEnd: function (e) { var draggingTarget = this._draggingTarget; if (draggingTarget) { draggingTarget.dragging = false; } this.dispatchToElement(draggingTarget, 'dragend', e.event); if (this._dropTarget) { this.dispatchToElement(this._dropTarget, 'drop', e.event); } this._draggingTarget = null; this._dropTarget = null; } }; module.exports = Draggable; /***/ }, /* 85 */ /***/ function(module, exports, __webpack_require__) { 'use strict'; /** * Storage内容仓库模块 * @module zrender/Storage * @author Kener (@Kener-林峰, kener.linfeng@gmail.com) * @author errorrik (errorrik@gmail.com) * @author pissang (https://github.com/pissang/) */ var util = __webpack_require__(4); var env = __webpack_require__(2); var Group = __webpack_require__(30); // Use timsort because in most case elements are partially sorted // https://jsfiddle.net/pissang/jr4x7mdm/8/ var timsort = __webpack_require__(86); function shapeCompareFunc(a, b) { if (a.zlevel === b.zlevel) { if (a.z === b.z) { // if (a.z2 === b.z2) { // // FIXME Slow has renderidx compare // // http://stackoverflow.com/questions/20883421/sorting-in-javascript-should-every-compare-function-have-a-return-0-statement // // https://github.com/v8/v8/blob/47cce544a31ed5577ffe2963f67acb4144ee0232/src/js/array.js#L1012 // return a.__renderidx - b.__renderidx; // } return a.z2 - b.z2; } return a.z - b.z; } return a.zlevel - b.zlevel; } /** * 内容仓库 (M) * @alias module:zrender/Storage * @constructor */ var Storage = function () { // 所有常规形状,id索引的map this._elements = {}; this._roots = []; this._displayList = []; this._displayListLen = 0; }; Storage.prototype = { constructor: Storage, /** * @param {Function} cb * */ traverse: function (cb, context) { for (var i = 0; i < this._roots.length; i++) { this._roots[i].traverse(cb, context); } }, /** * 返回所有图形的绘制队列 * @param {boolean} [update=false] 是否在返回前更新该数组 * @param {boolean} [includeIgnore=false] 是否包含 ignore 的数组, 在 update 为 true 的时候有效 * * 详见{@link module:zrender/graphic/Displayable.prototype.updateDisplayList} * @return {Array.} */ getDisplayList: function (update, includeIgnore) { includeIgnore = includeIgnore || false; if (update) { this.updateDisplayList(includeIgnore); } return this._displayList; }, /** * 更新图形的绘制队列。 * 每次绘制前都会调用,该方法会先深度优先遍历整个树,更新所有Group和Shape的变换并且把所有可见的Shape保存到数组中, * 最后根据绘制的优先级(zlevel > z > 插入顺序)排序得到绘制队列 * @param {boolean} [includeIgnore=false] 是否包含 ignore 的数组 */ updateDisplayList: function (includeIgnore) { this._displayListLen = 0; var roots = this._roots; var displayList = this._displayList; for (var i = 0, len = roots.length; i < len; i++) { this._updateAndAddDisplayable(roots[i], null, includeIgnore); } displayList.length = this._displayListLen; // for (var i = 0, len = displayList.length; i < len; i++) { // displayList[i].__renderidx = i; // } // displayList.sort(shapeCompareFunc); env.canvasSupported && timsort(displayList, shapeCompareFunc); }, _updateAndAddDisplayable: function (el, clipPaths, includeIgnore) { if (el.ignore && !includeIgnore) { return; } el.beforeUpdate(); if (el.__dirty) { el.update(); } el.afterUpdate(); var clipPath = el.clipPath; if (clipPath) { // clipPath 的变换是基于 group 的变换 clipPath.parent = el; clipPath.updateTransform(); // FIXME 效率影响 if (clipPaths) { clipPaths = clipPaths.slice(); clipPaths.push(clipPath); } else { clipPaths = [clipPath]; } } if (el.isGroup) { var children = el._children; for (var i = 0; i < children.length; i++) { var child = children[i]; // Force to mark as dirty if group is dirty // FIXME __dirtyPath ? if (el.__dirty) { child.__dirty = true; } this._updateAndAddDisplayable(child, clipPaths, includeIgnore); } // Mark group clean here el.__dirty = false; } else { el.__clipPaths = clipPaths; this._displayList[this._displayListLen++] = el; } }, /** * 添加图形(Shape)或者组(Group)到根节点 * @param {module:zrender/Element} el */ addRoot: function (el) { // Element has been added if (this._elements[el.id]) { return; } if (el instanceof Group) { el.addChildrenToStorage(this); } this.addToMap(el); this._roots.push(el); }, /** * 删除指定的图形(Shape)或者组(Group) * @param {string|Array.} [elId] 如果为空清空整个Storage */ delRoot: function (elId) { if (elId == null) { // 不指定elId清空 for (var i = 0; i < this._roots.length; i++) { var root = this._roots[i]; if (root instanceof Group) { root.delChildrenFromStorage(this); } } this._elements = {}; this._roots = []; this._displayList = []; this._displayListLen = 0; return; } if (elId instanceof Array) { for (var i = 0, l = elId.length; i < l; i++) { this.delRoot(elId[i]); } return; } var el; if (typeof(elId) == 'string') { el = this._elements[elId]; } else { el = elId; } var idx = util.indexOf(this._roots, el); if (idx >= 0) { this.delFromMap(el.id); this._roots.splice(idx, 1); if (el instanceof Group) { el.delChildrenFromStorage(this); } } }, addToMap: function (el) { if (el instanceof Group) { el.__storage = this; } el.dirty(false); this._elements[el.id] = el; return this; }, get: function (elId) { return this._elements[elId]; }, delFromMap: function (elId) { var elements = this._elements; var el = elements[elId]; if (el) { delete elements[elId]; if (el instanceof Group) { el.__storage = null; } } return this; }, /** * 清空并且释放Storage */ dispose: function () { this._elements = this._renderList = this._roots = null; }, displayableSortFunc: shapeCompareFunc }; module.exports = Storage; /***/ }, /* 86 */ /***/ function(module, exports) { // https://github.com/mziccard/node-timsort var DEFAULT_MIN_MERGE = 32; var DEFAULT_MIN_GALLOPING = 7; var DEFAULT_TMP_STORAGE_LENGTH = 256; function minRunLength(n) { var r = 0; while (n >= DEFAULT_MIN_MERGE) { r |= n & 1; n >>= 1; } return n + r; } function makeAscendingRun(array, lo, hi, compare) { var runHi = lo + 1; if (runHi === hi) { return 1; } if (compare(array[runHi++], array[lo]) < 0) { while (runHi < hi && compare(array[runHi], array[runHi - 1]) < 0) { runHi++; } reverseRun(array, lo, runHi); } else { while (runHi < hi && compare(array[runHi], array[runHi - 1]) >= 0) { runHi++; } } return runHi - lo; } function reverseRun(array, lo, hi) { hi--; while (lo < hi) { var t = array[lo]; array[lo++] = array[hi]; array[hi--] = t; } } function binaryInsertionSort(array, lo, hi, start, compare) { if (start === lo) { start++; } for (; start < hi; start++) { var pivot = array[start]; var left = lo; var right = start; var mid; while (left < right) { mid = left + right >>> 1; if (compare(pivot, array[mid]) < 0) { right = mid; } else { left = mid + 1; } } var n = start - left; switch (n) { case 3: array[left + 3] = array[left + 2]; case 2: array[left + 2] = array[left + 1]; case 1: array[left + 1] = array[left]; break; default: while (n > 0) { array[left + n] = array[left + n - 1]; n--; } } array[left] = pivot; } } function gallopLeft(value, array, start, length, hint, compare) { var lastOffset = 0; var maxOffset = 0; var offset = 1; if (compare(value, array[start + hint]) > 0) { maxOffset = length - hint; while (offset < maxOffset && compare(value, array[start + hint + offset]) > 0) { lastOffset = offset; offset = (offset << 1) + 1; if (offset <= 0) { offset = maxOffset; } } if (offset > maxOffset) { offset = maxOffset; } lastOffset += hint; offset += hint; } else { maxOffset = hint + 1; while (offset < maxOffset && compare(value, array[start + hint - offset]) <= 0) { lastOffset = offset; offset = (offset << 1) + 1; if (offset <= 0) { offset = maxOffset; } } if (offset > maxOffset) { offset = maxOffset; } var tmp = lastOffset; lastOffset = hint - offset; offset = hint - tmp; } lastOffset++; while (lastOffset < offset) { var m = lastOffset + (offset - lastOffset >>> 1); if (compare(value, array[start + m]) > 0) { lastOffset = m + 1; } else { offset = m; } } return offset; } function gallopRight(value, array, start, length, hint, compare) { var lastOffset = 0; var maxOffset = 0; var offset = 1; if (compare(value, array[start + hint]) < 0) { maxOffset = hint + 1; while (offset < maxOffset && compare(value, array[start + hint - offset]) < 0) { lastOffset = offset; offset = (offset << 1) + 1; if (offset <= 0) { offset = maxOffset; } } if (offset > maxOffset) { offset = maxOffset; } var tmp = lastOffset; lastOffset = hint - offset; offset = hint - tmp; } else { maxOffset = length - hint; while (offset < maxOffset && compare(value, array[start + hint + offset]) >= 0) { lastOffset = offset; offset = (offset << 1) + 1; if (offset <= 0) { offset = maxOffset; } } if (offset > maxOffset) { offset = maxOffset; } lastOffset += hint; offset += hint; } lastOffset++; while (lastOffset < offset) { var m = lastOffset + (offset - lastOffset >>> 1); if (compare(value, array[start + m]) < 0) { offset = m; } else { lastOffset = m + 1; } } return offset; } function TimSort(array, compare) { var minGallop = DEFAULT_MIN_GALLOPING; var length = 0; var tmpStorageLength = DEFAULT_TMP_STORAGE_LENGTH; var stackLength = 0; var runStart; var runLength; var stackSize = 0; length = array.length; if (length < 2 * DEFAULT_TMP_STORAGE_LENGTH) { tmpStorageLength = length >>> 1; } var tmp = []; stackLength = length < 120 ? 5 : length < 1542 ? 10 : length < 119151 ? 19 : 40; runStart = []; runLength = []; function pushRun(_runStart, _runLength) { runStart[stackSize] = _runStart; runLength[stackSize] = _runLength; stackSize += 1; } function mergeRuns() { while (stackSize > 1) { var n = stackSize - 2; if (n >= 1 && runLength[n - 1] <= runLength[n] + runLength[n + 1] || n >= 2 && runLength[n - 2] <= runLength[n] + runLength[n - 1]) { if (runLength[n - 1] < runLength[n + 1]) { n--; } } else if (runLength[n] > runLength[n + 1]) { break; } mergeAt(n); } } function forceMergeRuns() { while (stackSize > 1) { var n = stackSize - 2; if (n > 0 && runLength[n - 1] < runLength[n + 1]) { n--; } mergeAt(n); } } function mergeAt(i) { var start1 = runStart[i]; var length1 = runLength[i]; var start2 = runStart[i + 1]; var length2 = runLength[i + 1]; runLength[i] = length1 + length2; if (i === stackSize - 3) { runStart[i + 1] = runStart[i + 2]; runLength[i + 1] = runLength[i + 2]; } stackSize--; var k = gallopRight(array[start2], array, start1, length1, 0, compare); start1 += k; length1 -= k; if (length1 === 0) { return; } length2 = gallopLeft(array[start1 + length1 - 1], array, start2, length2, length2 - 1, compare); if (length2 === 0) { return; } if (length1 <= length2) { mergeLow(start1, length1, start2, length2); } else { mergeHigh(start1, length1, start2, length2); } } function mergeLow(start1, length1, start2, length2) { var i = 0; for (i = 0; i < length1; i++) { tmp[i] = array[start1 + i]; } var cursor1 = 0; var cursor2 = start2; var dest = start1; array[dest++] = array[cursor2++]; if (--length2 === 0) { for (i = 0; i < length1; i++) { array[dest + i] = tmp[cursor1 + i]; } return; } if (length1 === 1) { for (i = 0; i < length2; i++) { array[dest + i] = array[cursor2 + i]; } array[dest + length2] = tmp[cursor1]; return; } var _minGallop = minGallop; var count1, count2, exit; while (1) { count1 = 0; count2 = 0; exit = false; do { if (compare(array[cursor2], tmp[cursor1]) < 0) { array[dest++] = array[cursor2++]; count2++; count1 = 0; if (--length2 === 0) { exit = true; break; } } else { array[dest++] = tmp[cursor1++]; count1++; count2 = 0; if (--length1 === 1) { exit = true; break; } } } while ((count1 | count2) < _minGallop); if (exit) { break; } do { count1 = gallopRight(array[cursor2], tmp, cursor1, length1, 0, compare); if (count1 !== 0) { for (i = 0; i < count1; i++) { array[dest + i] = tmp[cursor1 + i]; } dest += count1; cursor1 += count1; length1 -= count1; if (length1 <= 1) { exit = true; break; } } array[dest++] = array[cursor2++]; if (--length2 === 0) { exit = true; break; } count2 = gallopLeft(tmp[cursor1], array, cursor2, length2, 0, compare); if (count2 !== 0) { for (i = 0; i < count2; i++) { array[dest + i] = array[cursor2 + i]; } dest += count2; cursor2 += count2; length2 -= count2; if (length2 === 0) { exit = true; break; } } array[dest++] = tmp[cursor1++]; if (--length1 === 1) { exit = true; break; } _minGallop--; } while (count1 >= DEFAULT_MIN_GALLOPING || count2 >= DEFAULT_MIN_GALLOPING); if (exit) { break; } if (_minGallop < 0) { _minGallop = 0; } _minGallop += 2; } minGallop = _minGallop; minGallop < 1 && (minGallop = 1); if (length1 === 1) { for (i = 0; i < length2; i++) { array[dest + i] = array[cursor2 + i]; } array[dest + length2] = tmp[cursor1]; } else if (length1 === 0) { throw new Error(); // throw new Error('mergeLow preconditions were not respected'); } else { for (i = 0; i < length1; i++) { array[dest + i] = tmp[cursor1 + i]; } } } function mergeHigh (start1, length1, start2, length2) { var i = 0; for (i = 0; i < length2; i++) { tmp[i] = array[start2 + i]; } var cursor1 = start1 + length1 - 1; var cursor2 = length2 - 1; var dest = start2 + length2 - 1; var customCursor = 0; var customDest = 0; array[dest--] = array[cursor1--]; if (--length1 === 0) { customCursor = dest - (length2 - 1); for (i = 0; i < length2; i++) { array[customCursor + i] = tmp[i]; } return; } if (length2 === 1) { dest -= length1; cursor1 -= length1; customDest = dest + 1; customCursor = cursor1 + 1; for (i = length1 - 1; i >= 0; i--) { array[customDest + i] = array[customCursor + i]; } array[dest] = tmp[cursor2]; return; } var _minGallop = minGallop; while (true) { var count1 = 0; var count2 = 0; var exit = false; do { if (compare(tmp[cursor2], array[cursor1]) < 0) { array[dest--] = array[cursor1--]; count1++; count2 = 0; if (--length1 === 0) { exit = true; break; } } else { array[dest--] = tmp[cursor2--]; count2++; count1 = 0; if (--length2 === 1) { exit = true; break; } } } while ((count1 | count2) < _minGallop); if (exit) { break; } do { count1 = length1 - gallopRight(tmp[cursor2], array, start1, length1, length1 - 1, compare); if (count1 !== 0) { dest -= count1; cursor1 -= count1; length1 -= count1; customDest = dest + 1; customCursor = cursor1 + 1; for (i = count1 - 1; i >= 0; i--) { array[customDest + i] = array[customCursor + i]; } if (length1 === 0) { exit = true; break; } } array[dest--] = tmp[cursor2--]; if (--length2 === 1) { exit = true; break; } count2 = length2 - gallopLeft(array[cursor1], tmp, 0, length2, length2 - 1, compare); if (count2 !== 0) { dest -= count2; cursor2 -= count2; length2 -= count2; customDest = dest + 1; customCursor = cursor2 + 1; for (i = 0; i < count2; i++) { array[customDest + i] = tmp[customCursor + i]; } if (length2 <= 1) { exit = true; break; } } array[dest--] = array[cursor1--]; if (--length1 === 0) { exit = true; break; } _minGallop--; } while (count1 >= DEFAULT_MIN_GALLOPING || count2 >= DEFAULT_MIN_GALLOPING); if (exit) { break; } if (_minGallop < 0) { _minGallop = 0; } _minGallop += 2; } minGallop = _minGallop; if (minGallop < 1) { minGallop = 1; } if (length2 === 1) { dest -= length1; cursor1 -= length1; customDest = dest + 1; customCursor = cursor1 + 1; for (i = length1 - 1; i >= 0; i--) { array[customDest + i] = array[customCursor + i]; } array[dest] = tmp[cursor2]; } else if (length2 === 0) { throw new Error(); // throw new Error('mergeHigh preconditions were not respected'); } else { customCursor = dest - (length2 - 1); for (i = 0; i < length2; i++) { array[customCursor + i] = tmp[i]; } } } this.mergeRuns = mergeRuns; this.forceMergeRuns = forceMergeRuns; this.pushRun = pushRun; } function sort(array, compare, lo, hi) { if (!lo) { lo = 0; } if (!hi) { hi = array.length; } var remaining = hi - lo; if (remaining < 2) { return; } var runLength = 0; if (remaining < DEFAULT_MIN_MERGE) { runLength = makeAscendingRun(array, lo, hi, compare); binaryInsertionSort(array, lo, hi, lo + runLength, compare); return; } var ts = new TimSort(array, compare); var minRun = minRunLength(remaining); do { runLength = makeAscendingRun(array, lo, hi, compare); if (runLength < minRun) { var force = remaining; if (force > minRun) { force = minRun; } binaryInsertionSort(array, lo, lo + force, lo + runLength, compare); runLength = force; } ts.pushRun(lo, runLength); ts.mergeRuns(); remaining -= runLength; lo += runLength; } while (remaining !== 0); ts.forceMergeRuns(); } module.exports = sort; /***/ }, /* 87 */ /***/ function(module, exports, __webpack_require__) { 'use strict'; /** * 动画主类, 调度和管理所有动画控制器 * * @module zrender/animation/Animation * @author pissang(https://github.com/pissang) */ // TODO Additive animation // http://iosoteric.com/additive-animations-animatewithduration-in-ios-8/ // https://developer.apple.com/videos/wwdc2014/#236 var util = __webpack_require__(4); var Dispatcher = __webpack_require__(88).Dispatcher; var requestAnimationFrame = __webpack_require__(89); var Animator = __webpack_require__(36); /** * @typedef {Object} IZRenderStage * @property {Function} update */ /** * @alias module:zrender/animation/Animation * @constructor * @param {Object} [options] * @param {Function} [options.onframe] * @param {IZRenderStage} [options.stage] * @example * var animation = new Animation(); * var obj = { * x: 100, * y: 100 * }; * animation.animate(node.position) * .when(1000, { * x: 500, * y: 500 * }) * .when(2000, { * x: 100, * y: 100 * }) * .start('spline'); */ var Animation = function (options) { options = options || {}; this.stage = options.stage || {}; this.onframe = options.onframe || function() {}; // private properties this._clips = []; this._running = false; this._time; this._pausedTime; this._pauseStart; this._paused = false; Dispatcher.call(this); }; Animation.prototype = { constructor: Animation, /** * 添加 clip * @param {module:zrender/animation/Clip} clip */ addClip: function (clip) { this._clips.push(clip); }, /** * 添加 animator * @param {module:zrender/animation/Animator} animator */ addAnimator: function (animator) { animator.animation = this; var clips = animator.getClips(); for (var i = 0; i < clips.length; i++) { this.addClip(clips[i]); } }, /** * 删除动画片段 * @param {module:zrender/animation/Clip} clip */ removeClip: function(clip) { var idx = util.indexOf(this._clips, clip); if (idx >= 0) { this._clips.splice(idx, 1); } }, /** * 删除动画片段 * @param {module:zrender/animation/Animator} animator */ removeAnimator: function (animator) { var clips = animator.getClips(); for (var i = 0; i < clips.length; i++) { this.removeClip(clips[i]); } animator.animation = null; }, _update: function() { var time = new Date().getTime() - this._pausedTime; var delta = time - this._time; var clips = this._clips; var len = clips.length; var deferredEvents = []; var deferredClips = []; for (var i = 0; i < len; i++) { var clip = clips[i]; var e = clip.step(time); // Throw out the events need to be called after // stage.update, like destroy if (e) { deferredEvents.push(e); deferredClips.push(clip); } } // Remove the finished clip for (var i = 0; i < len;) { if (clips[i]._needsRemove) { clips[i] = clips[len - 1]; clips.pop(); len--; } else { i++; } } len = deferredEvents.length; for (var i = 0; i < len; i++) { deferredClips[i].fire(deferredEvents[i]); } this._time = time; this.onframe(delta); this.trigger('frame', delta); if (this.stage.update) { this.stage.update(); } }, _startLoop: function () { var self = this; this._running = true; function step() { if (self._running) { requestAnimationFrame(step); !self._paused && self._update(); } } requestAnimationFrame(step); }, /** * 开始运行动画 */ start: function () { this._time = new Date().getTime(); this._pausedTime = 0; this._startLoop(); }, /** * 停止运行动画 */ stop: function () { this._running = false; }, /** * Pause */ pause: function () { if (!this._paused) { this._pauseStart = new Date().getTime(); this._paused = true; } }, /** * Resume */ resume: function () { if (this._paused) { this._pausedTime += (new Date().getTime()) - this._pauseStart; this._paused = false; } }, /** * 清除所有动画片段 */ clear: function () { this._clips = []; }, /** * 对一个目标创建一个animator对象,可以指定目标中的属性使用动画 * @param {Object} target * @param {Object} options * @param {boolean} [options.loop=false] 是否循环播放动画 * @param {Function} [options.getter=null] * 如果指定getter函数,会通过getter函数取属性值 * @param {Function} [options.setter=null] * 如果指定setter函数,会通过setter函数设置属性值 * @return {module:zrender/animation/Animation~Animator} */ // TODO Gap animate: function (target, options) { options = options || {}; var animator = new Animator( target, options.loop, options.getter, options.setter ); return animator; } }; util.mixin(Animation, Dispatcher); module.exports = Animation; /***/ }, /* 88 */ /***/ function(module, exports, __webpack_require__) { 'use strict'; /** * 事件辅助类 * @module zrender/core/event * @author Kener (@Kener-林峰, kener.linfeng@gmail.com) */ var Eventful = __webpack_require__(33); var env = __webpack_require__(2); var isDomLevel2 = (typeof window !== 'undefined') && !!window.addEventListener; function getBoundingClientRect(el) { // BlackBerry 5, iOS 3 (original iPhone) don't have getBoundingRect return el.getBoundingClientRect ? el.getBoundingClientRect() : {left: 0, top: 0}; } // `calculate` is optional, default false function clientToLocal(el, e, out, calculate) { out = out || {}; // According to the W3C Working Draft, offsetX and offsetY should be relative // to the padding edge of the target element. The only browser using this convention // is IE. Webkit uses the border edge, Opera uses the content edge, and FireFox does // not support the properties. // (see http://www.jacklmoore.com/notes/mouse-position/) // In zr painter.dom, padding edge equals to border edge. // FIXME // When mousemove event triggered on ec tooltip, target is not zr painter.dom, and // offsetX/Y is relative to e.target, where the calculation of zrX/Y via offsetX/Y // is too complex. So css-transfrom dont support in this case temporarily. if (calculate || !env.canvasSupported) { defaultGetZrXY(el, e, out); } // Caution: In FireFox, layerX/layerY Mouse position relative to the closest positioned // ancestor element, so we should make sure el is positioned (e.g., not position:static). // BTW1, Webkit don't return the same results as FF in non-simple cases (like add // zoom-factor, overflow / opacity layers, transforms ...) // BTW2, (ev.offsetY || ev.pageY - $(ev.target).offset().top) is not correct in preserve-3d. // // BTW3, In ff, offsetX/offsetY is always 0. else if (env.browser.firefox && e.layerX != null && e.layerX !== e.offsetX) { out.zrX = e.layerX; out.zrY = e.layerY; } // For IE6+, chrome, safari, opera. (When will ff support offsetX?) else if (e.offsetX != null) { out.zrX = e.offsetX; out.zrY = e.offsetY; } // For some other device, e.g., IOS safari. else { defaultGetZrXY(el, e, out); } return out; } function defaultGetZrXY(el, e, out) { // This well-known method below does not support css transform. var box = getBoundingClientRect(el); out.zrX = e.clientX - box.left; out.zrY = e.clientY - box.top; } /** * 如果存在第三方嵌入的一些dom触发的事件,或touch事件,需要转换一下事件坐标. * `calculate` is optional, default false. */ function normalizeEvent(el, e, calculate) { e = e || window.event; if (e.zrX != null) { return e; } var eventType = e.type; var isTouch = eventType && eventType.indexOf('touch') >= 0; if (!isTouch) { clientToLocal(el, e, e, calculate); e.zrDelta = (e.wheelDelta) ? e.wheelDelta / 120 : -(e.detail || 0) / 3; } else { var touch = eventType != 'touchend' ? e.targetTouches[0] : e.changedTouches[0]; touch && clientToLocal(el, touch, e, calculate); } return e; } function addEventListener(el, name, handler) { if (isDomLevel2) { el.addEventListener(name, handler); } else { el.attachEvent('on' + name, handler); } } function removeEventListener(el, name, handler) { if (isDomLevel2) { el.removeEventListener(name, handler); } else { el.detachEvent('on' + name, handler); } } /** * 停止冒泡和阻止默认行为 * @memberOf module:zrender/core/event * @method * @param {Event} e : event对象 */ var stop = isDomLevel2 ? function (e) { e.preventDefault(); e.stopPropagation(); e.cancelBubble = true; } : function (e) { e.returnValue = false; e.cancelBubble = true; }; module.exports = { clientToLocal: clientToLocal, normalizeEvent: normalizeEvent, addEventListener: addEventListener, removeEventListener: removeEventListener, stop: stop, // 做向上兼容 Dispatcher: Eventful }; /***/ }, /* 89 */ /***/ function(module, exports) { module.exports = (typeof window !== 'undefined' && (window.requestAnimationFrame || window.msRequestAnimationFrame || window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame)) || function (func) { setTimeout(func, 16); }; /***/ }, /* 90 */ /***/ function(module, exports, __webpack_require__) { var eventTool = __webpack_require__(88); var zrUtil = __webpack_require__(4); var Eventful = __webpack_require__(33); var env = __webpack_require__(2); var GestureMgr = __webpack_require__(91); var addEventListener = eventTool.addEventListener; var removeEventListener = eventTool.removeEventListener; var normalizeEvent = eventTool.normalizeEvent; var TOUCH_CLICK_DELAY = 300; var mouseHandlerNames = [ 'click', 'dblclick', 'mousewheel', 'mouseout', 'mouseup', 'mousedown', 'mousemove', 'contextmenu' ]; var touchHandlerNames = [ 'touchstart', 'touchend', 'touchmove' ]; function eventNameFix(name) { return (name === 'mousewheel' && env.browser.firefox) ? 'DOMMouseScroll' : name; } function processGesture(proxy, event, stage) { var gestureMgr = proxy._gestureMgr; stage === 'start' && gestureMgr.clear(); var gestureInfo = gestureMgr.recognize( event, proxy.handler.findHover(event.zrX, event.zrY, null), proxy.dom ); stage === 'end' && gestureMgr.clear(); if (gestureInfo) { // eventTool.stop(event); var type = gestureInfo.type; event.gestureEvent = type; proxy.handler.dispatchToElement(gestureInfo.target, type, gestureInfo.event); } } /** * Prevent mouse event from being dispatched after Touch Events action * @see * 1. Mobile browsers dispatch mouse events 300ms after touchend. * 2. Chrome for Android dispatch mousedown for long-touch about 650ms * Result: Blocking Mouse Events for 700ms. */ function setTouchTimer(instance) { instance._touching = true; clearTimeout(instance._touchTimer); instance._touchTimer = setTimeout(function () { instance._touching = false; }, 700); } function useTouchEvent() { return env.touchEventsSupported; } var domHandlers = { /** * Mouse move handler * @inner * @param {Event} event */ mousemove: function (event) { event = normalizeEvent(this.dom, event); this.trigger('mousemove', event); }, /** * Mouse out handler * @inner * @param {Event} event */ mouseout: function (event) { event = normalizeEvent(this.dom, event); var element = event.toElement || event.relatedTarget; if (element != this.dom) { while (element && element.nodeType != 9) { // 忽略包含在root中的dom引起的mouseOut if (element === this.dom) { return; } element = element.parentNode; } } this.trigger('mouseout', event); }, /** * Touch开始响应函数 * @inner * @param {Event} event */ touchstart: function (event) { // Default mouse behaviour should not be disabled here. // For example, page may needs to be slided. event = normalizeEvent(this.dom, event); // Mark touch, which is useful in distinguish touch and // mouse event in upper applicatoin. event.zrByTouch = true; this._lastTouchMoment = new Date(); processGesture(this, event, 'start'); // In touch device, trigger `mousemove`(`mouseover`) should // be triggered. domHandlers.mousemove.call(this, event); domHandlers.mousedown.call(this, event); setTouchTimer(this); }, /** * Touch移动响应函数 * @inner * @param {Event} event */ touchmove: function (event) { event = normalizeEvent(this.dom, event); // Mark touch, which is useful in distinguish touch and // mouse event in upper applicatoin. event.zrByTouch = true; processGesture(this, event, 'change'); // Mouse move should always be triggered no matter whether // there is gestrue event, because mouse move and pinch may // be used at the same time. domHandlers.mousemove.call(this, event); setTouchTimer(this); }, /** * Touch结束响应函数 * @inner * @param {Event} event */ touchend: function (event) { event = normalizeEvent(this.dom, event); // Mark touch, which is useful in distinguish touch and // mouse event in upper applicatoin. event.zrByTouch = true; processGesture(this, event, 'end'); domHandlers.mouseup.call(this, event); // Do not trigger `mouseout` here, in spite of `mousemove`(`mouseover`) is // triggered in `touchstart`. This seems to be illogical, but by this mechanism, // we can conveniently implement "hover style" in both PC and touch device just // by listening to `mouseover` to add "hover style" and listening to `mouseout` // to remove "hover style" on an element, without any additional code for // compatibility. (`mouseout` will not be triggered in `touchend`, so "hover // style" will remain for user view) // click event should always be triggered no matter whether // there is gestrue event. System click can not be prevented. if (+new Date() - this._lastTouchMoment < TOUCH_CLICK_DELAY) { domHandlers.click.call(this, event); } setTouchTimer(this); } }; // Common handlers zrUtil.each(['click', 'mousedown', 'mouseup', 'mousewheel', 'dblclick', 'contextmenu'], function (name) { domHandlers[name] = function (event) { event = normalizeEvent(this.dom, event); this.trigger(name, event); }; }); /** * 为控制类实例初始化dom 事件处理函数 * * @inner * @param {module:zrender/Handler} instance 控制类实例 */ function initDomHandler(instance) { for (var i = 0; i < touchHandlerNames.length; i++) { var name = touchHandlerNames[i]; instance._handlers[name] = zrUtil.bind(domHandlers[name], instance); } for (var i = 0; i < mouseHandlerNames.length; i++) { var name = mouseHandlerNames[i]; instance._handlers[name] = makeMouseHandler(domHandlers[name], instance); } function makeMouseHandler(fn, instance) { return function () { if (instance._touching) { return; } return fn.apply(instance, arguments); }; } } function HandlerDomProxy(dom) { Eventful.call(this); this.dom = dom; /** * @private * @type {boolean} */ this._touching = false; /** * @private * @type {number} */ this._touchTimer; /** * @private * @type {module:zrender/core/GestureMgr} */ this._gestureMgr = new GestureMgr(); this._handlers = {}; initDomHandler(this); if (useTouchEvent()) { mountHandlers(touchHandlerNames, this); // Handler of 'mouseout' event is needed in touch mode, which will be mounted below. // addEventListener(root, 'mouseout', this._mouseoutHandler); } // Considering some devices that both enable touch and mouse event (like MS Surface // and lenovo X240, @see #2350), we make mouse event be always listened, otherwise // mouse event can not be handle in those devices. mountHandlers(mouseHandlerNames, this); function mountHandlers(handlerNames, instance) { zrUtil.each(handlerNames, function (name) { addEventListener(dom, eventNameFix(name), instance._handlers[name]); }, instance); } } var handlerDomProxyProto = HandlerDomProxy.prototype; handlerDomProxyProto.dispose = function () { var handlerNames = mouseHandlerNames.concat(touchHandlerNames); for (var i = 0; i < handlerNames.length; i++) { var name = handlerNames[i]; removeEventListener(this.dom, eventNameFix(name), this._handlers[name]); } }; handlerDomProxyProto.setCursor = function (cursorStyle) { this.dom.style.cursor = cursorStyle || 'default'; }; zrUtil.mixin(HandlerDomProxy, Eventful); module.exports = HandlerDomProxy; /***/ }, /* 91 */ /***/ function(module, exports, __webpack_require__) { 'use strict'; /** * Only implements needed gestures for mobile. */ var eventUtil = __webpack_require__(88); var GestureMgr = function () { /** * @private * @type {Array.} */ this._track = []; }; GestureMgr.prototype = { constructor: GestureMgr, recognize: function (event, target, root) { this._doTrack(event, target, root); return this._recognize(event); }, clear: function () { this._track.length = 0; return this; }, _doTrack: function (event, target, root) { var touches = event.touches; if (!touches) { return; } var trackItem = { points: [], touches: [], target: target, event: event }; for (var i = 0, len = touches.length; i < len; i++) { var touch = touches[i]; var pos = eventUtil.clientToLocal(root, touch, {}); trackItem.points.push([pos.zrX, pos.zrY]); trackItem.touches.push(touch); } this._track.push(trackItem); }, _recognize: function (event) { for (var eventName in recognizers) { if (recognizers.hasOwnProperty(eventName)) { var gestureInfo = recognizers[eventName](this._track, event); if (gestureInfo) { return gestureInfo; } } } } }; function dist(pointPair) { var dx = pointPair[1][0] - pointPair[0][0]; var dy = pointPair[1][1] - pointPair[0][1]; return Math.sqrt(dx * dx + dy * dy); } function center(pointPair) { return [ (pointPair[0][0] + pointPair[1][0]) / 2, (pointPair[0][1] + pointPair[1][1]) / 2 ]; } var recognizers = { pinch: function (track, event) { var trackLen = track.length; if (!trackLen) { return; } var pinchEnd = (track[trackLen - 1] || {}).points; var pinchPre = (track[trackLen - 2] || {}).points || pinchEnd; if (pinchPre && pinchPre.length > 1 && pinchEnd && pinchEnd.length > 1 ) { var pinchScale = dist(pinchEnd) / dist(pinchPre); !isFinite(pinchScale) && (pinchScale = 1); event.pinchScale = pinchScale; var pinchCenter = center(pinchEnd); event.pinchX = pinchCenter[0]; event.pinchY = pinchCenter[1]; return { type: 'pinch', target: track[0].target, event: event }; } } // Only pinch currently. }; module.exports = GestureMgr; /***/ }, /* 92 */ /***/ function(module, exports, __webpack_require__) { 'use strict'; /** * Default canvas painter * @module zrender/Painter * @author Kener (@Kener-林峰, kener.linfeng@gmail.com) * errorrik (errorrik@gmail.com) * pissang (https://www.github.com/pissang) */ var config = __webpack_require__(41); var util = __webpack_require__(4); var log = __webpack_require__(40); var BoundingRect = __webpack_require__(9); var timsort = __webpack_require__(86); var Layer = __webpack_require__(93); var requestAnimationFrame = __webpack_require__(89); // PENDIGN // Layer exceeds MAX_PROGRESSIVE_LAYER_NUMBER may have some problem when flush directly second time. // // Maximum progressive layer. When exceeding this number. All elements will be drawed in the last layer. var MAX_PROGRESSIVE_LAYER_NUMBER = 5; function parseInt10(val) { return parseInt(val, 10); } function isLayerValid(layer) { if (!layer) { return false; } if (layer.isBuildin) { return true; } if (typeof(layer.resize) !== 'function' || typeof(layer.refresh) !== 'function' ) { return false; } return true; } function preProcessLayer(layer) { layer.__unusedCount++; } function postProcessLayer(layer) { if (layer.__unusedCount == 1) { layer.clear(); } } var tmpRect = new BoundingRect(0, 0, 0, 0); var viewRect = new BoundingRect(0, 0, 0, 0); function isDisplayableCulled(el, width, height) { tmpRect.copy(el.getBoundingRect()); if (el.transform) { tmpRect.applyTransform(el.transform); } viewRect.width = width; viewRect.height = height; return !tmpRect.intersect(viewRect); } function isClipPathChanged(clipPaths, prevClipPaths) { if (clipPaths == prevClipPaths) { // Can both be null or undefined return false; } if (!clipPaths || !prevClipPaths || (clipPaths.length !== prevClipPaths.length)) { return true; } for (var i = 0; i < clipPaths.length; i++) { if (clipPaths[i] !== prevClipPaths[i]) { return true; } } } function doClip(clipPaths, ctx) { for (var i = 0; i < clipPaths.length; i++) { var clipPath = clipPaths[i]; var path = clipPath.path; clipPath.setTransform(ctx); path.beginPath(ctx); clipPath.buildPath(path, clipPath.shape); ctx.clip(); // Transform back clipPath.restoreTransform(ctx); } } function createRoot(width, height) { var domRoot = document.createElement('div'); // domRoot.onselectstart = returnFalse; // 避免页面选中的尴尬 domRoot.style.cssText = [ 'position:relative', 'overflow:hidden', 'width:' + width + 'px', 'height:' + height + 'px', 'padding:0', 'margin:0', 'border-width:0' ].join(';') + ';'; return domRoot; } /** * @alias module:zrender/Painter * @constructor * @param {HTMLElement} root 绘图容器 * @param {module:zrender/Storage} storage * @param {Ojbect} opts */ var Painter = function (root, storage, opts) { // In node environment using node-canvas var singleCanvas = !root.nodeName // In node ? || root.nodeName.toUpperCase() === 'CANVAS'; this._opts = opts = util.extend({}, opts || {}); /** * @type {number} */ this.dpr = opts.devicePixelRatio || config.devicePixelRatio; /** * @type {boolean} * @private */ this._singleCanvas = singleCanvas; /** * 绘图容器 * @type {HTMLElement} */ this.root = root; var rootStyle = root.style; if (rootStyle) { rootStyle['-webkit-tap-highlight-color'] = 'transparent'; rootStyle['-webkit-user-select'] = rootStyle['user-select'] = rootStyle['-webkit-touch-callout'] = 'none'; root.innerHTML = ''; } /** * @type {module:zrender/Storage} */ this.storage = storage; /** * @type {Array.} * @private */ var zlevelList = this._zlevelList = []; /** * @type {Object.} * @private */ var layers = this._layers = {}; /** * @type {Object.} * @type {private} */ this._layerConfig = {}; if (!singleCanvas) { this._width = this._getSize(0); this._height = this._getSize(1); var domRoot = this._domRoot = createRoot( this._width, this._height ); root.appendChild(domRoot); } else { // Use canvas width and height directly var width = root.width; var height = root.height; this._width = width; this._height = height; // Create layer if only one given canvas // Device pixel ratio is fixed to 1 because given canvas has its specified width and height var mainLayer = new Layer(root, this, 1); mainLayer.initContext(); // FIXME Use canvas width and height // mainLayer.resize(width, height); layers[0] = mainLayer; zlevelList.push(0); } this.pathToImage = this._createPathToImage(); // Layers for progressive rendering this._progressiveLayers = []; /** * @type {module:zrender/Layer} * @private */ this._hoverlayer; this._hoverElements = []; }; Painter.prototype = { constructor: Painter, /** * If painter use a single canvas * @return {boolean} */ isSingleCanvas: function () { return this._singleCanvas; }, /** * @return {HTMLDivElement} */ getViewportRoot: function () { return this._singleCanvas ? this._layers[0].dom : this._domRoot; }, /** * 刷新 * @param {boolean} [paintAll=false] 强制绘制所有displayable */ refresh: function (paintAll) { var list = this.storage.getDisplayList(true); var zlevelList = this._zlevelList; this._paintList(list, paintAll); // Paint custum layers for (var i = 0; i < zlevelList.length; i++) { var z = zlevelList[i]; var layer = this._layers[z]; if (!layer.isBuildin && layer.refresh) { layer.refresh(); } } this.refreshHover(); if (this._progressiveLayers.length) { this._startProgessive(); } return this; }, addHover: function (el, hoverStyle) { if (el.__hoverMir) { return; } var elMirror = new el.constructor({ style: el.style, shape: el.shape }); elMirror.__from = el; el.__hoverMir = elMirror; elMirror.setStyle(hoverStyle); this._hoverElements.push(elMirror); }, removeHover: function (el) { var elMirror = el.__hoverMir; var hoverElements = this._hoverElements; var idx = util.indexOf(hoverElements, elMirror); if (idx >= 0) { hoverElements.splice(idx, 1); } el.__hoverMir = null; }, clearHover: function (el) { var hoverElements = this._hoverElements; for (var i = 0; i < hoverElements.length; i++) { var from = hoverElements[i].__from; if (from) { from.__hoverMir = null; } } hoverElements.length = 0; }, refreshHover: function () { var hoverElements = this._hoverElements; var len = hoverElements.length; var hoverLayer = this._hoverlayer; hoverLayer && hoverLayer.clear(); if (!len) { return; } timsort(hoverElements, this.storage.displayableSortFunc); // Use a extream large zlevel // FIXME? if (!hoverLayer) { hoverLayer = this._hoverlayer = this.getLayer(1e5); } var scope = {}; hoverLayer.ctx.save(); for (var i = 0; i < len;) { var el = hoverElements[i]; var originalEl = el.__from; // Original el is removed // PENDING if (!(originalEl && originalEl.__zr)) { hoverElements.splice(i, 1); originalEl.__hoverMir = null; len--; continue; } i++; // Use transform // FIXME style and shape ? if (!originalEl.invisible) { el.transform = originalEl.transform; el.invTransform = originalEl.invTransform; el.__clipPaths = originalEl.__clipPaths; // el. this._doPaintEl(el, hoverLayer, true, scope); } } hoverLayer.ctx.restore(); }, _startProgessive: function () { var self = this; if (!self._furtherProgressive) { return; } // Use a token to stop progress steps triggered by // previous zr.refresh calling. var token = self._progressiveToken = +new Date(); self._progress++; requestAnimationFrame(step); function step() { // In case refreshed or disposed if (token === self._progressiveToken && self.storage) { self._doPaintList(self.storage.getDisplayList()); if (self._furtherProgressive) { self._progress++; requestAnimationFrame(step); } else { self._progressiveToken = -1; } } } }, _clearProgressive: function () { this._progressiveToken = -1; this._progress = 0; util.each(this._progressiveLayers, function (layer) { layer.__dirty && layer.clear(); }); }, _paintList: function (list, paintAll) { if (paintAll == null) { paintAll = false; } this._updateLayerStatus(list); this._clearProgressive(); this.eachBuildinLayer(preProcessLayer); this._doPaintList(list, paintAll); this.eachBuildinLayer(postProcessLayer); }, _doPaintList: function (list, paintAll) { var currentLayer; var currentZLevel; var ctx; // var invTransform = []; var scope; var progressiveLayerIdx = 0; var currentProgressiveLayer; var width = this._width; var height = this._height; var layerProgress; var frame = this._progress; function flushProgressiveLayer(layer) { var dpr = ctx.dpr || 1; ctx.save(); ctx.globalAlpha = 1; ctx.shadowBlur = 0; // Avoid layer don't clear in next progressive frame currentLayer.__dirty = true; ctx.setTransform(1, 0, 0, 1, 0, 0); ctx.drawImage(layer.dom, 0, 0, width * dpr, height * dpr); ctx.restore(); } for (var i = 0, l = list.length; i < l; i++) { var el = list[i]; var elZLevel = this._singleCanvas ? 0 : el.zlevel; var elFrame = el.__frame; // Flush at current context // PENDING if (elFrame < 0 && currentProgressiveLayer) { flushProgressiveLayer(currentProgressiveLayer); currentProgressiveLayer = null; } // Change draw layer if (currentZLevel !== elZLevel) { if (ctx) { ctx.restore(); } // Reset scope scope = {}; // Only 0 zlevel if only has one canvas currentZLevel = elZLevel; currentLayer = this.getLayer(currentZLevel); if (!currentLayer.isBuildin) { log( 'ZLevel ' + currentZLevel + ' has been used by unkown layer ' + currentLayer.id ); } ctx = currentLayer.ctx; ctx.save(); // Reset the count currentLayer.__unusedCount = 0; if (currentLayer.__dirty || paintAll) { currentLayer.clear(); } } if (!(currentLayer.__dirty || paintAll)) { continue; } if (elFrame >= 0) { // Progressive layer changed if (!currentProgressiveLayer) { currentProgressiveLayer = this._progressiveLayers[ Math.min(progressiveLayerIdx++, MAX_PROGRESSIVE_LAYER_NUMBER - 1) ]; currentProgressiveLayer.ctx.save(); currentProgressiveLayer.renderScope = {}; if (currentProgressiveLayer && (currentProgressiveLayer.__progress > currentProgressiveLayer.__maxProgress) ) { // flushProgressiveLayer(currentProgressiveLayer); // Quick jump all progressive elements // All progressive element are not dirty, jump over and flush directly i = currentProgressiveLayer.__nextIdxNotProg - 1; // currentProgressiveLayer = null; continue; } layerProgress = currentProgressiveLayer.__progress; if (!currentProgressiveLayer.__dirty) { // Keep rendering frame = layerProgress; } currentProgressiveLayer.__progress = frame + 1; } if (elFrame === frame) { this._doPaintEl(el, currentProgressiveLayer, true, currentProgressiveLayer.renderScope); } } else { this._doPaintEl(el, currentLayer, paintAll, scope); } el.__dirty = false; } if (currentProgressiveLayer) { flushProgressiveLayer(currentProgressiveLayer); } // Restore the lastLayer ctx ctx && ctx.restore(); // If still has clipping state // if (scope.prevElClipPaths) { // ctx.restore(); // } this._furtherProgressive = false; util.each(this._progressiveLayers, function (layer) { if (layer.__maxProgress >= layer.__progress) { this._furtherProgressive = true; } }, this); }, _doPaintEl: function (el, currentLayer, forcePaint, scope) { var ctx = currentLayer.ctx; var m = el.transform; if ( (currentLayer.__dirty || forcePaint) // Ignore invisible element && !el.invisible // Ignore transparent element && el.style.opacity !== 0 // Ignore scale 0 element, in some environment like node-canvas // Draw a scale 0 element can cause all following draw wrong // And setTransform with scale 0 will cause set back transform failed. && !(m && !m[0] && !m[3]) // Ignore culled element && !(el.culling && isDisplayableCulled(el, this._width, this._height)) ) { var clipPaths = el.__clipPaths; // Optimize when clipping on group with several elements if (scope.prevClipLayer !== currentLayer || isClipPathChanged(clipPaths, scope.prevElClipPaths) ) { // If has previous clipping state, restore from it if (scope.prevElClipPaths) { scope.prevClipLayer.ctx.restore(); scope.prevClipLayer = scope.prevElClipPaths = null; // Reset prevEl since context has been restored scope.prevEl = null; } // New clipping state if (clipPaths) { ctx.save(); doClip(clipPaths, ctx); scope.prevClipLayer = currentLayer; scope.prevElClipPaths = clipPaths; } } el.beforeBrush && el.beforeBrush(ctx); el.brush(ctx, scope.prevEl || null); scope.prevEl = el; el.afterBrush && el.afterBrush(ctx); } }, /** * 获取 zlevel 所在层,如果不存在则会创建一个新的层 * @param {number} zlevel * @return {module:zrender/Layer} */ getLayer: function (zlevel) { if (this._singleCanvas) { return this._layers[0]; } var layer = this._layers[zlevel]; if (!layer) { // Create a new layer layer = new Layer('zr_' + zlevel, this, this.dpr); layer.isBuildin = true; if (this._layerConfig[zlevel]) { util.merge(layer, this._layerConfig[zlevel], true); } this.insertLayer(zlevel, layer); // Context is created after dom inserted to document // Or excanvas will get 0px clientWidth and clientHeight layer.initContext(); } return layer; }, insertLayer: function (zlevel, layer) { var layersMap = this._layers; var zlevelList = this._zlevelList; var len = zlevelList.length; var prevLayer = null; var i = -1; var domRoot = this._domRoot; if (layersMap[zlevel]) { log('ZLevel ' + zlevel + ' has been used already'); return; } // Check if is a valid layer if (!isLayerValid(layer)) { log('Layer of zlevel ' + zlevel + ' is not valid'); return; } if (len > 0 && zlevel > zlevelList[0]) { for (i = 0; i < len - 1; i++) { if ( zlevelList[i] < zlevel && zlevelList[i + 1] > zlevel ) { break; } } prevLayer = layersMap[zlevelList[i]]; } zlevelList.splice(i + 1, 0, zlevel); if (prevLayer) { var prevDom = prevLayer.dom; if (prevDom.nextSibling) { domRoot.insertBefore( layer.dom, prevDom.nextSibling ); } else { domRoot.appendChild(layer.dom); } } else { if (domRoot.firstChild) { domRoot.insertBefore(layer.dom, domRoot.firstChild); } else { domRoot.appendChild(layer.dom); } } layersMap[zlevel] = layer; }, // Iterate each layer eachLayer: function (cb, context) { var zlevelList = this._zlevelList; var z; var i; for (i = 0; i < zlevelList.length; i++) { z = zlevelList[i]; cb.call(context, this._layers[z], z); } }, // Iterate each buildin layer eachBuildinLayer: function (cb, context) { var zlevelList = this._zlevelList; var layer; var z; var i; for (i = 0; i < zlevelList.length; i++) { z = zlevelList[i]; layer = this._layers[z]; if (layer.isBuildin) { cb.call(context, layer, z); } } }, // Iterate each other layer except buildin layer eachOtherLayer: function (cb, context) { var zlevelList = this._zlevelList; var layer; var z; var i; for (i = 0; i < zlevelList.length; i++) { z = zlevelList[i]; layer = this._layers[z]; if (! layer.isBuildin) { cb.call(context, layer, z); } } }, /** * 获取所有已创建的层 * @param {Array.} [prevLayer] */ getLayers: function () { return this._layers; }, _updateLayerStatus: function (list) { var layers = this._layers; var progressiveLayers = this._progressiveLayers; var elCountsLastFrame = {}; var progressiveElCountsLastFrame = {}; this.eachBuildinLayer(function (layer, z) { elCountsLastFrame[z] = layer.elCount; layer.elCount = 0; layer.__dirty = false; }); util.each(progressiveLayers, function (layer, idx) { progressiveElCountsLastFrame[idx] = layer.elCount; layer.elCount = 0; layer.__dirty = false; }); var progressiveLayerCount = 0; var currentProgressiveLayer; var lastProgressiveKey; var frameCount = 0; for (var i = 0, l = list.length; i < l; i++) { var el = list[i]; var zlevel = this._singleCanvas ? 0 : el.zlevel; var layer = layers[zlevel]; var elProgress = el.progressive; if (layer) { layer.elCount++; layer.__dirty = layer.__dirty || el.__dirty; } /////// Update progressive if (elProgress >= 0) { // Fix wrong progressive sequence problem. if (lastProgressiveKey !== elProgress) { lastProgressiveKey = elProgress; frameCount++; } var elFrame = el.__frame = frameCount - 1; if (!currentProgressiveLayer) { var idx = Math.min(progressiveLayerCount, MAX_PROGRESSIVE_LAYER_NUMBER - 1); currentProgressiveLayer = progressiveLayers[idx]; if (!currentProgressiveLayer) { currentProgressiveLayer = progressiveLayers[idx] = new Layer( 'progressive', this, this.dpr ); currentProgressiveLayer.initContext(); } currentProgressiveLayer.__maxProgress = 0; } currentProgressiveLayer.__dirty = currentProgressiveLayer.__dirty || el.__dirty; currentProgressiveLayer.elCount++; currentProgressiveLayer.__maxProgress = Math.max( currentProgressiveLayer.__maxProgress, elFrame ); if (currentProgressiveLayer.__maxProgress >= currentProgressiveLayer.__progress) { // Should keep rendering this layer because progressive rendering is not finished yet layer.__dirty = true; } } else { el.__frame = -1; if (currentProgressiveLayer) { currentProgressiveLayer.__nextIdxNotProg = i; progressiveLayerCount++; currentProgressiveLayer = null; } } } if (currentProgressiveLayer) { progressiveLayerCount++; currentProgressiveLayer.__nextIdxNotProg = i; } // 层中的元素数量有发生变化 this.eachBuildinLayer(function (layer, z) { if (elCountsLastFrame[z] !== layer.elCount) { layer.__dirty = true; } }); progressiveLayers.length = Math.min(progressiveLayerCount, MAX_PROGRESSIVE_LAYER_NUMBER); util.each(progressiveLayers, function (layer, idx) { if (progressiveElCountsLastFrame[idx] !== layer.elCount) { el.__dirty = true; } if (layer.__dirty) { layer.__progress = 0; } }); }, /** * 清除hover层外所有内容 */ clear: function () { this.eachBuildinLayer(this._clearLayer); return this; }, _clearLayer: function (layer) { layer.clear(); }, /** * 修改指定zlevel的绘制参数 * * @param {string} zlevel * @param {Object} config 配置对象 * @param {string} [config.clearColor=0] 每次清空画布的颜色 * @param {string} [config.motionBlur=false] 是否开启动态模糊 * @param {number} [config.lastFrameAlpha=0.7] * 在开启动态模糊的时候使用,与上一帧混合的alpha值,值越大尾迹越明显 */ configLayer: function (zlevel, config) { if (config) { var layerConfig = this._layerConfig; if (!layerConfig[zlevel]) { layerConfig[zlevel] = config; } else { util.merge(layerConfig[zlevel], config, true); } var layer = this._layers[zlevel]; if (layer) { util.merge(layer, layerConfig[zlevel], true); } } }, /** * 删除指定层 * @param {number} zlevel 层所在的zlevel */ delLayer: function (zlevel) { var layers = this._layers; var zlevelList = this._zlevelList; var layer = layers[zlevel]; if (!layer) { return; } layer.dom.parentNode.removeChild(layer.dom); delete layers[zlevel]; zlevelList.splice(util.indexOf(zlevelList, zlevel), 1); }, /** * 区域大小变化后重绘 */ resize: function (width, height) { var domRoot = this._domRoot; // FIXME Why ? domRoot.style.display = 'none'; // Save input w/h var opts = this._opts; width != null && (opts.width = width); height != null && (opts.height = height); width = this._getSize(0); height = this._getSize(1); domRoot.style.display = ''; // 优化没有实际改变的resize if (this._width != width || height != this._height) { domRoot.style.width = width + 'px'; domRoot.style.height = height + 'px'; for (var id in this._layers) { if (this._layers.hasOwnProperty(id)) { this._layers[id].resize(width, height); } } util.each(this._progressiveLayers, function (layer) { layer.resize(width, height); }); this.refresh(true); } this._width = width; this._height = height; return this; }, /** * 清除单独的一个层 * @param {number} zlevel */ clearLayer: function (zlevel) { var layer = this._layers[zlevel]; if (layer) { layer.clear(); } }, /** * 释放 */ dispose: function () { this.root.innerHTML = ''; this.root = this.storage = this._domRoot = this._layers = null; }, /** * Get canvas which has all thing rendered * @param {Object} opts * @param {string} [opts.backgroundColor] */ getRenderedCanvas: function (opts) { opts = opts || {}; if (this._singleCanvas) { return this._layers[0].dom; } var imageLayer = new Layer('image', this, opts.pixelRatio || this.dpr); imageLayer.initContext(); imageLayer.clearColor = opts.backgroundColor; imageLayer.clear(); var displayList = this.storage.getDisplayList(true); var scope = {}; for (var i = 0; i < displayList.length; i++) { var el = displayList[i]; this._doPaintEl(el, imageLayer, true, scope); } return imageLayer.dom; }, /** * 获取绘图区域宽度 */ getWidth: function () { return this._width; }, /** * 获取绘图区域高度 */ getHeight: function () { return this._height; }, _getSize: function (whIdx) { var opts = this._opts; var wh = ['width', 'height'][whIdx]; var cwh = ['clientWidth', 'clientHeight'][whIdx]; var plt = ['paddingLeft', 'paddingTop'][whIdx]; var prb = ['paddingRight', 'paddingBottom'][whIdx]; if (opts[wh] != null && opts[wh] !== 'auto') { return parseFloat(opts[wh]); } var root = this.root; var stl = document.defaultView.getComputedStyle(root); return ( (root[cwh] || parseInt10(stl[wh]) || parseInt10(root.style[wh])) - (parseInt10(stl[plt]) || 0) - (parseInt10(stl[prb]) || 0) ) | 0; }, _pathToImage: function (id, path, width, height, dpr) { var canvas = document.createElement('canvas'); var ctx = canvas.getContext('2d'); canvas.width = width * dpr; canvas.height = height * dpr; ctx.clearRect(0, 0, width * dpr, height * dpr); var pathTransform = { position: path.position, rotation: path.rotation, scale: path.scale }; path.position = [0, 0, 0]; path.rotation = 0; path.scale = [1, 1]; if (path) { path.brush(ctx); } var ImageShape = __webpack_require__(61); var imgShape = new ImageShape({ id: id, style: { x: 0, y: 0, image: canvas } }); if (pathTransform.position != null) { imgShape.position = path.position = pathTransform.position; } if (pathTransform.rotation != null) { imgShape.rotation = path.rotation = pathTransform.rotation; } if (pathTransform.scale != null) { imgShape.scale = path.scale = pathTransform.scale; } return imgShape; }, _createPathToImage: function () { var me = this; return function (id, e, width, height) { return me._pathToImage( id, e, width, height, me.dpr ); }; } }; module.exports = Painter; /***/ }, /* 93 */ /***/ function(module, exports, __webpack_require__) { /** * @module zrender/Layer * @author pissang(https://www.github.com/pissang) */ var util = __webpack_require__(4); var config = __webpack_require__(41); var Style = __webpack_require__(47); var Pattern = __webpack_require__(59); function returnFalse() { return false; } /** * 创建dom * * @inner * @param {string} id dom id 待用 * @param {string} type dom type,such as canvas, div etc. * @param {Painter} painter painter instance * @param {number} number */ function createDom(id, type, painter, dpr) { var newDom = document.createElement(type); var width = painter.getWidth(); var height = painter.getHeight(); var newDomStyle = newDom.style; // 没append呢,请原谅我这样写,清晰~ newDomStyle.position = 'absolute'; newDomStyle.left = 0; newDomStyle.top = 0; newDomStyle.width = width + 'px'; newDomStyle.height = height + 'px'; newDom.width = width * dpr; newDom.height = height * dpr; // id不作为索引用,避免可能造成的重名,定义为私有属性 newDom.setAttribute('data-zr-dom-id', id); return newDom; } /** * @alias module:zrender/Layer * @constructor * @extends module:zrender/mixin/Transformable * @param {string} id * @param {module:zrender/Painter} painter * @param {number} [dpr] */ var Layer = function(id, painter, dpr) { var dom; dpr = dpr || config.devicePixelRatio; if (typeof id === 'string') { dom = createDom(id, 'canvas', painter, dpr); } // Not using isDom because in node it will return false else if (util.isObject(id)) { dom = id; id = dom.id; } this.id = id; this.dom = dom; var domStyle = dom.style; if (domStyle) { // Not in node dom.onselectstart = returnFalse; // 避免页面选中的尴尬 domStyle['-webkit-user-select'] = 'none'; domStyle['user-select'] = 'none'; domStyle['-webkit-touch-callout'] = 'none'; domStyle['-webkit-tap-highlight-color'] = 'rgba(0,0,0,0)'; domStyle['padding'] = 0; domStyle['margin'] = 0; domStyle['border-width'] = 0; } this.domBack = null; this.ctxBack = null; this.painter = painter; this.config = null; // Configs /** * 每次清空画布的颜色 * @type {string} * @default 0 */ this.clearColor = 0; /** * 是否开启动态模糊 * @type {boolean} * @default false */ this.motionBlur = false; /** * 在开启动态模糊的时候使用,与上一帧混合的alpha值,值越大尾迹越明显 * @type {number} * @default 0.7 */ this.lastFrameAlpha = 0.7; /** * Layer dpr * @type {number} */ this.dpr = dpr; }; Layer.prototype = { constructor: Layer, elCount: 0, __dirty: true, initContext: function () { this.ctx = this.dom.getContext('2d'); this.ctx.dpr = this.dpr; }, createBackBuffer: function () { var dpr = this.dpr; this.domBack = createDom('back-' + this.id, 'canvas', this.painter, dpr); this.ctxBack = this.domBack.getContext('2d'); if (dpr != 1) { this.ctxBack.scale(dpr, dpr); } }, /** * @param {number} width * @param {number} height */ resize: function (width, height) { var dpr = this.dpr; var dom = this.dom; var domStyle = dom.style; var domBack = this.domBack; domStyle.width = width + 'px'; domStyle.height = height + 'px'; dom.width = width * dpr; dom.height = height * dpr; if (domBack) { domBack.width = width * dpr; domBack.height = height * dpr; if (dpr != 1) { this.ctxBack.scale(dpr, dpr); } } }, /** * 清空该层画布 * @param {boolean} clearAll Clear all with out motion blur */ clear: function (clearAll) { var dom = this.dom; var ctx = this.ctx; var width = dom.width; var height = dom.height; var clearColor = this.clearColor; var haveMotionBLur = this.motionBlur && !clearAll; var lastFrameAlpha = this.lastFrameAlpha; var dpr = this.dpr; if (haveMotionBLur) { if (!this.domBack) { this.createBackBuffer(); } this.ctxBack.globalCompositeOperation = 'copy'; this.ctxBack.drawImage( dom, 0, 0, width / dpr, height / dpr ); } ctx.clearRect(0, 0, width, height); if (clearColor) { var clearColorGradientOrPattern; // Gradient if (clearColor.colorStops) { // Cache canvas gradient clearColorGradientOrPattern = clearColor.__canvasGradient || Style.getGradient(ctx, clearColor, { x: 0, y: 0, width: width, height: height }); clearColor.__canvasGradient = clearColorGradientOrPattern; } // Pattern else if (clearColor.image) { clearColorGradientOrPattern = Pattern.prototype.getCanvasPattern.call(clearColor, ctx); } ctx.save(); ctx.fillStyle = clearColorGradientOrPattern || clearColor; ctx.fillRect(0, 0, width, height); ctx.restore(); } if (haveMotionBLur) { var domBack = this.domBack; ctx.save(); ctx.globalAlpha = lastFrameAlpha; ctx.drawImage(domBack, 0, 0, width, height); ctx.restore(); } } }; module.exports = Layer; /***/ }, /* 94 */ /***/ function(module, exports, __webpack_require__) { var Gradient = __webpack_require__(79); module.exports = function (ecModel) { function encodeColor(seriesModel) { var colorAccessPath = (seriesModel.visualColorAccessPath || 'itemStyle.normal.color').split('.'); var data = seriesModel.getData(); var color = seriesModel.get(colorAccessPath) // Set in itemStyle || seriesModel.getColorFromPalette(seriesModel.get('name')); // Default color // FIXME Set color function or use the platte color data.setVisual('color', color); // Only visible series has each data be visual encoded if (!ecModel.isSeriesFiltered(seriesModel)) { if (typeof color === 'function' && !(color instanceof Gradient)) { data.each(function (idx) { data.setItemVisual( idx, 'color', color(seriesModel.getDataParams(idx)) ); }); } // itemStyle in each data item data.each(function (idx) { var itemModel = data.getItemModel(idx); var color = itemModel.get(colorAccessPath, true); if (color != null) { data.setItemVisual(idx, 'color', color); } }); } } ecModel.eachRawSeries(encodeColor); }; /***/ }, /* 95 */ /***/ function(module, exports, __webpack_require__) { // Compatitable with 2.0 var zrUtil = __webpack_require__(4); var compatStyle = __webpack_require__(96); function get(opt, path) { path = path.split(','); var obj = opt; for (var i = 0; i < path.length; i++) { obj = obj && obj[path[i]]; if (obj == null) { break; } } return obj; } function set(opt, path, val, overwrite) { path = path.split(','); var obj = opt; var key; for (var i = 0; i < path.length - 1; i++) { key = path[i]; if (obj[key] == null) { obj[key] = {}; } obj = obj[key]; } if (overwrite || obj[path[i]] == null) { obj[path[i]] = val; } } function compatLayoutProperties(option) { each(LAYOUT_PROPERTIES, function (prop) { if (prop[0] in option && !(prop[1] in option)) { option[prop[1]] = option[prop[0]]; } }); } var LAYOUT_PROPERTIES = [ ['x', 'left'], ['y', 'top'], ['x2', 'right'], ['y2', 'bottom'] ]; var COMPATITABLE_COMPONENTS = [ 'grid', 'geo', 'parallel', 'legend', 'toolbox', 'title', 'visualMap', 'dataZoom', 'timeline' ]; var COMPATITABLE_SERIES = [ 'bar', 'boxplot', 'candlestick', 'chord', 'effectScatter', 'funnel', 'gauge', 'lines', 'graph', 'heatmap', 'line', 'map', 'parallel', 'pie', 'radar', 'sankey', 'scatter', 'treemap' ]; var each = zrUtil.each; module.exports = function (option) { each(option.series, function (seriesOpt) { if (!zrUtil.isObject(seriesOpt)) { return; } var seriesType = seriesOpt.type; compatStyle(seriesOpt); if (seriesType === 'pie' || seriesType === 'gauge') { if (seriesOpt.clockWise != null) { seriesOpt.clockwise = seriesOpt.clockWise; } } if (seriesType === 'gauge') { var pointerColor = get(seriesOpt, 'pointer.color'); pointerColor != null && set(seriesOpt, 'itemStyle.normal.color', pointerColor); } for (var i = 0; i < COMPATITABLE_SERIES.length; i++) { if (COMPATITABLE_SERIES[i] === seriesOpt.type) { compatLayoutProperties(seriesOpt); break; } } }); // dataRange has changed to visualMap if (option.dataRange) { option.visualMap = option.dataRange; } each(COMPATITABLE_COMPONENTS, function (componentName) { var options = option[componentName]; if (options) { if (!zrUtil.isArray(options)) { options = [options]; } each(options, function (option) { compatLayoutProperties(option); }); } }); }; /***/ }, /* 96 */ /***/ function(module, exports, __webpack_require__) { var zrUtil = __webpack_require__(4); var POSSIBLE_STYLES = [ 'areaStyle', 'lineStyle', 'nodeStyle', 'linkStyle', 'chordStyle', 'label', 'labelLine' ]; function compatItemStyle(opt) { var itemStyleOpt = opt && opt.itemStyle; if (itemStyleOpt) { zrUtil.each(POSSIBLE_STYLES, function (styleName) { var normalItemStyleOpt = itemStyleOpt.normal; var emphasisItemStyleOpt = itemStyleOpt.emphasis; if (normalItemStyleOpt && normalItemStyleOpt[styleName]) { opt[styleName] = opt[styleName] || {}; if (!opt[styleName].normal) { opt[styleName].normal = normalItemStyleOpt[styleName]; } else { zrUtil.merge(opt[styleName].normal, normalItemStyleOpt[styleName]); } normalItemStyleOpt[styleName] = null; } if (emphasisItemStyleOpt && emphasisItemStyleOpt[styleName]) { opt[styleName] = opt[styleName] || {}; if (!opt[styleName].emphasis) { opt[styleName].emphasis = emphasisItemStyleOpt[styleName]; } else { zrUtil.merge(opt[styleName].emphasis, emphasisItemStyleOpt[styleName]); } emphasisItemStyleOpt[styleName] = null; } }); } } module.exports = function (seriesOpt) { if (!seriesOpt) { return; } compatItemStyle(seriesOpt); compatItemStyle(seriesOpt.markPoint); compatItemStyle(seriesOpt.markLine); var data = seriesOpt.data; if (data) { for (var i = 0; i < data.length; i++) { compatItemStyle(data[i]); } // mark point data var markPoint = seriesOpt.markPoint; if (markPoint && markPoint.data) { var mpData = markPoint.data; for (var i = 0; i < mpData.length; i++) { compatItemStyle(mpData[i]); } } // mark line data var markLine = seriesOpt.markLine; if (markLine && markLine.data) { var mlData = markLine.data; for (var i = 0; i < mlData.length; i++) { if (zrUtil.isArray(mlData[i])) { compatItemStyle(mlData[i][0]); compatItemStyle(mlData[i][1]); } else { compatItemStyle(mlData[i]); } } } } }; /***/ }, /* 97 */ /***/ function(module, exports, __webpack_require__) { var graphic = __webpack_require__(43); var zrUtil = __webpack_require__(4); var PI = Math.PI; /** * @param {module:echarts/ExtensionAPI} api * @param {Object} [opts] * @param {string} [opts.text] * @param {string} [opts.color] * @param {string} [opts.textColor] * @return {module:zrender/Element} */ module.exports = function (api, opts) { opts = opts || {}; zrUtil.defaults(opts, { text: 'loading', color: '#c23531', textColor: '#000', maskColor: 'rgba(255, 255, 255, 0.8)', zlevel: 0 }); var mask = new graphic.Rect({ style: { fill: opts.maskColor }, zlevel: opts.zlevel, z: 10000 }); var arc = new graphic.Arc({ shape: { startAngle: -PI / 2, endAngle: -PI / 2 + 0.1, r: 10 }, style: { stroke: opts.color, lineCap: 'round', lineWidth: 5 }, zlevel: opts.zlevel, z: 10001 }); var labelRect = new graphic.Rect({ style: { fill: 'none', text: opts.text, textPosition: 'right', textDistance: 10, textFill: opts.textColor }, zlevel: opts.zlevel, z: 10001 }); arc.animateShape(true) .when(1000, { endAngle: PI * 3 / 2 }) .start('circularInOut'); arc.animateShape(true) .when(1000, { startAngle: PI * 3 / 2 }) .delay(300) .start('circularInOut'); var group = new graphic.Group(); group.add(arc); group.add(labelRect); group.add(mask); // Inject resize group.resize = function () { var cx = api.getWidth() / 2; var cy = api.getHeight() / 2; arc.setShape({ cx: cx, cy: cy }); var r = arc.shape.r; labelRect.setShape({ x: cx - r, y: cy - r, width: r * 2, height: r * 2 }); mask.setShape({ x: 0, y: 0, width: api.getWidth(), height: api.getHeight() }); }; group.resize(); return group; }; /***/ }, /* 98 */ /***/ function(module, exports, __webpack_require__) { /* WEBPACK VAR INJECTION */(function(global) {/** * List for data storage * @module echarts/data/List */ var UNDEFINED = 'undefined'; var globalObj = typeof window === 'undefined' ? global : window; var Float64Array = typeof globalObj.Float64Array === UNDEFINED ? Array : globalObj.Float64Array; var Int32Array = typeof globalObj.Int32Array === UNDEFINED ? Array : globalObj.Int32Array; var dataCtors = { 'float': Float64Array, 'int': Int32Array, // Ordinal data type can be string or int 'ordinal': Array, 'number': Array, 'time': Array }; var Model = __webpack_require__(12); var DataDiffer = __webpack_require__(99); var zrUtil = __webpack_require__(4); var modelUtil = __webpack_require__(5); var isObject = zrUtil.isObject; var TRANSFERABLE_PROPERTIES = [ 'stackedOn', 'hasItemOption', '_nameList', '_idList', '_rawData' ]; var transferProperties = function (a, b) { zrUtil.each(TRANSFERABLE_PROPERTIES.concat(b.__wrappedMethods || []), function (propName) { if (b.hasOwnProperty(propName)) { a[propName] = b[propName]; } }); a.__wrappedMethods = b.__wrappedMethods; }; /** * @constructor * @alias module:echarts/data/List * * @param {Array.} dimensions * Dimensions should be concrete names like x, y, z, lng, lat, angle, radius * @param {module:echarts/model/Model} hostModel */ var List = function (dimensions, hostModel) { dimensions = dimensions || ['x', 'y']; var dimensionInfos = {}; var dimensionNames = []; for (var i = 0; i < dimensions.length; i++) { var dimensionName; var dimensionInfo = {}; if (typeof dimensions[i] === 'string') { dimensionName = dimensions[i]; dimensionInfo = { name: dimensionName, stackable: false, // Type can be 'float', 'int', 'number' // Default is number, Precision of float may not enough type: 'number' }; } else { dimensionInfo = dimensions[i]; dimensionName = dimensionInfo.name; dimensionInfo.type = dimensionInfo.type || 'number'; } dimensionNames.push(dimensionName); dimensionInfos[dimensionName] = dimensionInfo; } /** * @readOnly * @type {Array.} */ this.dimensions = dimensionNames; /** * Infomation of each data dimension, like data type. * @type {Object} */ this._dimensionInfos = dimensionInfos; /** * @type {module:echarts/model/Model} */ this.hostModel = hostModel; /** * @type {module:echarts/model/Model} */ this.dataType; /** * Indices stores the indices of data subset after filtered. * This data subset will be used in chart. * @type {Array.} * @readOnly */ this.indices = []; /** * Data storage * @type {Object.} * @private */ this._storage = {}; /** * @type {Array.} */ this._nameList = []; /** * @type {Array.} */ this._idList = []; /** * Models of data option is stored sparse for optimizing memory cost * @type {Array.} * @private */ this._optionModels = []; /** * @param {module:echarts/data/List} */ this.stackedOn = null; /** * Global visual properties after visual coding * @type {Object} * @private */ this._visual = {}; /** * Globel layout properties. * @type {Object} * @private */ this._layout = {}; /** * Item visual properties after visual coding * @type {Array.} * @private */ this._itemVisuals = []; /** * Item layout properties after layout * @type {Array.} * @private */ this._itemLayouts = []; /** * Graphic elemnents * @type {Array.} * @private */ this._graphicEls = []; /** * @type {Array.} * @private */ this._rawData; /** * @type {Object} * @private */ this._extent; }; var listProto = List.prototype; listProto.type = 'list'; /** * If each data item has it's own option * @type {boolean} */ listProto.hasItemOption = true; /** * Get dimension name * @param {string|number} dim * Dimension can be concrete names like x, y, z, lng, lat, angle, radius * Or a ordinal number. For example getDimensionInfo(0) will return 'x' or 'lng' or 'radius' * @return {string} Concrete dim name. */ listProto.getDimension = function (dim) { if (!isNaN(dim)) { dim = this.dimensions[dim] || dim; } return dim; }; /** * Get type and stackable info of particular dimension * @param {string|number} dim * Dimension can be concrete names like x, y, z, lng, lat, angle, radius * Or a ordinal number. For example getDimensionInfo(0) will return 'x' or 'lng' or 'radius' */ listProto.getDimensionInfo = function (dim) { return zrUtil.clone(this._dimensionInfos[this.getDimension(dim)]); }; /** * Initialize from data * @param {Array.} data * @param {Array.} [nameList] * @param {Function} [dimValueGetter] (dataItem, dimName, dataIndex, dimIndex) => number */ listProto.initData = function (data, nameList, dimValueGetter) { data = data || []; if (true) { if (!zrUtil.isArray(data)) { throw new Error('Invalid data.'); } } this._rawData = data; // Clear var storage = this._storage = {}; var indices = this.indices = []; var dimensions = this.dimensions; var size = data.length; var dimensionInfoMap = this._dimensionInfos; var idList = []; var nameRepeatCount = {}; nameList = nameList || []; // Init storage for (var i = 0; i < dimensions.length; i++) { var dimInfo = dimensionInfoMap[dimensions[i]]; var DataCtor = dataCtors[dimInfo.type]; storage[dimensions[i]] = new DataCtor(size); } var self = this; if (!dimValueGetter) { self.hasItemOption = false; } // Default dim value getter dimValueGetter = dimValueGetter || function (dataItem, dimName, dataIndex, dimIndex) { var value = modelUtil.getDataItemValue(dataItem); // If any dataItem is like { value: 10 } if (modelUtil.isDataItemOption(dataItem)) { self.hasItemOption = true; } return modelUtil.converDataValue( (value instanceof Array) ? value[dimIndex] // If value is a single number or something else not array. : value, dimensionInfoMap[dimName] ); }; for (var idx = 0; idx < data.length; idx++) { var dataItem = data[idx]; // Each data item is value // [1, 2] // 2 // Bar chart, line chart which uses category axis // only gives the 'y' value. 'x' value is the indices of cateogry // Use a tempValue to normalize the value to be a (x, y) value // Store the data by dimensions for (var k = 0; k < dimensions.length; k++) { var dim = dimensions[k]; var dimStorage = storage[dim]; // PENDING NULL is empty or zero dimStorage[idx] = dimValueGetter(dataItem, dim, idx, k); } indices.push(idx); } // Use the name in option and create id for (var i = 0; i < data.length; i++) { if (!nameList[i]) { if (data[i] && data[i].name != null) { nameList[i] = data[i].name; } } var name = nameList[i] || ''; // Try using the id in option var id = data[i] && data[i].id; if (!id && name) { // Use name as id and add counter to avoid same name nameRepeatCount[name] = nameRepeatCount[name] || 0; id = name; if (nameRepeatCount[name] > 0) { id += '__ec__' + nameRepeatCount[name]; } nameRepeatCount[name]++; } id && (idList[i] = id); } this._nameList = nameList; this._idList = idList; }; /** * @return {number} */ listProto.count = function () { return this.indices.length; }; /** * Get value. Return NaN if idx is out of range. * @param {string} dim Dim must be concrete name. * @param {number} idx * @param {boolean} stack * @return {number} */ listProto.get = function (dim, idx, stack) { var storage = this._storage; var dataIndex = this.indices[idx]; // If value not exists if (dataIndex == null) { return NaN; } var value = storage[dim] && storage[dim][dataIndex]; // FIXME ordinal data type is not stackable if (stack) { var dimensionInfo = this._dimensionInfos[dim]; if (dimensionInfo && dimensionInfo.stackable) { var stackedOn = this.stackedOn; while (stackedOn) { // Get no stacked data of stacked on var stackedValue = stackedOn.get(dim, idx); // Considering positive stack, negative stack and empty data if ((value >= 0 && stackedValue > 0) // Positive stack || (value <= 0 && stackedValue < 0) // Negative stack ) { value += stackedValue; } stackedOn = stackedOn.stackedOn; } } } return value; }; /** * Get value for multi dimensions. * @param {Array.} [dimensions] If ignored, using all dimensions. * @param {number} idx * @param {boolean} stack * @return {number} */ listProto.getValues = function (dimensions, idx, stack) { var values = []; if (!zrUtil.isArray(dimensions)) { stack = idx; idx = dimensions; dimensions = this.dimensions; } for (var i = 0, len = dimensions.length; i < len; i++) { values.push(this.get(dimensions[i], idx, stack)); } return values; }; /** * If value is NaN. Inlcuding '-' * @param {string} dim * @param {number} idx * @return {number} */ listProto.hasValue = function (idx) { var dimensions = this.dimensions; var dimensionInfos = this._dimensionInfos; for (var i = 0, len = dimensions.length; i < len; i++) { if ( // Ordinal type can be string or number dimensionInfos[dimensions[i]].type !== 'ordinal' && isNaN(this.get(dimensions[i], idx)) ) { return false; } } return true; }; /** * Get extent of data in one dimension * @param {string} dim * @param {boolean} stack */ listProto.getDataExtent = function (dim, stack) { dim = this.getDimension(dim); var dimData = this._storage[dim]; var dimInfo = this.getDimensionInfo(dim); stack = (dimInfo && dimInfo.stackable) && stack; var dimExtent = (this._extent || (this._extent = {}))[dim + (!!stack)]; var value; if (dimExtent) { return dimExtent; } // var dimInfo = this._dimensionInfos[dim]; if (dimData) { var min = Infinity; var max = -Infinity; // var isOrdinal = dimInfo.type === 'ordinal'; for (var i = 0, len = this.count(); i < len; i++) { value = this.get(dim, i, stack); // FIXME // if (isOrdinal && typeof value === 'string') { // value = zrUtil.indexOf(dimData, value); // } value < min && (min = value); value > max && (max = value); } return (this._extent[dim + !!stack] = [min, max]); } else { return [Infinity, -Infinity]; } }; /** * Get sum of data in one dimension * @param {string} dim * @param {boolean} stack */ listProto.getSum = function (dim, stack) { var dimData = this._storage[dim]; var sum = 0; if (dimData) { for (var i = 0, len = this.count(); i < len; i++) { var value = this.get(dim, i, stack); if (!isNaN(value)) { sum += value; } } } return sum; }; /** * Retreive the index with given value * @param {number} idx * @param {number} value * @return {number} */ // FIXME Precision of float value listProto.indexOf = function (dim, value) { var storage = this._storage; var dimData = storage[dim]; var indices = this.indices; if (dimData) { for (var i = 0, len = indices.length; i < len; i++) { var rawIndex = indices[i]; if (dimData[rawIndex] === value) { return i; } } } return -1; }; /** * Retreive the index with given name * @param {number} idx * @param {number} name * @return {number} */ listProto.indexOfName = function (name) { var indices = this.indices; var nameList = this._nameList; for (var i = 0, len = indices.length; i < len; i++) { var rawIndex = indices[i]; if (nameList[rawIndex] === name) { return i; } } return -1; }; /** * Retreive the index with given raw data index * @param {number} idx * @param {number} name * @return {number} */ listProto.indexOfRawIndex = function (rawIndex) { // Indices are ascending var indices = this.indices; // If rawIndex === dataIndex var rawDataIndex = indices[rawIndex]; if (rawDataIndex != null && rawDataIndex === rawIndex) { return rawIndex; } var left = 0; var right = indices.length - 1; while (left <= right) { var mid = (left + right) / 2 | 0; if (indices[mid] < rawIndex) { left = mid + 1; } else if (indices[mid] > rawIndex) { right = mid - 1; } else { return mid; } } return -1; }; /** * Retreive the index of nearest value * @param {string} dim * @param {number} value * @param {boolean} stack If given value is after stacked * @param {number} [maxDistance=Infinity] * @return {number} */ listProto.indexOfNearest = function (dim, value, stack, maxDistance) { var storage = this._storage; var dimData = storage[dim]; if (maxDistance == null) { maxDistance = Infinity; } var nearestIdx = -1; if (dimData) { var minDist = Number.MAX_VALUE; for (var i = 0, len = this.count(); i < len; i++) { var diff = value - this.get(dim, i, stack); var dist = Math.abs(diff); if ( diff <= maxDistance && (dist < minDist // For the case of two data are same on xAxis, which has sequence data. // Show the nearest index // https://github.com/ecomfe/echarts/issues/2869 || (dist === minDist && diff > 0) ) ) { minDist = dist; nearestIdx = i; } } } return nearestIdx; }; /** * Get raw data index * @param {number} idx * @return {number} */ listProto.getRawIndex = function (idx) { var rawIdx = this.indices[idx]; return rawIdx == null ? -1 : rawIdx; }; /** * Get raw data item * @param {number} idx * @return {number} */ listProto.getRawDataItem = function (idx) { return this._rawData[this.getRawIndex(idx)]; }; /** * @param {number} idx * @param {boolean} [notDefaultIdx=false] * @return {string} */ listProto.getName = function (idx) { return this._nameList[this.indices[idx]] || ''; }; /** * @param {number} idx * @param {boolean} [notDefaultIdx=false] * @return {string} */ listProto.getId = function (idx) { return this._idList[this.indices[idx]] || (this.getRawIndex(idx) + ''); }; function normalizeDimensions(dimensions) { if (!zrUtil.isArray(dimensions)) { dimensions = [dimensions]; } return dimensions; } /** * Data iteration * @param {string|Array.} * @param {Function} cb * @param {boolean} [stack=false] * @param {*} [context=this] * * @example * list.each('x', function (x, idx) {}); * list.each(['x', 'y'], function (x, y, idx) {}); * list.each(function (idx) {}) */ listProto.each = function (dims, cb, stack, context) { if (typeof dims === 'function') { context = stack; stack = cb; cb = dims; dims = []; } dims = zrUtil.map(normalizeDimensions(dims), this.getDimension, this); var value = []; var dimSize = dims.length; var indices = this.indices; context = context || this; for (var i = 0; i < indices.length; i++) { // Simple optimization switch (dimSize) { case 0: cb.call(context, i); break; case 1: cb.call(context, this.get(dims[0], i, stack), i); break; case 2: cb.call(context, this.get(dims[0], i, stack), this.get(dims[1], i, stack), i); break; default: for (var k = 0; k < dimSize; k++) { value[k] = this.get(dims[k], i, stack); } // Index value[k] = i; cb.apply(context, value); } } }; /** * Data filter * @param {string|Array.} * @param {Function} cb * @param {boolean} [stack=false] * @param {*} [context=this] */ listProto.filterSelf = function (dimensions, cb, stack, context) { if (typeof dimensions === 'function') { context = stack; stack = cb; cb = dimensions; dimensions = []; } dimensions = zrUtil.map( normalizeDimensions(dimensions), this.getDimension, this ); var newIndices = []; var value = []; var dimSize = dimensions.length; var indices = this.indices; context = context || this; for (var i = 0; i < indices.length; i++) { var keep; // Simple optimization if (dimSize === 1) { keep = cb.call( context, this.get(dimensions[0], i, stack), i ); } else { for (var k = 0; k < dimSize; k++) { value[k] = this.get(dimensions[k], i, stack); } value[k] = i; keep = cb.apply(context, value); } if (keep) { newIndices.push(indices[i]); } } this.indices = newIndices; // Reset data extent this._extent = {}; return this; }; /** * Data mapping to a plain array * @param {string|Array.} [dimensions] * @param {Function} cb * @param {boolean} [stack=false] * @param {*} [context=this] * @return {Array} */ listProto.mapArray = function (dimensions, cb, stack, context) { if (typeof dimensions === 'function') { context = stack; stack = cb; cb = dimensions; dimensions = []; } var result = []; this.each(dimensions, function () { result.push(cb && cb.apply(this, arguments)); }, stack, context); return result; }; function cloneListForMapAndSample(original, excludeDimensions) { var allDimensions = original.dimensions; var list = new List( zrUtil.map(allDimensions, original.getDimensionInfo, original), original.hostModel ); // FIXME If needs stackedOn, value may already been stacked transferProperties(list, original); var storage = list._storage = {}; var originalStorage = original._storage; // Init storage for (var i = 0; i < allDimensions.length; i++) { var dim = allDimensions[i]; var dimStore = originalStorage[dim]; if (zrUtil.indexOf(excludeDimensions, dim) >= 0) { storage[dim] = new dimStore.constructor( originalStorage[dim].length ); } else { // Direct reference for other dimensions storage[dim] = originalStorage[dim]; } } return list; } /** * Data mapping to a new List with given dimensions * @param {string|Array.} dimensions * @param {Function} cb * @param {boolean} [stack=false] * @param {*} [context=this] * @return {Array} */ listProto.map = function (dimensions, cb, stack, context) { dimensions = zrUtil.map( normalizeDimensions(dimensions), this.getDimension, this ); var list = cloneListForMapAndSample(this, dimensions); // Following properties are all immutable. // So we can reference to the same value var indices = list.indices = this.indices; var storage = list._storage; var tmpRetValue = []; this.each(dimensions, function () { var idx = arguments[arguments.length - 1]; var retValue = cb && cb.apply(this, arguments); if (retValue != null) { // a number if (typeof retValue === 'number') { tmpRetValue[0] = retValue; retValue = tmpRetValue; } for (var i = 0; i < retValue.length; i++) { var dim = dimensions[i]; var dimStore = storage[dim]; var rawIdx = indices[idx]; if (dimStore) { dimStore[rawIdx] = retValue[i]; } } } }, stack, context); return list; }; /** * Large data down sampling on given dimension * @param {string} dimension * @param {number} rate * @param {Function} sampleValue * @param {Function} sampleIndex Sample index for name and id */ listProto.downSample = function (dimension, rate, sampleValue, sampleIndex) { var list = cloneListForMapAndSample(this, [dimension]); var storage = this._storage; var targetStorage = list._storage; var originalIndices = this.indices; var indices = list.indices = []; var frameValues = []; var frameIndices = []; var frameSize = Math.floor(1 / rate); var dimStore = targetStorage[dimension]; var len = this.count(); // Copy data from original data for (var i = 0; i < storage[dimension].length; i++) { targetStorage[dimension][i] = storage[dimension][i]; } for (var i = 0; i < len; i += frameSize) { // Last frame if (frameSize > len - i) { frameSize = len - i; frameValues.length = frameSize; } for (var k = 0; k < frameSize; k++) { var idx = originalIndices[i + k]; frameValues[k] = dimStore[idx]; frameIndices[k] = idx; } var value = sampleValue(frameValues); var idx = frameIndices[sampleIndex(frameValues, value) || 0]; // Only write value on the filtered data dimStore[idx] = value; indices.push(idx); } return list; }; /** * Get model of one data item. * * @param {number} idx */ // FIXME Model proxy ? listProto.getItemModel = function (idx) { var hostModel = this.hostModel; idx = this.indices[idx]; return new Model(this._rawData[idx], hostModel, hostModel && hostModel.ecModel); }; /** * Create a data differ * @param {module:echarts/data/List} otherList * @return {module:echarts/data/DataDiffer} */ listProto.diff = function (otherList) { var idList = this._idList; var otherIdList = otherList && otherList._idList; var val; // Use prefix to avoid index to be the same as otherIdList[idx], // which will cause weird udpate animation. var prefix = 'e\0\0'; return new DataDiffer( otherList ? otherList.indices : [], this.indices, function (idx) { return (val = otherIdList[idx]) != null ? val : prefix + idx; }, function (idx) { return (val = idList[idx]) != null ? val : prefix + idx; } ); }; /** * Get visual property. * @param {string} key */ listProto.getVisual = function (key) { var visual = this._visual; return visual && visual[key]; }; /** * Set visual property * @param {string|Object} key * @param {*} [value] * * @example * setVisual('color', color); * setVisual({ * 'color': color * }); */ listProto.setVisual = function (key, val) { if (isObject(key)) { for (var name in key) { if (key.hasOwnProperty(name)) { this.setVisual(name, key[name]); } } return; } this._visual = this._visual || {}; this._visual[key] = val; }; /** * Set layout property. * @param {string} key * @param {*} [val] */ listProto.setLayout = function (key, val) { if (isObject(key)) { for (var name in key) { if (key.hasOwnProperty(name)) { this.setLayout(name, key[name]); } } return; } this._layout[key] = val; }; /** * Get layout property. * @param {string} key. * @return {*} */ listProto.getLayout = function (key) { return this._layout[key]; }; /** * Get layout of single data item * @param {number} idx */ listProto.getItemLayout = function (idx) { return this._itemLayouts[idx]; }; /** * Set layout of single data item * @param {number} idx * @param {Object} layout * @param {boolean=} [merge=false] */ listProto.setItemLayout = function (idx, layout, merge) { this._itemLayouts[idx] = merge ? zrUtil.extend(this._itemLayouts[idx] || {}, layout) : layout; }; /** * Clear all layout of single data item */ listProto.clearItemLayouts = function () { this._itemLayouts.length = 0; }; /** * Get visual property of single data item * @param {number} idx * @param {string} key * @param {boolean} ignoreParent */ listProto.getItemVisual = function (idx, key, ignoreParent) { var itemVisual = this._itemVisuals[idx]; var val = itemVisual && itemVisual[key]; if (val == null && !ignoreParent) { // Use global visual property return this.getVisual(key); } return val; }; /** * Set visual property of single data item * * @param {number} idx * @param {string|Object} key * @param {*} [value] * * @example * setItemVisual(0, 'color', color); * setItemVisual(0, { * 'color': color * }); */ listProto.setItemVisual = function (idx, key, value) { var itemVisual = this._itemVisuals[idx] || {}; this._itemVisuals[idx] = itemVisual; if (isObject(key)) { for (var name in key) { if (key.hasOwnProperty(name)) { itemVisual[name] = key[name]; } } return; } itemVisual[key] = value; }; /** * Clear itemVisuals and list visual. */ listProto.clearAllVisual = function () { this._visual = {}; this._itemVisuals = []; }; var setItemDataAndSeriesIndex = function (child) { child.seriesIndex = this.seriesIndex; child.dataIndex = this.dataIndex; child.dataType = this.dataType; }; /** * Set graphic element relative to data. It can be set as null * @param {number} idx * @param {module:zrender/Element} [el] */ listProto.setItemGraphicEl = function (idx, el) { var hostModel = this.hostModel; if (el) { // Add data index and series index for indexing the data by element // Useful in tooltip el.dataIndex = idx; el.dataType = this.dataType; el.seriesIndex = hostModel && hostModel.seriesIndex; if (el.type === 'group') { el.traverse(setItemDataAndSeriesIndex, el); } } this._graphicEls[idx] = el; }; /** * @param {number} idx * @return {module:zrender/Element} */ listProto.getItemGraphicEl = function (idx) { return this._graphicEls[idx]; }; /** * @param {Function} cb * @param {*} context */ listProto.eachItemGraphicEl = function (cb, context) { zrUtil.each(this._graphicEls, function (el, idx) { if (el) { cb && cb.call(context, el, idx); } }); }; /** * Shallow clone a new list except visual and layout properties, and graph elements. * New list only change the indices. */ listProto.cloneShallow = function () { var dimensionInfoList = zrUtil.map(this.dimensions, this.getDimensionInfo, this); var list = new List(dimensionInfoList, this.hostModel); // FIXME list._storage = this._storage; transferProperties(list, this); // Clone will not change the data extent and indices list.indices = this.indices.slice(); if (this._extent) { list._extent = zrUtil.extend({}, this._extent); } return list; }; /** * Wrap some method to add more feature * @param {string} methodName * @param {Function} injectFunction */ listProto.wrapMethod = function (methodName, injectFunction) { var originalMethod = this[methodName]; if (typeof originalMethod !== 'function') { return; } this.__wrappedMethods = this.__wrappedMethods || []; this.__wrappedMethods.push(methodName); this[methodName] = function () { var res = originalMethod.apply(this, arguments); return injectFunction.apply(this, [res].concat(zrUtil.slice(arguments))); }; }; // Methods that create a new list based on this list should be listed here. // Notice that those method should `RETURN` the new list. listProto.TRANSFERABLE_METHODS = ['cloneShallow', 'downSample', 'map']; // Methods that change indices of this list should be listed here. listProto.CHANGABLE_METHODS = ['filterSelf']; module.exports = List; /* WEBPACK VAR INJECTION */}.call(exports, (function() { return this; }()))) /***/ }, /* 99 */ /***/ function(module, exports) { 'use strict'; function defaultKeyGetter(item) { return item; } function DataDiffer(oldArr, newArr, oldKeyGetter, newKeyGetter) { this._old = oldArr; this._new = newArr; this._oldKeyGetter = oldKeyGetter || defaultKeyGetter; this._newKeyGetter = newKeyGetter || defaultKeyGetter; } DataDiffer.prototype = { constructor: DataDiffer, /** * Callback function when add a data */ add: function (func) { this._add = func; return this; }, /** * Callback function when update a data */ update: function (func) { this._update = func; return this; }, /** * Callback function when remove a data */ remove: function (func) { this._remove = func; return this; }, execute: function () { var oldArr = this._old; var newArr = this._new; var oldKeyGetter = this._oldKeyGetter; var newKeyGetter = this._newKeyGetter; var oldDataIndexMap = {}; var newDataIndexMap = {}; var oldDataKeyArr = []; var newDataKeyArr = []; var i; initIndexMap(oldArr, oldDataIndexMap, oldDataKeyArr, oldKeyGetter); initIndexMap(newArr, newDataIndexMap, newDataKeyArr, newKeyGetter); // Travel by inverted order to make sure order consistency // when duplicate keys exists (consider newDataIndex.pop() below). // For performance consideration, these code below do not look neat. for (i = 0; i < oldArr.length; i++) { var key = oldDataKeyArr[i]; var idx = newDataIndexMap[key]; // idx can never be empty array here. see 'set null' logic below. if (idx != null) { // Consider there is duplicate key (for example, use dataItem.name as key). // We should make sure every item in newArr and oldArr can be visited. var len = idx.length; if (len) { len === 1 && (newDataIndexMap[key] = null); idx = idx.unshift(); } else { newDataIndexMap[key] = null; } this._update && this._update(idx, i); } else { this._remove && this._remove(i); } } for (var i = 0; i < newDataKeyArr.length; i++) { var key = newDataKeyArr[i]; if (newDataIndexMap.hasOwnProperty(key)) { var idx = newDataIndexMap[key]; if (idx == null) { continue; } // idx can never be empty array here. see 'set null' logic above. if (!idx.length) { this._add && this._add(idx); } else { for (var j = 0, len = idx.length; j < len; j++) { this._add && this._add(idx[j]); } } } } } }; function initIndexMap(arr, map, keyArr, keyGetter) { for (var i = 0; i < arr.length; i++) { var key = keyGetter(arr[i], i); var existence = map[key]; if (existence == null) { keyArr.push(key); map[key] = i; } else { if (!existence.length) { map[key] = existence = [existence]; } existence.push(i); } } } module.exports = DataDiffer; /***/ }, /* 100 */ /***/ function(module, exports, __webpack_require__) { var zrUtil = __webpack_require__(4); var echarts = __webpack_require__(1); var PRIORITY = echarts.PRIORITY; __webpack_require__(101); __webpack_require__(104); echarts.registerVisual(zrUtil.curry( __webpack_require__(110), 'line', 'circle', 'line' )); echarts.registerLayout(zrUtil.curry( __webpack_require__(111), 'line' )); // Down sample after filter echarts.registerProcessor(PRIORITY.PROCESSOR.STATISTIC, zrUtil.curry( __webpack_require__(112), 'line' )); // In case developer forget to include grid component __webpack_require__(113); /***/ }, /* 101 */ /***/ function(module, exports, __webpack_require__) { 'use strict'; var createListFromArray = __webpack_require__(102); var SeriesModel = __webpack_require__(28); module.exports = SeriesModel.extend({ type: 'series.line', dependencies: ['grid', 'polar'], getInitialData: function (option, ecModel) { if (true) { var coordSys = option.coordinateSystem; if (coordSys !== 'polar' && coordSys !== 'cartesian2d') { throw new Error('Line not support coordinateSystem besides cartesian and polar'); } } return createListFromArray(option.data, this, ecModel); }, defaultOption: { zlevel: 0, // 一级层叠 z: 2, // 二级层叠 coordinateSystem: 'cartesian2d', legendHoverLink: true, hoverAnimation: true, // stack: null // xAxisIndex: 0, // yAxisIndex: 0, // polarIndex: 0, // If clip the overflow value clipOverflow: true, label: { normal: { position: 'top' } }, // itemStyle: { // normal: {}, // emphasis: {} // }, lineStyle: { normal: { width: 2, type: 'solid' } }, // areaStyle: {}, // false, 'start', 'end', 'middle' step: false, // Disabled if step is true smooth: false, smoothMonotone: null, // 拐点图形类型 symbol: 'emptyCircle', // 拐点图形大小 symbolSize: 4, // 拐点图形旋转控制 symbolRotate: null, // 是否显示 symbol, 只有在 tooltip hover 的时候显示 showSymbol: true, // 标志图形默认只有主轴显示(随主轴标签间隔隐藏策略) showAllSymbol: false, // 是否连接断点 connectNulls: false, // 数据过滤,'average', 'max', 'min', 'sum' sampling: 'none', animationEasing: 'linear', // Disable progressive progressive: 0, hoverLayerThreshold: Infinity } }); /***/ }, /* 102 */ /***/ function(module, exports, __webpack_require__) { 'use strict'; var List = __webpack_require__(98); var completeDimensions = __webpack_require__(103); var zrUtil = __webpack_require__(4); var modelUtil = __webpack_require__(5); var CoordinateSystem = __webpack_require__(26); var getDataItemValue = modelUtil.getDataItemValue; var converDataValue = modelUtil.converDataValue; function firstDataNotNull(data) { var i = 0; while (i < data.length && data[i] == null) { i++; } return data[i]; } function ifNeedCompleteOrdinalData(data) { var sampleItem = firstDataNotNull(data); return sampleItem != null && !zrUtil.isArray(getDataItemValue(sampleItem)); } /** * Helper function to create a list from option data */ function createListFromArray(data, seriesModel, ecModel) { // If data is undefined data = data || []; if (true) { if (!zrUtil.isArray(data)) { throw new Error('Invalid data.'); } } var coordSysName = seriesModel.get('coordinateSystem'); var creator = creators[coordSysName]; var registeredCoordSys = CoordinateSystem.get(coordSysName); // FIXME var axesInfo = creator && creator(data, seriesModel, ecModel); var dimensions = axesInfo && axesInfo.dimensions; if (!dimensions) { // Get dimensions from registered coordinate system dimensions = (registeredCoordSys && registeredCoordSys.dimensions) || ['x', 'y']; dimensions = completeDimensions(dimensions, data, dimensions.concat(['value'])); } var categoryIndex = axesInfo ? axesInfo.categoryIndex : -1; var list = new List(dimensions, seriesModel); var nameList = createNameList(axesInfo, data); var categories = {}; var dimValueGetter = (categoryIndex >= 0 && ifNeedCompleteOrdinalData(data)) ? function (itemOpt, dimName, dataIndex, dimIndex) { // If any dataItem is like { value: 10 } if (modelUtil.isDataItemOption(itemOpt)) { list.hasItemOption = true; } // Use dataIndex as ordinal value in categoryAxis return dimIndex === categoryIndex ? dataIndex : converDataValue(getDataItemValue(itemOpt), dimensions[dimIndex]); } : function (itemOpt, dimName, dataIndex, dimIndex) { var value = getDataItemValue(itemOpt); var val = converDataValue(value && value[dimIndex], dimensions[dimIndex]); // If any dataItem is like { value: 10 } if (modelUtil.isDataItemOption(itemOpt)) { list.hasItemOption = true; } var categoryAxesModels = axesInfo && axesInfo.categoryAxesModels; if (categoryAxesModels && categoryAxesModels[dimName]) { // If given value is a category string if (typeof val === 'string') { // Lazy get categories categories[dimName] = categories[dimName] || categoryAxesModels[dimName].getCategories(); val = zrUtil.indexOf(categories[dimName], val); if (val < 0 && !isNaN(val)) { // In case some one write '1', '2' istead of 1, 2 val = +val; } } } return val; }; list.hasItemOption = false; list.initData(data, nameList, dimValueGetter); return list; } function isStackable(axisType) { return axisType !== 'category' && axisType !== 'time'; } function getDimTypeByAxis(axisType) { return axisType === 'category' ? 'ordinal' : axisType === 'time' ? 'time' : 'float'; } /** * Creaters for each coord system. */ var creators = { cartesian2d: function (data, seriesModel, ecModel) { var axesModels = zrUtil.map(['xAxis', 'yAxis'], function (name) { return ecModel.queryComponents({ mainType: name, index: seriesModel.get(name + 'Index'), id: seriesModel.get(name + 'Id') })[0]; }); var xAxisModel = axesModels[0]; var yAxisModel = axesModels[1]; if (true) { if (!xAxisModel) { throw new Error('xAxis "' + zrUtil.retrieve( seriesModel.get('xAxisIndex'), seriesModel.get('xAxisId'), 0 ) + '" not found'); } if (!yAxisModel) { throw new Error('yAxis "' + zrUtil.retrieve( seriesModel.get('xAxisIndex'), seriesModel.get('yAxisId'), 0 ) + '" not found'); } } var xAxisType = xAxisModel.get('type'); var yAxisType = yAxisModel.get('type'); var dimensions = [ { name: 'x', type: getDimTypeByAxis(xAxisType), stackable: isStackable(xAxisType) }, { name: 'y', // If two category axes type: getDimTypeByAxis(yAxisType), stackable: isStackable(yAxisType) } ]; var isXAxisCateogry = xAxisType === 'category'; var isYAxisCategory = yAxisType === 'category'; completeDimensions(dimensions, data, ['x', 'y', 'z']); var categoryAxesModels = {}; if (isXAxisCateogry) { categoryAxesModels.x = xAxisModel; } if (isYAxisCategory) { categoryAxesModels.y = yAxisModel; } return { dimensions: dimensions, categoryIndex: isXAxisCateogry ? 0 : (isYAxisCategory ? 1 : -1), categoryAxesModels: categoryAxesModels }; }, polar: function (data, seriesModel, ecModel) { var polarModel = ecModel.queryComponents({ mainType: 'polar', index: seriesModel.get('polarIndex'), id: seriesModel.get('polarId') })[0]; var angleAxisModel = polarModel.findAxisModel('angleAxis'); var radiusAxisModel = polarModel.findAxisModel('radiusAxis'); if (true) { if (!angleAxisModel) { throw new Error('angleAxis option not found'); } if (!radiusAxisModel) { throw new Error('radiusAxis option not found'); } } var radiusAxisType = radiusAxisModel.get('type'); var angleAxisType = angleAxisModel.get('type'); var dimensions = [ { name: 'radius', type: getDimTypeByAxis(radiusAxisType), stackable: isStackable(radiusAxisType) }, { name: 'angle', type: getDimTypeByAxis(angleAxisType), stackable: isStackable(angleAxisType) } ]; var isAngleAxisCateogry = angleAxisType === 'category'; var isRadiusAxisCateogry = radiusAxisType === 'category'; completeDimensions(dimensions, data, ['radius', 'angle', 'value']); var categoryAxesModels = {}; if (isRadiusAxisCateogry) { categoryAxesModels.radius = radiusAxisModel; } if (isAngleAxisCateogry) { categoryAxesModels.angle = angleAxisModel; } return { dimensions: dimensions, categoryIndex: isAngleAxisCateogry ? 1 : (isRadiusAxisCateogry ? 0 : -1), categoryAxesModels: categoryAxesModels }; }, geo: function (data, seriesModel, ecModel) { // TODO Region // 多个散点图系列在同一个地区的时候 return { dimensions: completeDimensions([ {name: 'lng'}, {name: 'lat'} ], data, ['lng', 'lat', 'value']) }; } }; function createNameList(result, data) { var nameList = []; var categoryDim = result && result.dimensions[result.categoryIndex]; var categoryAxisModel; if (categoryDim) { categoryAxisModel = result.categoryAxesModels[categoryDim.name]; } if (categoryAxisModel) { // FIXME Two category axis var categories = categoryAxisModel.getCategories(); if (categories) { var dataLen = data.length; // Ordered data is given explicitly like // [[3, 0.2], [1, 0.3], [2, 0.15]] // or given scatter data, // pick the category if (zrUtil.isArray(data[0]) && data[0].length > 1) { nameList = []; for (var i = 0; i < dataLen; i++) { nameList[i] = categories[data[i][result.categoryIndex || 0]]; } } else { nameList = categories.slice(0); } } } return nameList; } module.exports = createListFromArray; /***/ }, /* 103 */ /***/ function(module, exports, __webpack_require__) { /** * Complete dimensions by data (guess dimension). */ var zrUtil = __webpack_require__(4); /** * Complete the dimensions array guessed from the data structure. * @param {Array.} dimensions Necessary dimensions, like ['x', 'y'] * @param {Array} data Data list. [[1, 2, 3], [2, 3, 4]] * @param {Array.} defaultNames Default names to fill not necessary dimensions, like ['value'] * @param {string} extraPrefix Prefix of name when filling the left dimensions. * @return {Array.} */ function completeDimensions(dimensions, data, defaultNames, extraPrefix) { if (!data) { return dimensions; } var value0 = retrieveValue(data[0]); var dimSize = zrUtil.isArray(value0) && value0.length || 1; defaultNames = defaultNames || []; extraPrefix = extraPrefix || 'extra'; for (var i = 0; i < dimSize; i++) { if (!dimensions[i]) { var name = defaultNames[i] || (extraPrefix + (i - defaultNames.length)); dimensions[i] = guessOrdinal(data, i) ? {type: 'ordinal', name: name} : name; } } return dimensions; } // The rule should not be complex, otherwise user might not // be able to known where the data is wrong. var guessOrdinal = completeDimensions.guessOrdinal = function (data, dimIndex) { for (var i = 0, len = data.length; i < len; i++) { var value = retrieveValue(data[i]); if (!zrUtil.isArray(value)) { return false; } var value = value[dimIndex]; if (value != null && isFinite(value)) { return false; } else if (zrUtil.isString(value) && value !== '-') { return true; } } return false; }; function retrieveValue(o) { return zrUtil.isArray(o) ? o : zrUtil.isObject(o) ? o.value: o; } module.exports = completeDimensions; /***/ }, /* 104 */ /***/ function(module, exports, __webpack_require__) { 'use strict'; // FIXME step not support polar var zrUtil = __webpack_require__(4); var SymbolDraw = __webpack_require__(105); var Symbol = __webpack_require__(106); var lineAnimationDiff = __webpack_require__(108); var graphic = __webpack_require__(43); var modelUtil = __webpack_require__(5); var polyHelper = __webpack_require__(109); var ChartView = __webpack_require__(42); function isPointsSame(points1, points2) { if (points1.length !== points2.length) { return; } for (var i = 0; i < points1.length; i++) { var p1 = points1[i]; var p2 = points2[i]; if (p1[0] !== p2[0] || p1[1] !== p2[1]) { return; } } return true; } function getSmooth(smooth) { return typeof (smooth) === 'number' ? smooth : (smooth ? 0.3 : 0); } function getAxisExtentWithGap(axis) { var extent = axis.getGlobalExtent(); if (axis.onBand) { // Remove extra 1px to avoid line miter in clipped edge var halfBandWidth = axis.getBandWidth() / 2 - 1; var dir = extent[1] > extent[0] ? 1 : -1; extent[0] += dir * halfBandWidth; extent[1] -= dir * halfBandWidth; } return extent; } function sign(val) { return val >= 0 ? 1 : -1; } /** * @param {module:echarts/coord/cartesian/Cartesian2D|module:echarts/coord/polar/Polar} coordSys * @param {module:echarts/data/List} data * @param {Array.>} points * @private */ function getStackedOnPoints(coordSys, data) { var baseAxis = coordSys.getBaseAxis(); var valueAxis = coordSys.getOtherAxis(baseAxis); var valueStart = baseAxis.onZero ? 0 : valueAxis.scale.getExtent()[0]; var valueDim = valueAxis.dim; var baseDataOffset = valueDim === 'x' || valueDim === 'radius' ? 1 : 0; return data.mapArray([valueDim], function (val, idx) { var stackedOnSameSign; var stackedOn = data.stackedOn; // Find first stacked value with same sign while (stackedOn && sign(stackedOn.get(valueDim, idx)) === sign(val) ) { stackedOnSameSign = stackedOn; break; } var stackedData = []; stackedData[baseDataOffset] = data.get(baseAxis.dim, idx); stackedData[1 - baseDataOffset] = stackedOnSameSign ? stackedOnSameSign.get(valueDim, idx, true) : valueStart; return coordSys.dataToPoint(stackedData); }, true); } function createGridClipShape(cartesian, hasAnimation, seriesModel) { var xExtent = getAxisExtentWithGap(cartesian.getAxis('x')); var yExtent = getAxisExtentWithGap(cartesian.getAxis('y')); var isHorizontal = cartesian.getBaseAxis().isHorizontal(); var x = Math.min(xExtent[0], xExtent[1]); var y = Math.min(yExtent[0], yExtent[1]); var width = Math.max(xExtent[0], xExtent[1]) - x; var height = Math.max(yExtent[0], yExtent[1]) - y; var lineWidth = seriesModel.get('lineStyle.normal.width') || 2; // Expand clip shape to avoid clipping when line value exceeds axis var expandSize = seriesModel.get('clipOverflow') ? lineWidth / 2 : Math.max(width, height); if (isHorizontal) { y -= expandSize; height += expandSize * 2; } else { x -= expandSize; width += expandSize * 2; } var clipPath = new graphic.Rect({ shape: { x: x, y: y, width: width, height: height } }); if (hasAnimation) { clipPath.shape[isHorizontal ? 'width' : 'height'] = 0; graphic.initProps(clipPath, { shape: { width: width, height: height } }, seriesModel); } return clipPath; } function createPolarClipShape(polar, hasAnimation, seriesModel) { var angleAxis = polar.getAngleAxis(); var radiusAxis = polar.getRadiusAxis(); var radiusExtent = radiusAxis.getExtent(); var angleExtent = angleAxis.getExtent(); var RADIAN = Math.PI / 180; var clipPath = new graphic.Sector({ shape: { cx: polar.cx, cy: polar.cy, r0: radiusExtent[0], r: radiusExtent[1], startAngle: -angleExtent[0] * RADIAN, endAngle: -angleExtent[1] * RADIAN, clockwise: angleAxis.inverse } }); if (hasAnimation) { clipPath.shape.endAngle = -angleExtent[0] * RADIAN; graphic.initProps(clipPath, { shape: { endAngle: -angleExtent[1] * RADIAN } }, seriesModel); } return clipPath; } function createClipShape(coordSys, hasAnimation, seriesModel) { return coordSys.type === 'polar' ? createPolarClipShape(coordSys, hasAnimation, seriesModel) : createGridClipShape(coordSys, hasAnimation, seriesModel); } function turnPointsIntoStep(points, coordSys, stepTurnAt) { var baseAxis = coordSys.getBaseAxis(); var baseIndex = baseAxis.dim === 'x' || baseAxis.dim === 'radius' ? 0 : 1; var stepPoints = []; for (var i = 0; i < points.length - 1; i++) { var nextPt = points[i + 1]; var pt = points[i]; stepPoints.push(pt); var stepPt = []; switch (stepTurnAt) { case 'end': stepPt[baseIndex] = nextPt[baseIndex]; stepPt[1 - baseIndex] = pt[1 - baseIndex]; // default is start stepPoints.push(stepPt); break; case 'middle': // default is start var middle = (pt[baseIndex] + nextPt[baseIndex]) / 2; var stepPt2 = []; stepPt[baseIndex] = stepPt2[baseIndex] = middle; stepPt[1 - baseIndex] = pt[1 - baseIndex]; stepPt2[1 - baseIndex] = nextPt[1 - baseIndex]; stepPoints.push(stepPt); stepPoints.push(stepPt2); break; default: stepPt[baseIndex] = pt[baseIndex]; stepPt[1 - baseIndex] = nextPt[1 - baseIndex]; // default is start stepPoints.push(stepPt); } } // Last points points[i] && stepPoints.push(points[i]); return stepPoints; } function getVisualGradient(data, coordSys) { var visualMetaList = data.getVisual('visualMeta'); if (!visualMetaList || !visualMetaList.length || !data.count()) { // When data.count() is 0, gradient range can not be calculated. return; } var visualMeta; for (var i = visualMetaList.length - 1; i >= 0; i--) { // Can only be x or y if (visualMetaList[i].dimension < 2) { visualMeta = visualMetaList[i]; break; } } if (!visualMeta || coordSys.type !== 'cartesian2d') { if (true) { console.warn('Visual map on line style only support x or y dimension.'); } return; } // If the area to be rendered is bigger than area defined by LinearGradient, // the canvas spec prescribes that the color of the first stop and the last // stop should be used. But if two stops are added at offset 0, in effect // browsers use the color of the second stop to render area outside // LinearGradient. So we can only infinitesimally extend area defined in // LinearGradient to render `outerColors`. var dimension = visualMeta.dimension; var dimName = data.dimensions[dimension]; var axis = coordSys.getAxis(dimName); // dataToCoor mapping may not be linear, but must be monotonic. var colorStops = zrUtil.map(visualMeta.stops, function (stop) { return { coord: axis.toGlobalCoord(axis.dataToCoord(stop.value)), color: stop.color }; }); var stopLen = colorStops.length; var outerColors = visualMeta.outerColors.slice(); if (stopLen && colorStops[0].coord > colorStops[stopLen - 1].coord) { colorStops.reverse(); outerColors.reverse(); } var tinyExtent = 10; // Arbitrary value: 10px var minCoord = colorStops[0].coord - tinyExtent; var maxCoord = colorStops[stopLen - 1].coord + tinyExtent; var coordSpan = maxCoord - minCoord; if (coordSpan < 1e-3) { return 'transparent'; } zrUtil.each(colorStops, function (stop) { stop.offset = (stop.coord - minCoord) / coordSpan; }); colorStops.push({ offset: stopLen ? colorStops[stopLen - 1].offset : 0.5, color: outerColors[1] || 'transparent' }); colorStops.unshift({ // notice colorStops.length have been changed. offset: stopLen ? colorStops[0].offset : 0.5, color: outerColors[0] || 'transparent' }); // zrUtil.each(colorStops, function (colorStop) { // // Make sure each offset has rounded px to avoid not sharp edge // colorStop.offset = (Math.round(colorStop.offset * (end - start) + start) - start) / (end - start); // }); var gradient = new graphic.LinearGradient(0, 0, 0, 0, colorStops, true); gradient[dimName] = minCoord; gradient[dimName + '2'] = maxCoord; return gradient; } module.exports = ChartView.extend({ type: 'line', init: function () { var lineGroup = new graphic.Group(); var symbolDraw = new SymbolDraw(); this.group.add(symbolDraw.group); this._symbolDraw = symbolDraw; this._lineGroup = lineGroup; }, render: function (seriesModel, ecModel, api) { var coordSys = seriesModel.coordinateSystem; var group = this.group; var data = seriesModel.getData(); var lineStyleModel = seriesModel.getModel('lineStyle.normal'); var areaStyleModel = seriesModel.getModel('areaStyle.normal'); var points = data.mapArray(data.getItemLayout, true); var isCoordSysPolar = coordSys.type === 'polar'; var prevCoordSys = this._coordSys; var symbolDraw = this._symbolDraw; var polyline = this._polyline; var polygon = this._polygon; var lineGroup = this._lineGroup; var hasAnimation = seriesModel.get('animation'); var isAreaChart = !areaStyleModel.isEmpty(); var stackedOnPoints = getStackedOnPoints(coordSys, data); var showSymbol = seriesModel.get('showSymbol'); var isSymbolIgnore = showSymbol && !isCoordSysPolar && !seriesModel.get('showAllSymbol') && this._getSymbolIgnoreFunc(data, coordSys); // Remove temporary symbols var oldData = this._data; oldData && oldData.eachItemGraphicEl(function (el, idx) { if (el.__temp) { group.remove(el); oldData.setItemGraphicEl(idx, null); } }); // Remove previous created symbols if showSymbol changed to false if (!showSymbol) { symbolDraw.remove(); } group.add(lineGroup); // FIXME step not support polar var step = !isCoordSysPolar && seriesModel.get('step'); // Initialization animation or coordinate system changed if ( !(polyline && prevCoordSys.type === coordSys.type && step === this._step) ) { showSymbol && symbolDraw.updateData(data, isSymbolIgnore); if (step) { // TODO If stacked series is not step points = turnPointsIntoStep(points, coordSys, step); stackedOnPoints = turnPointsIntoStep(stackedOnPoints, coordSys, step); } polyline = this._newPolyline(points, coordSys, hasAnimation); if (isAreaChart) { polygon = this._newPolygon( points, stackedOnPoints, coordSys, hasAnimation ); } lineGroup.setClipPath(createClipShape(coordSys, true, seriesModel)); } else { if (isAreaChart && !polygon) { // If areaStyle is added polygon = this._newPolygon( points, stackedOnPoints, coordSys, hasAnimation ); } else if (polygon && !isAreaChart) { // If areaStyle is removed lineGroup.remove(polygon); polygon = this._polygon = null; } // Update clipPath lineGroup.setClipPath(createClipShape(coordSys, false, seriesModel)); // Always update, or it is wrong in the case turning on legend // because points are not changed showSymbol && symbolDraw.updateData(data, isSymbolIgnore); // Stop symbol animation and sync with line points // FIXME performance? data.eachItemGraphicEl(function (el) { el.stopAnimation(true); }); // In the case data zoom triggerred refreshing frequently // Data may not change if line has a category axis. So it should animate nothing if (!isPointsSame(this._stackedOnPoints, stackedOnPoints) || !isPointsSame(this._points, points) ) { if (hasAnimation) { this._updateAnimation( data, stackedOnPoints, coordSys, api, step ); } else { // Not do it in update with animation if (step) { // TODO If stacked series is not step points = turnPointsIntoStep(points, coordSys, step); stackedOnPoints = turnPointsIntoStep(stackedOnPoints, coordSys, step); } polyline.setShape({ points: points }); polygon && polygon.setShape({ points: points, stackedOnPoints: stackedOnPoints }); } } } var visualColor = getVisualGradient(data, coordSys) || data.getVisual('color'); polyline.useStyle(zrUtil.defaults( // Use color in lineStyle first lineStyleModel.getLineStyle(), { fill: 'none', stroke: visualColor, lineJoin: 'bevel' } )); var smooth = seriesModel.get('smooth'); smooth = getSmooth(seriesModel.get('smooth')); polyline.setShape({ smooth: smooth, smoothMonotone: seriesModel.get('smoothMonotone'), connectNulls: seriesModel.get('connectNulls') }); if (polygon) { var stackedOn = data.stackedOn; var stackedOnSmooth = 0; polygon.useStyle(zrUtil.defaults( areaStyleModel.getAreaStyle(), { fill: visualColor, opacity: 0.7, lineJoin: 'bevel' } )); if (stackedOn) { var stackedOnSeries = stackedOn.hostModel; stackedOnSmooth = getSmooth(stackedOnSeries.get('smooth')); } polygon.setShape({ smooth: smooth, stackedOnSmooth: stackedOnSmooth, smoothMonotone: seriesModel.get('smoothMonotone'), connectNulls: seriesModel.get('connectNulls') }); } this._data = data; // Save the coordinate system for transition animation when data changed this._coordSys = coordSys; this._stackedOnPoints = stackedOnPoints; this._points = points; this._step = step; }, dispose: function () {}, highlight: function (seriesModel, ecModel, api, payload) { var data = seriesModel.getData(); var dataIndex = modelUtil.queryDataIndex(data, payload); if (!(dataIndex instanceof Array) && dataIndex != null && dataIndex >= 0) { var symbol = data.getItemGraphicEl(dataIndex); if (!symbol) { // Create a temporary symbol if it is not exists var pt = data.getItemLayout(dataIndex); if (!pt) { // Null data return; } symbol = new Symbol(data, dataIndex); symbol.position = pt; symbol.setZ( seriesModel.get('zlevel'), seriesModel.get('z') ); symbol.ignore = isNaN(pt[0]) || isNaN(pt[1]); symbol.__temp = true; data.setItemGraphicEl(dataIndex, symbol); // Stop scale animation symbol.stopSymbolAnimation(true); this.group.add(symbol); } symbol.highlight(); } else { // Highlight whole series ChartView.prototype.highlight.call( this, seriesModel, ecModel, api, payload ); } }, downplay: function (seriesModel, ecModel, api, payload) { var data = seriesModel.getData(); var dataIndex = modelUtil.queryDataIndex(data, payload); if (dataIndex != null && dataIndex >= 0) { var symbol = data.getItemGraphicEl(dataIndex); if (symbol) { if (symbol.__temp) { data.setItemGraphicEl(dataIndex, null); this.group.remove(symbol); } else { symbol.downplay(); } } } else { // Downplay whole series ChartView.prototype.downplay.call( this, seriesModel, ecModel, api, payload ); } }, /** * @param {module:zrender/container/Group} group * @param {Array.>} points * @private */ _newPolyline: function (points) { var polyline = this._polyline; // Remove previous created polyline if (polyline) { this._lineGroup.remove(polyline); } polyline = new polyHelper.Polyline({ shape: { points: points }, silent: true, z2: 10 }); this._lineGroup.add(polyline); this._polyline = polyline; return polyline; }, /** * @param {module:zrender/container/Group} group * @param {Array.>} stackedOnPoints * @param {Array.>} points * @private */ _newPolygon: function (points, stackedOnPoints) { var polygon = this._polygon; // Remove previous created polygon if (polygon) { this._lineGroup.remove(polygon); } polygon = new polyHelper.Polygon({ shape: { points: points, stackedOnPoints: stackedOnPoints }, silent: true }); this._lineGroup.add(polygon); this._polygon = polygon; return polygon; }, /** * @private */ _getSymbolIgnoreFunc: function (data, coordSys) { var categoryAxis = coordSys.getAxesByScale('ordinal')[0]; // `getLabelInterval` is provided by echarts/component/axis if (categoryAxis && categoryAxis.isLabelIgnored) { return zrUtil.bind(categoryAxis.isLabelIgnored, categoryAxis); } }, /** * @private */ // FIXME Two value axis _updateAnimation: function (data, stackedOnPoints, coordSys, api, step) { var polyline = this._polyline; var polygon = this._polygon; var seriesModel = data.hostModel; var diff = lineAnimationDiff( this._data, data, this._stackedOnPoints, stackedOnPoints, this._coordSys, coordSys ); var current = diff.current; var stackedOnCurrent = diff.stackedOnCurrent; var next = diff.next; var stackedOnNext = diff.stackedOnNext; if (step) { // TODO If stacked series is not step current = turnPointsIntoStep(diff.current, coordSys, step); stackedOnCurrent = turnPointsIntoStep(diff.stackedOnCurrent, coordSys, step); next = turnPointsIntoStep(diff.next, coordSys, step); stackedOnNext = turnPointsIntoStep(diff.stackedOnNext, coordSys, step); } // `diff.current` is subset of `current` (which should be ensured by // turnPointsIntoStep), so points in `__points` can be updated when // points in `current` are update during animation. polyline.shape.__points = diff.current; polyline.shape.points = current; graphic.updateProps(polyline, { shape: { points: next } }, seriesModel); if (polygon) { polygon.setShape({ points: current, stackedOnPoints: stackedOnCurrent }); graphic.updateProps(polygon, { shape: { points: next, stackedOnPoints: stackedOnNext } }, seriesModel); } var updatedDataInfo = []; var diffStatus = diff.status; for (var i = 0; i < diffStatus.length; i++) { var cmd = diffStatus[i].cmd; if (cmd === '=') { var el = data.getItemGraphicEl(diffStatus[i].idx1); if (el) { updatedDataInfo.push({ el: el, ptIdx: i // Index of points }); } } } if (polyline.animators && polyline.animators.length) { polyline.animators[0].during(function () { for (var i = 0; i < updatedDataInfo.length; i++) { var el = updatedDataInfo[i].el; el.attr('position', polyline.shape.__points[updatedDataInfo[i].ptIdx]); } }); } }, remove: function (ecModel) { var group = this.group; var oldData = this._data; this._lineGroup.removeAll(); this._symbolDraw.remove(true); // Remove temporary created elements when highlighting oldData && oldData.eachItemGraphicEl(function (el, idx) { if (el.__temp) { group.remove(el); oldData.setItemGraphicEl(idx, null); } }); this._polyline = this._polygon = this._coordSys = this._points = this._stackedOnPoints = this._data = null; } }); /***/ }, /* 105 */ /***/ function(module, exports, __webpack_require__) { /** * @module echarts/chart/helper/SymbolDraw */ var graphic = __webpack_require__(43); var Symbol = __webpack_require__(106); /** * @constructor * @alias module:echarts/chart/helper/SymbolDraw * @param {module:zrender/graphic/Group} [symbolCtor] */ function SymbolDraw(symbolCtor) { this.group = new graphic.Group(); this._symbolCtor = symbolCtor || Symbol; } var symbolDrawProto = SymbolDraw.prototype; function symbolNeedsDraw(data, idx, isIgnore) { var point = data.getItemLayout(idx); // Is an object // if (point && point.hasOwnProperty('point')) { // point = point.point; // } return point && !isNaN(point[0]) && !isNaN(point[1]) && !(isIgnore && isIgnore(idx)) && data.getItemVisual(idx, 'symbol') !== 'none'; } /** * Update symbols draw by new data * @param {module:echarts/data/List} data * @param {Array.} [isIgnore] */ symbolDrawProto.updateData = function (data, isIgnore) { var group = this.group; var seriesModel = data.hostModel; var oldData = this._data; var SymbolCtor = this._symbolCtor; var seriesScope = { itemStyle: seriesModel.getModel('itemStyle.normal').getItemStyle(['color']), hoverItemStyle: seriesModel.getModel('itemStyle.emphasis').getItemStyle(), symbolRotate: seriesModel.get('symbolRotate'), symbolOffset: seriesModel.get('symbolOffset'), hoverAnimation: seriesModel.get('hoverAnimation'), labelModel: seriesModel.getModel('label.normal'), hoverLabelModel: seriesModel.getModel('label.emphasis') }; data.diff(oldData) .add(function (newIdx) { var point = data.getItemLayout(newIdx); if (symbolNeedsDraw(data, newIdx, isIgnore)) { var symbolEl = new SymbolCtor(data, newIdx, seriesScope); symbolEl.attr('position', point); data.setItemGraphicEl(newIdx, symbolEl); group.add(symbolEl); } }) .update(function (newIdx, oldIdx) { var symbolEl = oldData.getItemGraphicEl(oldIdx); var point = data.getItemLayout(newIdx); if (!symbolNeedsDraw(data, newIdx, isIgnore)) { group.remove(symbolEl); return; } if (!symbolEl) { symbolEl = new SymbolCtor(data, newIdx); symbolEl.attr('position', point); } else { symbolEl.updateData(data, newIdx, seriesScope); graphic.updateProps(symbolEl, { position: point }, seriesModel); } // Add back group.add(symbolEl); data.setItemGraphicEl(newIdx, symbolEl); }) .remove(function (oldIdx) { var el = oldData.getItemGraphicEl(oldIdx); el && el.fadeOut(function () { group.remove(el); }); }) .execute(); this._data = data; }; symbolDrawProto.updateLayout = function () { var data = this._data; if (data) { // Not use animation data.eachItemGraphicEl(function (el, idx) { var point = data.getItemLayout(idx); el.attr('position', point); }); } }; symbolDrawProto.remove = function (enableAnimation) { var group = this.group; var data = this._data; if (data) { if (enableAnimation) { data.eachItemGraphicEl(function (el) { el.fadeOut(function () { group.remove(el); }); }); } else { group.removeAll(); } } }; module.exports = SymbolDraw; /***/ }, /* 106 */ /***/ function(module, exports, __webpack_require__) { /** * @module echarts/chart/helper/Symbol */ var zrUtil = __webpack_require__(4); var symbolUtil = __webpack_require__(107); var graphic = __webpack_require__(43); var numberUtil = __webpack_require__(7); function normalizeSymbolSize(symbolSize) { symbolSize = symbolSize instanceof Array ? symbolSize.slice() : [+symbolSize, +symbolSize]; symbolSize[0] /= 2; symbolSize[1] /= 2; return symbolSize; } /** * @constructor * @alias {module:echarts/chart/helper/Symbol} * @param {module:echarts/data/List} data * @param {number} idx * @extends {module:zrender/graphic/Group} */ function Symbol(data, idx, seriesScope) { graphic.Group.call(this); this.updateData(data, idx, seriesScope); } var symbolProto = Symbol.prototype; function driftSymbol(dx, dy) { this.parent.drift(dx, dy); } symbolProto._createSymbol = function (symbolType, data, idx) { // Remove paths created before this.removeAll(); var seriesModel = data.hostModel; var color = data.getItemVisual(idx, 'color'); // var symbolPath = symbolUtil.createSymbol( // symbolType, -0.5, -0.5, 1, 1, color // ); // If width/height are set too small (e.g., set to 1) on ios10 // and macOS Sierra, a circle stroke become a rect, no matter what // the scale is set. So we set width/height as 2. See #4150. var symbolPath = symbolUtil.createSymbol( symbolType, -1, -1, 2, 2, color ); symbolPath.attr({ z2: 100, culling: true, scale: [0, 0] }); // Rewrite drift method symbolPath.drift = driftSymbol; var size = normalizeSymbolSize(data.getItemVisual(idx, 'symbolSize')); graphic.initProps(symbolPath, { scale: size }, seriesModel, idx); this._symbolType = symbolType; this.add(symbolPath); }; /** * Stop animation * @param {boolean} toLastFrame */ symbolProto.stopSymbolAnimation = function (toLastFrame) { this.childAt(0).stopAnimation(toLastFrame); }; /** * Get symbol path element */ symbolProto.getSymbolPath = function () { return this.childAt(0); }; /** * Get scale(aka, current symbol size). * Including the change caused by animation */ symbolProto.getScale = function () { return this.childAt(0).scale; }; /** * Highlight symbol */ symbolProto.highlight = function () { this.childAt(0).trigger('emphasis'); }; /** * Downplay symbol */ symbolProto.downplay = function () { this.childAt(0).trigger('normal'); }; /** * @param {number} zlevel * @param {number} z */ symbolProto.setZ = function (zlevel, z) { var symbolPath = this.childAt(0); symbolPath.zlevel = zlevel; symbolPath.z = z; }; symbolProto.setDraggable = function (draggable) { var symbolPath = this.childAt(0); symbolPath.draggable = draggable; symbolPath.cursor = draggable ? 'move' : 'pointer'; }; /** * Update symbol properties * @param {module:echarts/data/List} data * @param {number} idx */ symbolProto.updateData = function (data, idx, seriesScope) { this.silent = false; var symbolType = data.getItemVisual(idx, 'symbol') || 'circle'; var seriesModel = data.hostModel; var symbolSize = normalizeSymbolSize(data.getItemVisual(idx, 'symbolSize')); if (symbolType !== this._symbolType) { this._createSymbol(symbolType, data, idx); } else { var symbolPath = this.childAt(0); graphic.updateProps(symbolPath, { scale: symbolSize }, seriesModel, idx); } this._updateCommon(data, idx, symbolSize, seriesScope); this._seriesModel = seriesModel; }; // Update common properties var normalStyleAccessPath = ['itemStyle', 'normal']; var emphasisStyleAccessPath = ['itemStyle', 'emphasis']; var normalLabelAccessPath = ['label', 'normal']; var emphasisLabelAccessPath = ['label', 'emphasis']; symbolProto._updateCommon = function (data, idx, symbolSize, seriesScope) { var symbolPath = this.childAt(0); var seriesModel = data.hostModel; var color = data.getItemVisual(idx, 'color'); // Reset style if (symbolPath.type !== 'image') { symbolPath.useStyle({ strokeNoScale: true }); } seriesScope = seriesScope || null; var itemStyle = seriesScope && seriesScope.itemStyle; var hoverItemStyle = seriesScope && seriesScope.hoverItemStyle; var symbolRotate = seriesScope && seriesScope.symbolRotate; var symbolOffset = seriesScope && seriesScope.symbolOffset; var labelModel = seriesScope && seriesScope.labelModel; var hoverLabelModel = seriesScope && seriesScope.hoverLabelModel; var hoverAnimation = seriesScope && seriesScope.hoverAnimation; if (!seriesScope || data.hasItemOption) { var itemModel = data.getItemModel(idx); // Color must be excluded. // Because symbol provide setColor individually to set fill and stroke itemStyle = itemModel.getModel(normalStyleAccessPath).getItemStyle(['color']); hoverItemStyle = itemModel.getModel(emphasisStyleAccessPath).getItemStyle(); symbolRotate = itemModel.getShallow('symbolRotate'); symbolOffset = itemModel.getShallow('symbolOffset'); labelModel = itemModel.getModel(normalLabelAccessPath); hoverLabelModel = itemModel.getModel(emphasisLabelAccessPath); hoverAnimation = itemModel.getShallow('hoverAnimation'); } else { hoverItemStyle = zrUtil.extend({}, hoverItemStyle); } var elStyle = symbolPath.style; symbolPath.attr('rotation', (symbolRotate || 0) * Math.PI / 180 || 0); if (symbolOffset) { symbolPath.attr('position', [ numberUtil.parsePercent(symbolOffset[0], symbolSize[0]), numberUtil.parsePercent(symbolOffset[1], symbolSize[1]) ]); } // PENDING setColor before setStyle!!! symbolPath.setColor(color); symbolPath.setStyle(itemStyle); var opacity = data.getItemVisual(idx, 'opacity'); if (opacity != null) { elStyle.opacity = opacity; } // Get last value dim var dimensions = data.dimensions.slice(); var valueDim; var dataType; while (dimensions.length && ( valueDim = dimensions.pop(), dataType = data.getDimensionInfo(valueDim).type, dataType === 'ordinal' || dataType === 'time' )) {} // jshint ignore:line if (valueDim != null && labelModel.getShallow('show')) { graphic.setText(elStyle, labelModel, color); elStyle.text = zrUtil.retrieve( seriesModel.getFormattedLabel(idx, 'normal'), data.get(valueDim, idx) ); } else { elStyle.text = ''; } if (valueDim != null && hoverLabelModel.getShallow('show')) { graphic.setText(hoverItemStyle, hoverLabelModel, color); hoverItemStyle.text = zrUtil.retrieve( seriesModel.getFormattedLabel(idx, 'emphasis'), data.get(valueDim, idx) ); } else { hoverItemStyle.text = ''; } var size = normalizeSymbolSize(data.getItemVisual(idx, 'symbolSize')); symbolPath.off('mouseover') .off('mouseout') .off('emphasis') .off('normal'); symbolPath.hoverStyle = hoverItemStyle; graphic.setHoverStyle(symbolPath); if (hoverAnimation && seriesModel.ifEnableAnimation()) { var onEmphasis = function() { var ratio = size[1] / size[0]; this.animateTo({ scale: [ Math.max(size[0] * 1.1, size[0] + 3), Math.max(size[1] * 1.1, size[1] + 3 * ratio) ] }, 400, 'elasticOut'); }; var onNormal = function() { this.animateTo({ scale: size }, 400, 'elasticOut'); }; symbolPath.on('mouseover', onEmphasis) .on('mouseout', onNormal) .on('emphasis', onEmphasis) .on('normal', onNormal); } }; symbolProto.fadeOut = function (cb) { var symbolPath = this.childAt(0); // Avoid mistaken hover when fading out this.silent = true; // Not show text when animating symbolPath.style.text = ''; graphic.updateProps(symbolPath, { scale: [0, 0] }, this._seriesModel, this.dataIndex, cb); }; zrUtil.inherits(Symbol, graphic.Group); module.exports = Symbol; /***/ }, /* 107 */ /***/ function(module, exports, __webpack_require__) { 'use strict'; // Symbol factory var graphic = __webpack_require__(43); var BoundingRect = __webpack_require__(9); /** * Triangle shape * @inner */ var Triangle = graphic.extendShape({ type: 'triangle', shape: { cx: 0, cy: 0, width: 0, height: 0 }, buildPath: function (path, shape) { var cx = shape.cx; var cy = shape.cy; var width = shape.width / 2; var height = shape.height / 2; path.moveTo(cx, cy - height); path.lineTo(cx + width, cy + height); path.lineTo(cx - width, cy + height); path.closePath(); } }); /** * Diamond shape * @inner */ var Diamond = graphic.extendShape({ type: 'diamond', shape: { cx: 0, cy: 0, width: 0, height: 0 }, buildPath: function (path, shape) { var cx = shape.cx; var cy = shape.cy; var width = shape.width / 2; var height = shape.height / 2; path.moveTo(cx, cy - height); path.lineTo(cx + width, cy); path.lineTo(cx, cy + height); path.lineTo(cx - width, cy); path.closePath(); } }); /** * Pin shape * @inner */ var Pin = graphic.extendShape({ type: 'pin', shape: { // x, y on the cusp x: 0, y: 0, width: 0, height: 0 }, buildPath: function (path, shape) { var x = shape.x; var y = shape.y; var w = shape.width / 5 * 3; // Height must be larger than width var h = Math.max(w, shape.height); var r = w / 2; // Dist on y with tangent point and circle center var dy = r * r / (h - r); var cy = y - h + r + dy; var angle = Math.asin(dy / r); // Dist on x with tangent point and circle center var dx = Math.cos(angle) * r; var tanX = Math.sin(angle); var tanY = Math.cos(angle); path.arc( x, cy, r, Math.PI - angle, Math.PI * 2 + angle ); var cpLen = r * 0.6; var cpLen2 = r * 0.7; path.bezierCurveTo( x + dx - tanX * cpLen, cy + dy + tanY * cpLen, x, y - cpLen2, x, y ); path.bezierCurveTo( x, y - cpLen2, x - dx + tanX * cpLen, cy + dy + tanY * cpLen, x - dx, cy + dy ); path.closePath(); } }); /** * Arrow shape * @inner */ var Arrow = graphic.extendShape({ type: 'arrow', shape: { x: 0, y: 0, width: 0, height: 0 }, buildPath: function (ctx, shape) { var height = shape.height; var width = shape.width; var x = shape.x; var y = shape.y; var dx = width / 3 * 2; ctx.moveTo(x, y); ctx.lineTo(x + dx, y + height); ctx.lineTo(x, y + height / 4 * 3); ctx.lineTo(x - dx, y + height); ctx.lineTo(x, y); ctx.closePath(); } }); /** * Map of path contructors * @type {Object.} */ var symbolCtors = { line: graphic.Line, rect: graphic.Rect, roundRect: graphic.Rect, square: graphic.Rect, circle: graphic.Circle, diamond: Diamond, pin: Pin, arrow: Arrow, triangle: Triangle }; var symbolShapeMakers = { line: function (x, y, w, h, shape) { // FIXME shape.x1 = x; shape.y1 = y + h / 2; shape.x2 = x + w; shape.y2 = y + h / 2; }, rect: function (x, y, w, h, shape) { shape.x = x; shape.y = y; shape.width = w; shape.height = h; }, roundRect: function (x, y, w, h, shape) { shape.x = x; shape.y = y; shape.width = w; shape.height = h; shape.r = Math.min(w, h) / 4; }, square: function (x, y, w, h, shape) { var size = Math.min(w, h); shape.x = x; shape.y = y; shape.width = size; shape.height = size; }, circle: function (x, y, w, h, shape) { // Put circle in the center of square shape.cx = x + w / 2; shape.cy = y + h / 2; shape.r = Math.min(w, h) / 2; }, diamond: function (x, y, w, h, shape) { shape.cx = x + w / 2; shape.cy = y + h / 2; shape.width = w; shape.height = h; }, pin: function (x, y, w, h, shape) { shape.x = x + w / 2; shape.y = y + h / 2; shape.width = w; shape.height = h; }, arrow: function (x, y, w, h, shape) { shape.x = x + w / 2; shape.y = y + h / 2; shape.width = w; shape.height = h; }, triangle: function (x, y, w, h, shape) { shape.cx = x + w / 2; shape.cy = y + h / 2; shape.width = w; shape.height = h; } }; var symbolBuildProxies = {}; for (var name in symbolCtors) { if (symbolCtors.hasOwnProperty(name)) { symbolBuildProxies[name] = new symbolCtors[name](); } } var Symbol = graphic.extendShape({ type: 'symbol', shape: { symbolType: '', x: 0, y: 0, width: 0, height: 0 }, beforeBrush: function () { var style = this.style; var shape = this.shape; // FIXME if (shape.symbolType === 'pin' && style.textPosition === 'inside') { style.textPosition = ['50%', '40%']; style.textAlign = 'center'; style.textVerticalAlign = 'middle'; } }, buildPath: function (ctx, shape, inBundle) { var symbolType = shape.symbolType; var proxySymbol = symbolBuildProxies[symbolType]; if (shape.symbolType !== 'none') { if (!proxySymbol) { // Default rect symbolType = 'rect'; proxySymbol = symbolBuildProxies[symbolType]; } symbolShapeMakers[symbolType]( shape.x, shape.y, shape.width, shape.height, proxySymbol.shape ); proxySymbol.buildPath(ctx, proxySymbol.shape, inBundle); } } }); // Provide setColor helper method to avoid determine if set the fill or stroke outside var symbolPathSetColor = function (color) { if (this.type !== 'image') { var symbolStyle = this.style; var symbolShape = this.shape; if (symbolShape && symbolShape.symbolType === 'line') { symbolStyle.stroke = color; } else if (this.__isEmptyBrush) { symbolStyle.stroke = color; symbolStyle.fill = '#fff'; } else { // FIXME 判断图形默认是填充还是描边,使用 onlyStroke ? symbolStyle.fill && (symbolStyle.fill = color); symbolStyle.stroke && (symbolStyle.stroke = color); } this.dirty(false); } }; var symbolUtil = { /** * Create a symbol element with given symbol configuration: shape, x, y, width, height, color * @param {string} symbolType * @param {number} x * @param {number} y * @param {number} w * @param {number} h * @param {string} color */ createSymbol: function (symbolType, x, y, w, h, color) { var isEmpty = symbolType.indexOf('empty') === 0; if (isEmpty) { symbolType = symbolType.substr(5, 1).toLowerCase() + symbolType.substr(6); } var symbolPath; if (symbolType.indexOf('image://') === 0) { symbolPath = new graphic.Image({ style: { image: symbolType.slice(8), x: x, y: y, width: w, height: h } }); } else if (symbolType.indexOf('path://') === 0) { symbolPath = graphic.makePath(symbolType.slice(7), {}, new BoundingRect(x, y, w, h)); } else { symbolPath = new Symbol({ shape: { symbolType: symbolType, x: x, y: y, width: w, height: h } }); } symbolPath.__isEmptyBrush = isEmpty; symbolPath.setColor = symbolPathSetColor; symbolPath.setColor(color); return symbolPath; } }; module.exports = symbolUtil; /***/ }, /* 108 */ /***/ function(module, exports) { // var arrayDiff = require('zrender/lib/core/arrayDiff'); // 'zrender/core/arrayDiff' has been used before, but it did // not do well in performance when roam with fixed dataZoom window. function sign(val) { return val >= 0 ? 1 : -1; } function getStackedOnPoint(coordSys, data, idx) { var baseAxis = coordSys.getBaseAxis(); var valueAxis = coordSys.getOtherAxis(baseAxis); var valueStart = baseAxis.onZero ? 0 : valueAxis.scale.getExtent()[0]; var valueDim = valueAxis.dim; var baseDataOffset = valueDim === 'x' || valueDim === 'radius' ? 1 : 0; var stackedOnSameSign; var stackedOn = data.stackedOn; var val = data.get(valueDim, idx); // Find first stacked value with same sign while (stackedOn && sign(stackedOn.get(valueDim, idx)) === sign(val) ) { stackedOnSameSign = stackedOn; break; } var stackedData = []; stackedData[baseDataOffset] = data.get(baseAxis.dim, idx); stackedData[1 - baseDataOffset] = stackedOnSameSign ? stackedOnSameSign.get(valueDim, idx, true) : valueStart; return coordSys.dataToPoint(stackedData); } // function convertToIntId(newIdList, oldIdList) { // // Generate int id instead of string id. // // Compare string maybe slow in score function of arrDiff // // Assume id in idList are all unique // var idIndicesMap = {}; // var idx = 0; // for (var i = 0; i < newIdList.length; i++) { // idIndicesMap[newIdList[i]] = idx; // newIdList[i] = idx++; // } // for (var i = 0; i < oldIdList.length; i++) { // var oldId = oldIdList[i]; // // Same with newIdList // if (idIndicesMap[oldId]) { // oldIdList[i] = idIndicesMap[oldId]; // } // else { // oldIdList[i] = idx++; // } // } // } function diffData(oldData, newData) { var diffResult = []; newData.diff(oldData) .add(function (idx) { diffResult.push({cmd: '+', idx: idx}); }) .update(function (newIdx, oldIdx) { diffResult.push({cmd: '=', idx: oldIdx, idx1: newIdx}); }) .remove(function (idx) { diffResult.push({cmd: '-', idx: idx}); }) .execute(); return diffResult; } module.exports = function ( oldData, newData, oldStackedOnPoints, newStackedOnPoints, oldCoordSys, newCoordSys ) { var diff = diffData(oldData, newData); // var newIdList = newData.mapArray(newData.getId); // var oldIdList = oldData.mapArray(oldData.getId); // convertToIntId(newIdList, oldIdList); // // FIXME One data ? // diff = arrayDiff(oldIdList, newIdList); var currPoints = []; var nextPoints = []; // Points for stacking base line var currStackedPoints = []; var nextStackedPoints = []; var status = []; var sortedIndices = []; var rawIndices = []; var dims = newCoordSys.dimensions; for (var i = 0; i < diff.length; i++) { var diffItem = diff[i]; var pointAdded = true; // FIXME, animation is not so perfect when dataZoom window moves fast // Which is in case remvoing or add more than one data in the tail or head switch (diffItem.cmd) { case '=': var currentPt = oldData.getItemLayout(diffItem.idx); var nextPt = newData.getItemLayout(diffItem.idx1); // If previous data is NaN, use next point directly if (isNaN(currentPt[0]) || isNaN(currentPt[1])) { currentPt = nextPt.slice(); } currPoints.push(currentPt); nextPoints.push(nextPt); currStackedPoints.push(oldStackedOnPoints[diffItem.idx]); nextStackedPoints.push(newStackedOnPoints[diffItem.idx1]); rawIndices.push(newData.getRawIndex(diffItem.idx1)); break; case '+': var idx = diffItem.idx; currPoints.push( oldCoordSys.dataToPoint([ newData.get(dims[0], idx, true), newData.get(dims[1], idx, true) ]) ); nextPoints.push(newData.getItemLayout(idx).slice()); currStackedPoints.push( getStackedOnPoint(oldCoordSys, newData, idx) ); nextStackedPoints.push(newStackedOnPoints[idx]); rawIndices.push(newData.getRawIndex(idx)); break; case '-': var idx = diffItem.idx; var rawIndex = oldData.getRawIndex(idx); // Data is replaced. In the case of dynamic data queue // FIXME FIXME FIXME if (rawIndex !== idx) { currPoints.push(oldData.getItemLayout(idx)); nextPoints.push(newCoordSys.dataToPoint([ oldData.get(dims[0], idx, true), oldData.get(dims[1], idx, true) ])); currStackedPoints.push(oldStackedOnPoints[idx]); nextStackedPoints.push( getStackedOnPoint( newCoordSys, oldData, idx ) ); rawIndices.push(rawIndex); } else { pointAdded = false; } } // Original indices if (pointAdded) { status.push(diffItem); sortedIndices.push(sortedIndices.length); } } // Diff result may be crossed if all items are changed // Sort by data index sortedIndices.sort(function (a, b) { return rawIndices[a] - rawIndices[b]; }); var sortedCurrPoints = []; var sortedNextPoints = []; var sortedCurrStackedPoints = []; var sortedNextStackedPoints = []; var sortedStatus = []; for (var i = 0; i < sortedIndices.length; i++) { var idx = sortedIndices[i]; sortedCurrPoints[i] = currPoints[idx]; sortedNextPoints[i] = nextPoints[idx]; sortedCurrStackedPoints[i] = currStackedPoints[idx]; sortedNextStackedPoints[i] = nextStackedPoints[idx]; sortedStatus[i] = status[idx]; } return { current: sortedCurrPoints, next: sortedNextPoints, stackedOnCurrent: sortedCurrStackedPoints, stackedOnNext: sortedNextStackedPoints, status: sortedStatus }; }; /***/ }, /* 109 */ /***/ function(module, exports, __webpack_require__) { // Poly path support NaN point var Path = __webpack_require__(45); var vec2 = __webpack_require__(10); var vec2Min = vec2.min; var vec2Max = vec2.max; var scaleAndAdd = vec2.scaleAndAdd; var v2Copy = vec2.copy; // Temporary variable var v = []; var cp0 = []; var cp1 = []; function isPointNull(p) { return isNaN(p[0]) || isNaN(p[1]); } function drawSegment( ctx, points, start, segLen, allLen, dir, smoothMin, smoothMax, smooth, smoothMonotone, connectNulls ) { var prevIdx = 0; var idx = start; for (var k = 0; k < segLen; k++) { var p = points[idx]; if (idx >= allLen || idx < 0) { break; } if (isPointNull(p)) { if (connectNulls) { idx += dir; continue; } break; } if (idx === start) { ctx[dir > 0 ? 'moveTo' : 'lineTo'](p[0], p[1]); v2Copy(cp0, p); } else { if (smooth > 0) { var nextIdx = idx + dir; var nextP = points[nextIdx]; if (connectNulls) { // Find next point not null while (nextP && isPointNull(points[nextIdx])) { nextIdx += dir; nextP = points[nextIdx]; } } var ratioNextSeg = 0.5; var prevP = points[prevIdx]; var nextP = points[nextIdx]; // Last point if (!nextP || isPointNull(nextP)) { v2Copy(cp1, p); } else { // If next data is null in not connect case if (isPointNull(nextP) && !connectNulls) { nextP = p; } vec2.sub(v, nextP, prevP); var lenPrevSeg; var lenNextSeg; if (smoothMonotone === 'x' || smoothMonotone === 'y') { var dim = smoothMonotone === 'x' ? 0 : 1; lenPrevSeg = Math.abs(p[dim] - prevP[dim]); lenNextSeg = Math.abs(p[dim] - nextP[dim]); } else { lenPrevSeg = vec2.dist(p, prevP); lenNextSeg = vec2.dist(p, nextP); } // Use ratio of seg length ratioNextSeg = lenNextSeg / (lenNextSeg + lenPrevSeg); scaleAndAdd(cp1, p, v, -smooth * (1 - ratioNextSeg)); } // Smooth constraint vec2Min(cp0, cp0, smoothMax); vec2Max(cp0, cp0, smoothMin); vec2Min(cp1, cp1, smoothMax); vec2Max(cp1, cp1, smoothMin); ctx.bezierCurveTo( cp0[0], cp0[1], cp1[0], cp1[1], p[0], p[1] ); // cp0 of next segment scaleAndAdd(cp0, p, v, smooth * ratioNextSeg); } else { ctx.lineTo(p[0], p[1]); } } prevIdx = idx; idx += dir; } return k; } function getBoundingBox(points, smoothConstraint) { var ptMin = [Infinity, Infinity]; var ptMax = [-Infinity, -Infinity]; if (smoothConstraint) { for (var i = 0; i < points.length; i++) { var pt = points[i]; if (pt[0] < ptMin[0]) { ptMin[0] = pt[0]; } if (pt[1] < ptMin[1]) { ptMin[1] = pt[1]; } if (pt[0] > ptMax[0]) { ptMax[0] = pt[0]; } if (pt[1] > ptMax[1]) { ptMax[1] = pt[1]; } } } return { min: smoothConstraint ? ptMin : ptMax, max: smoothConstraint ? ptMax : ptMin }; } module.exports = { Polyline: Path.extend({ type: 'ec-polyline', shape: { points: [], smooth: 0, smoothConstraint: true, smoothMonotone: null, connectNulls: false }, style: { fill: null, stroke: '#000' }, buildPath: function (ctx, shape) { var points = shape.points; var i = 0; var len = points.length; var result = getBoundingBox(points, shape.smoothConstraint); if (shape.connectNulls) { // Must remove first and last null values avoid draw error in polygon for (; len > 0; len--) { if (!isPointNull(points[len - 1])) { break; } } for (; i < len; i++) { if (!isPointNull(points[i])) { break; } } } while (i < len) { i += drawSegment( ctx, points, i, len, len, 1, result.min, result.max, shape.smooth, shape.smoothMonotone, shape.connectNulls ) + 1; } } }), Polygon: Path.extend({ type: 'ec-polygon', shape: { points: [], // Offset between stacked base points and points stackedOnPoints: [], smooth: 0, stackedOnSmooth: 0, smoothConstraint: true, smoothMonotone: null, connectNulls: false }, buildPath: function (ctx, shape) { var points = shape.points; var stackedOnPoints = shape.stackedOnPoints; var i = 0; var len = points.length; var smoothMonotone = shape.smoothMonotone; var bbox = getBoundingBox(points, shape.smoothConstraint); var stackedOnBBox = getBoundingBox(stackedOnPoints, shape.smoothConstraint); if (shape.connectNulls) { // Must remove first and last null values avoid draw error in polygon for (; len > 0; len--) { if (!isPointNull(points[len - 1])) { break; } } for (; i < len; i++) { if (!isPointNull(points[i])) { break; } } } while (i < len) { var k = drawSegment( ctx, points, i, len, len, 1, bbox.min, bbox.max, shape.smooth, smoothMonotone, shape.connectNulls ); drawSegment( ctx, stackedOnPoints, i + k - 1, k, len, -1, stackedOnBBox.min, stackedOnBBox.max, shape.stackedOnSmooth, smoothMonotone, shape.connectNulls ); i += k + 1; ctx.closePath(); } } }) }; /***/ }, /* 110 */ /***/ function(module, exports) { module.exports = function (seriesType, defaultSymbolType, legendSymbol, ecModel, api) { // Encoding visual for all series include which is filtered for legend drawing ecModel.eachRawSeriesByType(seriesType, function (seriesModel) { var data = seriesModel.getData(); var symbolType = seriesModel.get('symbol') || defaultSymbolType; var symbolSize = seriesModel.get('symbolSize'); data.setVisual({ legendSymbol: legendSymbol || symbolType, symbol: symbolType, symbolSize: symbolSize }); // Only visible series has each data be visual encoded if (!ecModel.isSeriesFiltered(seriesModel)) { if (typeof symbolSize === 'function') { data.each(function (idx) { var rawValue = seriesModel.getRawValue(idx); // FIXME var params = seriesModel.getDataParams(idx); data.setItemVisual(idx, 'symbolSize', symbolSize(rawValue, params)); }); } data.each(function (idx) { var itemModel = data.getItemModel(idx); var itemSymbolType = itemModel.getShallow('symbol', true); var itemSymbolSize = itemModel.getShallow('symbolSize', true); // If has item symbol if (itemSymbolType != null) { data.setItemVisual(idx, 'symbol', itemSymbolType); } if (itemSymbolSize != null) { // PENDING Transform symbolSize ? data.setItemVisual(idx, 'symbolSize', itemSymbolSize); } }); } }); }; /***/ }, /* 111 */ /***/ function(module, exports) { module.exports = function (seriesType, ecModel) { ecModel.eachSeriesByType(seriesType, function (seriesModel) { var data = seriesModel.getData(); var coordSys = seriesModel.coordinateSystem; if (coordSys) { var dims = coordSys.dimensions; if (coordSys.type === 'singleAxis') { data.each(dims[0], function (x, idx) { // Also {Array.}, not undefined to avoid if...else... statement data.setItemLayout(idx, isNaN(x) ? [NaN, NaN] : coordSys.dataToPoint(x)); }); } else { data.each(dims, function (x, y, idx) { // Also {Array.}, not undefined to avoid if...else... statement data.setItemLayout( idx, (isNaN(x) || isNaN(y)) ? [NaN, NaN] : coordSys.dataToPoint([x, y]) ); }, true); } } }); }; /***/ }, /* 112 */ /***/ function(module, exports) { var samplers = { average: function (frame) { var sum = 0; var count = 0; for (var i = 0; i < frame.length; i++) { if (!isNaN(frame[i])) { sum += frame[i]; count++; } } // Return NaN if count is 0 return count === 0 ? NaN : sum / count; }, sum: function (frame) { var sum = 0; for (var i = 0; i < frame.length; i++) { // Ignore NaN sum += frame[i] || 0; } return sum; }, max: function (frame) { var max = -Infinity; for (var i = 0; i < frame.length; i++) { frame[i] > max && (max = frame[i]); } return max; }, min: function (frame) { var min = Infinity; for (var i = 0; i < frame.length; i++) { frame[i] < min && (min = frame[i]); } return min; }, // TODO // Median nearest: function (frame) { return frame[0]; } }; var indexSampler = function (frame, value) { return Math.round(frame.length / 2); }; module.exports = function (seriesType, ecModel, api) { ecModel.eachSeriesByType(seriesType, function (seriesModel) { var data = seriesModel.getData(); var sampling = seriesModel.get('sampling'); var coordSys = seriesModel.coordinateSystem; // Only cartesian2d support down sampling if (coordSys.type === 'cartesian2d' && sampling) { var baseAxis = coordSys.getBaseAxis(); var valueAxis = coordSys.getOtherAxis(baseAxis); var extent = baseAxis.getExtent(); // Coordinste system has been resized var size = extent[1] - extent[0]; var rate = Math.round(data.count() / size); if (rate > 1) { var sampler; if (typeof sampling === 'string') { sampler = samplers[sampling]; } else if (typeof sampling === 'function') { sampler = sampling; } if (sampler) { data = data.downSample( valueAxis.dim, 1 / rate, sampler, indexSampler ); seriesModel.setData(data); } } } }, this); }; /***/ }, /* 113 */ /***/ function(module, exports, __webpack_require__) { 'use strict'; var graphic = __webpack_require__(43); var zrUtil = __webpack_require__(4); var echarts = __webpack_require__(1); __webpack_require__(114); __webpack_require__(132); // Grid view echarts.extendComponentView({ type: 'grid', render: function (gridModel, ecModel) { this.group.removeAll(); if (gridModel.get('show')) { this.group.add(new graphic.Rect({ shape: gridModel.coordinateSystem.getRect(), style: zrUtil.defaults({ fill: gridModel.get('backgroundColor') }, gridModel.getItemStyle()), silent: true, z2: -1 })); } } }); echarts.registerPreprocessor(function (option) { // Only create grid when need if (option.xAxis && option.yAxis && !option.grid) { option.grid = {}; } }); /***/ }, /* 114 */ /***/ function(module, exports, __webpack_require__) { /** * Grid is a region which contains at most 4 cartesian systems * * TODO Default cartesian */ var factory = exports; var layout = __webpack_require__(21); var axisHelper = __webpack_require__(115); var zrUtil = __webpack_require__(4); var Cartesian2D = __webpack_require__(121); var Axis2D = __webpack_require__(123); var each = zrUtil.each; var ifAxisCrossZero = axisHelper.ifAxisCrossZero; var niceScaleExtent = axisHelper.niceScaleExtent; // 依赖 GridModel, AxisModel 做预处理 __webpack_require__(126); /** * Check if the axis is used in the specified grid * @inner */ function isAxisUsedInTheGrid(axisModel, gridModel, ecModel) { return axisModel.findGridModel() === gridModel; } function getLabelUnionRect(axis) { var axisModel = axis.model; var labels = axisModel.getFormattedLabels(); var textStyleModel = axisModel.getModel('axisLabel.textStyle'); var rect; var step = 1; var labelCount = labels.length; if (labelCount > 40) { // Simple optimization for large amount of labels step = Math.ceil(labelCount / 40); } for (var i = 0; i < labelCount; i += step) { if (!axis.isLabelIgnored(i)) { var singleRect = textStyleModel.getTextRect(labels[i]); // FIXME consider label rotate rect ? rect.union(singleRect) : (rect = singleRect); } } return rect; } function Grid(gridModel, ecModel, api) { /** * @type {Object.} * @private */ this._coordsMap = {}; /** * @type {Array.} * @private */ this._coordsList = []; /** * @type {Object.} * @private */ this._axesMap = {}; /** * @type {Array.} * @private */ this._axesList = []; this._initCartesian(gridModel, ecModel, api); this._model = gridModel; } var gridProto = Grid.prototype; gridProto.type = 'grid'; gridProto.getRect = function () { return this._rect; }; gridProto.update = function (ecModel, api) { var axesMap = this._axesMap; this._updateScale(ecModel, this._model); function ifAxisCanNotOnZero(otherAxisDim) { var axes = axesMap[otherAxisDim]; for (var idx in axes) { if (axes.hasOwnProperty(idx)) { var axis = axes[idx]; if (axis && (axis.type === 'category' || !ifAxisCrossZero(axis))) { return true; } } } return false; } each(axesMap.x, function (xAxis) { niceScaleExtent(xAxis, xAxis.model); }); each(axesMap.y, function (yAxis) { niceScaleExtent(yAxis, yAxis.model); }); // Fix configuration each(axesMap.x, function (xAxis) { // onZero can not be enabled in these two situations // 1. When any other axis is a category axis // 2. When any other axis not across 0 point if (ifAxisCanNotOnZero('y')) { xAxis.onZero = false; } }); each(axesMap.y, function (yAxis) { if (ifAxisCanNotOnZero('x')) { yAxis.onZero = false; } }); // Resize again if containLabel is enabled // FIXME It may cause getting wrong grid size in data processing stage this.resize(this._model, api); }; /** * Resize the grid * @param {module:echarts/coord/cartesian/GridModel} gridModel * @param {module:echarts/ExtensionAPI} api */ gridProto.resize = function (gridModel, api) { var gridRect = layout.getLayoutRect( gridModel.getBoxLayoutParams(), { width: api.getWidth(), height: api.getHeight() }); this._rect = gridRect; var axesList = this._axesList; adjustAxes(); // Minus label size if (gridModel.get('containLabel')) { each(axesList, function (axis) { if (!axis.model.get('axisLabel.inside')) { var labelUnionRect = getLabelUnionRect(axis); if (labelUnionRect) { var dim = axis.isHorizontal() ? 'height' : 'width'; var margin = axis.model.get('axisLabel.margin'); gridRect[dim] -= labelUnionRect[dim] + margin; if (axis.position === 'top') { gridRect.y += labelUnionRect.height + margin; } else if (axis.position === 'left') { gridRect.x += labelUnionRect.width + margin; } } } }); adjustAxes(); } function adjustAxes() { each(axesList, function (axis) { var isHorizontal = axis.isHorizontal(); var extent = isHorizontal ? [0, gridRect.width] : [0, gridRect.height]; var idx = axis.inverse ? 1 : 0; axis.setExtent(extent[idx], extent[1 - idx]); updateAxisTransfrom(axis, isHorizontal ? gridRect.x : gridRect.y); }); } }; /** * @param {string} axisType * @param {ndumber} [axisIndex] */ gridProto.getAxis = function (axisType, axisIndex) { var axesMapOnDim = this._axesMap[axisType]; if (axesMapOnDim != null) { if (axisIndex == null) { // Find first axis for (var name in axesMapOnDim) { if (axesMapOnDim.hasOwnProperty(name)) { return axesMapOnDim[name]; } } } return axesMapOnDim[axisIndex]; } }; gridProto.getCartesian = function (xAxisIndex, yAxisIndex) { if (xAxisIndex != null && yAxisIndex != null) { var key = 'x' + xAxisIndex + 'y' + yAxisIndex; return this._coordsMap[key]; } else { // When only xAxisIndex or yAxisIndex given, find its first cartesian. for (var i = 0, coordList = this._coordsList; i < coordList.length; i++) { if (coordList[i].getAxis('x').index === xAxisIndex || coordList[i].getAxis('y').index === yAxisIndex ) { return coordList[i]; } } } }; /** * @implements * see {module:echarts/CoodinateSystem} */ gridProto.convertToPixel = function (ecModel, finder, value) { var target = this._findConvertTarget(ecModel, finder); return target.cartesian ? target.cartesian.dataToPoint(value) : target.axis ? target.axis.toGlobalCoord(target.axis.dataToCoord(value)) : null; }; /** * @implements * see {module:echarts/CoodinateSystem} */ gridProto.convertFromPixel = function (ecModel, finder, value) { var target = this._findConvertTarget(ecModel, finder); return target.cartesian ? target.cartesian.pointToData(value) : target.axis ? target.axis.coordToData(target.axis.toLocalCoord(value)) : null; }; /** * @inner */ gridProto._findConvertTarget = function (ecModel, finder) { var seriesModel = finder.seriesModel; var xAxisModel = finder.xAxisModel || (seriesModel && seriesModel.getReferringComponents('xAxis')[0]); var yAxisModel = finder.yAxisModel || (seriesModel && seriesModel.getReferringComponents('yAxis')[0]); var gridModel = finder.gridModel; var coordsList = this._coordsList; var cartesian; var axis; if (seriesModel) { cartesian = seriesModel.coordinateSystem; zrUtil.indexOf(coordsList, cartesian) < 0 && (cartesian = null); } else if (xAxisModel && yAxisModel) { cartesian = this.getCartesian(xAxisModel.componentIndex, yAxisModel.componentIndex); } else if (xAxisModel) { axis = this.getAxis('x', xAxisModel.componentIndex); } else if (yAxisModel) { axis = this.getAxis('y', yAxisModel.componentIndex); } // Lowest priority. else if (gridModel) { var grid = gridModel.coordinateSystem; if (grid === this) { cartesian = this._coordsList[0]; } } return {cartesian: cartesian, axis: axis}; }; /** * @implements * see {module:echarts/CoodinateSystem} */ gridProto.containPoint = function (point) { var coord = this._coordsList[0]; if (coord) { return coord.containPoint(point); } }; /** * Initialize cartesian coordinate systems * @private */ gridProto._initCartesian = function (gridModel, ecModel, api) { var axisPositionUsed = { left: false, right: false, top: false, bottom: false }; var axesMap = { x: {}, y: {} }; var axesCount = { x: 0, y: 0 }; /// Create axis ecModel.eachComponent('xAxis', createAxisCreator('x'), this); ecModel.eachComponent('yAxis', createAxisCreator('y'), this); if (!axesCount.x || !axesCount.y) { // Roll back when there no either x or y axis this._axesMap = {}; this._axesList = []; return; } this._axesMap = axesMap; /// Create cartesian2d each(axesMap.x, function (xAxis, xAxisIndex) { each(axesMap.y, function (yAxis, yAxisIndex) { var key = 'x' + xAxisIndex + 'y' + yAxisIndex; var cartesian = new Cartesian2D(key); cartesian.grid = this; this._coordsMap[key] = cartesian; this._coordsList.push(cartesian); cartesian.addAxis(xAxis); cartesian.addAxis(yAxis); }, this); }, this); function createAxisCreator(axisType) { return function (axisModel, idx) { if (!isAxisUsedInTheGrid(axisModel, gridModel, ecModel)) { return; } var axisPosition = axisModel.get('position'); if (axisType === 'x') { // Fix position if (axisPosition !== 'top' && axisPosition !== 'bottom') { // Default bottom of X axisPosition = 'bottom'; if (axisPositionUsed[axisPosition]) { axisPosition = axisPosition === 'top' ? 'bottom' : 'top'; } } } else { // Fix position if (axisPosition !== 'left' && axisPosition !== 'right') { // Default left of Y axisPosition = 'left'; if (axisPositionUsed[axisPosition]) { axisPosition = axisPosition === 'left' ? 'right' : 'left'; } } } axisPositionUsed[axisPosition] = true; var axis = new Axis2D( axisType, axisHelper.createScaleByModel(axisModel), [0, 0], axisModel.get('type'), axisPosition ); var isCategory = axis.type === 'category'; axis.onBand = isCategory && axisModel.get('boundaryGap'); axis.inverse = axisModel.get('inverse'); axis.onZero = axisModel.get('axisLine.onZero'); // Inject axis into axisModel axisModel.axis = axis; // Inject axisModel into axis axis.model = axisModel; // Inject grid info axis axis.grid = this; // Index of axis, can be used as key axis.index = idx; this._axesList.push(axis); axesMap[axisType][idx] = axis; axesCount[axisType]++; }; } }; /** * Update cartesian properties from series * @param {module:echarts/model/Option} option * @private */ gridProto._updateScale = function (ecModel, gridModel) { // Reset scale zrUtil.each(this._axesList, function (axis) { axis.scale.setExtent(Infinity, -Infinity); }); ecModel.eachSeries(function (seriesModel) { if (isCartesian2D(seriesModel)) { var axesModels = findAxesModels(seriesModel, ecModel); var xAxisModel = axesModels[0]; var yAxisModel = axesModels[1]; if (!isAxisUsedInTheGrid(xAxisModel, gridModel, ecModel) || !isAxisUsedInTheGrid(yAxisModel, gridModel, ecModel) ) { return; } var cartesian = this.getCartesian( xAxisModel.componentIndex, yAxisModel.componentIndex ); var data = seriesModel.getData(); var xAxis = cartesian.getAxis('x'); var yAxis = cartesian.getAxis('y'); if (data.type === 'list') { unionExtent(data, xAxis, seriesModel); unionExtent(data, yAxis, seriesModel); } } }, this); function unionExtent(data, axis, seriesModel) { each(seriesModel.coordDimToDataDim(axis.dim), function (dim) { axis.scale.unionExtent(data.getDataExtent( dim, axis.scale.type !== 'ordinal' )); }); } }; /** * @inner */ function updateAxisTransfrom(axis, coordBase) { var axisExtent = axis.getExtent(); var axisExtentSum = axisExtent[0] + axisExtent[1]; // Fast transform axis.toGlobalCoord = axis.dim === 'x' ? function (coord) { return coord + coordBase; } : function (coord) { return axisExtentSum - coord + coordBase; }; axis.toLocalCoord = axis.dim === 'x' ? function (coord) { return coord - coordBase; } : function (coord) { return axisExtentSum - coord + coordBase; }; } var axesTypes = ['xAxis', 'yAxis']; /** * @inner */ function findAxesModels(seriesModel, ecModel) { return zrUtil.map(axesTypes, function (axisType) { var axisModel = seriesModel.getReferringComponents(axisType)[0]; if (true) { if (!axisModel) { throw new Error(axisType + ' "' + zrUtil.retrieve( seriesModel.get(axisType + 'Index'), seriesModel.get(axisType + 'Id'), 0 ) + '" not found'); } } return axisModel; }); } /** * @inner */ function isCartesian2D(seriesModel) { return seriesModel.get('coordinateSystem') === 'cartesian2d'; } Grid.create = function (ecModel, api) { var grids = []; ecModel.eachComponent('grid', function (gridModel, idx) { var grid = new Grid(gridModel, ecModel, api); grid.name = 'grid_' + idx; grid.resize(gridModel, api); gridModel.coordinateSystem = grid; grids.push(grid); }); // Inject the coordinateSystems into seriesModel ecModel.eachSeries(function (seriesModel) { if (!isCartesian2D(seriesModel)) { return; } var axesModels = findAxesModels(seriesModel, ecModel); var xAxisModel = axesModels[0]; var yAxisModel = axesModels[1]; var gridModel = xAxisModel.findGridModel(); if (true) { if (!gridModel) { throw new Error( 'Grid "' + zrUtil.retrieve( xAxisModel.get('gridIndex'), xAxisModel.get('gridId'), 0 ) + '" not found' ); } if (xAxisModel.findGridModel() !== yAxisModel.findGridModel()) { throw new Error('xAxis and yAxis must use the same grid'); } } var grid = gridModel.coordinateSystem; seriesModel.coordinateSystem = grid.getCartesian( xAxisModel.componentIndex, yAxisModel.componentIndex ); }); return grids; }; // For deciding which dimensions to use when creating list data Grid.dimensions = Cartesian2D.prototype.dimensions; __webpack_require__(26).register('cartesian2d', Grid); module.exports = Grid; /***/ }, /* 115 */ /***/ function(module, exports, __webpack_require__) { var OrdinalScale = __webpack_require__(116); var IntervalScale = __webpack_require__(118); __webpack_require__(119); __webpack_require__(120); var Scale = __webpack_require__(117); var numberUtil = __webpack_require__(7); var zrUtil = __webpack_require__(4); var textContain = __webpack_require__(8); var axisHelper = {}; /** * Get axis scale extent before niced. */ axisHelper.getScaleExtent = function (axis, model) { var scale = axis.scale; var originalExtent = scale.getExtent(); var span = originalExtent[1] - originalExtent[0]; if (scale.type === 'ordinal') { // If series has no data, scale extent may be wrong if (!isFinite(span)) { return [0, 0]; } else { return originalExtent; } } var min = model.getMin ? model.getMin() : model.get('min'); var max = model.getMax ? model.getMax() : model.get('max'); var crossZero = model.getNeedCrossZero ? model.getNeedCrossZero() : !model.get('scale'); var boundaryGap = model.get('boundaryGap'); if (!zrUtil.isArray(boundaryGap)) { boundaryGap = [boundaryGap || 0, boundaryGap || 0]; } boundaryGap[0] = numberUtil.parsePercent(boundaryGap[0], 1); boundaryGap[1] = numberUtil.parsePercent(boundaryGap[1], 1); var fixMin = true; var fixMax = true; // Add boundary gap if (min == null) { min = originalExtent[0] - boundaryGap[0] * span; fixMin = false; } if (max == null) { max = originalExtent[1] + boundaryGap[1] * span; fixMax = false; } if (min === 'dataMin') { min = originalExtent[0]; } if (max === 'dataMax') { max = originalExtent[1]; } // Evaluate if axis needs cross zero if (crossZero) { // Axis is over zero and min is not set if (min > 0 && max > 0 && !fixMin) { min = 0; } // Axis is under zero and max is not set if (min < 0 && max < 0 && !fixMax) { max = 0; } } return [min, max]; }; axisHelper.niceScaleExtent = function (axis, model) { var scale = axis.scale; var extent = axisHelper.getScaleExtent(axis, model); var fixMin = (model.getMin ? model.getMin() : model.get('min')) != null; var fixMax = (model.getMax ? model.getMax() : model.get('max')) != null; var splitNumber = model.get('splitNumber'); if (scale.type === 'log') { scale.base = model.get('logBase'); } scale.setExtent(extent[0], extent[1]); scale.niceExtent(splitNumber, fixMin, fixMax); // Use minInterval to constraint the calculated interval. // If calculated interval is less than minInterval. increase the interval quantity until // it is larger than minInterval. // For example: // minInterval is 1, calculated interval is 0.2, so increase it to be 1. In this way we can get // an integer axis. var minInterval = model.get('minInterval'); if (isFinite(minInterval) && !fixMin && !fixMax && scale.type === 'interval') { var interval = scale.getInterval(); var intervalScale = Math.max(Math.abs(interval), minInterval) / interval; // while (interval < minInterval) { // var quantity = numberUtil.quantity(interval); // interval = quantity * 10; // scaleQuantity *= 10; // } extent = scale.getExtent(); var origin = (extent[1] + extent[0]) / 2; scale.setExtent( intervalScale * (extent[0] - origin) + origin, intervalScale * (extent[1] - origin) + origin ); scale.niceExtent(splitNumber); } // If some one specified the min, max. And the default calculated interval // is not good enough. He can specify the interval. It is often appeared // in angle axis with angle 0 - 360. Interval calculated in interval scale is hard // to be 60. // FIXME var interval = model.get('interval'); if (interval != null) { scale.setInterval && scale.setInterval(interval); } }; /** * @param {module:echarts/model/Model} model * @param {string} [axisType] Default retrieve from model.type * @return {module:echarts/scale/*} */ axisHelper.createScaleByModel = function(model, axisType) { axisType = axisType || model.get('type'); if (axisType) { switch (axisType) { // Buildin scale case 'category': return new OrdinalScale( model.getCategories(), [Infinity, -Infinity] ); case 'value': return new IntervalScale(); // Extended scale, like time and log default: return (Scale.getClass(axisType) || IntervalScale).create(model); } } }; /** * Check if the axis corss 0 */ axisHelper.ifAxisCrossZero = function (axis) { var dataExtent = axis.scale.getExtent(); var min = dataExtent[0]; var max = dataExtent[1]; return !((min > 0 && max > 0) || (min < 0 && max < 0)); }; /** * @param {Array.} tickCoords In axis self coordinate. * @param {Array.} labels * @param {string} font * @param {boolean} isAxisHorizontal * @return {number} */ axisHelper.getAxisLabelInterval = function (tickCoords, labels, font, isAxisHorizontal) { // FIXME // 不同角的axis和label,不只是horizontal和vertical. var textSpaceTakenRect; var autoLabelInterval = 0; var accumulatedLabelInterval = 0; var step = 1; if (labels.length > 40) { // Simple optimization for large amount of labels step = Math.floor(labels.length / 40); } for (var i = 0; i < tickCoords.length; i += step) { var tickCoord = tickCoords[i]; var rect = textContain.getBoundingRect( labels[i], font, 'center', 'top' ); rect[isAxisHorizontal ? 'x' : 'y'] += tickCoord; // FIXME Magic number 1.5 rect[isAxisHorizontal ? 'width' : 'height'] *= 1.3; if (!textSpaceTakenRect) { textSpaceTakenRect = rect.clone(); } // There is no space for current label; else if (textSpaceTakenRect.intersect(rect)) { accumulatedLabelInterval++; autoLabelInterval = Math.max(autoLabelInterval, accumulatedLabelInterval); } else { textSpaceTakenRect.union(rect); // Reset accumulatedLabelInterval = 0; } } if (autoLabelInterval === 0 && step > 1) { return step; } return (autoLabelInterval + 1) * step - 1; }; /** * @param {Object} axis * @param {Function} labelFormatter * @return {Array.} */ axisHelper.getFormattedLabels = function (axis, labelFormatter) { var scale = axis.scale; var labels = scale.getTicksLabels(); var ticks = scale.getTicks(); if (typeof labelFormatter === 'string') { labelFormatter = (function (tpl) { return function (val) { return tpl.replace('{value}', val != null ? val : ''); }; })(labelFormatter); // Consider empty array return zrUtil.map(labels, labelFormatter); } else if (typeof labelFormatter === 'function') { return zrUtil.map(ticks, function (tick, idx) { return labelFormatter( axis.type === 'category' ? scale.getLabel(tick) : tick, idx ); }, this); } else { return labels; } }; module.exports = axisHelper; /***/ }, /* 116 */ /***/ function(module, exports, __webpack_require__) { /** * Linear continuous scale * @module echarts/coord/scale/Ordinal * * http://en.wikipedia.org/wiki/Level_of_measurement */ // FIXME only one data var zrUtil = __webpack_require__(4); var Scale = __webpack_require__(117); var scaleProto = Scale.prototype; var OrdinalScale = Scale.extend({ type: 'ordinal', init: function (data, extent) { this._data = data; this._extent = extent || [0, data.length - 1]; }, parse: function (val) { return typeof val === 'string' ? zrUtil.indexOf(this._data, val) // val might be float. : Math.round(val); }, contain: function (rank) { rank = this.parse(rank); return scaleProto.contain.call(this, rank) && this._data[rank] != null; }, /** * Normalize given rank or name to linear [0, 1] * @param {number|string} [val] * @return {number} */ normalize: function (val) { return scaleProto.normalize.call(this, this.parse(val)); }, scale: function (val) { return Math.round(scaleProto.scale.call(this, val)); }, /** * @return {Array} */ getTicks: function () { var ticks = []; var extent = this._extent; var rank = extent[0]; while (rank <= extent[1]) { ticks.push(rank); rank++; } return ticks; }, /** * Get item on rank n * @param {number} n * @return {string} */ getLabel: function (n) { return this._data[n]; }, /** * @return {number} */ count: function () { return this._extent[1] - this._extent[0] + 1; }, niceTicks: zrUtil.noop, niceExtent: zrUtil.noop }); /** * @return {module:echarts/scale/Time} */ OrdinalScale.create = function () { return new OrdinalScale(); }; module.exports = OrdinalScale; /***/ }, /* 117 */ /***/ function(module, exports, __webpack_require__) { /** * // Scale class management * @module echarts/scale/Scale */ var clazzUtil = __webpack_require__(13); function Scale() { /** * Extent * @type {Array.} * @protected */ this._extent = [Infinity, -Infinity]; /** * Step is calculated in adjustExtent * @type {Array.} * @protected */ this._interval = 0; this.init && this.init.apply(this, arguments); } var scaleProto = Scale.prototype; /** * Parse input val to valid inner number. * @param {*} val * @return {number} */ scaleProto.parse = function (val) { // Notice: This would be a trap here, If the implementation // of this method depends on extent, and this method is used // before extent set (like in dataZoom), it would be wrong. // Nevertheless, parse does not depend on extent generally. return val; }; scaleProto.contain = function (val) { var extent = this._extent; return val >= extent[0] && val <= extent[1]; }; /** * Normalize value to linear [0, 1], return 0.5 if extent span is 0 * @param {number} val * @return {number} */ scaleProto.normalize = function (val) { var extent = this._extent; if (extent[1] === extent[0]) { return 0.5; } return (val - extent[0]) / (extent[1] - extent[0]); }; /** * Scale normalized value * @param {number} val * @return {number} */ scaleProto.scale = function (val) { var extent = this._extent; return val * (extent[1] - extent[0]) + extent[0]; }; /** * Set extent from data * @param {Array.} other */ scaleProto.unionExtent = function (other) { var extent = this._extent; other[0] < extent[0] && (extent[0] = other[0]); other[1] > extent[1] && (extent[1] = other[1]); // not setExtent because in log axis it may transformed to power // this.setExtent(extent[0], extent[1]); }; /** * Get extent * @return {Array.} */ scaleProto.getExtent = function () { return this._extent.slice(); }; /** * Set extent * @param {number} start * @param {number} end */ scaleProto.setExtent = function (start, end) { var thisExtent = this._extent; if (!isNaN(start)) { thisExtent[0] = start; } if (!isNaN(end)) { thisExtent[1] = end; } }; /** * @return {Array.} */ scaleProto.getTicksLabels = function () { var labels = []; var ticks = this.getTicks(); for (var i = 0; i < ticks.length; i++) { labels.push(this.getLabel(ticks[i])); } return labels; }; clazzUtil.enableClassExtend(Scale); clazzUtil.enableClassManagement(Scale, { registerWhenExtend: true }); module.exports = Scale; /***/ }, /* 118 */ /***/ function(module, exports, __webpack_require__) { /** * Interval scale * @module echarts/scale/Interval */ var numberUtil = __webpack_require__(7); var formatUtil = __webpack_require__(6); var Scale = __webpack_require__(117); var mathFloor = Math.floor; var mathCeil = Math.ceil; var getPrecisionSafe = numberUtil.getPrecisionSafe; var roundingErrorFix = numberUtil.round; /** * @alias module:echarts/coord/scale/Interval * @constructor */ var IntervalScale = Scale.extend({ type: 'interval', _interval: 0, setExtent: function (start, end) { var thisExtent = this._extent; //start,end may be a Number like '25',so... if (!isNaN(start)) { thisExtent[0] = parseFloat(start); } if (!isNaN(end)) { thisExtent[1] = parseFloat(end); } }, unionExtent: function (other) { var extent = this._extent; other[0] < extent[0] && (extent[0] = other[0]); other[1] > extent[1] && (extent[1] = other[1]); // unionExtent may called by it's sub classes IntervalScale.prototype.setExtent.call(this, extent[0], extent[1]); }, /** * Get interval */ getInterval: function () { if (!this._interval) { this.niceTicks(); } return this._interval; }, /** * Set interval */ setInterval: function (interval) { this._interval = interval; // Dropped auto calculated niceExtent and use user setted extent // We assume user wan't to set both interval, min, max to get a better result this._niceExtent = this._extent.slice(); }, /** * @return {Array.} */ getTicks: function () { if (!this._interval) { this.niceTicks(); } var interval = this._interval; var extent = this._extent; var ticks = []; // Consider this case: using dataZoom toolbox, zoom and zoom. var safeLimit = 10000; if (interval) { var niceExtent = this._niceExtent; var precision = getPrecisionSafe(interval) + 2; if (extent[0] < niceExtent[0]) { ticks.push(extent[0]); } var tick = niceExtent[0]; while (tick <= niceExtent[1]) { ticks.push(tick); // Avoid rounding error tick = roundingErrorFix(tick + interval, precision); if (ticks.length > safeLimit) { return []; } } // Consider this case: the last item of ticks is smaller // than niceExtent[1] and niceExtent[1] === extent[1]. if (extent[1] > (ticks.length ? ticks[ticks.length - 1] : niceExtent[1])) { ticks.push(extent[1]); } } return ticks; }, /** * @return {Array.} */ getTicksLabels: function () { var labels = []; var ticks = this.getTicks(); for (var i = 0; i < ticks.length; i++) { labels.push(this.getLabel(ticks[i])); } return labels; }, /** * @param {number} n * @return {number} */ getLabel: function (data) { return formatUtil.addCommas(data); }, /** * Update interval and extent of intervals for nice ticks * * @param {number} [splitNumber = 5] Desired number of ticks */ niceTicks: function (splitNumber) { splitNumber = splitNumber || 5; var extent = this._extent; var span = extent[1] - extent[0]; if (!isFinite(span)) { return; } // User may set axis min 0 and data are all negative // FIXME If it needs to reverse ? if (span < 0) { span = -span; extent.reverse(); } // From "Nice Numbers for Graph Labels" of Graphic Gems // var niceSpan = numberUtil.nice(span, false); var step = roundingErrorFix( numberUtil.nice(span / splitNumber, true), Math.max( getPrecisionSafe(extent[0]), getPrecisionSafe(extent[1]) // extent may be [0, 1], and step should have 1 more digits. // To make it safe we add 2 more digits ) + 2 ); var precision = getPrecisionSafe(step) + 2; // Niced extent inside original extent var niceExtent = [ roundingErrorFix(mathCeil(extent[0] / step) * step, precision), roundingErrorFix(mathFloor(extent[1] / step) * step, precision) ]; this._interval = step; this._niceExtent = niceExtent; }, /** * Nice extent. * @param {number} [splitNumber = 5] Given approx tick number * @param {boolean} [fixMin=false] * @param {boolean} [fixMax=false] */ niceExtent: function (splitNumber, fixMin, fixMax) { var extent = this._extent; // If extent start and end are same, expand them if (extent[0] === extent[1]) { if (extent[0] !== 0) { // Expand extent var expandSize = extent[0]; // In the fowllowing case // Axis has been fixed max 100 // Plus data are all 100 and axis extent are [100, 100]. // Extend to the both side will cause expanded max is larger than fixed max. // So only expand to the smaller side. if (!fixMax) { extent[1] += expandSize / 2; extent[0] -= expandSize / 2; } else { extent[0] -= expandSize / 2; } } else { extent[1] = 1; } } var span = extent[1] - extent[0]; // If there are no data and extent are [Infinity, -Infinity] if (!isFinite(span)) { extent[0] = 0; extent[1] = 1; } this.niceTicks(splitNumber); // var extent = this._extent; var interval = this._interval; if (!fixMin) { extent[0] = roundingErrorFix(mathFloor(extent[0] / interval) * interval); } if (!fixMax) { extent[1] = roundingErrorFix(mathCeil(extent[1] / interval) * interval); } } }); /** * @return {module:echarts/scale/Time} */ IntervalScale.create = function () { return new IntervalScale(); }; module.exports = IntervalScale; /***/ }, /* 119 */ /***/ function(module, exports, __webpack_require__) { /** * Interval scale * @module echarts/coord/scale/Time */ var zrUtil = __webpack_require__(4); var numberUtil = __webpack_require__(7); var formatUtil = __webpack_require__(6); var IntervalScale = __webpack_require__(118); var intervalScaleProto = IntervalScale.prototype; var mathCeil = Math.ceil; var mathFloor = Math.floor; var ONE_SECOND = 1000; var ONE_MINUTE = ONE_SECOND * 60; var ONE_HOUR = ONE_MINUTE * 60; var ONE_DAY = ONE_HOUR * 24; // FIXME 公用? var bisect = function (a, x, lo, hi) { while (lo < hi) { var mid = lo + hi >>> 1; if (a[mid][2] < x) { lo = mid + 1; } else { hi = mid; } } return lo; }; /** * @alias module:echarts/coord/scale/Time * @constructor */ var TimeScale = IntervalScale.extend({ type: 'time', // Overwrite getLabel: function (val) { var stepLvl = this._stepLvl; var date = new Date(val); return formatUtil.formatTime(stepLvl[0], date); }, // Overwrite niceExtent: function (approxTickNum, fixMin, fixMax) { var extent = this._extent; // If extent start and end are same, expand them if (extent[0] === extent[1]) { // Expand extent extent[0] -= ONE_DAY; extent[1] += ONE_DAY; } // If there are no data and extent are [Infinity, -Infinity] if (extent[1] === -Infinity && extent[0] === Infinity) { var d = new Date(); extent[1] = new Date(d.getFullYear(), d.getMonth(), d.getDate()); extent[0] = extent[1] - ONE_DAY; } this.niceTicks(approxTickNum); // var extent = this._extent; var interval = this._interval; if (!fixMin) { extent[0] = numberUtil.round(mathFloor(extent[0] / interval) * interval); } if (!fixMax) { extent[1] = numberUtil.round(mathCeil(extent[1] / interval) * interval); } }, // Overwrite niceTicks: function (approxTickNum) { approxTickNum = approxTickNum || 10; var extent = this._extent; var span = extent[1] - extent[0]; var approxInterval = span / approxTickNum; var scaleLevelsLen = scaleLevels.length; var idx = bisect(scaleLevels, approxInterval, 0, scaleLevelsLen); var level = scaleLevels[Math.min(idx, scaleLevelsLen - 1)]; var interval = level[2]; // Same with interval scale if span is much larger than 1 year if (level[0] === 'year') { var yearSpan = span / interval; // From "Nice Numbers for Graph Labels" of Graphic Gems // var niceYearSpan = numberUtil.nice(yearSpan, false); var yearStep = numberUtil.nice(yearSpan / approxTickNum, true); interval *= yearStep; } var niceExtent = [ mathCeil(extent[0] / interval) * interval, mathFloor(extent[1] / interval) * interval ]; this._stepLvl = level; // Interval will be used in getTicks this._interval = interval; this._niceExtent = niceExtent; }, parse: function (val) { // val might be float. return +numberUtil.parseDate(val); } }); zrUtil.each(['contain', 'normalize'], function (methodName) { TimeScale.prototype[methodName] = function (val) { return intervalScaleProto[methodName].call(this, this.parse(val)); }; }); // Steps from d3 var scaleLevels = [ // Format step interval ['hh:mm:ss', 1, ONE_SECOND], // 1s ['hh:mm:ss', 5, ONE_SECOND * 5], // 5s ['hh:mm:ss', 10, ONE_SECOND * 10], // 10s ['hh:mm:ss', 15, ONE_SECOND * 15], // 15s ['hh:mm:ss', 30, ONE_SECOND * 30], // 30s ['hh:mm\nMM-dd',1, ONE_MINUTE], // 1m ['hh:mm\nMM-dd',5, ONE_MINUTE * 5], // 5m ['hh:mm\nMM-dd',10, ONE_MINUTE * 10], // 10m ['hh:mm\nMM-dd',15, ONE_MINUTE * 15], // 15m ['hh:mm\nMM-dd',30, ONE_MINUTE * 30], // 30m ['hh:mm\nMM-dd',1, ONE_HOUR], // 1h ['hh:mm\nMM-dd',2, ONE_HOUR * 2], // 2h ['hh:mm\nMM-dd',6, ONE_HOUR * 6], // 6h ['hh:mm\nMM-dd',12, ONE_HOUR * 12], // 12h ['MM-dd\nyyyy', 1, ONE_DAY], // 1d ['week', 7, ONE_DAY * 7], // 7d ['month', 1, ONE_DAY * 31], // 1M ['quarter', 3, ONE_DAY * 380 / 4], // 3M ['half-year', 6, ONE_DAY * 380 / 2], // 6M ['year', 1, ONE_DAY * 380] // 1Y ]; /** * @return {module:echarts/scale/Time} */ TimeScale.create = function () { return new TimeScale(); }; module.exports = TimeScale; /***/ }, /* 120 */ /***/ function(module, exports, __webpack_require__) { /** * Log scale * @module echarts/scale/Log */ var zrUtil = __webpack_require__(4); var Scale = __webpack_require__(117); var numberUtil = __webpack_require__(7); // Use some method of IntervalScale var IntervalScale = __webpack_require__(118); var scaleProto = Scale.prototype; var intervalScaleProto = IntervalScale.prototype; var getPrecisionSafe = numberUtil.getPrecisionSafe; var roundingErrorFix = numberUtil.round; var mathFloor = Math.floor; var mathCeil = Math.ceil; var mathPow = Math.pow; var mathLog = Math.log; var LogScale = Scale.extend({ type: 'log', base: 10, $constructor: function () { Scale.apply(this, arguments); this._originalScale = new IntervalScale(); }, /** * @return {Array.} */ getTicks: function () { var originalScale = this._originalScale; var extent = this._extent; var originalExtent = originalScale.getExtent(); return zrUtil.map(intervalScaleProto.getTicks.call(this), function (val) { var powVal = numberUtil.round(mathPow(this.base, val)); // Fix #4158 powVal = (val === extent[0] && originalScale.__fixMin) ? fixRoundingError(powVal, originalExtent[0]) : powVal; powVal = (val === extent[1] && originalScale.__fixMax) ? fixRoundingError(powVal, originalExtent[1]) : powVal; return powVal; }, this); }, /** * @param {number} val * @return {string} */ getLabel: intervalScaleProto.getLabel, /** * @param {number} val * @return {number} */ scale: function (val) { val = scaleProto.scale.call(this, val); return mathPow(this.base, val); }, /** * @param {number} start * @param {number} end */ setExtent: function (start, end) { var base = this.base; start = mathLog(start) / mathLog(base); end = mathLog(end) / mathLog(base); intervalScaleProto.setExtent.call(this, start, end); }, /** * @return {number} end */ getExtent: function () { var base = this.base; var extent = scaleProto.getExtent.call(this); extent[0] = mathPow(base, extent[0]); extent[1] = mathPow(base, extent[1]); // Fix #4158 var originalScale = this._originalScale; var originalExtent = originalScale.getExtent(); originalScale.__fixMin && (extent[0] = fixRoundingError(extent[0], originalExtent[0])); originalScale.__fixMax && (extent[1] = fixRoundingError(extent[1], originalExtent[1])); return extent; }, /** * @param {Array.} extent */ unionExtent: function (extent) { this._originalScale.unionExtent(extent); var base = this.base; extent[0] = mathLog(extent[0]) / mathLog(base); extent[1] = mathLog(extent[1]) / mathLog(base); scaleProto.unionExtent.call(this, extent); }, /** * Update interval and extent of intervals for nice ticks * @param {number} [approxTickNum = 10] Given approx tick number */ niceTicks: function (approxTickNum) { approxTickNum = approxTickNum || 10; var extent = this._extent; var span = extent[1] - extent[0]; if (span === Infinity || span <= 0) { return; } var interval = numberUtil.quantity(span); var err = approxTickNum / span * interval; // Filter ticks to get closer to the desired count. if (err <= 0.5) { interval *= 10; } // Interval should be integer while (!isNaN(interval) && Math.abs(interval) < 1 && Math.abs(interval) > 0) { interval *= 10; } var niceExtent = [ numberUtil.round(mathCeil(extent[0] / interval) * interval), numberUtil.round(mathFloor(extent[1] / interval) * interval) ]; this._interval = interval; this._niceExtent = niceExtent; }, /** * Nice extent. * @param {number} [approxTickNum = 10] Given approx tick number * @param {boolean} [fixMin=false] * @param {boolean} [fixMax=false] */ niceExtent: function (splitNumber, fixMin, fixMax) { intervalScaleProto.niceExtent.call(this, splitNumber, fixMin, fixMax); var originalScale = this._originalScale; originalScale.__fixMin = fixMin; originalScale.__fixMax = fixMax; } }); zrUtil.each(['contain', 'normalize'], function (methodName) { LogScale.prototype[methodName] = function (val) { val = mathLog(val) / mathLog(this.base); return scaleProto[methodName].call(this, val); }; }); LogScale.create = function () { return new LogScale(); }; function fixRoundingError(val, originalVal) { return roundingErrorFix(val, getPrecisionSafe(originalVal)); } module.exports = LogScale; /***/ }, /* 121 */ /***/ function(module, exports, __webpack_require__) { 'use strict'; var zrUtil = __webpack_require__(4); var Cartesian = __webpack_require__(122); function Cartesian2D(name) { Cartesian.call(this, name); } Cartesian2D.prototype = { constructor: Cartesian2D, type: 'cartesian2d', /** * @type {Array.} * @readOnly */ dimensions: ['x', 'y'], /** * Base axis will be used on stacking. * * @return {module:echarts/coord/cartesian/Axis2D} */ getBaseAxis: function () { return this.getAxesByScale('ordinal')[0] || this.getAxesByScale('time')[0] || this.getAxis('x'); }, /** * If contain point * @param {Array.} point * @return {boolean} */ containPoint: function (point) { var axisX = this.getAxis('x'); var axisY = this.getAxis('y'); return axisX.contain(axisX.toLocalCoord(point[0])) && axisY.contain(axisY.toLocalCoord(point[1])); }, /** * If contain data * @param {Array.} data * @return {boolean} */ containData: function (data) { return this.getAxis('x').containData(data[0]) && this.getAxis('y').containData(data[1]); }, /** * Convert series data to an array of points * @param {module:echarts/data/List} data * @param {boolean} stack * @return {Array} * Return array of points. For example: * `[[10, 10], [20, 20], [30, 30]]` */ dataToPoints: function (data, stack) { return data.mapArray(['x', 'y'], function (x, y) { return this.dataToPoint([x, y]); }, stack, this); }, /** * @param {Array.} data * @param {boolean} [clamp=false] * @return {Array.} */ dataToPoint: function (data, clamp) { var xAxis = this.getAxis('x'); var yAxis = this.getAxis('y'); return [ xAxis.toGlobalCoord(xAxis.dataToCoord(data[0], clamp)), yAxis.toGlobalCoord(yAxis.dataToCoord(data[1], clamp)) ]; }, /** * @param {Array.} point * @param {boolean} [clamp=false] * @return {Array.} */ pointToData: function (point, clamp) { var xAxis = this.getAxis('x'); var yAxis = this.getAxis('y'); return [ xAxis.coordToData(xAxis.toLocalCoord(point[0]), clamp), yAxis.coordToData(yAxis.toLocalCoord(point[1]), clamp) ]; }, /** * Get other axis * @param {module:echarts/coord/cartesian/Axis2D} axis */ getOtherAxis: function (axis) { return this.getAxis(axis.dim === 'x' ? 'y' : 'x'); } }; zrUtil.inherits(Cartesian2D, Cartesian); module.exports = Cartesian2D; /***/ }, /* 122 */ /***/ function(module, exports, __webpack_require__) { 'use strict'; /** * Cartesian coordinate system * @module echarts/coord/Cartesian * */ var zrUtil = __webpack_require__(4); function dimAxisMapper(dim) { return this._axes[dim]; } /** * @alias module:echarts/coord/Cartesian * @constructor */ var Cartesian = function (name) { this._axes = {}; this._dimList = []; /** * @type {string} */ this.name = name || ''; }; Cartesian.prototype = { constructor: Cartesian, type: 'cartesian', /** * Get axis * @param {number|string} dim * @return {module:echarts/coord/Cartesian~Axis} */ getAxis: function (dim) { return this._axes[dim]; }, /** * Get axes list * @return {Array.} */ getAxes: function () { return zrUtil.map(this._dimList, dimAxisMapper, this); }, /** * Get axes list by given scale type */ getAxesByScale: function (scaleType) { scaleType = scaleType.toLowerCase(); return zrUtil.filter( this.getAxes(), function (axis) { return axis.scale.type === scaleType; } ); }, /** * Add axis * @param {module:echarts/coord/Cartesian.Axis} */ addAxis: function (axis) { var dim = axis.dim; this._axes[dim] = axis; this._dimList.push(dim); }, /** * Convert data to coord in nd space * @param {Array.|Object.} val * @return {Array.|Object.} */ dataToCoord: function (val) { return this._dataCoordConvert(val, 'dataToCoord'); }, /** * Convert coord in nd space to data * @param {Array.|Object.} val * @return {Array.|Object.} */ coordToData: function (val) { return this._dataCoordConvert(val, 'coordToData'); }, _dataCoordConvert: function (input, method) { var dimList = this._dimList; var output = input instanceof Array ? [] : {}; for (var i = 0; i < dimList.length; i++) { var dim = dimList[i]; var axis = this._axes[dim]; output[dim] = axis[method](input[dim]); } return output; } }; module.exports = Cartesian; /***/ }, /* 123 */ /***/ function(module, exports, __webpack_require__) { var zrUtil = __webpack_require__(4); var Axis = __webpack_require__(124); var axisLabelInterval = __webpack_require__(125); /** * Extend axis 2d * @constructor module:echarts/coord/cartesian/Axis2D * @extends {module:echarts/coord/cartesian/Axis} * @param {string} dim * @param {*} scale * @param {Array.} coordExtent * @param {string} axisType * @param {string} position */ var Axis2D = function (dim, scale, coordExtent, axisType, position) { Axis.call(this, dim, scale, coordExtent); /** * Axis type * - 'category' * - 'value' * - 'time' * - 'log' * @type {string} */ this.type = axisType || 'value'; /** * Axis position * - 'top' * - 'bottom' * - 'left' * - 'right' */ this.position = position || 'bottom'; }; Axis2D.prototype = { constructor: Axis2D, /** * Index of axis, can be used as key */ index: 0, /** * If axis is on the zero position of the other axis * @type {boolean} */ onZero: false, /** * Axis model * @param {module:echarts/coord/cartesian/AxisModel} */ model: null, isHorizontal: function () { var position = this.position; return position === 'top' || position === 'bottom'; }, getGlobalExtent: function () { var ret = this.getExtent(); ret[0] = this.toGlobalCoord(ret[0]); ret[1] = this.toGlobalCoord(ret[1]); return ret; }, /** * @return {number} */ getLabelInterval: function () { var labelInterval = this._labelInterval; if (!labelInterval) { labelInterval = this._labelInterval = axisLabelInterval(this); } return labelInterval; }, /** * If label is ignored. * Automatically used when axis is category and label can not be all shown * @param {number} idx * @return {boolean} */ isLabelIgnored: function (idx) { if (this.type === 'category') { var labelInterval = this.getLabelInterval(); return ((typeof labelInterval === 'function') && !labelInterval(idx, this.scale.getLabel(idx))) || idx % (labelInterval + 1); } }, /** * Transform global coord to local coord, * i.e. var localCoord = axis.toLocalCoord(80); * designate by module:echarts/coord/cartesian/Grid. * @type {Function} */ toLocalCoord: null, /** * Transform global coord to local coord, * i.e. var globalCoord = axis.toLocalCoord(40); * designate by module:echarts/coord/cartesian/Grid. * @type {Function} */ toGlobalCoord: null }; zrUtil.inherits(Axis2D, Axis); module.exports = Axis2D; /***/ }, /* 124 */ /***/ function(module, exports, __webpack_require__) { var numberUtil = __webpack_require__(7); var linearMap = numberUtil.linearMap; var zrUtil = __webpack_require__(4); function fixExtentWithBands(extent, nTick) { var size = extent[1] - extent[0]; var len = nTick; var margin = size / len / 2; extent[0] += margin; extent[1] -= margin; } var normalizedExtent = [0, 1]; /** * @name module:echarts/coord/CartesianAxis * @constructor */ var Axis = function (dim, scale, extent) { /** * Axis dimension. Such as 'x', 'y', 'z', 'angle', 'radius' * @type {string} */ this.dim = dim; /** * Axis scale * @type {module:echarts/coord/scale/*} */ this.scale = scale; /** * @type {Array.} * @private */ this._extent = extent || [0, 0]; /** * @type {boolean} */ this.inverse = false; /** * Usually true when axis has a ordinal scale * @type {boolean} */ this.onBand = false; }; Axis.prototype = { constructor: Axis, /** * If axis extent contain given coord * @param {number} coord * @return {boolean} */ contain: function (coord) { var extent = this._extent; var min = Math.min(extent[0], extent[1]); var max = Math.max(extent[0], extent[1]); return coord >= min && coord <= max; }, /** * If axis extent contain given data * @param {number} data * @return {boolean} */ containData: function (data) { return this.contain(this.dataToCoord(data)); }, /** * Get coord extent. * @return {Array.} */ getExtent: function () { var ret = this._extent.slice(); return ret; }, /** * Get precision used for formatting * @param {Array.} [dataExtent] * @return {number} */ getPixelPrecision: function (dataExtent) { return numberUtil.getPixelPrecision( dataExtent || this.scale.getExtent(), this._extent ); }, /** * Set coord extent * @param {number} start * @param {number} end */ setExtent: function (start, end) { var extent = this._extent; extent[0] = start; extent[1] = end; }, /** * Convert data to coord. Data is the rank if it has a ordinal scale * @param {number} data * @param {boolean} clamp * @return {number} */ dataToCoord: function (data, clamp) { var extent = this._extent; var scale = this.scale; data = scale.normalize(data); if (this.onBand && scale.type === 'ordinal') { extent = extent.slice(); fixExtentWithBands(extent, scale.count()); } return linearMap(data, normalizedExtent, extent, clamp); }, /** * Convert coord to data. Data is the rank if it has a ordinal scale * @param {number} coord * @param {boolean} clamp * @return {number} */ coordToData: function (coord, clamp) { var extent = this._extent; var scale = this.scale; if (this.onBand && scale.type === 'ordinal') { extent = extent.slice(); fixExtentWithBands(extent, scale.count()); } var t = linearMap(coord, extent, normalizedExtent, clamp); return this.scale.scale(t); }, /** * @return {Array.} */ getTicksCoords: function (alignWithLabel) { if (this.onBand && !alignWithLabel) { var bands = this.getBands(); var coords = []; for (var i = 0; i < bands.length; i++) { coords.push(bands[i][0]); } if (bands[i - 1]) { coords.push(bands[i - 1][1]); } return coords; } else { return zrUtil.map(this.scale.getTicks(), this.dataToCoord, this); } }, /** * Coords of labels are on the ticks or on the middle of bands * @return {Array.} */ getLabelsCoords: function () { return zrUtil.map(this.scale.getTicks(), this.dataToCoord, this); }, /** * Get bands. * * If axis has labels [1, 2, 3, 4]. Bands on the axis are * |---1---|---2---|---3---|---4---|. * * @return {Array} */ // FIXME Situation when labels is on ticks getBands: function () { var extent = this.getExtent(); var bands = []; var len = this.scale.count(); var start = extent[0]; var end = extent[1]; var span = end - start; for (var i = 0; i < len; i++) { bands.push([ span * i / len + start, span * (i + 1) / len + start ]); } return bands; }, /** * Get width of band * @return {number} */ getBandWidth: function () { var axisExtent = this._extent; var dataExtent = this.scale.getExtent(); var len = dataExtent[1] - dataExtent[0] + (this.onBand ? 1 : 0); // Fix #2728, avoid NaN when only one data. len === 0 && (len = 1); var size = Math.abs(axisExtent[1] - axisExtent[0]); return Math.abs(size) / len; } }; module.exports = Axis; /***/ }, /* 125 */ /***/ function(module, exports, __webpack_require__) { 'use strict'; /** * Helper function for axisLabelInterval calculation */ var zrUtil = __webpack_require__(4); var axisHelper = __webpack_require__(115); module.exports = function (axis) { var axisModel = axis.model; var labelModel = axisModel.getModel('axisLabel'); var labelInterval = labelModel.get('interval'); if (!(axis.type === 'category' && labelInterval === 'auto')) { return labelInterval === 'auto' ? 0 : labelInterval; } return axisHelper.getAxisLabelInterval( zrUtil.map(axis.scale.getTicks(), axis.dataToCoord, axis), axisModel.getFormattedLabels(), labelModel.getModel('textStyle').getFont(), axis.isHorizontal() ); }; /***/ }, /* 126 */ /***/ function(module, exports, __webpack_require__) { 'use strict'; // Grid 是在有直角坐标系的时候必须要存在的 // 所以这里也要被 Cartesian2D 依赖 __webpack_require__(127); var ComponentModel = __webpack_require__(19); module.exports = ComponentModel.extend({ type: 'grid', dependencies: ['xAxis', 'yAxis'], layoutMode: 'box', /** * @type {module:echarts/coord/cartesian/Grid} */ coordinateSystem: null, defaultOption: { show: false, zlevel: 0, z: 0, left: '10%', top: 60, right: '10%', bottom: 60, // If grid size contain label containLabel: false, // width: {totalWidth} - left - right, // height: {totalHeight} - top - bottom, backgroundColor: 'rgba(0,0,0,0)', borderWidth: 1, borderColor: '#ccc' } }); /***/ }, /* 127 */ /***/ function(module, exports, __webpack_require__) { 'use strict'; var ComponentModel = __webpack_require__(19); var zrUtil = __webpack_require__(4); var axisModelCreator = __webpack_require__(128); var AxisModel = ComponentModel.extend({ type: 'cartesian2dAxis', /** * @type {module:echarts/coord/cartesian/Axis2D} */ axis: null, /** * @override */ init: function () { AxisModel.superApply(this, 'init', arguments); this.resetRange(); }, /** * @override */ mergeOption: function () { AxisModel.superApply(this, 'mergeOption', arguments); this.resetRange(); }, /** * @override */ restoreData: function () { AxisModel.superApply(this, 'restoreData', arguments); this.resetRange(); }, /** * @return {module:echarts/model/Model} */ findGridModel: function () { return this.ecModel.queryComponents({ mainType: 'grid', index: this.get('gridIndex'), id: this.get('gridId') })[0]; } }); function getAxisType(axisDim, option) { // Default axis with data is category axis return option.type || (option.data ? 'category' : 'value'); } zrUtil.merge(AxisModel.prototype, __webpack_require__(130)); zrUtil.merge(AxisModel.prototype, __webpack_require__(131)); var extraOption = { // gridIndex: 0, // gridId: '', // Offset is for multiple axis on the same position offset: 0 }; axisModelCreator('x', AxisModel, getAxisType, extraOption); axisModelCreator('y', AxisModel, getAxisType, extraOption); module.exports = AxisModel; /***/ }, /* 128 */ /***/ function(module, exports, __webpack_require__) { var axisDefault = __webpack_require__(129); var zrUtil = __webpack_require__(4); var ComponentModel = __webpack_require__(19); var layout = __webpack_require__(21); // FIXME axisType is fixed ? var AXIS_TYPES = ['value', 'category', 'time', 'log']; /** * Generate sub axis model class * @param {string} axisName 'x' 'y' 'radius' 'angle' 'parallel' * @param {module:echarts/model/Component} BaseAxisModelClass * @param {Function} axisTypeDefaulter * @param {Object} [extraDefaultOption] */ module.exports = function (axisName, BaseAxisModelClass, axisTypeDefaulter, extraDefaultOption) { zrUtil.each(AXIS_TYPES, function (axisType) { BaseAxisModelClass.extend({ type: axisName + 'Axis.' + axisType, mergeDefaultAndTheme: function (option, ecModel) { var layoutMode = this.layoutMode; var inputPositionParams = layoutMode ? layout.getLayoutParams(option) : {}; var themeModel = ecModel.getTheme(); zrUtil.merge(option, themeModel.get(axisType + 'Axis')); zrUtil.merge(option, this.getDefaultOption()); option.type = axisTypeDefaulter(axisName, option); if (layoutMode) { layout.mergeLayoutParam(option, inputPositionParams, layoutMode); } }, defaultOption: zrUtil.mergeAll( [ {}, axisDefault[axisType + 'Axis'], extraDefaultOption ], true ) }); }); ComponentModel.registerSubTypeDefaulter( axisName + 'Axis', zrUtil.curry(axisTypeDefaulter, axisName) ); }; /***/ }, /* 129 */ /***/ function(module, exports, __webpack_require__) { var zrUtil = __webpack_require__(4); var defaultOption = { show: true, zlevel: 0, // 一级层叠 z: 0, // 二级层叠 // 反向坐标轴 inverse: false, // 坐标轴名字,默认为空 name: '', // 坐标轴名字位置,支持'start' | 'middle' | 'end' nameLocation: 'end', // 坐标轴名字旋转,degree。 nameRotate: null, // Adapt to axis rotate, when nameLocation is 'middle'. nameTruncate: { maxWidth: null, ellipsis: '...', placeholder: '.' }, // 坐标轴文字样式,默认取全局样式 nameTextStyle: {}, // 文字与轴线距离 nameGap: 15, silent: false, // Default false to support tooltip. triggerEvent: false, // Default false to avoid legacy user event listener fail. tooltip: { show: false }, // 坐标轴线 axisLine: { // 默认显示,属性show控制显示与否 show: true, onZero: true, // 属性lineStyle控制线条样式 lineStyle: { color: '#333', width: 1, type: 'solid' } }, // 坐标轴小标记 axisTick: { // 属性show控制显示与否,默认显示 show: true, // 控制小标记是否在grid里 inside: false, // 属性length控制线长 length: 5, // 属性lineStyle控制线条样式 lineStyle: { width: 1 } }, // 坐标轴文本标签,详见axis.axisLabel axisLabel: { show: true, // 控制文本标签是否在grid里 inside: false, rotate: 0, margin: 8, // formatter: null, // 其余属性默认使用全局文本样式,详见TEXTSTYLE textStyle: { fontSize: 12 } }, // 分隔线 splitLine: { // 默认显示,属性show控制显示与否 show: true, // 属性lineStyle(详见lineStyle)控制线条样式 lineStyle: { color: ['#ccc'], width: 1, type: 'solid' } }, // 分隔区域 splitArea: { // 默认不显示,属性show控制显示与否 show: false, // 属性areaStyle(详见areaStyle)控制区域样式 areaStyle: { color: ['rgba(250,250,250,0.3)','rgba(200,200,200,0.3)'] } } }; var categoryAxis = zrUtil.merge({ // 类目起始和结束两端空白策略 boundaryGap: true, // splitArea: { // show: false // }, splitLine: { show: false }, // 坐标轴小标记 axisTick: { // If tick is align with label when boundaryGap is true // Default with axisTick alignWithLabel: false, interval: 'auto' }, // 坐标轴文本标签,详见axis.axisLabel axisLabel: { interval: 'auto' } }, defaultOption); var valueAxis = zrUtil.merge({ // 数值起始和结束两端空白策略 boundaryGap: [0, 0], // 最小值, 设置成 'dataMin' 则从数据中计算最小值 // min: null, // 最大值,设置成 'dataMax' 则从数据中计算最大值 // max: null, // Readonly prop, specifies start value of the range when using data zoom. // rangeStart: null // Readonly prop, specifies end value of the range when using data zoom. // rangeEnd: null // 脱离0值比例,放大聚焦到最终_min,_max区间 // scale: false, // 分割段数,默认为5 splitNumber: 5 // Minimum interval // minInterval: null }, defaultOption); // FIXME var timeAxis = zrUtil.defaults({ scale: true, min: 'dataMin', max: 'dataMax' }, valueAxis); var logAxis = zrUtil.defaults({ logBase: 10 }, valueAxis); logAxis.scale = true; module.exports = { categoryAxis: categoryAxis, valueAxis: valueAxis, timeAxis: timeAxis, logAxis: logAxis }; /***/ }, /* 130 */ /***/ function(module, exports, __webpack_require__) { var zrUtil = __webpack_require__(4); var axisHelper = __webpack_require__(115); function getName(obj) { if (zrUtil.isObject(obj) && obj.value != null) { return obj.value; } else { return obj; } } /** * Get categories */ function getCategories() { return this.get('type') === 'category' && zrUtil.map(this.get('data'), getName); } /** * Format labels * @return {Array.} */ function getFormattedLabels() { return axisHelper.getFormattedLabels( this.axis, this.get('axisLabel.formatter') ); } module.exports = { getFormattedLabels: getFormattedLabels, getCategories: getCategories }; /***/ }, /* 131 */ /***/ function(module, exports) { module.exports = { /** * @public * @return {Array.} */ getMin: function () { var option = this.option; var min = option.rangeStart != null ? option.rangeStart : option.min; // In case of axis.type === 'time', Date should be converted to timestamp. // In other cases, min/max should be a number or null/undefined or 'dataMin/Max'. if (min instanceof Date) { min = +min; } return min; }, /** * @public * @return {Array.} */ getMax: function () { var option = this.option; var max = option.rangeEnd != null ? option.rangeEnd : option.max; // In case of axis.type === 'time', Date should be converted to timestamp. // In other cases, min/max should be a number or null/undefined or 'dataMin/Max'. if (max instanceof Date) { max = +max; } return max; }, /** * @public * @return {boolean} */ getNeedCrossZero: function () { var option = this.option; return (option.rangeStart != null || option.rangeEnd != null) ? false : !option.scale; }, /** * @public * @param {number} rangeStart * @param {number} rangeEnd */ setRange: function (rangeStart, rangeEnd) { this.option.rangeStart = rangeStart; this.option.rangeEnd = rangeEnd; }, /** * @public */ resetRange: function () { // rangeStart and rangeEnd is readonly. this.option.rangeStart = this.option.rangeEnd = null; } }; /***/ }, /* 132 */ /***/ function(module, exports, __webpack_require__) { 'use strict'; // TODO boundaryGap __webpack_require__(127); __webpack_require__(133); /***/ }, /* 133 */ /***/ function(module, exports, __webpack_require__) { var zrUtil = __webpack_require__(4); var graphic = __webpack_require__(43); var AxisBuilder = __webpack_require__(134); var ifIgnoreOnTick = AxisBuilder.ifIgnoreOnTick; var getInterval = AxisBuilder.getInterval; var axisBuilderAttrs = [ 'axisLine', 'axisLabel', 'axisTick', 'axisName' ]; var selfBuilderAttrs = [ 'splitArea', 'splitLine' ]; // function getAlignWithLabel(model, axisModel) { // var alignWithLabel = model.get('alignWithLabel'); // if (alignWithLabel === 'auto') { // alignWithLabel = axisModel.get('axisTick.alignWithLabel'); // } // return alignWithLabel; // } var AxisView = __webpack_require__(1).extendComponentView({ type: 'axis', render: function (axisModel, ecModel) { this.group.removeAll(); var oldAxisGroup = this._axisGroup; this._axisGroup = new graphic.Group(); this.group.add(this._axisGroup); if (!axisModel.get('show')) { return; } var gridModel = axisModel.findGridModel(); var layout = layoutAxis(gridModel, axisModel); var axisBuilder = new AxisBuilder(axisModel, layout); zrUtil.each(axisBuilderAttrs, axisBuilder.add, axisBuilder); this._axisGroup.add(axisBuilder.getGroup()); zrUtil.each(selfBuilderAttrs, function (name) { if (axisModel.get(name + '.show')) { this['_' + name](axisModel, gridModel, layout.labelInterval); } }, this); graphic.groupTransition(oldAxisGroup, this._axisGroup, axisModel); }, /** * @param {module:echarts/coord/cartesian/AxisModel} axisModel * @param {module:echarts/coord/cartesian/GridModel} gridModel * @param {number|Function} labelInterval * @private */ _splitLine: function (axisModel, gridModel, labelInterval) { var axis = axisModel.axis; var splitLineModel = axisModel.getModel('splitLine'); var lineStyleModel = splitLineModel.getModel('lineStyle'); var lineColors = lineStyleModel.get('color'); var lineInterval = getInterval(splitLineModel, labelInterval); lineColors = zrUtil.isArray(lineColors) ? lineColors : [lineColors]; var gridRect = gridModel.coordinateSystem.getRect(); var isHorizontal = axis.isHorizontal(); var lineCount = 0; var ticksCoords = axis.getTicksCoords( // splitLineModel.get('alignWithLabel') ); var ticks = axis.scale.getTicks(); var p1 = []; var p2 = []; // Simple optimization // Batching the lines if color are the same var lineStyle = lineStyleModel.getLineStyle(); for (var i = 0; i < ticksCoords.length; i++) { if (ifIgnoreOnTick(axis, i, lineInterval)) { continue; } var tickCoord = axis.toGlobalCoord(ticksCoords[i]); if (isHorizontal) { p1[0] = tickCoord; p1[1] = gridRect.y; p2[0] = tickCoord; p2[1] = gridRect.y + gridRect.height; } else { p1[0] = gridRect.x; p1[1] = tickCoord; p2[0] = gridRect.x + gridRect.width; p2[1] = tickCoord; } var colorIndex = (lineCount++) % lineColors.length; this._axisGroup.add(new graphic.Line(graphic.subPixelOptimizeLine({ anid: 'line_' + ticks[i], shape: { x1: p1[0], y1: p1[1], x2: p2[0], y2: p2[1] }, style: zrUtil.defaults({ stroke: lineColors[colorIndex] }, lineStyle), silent: true }))); } }, /** * @param {module:echarts/coord/cartesian/AxisModel} axisModel * @param {module:echarts/coord/cartesian/GridModel} gridModel * @param {number|Function} labelInterval * @private */ _splitArea: function (axisModel, gridModel, labelInterval) { var axis = axisModel.axis; var splitAreaModel = axisModel.getModel('splitArea'); var areaStyleModel = splitAreaModel.getModel('areaStyle'); var areaColors = areaStyleModel.get('color'); var gridRect = gridModel.coordinateSystem.getRect(); var ticksCoords = axis.getTicksCoords( // splitAreaModel.get('alignWithLabel') ); var ticks = axis.scale.getTicks(); var prevX = axis.toGlobalCoord(ticksCoords[0]); var prevY = axis.toGlobalCoord(ticksCoords[0]); var count = 0; var areaInterval = getInterval(splitAreaModel, labelInterval); var areaStyle = areaStyleModel.getAreaStyle(); areaColors = zrUtil.isArray(areaColors) ? areaColors : [areaColors]; for (var i = 1; i < ticksCoords.length; i++) { if (ifIgnoreOnTick(axis, i, areaInterval)) { continue; } var tickCoord = axis.toGlobalCoord(ticksCoords[i]); var x; var y; var width; var height; if (axis.isHorizontal()) { x = prevX; y = gridRect.y; width = tickCoord - x; height = gridRect.height; } else { x = gridRect.x; y = prevY; width = gridRect.width; height = tickCoord - y; } var colorIndex = (count++) % areaColors.length; this._axisGroup.add(new graphic.Rect({ anid: 'area_' + ticks[i], shape: { x: x, y: y, width: width, height: height }, style: zrUtil.defaults({ fill: areaColors[colorIndex] }, areaStyle), silent: true })); prevX = x + width; prevY = y + height; } } }); AxisView.extend({ type: 'xAxis' }); AxisView.extend({ type: 'yAxis' }); /** * @inner */ function layoutAxis(gridModel, axisModel) { var grid = gridModel.coordinateSystem; var axis = axisModel.axis; var layout = {}; var rawAxisPosition = axis.position; var axisPosition = axis.onZero ? 'onZero' : rawAxisPosition; var axisDim = axis.dim; // [left, right, top, bottom] var rect = grid.getRect(); var rectBound = [rect.x, rect.x + rect.width, rect.y, rect.y + rect.height]; var axisOffset = axisModel.get('offset') || 0; var posMap = { x: { top: rectBound[2] - axisOffset, bottom: rectBound[3] + axisOffset }, y: { left: rectBound[0] - axisOffset, right: rectBound[1] + axisOffset } }; posMap.x.onZero = Math.max(Math.min(getZero('y'), posMap.x.bottom), posMap.x.top); posMap.y.onZero = Math.max(Math.min(getZero('x'), posMap.y.right), posMap.y.left); function getZero(dim, val) { var theAxis = grid.getAxis(dim); return theAxis.toGlobalCoord(theAxis.dataToCoord(0)); } // Axis position layout.position = [ axisDim === 'y' ? posMap.y[axisPosition] : rectBound[0], axisDim === 'x' ? posMap.x[axisPosition] : rectBound[3] ]; // Axis rotation layout.rotation = Math.PI / 2 * (axisDim === 'x' ? 0 : 1); // Tick and label direction, x y is axisDim var dirMap = {top: -1, bottom: 1, left: -1, right: 1}; layout.labelDirection = layout.tickDirection = layout.nameDirection = dirMap[rawAxisPosition]; if (axis.onZero) { layout.labelOffset = posMap[axisDim][rawAxisPosition] - posMap[axisDim].onZero; } if (axisModel.getModel('axisTick').get('inside')) { layout.tickDirection = -layout.tickDirection; } if (axisModel.getModel('axisLabel').get('inside')) { layout.labelDirection = -layout.labelDirection; } // Special label rotation var labelRotation = axisModel.getModel('axisLabel').get('rotate'); layout.labelRotation = axisPosition === 'top' ? -labelRotation : labelRotation; // label interval when auto mode. layout.labelInterval = axis.getLabelInterval(); // Over splitLine and splitArea layout.z2 = 1; return layout; } /***/ }, /* 134 */ /***/ function(module, exports, __webpack_require__) { var zrUtil = __webpack_require__(4); var formatUtil = __webpack_require__(6); var graphic = __webpack_require__(43); var Model = __webpack_require__(12); var numberUtil = __webpack_require__(7); var remRadian = numberUtil.remRadian; var isRadianAroundZero = numberUtil.isRadianAroundZero; var vec2 = __webpack_require__(10); var v2ApplyTransform = vec2.applyTransform; var retrieve = zrUtil.retrieve; var PI = Math.PI; function makeAxisEventDataBase(axisModel) { var eventData = { componentType: axisModel.mainType }; eventData[axisModel.mainType + 'Index'] = axisModel.componentIndex; return eventData; } /** * A final axis is translated and rotated from a "standard axis". * So opt.position and opt.rotation is required. * * A standard axis is and axis from [0, 0] to [0, axisExtent[1]], * for example: (0, 0) ------------> (0, 50) * * nameDirection or tickDirection or labelDirection is 1 means tick * or label is below the standard axis, whereas is -1 means above * the standard axis. labelOffset means offset between label and axis, * which is useful when 'onZero', where axisLabel is in the grid and * label in outside grid. * * Tips: like always, * positive rotation represents anticlockwise, and negative rotation * represents clockwise. * The direction of position coordinate is the same as the direction * of screen coordinate. * * Do not need to consider axis 'inverse', which is auto processed by * axis extent. * * @param {module:zrender/container/Group} group * @param {Object} axisModel * @param {Object} opt Standard axis parameters. * @param {Array.} opt.position [x, y] * @param {number} opt.rotation by radian * @param {number} [opt.nameDirection=1] 1 or -1 Used when nameLocation is 'middle'. * @param {number} [opt.tickDirection=1] 1 or -1 * @param {number} [opt.labelDirection=1] 1 or -1 * @param {number} [opt.labelOffset=0] Usefull when onZero. * @param {string} [opt.axisLabelShow] default get from axisModel. * @param {string} [opt.axisName] default get from axisModel. * @param {number} [opt.axisNameAvailableWidth] * @param {number} [opt.labelRotation] by degree, default get from axisModel. * @param {number} [opt.labelInterval] Default label interval when label * interval from model is null or 'auto'. * @param {number} [opt.strokeContainThreshold] Default label interval when label */ var AxisBuilder = function (axisModel, opt) { /** * @readOnly */ this.opt = opt; /** * @readOnly */ this.axisModel = axisModel; // Default value zrUtil.defaults( opt, { labelOffset: 0, nameDirection: 1, tickDirection: 1, labelDirection: 1, silent: true } ); /** * @readOnly */ this.group = new graphic.Group(); // FIXME Not use a seperate text group? var dumbGroup = new graphic.Group({ position: opt.position.slice(), rotation: opt.rotation }); // this.group.add(dumbGroup); // this._dumbGroup = dumbGroup; dumbGroup.updateTransform(); this._transform = dumbGroup.transform; this._dumbGroup = dumbGroup; }; AxisBuilder.prototype = { constructor: AxisBuilder, hasBuilder: function (name) { return !!builders[name]; }, add: function (name) { builders[name].call(this); }, getGroup: function () { return this.group; } }; var builders = { /** * @private */ axisLine: function () { var opt = this.opt; var axisModel = this.axisModel; if (!axisModel.get('axisLine.show')) { return; } var extent = this.axisModel.axis.getExtent(); var matrix = this._transform; var pt1 = [extent[0], 0]; var pt2 = [extent[1], 0]; if (matrix) { v2ApplyTransform(pt1, pt1, matrix); v2ApplyTransform(pt2, pt2, matrix); } this.group.add(new graphic.Line(graphic.subPixelOptimizeLine({ // Id for animation anid: 'line', shape: { x1: pt1[0], y1: pt1[1], x2: pt2[0], y2: pt2[1] }, style: zrUtil.extend( {lineCap: 'round'}, axisModel.getModel('axisLine.lineStyle').getLineStyle() ), strokeContainThreshold: opt.strokeContainThreshold || 5, silent: true, z2: 1 }))); }, /** * @private */ axisTick: function () { var axisModel = this.axisModel; if (!axisModel.get('axisTick.show')) { return; } var axis = axisModel.axis; var tickModel = axisModel.getModel('axisTick'); var opt = this.opt; var lineStyleModel = tickModel.getModel('lineStyle'); var tickLen = tickModel.get('length'); var tickInterval = getInterval(tickModel, opt.labelInterval); var ticksCoords = axis.getTicksCoords(tickModel.get('alignWithLabel')); var ticks = axis.scale.getTicks(); var pt1 = []; var pt2 = []; var matrix = this._transform; for (var i = 0; i < ticksCoords.length; i++) { // Only ordinal scale support tick interval if (ifIgnoreOnTick(axis, i, tickInterval)) { continue; } var tickCoord = ticksCoords[i]; pt1[0] = tickCoord; pt1[1] = 0; pt2[0] = tickCoord; pt2[1] = opt.tickDirection * tickLen; if (matrix) { v2ApplyTransform(pt1, pt1, matrix); v2ApplyTransform(pt2, pt2, matrix); } // Tick line, Not use group transform to have better line draw this.group.add(new graphic.Line(graphic.subPixelOptimizeLine({ // Id for animation anid: 'tick_' + ticks[i], shape: { x1: pt1[0], y1: pt1[1], x2: pt2[0], y2: pt2[1] }, style: zrUtil.defaults( lineStyleModel.getLineStyle(), { stroke: axisModel.get('axisLine.lineStyle.color') } ), z2: 2, silent: true }))); } }, /** * @param {module:echarts/coord/cartesian/AxisModel} axisModel * @param {module:echarts/coord/cartesian/GridModel} gridModel * @private */ axisLabel: function () { var opt = this.opt; var axisModel = this.axisModel; var show = retrieve(opt.axisLabelShow, axisModel.get('axisLabel.show')); if (!show) { return; } var axis = axisModel.axis; var labelModel = axisModel.getModel('axisLabel'); var textStyleModel = labelModel.getModel('textStyle'); var labelMargin = labelModel.get('margin'); var ticks = axis.scale.getTicks(); var labels = axisModel.getFormattedLabels(); // Special label rotate. var labelRotation = retrieve(opt.labelRotation, labelModel.get('rotate')) || 0; // To radian. labelRotation = labelRotation * PI / 180; var labelLayout = innerTextLayout(opt, labelRotation, opt.labelDirection); var categoryData = axisModel.get('data'); var textEls = []; var silent = isSilent(axisModel); var triggerEvent = axisModel.get('triggerEvent'); zrUtil.each(ticks, function (tickVal, index) { if (ifIgnoreOnTick(axis, index, opt.labelInterval)) { return; } var itemTextStyleModel = textStyleModel; if (categoryData && categoryData[tickVal] && categoryData[tickVal].textStyle) { itemTextStyleModel = new Model( categoryData[tickVal].textStyle, textStyleModel, axisModel.ecModel ); } var textColor = itemTextStyleModel.getTextColor() || axisModel.get('axisLine.lineStyle.color'); var tickCoord = axis.dataToCoord(tickVal); var pos = [ tickCoord, opt.labelOffset + opt.labelDirection * labelMargin ]; var labelBeforeFormat = axis.scale.getLabel(tickVal); var textEl = new graphic.Text({ // Id for animation anid: 'label_' + tickVal, style: { text: labels[index], textAlign: itemTextStyleModel.get('align', true) || labelLayout.textAlign, textVerticalAlign: itemTextStyleModel.get('baseline', true) || labelLayout.verticalAlign, textFont: itemTextStyleModel.getFont(), fill: typeof textColor === 'function' ? textColor(labelBeforeFormat) : textColor }, position: pos, rotation: labelLayout.rotation, silent: silent, z2: 10 }); // Pack data for mouse event if (triggerEvent) { textEl.eventData = makeAxisEventDataBase(axisModel); textEl.eventData.targetType = 'axisLabel'; textEl.eventData.value = labelBeforeFormat; } // FIXME this._dumbGroup.add(textEl); textEl.updateTransform(); textEls.push(textEl); this.group.add(textEl); textEl.decomposeTransform(); }, this); function isTwoLabelOverlapped(current, next) { var firstRect = current && current.getBoundingRect().clone(); var nextRect = next && next.getBoundingRect().clone(); if (firstRect && nextRect) { firstRect.applyTransform(current.getLocalTransform()); nextRect.applyTransform(next.getLocalTransform()); return firstRect.intersect(nextRect); } } if (axis.type !== 'category') { // If min or max are user set, we need to check // If the tick on min(max) are overlap on their neighbour tick // If they are overlapped, we need to hide the min(max) tick label if (axisModel.getMin ? axisModel.getMin() : axisModel.get('min')) { var firstLabel = textEls[0]; var nextLabel = textEls[1]; if (isTwoLabelOverlapped(firstLabel, nextLabel)) { firstLabel.ignore = true; } } if (axisModel.getMax ? axisModel.getMax() : axisModel.get('max')) { var lastLabel = textEls[textEls.length - 1]; var prevLabel = textEls[textEls.length - 2]; if (isTwoLabelOverlapped(prevLabel, lastLabel)) { lastLabel.ignore = true; } } } }, /** * @private */ axisName: function () { var opt = this.opt; var axisModel = this.axisModel; var name = retrieve(opt.axisName, axisModel.get('name')); if (!name) { return; } var nameLocation = axisModel.get('nameLocation'); var nameDirection = opt.nameDirection; var textStyleModel = axisModel.getModel('nameTextStyle'); var gap = axisModel.get('nameGap') || 0; var extent = this.axisModel.axis.getExtent(); var gapSignal = extent[0] > extent[1] ? -1 : 1; var pos = [ nameLocation === 'start' ? extent[0] - gapSignal * gap : nameLocation === 'end' ? extent[1] + gapSignal * gap : (extent[0] + extent[1]) / 2, // 'middle' // Reuse labelOffset. nameLocation === 'middle' ? opt.labelOffset + nameDirection * gap : 0 ]; var labelLayout; var nameRotation = axisModel.get('nameRotate'); if (nameRotation != null) { nameRotation = nameRotation * PI / 180; // To radian. } var axisNameAvailableWidth; if (nameLocation === 'middle') { labelLayout = innerTextLayout( opt, nameRotation != null ? nameRotation : opt.rotation, // Adapt to axis. nameDirection ); } else { labelLayout = endTextLayout( opt, nameLocation, nameRotation || 0, extent ); axisNameAvailableWidth = opt.axisNameAvailableWidth; if (axisNameAvailableWidth != null) { axisNameAvailableWidth = Math.abs( axisNameAvailableWidth / Math.sin(labelLayout.rotation) ); !isFinite(axisNameAvailableWidth) && (axisNameAvailableWidth = null); } } var textFont = textStyleModel.getFont(); var truncateOpt = axisModel.get('nameTruncate', true) || {}; var ellipsis = truncateOpt.ellipsis; var maxWidth = retrieve(truncateOpt.maxWidth, axisNameAvailableWidth); var truncatedText = (ellipsis != null && maxWidth != null) ? formatUtil.truncateText( name, maxWidth, textFont, ellipsis, {minChar: 2, placeholder: truncateOpt.placeholder} ) : name; var tooltipOpt = axisModel.get('tooltip', true); var mainType = axisModel.mainType; var formatterParams = { componentType: mainType, name: name, $vars: ['name'] }; formatterParams[mainType + 'Index'] = axisModel.componentIndex; var textEl = new graphic.Text({ // Id for animation anid: 'name', __fullText: name, __truncatedText: truncatedText, style: { text: truncatedText, textFont: textFont, fill: textStyleModel.getTextColor() || axisModel.get('axisLine.lineStyle.color'), textAlign: labelLayout.textAlign, textVerticalAlign: labelLayout.verticalAlign }, position: pos, rotation: labelLayout.rotation, silent: isSilent(axisModel), z2: 1, tooltip: (tooltipOpt && tooltipOpt.show) ? zrUtil.extend({ content: name, formatter: function () { return name; }, formatterParams: formatterParams }, tooltipOpt) : null }); if (axisModel.get('triggerEvent')) { textEl.eventData = makeAxisEventDataBase(axisModel); textEl.eventData.targetType = 'axisName'; textEl.eventData.name = name; } // FIXME this._dumbGroup.add(textEl); textEl.updateTransform(); this.group.add(textEl); textEl.decomposeTransform(); } }; /** * @inner */ function innerTextLayout(opt, textRotation, direction) { var rotationDiff = remRadian(textRotation - opt.rotation); var textAlign; var verticalAlign; if (isRadianAroundZero(rotationDiff)) { // Label is parallel with axis line. verticalAlign = direction > 0 ? 'top' : 'bottom'; textAlign = 'center'; } else if (isRadianAroundZero(rotationDiff - PI)) { // Label is inverse parallel with axis line. verticalAlign = direction > 0 ? 'bottom' : 'top'; textAlign = 'center'; } else { verticalAlign = 'middle'; if (rotationDiff > 0 && rotationDiff < PI) { textAlign = direction > 0 ? 'right' : 'left'; } else { textAlign = direction > 0 ? 'left' : 'right'; } } return { rotation: rotationDiff, textAlign: textAlign, verticalAlign: verticalAlign }; } /** * @inner */ function endTextLayout(opt, textPosition, textRotate, extent) { var rotationDiff = remRadian(textRotate - opt.rotation); var textAlign; var verticalAlign; var inverse = extent[0] > extent[1]; var onLeft = (textPosition === 'start' && !inverse) || (textPosition !== 'start' && inverse); if (isRadianAroundZero(rotationDiff - PI / 2)) { verticalAlign = onLeft ? 'bottom' : 'top'; textAlign = 'center'; } else if (isRadianAroundZero(rotationDiff - PI * 1.5)) { verticalAlign = onLeft ? 'top' : 'bottom'; textAlign = 'center'; } else { verticalAlign = 'middle'; if (rotationDiff < PI * 1.5 && rotationDiff > PI / 2) { textAlign = onLeft ? 'left' : 'right'; } else { textAlign = onLeft ? 'right' : 'left'; } } return { rotation: rotationDiff, textAlign: textAlign, verticalAlign: verticalAlign }; } /** * @inner */ function isSilent(axisModel) { var tooltipOpt = axisModel.get('tooltip'); return axisModel.get('silent') // Consider mouse cursor, add these restrictions. || !( axisModel.get('triggerEvent') || (tooltipOpt && tooltipOpt.show) ); } /** * @static */ var ifIgnoreOnTick = AxisBuilder.ifIgnoreOnTick = function (axis, i, interval) { var rawTick; var scale = axis.scale; return scale.type === 'ordinal' && ( typeof interval === 'function' ? ( rawTick = scale.getTicks()[i], !interval(rawTick, scale.getLabel(rawTick)) ) : i % (interval + 1) ); }; /** * @static */ var getInterval = AxisBuilder.getInterval = function (model, labelInterval) { var interval = model.get('interval'); if (interval == null || interval == 'auto') { interval = labelInterval; } return interval; }; module.exports = AxisBuilder; /***/ }, /* 135 */ /***/ function(module, exports, __webpack_require__) { var zrUtil = __webpack_require__(4); __webpack_require__(114); __webpack_require__(136); __webpack_require__(137); var barLayoutGrid = __webpack_require__(139); var echarts = __webpack_require__(1); echarts.registerLayout(zrUtil.curry(barLayoutGrid, 'bar')); // Visual coding for legend echarts.registerVisual(function (ecModel) { ecModel.eachSeriesByType('bar', function (seriesModel) { var data = seriesModel.getData(); data.setVisual('legendSymbol', 'roundRect'); }); }); // In case developer forget to include grid component __webpack_require__(113); /***/ }, /* 136 */ /***/ function(module, exports, __webpack_require__) { 'use strict'; var SeriesModel = __webpack_require__(28); var createListFromArray = __webpack_require__(102); module.exports = SeriesModel.extend({ type: 'series.bar', dependencies: ['grid', 'polar'], getInitialData: function (option, ecModel) { if (true) { var coordSys = option.coordinateSystem; if (coordSys !== 'cartesian2d') { throw new Error('Bar only support cartesian2d coordinateSystem'); } } return createListFromArray(option.data, this, ecModel); }, getMarkerPosition: function (value) { var coordSys = this.coordinateSystem; if (coordSys) { // PENDING if clamp ? var pt = coordSys.dataToPoint(value, true); var data = this.getData(); var offset = data.getLayout('offset'); var size = data.getLayout('size'); var offsetIndex = coordSys.getBaseAxis().isHorizontal() ? 0 : 1; pt[offsetIndex] += offset + size / 2; return pt; } return [NaN, NaN]; }, brushSelector: 'rect', defaultOption: { zlevel: 0, // 一级层叠 z: 2, // 二级层叠 coordinateSystem: 'cartesian2d', legendHoverLink: true, // stack: null // Cartesian coordinate system // xAxisIndex: 0, // yAxisIndex: 0, // 最小高度改为0 barMinHeight: 0, // barMaxWidth: null, // 默认自适应 // barWidth: null, // 柱间距离,默认为柱形宽度的30%,可设固定值 // barGap: '30%', // 类目间柱形距离,默认为类目间距的20%,可设固定值 // barCategoryGap: '20%', // label: { // normal: { // show: false // } // }, itemStyle: { normal: { // color: '各异' }, emphasis: {} } } }); /***/ }, /* 137 */ /***/ function(module, exports, __webpack_require__) { 'use strict'; var zrUtil = __webpack_require__(4); var graphic = __webpack_require__(43); zrUtil.extend(__webpack_require__(12).prototype, __webpack_require__(138)); function fixLayoutWithLineWidth(layout, lineWidth) { var signX = layout.width > 0 ? 1 : -1; var signY = layout.height > 0 ? 1 : -1; // In case width or height are too small. lineWidth = Math.min(lineWidth, Math.abs(layout.width), Math.abs(layout.height)); layout.x += signX * lineWidth / 2; layout.y += signY * lineWidth / 2; layout.width -= signX * lineWidth; layout.height -= signY * lineWidth; } module.exports = __webpack_require__(1).extendChartView({ type: 'bar', render: function (seriesModel, ecModel, api) { var coordinateSystemType = seriesModel.get('coordinateSystem'); if (coordinateSystemType === 'cartesian2d') { this._renderOnCartesian(seriesModel, ecModel, api); } return this.group; }, dispose: zrUtil.noop, _renderOnCartesian: function (seriesModel, ecModel, api) { var group = this.group; var data = seriesModel.getData(); var oldData = this._data; var cartesian = seriesModel.coordinateSystem; var baseAxis = cartesian.getBaseAxis(); var isHorizontal = baseAxis.isHorizontal(); var enableAnimation = seriesModel.get('animation'); var barBorderWidthQuery = ['itemStyle', 'normal', 'barBorderWidth']; function createRect(dataIndex, isUpdate) { var layout = data.getItemLayout(dataIndex); var lineWidth = data.getItemModel(dataIndex).get(barBorderWidthQuery) || 0; fixLayoutWithLineWidth(layout, lineWidth); var rect = new graphic.Rect({ shape: zrUtil.extend({}, layout) }); // Animation if (enableAnimation) { var rectShape = rect.shape; var animateProperty = isHorizontal ? 'height' : 'width'; var animateTarget = {}; rectShape[animateProperty] = 0; animateTarget[animateProperty] = layout[animateProperty]; graphic[isUpdate? 'updateProps' : 'initProps'](rect, { shape: animateTarget }, seriesModel, dataIndex); } return rect; } data.diff(oldData) .add(function (dataIndex) { // 空数据 if (!data.hasValue(dataIndex)) { return; } var rect = createRect(dataIndex); data.setItemGraphicEl(dataIndex, rect); group.add(rect); }) .update(function (newIndex, oldIndex) { var rect = oldData.getItemGraphicEl(oldIndex); // 空数据 if (!data.hasValue(newIndex)) { group.remove(rect); return; } if (!rect) { rect = createRect(newIndex, true); } var layout = data.getItemLayout(newIndex); var lineWidth = data.getItemModel(newIndex).get(barBorderWidthQuery) || 0; fixLayoutWithLineWidth(layout, lineWidth); graphic.updateProps(rect, { shape: layout }, seriesModel, newIndex); data.setItemGraphicEl(newIndex, rect); // Add back group.add(rect); }) .remove(function (idx) { var rect = oldData.getItemGraphicEl(idx); if (rect) { // Not show text when animating rect.style.text = ''; graphic.updateProps(rect, { shape: { width: 0 } }, seriesModel, idx, function () { group.remove(rect); }); } }) .execute(); this._updateStyle(seriesModel, data, isHorizontal); this._data = data; }, _updateStyle: function (seriesModel, data, isHorizontal) { function setLabel(style, model, color, labelText, labelPositionOutside) { graphic.setText(style, model, color); style.text = labelText; if (style.textPosition === 'outside') { style.textPosition = labelPositionOutside; } } data.eachItemGraphicEl(function (rect, idx) { var itemModel = data.getItemModel(idx); var color = data.getItemVisual(idx, 'color'); var opacity = data.getItemVisual(idx, 'opacity'); var layout = data.getItemLayout(idx); var itemStyleModel = itemModel.getModel('itemStyle.normal'); var hoverStyle = itemModel.getModel('itemStyle.emphasis').getBarItemStyle(); rect.setShape('r', itemStyleModel.get('barBorderRadius') || 0); rect.useStyle(zrUtil.defaults( { fill: color, opacity: opacity }, itemStyleModel.getBarItemStyle() )); var labelPositionOutside = isHorizontal ? (layout.height > 0 ? 'bottom' : 'top') : (layout.width > 0 ? 'left' : 'right'); var labelModel = itemModel.getModel('label.normal'); var hoverLabelModel = itemModel.getModel('label.emphasis'); var rectStyle = rect.style; if (labelModel.get('show')) { setLabel( rectStyle, labelModel, color, zrUtil.retrieve( seriesModel.getFormattedLabel(idx, 'normal'), seriesModel.getRawValue(idx) ), labelPositionOutside ); } else { rectStyle.text = ''; } if (hoverLabelModel.get('show')) { setLabel( hoverStyle, hoverLabelModel, color, zrUtil.retrieve( seriesModel.getFormattedLabel(idx, 'emphasis'), seriesModel.getRawValue(idx) ), labelPositionOutside ); } else { hoverStyle.text = ''; } graphic.setHoverStyle(rect, hoverStyle); }); }, remove: function (ecModel, api) { var group = this.group; if (ecModel.get('animation')) { if (this._data) { this._data.eachItemGraphicEl(function (el) { // Not show text when animating el.style.text = ''; graphic.updateProps(el, { shape: { width: 0 } }, ecModel, el.dataIndex, function () { group.remove(el); }); }); } } else { group.removeAll(); } } }); /***/ }, /* 138 */ /***/ function(module, exports, __webpack_require__) { var getBarItemStyle = __webpack_require__(15)( [ ['fill', 'color'], ['stroke', 'borderColor'], ['lineWidth', 'borderWidth'], // Compatitable with 2 ['stroke', 'barBorderColor'], ['lineWidth', 'barBorderWidth'], ['opacity'], ['shadowBlur'], ['shadowOffsetX'], ['shadowOffsetY'], ['shadowColor'] ] ); module.exports = { getBarItemStyle: function (excludes) { var style = getBarItemStyle.call(this, excludes); if (this.getBorderLineDash) { var lineDash = this.getBorderLineDash(); lineDash && (style.lineDash = lineDash); } return style; } }; /***/ }, /* 139 */ /***/ function(module, exports, __webpack_require__) { 'use strict'; var zrUtil = __webpack_require__(4); var numberUtil = __webpack_require__(7); var parsePercent = numberUtil.parsePercent; function getSeriesStackId(seriesModel) { return seriesModel.get('stack') || '__ec_stack_' + seriesModel.seriesIndex; } function getAxisKey(axis) { return axis.dim + axis.index; } function calBarWidthAndOffset(barSeries, api) { // Columns info on each category axis. Key is cartesian name var columnsMap = {}; zrUtil.each(barSeries, function (seriesModel, idx) { var data = seriesModel.getData(); var cartesian = seriesModel.coordinateSystem; var baseAxis = cartesian.getBaseAxis(); var axisExtent = baseAxis.getExtent(); var bandWidth = baseAxis.type === 'category' ? baseAxis.getBandWidth() : (Math.abs(axisExtent[1] - axisExtent[0]) / data.count()); var columnsOnAxis = columnsMap[getAxisKey(baseAxis)] || { bandWidth: bandWidth, remainedWidth: bandWidth, autoWidthCount: 0, categoryGap: '20%', gap: '30%', stacks: {} }; var stacks = columnsOnAxis.stacks; columnsMap[getAxisKey(baseAxis)] = columnsOnAxis; var stackId = getSeriesStackId(seriesModel); if (!stacks[stackId]) { columnsOnAxis.autoWidthCount++; } stacks[stackId] = stacks[stackId] || { width: 0, maxWidth: 0 }; var barWidth = parsePercent( seriesModel.get('barWidth'), bandWidth ); var barMaxWidth = parsePercent( seriesModel.get('barMaxWidth'), bandWidth ); var barGap = seriesModel.get('barGap'); var barCategoryGap = seriesModel.get('barCategoryGap'); // TODO if (barWidth && !stacks[stackId].width) { barWidth = Math.min(columnsOnAxis.remainedWidth, barWidth); stacks[stackId].width = barWidth; columnsOnAxis.remainedWidth -= barWidth; } barMaxWidth && (stacks[stackId].maxWidth = barMaxWidth); (barGap != null) && (columnsOnAxis.gap = barGap); (barCategoryGap != null) && (columnsOnAxis.categoryGap = barCategoryGap); }); var result = {}; zrUtil.each(columnsMap, function (columnsOnAxis, coordSysName) { result[coordSysName] = {}; var stacks = columnsOnAxis.stacks; var bandWidth = columnsOnAxis.bandWidth; var categoryGap = parsePercent(columnsOnAxis.categoryGap, bandWidth); var barGapPercent = parsePercent(columnsOnAxis.gap, 1); var remainedWidth = columnsOnAxis.remainedWidth; var autoWidthCount = columnsOnAxis.autoWidthCount; var autoWidth = (remainedWidth - categoryGap) / (autoWidthCount + (autoWidthCount - 1) * barGapPercent); autoWidth = Math.max(autoWidth, 0); // Find if any auto calculated bar exceeded maxBarWidth zrUtil.each(stacks, function (column, stack) { var maxWidth = column.maxWidth; if (!column.width && maxWidth && maxWidth < autoWidth) { maxWidth = Math.min(maxWidth, remainedWidth); remainedWidth -= maxWidth; column.width = maxWidth; autoWidthCount--; } }); // Recalculate width again autoWidth = (remainedWidth - categoryGap) / (autoWidthCount + (autoWidthCount - 1) * barGapPercent); autoWidth = Math.max(autoWidth, 0); var widthSum = 0; var lastColumn; zrUtil.each(stacks, function (column, idx) { if (!column.width) { column.width = autoWidth; } lastColumn = column; widthSum += column.width * (1 + barGapPercent); }); if (lastColumn) { widthSum -= lastColumn.width * barGapPercent; } var offset = -widthSum / 2; zrUtil.each(stacks, function (column, stackId) { result[coordSysName][stackId] = result[coordSysName][stackId] || { offset: offset, width: column.width }; offset += column.width * (1 + barGapPercent); }); }); return result; } /** * @param {string} seriesType * @param {module:echarts/model/Global} ecModel * @param {module:echarts/ExtensionAPI} api */ function barLayoutGrid(seriesType, ecModel, api) { var barWidthAndOffset = calBarWidthAndOffset( zrUtil.filter( ecModel.getSeriesByType(seriesType), function (seriesModel) { return !ecModel.isSeriesFiltered(seriesModel) && seriesModel.coordinateSystem && seriesModel.coordinateSystem.type === 'cartesian2d'; } ) ); var lastStackCoords = {}; var lastStackCoordsOrigin = {}; ecModel.eachSeriesByType(seriesType, function (seriesModel) { var data = seriesModel.getData(); var cartesian = seriesModel.coordinateSystem; var baseAxis = cartesian.getBaseAxis(); var stackId = getSeriesStackId(seriesModel); var columnLayoutInfo = barWidthAndOffset[getAxisKey(baseAxis)][stackId]; var columnOffset = columnLayoutInfo.offset; var columnWidth = columnLayoutInfo.width; var valueAxis = cartesian.getOtherAxis(baseAxis); var barMinHeight = seriesModel.get('barMinHeight') || 0; var valueAxisStart = baseAxis.onZero ? valueAxis.toGlobalCoord(valueAxis.dataToCoord(0)) : valueAxis.getGlobalExtent()[0]; var coords = cartesian.dataToPoints(data, true); lastStackCoords[stackId] = lastStackCoords[stackId] || []; lastStackCoordsOrigin[stackId] = lastStackCoordsOrigin[stackId] || []; // Fix #4243 data.setLayout({ offset: columnOffset, size: columnWidth }); data.each(valueAxis.dim, function (value, idx) { // 空数据 if (isNaN(value)) { return; } if (!lastStackCoords[stackId][idx]) { lastStackCoords[stackId][idx] = { p: valueAxisStart, // Positive stack n: valueAxisStart // Negative stack }; lastStackCoordsOrigin[stackId][idx] = { p: valueAxisStart, // Positive stack n: valueAxisStart // Negative stack }; } var sign = value >= 0 ? 'p' : 'n'; var coord = coords[idx]; var lastCoord = lastStackCoords[stackId][idx][sign]; var lastCoordOrigin = lastStackCoordsOrigin[stackId][idx][sign]; var x; var y; var width; var height; if (valueAxis.isHorizontal()) { x = lastCoord; y = coord[1] + columnOffset; width = coord[0] - lastCoordOrigin; height = columnWidth; lastStackCoordsOrigin[stackId][idx][sign] += width; if (Math.abs(width) < barMinHeight) { width = (width < 0 ? -1 : 1) * barMinHeight; } lastStackCoords[stackId][idx][sign] += width; } else { x = coord[0] + columnOffset; y = lastCoord; width = columnWidth; height = coord[1] - lastCoordOrigin; lastStackCoordsOrigin[stackId][idx][sign] += height; if (Math.abs(height) < barMinHeight) { // Include zero to has a positive bar height = (height <= 0 ? -1 : 1) * barMinHeight; } lastStackCoords[stackId][idx][sign] += height; } data.setItemLayout(idx, { x: x, y: y, width: width, height: height }); }, true); }, this); } module.exports = barLayoutGrid; /***/ }, /* 140 */ /***/ function(module, exports, __webpack_require__) { var zrUtil = __webpack_require__(4); var echarts = __webpack_require__(1); __webpack_require__(141); __webpack_require__(143); __webpack_require__(144)('pie', [{ type: 'pieToggleSelect', event: 'pieselectchanged', method: 'toggleSelected' }, { type: 'pieSelect', event: 'pieselected', method: 'select' }, { type: 'pieUnSelect', event: 'pieunselected', method: 'unSelect' }]); echarts.registerVisual(zrUtil.curry(__webpack_require__(145), 'pie')); echarts.registerLayout(zrUtil.curry( __webpack_require__(146), 'pie' )); echarts.registerProcessor(zrUtil.curry(__webpack_require__(148), 'pie')); /***/ }, /* 141 */ /***/ function(module, exports, __webpack_require__) { 'use strict'; var List = __webpack_require__(98); var zrUtil = __webpack_require__(4); var modelUtil = __webpack_require__(5); var completeDimensions = __webpack_require__(103); var dataSelectableMixin = __webpack_require__(142); var PieSeries = __webpack_require__(1).extendSeriesModel({ type: 'series.pie', // Overwrite init: function (option) { PieSeries.superApply(this, 'init', arguments); // Enable legend selection for each data item // Use a function instead of direct access because data reference may changed this.legendDataProvider = function () { return this._dataBeforeProcessed; }; this.updateSelectedMap(option.data); this._defaultLabelLine(option); }, // Overwrite mergeOption: function (newOption) { PieSeries.superCall(this, 'mergeOption', newOption); this.updateSelectedMap(this.option.data); }, getInitialData: function (option, ecModel) { var dimensions = completeDimensions(['value'], option.data); var list = new List(dimensions, this); list.initData(option.data); return list; }, // Overwrite getDataParams: function (dataIndex) { var data = this._data; var params = PieSeries.superCall(this, 'getDataParams', dataIndex); var sum = data.getSum('value'); // FIXME toFixed? // // Percent is 0 if sum is 0 params.percent = !sum ? 0 : +(data.get('value', dataIndex) / sum * 100).toFixed(2); params.$vars.push('percent'); return params; }, _defaultLabelLine: function (option) { // Extend labelLine emphasis modelUtil.defaultEmphasis(option.labelLine, ['show']); var labelLineNormalOpt = option.labelLine.normal; var labelLineEmphasisOpt = option.labelLine.emphasis; // Not show label line if `label.normal.show = false` labelLineNormalOpt.show = labelLineNormalOpt.show && option.label.normal.show; labelLineEmphasisOpt.show = labelLineEmphasisOpt.show && option.label.emphasis.show; }, defaultOption: { zlevel: 0, z: 2, legendHoverLink: true, hoverAnimation: true, // 默认全局居中 center: ['50%', '50%'], radius: [0, '75%'], // 默认顺时针 clockwise: true, startAngle: 90, // 最小角度改为0 minAngle: 0, // 选中是扇区偏移量 selectedOffset: 10, // If use strategy to avoid label overlapping avoidLabelOverlap: true, // 选择模式,默认关闭,可选single,multiple // selectedMode: false, // 南丁格尔玫瑰图模式,'radius'(半径) | 'area'(面积) // roseType: null, label: { normal: { // If rotate around circle rotate: false, show: true, // 'outer', 'inside', 'center' position: 'outer' // formatter: 标签文本格式器,同Tooltip.formatter,不支持异步回调 // textStyle: null // 默认使用全局文本样式,详见TEXTSTYLE // distance: 当position为inner时有效,为label位置到圆心的距离与圆半径(环状图为内外半径和)的比例系数 }, emphasis: {} }, // Enabled when label.normal.position is 'outer' labelLine: { normal: { show: true, // 引导线两段中的第一段长度 length: 15, // 引导线两段中的第二段长度 length2: 15, smooth: false, lineStyle: { // color: 各异, width: 1, type: 'solid' } } }, itemStyle: { normal: { borderWidth: 1 }, emphasis: {} }, animationEasing: 'cubicOut', data: [] } }); zrUtil.mixin(PieSeries, dataSelectableMixin); module.exports = PieSeries; /***/ }, /* 142 */ /***/ function(module, exports, __webpack_require__) { /** * Data selectable mixin for chart series. * To eanble data select, option of series must have `selectedMode`. * And each data item will use `selected` to toggle itself selected status * * @module echarts/chart/helper/DataSelectable */ var zrUtil = __webpack_require__(4); module.exports = { updateSelectedMap: function (targetList) { this._selectTargetMap = zrUtil.reduce(targetList || [], function (targetMap, target) { targetMap[target.name] = target; return targetMap; }, {}); }, /** * @param {string} name */ // PENGING If selectedMode is null ? select: function (name) { var targetMap = this._selectTargetMap; var target = targetMap[name]; var selectedMode = this.get('selectedMode'); if (selectedMode === 'single') { zrUtil.each(targetMap, function (target) { target.selected = false; }); } target && (target.selected = true); }, /** * @param {string} name */ unSelect: function (name) { var target = this._selectTargetMap[name]; // var selectedMode = this.get('selectedMode'); // selectedMode !== 'single' && target && (target.selected = false); target && (target.selected = false); }, /** * @param {string} name */ toggleSelected: function (name) { var target = this._selectTargetMap[name]; if (target != null) { this[target.selected ? 'unSelect' : 'select'](name); return target.selected; } }, /** * @param {string} name */ isSelected: function (name) { var target = this._selectTargetMap[name]; return target && target.selected; } }; /***/ }, /* 143 */ /***/ function(module, exports, __webpack_require__) { var graphic = __webpack_require__(43); var zrUtil = __webpack_require__(4); /** * @param {module:echarts/model/Series} seriesModel * @param {boolean} hasAnimation * @inner */ function updateDataSelected(uid, seriesModel, hasAnimation, api) { var data = seriesModel.getData(); var dataIndex = this.dataIndex; var name = data.getName(dataIndex); var selectedOffset = seriesModel.get('selectedOffset'); api.dispatchAction({ type: 'pieToggleSelect', from: uid, name: name, seriesId: seriesModel.id }); data.each(function (idx) { toggleItemSelected( data.getItemGraphicEl(idx), data.getItemLayout(idx), seriesModel.isSelected(data.getName(idx)), selectedOffset, hasAnimation ); }); } /** * @param {module:zrender/graphic/Sector} el * @param {Object} layout * @param {boolean} isSelected * @param {number} selectedOffset * @param {boolean} hasAnimation * @inner */ function toggleItemSelected(el, layout, isSelected, selectedOffset, hasAnimation) { var midAngle = (layout.startAngle + layout.endAngle) / 2; var dx = Math.cos(midAngle); var dy = Math.sin(midAngle); var offset = isSelected ? selectedOffset : 0; var position = [dx * offset, dy * offset]; hasAnimation // animateTo will stop revious animation like update transition ? el.animate() .when(200, { position: position }) .start('bounceOut') : el.attr('position', position); } /** * Piece of pie including Sector, Label, LabelLine * @constructor * @extends {module:zrender/graphic/Group} */ function PiePiece(data, idx) { graphic.Group.call(this); var sector = new graphic.Sector({ z2: 2 }); var polyline = new graphic.Polyline(); var text = new graphic.Text(); this.add(sector); this.add(polyline); this.add(text); this.updateData(data, idx, true); // Hover to change label and labelLine function onEmphasis() { polyline.ignore = polyline.hoverIgnore; text.ignore = text.hoverIgnore; } function onNormal() { polyline.ignore = polyline.normalIgnore; text.ignore = text.normalIgnore; } this.on('emphasis', onEmphasis) .on('normal', onNormal) .on('mouseover', onEmphasis) .on('mouseout', onNormal); } var piePieceProto = PiePiece.prototype; function getLabelStyle(data, idx, state, labelModel, labelPosition) { var textStyleModel = labelModel.getModel('textStyle'); var isLabelInside = labelPosition === 'inside' || labelPosition === 'inner'; return { fill: textStyleModel.getTextColor() || (isLabelInside ? '#fff' : data.getItemVisual(idx, 'color')), opacity: data.getItemVisual(idx, 'opacity'), textFont: textStyleModel.getFont(), text: zrUtil.retrieve( data.hostModel.getFormattedLabel(idx, state), data.getName(idx) ) }; } piePieceProto.updateData = function (data, idx, firstCreate) { var sector = this.childAt(0); var seriesModel = data.hostModel; var itemModel = data.getItemModel(idx); var layout = data.getItemLayout(idx); var sectorShape = zrUtil.extend({}, layout); sectorShape.label = null; if (firstCreate) { sector.setShape(sectorShape); sector.shape.endAngle = layout.startAngle; graphic.updateProps(sector, { shape: { endAngle: layout.endAngle } }, seriesModel, idx); } else { graphic.updateProps(sector, { shape: sectorShape }, seriesModel, idx); } // Update common style var itemStyleModel = itemModel.getModel('itemStyle'); var visualColor = data.getItemVisual(idx, 'color'); sector.useStyle( zrUtil.defaults( { lineJoin: 'bevel', fill: visualColor }, itemStyleModel.getModel('normal').getItemStyle() ) ); sector.hoverStyle = itemStyleModel.getModel('emphasis').getItemStyle(); // Toggle selected toggleItemSelected( this, data.getItemLayout(idx), itemModel.get('selected'), seriesModel.get('selectedOffset'), seriesModel.get('animation') ); function onEmphasis() { // Sector may has animation of updating data. Force to move to the last frame // Or it may stopped on the wrong shape sector.stopAnimation(true); sector.animateTo({ shape: { r: layout.r + 10 } }, 300, 'elasticOut'); } function onNormal() { sector.stopAnimation(true); sector.animateTo({ shape: { r: layout.r } }, 300, 'elasticOut'); } sector.off('mouseover').off('mouseout').off('emphasis').off('normal'); if (itemModel.get('hoverAnimation') && seriesModel.ifEnableAnimation()) { sector .on('mouseover', onEmphasis) .on('mouseout', onNormal) .on('emphasis', onEmphasis) .on('normal', onNormal); } this._updateLabel(data, idx); graphic.setHoverStyle(this); }; piePieceProto._updateLabel = function (data, idx) { var labelLine = this.childAt(1); var labelText = this.childAt(2); var seriesModel = data.hostModel; var itemModel = data.getItemModel(idx); var layout = data.getItemLayout(idx); var labelLayout = layout.label; var visualColor = data.getItemVisual(idx, 'color'); graphic.updateProps(labelLine, { shape: { points: labelLayout.linePoints || [ [labelLayout.x, labelLayout.y], [labelLayout.x, labelLayout.y], [labelLayout.x, labelLayout.y] ] } }, seriesModel, idx); graphic.updateProps(labelText, { style: { x: labelLayout.x, y: labelLayout.y } }, seriesModel, idx); labelText.attr({ style: { textVerticalAlign: labelLayout.verticalAlign, textAlign: labelLayout.textAlign, textFont: labelLayout.font }, rotation: labelLayout.rotation, origin: [labelLayout.x, labelLayout.y], z2: 10 }); var labelModel = itemModel.getModel('label.normal'); var labelHoverModel = itemModel.getModel('label.emphasis'); var labelLineModel = itemModel.getModel('labelLine.normal'); var labelLineHoverModel = itemModel.getModel('labelLine.emphasis'); var labelPosition = labelModel.get('position') || labelHoverModel.get('position'); labelText.setStyle(getLabelStyle(data, idx, 'normal', labelModel, labelPosition)); labelText.ignore = labelText.normalIgnore = !labelModel.get('show'); labelText.hoverIgnore = !labelHoverModel.get('show'); labelLine.ignore = labelLine.normalIgnore = !labelLineModel.get('show'); labelLine.hoverIgnore = !labelLineHoverModel.get('show'); // Default use item visual color labelLine.setStyle({ stroke: visualColor, opacity: data.getItemVisual(idx, 'opacity') }); labelLine.setStyle(labelLineModel.getModel('lineStyle').getLineStyle()); labelText.hoverStyle = getLabelStyle(data, idx, 'emphasis', labelHoverModel, labelPosition); labelLine.hoverStyle = labelLineHoverModel.getModel('lineStyle').getLineStyle(); var smooth = labelLineModel.get('smooth'); if (smooth && smooth === true) { smooth = 0.4; } labelLine.setShape({ smooth: smooth }); }; zrUtil.inherits(PiePiece, graphic.Group); // Pie view var Pie = __webpack_require__(42).extend({ type: 'pie', init: function () { var sectorGroup = new graphic.Group(); this._sectorGroup = sectorGroup; }, render: function (seriesModel, ecModel, api, payload) { if (payload && (payload.from === this.uid)) { return; } var data = seriesModel.getData(); var oldData = this._data; var group = this.group; var hasAnimation = ecModel.get('animation'); var isFirstRender = !oldData; var onSectorClick = zrUtil.curry( updateDataSelected, this.uid, seriesModel, hasAnimation, api ); var selectedMode = seriesModel.get('selectedMode'); data.diff(oldData) .add(function (idx) { var piePiece = new PiePiece(data, idx); if (isFirstRender) { piePiece.eachChild(function (child) { child.stopAnimation(true); }); } selectedMode && piePiece.on('click', onSectorClick); data.setItemGraphicEl(idx, piePiece); group.add(piePiece); }) .update(function (newIdx, oldIdx) { var piePiece = oldData.getItemGraphicEl(oldIdx); piePiece.updateData(data, newIdx); piePiece.off('click'); selectedMode && piePiece.on('click', onSectorClick); group.add(piePiece); data.setItemGraphicEl(newIdx, piePiece); }) .remove(function (idx) { var piePiece = oldData.getItemGraphicEl(idx); group.remove(piePiece); }) .execute(); if (hasAnimation && isFirstRender && data.count() > 0) { var shape = data.getItemLayout(0); var r = Math.max(api.getWidth(), api.getHeight()) / 2; var removeClipPath = zrUtil.bind(group.removeClipPath, group); group.setClipPath(this._createClipPath( shape.cx, shape.cy, r, shape.startAngle, shape.clockwise, removeClipPath, seriesModel )); } this._data = data; }, dispose: function () {}, _createClipPath: function ( cx, cy, r, startAngle, clockwise, cb, seriesModel ) { var clipPath = new graphic.Sector({ shape: { cx: cx, cy: cy, r0: 0, r: r, startAngle: startAngle, endAngle: startAngle, clockwise: clockwise } }); graphic.initProps(clipPath, { shape: { endAngle: startAngle + (clockwise ? 1 : -1) * Math.PI * 2 } }, seriesModel, cb); return clipPath; }, /** * @implement */ containPoint: function (point, seriesModel) { var data = seriesModel.getData(); var itemLayout = data.getItemLayout(0); if (itemLayout) { var dx = point[0] - itemLayout.cx; var dy = point[1] - itemLayout.cy; var radius = Math.sqrt(dx * dx + dy * dy); return radius <= itemLayout.r && radius >= itemLayout.r0; } } }); module.exports = Pie; /***/ }, /* 144 */ /***/ function(module, exports, __webpack_require__) { var echarts = __webpack_require__(1); var zrUtil = __webpack_require__(4); module.exports = function (seriesType, actionInfos) { zrUtil.each(actionInfos, function (actionInfo) { actionInfo.update = 'updateView'; /** * @payload * @property {string} seriesName * @property {string} name */ echarts.registerAction(actionInfo, function (payload, ecModel) { var selected = {}; ecModel.eachComponent( {mainType: 'series', subType: seriesType, query: payload}, function (seriesModel) { if (seriesModel[actionInfo.method]) { seriesModel[actionInfo.method](payload.name); } var data = seriesModel.getData(); // Create selected map data.each(function (idx) { var name = data.getName(idx); selected[name] = seriesModel.isSelected(name) || false; }); } ); return { name: payload.name, selected: selected }; }); }); }; /***/ }, /* 145 */ /***/ function(module, exports) { // Pick color from palette for each data item module.exports = function (seriesType, ecModel) { // Pie and funnel may use diferrent scope var paletteScope = {}; ecModel.eachRawSeriesByType(seriesType, function (seriesModel) { var dataAll = seriesModel.getRawData(); var idxMap = {}; if (!ecModel.isSeriesFiltered(seriesModel)) { var data = seriesModel.getData(); data.each(function (idx) { var rawIdx = data.getRawIndex(idx); idxMap[rawIdx] = idx; }); dataAll.each(function (rawIdx) { // FIXME Performance var itemModel = dataAll.getItemModel(rawIdx); var filteredIdx = idxMap[rawIdx]; // If series.itemStyle.normal.color is a function. itemVisual may be encoded var singleDataColor = filteredIdx != null && data.getItemVisual(filteredIdx, 'color', true); if (!singleDataColor) { var color = itemModel.get('itemStyle.normal.color') || seriesModel.getColorFromPalette(dataAll.getName(rawIdx), paletteScope); // Legend may use the visual info in data before processed dataAll.setItemVisual(rawIdx, 'color', color); // Data is not filtered if (filteredIdx != null) { data.setItemVisual(filteredIdx, 'color', color); } } else { // Set data all color for legend dataAll.setItemVisual(rawIdx, 'color', singleDataColor); } }); } }); }; /***/ }, /* 146 */ /***/ function(module, exports, __webpack_require__) { // TODO minAngle var numberUtil = __webpack_require__(7); var parsePercent = numberUtil.parsePercent; var labelLayout = __webpack_require__(147); var zrUtil = __webpack_require__(4); var PI2 = Math.PI * 2; var RADIAN = Math.PI / 180; module.exports = function (seriesType, ecModel, api, payload) { ecModel.eachSeriesByType(seriesType, function (seriesModel) { var center = seriesModel.get('center'); var radius = seriesModel.get('radius'); if (!zrUtil.isArray(radius)) { radius = [0, radius]; } if (!zrUtil.isArray(center)) { center = [center, center]; } var width = api.getWidth(); var height = api.getHeight(); var size = Math.min(width, height); var cx = parsePercent(center[0], width); var cy = parsePercent(center[1], height); var r0 = parsePercent(radius[0], size / 2); var r = parsePercent(radius[1], size / 2); var data = seriesModel.getData(); var startAngle = -seriesModel.get('startAngle') * RADIAN; var minAngle = seriesModel.get('minAngle') * RADIAN; var sum = data.getSum('value'); // Sum may be 0 var unitRadian = Math.PI / (sum || data.count()) * 2; var clockwise = seriesModel.get('clockwise'); var roseType = seriesModel.get('roseType'); // [0...max] var extent = data.getDataExtent('value'); extent[0] = 0; // In the case some sector angle is smaller than minAngle var restAngle = PI2; var valueSumLargerThanMinAngle = 0; var currentAngle = startAngle; var dir = clockwise ? 1 : -1; data.each('value', function (value, idx) { var angle; // FIXME 兼容 2.0 但是 roseType 是 area 的时候才是这样? if (roseType !== 'area') { angle = sum === 0 ? unitRadian : (value * unitRadian); } else { angle = PI2 / (data.count() || 1); } if (angle < minAngle) { angle = minAngle; restAngle -= minAngle; } else { valueSumLargerThanMinAngle += value; } var endAngle = currentAngle + dir * angle; data.setItemLayout(idx, { angle: angle, startAngle: currentAngle, endAngle: endAngle, clockwise: clockwise, cx: cx, cy: cy, r0: r0, r: roseType ? numberUtil.linearMap(value, extent, [r0, r]) : r }); currentAngle = endAngle; }, true); // Some sector is constrained by minAngle // Rest sectors needs recalculate angle if (restAngle < PI2) { // Average the angle if rest angle is not enough after all angles is // Constrained by minAngle if (restAngle <= 1e-3) { var angle = PI2 / data.count(); data.each(function (idx) { var layout = data.getItemLayout(idx); layout.startAngle = startAngle + dir * idx * angle; layout.endAngle = startAngle + dir * (idx + 1) * angle; }); } else { unitRadian = restAngle / valueSumLargerThanMinAngle; currentAngle = startAngle; data.each('value', function (value, idx) { var layout = data.getItemLayout(idx); var angle = layout.angle === minAngle ? minAngle : value * unitRadian; layout.startAngle = currentAngle; layout.endAngle = currentAngle + dir * angle; currentAngle += dir * angle; }); } } labelLayout(seriesModel, r, width, height); }); }; /***/ }, /* 147 */ /***/ function(module, exports, __webpack_require__) { 'use strict'; // FIXME emphasis label position is not same with normal label position var textContain = __webpack_require__(8); function adjustSingleSide(list, cx, cy, r, dir, viewWidth, viewHeight) { list.sort(function (a, b) { return a.y - b.y; }); // 压 function shiftDown(start, end, delta, dir) { for (var j = start; j < end; j++) { list[j].y += delta; if (j > start && j + 1 < end && list[j + 1].y > list[j].y + list[j].height ) { shiftUp(j, delta / 2); return; } } shiftUp(end - 1, delta / 2); } // 弹 function shiftUp(end, delta) { for (var j = end; j >= 0; j--) { list[j].y -= delta; if (j > 0 && list[j].y > list[j - 1].y + list[j - 1].height ) { break; } } } function changeX(list, isDownList, cx, cy, r, dir) { var lastDeltaX = dir > 0 ? isDownList // 右侧 ? Number.MAX_VALUE // 下 : 0 // 上 : isDownList // 左侧 ? Number.MAX_VALUE // 下 : 0; // 上 for (var i = 0, l = list.length; i < l; i++) { // Not change x for center label if (list[i].position === 'center') { continue; } var deltaY = Math.abs(list[i].y - cy); var length = list[i].len; var length2 = list[i].len2; var deltaX = (deltaY < r + length) ? Math.sqrt( (r + length + length2) * (r + length + length2) - deltaY * deltaY ) : Math.abs(list[i].x - cx); if (isDownList && deltaX >= lastDeltaX) { // 右下,左下 deltaX = lastDeltaX - 10; } if (!isDownList && deltaX <= lastDeltaX) { // 右上,左上 deltaX = lastDeltaX + 10; } list[i].x = cx + deltaX * dir; lastDeltaX = deltaX; } } var lastY = 0; var delta; var len = list.length; var upList = []; var downList = []; for (var i = 0; i < len; i++) { delta = list[i].y - lastY; if (delta < 0) { shiftDown(i, len, -delta, dir); } lastY = list[i].y + list[i].height; } if (viewHeight - lastY < 0) { shiftUp(len - 1, lastY - viewHeight); } for (var i = 0; i < len; i++) { if (list[i].y >= cy) { downList.push(list[i]); } else { upList.push(list[i]); } } changeX(upList, false, cx, cy, r, dir); changeX(downList, true, cx, cy, r, dir); } function avoidOverlap(labelLayoutList, cx, cy, r, viewWidth, viewHeight) { var leftList = []; var rightList = []; for (var i = 0; i < labelLayoutList.length; i++) { if (labelLayoutList[i].x < cx) { leftList.push(labelLayoutList[i]); } else { rightList.push(labelLayoutList[i]); } } adjustSingleSide(rightList, cx, cy, r, 1, viewWidth, viewHeight); adjustSingleSide(leftList, cx, cy, r, -1, viewWidth, viewHeight); for (var i = 0; i < labelLayoutList.length; i++) { var linePoints = labelLayoutList[i].linePoints; if (linePoints) { var dist = linePoints[1][0] - linePoints[2][0]; if (labelLayoutList[i].x < cx) { linePoints[2][0] = labelLayoutList[i].x + 3; } else { linePoints[2][0] = labelLayoutList[i].x - 3; } linePoints[1][1] = linePoints[2][1] = labelLayoutList[i].y; linePoints[1][0] = linePoints[2][0] + dist; } } } module.exports = function (seriesModel, r, viewWidth, viewHeight) { var data = seriesModel.getData(); var labelLayoutList = []; var cx; var cy; var hasLabelRotate = false; data.each(function (idx) { var layout = data.getItemLayout(idx); var itemModel = data.getItemModel(idx); var labelModel = itemModel.getModel('label.normal'); // Use position in normal or emphasis var labelPosition = labelModel.get('position') || itemModel.get('label.emphasis.position'); var labelLineModel = itemModel.getModel('labelLine.normal'); var labelLineLen = labelLineModel.get('length'); var labelLineLen2 = labelLineModel.get('length2'); var midAngle = (layout.startAngle + layout.endAngle) / 2; var dx = Math.cos(midAngle); var dy = Math.sin(midAngle); var textX; var textY; var linePoints; var textAlign; cx = layout.cx; cy = layout.cy; var isLabelInside = labelPosition === 'inside' || labelPosition === 'inner'; if (labelPosition === 'center') { textX = layout.cx; textY = layout.cy; textAlign = 'center'; } else { var x1 = (isLabelInside ? (layout.r + layout.r0) / 2 * dx : layout.r * dx) + cx; var y1 = (isLabelInside ? (layout.r + layout.r0) / 2 * dy : layout.r * dy) + cy; textX = x1 + dx * 3; textY = y1 + dy * 3; if (!isLabelInside) { // For roseType var x2 = x1 + dx * (labelLineLen + r - layout.r); var y2 = y1 + dy * (labelLineLen + r - layout.r); var x3 = x2 + ((dx < 0 ? -1 : 1) * labelLineLen2); var y3 = y2; textX = x3 + (dx < 0 ? -5 : 5); textY = y3; linePoints = [[x1, y1], [x2, y2], [x3, y3]]; } textAlign = isLabelInside ? 'center' : (dx > 0 ? 'left' : 'right'); } var font = labelModel.getModel('textStyle').getFont(); var labelRotate = labelModel.get('rotate') ? (dx < 0 ? -midAngle + Math.PI : -midAngle) : 0; var text = seriesModel.getFormattedLabel(idx, 'normal') || data.getName(idx); var textRect = textContain.getBoundingRect( text, font, textAlign, 'top' ); hasLabelRotate = !!labelRotate; layout.label = { x: textX, y: textY, position: labelPosition, height: textRect.height, len: labelLineLen, len2: labelLineLen2, linePoints: linePoints, textAlign: textAlign, verticalAlign: 'middle', font: font, rotation: labelRotate }; // Not layout the inside label if (!isLabelInside) { labelLayoutList.push(layout.label); } }); if (!hasLabelRotate && seriesModel.get('avoidLabelOverlap')) { avoidOverlap(labelLayoutList, cx, cy, r, viewWidth, viewHeight); } }; /***/ }, /* 148 */ /***/ function(module, exports) { module.exports = function (seriesType, ecModel) { var legendModels = ecModel.findComponents({ mainType: 'legend' }); if (!legendModels || !legendModels.length) { return; } ecModel.eachSeriesByType(seriesType, function (series) { var data = series.getData(); data.filterSelf(function (idx) { var name = data.getName(idx); // If in any legend component the status is not selected. for (var i = 0; i < legendModels.length; i++) { if (!legendModels[i].isSelected(name)) { return false; } } return true; }, this); }, this); }; /***/ }, /* 149 */ /***/ function(module, exports, __webpack_require__) { var zrUtil = __webpack_require__(4); var echarts = __webpack_require__(1); __webpack_require__(150); __webpack_require__(151); echarts.registerVisual(zrUtil.curry( __webpack_require__(110), 'scatter', 'circle', null )); echarts.registerLayout(zrUtil.curry( __webpack_require__(111), 'scatter' )); // In case developer forget to include grid component __webpack_require__(113); /***/ }, /* 150 */ /***/ function(module, exports, __webpack_require__) { 'use strict'; var createListFromArray = __webpack_require__(102); var SeriesModel = __webpack_require__(28); module.exports = SeriesModel.extend({ type: 'series.scatter', dependencies: ['grid', 'polar'], getInitialData: function (option, ecModel) { var list = createListFromArray(option.data, this, ecModel); return list; }, brushSelector: 'point', defaultOption: { coordinateSystem: 'cartesian2d', zlevel: 0, z: 2, legendHoverLink: true, hoverAnimation: true, // Cartesian coordinate system // xAxisIndex: 0, // yAxisIndex: 0, // Polar coordinate system // polarIndex: 0, // Geo coordinate system // geoIndex: 0, // symbol: null, // 图形类型 symbolSize: 10, // 图形大小,半宽(半径)参数,当图形为方向或菱形则总宽度为symbolSize * 2 // symbolRotate: null, // 图形旋转控制 large: false, // Available when large is true largeThreshold: 2000, // label: { // normal: { // show: false // distance: 5, // formatter: 标签文本格式器,同Tooltip.formatter,不支持异步回调 // position: 默认自适应,水平布局为'top',垂直布局为'right',可选为 // 'inside'|'left'|'right'|'top'|'bottom' // textStyle: null // 默认使用全局文本样式,详见TEXTSTYLE // } // }, itemStyle: { normal: { opacity: 0.8 // color: 各异 } } } }); /***/ }, /* 151 */ /***/ function(module, exports, __webpack_require__) { var SymbolDraw = __webpack_require__(105); var LargeSymbolDraw = __webpack_require__(152); __webpack_require__(1).extendChartView({ type: 'scatter', init: function () { this._normalSymbolDraw = new SymbolDraw(); this._largeSymbolDraw = new LargeSymbolDraw(); }, render: function (seriesModel, ecModel, api) { var data = seriesModel.getData(); var largeSymbolDraw = this._largeSymbolDraw; var normalSymbolDraw = this._normalSymbolDraw; var group = this.group; var symbolDraw = seriesModel.get('large') && data.count() > seriesModel.get('largeThreshold') ? largeSymbolDraw : normalSymbolDraw; this._symbolDraw = symbolDraw; symbolDraw.updateData(data); group.add(symbolDraw.group); group.remove( symbolDraw === largeSymbolDraw ? normalSymbolDraw.group : largeSymbolDraw.group ); }, updateLayout: function (seriesModel) { this._symbolDraw.updateLayout(seriesModel); }, remove: function (ecModel, api) { this._symbolDraw && this._symbolDraw.remove(api, true); }, dispose: function () {} }); /***/ }, /* 152 */ /***/ function(module, exports, __webpack_require__) { // TODO Batch by color var graphic = __webpack_require__(43); var symbolUtil = __webpack_require__(107); var LargeSymbolPath = graphic.extendShape({ shape: { points: null, sizes: null }, symbolProxy: null, buildPath: function (path, shape) { var points = shape.points; var sizes = shape.sizes; var symbolProxy = this.symbolProxy; var symbolProxyShape = symbolProxy.shape; for (var i = 0; i < points.length; i++) { var pt = points[i]; var size = sizes[i]; if (size[0] < 4) { // Optimize for small symbol path.rect( pt[0] - size[0] / 2, pt[1] - size[1] / 2, size[0], size[1] ); } else { symbolProxyShape.x = pt[0] - size[0] / 2; symbolProxyShape.y = pt[1] - size[1] / 2; symbolProxyShape.width = size[0]; symbolProxyShape.height = size[1]; symbolProxy.buildPath(path, symbolProxyShape, true); } } }, findDataIndex: function (x, y) { var shape = this.shape; var points = shape.points; var sizes = shape.sizes; // Not consider transform // Treat each element as a rect // top down traverse for (var i = points.length - 1; i >= 0; i--) { var pt = points[i]; var size = sizes[i]; var x0 = pt[0] - size[0] / 2; var y0 = pt[1] - size[1] / 2; if (x >= x0 && y >= y0 && x <= x0 + size[0] && y <= y0 + size[1]) { // i is dataIndex return i; } } return -1; } }); function LargeSymbolDraw() { this.group = new graphic.Group(); this._symbolEl = new LargeSymbolPath({ // rectHover: true, // cursor: 'default' }); } var largeSymbolProto = LargeSymbolDraw.prototype; /** * Update symbols draw by new data * @param {module:echarts/data/List} data */ largeSymbolProto.updateData = function (data) { this.group.removeAll(); var symbolEl = this._symbolEl; var seriesModel = data.hostModel; symbolEl.setShape({ points: data.mapArray(data.getItemLayout), sizes: data.mapArray( function (idx) { var size = data.getItemVisual(idx, 'symbolSize'); if (!(size instanceof Array)) { size = [size, size]; } return size; } ) }); // Create symbolProxy to build path for each data symbolEl.symbolProxy = symbolUtil.createSymbol( data.getVisual('symbol'), 0, 0, 0, 0 ); // Use symbolProxy setColor method symbolEl.setColor = symbolEl.symbolProxy.setColor; symbolEl.useStyle( seriesModel.getModel('itemStyle.normal').getItemStyle(['color']) ); var visualColor = data.getVisual('color'); if (visualColor) { symbolEl.setColor(visualColor); } // Enable tooltip // PENDING May have performance issue when path is extremely large symbolEl.seriesIndex = seriesModel.seriesIndex; symbolEl.on('mousemove', function (e) { symbolEl.dataIndex = null; var dataIndex = symbolEl.findDataIndex(e.offsetX, e.offsetY); if (dataIndex > 0) { // Provide dataIndex for tooltip symbolEl.dataIndex = dataIndex; } }); // Add back this.group.add(symbolEl); }; largeSymbolProto.updateLayout = function (seriesModel) { var data = seriesModel.getData(); this._symbolEl.setShape({ points: data.mapArray(data.getItemLayout) }); }; largeSymbolProto.remove = function () { this.group.removeAll(); }; module.exports = LargeSymbolDraw; /***/ }, /* 153 */ /***/ function(module, exports, __webpack_require__) { var zrUtil = __webpack_require__(4); var echarts = __webpack_require__(1); // Must use radar component __webpack_require__(154); __webpack_require__(159); __webpack_require__(160); echarts.registerVisual(zrUtil.curry(__webpack_require__(145), 'radar')); echarts.registerVisual(zrUtil.curry( __webpack_require__(110), 'radar', 'circle', null )); echarts.registerLayout(__webpack_require__(161)); echarts.registerProcessor( zrUtil.curry(__webpack_require__(148), 'radar') ); echarts.registerPreprocessor(__webpack_require__(162)); /***/ }, /* 154 */ /***/ function(module, exports, __webpack_require__) { __webpack_require__(155); __webpack_require__(157); __webpack_require__(158); /***/ }, /* 155 */ /***/ function(module, exports, __webpack_require__) { // TODO clockwise var zrUtil = __webpack_require__(4); var IndicatorAxis = __webpack_require__(156); var IntervalScale = __webpack_require__(118); var numberUtil = __webpack_require__(7); var axisHelper = __webpack_require__(115); function Radar(radarModel, ecModel, api) { this._model = radarModel; /** * Radar dimensions * @type {Array.} */ this.dimensions = []; this._indicatorAxes = zrUtil.map(radarModel.getIndicatorModels(), function (indicatorModel, idx) { var dim = 'indicator_' + idx; var indicatorAxis = new IndicatorAxis(dim, new IntervalScale()); indicatorAxis.name = indicatorModel.get('name'); // Inject model and axis indicatorAxis.model = indicatorModel; indicatorModel.axis = indicatorAxis; this.dimensions.push(dim); return indicatorAxis; }, this); this.resize(radarModel, api); /** * @type {number} * @readOnly */ this.cx; /** * @type {number} * @readOnly */ this.cy; /** * @type {number} * @readOnly */ this.r; /** * @type {number} * @readOnly */ this.startAngle; } Radar.prototype.getIndicatorAxes = function () { return this._indicatorAxes; }; Radar.prototype.dataToPoint = function (value, indicatorIndex) { var indicatorAxis = this._indicatorAxes[indicatorIndex]; return this.coordToPoint(indicatorAxis.dataToCoord(value), indicatorIndex); }; Radar.prototype.coordToPoint = function (coord, indicatorIndex) { var indicatorAxis = this._indicatorAxes[indicatorIndex]; var angle = indicatorAxis.angle; var x = this.cx + coord * Math.cos(angle); var y = this.cy - coord * Math.sin(angle); return [x, y]; }; Radar.prototype.pointToData = function (pt) { var dx = pt[0] - this.cx; var dy = pt[1] - this.cy; var radius = Math.sqrt(dx * dx + dy * dy); dx /= radius; dy /= radius; var radian = Math.atan2(-dy, dx); // Find the closest angle // FIXME index can calculated directly var minRadianDiff = Infinity; var closestAxis; var closestAxisIdx = -1; for (var i = 0; i < this._indicatorAxes.length; i++) { var indicatorAxis = this._indicatorAxes[i]; var diff = Math.abs(radian - indicatorAxis.angle); if (diff < minRadianDiff) { closestAxis = indicatorAxis; closestAxisIdx = i; minRadianDiff = diff; } } return [closestAxisIdx, +(closestAxis && closestAxis.coodToData(radius))]; }; Radar.prototype.resize = function (radarModel, api) { var center = radarModel.get('center'); var viewWidth = api.getWidth(); var viewHeight = api.getHeight(); var viewSize = Math.min(viewWidth, viewHeight) / 2; this.cx = numberUtil.parsePercent(center[0], viewWidth); this.cy = numberUtil.parsePercent(center[1], viewHeight); this.startAngle = radarModel.get('startAngle') * Math.PI / 180; this.r = numberUtil.parsePercent(radarModel.get('radius'), viewSize); zrUtil.each(this._indicatorAxes, function (indicatorAxis, idx) { indicatorAxis.setExtent(0, this.r); var angle = (this.startAngle + idx * Math.PI * 2 / this._indicatorAxes.length); // Normalize to [-PI, PI] angle = Math.atan2(Math.sin(angle), Math.cos(angle)); indicatorAxis.angle = angle; }, this); }; Radar.prototype.update = function (ecModel, api) { var indicatorAxes = this._indicatorAxes; var radarModel = this._model; zrUtil.each(indicatorAxes, function (indicatorAxis) { indicatorAxis.scale.setExtent(Infinity, -Infinity); }); ecModel.eachSeriesByType('radar', function (radarSeries, idx) { if (radarSeries.get('coordinateSystem') !== 'radar' || ecModel.getComponent('radar', radarSeries.get('radarIndex')) !== radarModel ) { return; } var data = radarSeries.getData(); zrUtil.each(indicatorAxes, function (indicatorAxis) { indicatorAxis.scale.unionExtent(data.getDataExtent(indicatorAxis.dim)); }); }, this); var splitNumber = radarModel.get('splitNumber'); function increaseInterval(interval) { var exp10 = Math.pow(10, Math.floor(Math.log(interval) / Math.LN10)); // Increase interval var f = interval / exp10; if (f === 2) { f = 5; } else { // f is 2 or 5 f *= 2; } return f * exp10; } // Force all the axis fixing the maxSplitNumber. zrUtil.each(indicatorAxes, function (indicatorAxis, idx) { var rawExtent = axisHelper.getScaleExtent(indicatorAxis, indicatorAxis.model); axisHelper.niceScaleExtent(indicatorAxis, indicatorAxis.model); var axisModel = indicatorAxis.model; var scale = indicatorAxis.scale; var fixedMin = axisModel.get('min'); var fixedMax = axisModel.get('max'); var interval = scale.getInterval(); if (fixedMin != null && fixedMax != null) { // User set min, max, divide to get new interval // FIXME precision scale.setInterval( (fixedMax - fixedMin) / splitNumber ); } else if (fixedMin != null) { var max; // User set min, expand extent on the other side do { max = fixedMin + interval * splitNumber; scale.setExtent(+fixedMin, max); // Interval must been set after extent // FIXME scale.setInterval(interval); interval = increaseInterval(interval); } while (max < rawExtent[1] && isFinite(max) && isFinite(rawExtent[1])); } else if (fixedMax != null) { var min; // User set min, expand extent on the other side do { min = fixedMax - interval * splitNumber; scale.setExtent(min, +fixedMax); scale.setInterval(interval); interval = increaseInterval(interval); } while (min > rawExtent[0] && isFinite(min) && isFinite(rawExtent[0])); } else { var nicedSplitNumber = scale.getTicks().length - 1; if (nicedSplitNumber > splitNumber) { interval = increaseInterval(interval); } // PENDING var center = Math.round((rawExtent[0] + rawExtent[1]) / 2 / interval) * interval; var halfSplitNumber = Math.round(splitNumber / 2); scale.setExtent( numberUtil.round(center - halfSplitNumber * interval), numberUtil.round(center + (splitNumber - halfSplitNumber) * interval) ); scale.setInterval(interval); } }); }; /** * Radar dimensions is based on the data * @type {Array} */ Radar.dimensions = []; Radar.create = function (ecModel, api) { var radarList = []; ecModel.eachComponent('radar', function (radarModel) { var radar = new Radar(radarModel, ecModel, api); radarList.push(radar); radarModel.coordinateSystem = radar; }); ecModel.eachSeriesByType('radar', function (radarSeries) { if (radarSeries.get('coordinateSystem') === 'radar') { // Inject coordinate system radarSeries.coordinateSystem = radarList[radarSeries.get('radarIndex') || 0]; } }); return radarList; }; __webpack_require__(26).register('radar', Radar); module.exports = Radar; /***/ }, /* 156 */ /***/ function(module, exports, __webpack_require__) { var zrUtil = __webpack_require__(4); var Axis = __webpack_require__(124); function IndicatorAxis(dim, scale, radiusExtent) { Axis.call(this, dim, scale, radiusExtent); /** * Axis type * - 'category' * - 'value' * - 'time' * - 'log' * @type {string} */ this.type = 'value'; this.angle = 0; /** * Indicator name * @type {string} */ this.name = ''; /** * @type {module:echarts/model/Model} */ this.model; } zrUtil.inherits(IndicatorAxis, Axis); module.exports = IndicatorAxis; /***/ }, /* 157 */ /***/ function(module, exports, __webpack_require__) { var axisDefault = __webpack_require__(129); var valueAxisDefault = axisDefault.valueAxis; var Model = __webpack_require__(12); var zrUtil = __webpack_require__(4); var axisModelCommonMixin = __webpack_require__(130); function defaultsShow(opt, show) { return zrUtil.defaults({ show: show }, opt); } var RadarModel = __webpack_require__(1).extendComponentModel({ type: 'radar', optionUpdated: function () { var boundaryGap = this.get('boundaryGap'); var splitNumber = this.get('splitNumber'); var scale = this.get('scale'); var axisLine = this.get('axisLine'); var axisTick = this.get('axisTick'); var axisLabel = this.get('axisLabel'); var nameTextStyle = this.get('name.textStyle'); var showName = this.get('name.show'); var nameFormatter = this.get('name.formatter'); var nameGap = this.get('nameGap'); var triggerEvent = this.get('triggerEvent'); var indicatorModels = zrUtil.map(this.get('indicator') || [], function (indicatorOpt) { // PENDING if (indicatorOpt.max != null && indicatorOpt.max > 0 && !indicatorOpt.min) { indicatorOpt.min = 0; } else if (indicatorOpt.min != null && indicatorOpt.min < 0 && !indicatorOpt.max) { indicatorOpt.max = 0; } // Use same configuration indicatorOpt = zrUtil.merge(zrUtil.clone(indicatorOpt), { boundaryGap: boundaryGap, splitNumber: splitNumber, scale: scale, axisLine: axisLine, axisTick: axisTick, axisLabel: axisLabel, // Competitable with 2 and use text name: indicatorOpt.text, nameLocation: 'end', nameGap: nameGap, // min: 0, nameTextStyle: nameTextStyle, triggerEvent: triggerEvent }, false); if (!showName) { indicatorOpt.name = ''; } if (typeof nameFormatter === 'string') { var indName = indicatorOpt.name; indicatorOpt.name = nameFormatter.replace('{value}', indName != null ? indName : ''); } else if (typeof nameFormatter === 'function') { indicatorOpt.name = nameFormatter( indicatorOpt.name, indicatorOpt ); } var model = zrUtil.extend( new Model(indicatorOpt, null, this.ecModel), axisModelCommonMixin ); // For triggerEvent. model.mainType = 'radar'; model.componentIndex = this.componentIndex; return model; }, this); this.getIndicatorModels = function () { return indicatorModels; }; }, defaultOption: { zlevel: 0, z: 0, center: ['50%', '50%'], radius: '75%', startAngle: 90, name: { show: true // formatter: null // textStyle: {} }, boundaryGap: [0, 0], splitNumber: 5, nameGap: 15, scale: false, // Polygon or circle shape: 'polygon', axisLine: zrUtil.merge( { lineStyle: { color: '#bbb' } }, valueAxisDefault.axisLine ), axisLabel: defaultsShow(valueAxisDefault.axisLabel, false), axisTick: defaultsShow(valueAxisDefault.axisTick, false), splitLine: defaultsShow(valueAxisDefault.splitLine, true), splitArea: defaultsShow(valueAxisDefault.splitArea, true), // {text, min, max} indicator: [] } }); module.exports = RadarModel; /***/ }, /* 158 */ /***/ function(module, exports, __webpack_require__) { var AxisBuilder = __webpack_require__(134); var zrUtil = __webpack_require__(4); var graphic = __webpack_require__(43); var axisBuilderAttrs = [ 'axisLine', 'axisLabel', 'axisTick', 'axisName' ]; module.exports = __webpack_require__(1).extendComponentView({ type: 'radar', render: function (radarModel, ecModel, api) { var group = this.group; group.removeAll(); this._buildAxes(radarModel); this._buildSplitLineAndArea(radarModel); }, _buildAxes: function (radarModel) { var radar = radarModel.coordinateSystem; var indicatorAxes = radar.getIndicatorAxes(); var axisBuilders = zrUtil.map(indicatorAxes, function (indicatorAxis) { var axisBuilder = new AxisBuilder(indicatorAxis.model, { position: [radar.cx, radar.cy], rotation: indicatorAxis.angle, labelDirection: -1, tickDirection: -1, nameDirection: 1 }); return axisBuilder; }); zrUtil.each(axisBuilders, function (axisBuilder) { zrUtil.each(axisBuilderAttrs, axisBuilder.add, axisBuilder); this.group.add(axisBuilder.getGroup()); }, this); }, _buildSplitLineAndArea: function (radarModel) { var radar = radarModel.coordinateSystem; var splitNumber = radarModel.get('splitNumber'); var indicatorAxes = radar.getIndicatorAxes(); if (!indicatorAxes.length) { return; } var shape = radarModel.get('shape'); var splitLineModel = radarModel.getModel('splitLine'); var splitAreaModel = radarModel.getModel('splitArea'); var lineStyleModel = splitLineModel.getModel('lineStyle'); var areaStyleModel = splitAreaModel.getModel('areaStyle'); var showSplitLine = splitLineModel.get('show'); var showSplitArea = splitAreaModel.get('show'); var splitLineColors = lineStyleModel.get('color'); var splitAreaColors = areaStyleModel.get('color'); splitLineColors = zrUtil.isArray(splitLineColors) ? splitLineColors : [splitLineColors]; splitAreaColors = zrUtil.isArray(splitAreaColors) ? splitAreaColors : [splitAreaColors]; var splitLines = []; var splitAreas = []; function getColorIndex(areaOrLine, areaOrLineColorList, idx) { var colorIndex = idx % areaOrLineColorList.length; areaOrLine[colorIndex] = areaOrLine[colorIndex] || []; return colorIndex; } if (shape === 'circle') { var ticksRadius = indicatorAxes[0].getTicksCoords(); var cx = radar.cx; var cy = radar.cy; for (var i = 0; i < ticksRadius.length; i++) { if (showSplitLine) { var colorIndex = getColorIndex(splitLines, splitLineColors, i); splitLines[colorIndex].push(new graphic.Circle({ shape: { cx: cx, cy: cy, r: ticksRadius[i] } })); } if (showSplitArea && i < ticksRadius.length - 1) { var colorIndex = getColorIndex(splitAreas, splitAreaColors, i); splitAreas[colorIndex].push(new graphic.Ring({ shape: { cx: cx, cy: cy, r0: ticksRadius[i], r: ticksRadius[i + 1] } })); } } } // Polyyon else { var axesTicksPoints = zrUtil.map(indicatorAxes, function (indicatorAxis, idx) { var ticksCoords = indicatorAxis.getTicksCoords(); return zrUtil.map(ticksCoords, function (tickCoord) { return radar.coordToPoint(tickCoord, idx); }); }); var prevPoints = []; for (var i = 0; i <= splitNumber; i++) { var points = []; for (var j = 0; j < indicatorAxes.length; j++) { points.push(axesTicksPoints[j][i]); } // Close if (points[0]) { points.push(points[0].slice()); } else { if (true) { console.error('Can\'t draw value axis ' + i); } } if (showSplitLine) { var colorIndex = getColorIndex(splitLines, splitLineColors, i); splitLines[colorIndex].push(new graphic.Polyline({ shape: { points: points } })); } if (showSplitArea && prevPoints) { var colorIndex = getColorIndex(splitAreas, splitAreaColors, i - 1); splitAreas[colorIndex].push(new graphic.Polygon({ shape: { points: points.concat(prevPoints) } })); } prevPoints = points.slice().reverse(); } } var lineStyle = lineStyleModel.getLineStyle(); var areaStyle = areaStyleModel.getAreaStyle(); // Add splitArea before splitLine zrUtil.each(splitAreas, function (splitAreas, idx) { this.group.add(graphic.mergePath( splitAreas, { style: zrUtil.defaults({ stroke: 'none', fill: splitAreaColors[idx % splitAreaColors.length] }, areaStyle), silent: true } )); }, this); zrUtil.each(splitLines, function (splitLines, idx) { this.group.add(graphic.mergePath( splitLines, { style: zrUtil.defaults({ fill: 'none', stroke: splitLineColors[idx % splitLineColors.length] }, lineStyle), silent: true } )); }, this); } }); /***/ }, /* 159 */ /***/ function(module, exports, __webpack_require__) { 'use strict'; var SeriesModel = __webpack_require__(28); var List = __webpack_require__(98); var completeDimensions = __webpack_require__(103); var zrUtil = __webpack_require__(4); var RadarSeries = SeriesModel.extend({ type: 'series.radar', dependencies: ['radar'], // Overwrite init: function (option) { RadarSeries.superApply(this, 'init', arguments); // Enable legend selection for each data item // Use a function instead of direct access because data reference may changed this.legendDataProvider = function () { return this._dataBeforeProcessed; }; }, getInitialData: function (option, ecModel) { var data = option.data || []; var dimensions = completeDimensions( [], data, [], 'indicator_' ); var list = new List(dimensions, this); list.initData(data); return list; }, formatTooltip: function (dataIndex) { var value = this.getRawValue(dataIndex); var coordSys = this.coordinateSystem; var indicatorAxes = coordSys.getIndicatorAxes(); return (this._data.getName(dataIndex) == '' ? this.name : this._data.getName(dataIndex)) + '
' + zrUtil.map(indicatorAxes, function (axis, idx) { return axis.name + ' : ' + value[idx]; }).join('
'); }, defaultOption: { zlevel: 0, z: 2, coordinateSystem: 'radar', legendHoverLink: true, radarIndex: 0, lineStyle: { normal: { width: 2, type: 'solid' } }, label: { normal: { position: 'top' } }, // areaStyle: { // }, // itemStyle: {} symbol: 'emptyCircle', symbolSize: 4 // symbolRotate: null } }); module.exports = RadarSeries; /***/ }, /* 160 */ /***/ function(module, exports, __webpack_require__) { var graphic = __webpack_require__(43); var zrUtil = __webpack_require__(4); var symbolUtil = __webpack_require__(107); function normalizeSymbolSize(symbolSize) { if (!zrUtil.isArray(symbolSize)) { symbolSize = [+symbolSize, +symbolSize]; } return symbolSize; } module.exports = __webpack_require__(1).extendChartView({ type: 'radar', render: function (seriesModel, ecModel, api) { var polar = seriesModel.coordinateSystem; var group = this.group; var data = seriesModel.getData(); var oldData = this._data; function createSymbol(data, idx) { var symbolType = data.getItemVisual(idx, 'symbol') || 'circle'; var color = data.getItemVisual(idx, 'color'); if (symbolType === 'none') { return; } var symbolPath = symbolUtil.createSymbol( symbolType, -0.5, -0.5, 1, 1, color ); symbolPath.attr({ style: { strokeNoScale: true }, z2: 100, scale: normalizeSymbolSize(data.getItemVisual(idx, 'symbolSize')) }); return symbolPath; } function updateSymbols(oldPoints, newPoints, symbolGroup, data, idx, isInit) { // Simply rerender all symbolGroup.removeAll(); for (var i = 0; i < newPoints.length - 1; i++) { var symbolPath = createSymbol(data, idx); if (symbolPath) { symbolPath.__dimIdx = i; if (oldPoints[i]) { symbolPath.attr('position', oldPoints[i]); graphic[isInit ? 'initProps' : 'updateProps']( symbolPath, { position: newPoints[i] }, seriesModel, idx ); } else { symbolPath.attr('position', newPoints[i]); } symbolGroup.add(symbolPath); } } } function getInitialPoints(points) { return zrUtil.map(points, function (pt) { return [polar.cx, polar.cy]; }); } data.diff(oldData) .add(function (idx) { var points = data.getItemLayout(idx); if (!points) { return; } var polygon = new graphic.Polygon(); var polyline = new graphic.Polyline(); var target = { shape: { points: points } }; polygon.shape.points = getInitialPoints(points); polyline.shape.points = getInitialPoints(points); graphic.initProps(polygon, target, seriesModel, idx); graphic.initProps(polyline, target, seriesModel, idx); var itemGroup = new graphic.Group(); var symbolGroup = new graphic.Group(); itemGroup.add(polyline); itemGroup.add(polygon); itemGroup.add(symbolGroup); updateSymbols( polyline.shape.points, points, symbolGroup, data, idx, true ); data.setItemGraphicEl(idx, itemGroup); }) .update(function (newIdx, oldIdx) { var itemGroup = oldData.getItemGraphicEl(oldIdx); var polyline = itemGroup.childAt(0); var polygon = itemGroup.childAt(1); var symbolGroup = itemGroup.childAt(2); var target = { shape: { points: data.getItemLayout(newIdx) } }; if (!target.shape.points) { return; } updateSymbols( polyline.shape.points, target.shape.points, symbolGroup, data, newIdx, false ); graphic.updateProps(polyline, target, seriesModel); graphic.updateProps(polygon, target, seriesModel); data.setItemGraphicEl(newIdx, itemGroup); }) .remove(function (idx) { group.remove(oldData.getItemGraphicEl(idx)); }) .execute(); data.eachItemGraphicEl(function (itemGroup, idx) { var itemModel = data.getItemModel(idx); var polyline = itemGroup.childAt(0); var polygon = itemGroup.childAt(1); var symbolGroup = itemGroup.childAt(2); var color = data.getItemVisual(idx, 'color'); group.add(itemGroup); polyline.useStyle( zrUtil.defaults( itemModel.getModel('lineStyle.normal').getLineStyle(), { fill: 'none', stroke: color } ) ); polyline.hoverStyle = itemModel.getModel('lineStyle.emphasis').getLineStyle(); var areaStyleModel = itemModel.getModel('areaStyle.normal'); var hoverAreaStyleModel = itemModel.getModel('areaStyle.emphasis'); var polygonIgnore = areaStyleModel.isEmpty() && areaStyleModel.parentModel.isEmpty(); var hoverPolygonIgnore = hoverAreaStyleModel.isEmpty() && hoverAreaStyleModel.parentModel.isEmpty(); hoverPolygonIgnore = hoverPolygonIgnore && polygonIgnore; polygon.ignore = polygonIgnore; polygon.useStyle( zrUtil.defaults( areaStyleModel.getAreaStyle(), { fill: color, opacity: 0.7 } ) ); polygon.hoverStyle = hoverAreaStyleModel.getAreaStyle(); var itemStyle = itemModel.getModel('itemStyle.normal').getItemStyle(['color']); var itemHoverStyle = itemModel.getModel('itemStyle.emphasis').getItemStyle(); var labelModel = itemModel.getModel('label.normal'); var labelHoverModel = itemModel.getModel('label.emphasis'); symbolGroup.eachChild(function (symbolPath) { symbolPath.setStyle(itemStyle); symbolPath.hoverStyle = zrUtil.clone(itemHoverStyle); var defaultText = data.get(data.dimensions[symbolPath.__dimIdx], idx); graphic.setText(symbolPath.style, labelModel, color); symbolPath.setStyle({ text: labelModel.get('show') ? zrUtil.retrieve( seriesModel.getFormattedLabel( idx, 'normal', null, symbolPath.__dimIdx ), defaultText ) : '' }); graphic.setText(symbolPath.hoverStyle, labelHoverModel, color); symbolPath.hoverStyle.text = labelHoverModel.get('show') ? zrUtil.retrieve( seriesModel.getFormattedLabel( idx, 'emphasis', null, symbolPath.__dimIdx ), defaultText ) : ''; }); function onEmphasis() { polygon.attr('ignore', hoverPolygonIgnore); } function onNormal() { polygon.attr('ignore', polygonIgnore); } itemGroup.off('mouseover').off('mouseout').off('normal').off('emphasis'); itemGroup.on('emphasis', onEmphasis) .on('mouseover', onEmphasis) .on('normal', onNormal) .on('mouseout', onNormal); graphic.setHoverStyle(itemGroup); }); this._data = data; }, remove: function () { this.group.removeAll(); this._data = null; }, dispose: function () {} }); /***/ }, /* 161 */ /***/ function(module, exports) { module.exports = function (ecModel) { ecModel.eachSeriesByType('radar', function (seriesModel) { var data = seriesModel.getData(); var points = []; var coordSys = seriesModel.coordinateSystem; if (!coordSys) { return; } function pointsConverter(val, idx) { points[idx] = points[idx] || []; points[idx][i] = coordSys.dataToPoint(val, i); } for (var i = 0; i < coordSys.getIndicatorAxes().length; i++) { var dim = data.dimensions[i]; data.each(dim, pointsConverter); } data.each(function (idx) { // Close polygon points[idx][0] && points[idx].push(points[idx][0].slice()); data.setItemLayout(idx, points[idx]); }); }); }; /***/ }, /* 162 */ /***/ function(module, exports, __webpack_require__) { // Backward compat for radar chart in 2 var zrUtil = __webpack_require__(4); module.exports = function (option) { var polarOptArr = option.polar; if (polarOptArr) { if (!zrUtil.isArray(polarOptArr)) { polarOptArr = [polarOptArr]; } var polarNotRadar = []; zrUtil.each(polarOptArr, function (polarOpt, idx) { if (polarOpt.indicator) { if (polarOpt.type && !polarOpt.shape) { polarOpt.shape = polarOpt.type; } option.radar = option.radar || []; if (!zrUtil.isArray(option.radar)) { option.radar = [option.radar]; } option.radar.push(polarOpt); } else { polarNotRadar.push(polarOpt); } }); option.polar = polarNotRadar; } zrUtil.each(option.series, function (seriesOpt) { if (seriesOpt.type === 'radar' && seriesOpt.polarIndex) { seriesOpt.radarIndex = seriesOpt.polarIndex; } }); }; /***/ }, /* 163 */ /***/ function(module, exports, __webpack_require__) { var echarts = __webpack_require__(1); var PRIORITY = echarts.PRIORITY; __webpack_require__(164); __webpack_require__(174); __webpack_require__(178); __webpack_require__(165); echarts.registerLayout(__webpack_require__(180)); echarts.registerVisual(__webpack_require__(181)); echarts.registerProcessor(PRIORITY.PROCESSOR.STATISTIC, __webpack_require__(182)); echarts.registerPreprocessor(__webpack_require__(183)); __webpack_require__(144)('map', [{ type: 'mapToggleSelect', event: 'mapselectchanged', method: 'toggleSelected' }, { type: 'mapSelect', event: 'mapselected', method: 'select' }, { type: 'mapUnSelect', event: 'mapunselected', method: 'unSelect' }]); /***/ }, /* 164 */ /***/ function(module, exports, __webpack_require__) { var List = __webpack_require__(98); var SeriesModel = __webpack_require__(28); var zrUtil = __webpack_require__(4); var completeDimensions = __webpack_require__(103); var formatUtil = __webpack_require__(6); var encodeHTML = formatUtil.encodeHTML; var addCommas = formatUtil.addCommas; var dataSelectableMixin = __webpack_require__(142); var geoCreator = __webpack_require__(165); var MapSeries = SeriesModel.extend({ type: 'series.map', layoutMode: 'box', /** * Only first map series of same mapType will drawMap * @type {boolean} */ needsDrawMap: false, /** * Group of all map series with same mapType * @type {boolean} */ seriesGroup: [], init: function (option) { option = this._fillOption(option, option.map); this.option = option; MapSeries.superApply(this, 'init', arguments); this.updateSelectedMap(option.data); }, getInitialData: function (option) { var dimensions = completeDimensions(['value'], option.data || []); var list = new List(dimensions, this); list.initData(option.data); return list; }, mergeOption: function (newOption) { if (newOption.data) { newOption = this._fillOption(newOption, this.option.map); } MapSeries.superCall(this, 'mergeOption', newOption); this.updateSelectedMap(this.option.data); }, _fillOption: function (option, mapName) { // Shallow clone option = zrUtil.extend({}, option); option.data = geoCreator.getFilledRegions(option.data, mapName); return option; }, getRawValue: function (dataIndex) { // Use value stored in data instead because it is calculated from multiple series // FIXME Provide all value of multiple series ? return this._data.get('value', dataIndex); }, /** * Get model of region * @param {string} name * @return {module:echarts/model/Model} */ getRegionModel: function (regionName) { var data = this.getData(); return data.getItemModel(data.indexOfName(regionName)); }, /** * Map tooltip formatter * * @param {number} dataIndex */ formatTooltip: function (dataIndex) { // FIXME orignalData and data is a bit confusing var data = this.getData(); var formattedValue = addCommas(this.getRawValue(dataIndex)); var name = data.getName(dataIndex); var seriesGroup = this.seriesGroup; var seriesNames = []; for (var i = 0; i < seriesGroup.length; i++) { var otherIndex = seriesGroup[i].originalData.indexOfName(name); if (!isNaN(seriesGroup[i].originalData.get('value', otherIndex))) { seriesNames.push( encodeHTML(seriesGroup[i].name) ); } } return seriesNames.join(', ') + '
' + name + ' : ' + formattedValue; }, /** * @implement */ getTooltipPosition: function (dataIndex) { if (dataIndex != null) { var name = this.getData().getName(dataIndex); var geo = this.coordinateSystem; var region = geo.getRegion(name); return region && geo.dataToPoint(region.center); } }, setZoom: function (zoom) { this.option.zoom = zoom; }, setCenter: function (center) { this.option.center = center; }, defaultOption: { // 一级层叠 zlevel: 0, // 二级层叠 z: 2, coordinateSystem: 'geo', // 各省的 map 暂时都用中文 map: 'china', // 'center' | 'left' | 'right' | 'x%' | {number} left: 'center', // 'center' | 'top' | 'bottom' | 'x%' | {number} top: 'center', // right // bottom // width: // height // Aspect is width / height. Inited to be geoJson bbox aspect // This parameter is used for scale this aspect aspectScale: 0.75, ///// Layout with center and size // If you wan't to put map in a fixed size box with right aspect ratio // This two properties may more conveninet // layoutCenter: [50%, 50%] // layoutSize: 100 // 数值合并方式,默认加和,可选为: // 'sum' | 'average' | 'max' | 'min' // mapValueCalculation: 'sum', // 地图数值计算结果小数精度 // mapValuePrecision: 0, // 显示图例颜色标识(系列标识的小圆点),图例开启时有效 showLegendSymbol: true, // 选择模式,默认关闭,可选single,multiple // selectedMode: false, dataRangeHoverLink: true, // 是否开启缩放及漫游模式 // roam: false, // Default on center of map center: null, zoom: 1, scaleLimit: null, label: { normal: { show: false, textStyle: { color: '#000' } }, emphasis: { show: true, textStyle: { color: 'rgb(100,0,0)' } } }, // scaleLimit: null, itemStyle: { normal: { // color: 各异, borderWidth: 0.5, borderColor: '#444', areaColor: '#eee' }, // 也是选中样式 emphasis: { areaColor: 'rgba(255,215,0,0.8)' } } } }); zrUtil.mixin(MapSeries, dataSelectableMixin); module.exports = MapSeries; /***/ }, /* 165 */ /***/ function(module, exports, __webpack_require__) { var Geo = __webpack_require__(166); var layout = __webpack_require__(21); var zrUtil = __webpack_require__(4); var numberUtil = __webpack_require__(7); var mapDataStores = {}; /** * Resize method bound to the geo * @param {module:echarts/coord/geo/GeoModel|module:echarts/chart/map/MapModel} geoModel * @param {module:echarts/ExtensionAPI} api */ function resizeGeo (geoModel, api) { var rect = this.getBoundingRect(); var boxLayoutOption; var center = geoModel.get('layoutCenter'); var size = geoModel.get('layoutSize'); var viewWidth = api.getWidth(); var viewHeight = api.getHeight(); var aspectScale = geoModel.get('aspectScale') || 0.75; var aspect = rect.width / rect.height * aspectScale; var useCenterAndSize = false; if (center && size) { center = [ numberUtil.parsePercent(center[0], viewWidth), numberUtil.parsePercent(center[1], viewHeight) ]; size = numberUtil.parsePercent(size, Math.min(viewWidth, viewHeight)); if (!isNaN(center[0]) && !isNaN(center[1]) && !isNaN(size)) { useCenterAndSize = true; } else { if (true) { console.warn('Given layoutCenter or layoutSize data are invalid. Use left/top/width/height instead.'); } } } var viewRect; if (useCenterAndSize) { var viewRect = {}; if (aspect > 1) { // Width is same with size viewRect.width = size; viewRect.height = size / aspect; } else { viewRect.height = size; viewRect.width = size * aspect; } viewRect.y = center[1] - viewRect.height / 2; viewRect.x = center[0] - viewRect.width / 2; } else { // Use left/top/width/height boxLayoutOption = geoModel.getBoxLayoutParams(); // 0.75 rate boxLayoutOption.aspect = aspect; viewRect = layout.getLayoutRect(boxLayoutOption, { width: viewWidth, height: viewHeight }); } this.setViewRect(viewRect.x, viewRect.y, viewRect.width, viewRect.height); this.setCenter(geoModel.get('center')); this.setZoom(geoModel.get('zoom')); } /** * @param {module:echarts/coord/Geo} geo * @param {module:echarts/model/Model} model * @inner */ function setGeoCoords(geo, model) { zrUtil.each(model.get('geoCoord'), function (geoCoord, name) { geo.addGeoCoord(name, geoCoord); }); } if (true) { var mapNotExistsError = function (name) { console.error('Map ' + name + ' not exists. You can download map file on http://echarts.baidu.com/download-map.html'); }; } var geoCreator = { // For deciding which dimensions to use when creating list data dimensions: Geo.prototype.dimensions, create: function (ecModel, api) { var geoList = []; // FIXME Create each time may be slow ecModel.eachComponent('geo', function (geoModel, idx) { var name = geoModel.get('map'); var mapData = mapDataStores[name]; if (true) { if (!mapData) { mapNotExistsError(name); } } var geo = new Geo( name + idx, name, mapData && mapData.geoJson, mapData && mapData.specialAreas, geoModel.get('nameMap') ); geo.zoomLimit = geoModel.get('scaleLimit'); geoList.push(geo); setGeoCoords(geo, geoModel); geoModel.coordinateSystem = geo; geo.model = geoModel; // Inject resize method geo.resize = resizeGeo; geo.resize(geoModel, api); }); ecModel.eachSeries(function (seriesModel) { var coordSys = seriesModel.get('coordinateSystem'); if (coordSys === 'geo') { var geoIndex = seriesModel.get('geoIndex') || 0; seriesModel.coordinateSystem = geoList[geoIndex]; } }); // If has map series var mapModelGroupBySeries = {}; ecModel.eachSeriesByType('map', function (seriesModel) { var mapType = seriesModel.get('map'); mapModelGroupBySeries[mapType] = mapModelGroupBySeries[mapType] || []; mapModelGroupBySeries[mapType].push(seriesModel); }); zrUtil.each(mapModelGroupBySeries, function (mapSeries, mapType) { var mapData = mapDataStores[mapType]; if (true) { if (!mapData) { mapNotExistsError(mapSeries[0].get('map')); } } var nameMapList = zrUtil.map(mapSeries, function (singleMapSeries) { return singleMapSeries.get('nameMap'); }); var geo = new Geo( mapType, mapType, mapData && mapData.geoJson, mapData && mapData.specialAreas, zrUtil.mergeAll(nameMapList) ); geo.zoomLimit = zrUtil.retrieve.apply(null, zrUtil.map(mapSeries, function (singleMapSeries) { return singleMapSeries.get('scaleLimit'); })); geoList.push(geo); // Inject resize method geo.resize = resizeGeo; geo.resize(mapSeries[0], api); zrUtil.each(mapSeries, function (singleMapSeries) { singleMapSeries.coordinateSystem = geo; setGeoCoords(geo, singleMapSeries); }); }); return geoList; }, /** * @param {string} mapName * @param {Object|string} geoJson * @param {Object} [specialAreas] * * @example * $.get('USA.json', function (geoJson) { * echarts.registerMap('USA', geoJson); * // Or * echarts.registerMap('USA', { * geoJson: geoJson, * specialAreas: {} * }) * }); */ registerMap: function (mapName, geoJson, specialAreas) { if (geoJson.geoJson && !geoJson.features) { specialAreas = geoJson.specialAreas; geoJson = geoJson.geoJson; } if (typeof geoJson === 'string') { geoJson = (typeof JSON !== 'undefined' && JSON.parse) ? JSON.parse(geoJson) : (new Function('return (' + geoJson + ');'))(); } mapDataStores[mapName] = { geoJson: geoJson, specialAreas: specialAreas }; }, /** * @param {string} mapName * @return {Object} */ getMap: function (mapName) { return mapDataStores[mapName]; }, /** * Fill given regions array * @param {Array.} originRegionArr * @param {string} mapName * @return {Array} */ getFilledRegions: function (originRegionArr, mapName) { // Not use the original var regionsArr = (originRegionArr || []).slice(); var map = geoCreator.getMap(mapName); var geoJson = map && map.geoJson; if (!geoJson) { if (true) { mapNotExistsError(mapName); } return originRegionArr; } var dataNameMap = {}; var features = geoJson.features; for (var i = 0; i < regionsArr.length; i++) { dataNameMap[regionsArr[i].name] = regionsArr[i]; } for (var i = 0; i < features.length; i++) { var name = features[i].properties.name; if (!dataNameMap[name]) { regionsArr.push({ name: name }); } } return regionsArr; } }; // Inject methods into echarts var echarts = __webpack_require__(1); echarts.registerMap = geoCreator.registerMap; echarts.getMap = geoCreator.getMap; // TODO echarts.loadMap = function () {}; echarts.registerCoordinateSystem('geo', geoCreator); module.exports = geoCreator; /***/ }, /* 166 */ /***/ function(module, exports, __webpack_require__) { var parseGeoJson = __webpack_require__(167); var zrUtil = __webpack_require__(4); var BoundingRect = __webpack_require__(9); var View = __webpack_require__(170); // Geo fix functions var geoFixFuncs = [ __webpack_require__(171), __webpack_require__(172), __webpack_require__(173) ]; /** * [Geo description] * @param {string} name Geo name * @param {string} map Map type * @param {Object} geoJson * @param {Object} [specialAreas] * Specify the positioned areas by left, top, width, height * @param {Object.} [nameMap] * Specify name alias */ function Geo(name, map, geoJson, specialAreas, nameMap) { View.call(this, name); /** * Map type * @type {string} */ this.map = map; this._nameCoordMap = {}; this.loadGeoJson(geoJson, specialAreas, nameMap); } Geo.prototype = { constructor: Geo, type: 'geo', /** * @param {Array.} * @readOnly */ dimensions: ['lng', 'lat'], /** * If contain given lng,lat coord * @param {Array.} * @readOnly */ containCoord: function (coord) { var regions = this.regions; for (var i = 0; i < regions.length; i++) { if (regions[i].contain(coord)) { return true; } } return false; }, /** * @param {Object} geoJson * @param {Object} [specialAreas] * Specify the positioned areas by left, top, width, height * @param {Object.} [nameMap] * Specify name alias */ loadGeoJson: function (geoJson, specialAreas, nameMap) { // https://jsperf.com/try-catch-performance-overhead try { this.regions = geoJson ? parseGeoJson(geoJson) : []; } catch (e) { throw 'Invalid geoJson format\n' + e; } specialAreas = specialAreas || {}; nameMap = nameMap || {}; var regions = this.regions; var regionsMap = {}; for (var i = 0; i < regions.length; i++) { var regionName = regions[i].name; // Try use the alias in nameMap regionName = nameMap[regionName] || regionName; regions[i].name = regionName; regionsMap[regionName] = regions[i]; // Add geoJson this.addGeoCoord(regionName, regions[i].center); // Some area like Alaska in USA map needs to be tansformed // to look better var specialArea = specialAreas[regionName]; if (specialArea) { regions[i].transformTo( specialArea.left, specialArea.top, specialArea.width, specialArea.height ); } } this._regionsMap = regionsMap; this._rect = null; zrUtil.each(geoFixFuncs, function (fixFunc) { fixFunc(this); }, this); }, // Overwrite transformTo: function (x, y, width, height) { var rect = this.getBoundingRect(); rect = rect.clone(); // Longitute is inverted rect.y = -rect.y - rect.height; var viewTransform = this._viewTransform; viewTransform.transform = rect.calculateTransform( new BoundingRect(x, y, width, height) ); viewTransform.decomposeTransform(); var scale = viewTransform.scale; scale[1] = -scale[1]; viewTransform.updateTransform(); this._updateTransform(); }, /** * @param {string} name * @return {module:echarts/coord/geo/Region} */ getRegion: function (name) { return this._regionsMap[name]; }, getRegionByCoord: function (coord) { var regions = this.regions; for (var i = 0; i < regions.length; i++) { if (regions[i].contain(coord)) { return regions[i]; } } }, /** * Add geoCoord for indexing by name * @param {string} name * @param {Array.} geoCoord */ addGeoCoord: function (name, geoCoord) { this._nameCoordMap[name] = geoCoord; }, /** * Get geoCoord by name * @param {string} name * @return {Array.} */ getGeoCoord: function (name) { return this._nameCoordMap[name]; }, // Overwrite getBoundingRect: function () { if (this._rect) { return this._rect; } var rect; var regions = this.regions; for (var i = 0; i < regions.length; i++) { var regionRect = regions[i].getBoundingRect(); rect = rect || regionRect.clone(); rect.union(regionRect); } // FIXME Always return new ? return (this._rect = rect || new BoundingRect(0, 0, 0, 0)); }, /** * Convert series data to a list of points * @param {module:echarts/data/List} data * @param {boolean} stack * @return {Array} * Return list of points. For example: * `[[10, 10], [20, 20], [30, 30]]` */ dataToPoints: function (data) { var item = []; return data.mapArray(['lng', 'lat'], function (lon, lat) { item[0] = lon; item[1] = lat; return this.dataToPoint(item); }, this); }, // Overwrite /** * @param {string|Array.} data * @return {Array.} */ dataToPoint: function (data) { if (typeof data === 'string') { // Map area name to geoCoord data = this.getGeoCoord(data); } if (data) { return View.prototype.dataToPoint.call(this, data); } }, /** * @override * @implements * see {module:echarts/CoodinateSystem} */ convertToPixel: zrUtil.curry(doConvert, 'dataToPoint'), /** * @override * @implements * see {module:echarts/CoodinateSystem} */ convertFromPixel: zrUtil.curry(doConvert, 'pointToData') }; zrUtil.mixin(Geo, View); function doConvert(methodName, ecModel, finder, value) { var geoModel = finder.geoModel; var seriesModel = finder.seriesModel; var coordSys = geoModel ? geoModel.coordinateSystem : seriesModel ? ( seriesModel.coordinateSystem // For map. || (seriesModel.getReferringComponents('geo')[0] || {}).coordinateSystem ) : null; return coordSys === this ? coordSys[methodName](value) : null; } module.exports = Geo; /***/ }, /* 167 */ /***/ function(module, exports, __webpack_require__) { /** * Parse and decode geo json * @module echarts/coord/geo/parseGeoJson */ var zrUtil = __webpack_require__(4); var Region = __webpack_require__(168); function decode(json) { if (!json.UTF8Encoding) { return json; } var features = json.features; for (var f = 0; f < features.length; f++) { var feature = features[f]; var geometry = feature.geometry; var coordinates = geometry.coordinates; var encodeOffsets = geometry.encodeOffsets; for (var c = 0; c < coordinates.length; c++) { var coordinate = coordinates[c]; if (geometry.type === 'Polygon') { coordinates[c] = decodePolygon( coordinate, encodeOffsets[c] ); } else if (geometry.type === 'MultiPolygon') { for (var c2 = 0; c2 < coordinate.length; c2++) { var polygon = coordinate[c2]; coordinate[c2] = decodePolygon( polygon, encodeOffsets[c][c2] ); } } } } // Has been decoded json.UTF8Encoding = false; return json; } function decodePolygon(coordinate, encodeOffsets) { var result = []; var prevX = encodeOffsets[0]; var prevY = encodeOffsets[1]; for (var i = 0; i < coordinate.length; i += 2) { var x = coordinate.charCodeAt(i) - 64; var y = coordinate.charCodeAt(i + 1) - 64; // ZigZag decoding x = (x >> 1) ^ (-(x & 1)); y = (y >> 1) ^ (-(y & 1)); // Delta deocding x += prevX; y += prevY; prevX = x; prevY = y; // Dequantize result.push([x / 1024, y / 1024]); } return result; } /** * @inner */ function flattern2D(array) { var ret = []; for (var i = 0; i < array.length; i++) { for (var k = 0; k < array[i].length; k++) { ret.push(array[i][k]); } } return ret; } /** * @alias module:echarts/coord/geo/parseGeoJson * @param {Object} geoJson * @return {module:zrender/container/Group} */ module.exports = function (geoJson) { decode(geoJson); return zrUtil.map(zrUtil.filter(geoJson.features, function (featureObj) { // Output of mapshaper may have geometry null return featureObj.geometry && featureObj.properties; }), function (featureObj) { var properties = featureObj.properties; var geometry = featureObj.geometry; var coordinates = geometry.coordinates; if (geometry.type === 'MultiPolygon') { coordinates = flattern2D(coordinates); } return new Region( properties.name, coordinates, properties.cp ); }); }; /***/ }, /* 168 */ /***/ function(module, exports, __webpack_require__) { /** * @module echarts/coord/geo/Region */ var polygonContain = __webpack_require__(169); var BoundingRect = __webpack_require__(9); var bbox = __webpack_require__(51); var vec2 = __webpack_require__(10); /** * @param {string} name * @param {Array} contours * @param {Array.} cp */ function Region(name, contours, cp) { /** * @type {string} * @readOnly */ this.name = name; /** * @type {Array.} * @readOnly */ this.contours = contours; if (!cp) { var rect = this.getBoundingRect(); cp = [ rect.x + rect.width / 2, rect.y + rect.height / 2 ]; } else { cp = [cp[0], cp[1]]; } /** * @type {Array.} */ this.center = cp; } Region.prototype = { constructor: Region, /** * @return {module:zrender/core/BoundingRect} */ getBoundingRect: function () { var rect = this._rect; if (rect) { return rect; } var MAX_NUMBER = Number.MAX_VALUE; var min = [MAX_NUMBER, MAX_NUMBER]; var max = [-MAX_NUMBER, -MAX_NUMBER]; var min2 = []; var max2 = []; var contours = this.contours; for (var i = 0; i < contours.length; i++) { bbox.fromPoints(contours[i], min2, max2); vec2.min(min, min, min2); vec2.max(max, max, max2); } // No data if (i === 0) { min[0] = min[1] = max[0] = max[1] = 0; } return (this._rect = new BoundingRect( min[0], min[1], max[0] - min[0], max[1] - min[1] )); }, /** * @param {} coord * @return {boolean} */ contain: function (coord) { var rect = this.getBoundingRect(); var contours = this.contours; if (rect.contain(coord[0], coord[1])) { for (var i = 0, len = contours.length; i < len; i++) { if (polygonContain.contain(contours[i], coord[0], coord[1])) { return true; } } } return false; }, transformTo: function (x, y, width, height) { var rect = this.getBoundingRect(); var aspect = rect.width / rect.height; if (!width) { width = aspect * height; } else if (!height) { height = width / aspect ; } var target = new BoundingRect(x, y, width, height); var transform = rect.calculateTransform(target); var contours = this.contours; for (var i = 0; i < contours.length; i++) { for (var p = 0; p < contours[i].length; p++) { vec2.applyTransform(contours[i][p], contours[i][p], transform); } } rect = this._rect; rect.copy(target); // Update center this.center = [ rect.x + rect.width / 2, rect.y + rect.height / 2 ]; } }; module.exports = Region; /***/ }, /* 169 */ /***/ function(module, exports, __webpack_require__) { var windingLine = __webpack_require__(58); var EPSILON = 1e-8; function isAroundEqual(a, b) { return Math.abs(a - b) < EPSILON; } function contain(points, x, y) { var w = 0; var p = points[0]; if (!p) { return false; } for (var i = 1; i < points.length; i++) { var p2 = points[i]; w += windingLine(p[0], p[1], p2[0], p2[1], x, y); p = p2; } // Close polygon var p0 = points[0]; if (!isAroundEqual(p[0], p0[0]) || !isAroundEqual(p[1], p0[1])) { w += windingLine(p[0], p[1], p0[0], p0[1], x, y); } return w !== 0; } module.exports = { contain: contain }; /***/ }, /* 170 */ /***/ function(module, exports, __webpack_require__) { /** * Simple view coordinate system * Mapping given x, y to transformd view x, y */ var vector = __webpack_require__(10); var matrix = __webpack_require__(11); var Transformable = __webpack_require__(34); var zrUtil = __webpack_require__(4); var BoundingRect = __webpack_require__(9); var v2ApplyTransform = vector.applyTransform; // Dummy transform node function TransformDummy() { Transformable.call(this); } zrUtil.mixin(TransformDummy, Transformable); function View(name) { /** * @type {string} */ this.name = name; /** * @type {Object} */ this.zoomLimit; Transformable.call(this); this._roamTransform = new TransformDummy(); this._viewTransform = new TransformDummy(); this._center; this._zoom; } View.prototype = { constructor: View, type: 'view', /** * @param {Array.} * @readOnly */ dimensions: ['x', 'y'], /** * Set bounding rect * @param {number} x * @param {number} y * @param {number} width * @param {number} height */ // PENDING to getRect setBoundingRect: function (x, y, width, height) { this._rect = new BoundingRect(x, y, width, height); return this._rect; }, /** * @return {module:zrender/core/BoundingRect} */ // PENDING to getRect getBoundingRect: function () { return this._rect; }, /** * @param {number} x * @param {number} y * @param {number} width * @param {number} height */ setViewRect: function (x, y, width, height) { this.transformTo(x, y, width, height); this._viewRect = new BoundingRect(x, y, width, height); }, /** * Transformed to particular position and size * @param {number} x * @param {number} y * @param {number} width * @param {number} height */ transformTo: function (x, y, width, height) { var rect = this.getBoundingRect(); var viewTransform = this._viewTransform; viewTransform.transform = rect.calculateTransform( new BoundingRect(x, y, width, height) ); viewTransform.decomposeTransform(); this._updateTransform(); }, /** * Set center of view * @param {Array.} [centerCoord] */ setCenter: function (centerCoord) { if (!centerCoord) { return; } this._center = centerCoord; this._updateCenterAndZoom(); }, /** * @param {number} zoom */ setZoom: function (zoom) { zoom = zoom || 1; var zoomLimit = this.zoomLimit; if (zoomLimit) { if (zoomLimit.max != null) { zoom = Math.min(zoomLimit.max, zoom); } if (zoomLimit.min != null) { zoom = Math.max(zoomLimit.min, zoom); } } this._zoom = zoom; this._updateCenterAndZoom(); }, /** * Get default center without roam */ getDefaultCenter: function () { // Rect before any transform var rawRect = this.getBoundingRect(); var cx = rawRect.x + rawRect.width / 2; var cy = rawRect.y + rawRect.height / 2; return [cx, cy]; }, getCenter: function () { return this._center || this.getDefaultCenter(); }, getZoom: function () { return this._zoom || 1; }, /** * @return {Array.} data * @return {Array.} */ dataToPoint: function (data) { var transform = this.transform; return transform ? v2ApplyTransform([], data, transform) : [data[0], data[1]]; }, /** * Convert a (x, y) point to (lon, lat) data * @param {Array.} point * @return {Array.} */ pointToData: function (point) { var invTransform = this.invTransform; return invTransform ? v2ApplyTransform([], point, invTransform) : [point[0], point[1]]; }, /** * @implements * see {module:echarts/CoodinateSystem} */ convertToPixel: zrUtil.curry(doConvert, 'dataToPoint'), /** * @implements * see {module:echarts/CoodinateSystem} */ convertFromPixel: zrUtil.curry(doConvert, 'pointToData'), /** * @implements * see {module:echarts/CoodinateSystem} */ containPoint: function (point) { return this.getViewRectAfterRoam().contain(point[0], point[1]); } /** * @return {number} */ // getScalarScale: function () { // // Use determinant square root of transform to mutiply scalar // var m = this.transform; // var det = Math.sqrt(Math.abs(m[0] * m[3] - m[2] * m[1])); // return det; // } }; zrUtil.mixin(View, Transformable); function doConvert(methodName, ecModel, finder, value) { var seriesModel = finder.seriesModel; var coordSys = seriesModel ? seriesModel.coordinateSystem : null; // e.g., graph. return coordSys === this ? coordSys[methodName](value) : null; } module.exports = View; /***/ }, /* 171 */ /***/ function(module, exports, __webpack_require__) { // Fix for 南海诸岛 var Region = __webpack_require__(168); var geoCoord = [126, 25]; var points = [ [[0,3.5],[7,11.2],[15,11.9],[30,7],[42,0.7],[52,0.7], [56,7.7],[59,0.7],[64,0.7],[64,0],[5,0],[0,3.5]], [[13,16.1],[19,14.7],[16,21.7],[11,23.1],[13,16.1]], [[12,32.2],[14,38.5],[15,38.5],[13,32.2],[12,32.2]], [[16,47.6],[12,53.2],[13,53.2],[18,47.6],[16,47.6]], [[6,64.4],[8,70],[9,70],[8,64.4],[6,64.4]], [[23,82.6],[29,79.8],[30,79.8],[25,82.6],[23,82.6]], [[37,70.7],[43,62.3],[44,62.3],[39,70.7],[37,70.7]], [[48,51.1],[51,45.5],[53,45.5],[50,51.1],[48,51.1]], [[51,35],[51,28.7],[53,28.7],[53,35],[51,35]], [[52,22.4],[55,17.5],[56,17.5],[53,22.4],[52,22.4]], [[58,12.6],[62,7],[63,7],[60,12.6],[58,12.6]], [[0,3.5],[0,93.1],[64,93.1],[64,0],[63,0],[63,92.4], [1,92.4],[1,3.5],[0,3.5]] ]; for (var i = 0; i < points.length; i++) { for (var k = 0; k < points[i].length; k++) { points[i][k][0] /= 10.5; points[i][k][1] /= -10.5 / 0.75; points[i][k][0] += geoCoord[0]; points[i][k][1] += geoCoord[1]; } } module.exports = function (geo) { if (geo.map === 'china') { geo.regions.push(new Region( '南海诸岛', points, geoCoord )); } }; /***/ }, /* 172 */ /***/ function(module, exports, __webpack_require__) { var zrUtil = __webpack_require__(4); var coordsOffsetMap = { '南海诸岛' : [32, 80], // 全国 '广东': [0, -10], '香港': [10, 5], '澳门': [-10, 10], //'北京': [-10, 0], '天津': [5, 5] }; module.exports = function (geo) { zrUtil.each(geo.regions, function (region) { var coordFix = coordsOffsetMap[region.name]; if (coordFix) { var cp = region.center; cp[0] += coordFix[0] / 10.5; cp[1] += -coordFix[1] / (10.5 / 0.75); } }); }; /***/ }, /* 173 */ /***/ function(module, exports, __webpack_require__) { var zrUtil = __webpack_require__(4); var geoCoordMap = { 'Russia': [100, 60], 'United States of America': [-99, 38] }; module.exports = function (geo) { zrUtil.each(geo.regions, function (region) { var geoCoord = geoCoordMap[region.name]; if (geoCoord) { var cp = region.center; cp[0] = geoCoord[0]; cp[1] = geoCoord[1]; } }); }; /***/ }, /* 174 */ /***/ function(module, exports, __webpack_require__) { // var zrUtil = require('zrender/lib/core/util'); var graphic = __webpack_require__(43); var MapDraw = __webpack_require__(175); __webpack_require__(1).extendChartView({ type: 'map', render: function (mapModel, ecModel, api, payload) { // Not render if it is an toggleSelect action from self if (payload && payload.type === 'mapToggleSelect' && payload.from === this.uid ) { return; } var group = this.group; group.removeAll(); // Not update map if it is an roam action from self if (!(payload && payload.type === 'geoRoam' && payload.componentType === 'series' && payload.seriesId === mapModel.id)) { if (mapModel.needsDrawMap) { var mapDraw = this._mapDraw || new MapDraw(api, true); group.add(mapDraw.group); mapDraw.draw(mapModel, ecModel, api, this, payload); this._mapDraw = mapDraw; } else { // Remove drawed map this._mapDraw && this._mapDraw.remove(); this._mapDraw = null; } } else { var mapDraw = this._mapDraw; mapDraw && group.add(mapDraw.group); } mapModel.get('showLegendSymbol') && ecModel.getComponent('legend') && this._renderSymbols(mapModel, ecModel, api); }, remove: function () { this._mapDraw && this._mapDraw.remove(); this._mapDraw = null; this.group.removeAll(); }, dispose: function () { this._mapDraw && this._mapDraw.remove(); this._mapDraw = null; }, _renderSymbols: function (mapModel, ecModel, api) { var originalData = mapModel.originalData; var group = this.group; originalData.each('value', function (value, idx) { if (isNaN(value)) { return; } var layout = originalData.getItemLayout(idx); if (!layout || !layout.point) { // Not exists in map return; } var point = layout.point; var offset = layout.offset; var circle = new graphic.Circle({ style: { // Because the special of map draw. // Which needs statistic of multiple series and draw on one map. // And each series also need a symbol with legend color // // Layout and visual are put one the different data fill: mapModel.getData().getVisual('color') }, shape: { cx: point[0] + offset * 9, cy: point[1], r: 3 }, silent: true, z2: 10 }); // First data on the same region if (!offset) { var fullData = mapModel.mainSeries.getData(); var name = originalData.getName(idx); var labelText = name; var fullIndex = fullData.indexOfName(name); var itemModel = originalData.getItemModel(idx); var labelModel = itemModel.getModel('label.normal'); var hoverLabelModel = itemModel.getModel('label.emphasis'); var textStyleModel = labelModel.getModel('textStyle'); var hoverTextStyleModel = hoverLabelModel.getModel('textStyle'); var polygonGroups = fullData.getItemGraphicEl(fullIndex); circle.setStyle({ textPosition: 'bottom' }); var onEmphasis = function () { circle.setStyle({ text: hoverLabelModel.get('show') ? labelText : '', textFill: hoverTextStyleModel.getTextColor(), textFont: hoverTextStyleModel.getFont() }); }; var onNormal = function () { circle.setStyle({ text: labelModel.get('show') ? labelText : '', textFill: textStyleModel.getTextColor(), textFont: textStyleModel.getFont() }); }; polygonGroups.on('mouseover', onEmphasis) .on('mouseout', onNormal) .on('emphasis', onEmphasis) .on('normal', onNormal); onNormal(); } group.add(circle); }); } }); /***/ }, /* 175 */ /***/ function(module, exports, __webpack_require__) { /** * @module echarts/component/helper/MapDraw */ var RoamController = __webpack_require__(176); var graphic = __webpack_require__(43); var zrUtil = __webpack_require__(4); function getFixedItemStyle(model, scale) { var itemStyle = model.getItemStyle(); var areaColor = model.get('areaColor'); if (areaColor) { itemStyle.fill = areaColor; } return itemStyle; } function updateMapSelectHandler(mapDraw, mapOrGeoModel, group, api, fromView) { group.off('click'); group.off('mousedown'); if (mapOrGeoModel.get('selectedMode')) { group.on('mousedown', function () { mapDraw._mouseDownFlag = true; }); group.on('click', function (e) { if (!mapDraw._mouseDownFlag) { return; } mapDraw._mouseDownFlag = false; var el = e.target; while (!el.__region) { el = el.parent; } if (!el) { return; } var region = el.__region; var action = { type: (mapOrGeoModel.mainType === 'geo' ? 'geo' : 'map') + 'ToggleSelect', name: region.name, from: fromView.uid }; action[mapOrGeoModel.mainType + 'Id'] = mapOrGeoModel.id; api.dispatchAction(action); updateMapSelected(mapOrGeoModel, group); }); } } function updateMapSelected(mapOrGeoModel, group) { // FIXME group.eachChild(function (otherRegionEl) { if (otherRegionEl.__region) { otherRegionEl.trigger(mapOrGeoModel.isSelected(otherRegionEl.__region.name) ? 'emphasis' : 'normal'); } }); } /** * @alias module:echarts/component/helper/MapDraw * @param {module:echarts/ExtensionAPI} api * @param {boolean} updateGroup */ function MapDraw(api, updateGroup) { var group = new graphic.Group(); /** * @type {module:echarts/component/helper/RoamController} * @private */ this._controller = new RoamController( api.getZr(), updateGroup ? group : null, null ); /** * @type {module:zrender/container/Group} * @readOnly */ this.group = group; /** * @type {boolean} * @private */ this._updateGroup = updateGroup; /** * This flag is used to make sure that only one among * `pan`, `zoom`, `click` can occurs, otherwise 'selected' * action may be triggered when `pan`, which is unexpected. * @type {booelan} */ this._mouseDownFlag; } MapDraw.prototype = { constructor: MapDraw, draw: function (mapOrGeoModel, ecModel, api, fromView, payload) { // geoModel has no data var data = mapOrGeoModel.getData && mapOrGeoModel.getData(); var geo = mapOrGeoModel.coordinateSystem; var group = this.group; var scale = geo.scale; var groupNewProp = { position: geo.position, scale: scale }; // No animation when first draw or in action if (!group.childAt(0) || payload) { group.attr(groupNewProp); } else { graphic.updateProps(group, groupNewProp, mapOrGeoModel); } group.removeAll(); var itemStyleAccessPath = ['itemStyle', 'normal']; var hoverItemStyleAccessPath = ['itemStyle', 'emphasis']; var labelAccessPath = ['label', 'normal']; var hoverLabelAccessPath = ['label', 'emphasis']; zrUtil.each(geo.regions, function (region) { var regionGroup = new graphic.Group(); var compoundPath = new graphic.CompoundPath({ shape: { paths: [] } }); regionGroup.add(compoundPath); var regionModel = mapOrGeoModel.getRegionModel(region.name) || mapOrGeoModel; var itemStyleModel = regionModel.getModel(itemStyleAccessPath); var hoverItemStyleModel = regionModel.getModel(hoverItemStyleAccessPath); var itemStyle = getFixedItemStyle(itemStyleModel, scale); var hoverItemStyle = getFixedItemStyle(hoverItemStyleModel, scale); var labelModel = regionModel.getModel(labelAccessPath); var hoverLabelModel = regionModel.getModel(hoverLabelAccessPath); var dataIdx; // Use the itemStyle in data if has data if (data) { dataIdx = data.indexOfName(region.name); // Only visual color of each item will be used. It can be encoded by dataRange // But visual color of series is used in symbol drawing // // Visual color for each series is for the symbol draw var visualColor = data.getItemVisual(dataIdx, 'color', true); if (visualColor) { itemStyle.fill = visualColor; } } var textStyleModel = labelModel.getModel('textStyle'); var hoverTextStyleModel = hoverLabelModel.getModel('textStyle'); zrUtil.each(region.contours, function (contour) { var polygon = new graphic.Polygon({ shape: { points: contour } }); compoundPath.shape.paths.push(polygon); }); compoundPath.setStyle(itemStyle); compoundPath.style.strokeNoScale = true; compoundPath.culling = true; // Label var showLabel = labelModel.get('show'); var hoverShowLabel = hoverLabelModel.get('show'); var isDataNaN = data && isNaN(data.get('value', dataIdx)); var itemLayout = data && data.getItemLayout(dataIdx); // In the following cases label will be drawn // 1. In map series and data value is NaN // 2. In geo component // 4. Region has no series legendSymbol, which will be add a showLabel flag in mapSymbolLayout if ( (!data || isDataNaN && (showLabel || hoverShowLabel)) || (itemLayout && itemLayout.showLabel) ) { var query = data ? dataIdx : region.name; var formattedStr = mapOrGeoModel.getFormattedLabel(query, 'normal'); var hoverFormattedStr = mapOrGeoModel.getFormattedLabel(query, 'emphasis'); var text = new graphic.Text({ style: { text: showLabel ? (formattedStr || region.name) : '', fill: textStyleModel.getTextColor(), textFont: textStyleModel.getFont(), textAlign: 'center', textVerticalAlign: 'middle' }, hoverStyle: { text: hoverShowLabel ? (hoverFormattedStr || region.name) : '', fill: hoverTextStyleModel.getTextColor(), textFont: hoverTextStyleModel.getFont() }, position: region.center.slice(), scale: [1 / scale[0], 1 / scale[1]], z2: 10, silent: true }); regionGroup.add(text); } // setItemGraphicEl, setHoverStyle after all polygons and labels // are added to the rigionGroup if (data) { data.setItemGraphicEl(dataIdx, regionGroup); } else { var regionModel = mapOrGeoModel.getRegionModel(region.name); // Package custom mouse event for geo component compoundPath.eventData = { componentType: 'geo', geoIndex: mapOrGeoModel.componentIndex, name: region.name, region: (regionModel && regionModel.option) || {} }; } regionGroup.__region = region; graphic.setHoverStyle( regionGroup, hoverItemStyle, {hoverSilentOnTouch: !!mapOrGeoModel.get('selectedMode')} ); group.add(regionGroup); }); this._updateController(mapOrGeoModel, ecModel, api); updateMapSelectHandler(this, mapOrGeoModel, group, api, fromView); updateMapSelected(mapOrGeoModel, group); }, remove: function () { this.group.removeAll(); this._controller.dispose(); }, _updateController: function (mapOrGeoModel, ecModel, api) { var geo = mapOrGeoModel.coordinateSystem; var controller = this._controller; controller.zoomLimit = mapOrGeoModel.get('scaleLimit'); // Update zoom from model controller.zoom = geo.getZoom(); // roamType is will be set default true if it is null controller.enable(mapOrGeoModel.get('roam') || false); var mainType = mapOrGeoModel.mainType; function makeActionBase() { var action = { type: 'geoRoam', componentType: mainType }; action[mainType + 'Id'] = mapOrGeoModel.id; return action; } controller.off('pan').on('pan', function (dx, dy) { this._mouseDownFlag = false; api.dispatchAction(zrUtil.extend(makeActionBase(), { dx: dx, dy: dy })); }, this); controller.off('zoom').on('zoom', function (zoom, mouseX, mouseY) { this._mouseDownFlag = false; api.dispatchAction(zrUtil.extend(makeActionBase(), { zoom: zoom, originX: mouseX, originY: mouseY })); if (this._updateGroup) { var group = this.group; var scale = group.scale; group.traverse(function (el) { if (el.type === 'text') { el.attr('scale', [1 / scale[0], 1 / scale[1]]); } }); } }, this); controller.setContainsPoint(function (x, y) { return geo.getViewRectAfterRoam().contain(x, y); }); } }; module.exports = MapDraw; /***/ }, /* 176 */ /***/ function(module, exports, __webpack_require__) { /** * @module echarts/component/helper/RoamController */ var Eventful = __webpack_require__(33); var zrUtil = __webpack_require__(4); var eventTool = __webpack_require__(88); var interactionMutex = __webpack_require__(177); function mousedown(e) { if (e.target && e.target.draggable) { return; } var x = e.offsetX; var y = e.offsetY; if (this.containsPoint && this.containsPoint(x, y)) { this._x = x; this._y = y; this._dragging = true; } } function mousemove(e) { if (!this._dragging) { return; } eventTool.stop(e.event); if (e.gestureEvent !== 'pinch') { if (interactionMutex.isTaken(this._zr, 'globalPan')) { return; } var x = e.offsetX; var y = e.offsetY; var oldX = this._x; var oldY = this._y; var dx = x - oldX; var dy = y - oldY; this._x = x; this._y = y; var target = this.target; if (target) { var pos = target.position; pos[0] += dx; pos[1] += dy; target.dirty(); } eventTool.stop(e.event); this.trigger('pan', dx, dy, oldX, oldY, x, y); } } function mouseup(e) { this._dragging = false; } function mousewheel(e) { // Convenience: // Mac and VM Windows on Mac: scroll up: zoom out. // Windows: scroll up: zoom in. var zoomDelta = e.wheelDelta > 0 ? 1.1 : 1 / 1.1; zoom.call(this, e, zoomDelta, e.offsetX, e.offsetY); } function pinch(e) { if (interactionMutex.isTaken(this._zr, 'globalPan')) { return; } var zoomDelta = e.pinchScale > 1 ? 1.1 : 1 / 1.1; zoom.call(this, e, zoomDelta, e.pinchX, e.pinchY); } function zoom(e, zoomDelta, zoomX, zoomY) { if (this.containsPoint && this.containsPoint(zoomX, zoomY)) { // When mouse is out of roamController rect, // default befavoius should be be disabled, otherwise // page sliding is disabled, contrary to expectation. eventTool.stop(e.event); var target = this.target; var zoomLimit = this.zoomLimit; if (target) { var pos = target.position; var scale = target.scale; var newZoom = this.zoom = this.zoom || 1; newZoom *= zoomDelta; if (zoomLimit) { var zoomMin = zoomLimit.min || 0; var zoomMax = zoomLimit.max || Infinity; newZoom = Math.max( Math.min(zoomMax, newZoom), zoomMin ); } var zoomScale = newZoom / this.zoom; this.zoom = newZoom; // Keep the mouse center when scaling pos[0] -= (zoomX - pos[0]) * (zoomScale - 1); pos[1] -= (zoomY - pos[1]) * (zoomScale - 1); scale[0] *= zoomScale; scale[1] *= zoomScale; target.dirty(); } this.trigger('zoom', zoomDelta, zoomX, zoomY); } } /** * @alias module:echarts/component/helper/RoamController * @constructor * @mixin {module:zrender/mixin/Eventful} * * @param {module:zrender/zrender~ZRender} zr * @param {module:zrender/Element} target */ function RoamController(zr, target) { /** * @type {module:zrender/Element} */ this.target = target; /** * @type {Function} */ this.containsPoint; /** * { min: 1, max: 2 } * @type {Object} */ this.zoomLimit; /** * @type {number} */ this.zoom; /** * @type {module:zrender} */ this._zr = zr; // Avoid two roamController bind the same handler var bind = zrUtil.bind; var mousedownHandler = bind(mousedown, this); var mousemoveHandler = bind(mousemove, this); var mouseupHandler = bind(mouseup, this); var mousewheelHandler = bind(mousewheel, this); var pinchHandler = bind(pinch, this); Eventful.call(this); /** * @param {Function} containsPoint * input: x, y * output: boolean */ this.setContainsPoint = function (containsPoint) { this.containsPoint = containsPoint; }; /** * Notice: only enable needed types. For example, if 'zoom' * is not needed, 'zoom' should not be enabled, otherwise * default mousewheel behaviour (scroll page) will be disabled. * * @param {boolean|string} [controlType=true] Specify the control type, * which can be null/undefined or true/false * or 'pan/move' or 'zoom'/'scale' */ this.enable = function (controlType) { // Disable previous first this.disable(); if (controlType == null) { controlType = true; } if (controlType === true || (controlType === 'move' || controlType === 'pan')) { zr.on('mousedown', mousedownHandler); zr.on('mousemove', mousemoveHandler); zr.on('mouseup', mouseupHandler); } if (controlType === true || (controlType === 'scale' || controlType === 'zoom')) { zr.on('mousewheel', mousewheelHandler); zr.on('pinch', pinchHandler); } }; this.disable = function () { zr.off('mousedown', mousedownHandler); zr.off('mousemove', mousemoveHandler); zr.off('mouseup', mouseupHandler); zr.off('mousewheel', mousewheelHandler); zr.off('pinch', pinchHandler); }; this.dispose = this.disable; this.isDragging = function () { return this._dragging; }; this.isPinching = function () { return this._pinching; }; } zrUtil.mixin(RoamController, Eventful); module.exports = RoamController; /***/ }, /* 177 */ /***/ function(module, exports, __webpack_require__) { var ATTR = '\0_ec_interaction_mutex'; var interactionMutex = { take: function (zr, resourceKey, userKey) { var store = getStore(zr); store[resourceKey] = userKey; }, release: function (zr, resourceKey, userKey) { var store = getStore(zr); var uKey = store[resourceKey]; if (uKey === userKey) { store[resourceKey] = null; } }, isTaken: function (zr, resourceKey) { return !!getStore(zr)[resourceKey]; } }; function getStore(zr) { return zr[ATTR] || (zr[ATTR] = {}); } /** * payload: { * type: 'takeGlobalCursor', * key: 'dataZoomSelect', or 'brush', or ..., * If no userKey, release global cursor. * } */ __webpack_require__(1).registerAction( {type: 'takeGlobalCursor', event: 'globalCursorTaken', update: 'update'}, function () {} ); module.exports = interactionMutex; /***/ }, /* 178 */ /***/ function(module, exports, __webpack_require__) { var zrUtil = __webpack_require__(4); var roamHelper = __webpack_require__(179); var echarts = __webpack_require__(1); /** * @payload * @property {string} [componentType=series] * @property {number} [dx] * @property {number} [dy] * @property {number} [zoom] * @property {number} [originX] * @property {number} [originY] */ echarts.registerAction({ type: 'geoRoam', event: 'geoRoam', update: 'updateLayout' }, function (payload, ecModel) { var componentType = payload.componentType || 'series'; ecModel.eachComponent( { mainType: componentType, query: payload }, function (componentModel) { var geo = componentModel.coordinateSystem; if (geo.type !== 'geo') { return; } var res = roamHelper.updateCenterAndZoom( geo, payload, componentModel.get('scaleLimit') ); componentModel.setCenter && componentModel.setCenter(res.center); componentModel.setZoom && componentModel.setZoom(res.zoom); // All map series with same `map` use the same geo coordinate system // So the center and zoom must be in sync. Include the series not selected by legend if (componentType === 'series') { zrUtil.each(componentModel.seriesGroup, function (seriesModel) { seriesModel.setCenter(res.center); seriesModel.setZoom(res.zoom); }); } } ); }); /***/ }, /* 179 */ /***/ function(module, exports) { var roamHelper = {}; /** * @param {module:echarts/coord/View} view * @param {Object} payload * @param {Object} [zoomLimit] */ roamHelper.updateCenterAndZoom = function ( view, payload, zoomLimit ) { var previousZoom = view.getZoom(); var center = view.getCenter(); var zoom = payload.zoom; var point = view.dataToPoint(center); if (payload.dx != null && payload.dy != null) { point[0] -= payload.dx; point[1] -= payload.dy; var center = view.pointToData(point); view.setCenter(center); } if (zoom != null) { if (zoomLimit) { var zoomMin = zoomLimit.min || 0; var zoomMax = zoomLimit.max || Infinity; zoom = Math.max( Math.min(previousZoom * zoom, zoomMax), zoomMin ) / previousZoom; } // Zoom on given point(originX, originY) view.scale[0] *= zoom; view.scale[1] *= zoom; var position = view.position; var fixX = (payload.originX - position[0]) * (zoom - 1); var fixY = (payload.originY - position[1]) * (zoom - 1); position[0] -= fixX; position[1] -= fixY; view.updateTransform(); // Get the new center var center = view.pointToData(point); view.setCenter(center); view.setZoom(zoom * previousZoom); } return { center: view.getCenter(), zoom: view.getZoom() }; }; module.exports = roamHelper; /***/ }, /* 180 */ /***/ function(module, exports, __webpack_require__) { var zrUtil = __webpack_require__(4); module.exports = function (ecModel) { var processedMapType = {}; ecModel.eachSeriesByType('map', function (mapSeries) { var mapType = mapSeries.get('map'); if (processedMapType[mapType]) { return; } var mapSymbolOffsets = {}; zrUtil.each(mapSeries.seriesGroup, function (subMapSeries) { var geo = subMapSeries.coordinateSystem; var data = subMapSeries.originalData; if (subMapSeries.get('showLegendSymbol') && ecModel.getComponent('legend')) { data.each('value', function (value, idx) { var name = data.getName(idx); var region = geo.getRegion(name); // If input series.data is [11, 22, '-'/null/undefined, 44], // it will be filled with NaN: [11, 22, NaN, 44] and NaN will // not be drawn. So here must validate if value is NaN. if (!region || isNaN(value)) { return; } var offset = mapSymbolOffsets[name] || 0; var point = geo.dataToPoint(region.center); mapSymbolOffsets[name] = offset + 1; data.setItemLayout(idx, { point: point, offset: offset }); }); } }); // Show label of those region not has legendSymbol(which is offset 0) var data = mapSeries.getData(); data.each(function (idx) { var name = data.getName(idx); var layout = data.getItemLayout(idx) || {}; layout.showLabel = !mapSymbolOffsets[name]; data.setItemLayout(idx, layout); }); processedMapType[mapType] = true; }); }; /***/ }, /* 181 */ /***/ function(module, exports) { module.exports = function (ecModel) { ecModel.eachSeriesByType('map', function (seriesModel) { var colorList = seriesModel.get('color'); var itemStyleModel = seriesModel.getModel('itemStyle.normal'); var areaColor = itemStyleModel.get('areaColor'); var color = itemStyleModel.get('color') || colorList[seriesModel.seriesIndex % colorList.length]; seriesModel.getData().setVisual({ 'areaColor': areaColor, 'color': color }); }); }; /***/ }, /* 182 */ /***/ function(module, exports, __webpack_require__) { var zrUtil = __webpack_require__(4); // FIXME 公用? /** * @param {Array.} datas * @param {string} statisticType 'average' 'sum' * @inner */ function dataStatistics(datas, statisticType) { var dataNameMap = {}; var dims = ['value']; for (var i = 0; i < datas.length; i++) { datas[i].each(dims, function (value, idx) { var name = datas[i].getName(idx); dataNameMap[name] = dataNameMap[name] || []; if (!isNaN(value)) { dataNameMap[name].push(value); } }); } return datas[0].map(dims, function (value, idx) { var name = datas[0].getName(idx); var sum = 0; var min = Infinity; var max = -Infinity; var len = dataNameMap[name].length; for (var i = 0; i < len; i++) { min = Math.min(min, dataNameMap[name][i]); max = Math.max(max, dataNameMap[name][i]); sum += dataNameMap[name][i]; } var result; if (statisticType === 'min') { result = min; } else if (statisticType === 'max') { result = max; } else if (statisticType === 'average') { result = sum / len; } else { result = sum; } return len === 0 ? NaN : result; }); } module.exports = function (ecModel) { var seriesGroupByMapType = {}; ecModel.eachSeriesByType('map', function (seriesModel) { var mapType = seriesModel.get('map'); seriesGroupByMapType[mapType] = seriesGroupByMapType[mapType] || []; seriesGroupByMapType[mapType].push(seriesModel); }); zrUtil.each(seriesGroupByMapType, function (seriesList, mapType) { var data = dataStatistics( zrUtil.map(seriesList, function (seriesModel) { return seriesModel.getData(); }), seriesList[0].get('mapValueCalculation') ); for (var i = 0; i < seriesList.length; i++) { seriesList[i].originalData = seriesList[i].getData(); } // FIXME Put where? for (var i = 0; i < seriesList.length; i++) { seriesList[i].seriesGroup = seriesList; seriesList[i].needsDrawMap = i === 0; seriesList[i].setData(data.cloneShallow()); seriesList[i].mainSeries = seriesList[0]; } }); }; /***/ }, /* 183 */ /***/ function(module, exports, __webpack_require__) { var zrUtil = __webpack_require__(4); module.exports = function (option) { // Save geoCoord var mapSeries = []; zrUtil.each(option.series, function (seriesOpt) { if (seriesOpt.type === 'map') { mapSeries.push(seriesOpt); } }); zrUtil.each(mapSeries, function (seriesOpt) { seriesOpt.map = seriesOpt.map || seriesOpt.mapType; // Put x, y, width, height, x2, y2 in the top level zrUtil.defaults(seriesOpt, seriesOpt.mapLocation); }); }; /***/ }, /* 184 */ /***/ function(module, exports, __webpack_require__) { var echarts = __webpack_require__(1); __webpack_require__(185); __webpack_require__(189); __webpack_require__(192); echarts.registerVisual(__webpack_require__(193)); echarts.registerLayout(__webpack_require__(195)); /***/ }, /* 185 */ /***/ function(module, exports, __webpack_require__) { var SeriesModel = __webpack_require__(28); var Tree = __webpack_require__(186); var zrUtil = __webpack_require__(4); var Model = __webpack_require__(12); var formatUtil = __webpack_require__(6); var helper = __webpack_require__(188); var encodeHTML = formatUtil.encodeHTML; var addCommas = formatUtil.addCommas; module.exports = SeriesModel.extend({ type: 'series.treemap', layoutMode: 'box', dependencies: ['grid', 'polar'], /** * @type {module:echarts/data/Tree~Node} */ _viewRoot: null, defaultOption: { // Disable progressive rendering progressive: 0, hoverLayerThreshold: Infinity, // center: ['50%', '50%'], // not supported in ec3. // size: ['80%', '80%'], // deprecated, compatible with ec2. left: 'center', top: 'middle', right: null, bottom: null, width: '80%', height: '80%', sort: true, // Can be null or false or true // (order by desc default, asc not supported yet (strange effect)) clipWindow: 'origin', // Size of clipped window when zooming. 'origin' or 'fullscreen' squareRatio: 0.5 * (1 + Math.sqrt(5)), // golden ratio leafDepth: null, // Nodes on depth from root are regarded as leaves. // Count from zero (zero represents only view root). drillDownIcon: '▶', // Use html character temporarily because it is complicated // to align specialized icon. ▷▶❒❐▼✚ zoomToNodeRatio: 0.32 * 0.32, // Be effective when using zoomToNode. Specify the proportion of the // target node area in the view area. roam: true, // true, false, 'scale' or 'zoom', 'move'. nodeClick: 'zoomToNode', // Leaf node click behaviour: 'zoomToNode', 'link', false. // If leafDepth is set and clicking a node which has children but // be on left depth, the behaviour would be changing root. Otherwise // use behavious defined above. animation: true, animationDurationUpdate: 900, animationEasing: 'quinticInOut', breadcrumb: { show: true, height: 22, left: 'center', top: 'bottom', // right // bottom emptyItemWidth: 25, // Width of empty node. itemStyle: { normal: { color: 'rgba(0,0,0,0.7)', //'#5793f3', borderColor: 'rgba(255,255,255,0.7)', borderWidth: 1, shadowColor: 'rgba(150,150,150,1)', shadowBlur: 3, shadowOffsetX: 0, shadowOffsetY: 0, textStyle: { color: '#fff' } }, emphasis: { textStyle: {} } } }, label: { normal: { show: true, position: 'inside', // Can be [5, '5%'] or position stirng like 'insideTopLeft', ... textStyle: { color: '#fff', ellipsis: true } } }, itemStyle: { normal: { color: null, // Can be 'none' if not necessary. colorAlpha: null, // Can be 'none' if not necessary. colorSaturation: null, // Can be 'none' if not necessary. borderWidth: 0, gapWidth: 0, borderColor: '#fff', borderColorSaturation: null // If specified, borderColor will be ineffective, and the // border color is evaluated by color of current node and // borderColorSaturation. }, emphasis: { } }, visualDimension: 0, // Can be 0, 1, 2, 3. visualMin: null, visualMax: null, color: [], // + treemapSeries.color should not be modified. Please only modified // level[n].color (if necessary). // + Specify color list of each level. level[0].color would be global // color list if not specified. (see method `setDefault`). // + But set as a empty array to forbid fetch color from global palette // when using nodeModel.get('color'), otherwise nodes on deep level // will always has color palette set and are not able to inherit color // from parent node. // + TreemapSeries.color can not be set as 'none', otherwise effect // legend color fetching (see seriesColor.js). colorAlpha: null, // Array. Specify color alpha range of each level, like [0.2, 0.8] colorSaturation: null, // Array. Specify color saturation of each level, like [0.2, 0.5] colorMappingBy: 'index', // 'value' or 'index' or 'id'. visibleMin: 10, // If area less than this threshold (unit: pixel^2), node will not // be rendered. Only works when sort is 'asc' or 'desc'. childrenVisibleMin: null, // If area of a node less than this threshold (unit: pixel^2), // grandchildren will not show. // Why grandchildren? If not grandchildren but children, // some siblings show children and some not, // the appearance may be mess and not consistent, levels: [] // Each item: { // visibleMin, itemStyle, visualDimension, label // } // data: { // value: [], // children: [], // link: 'http://xxx.xxx.xxx', // target: 'blank' or 'self' // } }, /** * @override */ getInitialData: function (option, ecModel) { var data = option.data || []; var rootName = option.name; rootName == null && (rootName = option.name); // Create a virtual root. var root = {name: rootName, children: option.data}; var value0 = (data[0] || {}).value; completeTreeValue(root, zrUtil.isArray(value0) ? value0.length : -1); // FIXME // sereis.mergeOption 的 getInitData是否放在merge后,从而能直接获取merege后的结果而非手动判断。 var levels = option.levels || []; levels = option.levels = setDefault(levels, ecModel); // Make sure always a new tree is created when setOption, // in TreemapView, we check whether oldTree === newTree // to choose mappings approach among old shapes and new shapes. return Tree.createTree(root, this, levels).data; }, optionUpdated: function () { this.resetViewRoot(); }, /** * @override * @param {number} dataIndex * @param {boolean} [mutipleSeries=false] */ formatTooltip: function (dataIndex) { var data = this.getData(); var value = this.getRawValue(dataIndex); var formattedValue = zrUtil.isArray(value) ? addCommas(value[0]) : addCommas(value); var name = data.getName(dataIndex); return encodeHTML(name) + ': ' + formattedValue; }, /** * Add tree path to tooltip param * * @override * @param {number} dataIndex * @return {Object} */ getDataParams: function (dataIndex) { var params = SeriesModel.prototype.getDataParams.apply(this, arguments); var node = this.getData().tree.getNodeByDataIndex(dataIndex); params.treePathInfo = helper.wrapTreePathInfo(node, this); return params; }, /** * @public * @param {Object} layoutInfo { * x: containerGroup x * y: containerGroup y * width: containerGroup width * height: containerGroup height * } */ setLayoutInfo: function (layoutInfo) { /** * @readOnly * @type {Object} */ this.layoutInfo = this.layoutInfo || {}; zrUtil.extend(this.layoutInfo, layoutInfo); }, /** * @param {string} id * @return {number} index */ mapIdToIndex: function (id) { // A feature is implemented: // index is monotone increasing with the sequence of // input id at the first time. // This feature can make sure that each data item and its // mapped color have the same index between data list and // color list at the beginning, which is useful for user // to adjust data-color mapping. /** * @private * @type {Object} */ var idIndexMap = this._idIndexMap; if (!idIndexMap) { idIndexMap = this._idIndexMap = {}; /** * @private * @type {number} */ this._idIndexMapCount = 0; } var index = idIndexMap[id]; if (index == null) { idIndexMap[id] = index = this._idIndexMapCount++; } return index; }, getViewRoot: function () { return this._viewRoot; }, /** * @param {module:echarts/data/Tree~Node} [viewRoot] */ resetViewRoot: function (viewRoot) { viewRoot ? (this._viewRoot = viewRoot) : (viewRoot = this._viewRoot); var root = this.getData().tree.root; if (!viewRoot || (viewRoot !== root && !root.contains(viewRoot)) ) { this._viewRoot = root; } } }); /** * @param {Object} dataNode */ function completeTreeValue(dataNode, arrValueLength) { // Postorder travel tree. // If value of none-leaf node is not set, // calculate it by suming up the value of all children. var sum = 0; zrUtil.each(dataNode.children, function (child) { completeTreeValue(child, arrValueLength); var childValue = child.value; zrUtil.isArray(childValue) && (childValue = childValue[0]); sum += childValue; }); var thisValue = dataNode.value; if (arrValueLength >= 0) { if (!zrUtil.isArray(thisValue)) { dataNode.value = new Array(arrValueLength); } else { thisValue = thisValue[0]; } } if (thisValue == null || isNaN(thisValue)) { thisValue = sum; } // Value should not less than 0. if (thisValue < 0) { thisValue = 0; } arrValueLength >= 0 ? (dataNode.value[0] = thisValue) : (dataNode.value = thisValue); } /** * set default to level configuration */ function setDefault(levels, ecModel) { var globalColorList = ecModel.get('color'); if (!globalColorList) { return; } levels = levels || []; var hasColorDefine; zrUtil.each(levels, function (levelDefine) { var model = new Model(levelDefine); var modelColor = model.get('color'); if (model.get('itemStyle.normal.color') || (modelColor && modelColor !== 'none') ) { hasColorDefine = true; } }); if (!hasColorDefine) { var level0 = levels[0] || (levels[0] = {}); level0.color = globalColorList.slice(); } return levels; } /***/ }, /* 186 */ /***/ function(module, exports, __webpack_require__) { /** * Tree data structure * * @module echarts/data/Tree */ var zrUtil = __webpack_require__(4); var Model = __webpack_require__(12); var List = __webpack_require__(98); var linkList = __webpack_require__(187); var completeDimensions = __webpack_require__(103); /** * @constructor module:echarts/data/Tree~TreeNode * @param {string} name * @param {module:echarts/data/Tree} hostTree */ var TreeNode = function (name, hostTree) { /** * @type {string} */ this.name = name || ''; /** * Depth of node * * @type {number} * @readOnly */ this.depth = 0; /** * Height of the subtree rooted at this node. * @type {number} * @readOnly */ this.height = 0; /** * @type {module:echarts/data/Tree~TreeNode} * @readOnly */ this.parentNode = null; /** * Reference to list item. * Do not persistent dataIndex outside, * besause it may be changed by list. * If dataIndex -1, * this node is logical deleted (filtered) in list. * * @type {Object} * @readOnly */ this.dataIndex = -1; /** * @type {Array.} * @readOnly */ this.children = []; /** * @type {Array.} * @pubilc */ this.viewChildren = []; /** * @type {moduel:echarts/data/Tree} * @readOnly */ this.hostTree = hostTree; }; TreeNode.prototype = { constructor: TreeNode, /** * The node is removed. * @return {boolean} is removed. */ isRemoved: function () { return this.dataIndex < 0; }, /** * Travel this subtree (include this node). * Usage: * node.eachNode(function () { ... }); // preorder * node.eachNode('preorder', function () { ... }); // preorder * node.eachNode('postorder', function () { ... }); // postorder * node.eachNode( * {order: 'postorder', attr: 'viewChildren'}, * function () { ... } * ); // postorder * * @param {(Object|string)} options If string, means order. * @param {string=} options.order 'preorder' or 'postorder' * @param {string=} options.attr 'children' or 'viewChildren' * @param {Function} cb If in preorder and return false, * its subtree will not be visited. * @param {Object} [context] */ eachNode: function (options, cb, context) { if (typeof options === 'function') { context = cb; cb = options; options = null; } options = options || {}; if (zrUtil.isString(options)) { options = {order: options}; } var order = options.order || 'preorder'; var children = this[options.attr || 'children']; var suppressVisitSub; order === 'preorder' && (suppressVisitSub = cb.call(context, this)); for (var i = 0; !suppressVisitSub && i < children.length; i++) { children[i].eachNode(options, cb, context); } order === 'postorder' && cb.call(context, this); }, /** * Update depth and height of this subtree. * * @param {number} depth */ updateDepthAndHeight: function (depth) { var height = 0; this.depth = depth; for (var i = 0; i < this.children.length; i++) { var child = this.children[i]; child.updateDepthAndHeight(depth + 1); if (child.height > height) { height = child.height; } } this.height = height + 1; }, /** * @param {string} id * @return {module:echarts/data/Tree~TreeNode} */ getNodeById: function (id) { if (this.getId() === id) { return this; } for (var i = 0, children = this.children, len = children.length; i < len; i++) { var res = children[i].getNodeById(id); if (res) { return res; } } }, /** * @param {module:echarts/data/Tree~TreeNode} node * @return {boolean} */ contains: function (node) { if (node === this) { return true; } for (var i = 0, children = this.children, len = children.length; i < len; i++) { var res = children[i].contains(node); if (res) { return res; } } }, /** * @param {boolean} includeSelf Default false. * @return {Array.} order: [root, child, grandchild, ...] */ getAncestors: function (includeSelf) { var ancestors = []; var node = includeSelf ? this : this.parentNode; while (node) { ancestors.push(node); node = node.parentNode; } ancestors.reverse(); return ancestors; }, /** * @param {string|Array=} [dimension='value'] Default 'value'. can be 0, 1, 2, 3 * @return {number} Value. */ getValue: function (dimension) { var data = this.hostTree.data; return data.get(data.getDimension(dimension || 'value'), this.dataIndex); }, /** * @param {Object} layout * @param {boolean=} [merge=false] */ setLayout: function (layout, merge) { this.dataIndex >= 0 && this.hostTree.data.setItemLayout(this.dataIndex, layout, merge); }, /** * @return {Object} layout */ getLayout: function () { return this.hostTree.data.getItemLayout(this.dataIndex); }, /** * @param {string} path * @return {module:echarts/model/Model} */ getModel: function (path) { if (this.dataIndex < 0) { return; } var hostTree = this.hostTree; var itemModel = hostTree.data.getItemModel(this.dataIndex); var levelModel = this.getLevelModel(); return itemModel.getModel(path, (levelModel || hostTree.hostModel).getModel(path)); }, /** * @return {module:echarts/model/Model} */ getLevelModel: function () { return (this.hostTree.levelModels || [])[this.depth]; }, /** * @example * setItemVisual('color', color); * setItemVisual({ * 'color': color * }); */ setVisual: function (key, value) { this.dataIndex >= 0 && this.hostTree.data.setItemVisual(this.dataIndex, key, value); }, /** * Get item visual */ getVisual: function (key, ignoreParent) { return this.hostTree.data.getItemVisual(this.dataIndex, key, ignoreParent); }, /** * @public * @return {number} */ getRawIndex: function () { return this.hostTree.data.getRawIndex(this.dataIndex); }, /** * @public * @return {string} */ getId: function () { return this.hostTree.data.getId(this.dataIndex); } }; /** * @constructor * @alias module:echarts/data/Tree * @param {module:echarts/model/Model} hostModel * @param {Array.} levelOptions */ function Tree(hostModel, levelOptions) { /** * @type {module:echarts/data/Tree~TreeNode} * @readOnly */ this.root; /** * @type {module:echarts/data/List} * @readOnly */ this.data; /** * Index of each item is the same as the raw index of coresponding list item. * @private * @type {Array.} levelOptions * @return module:echarts/data/Tree */ Tree.createTree = function (dataRoot, hostModel, levelOptions) { var tree = new Tree(hostModel, levelOptions); var listData = []; buildHierarchy(dataRoot); function buildHierarchy(dataNode, parentNode) { listData.push(dataNode); var node = new TreeNode(dataNode.name, tree); parentNode ? addChild(node, parentNode) : (tree.root = node); tree._nodes.push(node); var children = dataNode.children; if (children) { for (var i = 0; i < children.length; i++) { buildHierarchy(children[i], node); } } } tree.root.updateDepthAndHeight(0); var dimensions = completeDimensions([{name: 'value'}], listData); var list = new List(dimensions, hostModel); list.initData(listData); linkList({ mainData: list, struct: tree, structAttr: 'tree' }); tree.update(); return tree; }; /** * It is needed to consider the mess of 'list', 'hostModel' when creating a TreeNote, * so this function is not ready and not necessary to be public. * * @param {(module:echarts/data/Tree~TreeNode|Object)} child */ function addChild(child, node) { var children = node.children; if (child.parentNode === node) { return; } children.push(child); child.parentNode = node; } module.exports = Tree; /***/ }, /* 187 */ /***/ function(module, exports, __webpack_require__) { /** * Link lists and struct (graph or tree) */ var zrUtil = __webpack_require__(4); var each = zrUtil.each; var DATAS = '\0__link_datas'; var MAIN_DATA = '\0__link_mainData'; // Caution: // In most case, either list or its shallow clones (see list.cloneShallow) // is active in echarts process. So considering heap memory consumption, // we do not clone tree or graph, but share them among list and its shallow clones. // But in some rare case, we have to keep old list (like do animation in chart). So // please take care that both the old list and the new list share the same tree/graph. /** * @param {Object} opt * @param {module:echarts/data/List} opt.mainData * @param {Object} [opt.struct] For example, instance of Graph or Tree. * @param {string} [opt.structAttr] designation: list[structAttr] = struct; * @param {Object} [opt.datas] {dataType: data}, * like: {node: nodeList, edge: edgeList}. * Should contain mainData. * @param {Object} [opt.datasAttr] {dataType: attr}, * designation: struct[datasAttr[dataType]] = list; */ function linkList(opt) { var mainData = opt.mainData; var datas = opt.datas; if (!datas) { datas = {main: mainData}; opt.datasAttr = {main: 'data'}; } opt.datas = opt.mainData = null; linkAll(mainData, datas, opt); // Porxy data original methods. each(datas, function (data) { each(mainData.TRANSFERABLE_METHODS, function (methodName) { data.wrapMethod(methodName, zrUtil.curry(transferInjection, opt)); }); }); // Beyond transfer, additional features should be added to `cloneShallow`. mainData.wrapMethod('cloneShallow', zrUtil.curry(cloneShallowInjection, opt)); // Only mainData trigger change, because struct.update may trigger // another changable methods, which may bring about dead lock. each(mainData.CHANGABLE_METHODS, function (methodName) { mainData.wrapMethod(methodName, zrUtil.curry(changeInjection, opt)); }); // Make sure datas contains mainData. zrUtil.assert(datas[mainData.dataType] === mainData); } function transferInjection(opt, res) { if (isMainData(this)) { // Transfer datas to new main data. var datas = zrUtil.extend({}, this[DATAS]); datas[this.dataType] = res; linkAll(res, datas, opt); } else { // Modify the reference in main data to point newData. linkSingle(res, this.dataType, this[MAIN_DATA], opt); } return res; } function changeInjection(opt, res) { opt.struct && opt.struct.update(this); return res; } function cloneShallowInjection(opt, res) { // cloneShallow, which brings about some fragilities, may be inappropriate // to be exposed as an API. So for implementation simplicity we can make // the restriction that cloneShallow of not-mainData should not be invoked // outside, but only be invoked here. each(res[DATAS], function (data, dataType) { data !== res && linkSingle(data.cloneShallow(), dataType, res, opt); }); return res; } /** * Supplement method to List. * * @public * @param {string} [dataType] If not specified, return mainData. * @return {module:echarts/data/List} */ function getLinkedData(dataType) { var mainData = this[MAIN_DATA]; return (dataType == null || mainData == null) ? mainData : mainData[DATAS][dataType]; } function isMainData(data) { return data[MAIN_DATA] === data; } function linkAll(mainData, datas, opt) { mainData[DATAS] = {}; each(datas, function (data, dataType) { linkSingle(data, dataType, mainData, opt); }); } function linkSingle(data, dataType, mainData, opt) { mainData[DATAS][dataType] = data; data[MAIN_DATA] = mainData; data.dataType = dataType; if (opt.struct) { data[opt.structAttr] = opt.struct; opt.struct[opt.datasAttr[dataType]] = data; } // Supplement method. data.getLinkedData = getLinkedData; } module.exports = linkList; /***/ }, /* 188 */ /***/ function(module, exports, __webpack_require__) { var zrUtil = __webpack_require__(4); var helper = { retrieveTargetInfo: function (payload, seriesModel) { if (payload && ( payload.type === 'treemapZoomToNode' || payload.type === 'treemapRootToNode' ) ) { var root = seriesModel.getData().tree.root; var targetNode = payload.targetNode; if (targetNode && root.contains(targetNode)) { return {node: targetNode}; } var targetNodeId = payload.targetNodeId; if (targetNodeId != null && (targetNode = root.getNodeById(targetNodeId))) { return {node: targetNode}; } } }, // Not includes the given node at the last item. getPathToRoot: function (node) { var path = []; while (node) { node = node.parentNode; node && path.push(node); } return path.reverse(); }, aboveViewRoot: function (viewRoot, node) { var viewPath = helper.getPathToRoot(viewRoot); return zrUtil.indexOf(viewPath, node) >= 0; }, // From root to the input node (the input node will be included). wrapTreePathInfo: function (node, seriesModel) { var treePathInfo = []; while (node) { var nodeDataIndex = node.dataIndex; treePathInfo.push({ name: node.name, dataIndex: nodeDataIndex, value: seriesModel.getRawValue(nodeDataIndex) }); node = node.parentNode; } treePathInfo.reverse(); return treePathInfo; } }; module.exports = helper; /***/ }, /* 189 */ /***/ function(module, exports, __webpack_require__) { var zrUtil = __webpack_require__(4); var graphic = __webpack_require__(43); var DataDiffer = __webpack_require__(99); var helper = __webpack_require__(188); var Breadcrumb = __webpack_require__(190); var RoamController = __webpack_require__(176); var BoundingRect = __webpack_require__(9); var matrix = __webpack_require__(11); var animationUtil = __webpack_require__(191); var bind = zrUtil.bind; var Group = graphic.Group; var Rect = graphic.Rect; var each = zrUtil.each; var DRAG_THRESHOLD = 3; var PATH_LABEL_NORMAL = ['label', 'normal']; var PATH_LABEL_EMPHASIS = ['label', 'emphasis']; var Z_BASE = 10; // Should bigger than every z. var Z_BG = 1; var Z_CONTENT = 2; module.exports = __webpack_require__(1).extendChartView({ type: 'treemap', /** * @override */ init: function (o, api) { /** * @private * @type {module:zrender/container/Group} */ this._containerGroup; /** * @private * @type {Object.>} */ this._storage = createStorage(); /** * @private * @type {module:echarts/data/Tree} */ this._oldTree; /** * @private * @type {module:echarts/chart/treemap/Breadcrumb} */ this._breadcrumb; /** * @private * @type {module:echarts/component/helper/RoamController} */ this._controller; /** * 'ready', 'animating' * @private */ this._state = 'ready'; /** * @private * @type {boolean} */ this._mayClick; }, /** * @override */ render: function (seriesModel, ecModel, api, payload) { var models = ecModel.findComponents({ mainType: 'series', subType: 'treemap', query: payload }); if (zrUtil.indexOf(models, seriesModel) < 0) { return; } this.seriesModel = seriesModel; this.api = api; this.ecModel = ecModel; var targetInfo = helper.retrieveTargetInfo(payload, seriesModel); var payloadType = payload && payload.type; var layoutInfo = seriesModel.layoutInfo; var isInit = !this._oldTree; var thisStorage = this._storage; // Mark new root when action is treemapRootToNode. var reRoot = (payloadType === 'treemapRootToNode' && targetInfo && thisStorage) ? { rootNodeGroup: thisStorage.nodeGroup[targetInfo.node.getRawIndex()], direction: payload.direction } : null; var containerGroup = this._giveContainerGroup(layoutInfo); var renderResult = this._doRender(containerGroup, seriesModel, reRoot); ( !isInit && ( !payloadType || payloadType === 'treemapZoomToNode' || payloadType === 'treemapRootToNode' ) ) ? this._doAnimation(containerGroup, renderResult, seriesModel, reRoot) : renderResult.renderFinally(); this._resetController(api); this._renderBreadcrumb(seriesModel, api, targetInfo); }, /** * @private */ _giveContainerGroup: function (layoutInfo) { var containerGroup = this._containerGroup; if (!containerGroup) { // FIXME // 加一层containerGroup是为了clip,但是现在clip功能并没有实现。 containerGroup = this._containerGroup = new Group(); this._initEvents(containerGroup); this.group.add(containerGroup); } containerGroup.attr('position', [layoutInfo.x, layoutInfo.y]); return containerGroup; }, /** * @private */ _doRender: function (containerGroup, seriesModel, reRoot) { var thisTree = seriesModel.getData().tree; var oldTree = this._oldTree; // Clear last shape records. var lastsForAnimation = createStorage(); var thisStorage = createStorage(); var oldStorage = this._storage; var willInvisibleEls = []; var doRenderNode = zrUtil.curry( renderNode, seriesModel, thisStorage, oldStorage, reRoot, lastsForAnimation, willInvisibleEls ); // Notice: when thisTree and oldTree are the same tree (see list.cloneShadow), // the oldTree is actually losted, so we can not find all of the old graphic // elements from tree. So we use this stragegy: make element storage, move // from old storage to new storage, clear old storage. dualTravel( thisTree.root ? [thisTree.root] : [], (oldTree && oldTree.root) ? [oldTree.root] : [], containerGroup, thisTree === oldTree || !oldTree, 0 ); // Process all removing. var willDeleteEls = clearStorage(oldStorage); this._oldTree = thisTree; this._storage = thisStorage; return { lastsForAnimation: lastsForAnimation, willDeleteEls: willDeleteEls, renderFinally: renderFinally }; function dualTravel(thisViewChildren, oldViewChildren, parentGroup, sameTree, depth) { // When 'render' is triggered by action, // 'this' and 'old' may be the same tree, // we use rawIndex in that case. if (sameTree) { oldViewChildren = thisViewChildren; each(thisViewChildren, function (child, index) { !child.isRemoved() && processNode(index, index); }); } // Diff hierarchically (diff only in each subtree, but not whole). // because, consistency of view is important. else { (new DataDiffer(oldViewChildren, thisViewChildren, getKey, getKey)) .add(processNode) .update(processNode) .remove(zrUtil.curry(processNode, null)) .execute(); } function getKey(node) { // Identify by name or raw index. return node.getId(); } function processNode(newIndex, oldIndex) { var thisNode = newIndex != null ? thisViewChildren[newIndex] : null; var oldNode = oldIndex != null ? oldViewChildren[oldIndex] : null; var group = doRenderNode(thisNode, oldNode, parentGroup, depth); group && dualTravel( thisNode && thisNode.viewChildren || [], oldNode && oldNode.viewChildren || [], group, sameTree, depth + 1 ); } } function clearStorage(storage) { var willDeleteEls = createStorage(); storage && each(storage, function (store, storageName) { var delEls = willDeleteEls[storageName]; each(store, function (el) { el && (delEls.push(el), el.__tmWillDelete = 1); }); }); return willDeleteEls; } function renderFinally() { each(willDeleteEls, function (els) { each(els, function (el) { el.parent && el.parent.remove(el); }); }); each(willInvisibleEls, function (el) { el.invisible = true; // Setting invisible is for optimizing, so no need to set dirty, // just mark as invisible. el.dirty(); }); } }, /** * @private */ _doAnimation: function (containerGroup, renderResult, seriesModel, reRoot) { if (!seriesModel.get('animation')) { return; } var duration = seriesModel.get('animationDurationUpdate'); var easing = seriesModel.get('animationEasing'); var animationWrap = animationUtil.createWrap(); // Make delete animations. each(renderResult.willDeleteEls, function (store, storageName) { each(store, function (el, rawIndex) { if (el.invisible) { return; } var parent = el.parent; // Always has parent, and parent is nodeGroup. var target; if (reRoot && reRoot.direction === 'drillDown') { target = parent === reRoot.rootNodeGroup // This is the content element of view root. // Only `content` will enter this branch, because // `background` and `nodeGroup` will not be deleted. ? { shape: { x: 0, y: 0, width: parent.__tmNodeWidth, height: parent.__tmNodeHeight }, style: { opacity: 0 } } // Others. : {style: {opacity: 0}}; } else { var targetX = 0; var targetY = 0; if (!parent.__tmWillDelete) { // Let node animate to right-bottom corner, cooperating with fadeout, // which is appropriate for user understanding. // Divided by 2 for reRoot rolling up effect. targetX = parent.__tmNodeWidth / 2; targetY = parent.__tmNodeHeight / 2; } target = storageName === 'nodeGroup' ? {position: [targetX, targetY], style: {opacity: 0}} : { shape: {x: targetX, y: targetY, width: 0, height: 0}, style: {opacity: 0} }; } target && animationWrap.add(el, target, duration, easing); }); }); // Make other animations each(this._storage, function (store, storageName) { each(store, function (el, rawIndex) { var last = renderResult.lastsForAnimation[storageName][rawIndex]; var target = {}; if (!last) { return; } if (storageName === 'nodeGroup') { if (last.old) { target.position = el.position.slice(); el.attr('position', last.old); } } else { if (last.old) { target.shape = zrUtil.extend({}, el.shape); el.setShape(last.old); } if (last.fadein) { el.setStyle('opacity', 0); target.style = {opacity: 1}; } // When animation is stopped for succedent animation starting, // el.style.opacity might not be 1 else if (el.style.opacity !== 1) { target.style = {opacity: 1}; } } animationWrap.add(el, target, duration, easing); }); }, this); this._state = 'animating'; animationWrap .done(bind(function () { this._state = 'ready'; renderResult.renderFinally(); }, this)) .start(); }, /** * @private */ _resetController: function (api) { var controller = this._controller; // Init controller. if (!controller) { controller = this._controller = new RoamController(api.getZr()); controller.enable(this.seriesModel.get('roam')); controller.on('pan', bind(this._onPan, this)); controller.on('zoom', bind(this._onZoom, this)); } var rect = new BoundingRect(0, 0, api.getWidth(), api.getHeight()); controller.setContainsPoint(function (x, y) { return rect.contain(x, y); }); }, /** * @private */ _clearController: function () { var controller = this._controller; if (controller) { controller.dispose(); controller = null; } }, /** * @private */ _onPan: function (dx, dy) { this._mayClick = false; if (this._state !== 'animating' && (Math.abs(dx) > DRAG_THRESHOLD || Math.abs(dy) > DRAG_THRESHOLD) ) { // These param must not be cached. var root = this.seriesModel.getData().tree.root; if (!root) { return; } var rootLayout = root.getLayout(); if (!rootLayout) { return; } this.api.dispatchAction({ type: 'treemapMove', from: this.uid, seriesId: this.seriesModel.id, rootRect: { x: rootLayout.x + dx, y: rootLayout.y + dy, width: rootLayout.width, height: rootLayout.height } }); } }, /** * @private */ _onZoom: function (scale, mouseX, mouseY) { this._mayClick = false; if (this._state !== 'animating') { // These param must not be cached. var root = this.seriesModel.getData().tree.root; if (!root) { return; } var rootLayout = root.getLayout(); if (!rootLayout) { return; } var rect = new BoundingRect( rootLayout.x, rootLayout.y, rootLayout.width, rootLayout.height ); var layoutInfo = this.seriesModel.layoutInfo; // Transform mouse coord from global to containerGroup. mouseX -= layoutInfo.x; mouseY -= layoutInfo.y; // Scale root bounding rect. var m = matrix.create(); matrix.translate(m, m, [-mouseX, -mouseY]); matrix.scale(m, m, [scale, scale]); matrix.translate(m, m, [mouseX, mouseY]); rect.applyTransform(m); this.api.dispatchAction({ type: 'treemapRender', from: this.uid, seriesId: this.seriesModel.id, rootRect: { x: rect.x, y: rect.y, width: rect.width, height: rect.height } }); } }, /** * @private */ _initEvents: function (containerGroup) { // FIXME // 不用click以及silent的原因是,animate时视图设置silent true来避免click生效, // 但是animate中,按下鼠标,animate结束后(silent设回为false)松开鼠标, // 还是会触发click,期望是不触发。 // Mousedown occurs when drag start, and mouseup occurs when drag end, // click event should not be triggered in that case. containerGroup.on('mousedown', function (e) { this._state === 'ready' && (this._mayClick = true); }, this); containerGroup.on('mouseup', function (e) { if (this._mayClick) { this._mayClick = false; this._state === 'ready' && onClick.call(this, e); } }, this); function onClick(e) { var nodeClick = this.seriesModel.get('nodeClick', true); if (!nodeClick) { return; } var targetInfo = this.findTarget(e.offsetX, e.offsetY); if (!targetInfo) { return; } var node = targetInfo.node; if (node.getLayout().isLeafRoot) { this._rootToNode(targetInfo); } else { if (nodeClick === 'zoomToNode') { this._zoomToNode(targetInfo); } else if (nodeClick === 'link') { var itemModel = node.hostTree.data.getItemModel(node.dataIndex); var link = itemModel.get('link', true); var linkTarget = itemModel.get('target', true) || 'blank'; link && window.open(link, linkTarget); } } } }, /** * @private */ _renderBreadcrumb: function (seriesModel, api, targetInfo) { if (!targetInfo) { targetInfo = seriesModel.get('leafDepth', true) != null ? {node: seriesModel.getViewRoot()} // FIXME // better way? // Find breadcrumb tail on center of containerGroup. : this.findTarget(api.getWidth() / 2, api.getHeight() / 2); if (!targetInfo) { targetInfo = {node: seriesModel.getData().tree.root}; } } (this._breadcrumb || (this._breadcrumb = new Breadcrumb(this.group))) .render(seriesModel, api, targetInfo.node, bind(onSelect, this)); function onSelect(node) { if (this._state !== 'animating') { helper.aboveViewRoot(seriesModel.getViewRoot(), node) ? this._rootToNode({node: node}) : this._zoomToNode({node: node}); } } }, /** * @override */ remove: function () { this._clearController(); this._containerGroup && this._containerGroup.removeAll(); this._storage = createStorage(); this._state = 'ready'; this._breadcrumb && this._breadcrumb.remove(); }, dispose: function () { this._clearController(); }, /** * @private */ _zoomToNode: function (targetInfo) { this.api.dispatchAction({ type: 'treemapZoomToNode', from: this.uid, seriesId: this.seriesModel.id, targetNode: targetInfo.node }); }, /** * @private */ _rootToNode: function (targetInfo) { this.api.dispatchAction({ type: 'treemapRootToNode', from: this.uid, seriesId: this.seriesModel.id, targetNode: targetInfo.node }); }, /** * @public * @param {number} x Global coord x. * @param {number} y Global coord y. * @return {Object} info If not found, return undefined; * @return {number} info.node Target node. * @return {number} info.offsetX x refer to target node. * @return {number} info.offsetY y refer to target node. */ findTarget: function (x, y) { var targetInfo; var viewRoot = this.seriesModel.getViewRoot(); viewRoot.eachNode({attr: 'viewChildren', order: 'preorder'}, function (node) { var bgEl = this._storage.background[node.getRawIndex()]; // If invisible, there might be no element. if (bgEl) { var point = bgEl.transformCoordToLocal(x, y); var shape = bgEl.shape; // For performance consideration, dont use 'getBoundingRect'. if (shape.x <= point[0] && point[0] <= shape.x + shape.width && shape.y <= point[1] && point[1] <= shape.y + shape.height ) { targetInfo = {node: node, offsetX: point[0], offsetY: point[1]}; } else { return false; // Suppress visit subtree. } } }, this); return targetInfo; } }); /** * @inner */ function createStorage() { return {nodeGroup: [], background: [], content: []}; } /** * @inner * @return Return undefined means do not travel further. */ function renderNode( seriesModel, thisStorage, oldStorage, reRoot, lastsForAnimation, willInvisibleEls, thisNode, oldNode, parentGroup, depth ) { // Whether under viewRoot. if (!thisNode) { // Deleting nodes will be performed finally. This method just find // element from old storage, or create new element, set them to new // storage, and set styles. return; } var thisLayout = thisNode.getLayout(); if (!thisLayout || !thisLayout.isInView) { return; } var thisWidth = thisLayout.width; var thisHeight = thisLayout.height; var thisInvisible = thisLayout.invisible; var thisRawIndex = thisNode.getRawIndex(); var oldRawIndex = oldNode && oldNode.getRawIndex(); // Node group var group = giveGraphic('nodeGroup', Group); if (!group) { return; } parentGroup.add(group); // x,y are not set when el is above view root. group.attr('position', [thisLayout.x || 0, thisLayout.y || 0]); group.__tmNodeWidth = thisWidth; group.__tmNodeHeight = thisHeight; if (thisLayout.isAboveViewRoot) { return group; } // Background var bg = giveGraphic('background', Rect, depth, Z_BG); if (bg) { bg.setShape({x: 0, y: 0, width: thisWidth, height: thisHeight}); updateStyle(bg, function () { bg.setStyle('fill', thisNode.getVisual('borderColor', true)); }); group.add(bg); } var thisViewChildren = thisNode.viewChildren; // No children, render content. if (!thisViewChildren || !thisViewChildren.length) { var content = giveGraphic('content', Rect, depth, Z_CONTENT); content && renderContent(group); } return group; // ---------------------------- // | Procedures in renderNode | // ---------------------------- function renderContent(group) { // For tooltip. content.dataIndex = thisNode.dataIndex; content.seriesIndex = seriesModel.seriesIndex; var borderWidth = thisLayout.borderWidth; var contentWidth = Math.max(thisWidth - 2 * borderWidth, 0); var contentHeight = Math.max(thisHeight - 2 * borderWidth, 0); content.culling = true; content.setShape({ x: borderWidth, y: borderWidth, width: contentWidth, height: contentHeight }); var visualColor = thisNode.getVisual('color', true); updateStyle(content, function () { var normalStyle = {fill: visualColor}; var emphasisStyle = thisNode.getModel('itemStyle.emphasis').getItemStyle(); prepareText(normalStyle, emphasisStyle, visualColor, contentWidth, contentHeight); content.setStyle(normalStyle); graphic.setHoverStyle(content, emphasisStyle); }); group.add(content); } function updateStyle(element, cb) { if (!thisInvisible) { // If invisible, do not set visual, otherwise the element will // change immediately before animation. We think it is OK to // remain its origin color when moving out of the view window. cb(); if (!element.__tmWillVisible) { element.invisible = false; } } else { // Delay invisible setting utill animation finished, // avoid element vanish suddenly before animation. !element.invisible && willInvisibleEls.push(element); } } function prepareText(normalStyle, emphasisStyle, visualColor, contentWidth, contentHeight) { var nodeModel = thisNode.getModel(); var text = nodeModel.get('name'); if (thisLayout.isLeafRoot) { var iconChar = seriesModel.get('drillDownIcon', true); text = iconChar ? iconChar + ' ' + text : text; } setText( text, normalStyle, nodeModel, PATH_LABEL_NORMAL, visualColor, contentWidth, contentHeight ); setText( text, emphasisStyle, nodeModel, PATH_LABEL_EMPHASIS, visualColor, contentWidth, contentHeight ); } function setText(text, style, nodeModel, labelPath, visualColor, contentWidth, contentHeight) { var labelModel = nodeModel.getModel(labelPath); var labelTextStyleModel = labelModel.getModel('textStyle'); graphic.setText(style, labelModel, visualColor); // text.align and text.baseline is not included by graphic.setText, // because in most cases the two attributes are not exposed to user, // except in treemap. style.textAlign = labelTextStyleModel.get('align'); style.textVerticalAlign = labelTextStyleModel.get('baseline'); var textRect = labelTextStyleModel.getTextRect(text); if (!labelModel.getShallow('show') || textRect.height > contentHeight) { style.text = ''; } else if (textRect.width > contentWidth) { style.text = labelTextStyleModel.get('ellipsis') ? labelTextStyleModel.truncateText( text, contentWidth, null, {minChar: 2} ) : ''; } else { style.text = text; } } function giveGraphic(storageName, Ctor, depth, z) { var element = oldRawIndex != null && oldStorage[storageName][oldRawIndex]; var lasts = lastsForAnimation[storageName]; if (element) { // Remove from oldStorage oldStorage[storageName][oldRawIndex] = null; prepareAnimationWhenHasOld(lasts, element, storageName); } // If invisible and no old element, do not create new element (for optimizing). else if (!thisInvisible) { element = new Ctor({z: calculateZ(depth, z)}); element.__tmDepth = depth; element.__tmStorageName = storageName; prepareAnimationWhenNoOld(lasts, element, storageName); } // Set to thisStorage return (thisStorage[storageName][thisRawIndex] = element); } function prepareAnimationWhenHasOld(lasts, element, storageName) { var lastCfg = lasts[thisRawIndex] = {}; lastCfg.old = storageName === 'nodeGroup' ? element.position.slice() : zrUtil.extend({}, element.shape); } // If a element is new, we need to find the animation start point carefully, // otherwise it will looks strange when 'zoomToNode'. function prepareAnimationWhenNoOld(lasts, element, storageName) { var lastCfg = lasts[thisRawIndex] = {}; var parentNode = thisNode.parentNode; if (parentNode && (!reRoot || reRoot.direction === 'drillDown')) { var parentOldX = 0; var parentOldY = 0; // New nodes appear from right-bottom corner in 'zoomToNode' animation. // For convenience, get old bounding rect from background. var parentOldBg = lastsForAnimation.background[parentNode.getRawIndex()]; if (!reRoot && parentOldBg && parentOldBg.old) { parentOldX = parentOldBg.old.width; parentOldY = parentOldBg.old.height; } // When no parent old shape found, its parent is new too, // so we can just use {x:0, y:0}. lastCfg.old = storageName === 'nodeGroup' ? [0, parentOldY] : {x: parentOldX, y: parentOldY, width: 0, height: 0}; } // Fade in, user can be aware that these nodes are new. lastCfg.fadein = storageName !== 'nodeGroup'; } } // We can not set all backgroud with the same z, Because the behaviour of // drill down and roll up differ background creation sequence from tree // hierarchy sequence, which cause that lowser background element overlap // upper ones. So we calculate z based on depth. // Moreover, we try to shrink down z interval to [0, 1] to avoid that // treemap with large z overlaps other components. function calculateZ(depth, zInLevel) { var zb = depth * Z_BASE + zInLevel; return (zb - 1) / zb; } /***/ }, /* 190 */ /***/ function(module, exports, __webpack_require__) { var graphic = __webpack_require__(43); var layout = __webpack_require__(21); var zrUtil = __webpack_require__(4); var helper = __webpack_require__(188); var TEXT_PADDING = 8; var ITEM_GAP = 8; var ARRAY_LENGTH = 5; function Breadcrumb(containerGroup) { /** * @private * @type {module:zrender/container/Group} */ this.group = new graphic.Group(); containerGroup.add(this.group); } Breadcrumb.prototype = { constructor: Breadcrumb, render: function (seriesModel, api, targetNode, onSelect) { var model = seriesModel.getModel('breadcrumb'); var thisGroup = this.group; thisGroup.removeAll(); if (!model.get('show') || !targetNode) { return; } var normalStyleModel = model.getModel('itemStyle.normal'); // var emphasisStyleModel = model.getModel('itemStyle.emphasis'); var textStyleModel = normalStyleModel.getModel('textStyle'); var layoutParam = { pos: { left: model.get('left'), right: model.get('right'), top: model.get('top'), bottom: model.get('bottom') }, box: { width: api.getWidth(), height: api.getHeight() }, emptyItemWidth: model.get('emptyItemWidth'), totalWidth: 0, renderList: [] }; this._prepare(targetNode, layoutParam, textStyleModel); this._renderContent(seriesModel, layoutParam, normalStyleModel, textStyleModel, onSelect); layout.positionElement(thisGroup, layoutParam.pos, layoutParam.box); }, /** * Prepare render list and total width * @private */ _prepare: function (targetNode, layoutParam, textStyleModel) { for (var node = targetNode; node; node = node.parentNode) { var text = node.getModel().get('name'); var textRect = textStyleModel.getTextRect(text); var itemWidth = Math.max( textRect.width + TEXT_PADDING * 2, layoutParam.emptyItemWidth ); layoutParam.totalWidth += itemWidth + ITEM_GAP; layoutParam.renderList.push({node: node, text: text, width: itemWidth}); } }, /** * @private */ _renderContent: function ( seriesModel, layoutParam, normalStyleModel, textStyleModel, onSelect ) { // Start rendering. var lastX = 0; var emptyItemWidth = layoutParam.emptyItemWidth; var height = seriesModel.get('breadcrumb.height'); var availableSize = layout.getAvailableSize(layoutParam.pos, layoutParam.box); var totalWidth = layoutParam.totalWidth; var renderList = layoutParam.renderList; for (var i = renderList.length - 1; i >= 0; i--) { var item = renderList[i]; var itemNode = item.node; var itemWidth = item.width; var text = item.text; // Hdie text and shorten width if necessary. if (totalWidth > availableSize.width) { totalWidth -= itemWidth - emptyItemWidth; itemWidth = emptyItemWidth; text = ''; } var el = new graphic.Polygon({ shape: { points: makeItemPoints( lastX, 0, itemWidth, height, i === renderList.length - 1, i === 0 ) }, style: zrUtil.defaults( normalStyleModel.getItemStyle(), { lineJoin: 'bevel', text: text, textFill: textStyleModel.getTextColor(), textFont: textStyleModel.getFont() } ), z: 10, onclick: zrUtil.curry(onSelect, itemNode) }); this.group.add(el); packEventData(el, seriesModel, itemNode); lastX += itemWidth + ITEM_GAP; } }, /** * @override */ remove: function () { this.group.removeAll(); } }; function makeItemPoints(x, y, itemWidth, itemHeight, head, tail) { var points = [ [head ? x : x - ARRAY_LENGTH, y], [x + itemWidth, y], [x + itemWidth, y + itemHeight], [head ? x : x - ARRAY_LENGTH, y + itemHeight] ]; !tail && points.splice(2, 0, [x + itemWidth + ARRAY_LENGTH, y + itemHeight / 2]); !head && points.push([x, y + itemHeight / 2]); return points; } // Package custom mouse event. function packEventData(el, seriesModel, itemNode) { el.eventData = { componentType: 'series', componentSubType: 'treemap', seriesIndex: seriesModel.componentIndex, seriesName: seriesModel.name, seriesType: 'treemap', selfType: 'breadcrumb', // Distinguish with click event on treemap node. nodeData: { dataIndex: itemNode && itemNode.dataIndex, name: itemNode && itemNode.name }, treePathInfo: itemNode && helper.wrapTreePathInfo(itemNode, seriesModel) }; } module.exports = Breadcrumb; /***/ }, /* 191 */ /***/ function(module, exports, __webpack_require__) { var zrUtil = __webpack_require__(4); /** * @param {number} [time=500] Time in ms * @param {string} [easing='linear'] * @param {number} [delay=0] * @param {Function} [callback] * * @example * // Animate position * animation * .createWrap() * .add(el1, {position: [10, 10]}) * .add(el2, {shape: {width: 500}, style: {fill: 'red'}}, 400) * .done(function () { // done }) * .start('cubicOut'); */ function createWrap() { var storage = []; var elExistsMap = {}; var doneCallback; return { /** * Caution: a el can only be added once, otherwise 'done' * might not be called. This method checks this (by el.id), * suppresses adding and returns false when existing el found. * * @param {modele:zrender/Element} el * @param {Object} target * @param {number} [time=500] * @param {number} [delay=0] * @param {string} [easing='linear'] * @return {boolean} Whether adding succeeded. * * @example * add(el, target, time, delay, easing); * add(el, target, time, easing); * add(el, target, time); * add(el, target); */ add: function (el, target, time, delay, easing) { if (zrUtil.isString(delay)) { easing = delay; delay = 0; } if (elExistsMap[el.id]) { return false; } elExistsMap[el.id] = 1; storage.push( {el: el, target: target, time: time, delay: delay, easing: easing} ); return true; }, /** * Only execute when animation finished. Will not execute when any * of 'stop' or 'stopAnimation' called. * * @param {Function} callback */ done: function (callback) { doneCallback = callback; return this; }, /** * Will stop exist animation firstly. */ start: function () { var count = storage.length; for (var i = 0, len = storage.length; i < len; i++) { var item = storage[i]; item.el.animateTo(item.target, item.time, item.delay, item.easing, done); } return this; function done() { count--; if (!count) { storage.length = 0; elExistsMap = {}; doneCallback && doneCallback(); } } } }; } module.exports = {createWrap: createWrap}; /***/ }, /* 192 */ /***/ function(module, exports, __webpack_require__) { /** * @file Treemap action */ var echarts = __webpack_require__(1); var helper = __webpack_require__(188); var noop = function () {}; var actionTypes = [ 'treemapZoomToNode', 'treemapRender', 'treemapMove' ]; for (var i = 0; i < actionTypes.length; i++) { echarts.registerAction({type: actionTypes[i], update: 'updateView'}, noop); } echarts.registerAction( {type: 'treemapRootToNode', update: 'updateView'}, function (payload, ecModel) { ecModel.eachComponent( {mainType: 'series', subType: 'treemap', query: payload}, handleRootToNode ); function handleRootToNode(model, index) { var targetInfo = helper.retrieveTargetInfo(payload, model); if (targetInfo) { var originViewRoot = model.getViewRoot(); if (originViewRoot) { payload.direction = helper.aboveViewRoot(originViewRoot, targetInfo.node) ? 'rollUp' : 'drillDown'; } model.resetViewRoot(targetInfo.node); } } } ); /***/ }, /* 193 */ /***/ function(module, exports, __webpack_require__) { var VisualMapping = __webpack_require__(194); var zrColor = __webpack_require__(39); var zrUtil = __webpack_require__(4); var isArray = zrUtil.isArray; var ITEM_STYLE_NORMAL = 'itemStyle.normal'; module.exports = function (ecModel, api, payload) { var condition = {mainType: 'series', subType: 'treemap', query: payload}; ecModel.eachComponent(condition, function (seriesModel) { var tree = seriesModel.getData().tree; var root = tree.root; var seriesItemStyleModel = seriesModel.getModel(ITEM_STYLE_NORMAL); if (root.isRemoved()) { return; } var levelItemStyles = zrUtil.map(tree.levelModels, function (levelModel) { return levelModel ? levelModel.get(ITEM_STYLE_NORMAL) : null; }); travelTree( root, // Visual should calculate from tree root but not view root. {}, levelItemStyles, seriesItemStyleModel, seriesModel.getViewRoot().getAncestors(), seriesModel ); }); }; function travelTree( node, designatedVisual, levelItemStyles, seriesItemStyleModel, viewRootAncestors, seriesModel ) { var nodeModel = node.getModel(); var nodeLayout = node.getLayout(); // Optimize if (!nodeLayout || nodeLayout.invisible || !nodeLayout.isInView) { return; } var nodeItemStyleModel = node.getModel(ITEM_STYLE_NORMAL); var levelItemStyle = levelItemStyles[node.depth]; var visuals = buildVisuals( nodeItemStyleModel, designatedVisual, levelItemStyle, seriesItemStyleModel ); // calculate border color var borderColor = nodeItemStyleModel.get('borderColor'); var borderColorSaturation = nodeItemStyleModel.get('borderColorSaturation'); var thisNodeColor; if (borderColorSaturation != null) { // For performance, do not always execute 'calculateColor'. thisNodeColor = calculateColor(visuals, node); borderColor = calculateBorderColor(borderColorSaturation, thisNodeColor); } node.setVisual('borderColor', borderColor); var viewChildren = node.viewChildren; if (!viewChildren || !viewChildren.length) { thisNodeColor = calculateColor(visuals, node); // Apply visual to this node. node.setVisual('color', thisNodeColor); } else { var mapping = buildVisualMapping( node, nodeModel, nodeLayout, nodeItemStyleModel, visuals, viewChildren ); // Designate visual to children. zrUtil.each(viewChildren, function (child, index) { // If higher than viewRoot, only ancestors of viewRoot is needed to visit. if (child.depth >= viewRootAncestors.length || child === viewRootAncestors[child.depth] ) { var childVisual = mapVisual( nodeModel, visuals, child, index, mapping, seriesModel ); travelTree( child, childVisual, levelItemStyles, seriesItemStyleModel, viewRootAncestors, seriesModel ); } }); } } function buildVisuals( nodeItemStyleModel, designatedVisual, levelItemStyle, seriesItemStyleModel ) { var visuals = zrUtil.extend({}, designatedVisual); zrUtil.each(['color', 'colorAlpha', 'colorSaturation'], function (visualName) { // Priority: thisNode > thisLevel > parentNodeDesignated > seriesModel var val = nodeItemStyleModel.get(visualName, true); // Ignore parent val == null && levelItemStyle && (val = levelItemStyle[visualName]); val == null && (val = designatedVisual[visualName]); val == null && (val = seriesItemStyleModel.get(visualName)); val != null && (visuals[visualName] = val); }); return visuals; } function calculateColor(visuals) { var color = getValueVisualDefine(visuals, 'color'); if (color) { var colorAlpha = getValueVisualDefine(visuals, 'colorAlpha'); var colorSaturation = getValueVisualDefine(visuals, 'colorSaturation'); if (colorSaturation) { color = zrColor.modifyHSL(color, null, null, colorSaturation); } if (colorAlpha) { color = zrColor.modifyAlpha(color, colorAlpha); } return color; } } function calculateBorderColor(borderColorSaturation, thisNodeColor) { return thisNodeColor != null ? zrColor.modifyHSL(thisNodeColor, null, null, borderColorSaturation) : null; } function getValueVisualDefine(visuals, name) { var value = visuals[name]; if (value != null && value !== 'none') { return value; } } function buildVisualMapping( node, nodeModel, nodeLayout, nodeItemStyleModel, visuals, viewChildren ) { if (!viewChildren || !viewChildren.length) { return; } var rangeVisual = getRangeVisual(nodeModel, 'color') || ( visuals.color != null && visuals.color !== 'none' && ( getRangeVisual(nodeModel, 'colorAlpha') || getRangeVisual(nodeModel, 'colorSaturation') ) ); if (!rangeVisual) { return; } var visualMin = nodeModel.get('visualMin'); var visualMax = nodeModel.get('visualMax'); var dataExtent = nodeLayout.dataExtent.slice(); visualMin != null && visualMin < dataExtent[0] && (dataExtent[0] = visualMin); visualMax != null && visualMax > dataExtent[1] && (dataExtent[1] = visualMax); var colorMappingBy = nodeModel.get('colorMappingBy'); var opt = { type: rangeVisual.name, dataExtent: dataExtent, visual: rangeVisual.range }; if (opt.type === 'color' && (colorMappingBy === 'index' || colorMappingBy === 'id') ) { opt.mappingMethod = 'category'; opt.loop = true; // categories is ordinal, so do not set opt.categories. } else { opt.mappingMethod = 'linear'; } var mapping = new VisualMapping(opt); mapping.__drColorMappingBy = colorMappingBy; return mapping; } // Notice: If we dont have the attribute 'colorRange', but only use // attribute 'color' to represent both concepts of 'colorRange' and 'color', // (It means 'colorRange' when 'color' is Array, means 'color' when not array), // this problem will be encountered: // If a level-1 node dont have children, and its siblings has children, // and colorRange is set on level-1, then the node can not be colored. // So we separate 'colorRange' and 'color' to different attributes. function getRangeVisual(nodeModel, name) { // 'colorRange', 'colorARange', 'colorSRange'. // If not exsits on this node, fetch from levels and series. var range = nodeModel.get(name); return (isArray(range) && range.length) ? {name: name, range: range} : null; } function mapVisual(nodeModel, visuals, child, index, mapping, seriesModel) { var childVisuals = zrUtil.extend({}, visuals); if (mapping) { var mappingType = mapping.type; var colorMappingBy = mappingType === 'color' && mapping.__drColorMappingBy; var value = colorMappingBy === 'index' ? index : colorMappingBy === 'id' ? seriesModel.mapIdToIndex(child.getId()) : child.getValue(nodeModel.get('visualDimension')); childVisuals[mappingType] = mapping.mapValueToVisual(value); } return childVisuals; } /***/ }, /* 194 */ /***/ function(module, exports, __webpack_require__) { /** * @file Visual mapping. */ var zrUtil = __webpack_require__(4); var zrColor = __webpack_require__(39); var linearMap = __webpack_require__(7).linearMap; var each = zrUtil.each; var isObject = zrUtil.isObject; var CATEGORY_DEFAULT_VISUAL_INDEX = -1; /** * @param {Object} option * @param {string} [option.type] See visualHandlers. * @param {string} [option.mappingMethod] 'linear' or 'piecewise' or 'category' or 'fixed' * @param {Array.=} [option.dataExtent] [minExtent, maxExtent], * required when mappingMethod is 'linear' * @param {Array.=} [option.pieceList] [ * {value: someValue}, * {interval: [min1, max1], visual: {...}}, * {interval: [min2, max2]} * ], * required when mappingMethod is 'piecewise'. * Visual for only each piece can be specified. * @param {Array.=} [option.categories] ['cate1', 'cate2'] * required when mappingMethod is 'category'. * If no option.categories, categories is set * as [0, 1, 2, ...]. * @param {boolean} [option.loop=false] Whether loop mapping when mappingMethod is 'category'. * @param {(Array|Object|*)} [option.visual] Visual data. * when mappingMethod is 'category', * visual data can be array or object * (like: {cate1: '#222', none: '#fff'}) * or primary types (which represents * defualt category visual), otherwise visual * can be array or primary (which will be * normalized to array). * */ var VisualMapping = function (option) { var mappingMethod = option.mappingMethod; var visualType = option.type; /** * @readOnly * @type {Object} */ var thisOption = this.option = zrUtil.clone(option); /** * @readOnly * @type {string} */ this.type = visualType; /** * @readOnly * @type {string} */ this.mappingMethod = mappingMethod; /** * @private * @type {Function} */ this._normalizeData = normalizers[mappingMethod]; var visualHandler = visualHandlers[visualType]; /** * @public * @type {Function} */ this.applyVisual = visualHandler.applyVisual; /** * @public * @type {Function} */ this.getColorMapper = visualHandler.getColorMapper; /** * @private * @type {Function} */ this._doMap = visualHandler._doMap[mappingMethod]; if (mappingMethod === 'piecewise') { normalizeVisualRange(thisOption); preprocessForPiecewise(thisOption); } else if (mappingMethod === 'category') { thisOption.categories ? preprocessForSpecifiedCategory(thisOption) // categories is ordinal when thisOption.categories not specified, // which need no more preprocess except normalize visual. : normalizeVisualRange(thisOption, true); } else { // mappingMethod === 'linear' or 'fixed' zrUtil.assert(mappingMethod !== 'linear' || thisOption.dataExtent); normalizeVisualRange(thisOption); } }; VisualMapping.prototype = { constructor: VisualMapping, mapValueToVisual: function (value) { var normalized = this._normalizeData(value); return this._doMap(normalized, value); }, getNormalizer: function () { return zrUtil.bind(this._normalizeData, this); } }; var visualHandlers = VisualMapping.visualHandlers = { color: { applyVisual: makeApplyVisual('color'), /** * Create a mapper function * @return {Function} */ getColorMapper: function () { var thisOption = this.option; var parsedVisual = zrUtil.map(thisOption.visual, zrColor.parse); return zrUtil.bind( thisOption.mappingMethod === 'category' ? function (value, isNormalized) { !isNormalized && (value = this._normalizeData(value)); return doMapCategory.call(this, value); } : function (value, isNormalized, out) { // If output rgb array // which will be much faster and useful in pixel manipulation var returnRGBArray = !!out; !isNormalized && (value = this._normalizeData(value)); out = zrColor.fastMapToColor(value, parsedVisual, out); return returnRGBArray ? out : zrUtil.stringify(out, 'rgba'); }, this ); }, _doMap: { linear: function (normalized) { return zrColor.mapToColor(normalized, this.option.visual); }, category: doMapCategory, piecewise: function (normalized, value) { var result = getSpecifiedVisual.call(this, value); if (result == null) { result = zrColor.mapToColor(normalized, this.option.visual); } return result; }, fixed: doMapFixed } }, colorHue: makePartialColorVisualHandler(function (color, value) { return zrColor.modifyHSL(color, value); }), colorSaturation: makePartialColorVisualHandler(function (color, value) { return zrColor.modifyHSL(color, null, value); }), colorLightness: makePartialColorVisualHandler(function (color, value) { return zrColor.modifyHSL(color, null, null, value); }), colorAlpha: makePartialColorVisualHandler(function (color, value) { return zrColor.modifyAlpha(color, value); }), opacity: { applyVisual: makeApplyVisual('opacity'), _doMap: makeDoMap([0, 1]) }, symbol: { applyVisual: function (value, getter, setter) { var symbolCfg = this.mapValueToVisual(value); if (zrUtil.isString(symbolCfg)) { setter('symbol', symbolCfg); } else if (isObject(symbolCfg)) { for (var name in symbolCfg) { if (symbolCfg.hasOwnProperty(name)) { setter(name, symbolCfg[name]); } } } }, _doMap: { linear: doMapToArray, category: doMapCategory, piecewise: function (normalized, value) { var result = getSpecifiedVisual.call(this, value); if (result == null) { result = doMapToArray.call(this, normalized); } return result; }, fixed: doMapFixed } }, symbolSize: { applyVisual: makeApplyVisual('symbolSize'), _doMap: makeDoMap([0, 1]) } }; function preprocessForPiecewise(thisOption) { var pieceList = thisOption.pieceList; thisOption.hasSpecialVisual = false; zrUtil.each(pieceList, function (piece, index) { piece.originIndex = index; // piece.visual is "result visual value" but not // a visual range, so it does not need to be normalized. if (piece.visual != null) { thisOption.hasSpecialVisual = true; } }); } function preprocessForSpecifiedCategory(thisOption) { // Hash categories. var categories = thisOption.categories; var visual = thisOption.visual; var categoryMap = thisOption.categoryMap = {}; each(categories, function (cate, index) { categoryMap[cate] = index; }); // Process visual map input. if (!zrUtil.isArray(visual)) { var visualArr = []; if (zrUtil.isObject(visual)) { each(visual, function (v, cate) { var index = categoryMap[cate]; visualArr[index != null ? index : CATEGORY_DEFAULT_VISUAL_INDEX] = v; }); } else { // Is primary type, represents default visual. visualArr[CATEGORY_DEFAULT_VISUAL_INDEX] = visual; } visual = thisOption.visual = visualArr; } // Remove categories that has no visual, // then we can mapping them to CATEGORY_DEFAULT_VISUAL_INDEX. for (var i = categories.length - 1; i >= 0; i--) { if (visual[i] == null) { delete categoryMap[categories[i]]; categories.pop(); } } } function normalizeVisualRange(thisOption, isCategory) { var visual = thisOption.visual; var visualArr = []; if (zrUtil.isObject(visual)) { each(visual, function (v) { visualArr.push(v); }); } else if (visual != null) { visualArr.push(visual); } var doNotNeedPair = {color: 1, symbol: 1}; if (!isCategory && visualArr.length === 1 && !doNotNeedPair.hasOwnProperty(thisOption.type) ) { // Do not care visualArr.length === 0, which is illegal. visualArr[1] = visualArr[0]; } thisOption.visual = visualArr; } function makePartialColorVisualHandler(applyValue) { return { applyVisual: function (value, getter, setter) { value = this.mapValueToVisual(value); // Must not be array value setter('color', applyValue(getter('color'), value)); }, _doMap: makeDoMap([0, 1]) }; } function doMapToArray(normalized) { var visual = this.option.visual; return visual[ Math.round(linearMap(normalized, [0, 1], [0, visual.length - 1], true)) ] || {}; } function makeApplyVisual(visualType) { return function (value, getter, setter) { setter(visualType, this.mapValueToVisual(value)); }; } function doMapCategory(normalized) { var visual = this.option.visual; return visual[ (this.option.loop && normalized !== CATEGORY_DEFAULT_VISUAL_INDEX) ? normalized % visual.length : normalized ]; } function doMapFixed() { return this.option.visual[0]; } function makeDoMap(sourceExtent) { return { linear: function (normalized) { return linearMap(normalized, sourceExtent, this.option.visual, true); }, category: doMapCategory, piecewise: function (normalized, value) { var result = getSpecifiedVisual.call(this, value); if (result == null) { result = linearMap(normalized, sourceExtent, this.option.visual, true); } return result; }, fixed: doMapFixed }; } function getSpecifiedVisual(value) { var thisOption = this.option; var pieceList = thisOption.pieceList; if (thisOption.hasSpecialVisual) { var pieceIndex = VisualMapping.findPieceIndex(value, pieceList); var piece = pieceList[pieceIndex]; if (piece && piece.visual) { return piece.visual[this.type]; } } } /** * Normalizers by mapping methods. */ var normalizers = { linear: function (value) { return linearMap(value, this.option.dataExtent, [0, 1], true); }, piecewise: function (value) { var pieceList = this.option.pieceList; var pieceIndex = VisualMapping.findPieceIndex(value, pieceList, true); if (pieceIndex != null) { return linearMap(pieceIndex, [0, pieceList.length - 1], [0, 1], true); } }, category: function (value) { var index = this.option.categories ? this.option.categoryMap[value] : value; // ordinal return index == null ? CATEGORY_DEFAULT_VISUAL_INDEX : index; }, fixed: zrUtil.noop }; /** * List available visual types. * * @public * @return {Array.} */ VisualMapping.listVisualTypes = function () { var visualTypes = []; zrUtil.each(visualHandlers, function (handler, key) { visualTypes.push(key); }); return visualTypes; }; /** * @public */ VisualMapping.addVisualHandler = function (name, handler) { visualHandlers[name] = handler; }; /** * @public */ VisualMapping.isValidType = function (visualType) { return visualHandlers.hasOwnProperty(visualType); }; /** * Convinent method. * Visual can be Object or Array or primary type. * * @public */ VisualMapping.eachVisual = function (visual, callback, context) { if (zrUtil.isObject(visual)) { zrUtil.each(visual, callback, context); } else { callback.call(context, visual); } }; VisualMapping.mapVisual = function (visual, callback, context) { var isPrimary; var newVisual = zrUtil.isArray(visual) ? [] : zrUtil.isObject(visual) ? {} : (isPrimary = true, null); VisualMapping.eachVisual(visual, function (v, key) { var newVal = callback.call(context, v, key); isPrimary ? (newVisual = newVal) : (newVisual[key] = newVal); }); return newVisual; }; /** * @public * @param {Object} obj * @return {Oject} new object containers visual values. * If no visuals, return null. */ VisualMapping.retrieveVisuals = function (obj) { var ret = {}; var hasVisual; obj && each(visualHandlers, function (h, visualType) { if (obj.hasOwnProperty(visualType)) { ret[visualType] = obj[visualType]; hasVisual = true; } }); return hasVisual ? ret : null; }; /** * Give order to visual types, considering colorSaturation, colorAlpha depends on color. * * @public * @param {(Object|Array)} visualTypes If Object, like: {color: ..., colorSaturation: ...} * IF Array, like: ['color', 'symbol', 'colorSaturation'] * @return {Array.} Sorted visual types. */ VisualMapping.prepareVisualTypes = function (visualTypes) { if (isObject(visualTypes)) { var types = []; each(visualTypes, function (item, type) { types.push(type); }); visualTypes = types; } else if (zrUtil.isArray(visualTypes)) { visualTypes = visualTypes.slice(); } else { return []; } visualTypes.sort(function (type1, type2) { // color should be front of colorSaturation, colorAlpha, ... // symbol and symbolSize do not matter. return (type2 === 'color' && type1 !== 'color' && type1.indexOf('color') === 0) ? 1 : -1; }); return visualTypes; }; /** * 'color', 'colorSaturation', 'colorAlpha', ... are depends on 'color'. * Other visuals are only depends on themself. * * @public * @param {string} visualType1 * @param {string} visualType2 * @return {boolean} */ VisualMapping.dependsOn = function (visualType1, visualType2) { return visualType2 === 'color' ? !!(visualType1 && visualType1.indexOf(visualType2) === 0) : visualType1 === visualType2; }; /** * @param {number} value * @param {Array.} pieceList [{value: ..., interval: [min, max]}, ...] * Always from small to big. * @param {boolean} [findClosestWhenOutside=false] * @return {number} index */ VisualMapping.findPieceIndex = function (value, pieceList, findClosestWhenOutside) { var possibleI; var abs = Infinity; // value has the higher priority. for (var i = 0, len = pieceList.length; i < len; i++) { var pieceValue = pieceList[i].value; if (pieceValue != null) { if (pieceValue === value) { return i; } findClosestWhenOutside && updatePossible(pieceValue, i); } } for (var i = 0, len = pieceList.length; i < len; i++) { var piece = pieceList[i]; var interval = piece.interval; var close = piece.close; if (interval) { if (interval[0] === -Infinity) { if (littleThan(close[1], value, interval[1])) { return i; } } else if (interval[1] === Infinity) { if (littleThan(close[0], interval[0], value)) { return i; } } else if ( littleThan(close[0], interval[0], value) && littleThan(close[1], value, interval[1]) ) { return i; } findClosestWhenOutside && updatePossible(interval[0], i); findClosestWhenOutside && updatePossible(interval[1], i); } } if (findClosestWhenOutside) { return value === Infinity ? pieceList.length - 1 : value === -Infinity ? 0 : possibleI; } function updatePossible(val, index) { var newAbs = Math.abs(val - value); if (newAbs < abs) { abs = newAbs; possibleI = index; } } }; function littleThan(close, a, b) { return close ? a <= b : a < b; } module.exports = VisualMapping; /***/ }, /* 195 */ /***/ function(module, exports, __webpack_require__) { var zrUtil = __webpack_require__(4); var numberUtil = __webpack_require__(7); var layout = __webpack_require__(21); var helper = __webpack_require__(188); var BoundingRect = __webpack_require__(9); var helper = __webpack_require__(188); var mathMax = Math.max; var mathMin = Math.min; var parsePercent = numberUtil.parsePercent; var retrieveValue = zrUtil.retrieve; var each = zrUtil.each; /** * @public */ function update(ecModel, api, payload) { // Layout result in each node: // {x, y, width, height, area, borderWidth} var condition = {mainType: 'series', subType: 'treemap', query: payload}; ecModel.eachComponent(condition, function (seriesModel) { var ecWidth = api.getWidth(); var ecHeight = api.getHeight(); var seriesOption = seriesModel.option; var size = seriesOption.size || []; // Compatible with ec2. var containerWidth = parsePercent( retrieveValue(seriesOption.width, size[0]), ecWidth ); var containerHeight = parsePercent( retrieveValue(seriesOption.height, size[1]), ecHeight ); var layoutInfo = layout.getLayoutRect( seriesModel.getBoxLayoutParams(), { width: api.getWidth(), height: api.getHeight() } ); // Fetch payload info. var payloadType = payload && payload.type; var targetInfo = helper.retrieveTargetInfo(payload, seriesModel); var rootRect = (payloadType === 'treemapRender' || payloadType === 'treemapMove') ? payload.rootRect : null; var viewRoot = seriesModel.getViewRoot(); var viewAbovePath = helper.getPathToRoot(viewRoot); if (payloadType !== 'treemapMove') { var rootSize = payloadType === 'treemapZoomToNode' ? estimateRootSize( seriesModel, targetInfo, viewRoot, containerWidth, containerHeight ) : rootRect ? [rootRect.width, rootRect.height] : [containerWidth, containerHeight]; var sort = seriesOption.sort; if (sort && sort !== 'asc' && sort !== 'desc') { sort = 'desc'; } var options = { squareRatio: seriesOption.squareRatio, sort: sort, leafDepth: seriesOption.leafDepth }; // layout should be cleared because using updateView but not update. viewRoot.hostTree.clearLayouts(); // TODO // optimize: if out of view clip, do not layout. // But take care that if do not render node out of view clip, // how to calculate start po var viewRootLayout = { x: 0, y: 0, width: rootSize[0], height: rootSize[1], area: rootSize[0] * rootSize[1] }; viewRoot.setLayout(viewRootLayout); squarify(viewRoot, options, false, 0); // Supplement layout. var viewRootLayout = viewRoot.getLayout(); each(viewAbovePath, function (node, index) { var childValue = (viewAbovePath[index + 1] || viewRoot).getValue(); node.setLayout(zrUtil.extend( {dataExtent: [childValue, childValue], borderWidth: 0}, viewRootLayout )); }); } var treeRoot = seriesModel.getData().tree.root; treeRoot.setLayout( calculateRootPosition(layoutInfo, rootRect, targetInfo), true ); seriesModel.setLayoutInfo(layoutInfo); // FIXME // 现在没有clip功能,暂时取ec高宽。 prunning( treeRoot, // Transform to base element coordinate system. new BoundingRect(-layoutInfo.x, -layoutInfo.y, ecWidth, ecHeight), viewAbovePath, viewRoot, 0 ); }); } /** * Layout treemap with squarify algorithm. * @see https://graphics.ethz.ch/teaching/scivis_common/Literature/squarifiedTreeMaps.pdf * @see https://github.com/mbostock/d3/blob/master/src/layout/treemap.js * * @protected * @param {module:echarts/data/Tree~TreeNode} node * @param {Object} options * @param {string} options.sort 'asc' or 'desc' * @param {number} options.squareRatio * @param {boolean} hideChildren * @param {number} depth */ function squarify(node, options, hideChildren, depth) { var width; var height; if (node.isRemoved()) { return; } var thisLayout = node.getLayout(); width = thisLayout.width; height = thisLayout.height; // Considering border and gap var itemStyleModel = node.getModel('itemStyle.normal'); var borderWidth = itemStyleModel.get('borderWidth'); var halfGapWidth = itemStyleModel.get('gapWidth') / 2; var layoutOffset = borderWidth - halfGapWidth; var nodeModel = node.getModel(); node.setLayout({borderWidth: borderWidth}, true); width = mathMax(width - 2 * layoutOffset, 0); height = mathMax(height - 2 * layoutOffset, 0); var totalArea = width * height; var viewChildren = initChildren( node, nodeModel, totalArea, options, hideChildren, depth ); if (!viewChildren.length) { return; } var rect = {x: layoutOffset, y: layoutOffset, width: width, height: height}; var rowFixedLength = mathMin(width, height); var best = Infinity; // the best row score so far var row = []; row.area = 0; for (var i = 0, len = viewChildren.length; i < len;) { var child = viewChildren[i]; row.push(child); row.area += child.getLayout().area; var score = worst(row, rowFixedLength, options.squareRatio); // continue with this orientation if (score <= best) { i++; best = score; } // abort, and try a different orientation else { row.area -= row.pop().getLayout().area; position(row, rowFixedLength, rect, halfGapWidth, false); rowFixedLength = mathMin(rect.width, rect.height); row.length = row.area = 0; best = Infinity; } } if (row.length) { position(row, rowFixedLength, rect, halfGapWidth, true); } if (!hideChildren) { var childrenVisibleMin = nodeModel.get('childrenVisibleMin'); if (childrenVisibleMin != null && totalArea < childrenVisibleMin) { hideChildren = true; } } for (var i = 0, len = viewChildren.length; i < len; i++) { squarify(viewChildren[i], options, hideChildren, depth + 1); } } /** * Set area to each child, and calculate data extent for visual coding. */ function initChildren(node, nodeModel, totalArea, options, hideChildren, depth) { var viewChildren = node.children || []; var orderBy = options.sort; orderBy !== 'asc' && orderBy !== 'desc' && (orderBy = null); var overLeafDepth = options.leafDepth != null && options.leafDepth <= depth; // leafDepth has higher priority. if (hideChildren && !overLeafDepth) { return (node.viewChildren = []); } // Sort children, order by desc. viewChildren = zrUtil.filter(viewChildren, function (child) { return !child.isRemoved(); }); sort(viewChildren, orderBy); var info = statistic(nodeModel, viewChildren, orderBy); if (info.sum === 0) { return (node.viewChildren = []); } info.sum = filterByThreshold(nodeModel, totalArea, info.sum, orderBy, viewChildren); if (info.sum === 0) { return (node.viewChildren = []); } // Set area to each child. for (var i = 0, len = viewChildren.length; i < len; i++) { var area = viewChildren[i].getValue() / info.sum * totalArea; // Do not use setLayout({...}, true), because it is needed to clear last layout. viewChildren[i].setLayout({area: area}); } if (overLeafDepth) { viewChildren.length && node.setLayout({isLeafRoot: true}, true); viewChildren.length = 0; } node.viewChildren = viewChildren; node.setLayout({dataExtent: info.dataExtent}, true); return viewChildren; } /** * Consider 'visibleMin'. Modify viewChildren and get new sum. */ function filterByThreshold(nodeModel, totalArea, sum, orderBy, orderedChildren) { // visibleMin is not supported yet when no option.sort. if (!orderBy) { return sum; } var visibleMin = nodeModel.get('visibleMin'); var len = orderedChildren.length; var deletePoint = len; // Always travel from little value to big value. for (var i = len - 1; i >= 0; i--) { var value = orderedChildren[ orderBy === 'asc' ? len - i - 1 : i ].getValue(); if (value / sum * totalArea < visibleMin) { deletePoint = i; sum -= value; } } orderBy === 'asc' ? orderedChildren.splice(0, len - deletePoint) : orderedChildren.splice(deletePoint, len - deletePoint); return sum; } /** * Sort */ function sort(viewChildren, orderBy) { if (orderBy) { viewChildren.sort(function (a, b) { return orderBy === 'asc' ? a.getValue() - b.getValue() : b.getValue() - a.getValue(); }); } return viewChildren; } /** * Statistic */ function statistic(nodeModel, children, orderBy) { // Calculate sum. var sum = 0; for (var i = 0, len = children.length; i < len; i++) { sum += children[i].getValue(); } // Statistic data extent for latter visual coding. // Notice: data extent should be calculate based on raw children // but not filtered view children, otherwise visual mapping will not // be stable when zoom (where children is filtered by visibleMin). var dimension = nodeModel.get('visualDimension'); var dataExtent; // The same as area dimension. if (!children || !children.length) { dataExtent = [NaN, NaN]; } else if (dimension === 'value' && orderBy) { dataExtent = [ children[children.length - 1].getValue(), children[0].getValue() ]; orderBy === 'asc' && dataExtent.reverse(); } // Other dimension. else { var dataExtent = [Infinity, -Infinity]; each(children, function (child) { var value = child.getValue(dimension); value < dataExtent[0] && (dataExtent[0] = value); value > dataExtent[1] && (dataExtent[1] = value); }); } return {sum: sum, dataExtent: dataExtent}; } /** * Computes the score for the specified row, * as the worst aspect ratio. */ function worst(row, rowFixedLength, ratio) { var areaMax = 0; var areaMin = Infinity; for (var i = 0, area, len = row.length; i < len; i++) { area = row[i].getLayout().area; if (area) { area < areaMin && (areaMin = area); area > areaMax && (areaMax = area); } } var squareArea = row.area * row.area; var f = rowFixedLength * rowFixedLength * ratio; return squareArea ? mathMax( (f * areaMax) / squareArea, squareArea / (f * areaMin) ) : Infinity; } /** * Positions the specified row of nodes. Modifies `rect`. */ function position(row, rowFixedLength, rect, halfGapWidth, flush) { // When rowFixedLength === rect.width, // it is horizontal subdivision, // rowFixedLength is the width of the subdivision, // rowOtherLength is the height of the subdivision, // and nodes will be positioned from left to right. // wh[idx0WhenH] means: when horizontal, // wh[idx0WhenH] => wh[0] => 'width'. // xy[idx1WhenH] => xy[1] => 'y'. var idx0WhenH = rowFixedLength === rect.width ? 0 : 1; var idx1WhenH = 1 - idx0WhenH; var xy = ['x', 'y']; var wh = ['width', 'height']; var last = rect[xy[idx0WhenH]]; var rowOtherLength = rowFixedLength ? row.area / rowFixedLength : 0; if (flush || rowOtherLength > rect[wh[idx1WhenH]]) { rowOtherLength = rect[wh[idx1WhenH]]; // over+underflow } for (var i = 0, rowLen = row.length; i < rowLen; i++) { var node = row[i]; var nodeLayout = {}; var step = rowOtherLength ? node.getLayout().area / rowOtherLength : 0; var wh1 = nodeLayout[wh[idx1WhenH]] = mathMax(rowOtherLength - 2 * halfGapWidth, 0); // We use Math.max/min to avoid negative width/height when considering gap width. var remain = rect[xy[idx0WhenH]] + rect[wh[idx0WhenH]] - last; var modWH = (i === rowLen - 1 || remain < step) ? remain : step; var wh0 = nodeLayout[wh[idx0WhenH]] = mathMax(modWH - 2 * halfGapWidth, 0); nodeLayout[xy[idx1WhenH]] = rect[xy[idx1WhenH]] + mathMin(halfGapWidth, wh1 / 2); nodeLayout[xy[idx0WhenH]] = last + mathMin(halfGapWidth, wh0 / 2); last += modWH; node.setLayout(nodeLayout, true); } rect[xy[idx1WhenH]] += rowOtherLength; rect[wh[idx1WhenH]] -= rowOtherLength; } // Return [containerWidth, containerHeight] as defualt. function estimateRootSize(seriesModel, targetInfo, viewRoot, containerWidth, containerHeight) { // If targetInfo.node exists, we zoom to the node, // so estimate whold width and heigth by target node. var currNode = (targetInfo || {}).node; var defaultSize = [containerWidth, containerHeight]; if (!currNode || currNode === viewRoot) { return defaultSize; } var parent; var viewArea = containerWidth * containerHeight; var area = viewArea * seriesModel.option.zoomToNodeRatio; while (parent = currNode.parentNode) { // jshint ignore:line var sum = 0; var siblings = parent.children; for (var i = 0, len = siblings.length; i < len; i++) { sum += siblings[i].getValue(); } var currNodeValue = currNode.getValue(); if (currNodeValue === 0) { return defaultSize; } area *= sum / currNodeValue; var borderWidth = parent.getModel('itemStyle.normal').get('borderWidth'); if (isFinite(borderWidth)) { // Considering border, suppose aspect ratio is 1. area += 4 * borderWidth * borderWidth + 4 * borderWidth * Math.pow(area, 0.5); } area > numberUtil.MAX_SAFE_INTEGER && (area = numberUtil.MAX_SAFE_INTEGER); currNode = parent; } area < viewArea && (area = viewArea); var scale = Math.pow(area / viewArea, 0.5); return [containerWidth * scale, containerHeight * scale]; } // Root postion base on coord of containerGroup function calculateRootPosition(layoutInfo, rootRect, targetInfo) { if (rootRect) { return {x: rootRect.x, y: rootRect.y}; } var defaultPosition = {x: 0, y: 0}; if (!targetInfo) { return defaultPosition; } // If targetInfo is fetched by 'retrieveTargetInfo', // old tree and new tree are the same tree, // so the node still exists and we can visit it. var targetNode = targetInfo.node; var layout = targetNode.getLayout(); if (!layout) { return defaultPosition; } // Transform coord from local to container. var targetCenter = [layout.width / 2, layout.height / 2]; var node = targetNode; while (node) { var nodeLayout = node.getLayout(); targetCenter[0] += nodeLayout.x; targetCenter[1] += nodeLayout.y; node = node.parentNode; } return { x: layoutInfo.width / 2 - targetCenter[0], y: layoutInfo.height / 2 - targetCenter[1] }; } // Mark nodes visible for prunning when visual coding and rendering. // Prunning depends on layout and root position, so we have to do it after layout. function prunning(node, clipRect, viewAbovePath, viewRoot, depth) { var nodeLayout = node.getLayout(); var nodeInViewAbovePath = viewAbovePath[depth]; var isAboveViewRoot = nodeInViewAbovePath && nodeInViewAbovePath === node; if ( (nodeInViewAbovePath && !isAboveViewRoot) || (depth === viewAbovePath.length && node !== viewRoot) ) { return; } node.setLayout({ // isInView means: viewRoot sub tree + viewAbovePath isInView: true, // invisible only means: outside view clip so that the node can not // see but still layout for animation preparation but not render. invisible: !isAboveViewRoot && !clipRect.intersect(nodeLayout), isAboveViewRoot: isAboveViewRoot }, true); // Transform to child coordinate. var childClipRect = new BoundingRect( clipRect.x - nodeLayout.x, clipRect.y - nodeLayout.y, clipRect.width, clipRect.height ); each(node.viewChildren || [], function (child) { prunning(child, childClipRect, viewAbovePath, viewRoot, depth + 1); }); } module.exports = update; /***/ }, /* 196 */ /***/ function(module, exports, __webpack_require__) { var echarts = __webpack_require__(1); var zrUtil = __webpack_require__(4); __webpack_require__(197); __webpack_require__(200); __webpack_require__(205); echarts.registerProcessor(__webpack_require__(206)); echarts.registerVisual(zrUtil.curry( __webpack_require__(110), 'graph', 'circle', null )); echarts.registerVisual(__webpack_require__(207)); echarts.registerVisual(__webpack_require__(208)); echarts.registerLayout(__webpack_require__(209)); echarts.registerLayout(__webpack_require__(212)); echarts.registerLayout(__webpack_require__(214)); // Graph view coordinate system echarts.registerCoordinateSystem('graphView', { create: __webpack_require__(216) }); /***/ }, /* 197 */ /***/ function(module, exports, __webpack_require__) { 'use strict'; var List = __webpack_require__(98); var zrUtil = __webpack_require__(4); var modelUtil = __webpack_require__(5); var Model = __webpack_require__(12); var createGraphFromNodeEdge = __webpack_require__(198); var GraphSeries = __webpack_require__(1).extendSeriesModel({ type: 'series.graph', init: function (option) { GraphSeries.superApply(this, 'init', arguments); // Provide data for legend select this.legendDataProvider = function () { return this._categoriesData; }; this.fillDataTextStyle(option.edges || option.links); this._updateCategoriesData(); }, mergeOption: function (option) { GraphSeries.superApply(this, 'mergeOption', arguments); this.fillDataTextStyle(option.edges || option.links); this._updateCategoriesData(); }, mergeDefaultAndTheme: function (option) { GraphSeries.superApply(this, 'mergeDefaultAndTheme', arguments); modelUtil.defaultEmphasis(option.edgeLabel, modelUtil.LABEL_OPTIONS); }, getInitialData: function (option, ecModel) { var edges = option.edges || option.links || []; var nodes = option.data || option.nodes || []; var self = this; if (nodes && edges) { return createGraphFromNodeEdge(nodes, edges, this, true, beforeLink).data; } function beforeLink(nodeData, edgeData) { // Overwrite nodeData.getItemModel to nodeData.wrapMethod('getItemModel', function (model) { var categoriesModels = self._categoriesModels; var categoryIdx = model.getShallow('category'); var categoryModel = categoriesModels[categoryIdx]; if (categoryModel) { categoryModel.parentModel = model.parentModel; model.parentModel = categoryModel; } return model; }); var edgeLabelModel = self.getModel('edgeLabel'); var wrappedGetEdgeModel = function (path, parentModel) { var pathArr = (path || '').split('.'); if (pathArr[0] === 'label') { parentModel = parentModel || edgeLabelModel.getModel(pathArr.slice(1)); } var model = Model.prototype.getModel.call(this, pathArr, parentModel); model.getModel = wrappedGetEdgeModel; return model; }; edgeData.wrapMethod('getItemModel', function (model) { // FIXME Wrap get method ? model.getModel = wrappedGetEdgeModel; return model; }); } }, /** * @return {module:echarts/data/Graph} */ getGraph: function () { return this.getData().graph; }, /** * @return {module:echarts/data/List} */ getEdgeData: function () { return this.getGraph().edgeData; }, /** * @return {module:echarts/data/List} */ getCategoriesData: function () { return this._categoriesData; }, /** * @override */ formatTooltip: function (dataIndex, multipleSeries, dataType) { if (dataType === 'edge') { var nodeData = this.getData(); var params = this.getDataParams(dataIndex, dataType); var edge = nodeData.graph.getEdgeByIndex(dataIndex); var sourceName = nodeData.getName(edge.node1.dataIndex); var targetName = nodeData.getName(edge.node2.dataIndex); var html = sourceName + ' > ' + targetName; if (params.value) { html += ' : ' + params.value; } return html; } else { // dataType === 'node' or empty return GraphSeries.superApply(this, 'formatTooltip', arguments); } }, _updateCategoriesData: function () { var categories = zrUtil.map(this.option.categories || [], function (category) { // Data must has value return category.value != null ? category : zrUtil.extend({ value: 0 }, category); }); var categoriesData = new List(['value'], this); categoriesData.initData(categories); this._categoriesData = categoriesData; this._categoriesModels = categoriesData.mapArray(function (idx) { return categoriesData.getItemModel(idx, true); }); }, setZoom: function (zoom) { this.option.zoom = zoom; }, setCenter: function (center) { this.option.center = center; }, ifEnableAnimation: function () { return GraphSeries.superCall(this, 'ifEnableAnimation') // Not enable animation when do force layout && !(this.get('layout') === 'force' && this.get('force.layoutAnimation')); }, defaultOption: { zlevel: 0, z: 2, coordinateSystem: 'view', // Default option for all coordinate systems // xAxisIndex: 0, // yAxisIndex: 0, // polarIndex: 0, // geoIndex: 0, legendHoverLink: true, hoverAnimation: true, layout: null, focusNodeAdjacency: false, // Configuration of circular layout circular: { rotateLabel: false }, // Configuration of force directed layout force: { initLayout: null, // Node repulsion. Can be an array to represent range. repulsion: [0, 50], gravity: 0.1, // Edge length. Can be an array to represent range. edgeLength: 30, layoutAnimation: true }, left: 'center', top: 'center', // right: null, // bottom: null, // width: '80%', // height: '80%', symbol: 'circle', symbolSize: 10, edgeSymbol: ['none', 'none'], edgeSymbolSize: 10, edgeLabel: { normal: { position: 'middle' }, emphasis: {} }, draggable: false, roam: false, // Default on center of graph center: null, zoom: 1, // Symbol size scale ratio in roam nodeScaleRatio: 0.6, // categories: [], // data: [] // Or // nodes: [] // // links: [] // Or // edges: [] label: { normal: { show: false, formatter: '{b}' }, emphasis: { show: true } }, itemStyle: { normal: {}, emphasis: {} }, lineStyle: { normal: { color: '#aaa', width: 1, curveness: 0, opacity: 0.5 }, emphasis: {} } } }); module.exports = GraphSeries; /***/ }, /* 198 */ /***/ function(module, exports, __webpack_require__) { var List = __webpack_require__(98); var Graph = __webpack_require__(199); var linkList = __webpack_require__(187); var completeDimensions = __webpack_require__(103); var CoordinateSystem = __webpack_require__(26); var zrUtil = __webpack_require__(4); var createListFromArray = __webpack_require__(102); module.exports = function (nodes, edges, hostModel, directed, beforeLink) { var graph = new Graph(directed); for (var i = 0; i < nodes.length; i++) { graph.addNode(zrUtil.retrieve( // Id, name, dataIndex nodes[i].id, nodes[i].name, i ), i); } var linkNameList = []; var validEdges = []; var linkCount = 0; for (var i = 0; i < edges.length; i++) { var link = edges[i]; var source = link.source; var target = link.target; // addEdge may fail when source or target not exists if (graph.addEdge(source, target, linkCount)) { validEdges.push(link); linkNameList.push(zrUtil.retrieve(link.id, source + ' > ' + target)); linkCount++; } } var coordSys = hostModel.get('coordinateSystem'); var nodeData; if (coordSys === 'cartesian2d' || coordSys === 'polar') { nodeData = createListFromArray(nodes, hostModel, hostModel.ecModel); } else { // FIXME var coordSysCtor = CoordinateSystem.get(coordSys); // FIXME var dimensionNames = completeDimensions( ((coordSysCtor && coordSysCtor.type !== 'view') ? (coordSysCtor.dimensions || []) : []).concat(['value']), nodes ); nodeData = new List(dimensionNames, hostModel); nodeData.initData(nodes); } var edgeData = new List(['value'], hostModel); edgeData.initData(validEdges, linkNameList); beforeLink && beforeLink(nodeData, edgeData); linkList({ mainData: nodeData, struct: graph, structAttr: 'graph', datas: {node: nodeData, edge: edgeData}, datasAttr: {node: 'data', edge: 'edgeData'} }); // Update dataIndex of nodes and edges because invalid edge may be removed graph.update(); return graph; }; /***/ }, /* 199 */ /***/ function(module, exports, __webpack_require__) { 'use strict'; /** * Graph data structure * * @module echarts/data/Graph * @author Yi Shen(https://www.github.com/pissang) */ var zrUtil = __webpack_require__(4); /** * @alias module:echarts/data/Graph * @constructor * @param {boolean} directed */ var Graph = function(directed) { /** * 是否是有向图 * @type {boolean} * @private */ this._directed = directed || false; /** * @type {Array.} * @readOnly */ this.nodes = []; /** * @type {Array.} * @readOnly */ this.edges = []; /** * @type {Object.} * @private */ this._nodesMap = {}; /** * @type {Object.} * @private */ this._edgesMap = {}; /** * @type {module:echarts/data/List} * @readOnly */ this.data; /** * @type {module:echarts/data/List} * @readOnly */ this.edgeData; }; var graphProto = Graph.prototype; /** * @type {string} */ graphProto.type = 'graph'; /** * If is directed graph * @return {boolean} */ graphProto.isDirected = function () { return this._directed; }; /** * Add a new node * @param {string} id * @param {number} [dataIndex] */ graphProto.addNode = function (id, dataIndex) { id = id || ('' + dataIndex); var nodesMap = this._nodesMap; if (nodesMap[id]) { return; } var node = new Node(id, dataIndex); node.hostGraph = this; this.nodes.push(node); nodesMap[id] = node; return node; }; /** * Get node by data index * @param {number} dataIndex * @return {module:echarts/data/Graph~Node} */ graphProto.getNodeByIndex = function (dataIndex) { var rawIdx = this.data.getRawIndex(dataIndex); return this.nodes[rawIdx]; }; /** * Get node by id * @param {string} id * @return {module:echarts/data/Graph.Node} */ graphProto.getNodeById = function (id) { return this._nodesMap[id]; }; /** * Add a new edge * @param {number|string|module:echarts/data/Graph.Node} n1 * @param {number|string|module:echarts/data/Graph.Node} n2 * @param {number} [dataIndex=-1] * @return {module:echarts/data/Graph.Edge} */ graphProto.addEdge = function (n1, n2, dataIndex) { var nodesMap = this._nodesMap; var edgesMap = this._edgesMap; // PNEDING if (typeof n1 === 'number') { n1 = this.nodes[n1]; } if (typeof n2 === 'number') { n2 = this.nodes[n2]; } if (!(n1 instanceof Node)) { n1 = nodesMap[n1]; } if (!(n2 instanceof Node)) { n2 = nodesMap[n2]; } if (!n1 || !n2) { return; } var key = n1.id + '-' + n2.id; // PENDING if (edgesMap[key]) { return; } var edge = new Edge(n1, n2, dataIndex); edge.hostGraph = this; if (this._directed) { n1.outEdges.push(edge); n2.inEdges.push(edge); } n1.edges.push(edge); if (n1 !== n2) { n2.edges.push(edge); } this.edges.push(edge); edgesMap[key] = edge; return edge; }; /** * Get edge by data index * @param {number} dataIndex * @return {module:echarts/data/Graph~Node} */ graphProto.getEdgeByIndex = function (dataIndex) { var rawIdx = this.edgeData.getRawIndex(dataIndex); return this.edges[rawIdx]; }; /** * Get edge by two linked nodes * @param {module:echarts/data/Graph.Node|string} n1 * @param {module:echarts/data/Graph.Node|string} n2 * @return {module:echarts/data/Graph.Edge} */ graphProto.getEdge = function (n1, n2) { if (n1 instanceof Node) { n1 = n1.id; } if (n2 instanceof Node) { n2 = n2.id; } var edgesMap = this._edgesMap; if (this._directed) { return edgesMap[n1 + '-' + n2]; } else { return edgesMap[n1 + '-' + n2] || edgesMap[n2 + '-' + n1]; } }; /** * Iterate all nodes * @param {Function} cb * @param {*} [context] */ graphProto.eachNode = function (cb, context) { var nodes = this.nodes; var len = nodes.length; for (var i = 0; i < len; i++) { if (nodes[i].dataIndex >= 0) { cb.call(context, nodes[i], i); } } }; /** * Iterate all edges * @param {Function} cb * @param {*} [context] */ graphProto.eachEdge = function (cb, context) { var edges = this.edges; var len = edges.length; for (var i = 0; i < len; i++) { if (edges[i].dataIndex >= 0 && edges[i].node1.dataIndex >= 0 && edges[i].node2.dataIndex >= 0 ) { cb.call(context, edges[i], i); } } }; /** * Breadth first traverse * @param {Function} cb * @param {module:echarts/data/Graph.Node} startNode * @param {string} [direction='none'] 'none'|'in'|'out' * @param {*} [context] */ graphProto.breadthFirstTraverse = function ( cb, startNode, direction, context ) { if (!(startNode instanceof Node)) { startNode = this._nodesMap[startNode]; } if (!startNode) { return; } var edgeType = direction === 'out' ? 'outEdges' : (direction === 'in' ? 'inEdges' : 'edges'); for (var i = 0; i < this.nodes.length; i++) { this.nodes[i].__visited = false; } if (cb.call(context, startNode, null)) { return; } var queue = [startNode]; while (queue.length) { var currentNode = queue.shift(); var edges = currentNode[edgeType]; for (var i = 0; i < edges.length; i++) { var e = edges[i]; var otherNode = e.node1 === currentNode ? e.node2 : e.node1; if (!otherNode.__visited) { if (cb.call(otherNode, otherNode, currentNode)) { // Stop traversing return; } queue.push(otherNode); otherNode.__visited = true; } } } }; // TODO // graphProto.depthFirstTraverse = function ( // cb, startNode, direction, context // ) { // }; // Filter update graphProto.update = function () { var data = this.data; var edgeData = this.edgeData; var nodes = this.nodes; var edges = this.edges; for (var i = 0, len = nodes.length; i < len; i++) { nodes[i].dataIndex = -1; } for (var i = 0, len = data.count(); i < len; i++) { nodes[data.getRawIndex(i)].dataIndex = i; } edgeData.filterSelf(function (idx) { var edge = edges[edgeData.getRawIndex(idx)]; return edge.node1.dataIndex >= 0 && edge.node2.dataIndex >= 0; }); // Update edge for (var i = 0, len = edges.length; i < len; i++) { edges[i].dataIndex = -1; } for (var i = 0, len = edgeData.count(); i < len; i++) { edges[edgeData.getRawIndex(i)].dataIndex = i; } }; /** * @return {module:echarts/data/Graph} */ graphProto.clone = function () { var graph = new Graph(this._directed); var nodes = this.nodes; var edges = this.edges; for (var i = 0; i < nodes.length; i++) { graph.addNode(nodes[i].id, nodes[i].dataIndex); } for (var i = 0; i < edges.length; i++) { var e = edges[i]; graph.addEdge(e.node1.id, e.node2.id, e.dataIndex); } return graph; }; /** * @alias module:echarts/data/Graph.Node */ function Node(id, dataIndex) { /** * @type {string} */ this.id = id == null ? '' : id; /** * @type {Array.} */ this.inEdges = []; /** * @type {Array.} */ this.outEdges = []; /** * @type {Array.} */ this.edges = []; /** * @type {module:echarts/data/Graph} */ this.hostGraph; /** * @type {number} */ this.dataIndex = dataIndex == null ? -1 : dataIndex; } Node.prototype = { constructor: Node, /** * @return {number} */ degree: function () { return this.edges.length; }, /** * @return {number} */ inDegree: function () { return this.inEdges.length; }, /** * @return {number} */ outDegree: function () { return this.outEdges.length; }, /** * @param {string} [path] * @return {module:echarts/model/Model} */ getModel: function (path) { if (this.dataIndex < 0) { return; } var graph = this.hostGraph; var itemModel = graph.data.getItemModel(this.dataIndex); return itemModel.getModel(path); } }; /** * 图边 * @alias module:echarts/data/Graph.Edge * @param {module:echarts/data/Graph.Node} n1 * @param {module:echarts/data/Graph.Node} n2 * @param {number} [dataIndex=-1] */ function Edge(n1, n2, dataIndex) { /** * 节点1,如果是有向图则为源节点 * @type {module:echarts/data/Graph.Node} */ this.node1 = n1; /** * 节点2,如果是有向图则为目标节点 * @type {module:echarts/data/Graph.Node} */ this.node2 = n2; this.dataIndex = dataIndex == null ? -1 : dataIndex; } /** * @param {string} [path] * @return {module:echarts/model/Model} */ Edge.prototype.getModel = function (path) { if (this.dataIndex < 0) { return; } var graph = this.hostGraph; var itemModel = graph.edgeData.getItemModel(this.dataIndex); return itemModel.getModel(path); }; var createGraphDataProxyMixin = function (hostName, dataName) { return { /** * @param {string=} [dimension='value'] Default 'value'. can be 'a', 'b', 'c', 'd', 'e'. * @return {number} */ getValue: function (dimension) { var data = this[hostName][dataName]; return data.get(data.getDimension(dimension || 'value'), this.dataIndex); }, /** * @param {Object|string} key * @param {*} [value] */ setVisual: function (key, value) { this.dataIndex >= 0 && this[hostName][dataName].setItemVisual(this.dataIndex, key, value); }, /** * @param {string} key * @return {boolean} */ getVisual: function (key, ignoreParent) { return this[hostName][dataName].getItemVisual(this.dataIndex, key, ignoreParent); }, /** * @param {Object} layout * @return {boolean} [merge=false] */ setLayout: function (layout, merge) { this.dataIndex >= 0 && this[hostName][dataName].setItemLayout(this.dataIndex, layout, merge); }, /** * @return {Object} */ getLayout: function () { return this[hostName][dataName].getItemLayout(this.dataIndex); }, /** * @return {module:zrender/Element} */ getGraphicEl: function () { return this[hostName][dataName].getItemGraphicEl(this.dataIndex); }, /** * @return {number} */ getRawIndex: function () { return this[hostName][dataName].getRawIndex(this.dataIndex); } }; }; zrUtil.mixin(Node, createGraphDataProxyMixin('hostGraph', 'data')); zrUtil.mixin(Edge, createGraphDataProxyMixin('hostGraph', 'edgeData')); Graph.Node = Node; Graph.Edge = Edge; module.exports = Graph; /***/ }, /* 200 */ /***/ function(module, exports, __webpack_require__) { var SymbolDraw = __webpack_require__(105); var LineDraw = __webpack_require__(201); var RoamController = __webpack_require__(176); var graphic = __webpack_require__(43); var adjustEdge = __webpack_require__(204); var zrUtil = __webpack_require__(4); var nodeOpacityPath = ['itemStyle', 'normal', 'opacity']; var lineOpacityPath = ['lineStyle', 'normal', 'opacity']; function getItemOpacity(item, opacityPath) { return item.getVisual('opacity') || item.getModel().get(opacityPath); } __webpack_require__(1).extendChartView({ type: 'graph', init: function (ecModel, api) { var symbolDraw = new SymbolDraw(); var lineDraw = new LineDraw(); var group = this.group; var controller = new RoamController(api.getZr(), group); group.add(symbolDraw.group); group.add(lineDraw.group); this._symbolDraw = symbolDraw; this._lineDraw = lineDraw; this._controller = controller; this._firstRender = true; }, render: function (seriesModel, ecModel, api) { var coordSys = seriesModel.coordinateSystem; this._model = seriesModel; this._nodeScaleRatio = seriesModel.get('nodeScaleRatio'); var symbolDraw = this._symbolDraw; var lineDraw = this._lineDraw; var group = this.group; if (coordSys.type === 'view') { var groupNewProp = { position: coordSys.position, scale: coordSys.scale }; if (this._firstRender) { group.attr(groupNewProp); } else { graphic.updateProps(group, groupNewProp, seriesModel); } } // Fix edge contact point with node adjustEdge(seriesModel.getGraph(), this._getNodeGlobalScale(seriesModel)); var data = seriesModel.getData(); symbolDraw.updateData(data); var edgeData = seriesModel.getEdgeData(); lineDraw.updateData(edgeData); this._updateNodeAndLinkScale(); this._updateController(seriesModel, api); clearTimeout(this._layoutTimeout); var forceLayout = seriesModel.forceLayout; var layoutAnimation = seriesModel.get('force.layoutAnimation'); if (forceLayout) { this._startForceLayoutIteration(forceLayout, layoutAnimation); } data.eachItemGraphicEl(function (el, idx) { var itemModel = data.getItemModel(idx); // Update draggable el.off('drag').off('dragend'); var draggable = data.getItemModel(idx).get('draggable'); if (draggable) { el.on('drag', function () { if (forceLayout) { forceLayout.warmUp(); !this._layouting && this._startForceLayoutIteration(forceLayout, layoutAnimation); forceLayout.setFixed(idx); // Write position back to layout data.setItemLayout(idx, el.position); } }, this).on('dragend', function () { if (forceLayout) { forceLayout.setUnfixed(idx); } }, this); } el.setDraggable(draggable && forceLayout); el.off('mouseover', this._focusNodeAdjacency); el.off('mouseout', this._unfocusAll); if (itemModel.get('focusNodeAdjacency')) { el.on('mouseover', this._focusNodeAdjacency, this); el.on('mouseout', this._unfocusAll, this); } }, this); var circularRotateLabel = seriesModel.get('layout') === 'circular' && seriesModel.get('circular.rotateLabel'); var cx = data.getLayout('cx'); var cy = data.getLayout('cy'); data.eachItemGraphicEl(function (el, idx) { var symbolPath = el.getSymbolPath(); if (circularRotateLabel) { var pos = data.getItemLayout(idx); var rad = Math.atan2(pos[1] - cy, pos[0] - cx); if (rad < 0) { rad = Math.PI * 2 + rad; } var isLeft = pos[0] < cx; if (isLeft) { rad = rad - Math.PI; } var textPosition = isLeft ? 'left' : 'right'; symbolPath.setStyle({ textRotation: rad, textPosition: textPosition }); symbolPath.hoverStyle && (symbolPath.hoverStyle.textPosition = textPosition); } else { symbolPath.setStyle({ textRotation: 0 }); } }); this._firstRender = false; }, dispose: function () { this._controller && this._controller.dispose(); }, _focusNodeAdjacency: function (e) { var data = this._model.getData(); var graph = data.graph; var el = e.target; var dataIndex = el.dataIndex; var dataType = el.dataType; function fadeOutItem(item, opacityPath) { var opacity = getItemOpacity(item, opacityPath); var el = item.getGraphicEl(); if (opacity == null) { opacity = 1; } el.traverse(function (child) { child.trigger('normal'); if (child.type !== 'group') { child.setStyle('opacity', opacity * 0.1); } }); } function fadeInItem(item, opacityPath) { var opacity = getItemOpacity(item, opacityPath); var el = item.getGraphicEl(); el.traverse(function (child) { child.trigger('emphasis'); if (child.type !== 'group') { child.setStyle('opacity', opacity); } }); } if (dataIndex !== null && dataType !== 'edge') { graph.eachNode(function (node) { fadeOutItem(node, nodeOpacityPath); }); graph.eachEdge(function (edge) { fadeOutItem(edge, lineOpacityPath); }); var node = graph.getNodeByIndex(dataIndex); fadeInItem(node, nodeOpacityPath); zrUtil.each(node.edges, function (edge) { if (edge.dataIndex < 0) { return; } fadeInItem(edge, lineOpacityPath); fadeInItem(edge.node1, nodeOpacityPath); fadeInItem(edge.node2, nodeOpacityPath); }); } }, _unfocusAll: function () { var data = this._model.getData(); var graph = data.graph; graph.eachNode(function (node) { var opacity = getItemOpacity(node, nodeOpacityPath); node.getGraphicEl().traverse(function (child) { child.trigger('normal'); if (child.type !== 'group') { child.setStyle('opacity', opacity); } }); }); graph.eachEdge(function (edge) { var opacity = getItemOpacity(edge, lineOpacityPath); edge.getGraphicEl().traverse(function (child) { child.trigger('normal'); if (child.type !== 'group') { child.setStyle('opacity', opacity); } }); }); }, _startForceLayoutIteration: function (forceLayout, layoutAnimation) { var self = this; (function step() { forceLayout.step(function (stopped) { self.updateLayout(self._model); (self._layouting = !stopped) && ( layoutAnimation ? (self._layoutTimeout = setTimeout(step, 16)) : step() ); }); })(); }, _updateController: function (seriesModel, api) { var controller = this._controller; var group = this.group; controller.setContainsPoint(function (x, y) { var rect = group.getBoundingRect(); rect.applyTransform(group.transform); return rect.contain(x, y); }); if (seriesModel.coordinateSystem.type !== 'view') { controller.disable(); return; } controller.enable(seriesModel.get('roam')); controller.zoomLimit = seriesModel.get('scaleLimit'); // Update zoom from model controller.zoom = seriesModel.coordinateSystem.getZoom(); controller .off('pan') .off('zoom') .on('pan', function (dx, dy) { api.dispatchAction({ seriesId: seriesModel.id, type: 'graphRoam', dx: dx, dy: dy }); }) .on('zoom', function (zoom, mouseX, mouseY) { api.dispatchAction({ seriesId: seriesModel.id, type: 'graphRoam', zoom: zoom, originX: mouseX, originY: mouseY }); this._updateNodeAndLinkScale(); adjustEdge(seriesModel.getGraph(), this._getNodeGlobalScale(seriesModel)); this._lineDraw.updateLayout(); }, this); }, _updateNodeAndLinkScale: function () { var seriesModel = this._model; var data = seriesModel.getData(); var nodeScale = this._getNodeGlobalScale(seriesModel); var invScale = [nodeScale, nodeScale]; data.eachItemGraphicEl(function (el, idx) { el.attr('scale', invScale); }); }, _getNodeGlobalScale: function (seriesModel) { var coordSys = seriesModel.coordinateSystem; if (coordSys.type !== 'view') { return 1; } var nodeScaleRatio = this._nodeScaleRatio; var groupScale = coordSys.scale; var groupZoom = (groupScale && groupScale[0]) || 1; // Scale node when zoom changes var roamZoom = coordSys.getZoom(); var nodeScale = (roamZoom - 1) * nodeScaleRatio + 1; return nodeScale / groupZoom; }, updateLayout: function (seriesModel) { adjustEdge(seriesModel.getGraph(), this._getNodeGlobalScale(seriesModel)); this._symbolDraw.updateLayout(); this._lineDraw.updateLayout(); }, remove: function (ecModel, api) { this._symbolDraw && this._symbolDraw.remove(); this._lineDraw && this._lineDraw.remove(); } }); /***/ }, /* 201 */ /***/ function(module, exports, __webpack_require__) { /** * @module echarts/chart/helper/LineDraw */ var graphic = __webpack_require__(43); var LineGroup = __webpack_require__(202); function isPointNaN(pt) { return isNaN(pt[0]) || isNaN(pt[1]); } function lineNeedsDraw(pts) { return !isPointNaN(pts[0]) && !isPointNaN(pts[1]); } /** * @alias module:echarts/component/marker/LineDraw * @constructor */ function LineDraw(ctor) { this._ctor = ctor || LineGroup; this.group = new graphic.Group(); } var lineDrawProto = LineDraw.prototype; /** * @param {module:echarts/data/List} lineData */ lineDrawProto.updateData = function (lineData) { var oldLineData = this._lineData; var group = this.group; var LineCtor = this._ctor; var hostModel = lineData.hostModel; var seriesScope = { lineStyle: hostModel.getModel('lineStyle.normal').getLineStyle(), hoverLineStyle: hostModel.getModel('lineStyle.emphasis').getLineStyle(), labelModel: hostModel.getModel('label.normal'), hoverLabelModel: hostModel.getModel('label.emphasis') }; lineData.diff(oldLineData) .add(function (idx) { if (!lineNeedsDraw(lineData.getItemLayout(idx))) { return; } var lineGroup = new LineCtor(lineData, idx, seriesScope); lineData.setItemGraphicEl(idx, lineGroup); group.add(lineGroup); }) .update(function (newIdx, oldIdx) { var lineGroup = oldLineData.getItemGraphicEl(oldIdx); if (!lineNeedsDraw(lineData.getItemLayout(newIdx))) { group.remove(lineGroup); return; } if (!lineGroup) { lineGroup = new LineCtor(lineData, newIdx, seriesScope); } else { lineGroup.updateData(lineData, newIdx, seriesScope); } lineData.setItemGraphicEl(newIdx, lineGroup); group.add(lineGroup); }) .remove(function (idx) { group.remove(oldLineData.getItemGraphicEl(idx)); }) .execute(); this._lineData = lineData; }; lineDrawProto.updateLayout = function () { var lineData = this._lineData; lineData.eachItemGraphicEl(function (el, idx) { el.updateLayout(lineData, idx); }, this); }; lineDrawProto.remove = function () { this.group.removeAll(); }; module.exports = LineDraw; /***/ }, /* 202 */ /***/ function(module, exports, __webpack_require__) { /** * @module echarts/chart/helper/Line */ var symbolUtil = __webpack_require__(107); var vector = __webpack_require__(10); // var matrix = require('zrender/lib/core/matrix'); var LinePath = __webpack_require__(203); var graphic = __webpack_require__(43); var zrUtil = __webpack_require__(4); var numberUtil = __webpack_require__(7); var SYMBOL_CATEGORIES = ['fromSymbol', 'toSymbol']; function makeSymbolTypeKey(symbolCategory) { return '_' + symbolCategory + 'Type'; } /** * @inner */ function createSymbol(name, lineData, idx) { var color = lineData.getItemVisual(idx, 'color'); var symbolType = lineData.getItemVisual(idx, name); var symbolSize = lineData.getItemVisual(idx, name + 'Size'); if (!symbolType || symbolType === 'none') { return; } if (!zrUtil.isArray(symbolSize)) { symbolSize = [symbolSize, symbolSize]; } var symbolPath = symbolUtil.createSymbol( symbolType, -symbolSize[0] / 2, -symbolSize[1] / 2, symbolSize[0], symbolSize[1], color ); symbolPath.name = name; return symbolPath; } function createLine(points) { var line = new LinePath({ name: 'line' }); setLinePoints(line.shape, points); return line; } function setLinePoints(targetShape, points) { var p1 = points[0]; var p2 = points[1]; var cp1 = points[2]; targetShape.x1 = p1[0]; targetShape.y1 = p1[1]; targetShape.x2 = p2[0]; targetShape.y2 = p2[1]; targetShape.percent = 1; if (cp1) { targetShape.cpx1 = cp1[0]; targetShape.cpy1 = cp1[1]; } else { targetShape.cpx1 = NaN; targetShape.cpy1 = NaN; } } function updateSymbolAndLabelBeforeLineUpdate () { var lineGroup = this; var symbolFrom = lineGroup.childOfName('fromSymbol'); var symbolTo = lineGroup.childOfName('toSymbol'); var label = lineGroup.childOfName('label'); // Quick reject if (!symbolFrom && !symbolTo && label.ignore) { return; } var invScale = 1; var parentNode = this.parent; while (parentNode) { if (parentNode.scale) { invScale /= parentNode.scale[0]; } parentNode = parentNode.parent; } var line = lineGroup.childOfName('line'); // If line not changed // FIXME Parent scale changed if (!this.__dirty && !line.__dirty) { return; } var percent = line.shape.percent; var fromPos = line.pointAt(0); var toPos = line.pointAt(percent); var d = vector.sub([], toPos, fromPos); vector.normalize(d, d); if (symbolFrom) { symbolFrom.attr('position', fromPos); var tangent = line.tangentAt(0); symbolFrom.attr('rotation', Math.PI / 2 - Math.atan2( tangent[1], tangent[0] )); symbolFrom.attr('scale', [invScale * percent, invScale * percent]); } if (symbolTo) { symbolTo.attr('position', toPos); var tangent = line.tangentAt(1); symbolTo.attr('rotation', -Math.PI / 2 - Math.atan2( tangent[1], tangent[0] )); symbolTo.attr('scale', [invScale * percent, invScale * percent]); } if (!label.ignore) { label.attr('position', toPos); var textPosition; var textAlign; var textVerticalAlign; var distance = 5 * invScale; // End if (label.__position === 'end') { textPosition = [d[0] * distance + toPos[0], d[1] * distance + toPos[1]]; textAlign = d[0] > 0.8 ? 'left' : (d[0] < -0.8 ? 'right' : 'center'); textVerticalAlign = d[1] > 0.8 ? 'top' : (d[1] < -0.8 ? 'bottom' : 'middle'); } // Middle else if (label.__position === 'middle') { var halfPercent = percent / 2; var tangent = line.tangentAt(halfPercent); var n = [tangent[1], -tangent[0]]; var cp = line.pointAt(halfPercent); if (n[1] > 0) { n[0] = -n[0]; n[1] = -n[1]; } textPosition = [cp[0] + n[0] * distance, cp[1] + n[1] * distance]; textAlign = 'center'; textVerticalAlign = 'bottom'; var rotation = -Math.atan2(tangent[1], tangent[0]); if (toPos[0] < fromPos[0]) { rotation = Math.PI + rotation; } label.attr('rotation', rotation); } // Start else { textPosition = [-d[0] * distance + fromPos[0], -d[1] * distance + fromPos[1]]; textAlign = d[0] > 0.8 ? 'right' : (d[0] < -0.8 ? 'left' : 'center'); textVerticalAlign = d[1] > 0.8 ? 'bottom' : (d[1] < -0.8 ? 'top' : 'middle'); } label.attr({ style: { // Use the user specified text align and baseline first textVerticalAlign: label.__verticalAlign || textVerticalAlign, textAlign: label.__textAlign || textAlign }, position: textPosition, scale: [invScale, invScale] }); } } /** * @constructor * @extends {module:zrender/graphic/Group} * @alias {module:echarts/chart/helper/Line} */ function Line(lineData, idx, seriesScope) { graphic.Group.call(this); this._createLine(lineData, idx, seriesScope); } var lineProto = Line.prototype; // Update symbol position and rotation lineProto.beforeUpdate = updateSymbolAndLabelBeforeLineUpdate; lineProto._createLine = function (lineData, idx, seriesScope) { var seriesModel = lineData.hostModel; var linePoints = lineData.getItemLayout(idx); var line = createLine(linePoints); line.shape.percent = 0; graphic.initProps(line, { shape: { percent: 1 } }, seriesModel, idx); this.add(line); var label = new graphic.Text({ name: 'label' }); this.add(label); zrUtil.each(SYMBOL_CATEGORIES, function (symbolCategory) { var symbol = createSymbol(symbolCategory, lineData, idx); // symbols must added after line to make sure // it will be updated after line#update. // Or symbol position and rotation update in line#beforeUpdate will be one frame slow this.add(symbol); this[makeSymbolTypeKey(symbolCategory)] = lineData.getItemVisual(idx, symbolCategory); }, this); this._updateCommonStl(lineData, idx, seriesScope); }; lineProto.updateData = function (lineData, idx, seriesScope) { var seriesModel = lineData.hostModel; var line = this.childOfName('line'); var linePoints = lineData.getItemLayout(idx); var target = { shape: {} }; setLinePoints(target.shape, linePoints); graphic.updateProps(line, target, seriesModel, idx); zrUtil.each(SYMBOL_CATEGORIES, function (symbolCategory) { var symbolType = lineData.getItemVisual(idx, symbolCategory); var key = makeSymbolTypeKey(symbolCategory); // Symbol changed if (this[key] !== symbolType) { this.remove(this.childOfName(symbolCategory)); var symbol = createSymbol(symbolCategory, lineData, idx); this.add(symbol); } this[key] = symbolType; }, this); this._updateCommonStl(lineData, idx, seriesScope); }; lineProto._updateCommonStl = function (lineData, idx, seriesScope) { var seriesModel = lineData.hostModel; var line = this.childOfName('line'); var lineStyle = seriesScope && seriesScope.lineStyle; var hoverLineStyle = seriesScope && seriesScope.hoverLineStyle; var labelModel = seriesScope && seriesScope.labelModel; var hoverLabelModel = seriesScope && seriesScope.hoverLabelModel; // Optimization for large dataset if (!seriesScope || lineData.hasItemOption) { var itemModel = lineData.getItemModel(idx); lineStyle = itemModel.getModel('lineStyle.normal').getLineStyle(); hoverLineStyle = itemModel.getModel('lineStyle.emphasis').getLineStyle(); labelModel = itemModel.getModel('label.normal'); hoverLabelModel = itemModel.getModel('label.emphasis'); } var visualColor = lineData.getItemVisual(idx, 'color'); var visualOpacity = zrUtil.retrieve( lineData.getItemVisual(idx, 'opacity'), lineStyle.opacity, 1 ); line.useStyle(zrUtil.defaults( { strokeNoScale: true, fill: 'none', stroke: visualColor, opacity: visualOpacity }, lineStyle )); line.hoverStyle = hoverLineStyle; // Update symbol zrUtil.each(SYMBOL_CATEGORIES, function (symbolCategory) { var symbol = this.childOfName(symbolCategory); if (symbol) { symbol.setColor(visualColor); symbol.setStyle({ opacity: visualOpacity }); } }, this); var showLabel = labelModel.getShallow('show'); var hoverShowLabel = hoverLabelModel.getShallow('show'); var label = this.childOfName('label'); var defaultLabelColor; var defaultText; if (showLabel || hoverShowLabel) { var rawVal = seriesModel.getRawValue(idx); defaultText = rawVal == null ? defaultText = lineData.getName(idx) : isFinite(rawVal) ? numberUtil.round(rawVal) : rawVal; defaultLabelColor = visualColor || '#000'; } // label.afterUpdate = lineAfterUpdate; if (showLabel) { var textStyleModel = labelModel.getModel('textStyle'); label.setStyle({ text: zrUtil.retrieve( seriesModel.getFormattedLabel(idx, 'normal', lineData.dataType), defaultText ), textFont: textStyleModel.getFont(), fill: textStyleModel.getTextColor() || defaultLabelColor }); label.__textAlign = textStyleModel.get('align'); label.__verticalAlign = textStyleModel.get('baseline'); label.__position = labelModel.get('position'); } else { label.setStyle('text', ''); } if (hoverShowLabel) { var textStyleHoverModel = hoverLabelModel.getModel('textStyle'); label.hoverStyle = { text: zrUtil.retrieve( seriesModel.getFormattedLabel(idx, 'emphasis', lineData.dataType), defaultText ), textFont: textStyleHoverModel.getFont(), fill: textStyleHoverModel.getTextColor() || defaultLabelColor }; } else { label.hoverStyle = { text: '' }; } label.ignore = !showLabel && !hoverShowLabel; graphic.setHoverStyle(this); }; lineProto.updateLayout = function (lineData, idx) { this.setLinePoints(lineData.getItemLayout(idx)); }; lineProto.setLinePoints = function (points) { var linePath = this.childOfName('line'); setLinePoints(linePath.shape, points); linePath.dirty(); }; zrUtil.inherits(Line, graphic.Group); module.exports = Line; /***/ }, /* 203 */ /***/ function(module, exports, __webpack_require__) { /** * Line path for bezier and straight line draw */ var graphic = __webpack_require__(43); var vec2 = __webpack_require__(10); var straightLineProto = graphic.Line.prototype; var bezierCurveProto = graphic.BezierCurve.prototype; function isLine(shape) { return isNaN(+shape.cpx1) || isNaN(+shape.cpy1); } module.exports = graphic.extendShape({ type: 'ec-line', style: { stroke: '#000', fill: null }, shape: { x1: 0, y1: 0, x2: 0, y2: 0, percent: 1, cpx1: null, cpy1: null }, buildPath: function (ctx, shape) { (isLine(shape) ? straightLineProto : bezierCurveProto).buildPath(ctx, shape); }, pointAt: function (t) { return isLine(this.shape) ? straightLineProto.pointAt.call(this, t) : bezierCurveProto.pointAt.call(this, t); }, tangentAt: function (t) { var shape = this.shape; var p = isLine(shape) ? [shape.x2 - shape.x1, shape.y2 - shape.y1] : bezierCurveProto.tangentAt.call(this, t); return vec2.normalize(p, p); } }); /***/ }, /* 204 */ /***/ function(module, exports, __webpack_require__) { var curveTool = __webpack_require__(50); var vec2 = __webpack_require__(10); var v1 = []; var v2 = []; var v3 = []; var quadraticAt = curveTool.quadraticAt; var v2DistSquare = vec2.distSquare; var mathAbs = Math.abs; function intersectCurveCircle(curvePoints, center, radius) { var p0 = curvePoints[0]; var p1 = curvePoints[1]; var p2 = curvePoints[2]; var d = Infinity; var t; var radiusSquare = radius * radius; var interval = 0.1; for (var _t = 0.1; _t <= 0.9; _t += 0.1) { v1[0] = quadraticAt(p0[0], p1[0], p2[0], _t); v1[1] = quadraticAt(p0[1], p1[1], p2[1], _t); var diff = mathAbs(v2DistSquare(v1, center) - radiusSquare); if (diff < d) { d = diff; t = _t; } } // Assume the segment is monotone,Find root through Bisection method // At most 32 iteration for (var i = 0; i < 32; i++) { // var prev = t - interval; var next = t + interval; // v1[0] = quadraticAt(p0[0], p1[0], p2[0], prev); // v1[1] = quadraticAt(p0[1], p1[1], p2[1], prev); v2[0] = quadraticAt(p0[0], p1[0], p2[0], t); v2[1] = quadraticAt(p0[1], p1[1], p2[1], t); v3[0] = quadraticAt(p0[0], p1[0], p2[0], next); v3[1] = quadraticAt(p0[1], p1[1], p2[1], next); var diff = v2DistSquare(v2, center) - radiusSquare; if (mathAbs(diff) < 1e-2) { break; } // var prevDiff = v2DistSquare(v1, center) - radiusSquare; var nextDiff = v2DistSquare(v3, center) - radiusSquare; interval /= 2; if (diff < 0) { if (nextDiff >= 0) { t = t + interval; } else { t = t - interval; } } else { if (nextDiff >= 0) { t = t - interval; } else { t = t + interval; } } } return t; } // Adjust edge to avoid module.exports = function (graph, scale) { var tmp0 = []; var quadraticSubdivide = curveTool.quadraticSubdivide; var pts = [[], [], []]; var pts2 = [[], []]; var v = []; scale /= 2; function getSymbolSize(node) { var symbolSize = node.getVisual('symbolSize'); if (symbolSize instanceof Array) { symbolSize = (symbolSize[0] + symbolSize[1]) / 2; } return symbolSize; } graph.eachEdge(function (edge, idx) { var linePoints = edge.getLayout(); var fromSymbol = edge.getVisual('fromSymbol'); var toSymbol = edge.getVisual('toSymbol'); if (!linePoints.__original) { linePoints.__original = [ vec2.clone(linePoints[0]), vec2.clone(linePoints[1]) ]; if (linePoints[2]) { linePoints.__original.push(vec2.clone(linePoints[2])); } } var originalPoints = linePoints.__original; // Quadratic curve if (linePoints[2] != null) { vec2.copy(pts[0], originalPoints[0]); vec2.copy(pts[1], originalPoints[2]); vec2.copy(pts[2], originalPoints[1]); if (fromSymbol && fromSymbol != 'none') { var symbolSize = getSymbolSize(edge.node1); var t = intersectCurveCircle(pts, originalPoints[0], symbolSize * scale); // Subdivide and get the second quadraticSubdivide(pts[0][0], pts[1][0], pts[2][0], t, tmp0); pts[0][0] = tmp0[3]; pts[1][0] = tmp0[4]; quadraticSubdivide(pts[0][1], pts[1][1], pts[2][1], t, tmp0); pts[0][1] = tmp0[3]; pts[1][1] = tmp0[4]; } if (toSymbol && toSymbol != 'none') { var symbolSize = getSymbolSize(edge.node2); var t = intersectCurveCircle(pts, originalPoints[1], symbolSize * scale); // Subdivide and get the first quadraticSubdivide(pts[0][0], pts[1][0], pts[2][0], t, tmp0); pts[1][0] = tmp0[1]; pts[2][0] = tmp0[2]; quadraticSubdivide(pts[0][1], pts[1][1], pts[2][1], t, tmp0); pts[1][1] = tmp0[1]; pts[2][1] = tmp0[2]; } // Copy back to layout vec2.copy(linePoints[0], pts[0]); vec2.copy(linePoints[1], pts[2]); vec2.copy(linePoints[2], pts[1]); } // Line else { vec2.copy(pts2[0], originalPoints[0]); vec2.copy(pts2[1], originalPoints[1]); vec2.sub(v, pts2[1], pts2[0]); vec2.normalize(v, v); if (fromSymbol && fromSymbol != 'none') { var symbolSize = getSymbolSize(edge.node1); vec2.scaleAndAdd(pts2[0], pts2[0], v, symbolSize * scale); } if (toSymbol && toSymbol != 'none') { var symbolSize = getSymbolSize(edge.node2); vec2.scaleAndAdd(pts2[1], pts2[1], v, -symbolSize * scale); } vec2.copy(linePoints[0], pts2[0]); vec2.copy(linePoints[1], pts2[1]); } }); }; /***/ }, /* 205 */ /***/ function(module, exports, __webpack_require__) { var echarts = __webpack_require__(1); var roamHelper = __webpack_require__(179); var actionInfo = { type: 'graphRoam', event: 'graphRoam', update: 'none' }; /** * @payload * @property {string} name Series name * @property {number} [dx] * @property {number} [dy] * @property {number} [zoom] * @property {number} [originX] * @property {number} [originY] */ echarts.registerAction(actionInfo, function (payload, ecModel) { ecModel.eachComponent({mainType: 'series', query: payload}, function (seriesModel) { var coordSys = seriesModel.coordinateSystem; var res = roamHelper.updateCenterAndZoom(coordSys, payload); seriesModel.setCenter && seriesModel.setCenter(res.center); seriesModel.setZoom && seriesModel.setZoom(res.zoom); }); }); /***/ }, /* 206 */ /***/ function(module, exports) { module.exports = function (ecModel) { var legendModels = ecModel.findComponents({ mainType: 'legend' }); if (!legendModels || !legendModels.length) { return; } ecModel.eachSeriesByType('graph', function (graphSeries) { var categoriesData = graphSeries.getCategoriesData(); var graph = graphSeries.getGraph(); var data = graph.data; var categoryNames = categoriesData.mapArray(categoriesData.getName); data.filterSelf(function (idx) { var model = data.getItemModel(idx); var category = model.getShallow('category'); if (category != null) { if (typeof category === 'number') { category = categoryNames[category]; } // If in any legend component the status is not selected. for (var i = 0; i < legendModels.length; i++) { if (!legendModels[i].isSelected(category)) { return false; } } } return true; }); }, this); }; /***/ }, /* 207 */ /***/ function(module, exports) { module.exports = function (ecModel) { var paletteScope = {}; ecModel.eachSeriesByType('graph', function (seriesModel) { var categoriesData = seriesModel.getCategoriesData(); var data = seriesModel.getData(); var categoryNameIdxMap = {}; categoriesData.each(function (idx) { var name = categoriesData.getName(idx); categoryNameIdxMap[name] = idx; var itemModel = categoriesData.getItemModel(idx); var color = itemModel.get('itemStyle.normal.color') || seriesModel.getColorFromPalette(name, paletteScope); categoriesData.setItemVisual(idx, 'color', color); }); // Assign category color to visual if (categoriesData.count()) { data.each(function (idx) { var model = data.getItemModel(idx); var category = model.getShallow('category'); if (category != null) { if (typeof category === 'string') { category = categoryNameIdxMap[category]; } if (!data.getItemVisual(idx, 'color', true)) { data.setItemVisual( idx, 'color', categoriesData.getItemVisual(category, 'color') ); } } }); } }); }; /***/ }, /* 208 */ /***/ function(module, exports) { function normalize(a) { if (!(a instanceof Array)) { a = [a, a]; } return a; } module.exports = function (ecModel) { ecModel.eachSeriesByType('graph', function (seriesModel) { var graph = seriesModel.getGraph(); var edgeData = seriesModel.getEdgeData(); var symbolType = normalize(seriesModel.get('edgeSymbol')); var symbolSize = normalize(seriesModel.get('edgeSymbolSize')); var colorQuery = 'lineStyle.normal.color'.split('.'); var opacityQuery = 'lineStyle.normal.opacity'.split('.'); edgeData.setVisual('fromSymbol', symbolType && symbolType[0]); edgeData.setVisual('toSymbol', symbolType && symbolType[1]); edgeData.setVisual('fromSymbolSize', symbolSize && symbolSize[0]); edgeData.setVisual('toSymbolSize', symbolSize && symbolSize[1]); edgeData.setVisual('color', seriesModel.get(colorQuery)); edgeData.setVisual('opacity', seriesModel.get(opacityQuery)); edgeData.each(function (idx) { var itemModel = edgeData.getItemModel(idx); var edge = graph.getEdgeByIndex(idx); var symbolType = normalize(itemModel.getShallow('symbol', true)); var symbolSize = normalize(itemModel.getShallow('symbolSize', true)); // Edge visual must after node visual var color = itemModel.get(colorQuery); var opacity = itemModel.get(opacityQuery); switch (color) { case 'source': color = edge.node1.getVisual('color'); break; case 'target': color = edge.node2.getVisual('color'); break; } symbolType[0] && edge.setVisual('fromSymbol', symbolType[0]); symbolType[1] && edge.setVisual('toSymbol', symbolType[1]); symbolSize[0] && edge.setVisual('fromSymbolSize', symbolSize[0]); symbolSize[1] && edge.setVisual('toSymbolSize', symbolSize[1]); edge.setVisual('color', color); edge.setVisual('opacity', opacity); }); }); }; /***/ }, /* 209 */ /***/ function(module, exports, __webpack_require__) { var simpleLayoutHelper = __webpack_require__(210); var simpleLayoutEdge = __webpack_require__(211); module.exports = function (ecModel, api) { ecModel.eachSeriesByType('graph', function (seriesModel) { var layout = seriesModel.get('layout'); var coordSys = seriesModel.coordinateSystem; if (coordSys && coordSys.type !== 'view') { var data = seriesModel.getData(); data.each(coordSys.dimensions, function (x, y, idx) { if (!isNaN(x) && !isNaN(y)) { data.setItemLayout(idx, coordSys.dataToPoint([x, y])); } else { // Also {Array.}, not undefined to avoid if...else... statement data.setItemLayout(idx, [NaN, NaN]); } }); simpleLayoutEdge(data.graph); } else if (!layout || layout === 'none') { simpleLayoutHelper(seriesModel); } }); }; /***/ }, /* 210 */ /***/ function(module, exports, __webpack_require__) { var simpleLayoutEdge = __webpack_require__(211); module.exports = function (seriesModel) { var coordSys = seriesModel.coordinateSystem; if (coordSys && coordSys.type !== 'view') { return; } var graph = seriesModel.getGraph(); graph.eachNode(function (node) { var model = node.getModel(); node.setLayout([+model.get('x'), +model.get('y')]); }); simpleLayoutEdge(graph); }; /***/ }, /* 211 */ /***/ function(module, exports, __webpack_require__) { var vec2 = __webpack_require__(10); module.exports = function (graph) { graph.eachEdge(function (edge) { var curveness = edge.getModel().get('lineStyle.normal.curveness') || 0; var p1 = vec2.clone(edge.node1.getLayout()); var p2 = vec2.clone(edge.node2.getLayout()); var points = [p1, p2]; if (+curveness) { points.push([ (p1[0] + p2[0]) / 2 - (p1[1] - p2[1]) * curveness, (p1[1] + p2[1]) / 2 - (p2[0] - p1[0]) * curveness ]); } edge.setLayout(points); }); }; /***/ }, /* 212 */ /***/ function(module, exports, __webpack_require__) { var circularLayoutHelper = __webpack_require__(213); module.exports = function (ecModel) { ecModel.eachSeriesByType('graph', function (seriesModel) { if (seriesModel.get('layout') === 'circular') { circularLayoutHelper(seriesModel); } }); }; /***/ }, /* 213 */ /***/ function(module, exports, __webpack_require__) { var vec2 = __webpack_require__(10); module.exports = function (seriesModel) { var coordSys = seriesModel.coordinateSystem; if (coordSys && coordSys.type !== 'view') { return; } var rect = coordSys.getBoundingRect(); var nodeData = seriesModel.getData(); var graph = nodeData.graph; var angle = 0; var sum = nodeData.getSum('value'); var unitAngle = Math.PI * 2 / (sum || nodeData.count()); var cx = rect.width / 2 + rect.x; var cy = rect.height / 2 + rect.y; var r = Math.min(rect.width, rect.height) / 2; graph.eachNode(function (node) { var value = node.getValue('value'); angle += unitAngle * (sum ? value : 1) / 2; node.setLayout([ r * Math.cos(angle) + cx, r * Math.sin(angle) + cy ]); angle += unitAngle * (sum ? value : 1) / 2; }); nodeData.setLayout({ cx: cx, cy: cy }); graph.eachEdge(function (edge) { var curveness = edge.getModel().get('lineStyle.normal.curveness') || 0; var p1 = vec2.clone(edge.node1.getLayout()); var p2 = vec2.clone(edge.node2.getLayout()); var cp1; var x12 = (p1[0] + p2[0]) / 2; var y12 = (p1[1] + p2[1]) / 2; if (+curveness) { curveness *= 3; cp1 = [ cx * curveness + x12 * (1 - curveness), cy * curveness + y12 * (1 - curveness) ]; } edge.setLayout([p1, p2, cp1]); }); }; /***/ }, /* 214 */ /***/ function(module, exports, __webpack_require__) { var forceHelper = __webpack_require__(215); var numberUtil = __webpack_require__(7); var simpleLayoutHelper = __webpack_require__(210); var circularLayoutHelper = __webpack_require__(213); var vec2 = __webpack_require__(10); var zrUtil = __webpack_require__(4); module.exports = function (ecModel) { ecModel.eachSeriesByType('graph', function (graphSeries) { var coordSys = graphSeries.coordinateSystem; if (coordSys && coordSys.type !== 'view') { return; } if (graphSeries.get('layout') === 'force') { var preservedPoints = graphSeries.preservedPoints || {}; var graph = graphSeries.getGraph(); var nodeData = graph.data; var edgeData = graph.edgeData; var forceModel = graphSeries.getModel('force'); var initLayout = forceModel.get('initLayout'); if (graphSeries.preservedPoints) { nodeData.each(function (idx) { var id = nodeData.getId(idx); nodeData.setItemLayout(idx, preservedPoints[id] || [NaN, NaN]); }); } else if (!initLayout || initLayout === 'none') { simpleLayoutHelper(graphSeries); } else if (initLayout === 'circular') { circularLayoutHelper(graphSeries); } var nodeDataExtent = nodeData.getDataExtent('value'); var edgeDataExtent = edgeData.getDataExtent('value'); // var edgeDataExtent = edgeData.getDataExtent('value'); var repulsion = forceModel.get('repulsion'); var edgeLength = forceModel.get('edgeLength'); if (!zrUtil.isArray(repulsion)) { repulsion = [repulsion, repulsion]; } if (!zrUtil.isArray(edgeLength)) { edgeLength = [edgeLength, edgeLength]; } // Larger value has smaller length edgeLength = [edgeLength[1], edgeLength[0]]; var nodes = nodeData.mapArray('value', function (value, idx) { var point = nodeData.getItemLayout(idx); // var w = numberUtil.linearMap(value, nodeDataExtent, [0, 50]); var rep = numberUtil.linearMap(value, nodeDataExtent, repulsion); if (isNaN(rep)) { rep = (repulsion[0] + repulsion[1]) / 2; } return { w: rep, rep: rep, p: (!point || isNaN(point[0]) || isNaN(point[1])) ? null : point }; }); var edges = edgeData.mapArray('value', function (value, idx) { var edge = graph.getEdgeByIndex(idx); var d = numberUtil.linearMap(value, edgeDataExtent, edgeLength); if (isNaN(d)) { d = (edgeLength[0] + edgeLength[1]) / 2; } return { n1: nodes[edge.node1.dataIndex], n2: nodes[edge.node2.dataIndex], d: d, curveness: edge.getModel().get('lineStyle.normal.curveness') || 0 }; }); var coordSys = graphSeries.coordinateSystem; var rect = coordSys.getBoundingRect(); var forceInstance = forceHelper(nodes, edges, { rect: rect, gravity: forceModel.get('gravity') }); var oldStep = forceInstance.step; forceInstance.step = function (cb) { for (var i = 0, l = nodes.length; i < l; i++) { if (nodes[i].fixed) { // Write back to layout instance vec2.copy(nodes[i].p, graph.getNodeByIndex(i).getLayout()); } } oldStep(function (nodes, edges, stopped) { for (var i = 0, l = nodes.length; i < l; i++) { if (!nodes[i].fixed) { graph.getNodeByIndex(i).setLayout(nodes[i].p); } preservedPoints[nodeData.getId(i)] = nodes[i].p; } for (var i = 0, l = edges.length; i < l; i++) { var e = edges[i]; var edge = graph.getEdgeByIndex(i); var p1 = e.n1.p; var p2 = e.n2.p; var points = edge.getLayout(); points = points ? points.slice() : []; points[0] = points[0] || []; points[1] = points[1] || []; vec2.copy(points[0], p1); vec2.copy(points[1], p2); if (+e.curveness) { points[2] = [ (p1[0] + p2[0]) / 2 - (p1[1] - p2[1]) * e.curveness, (p1[1] + p2[1]) / 2 - (p2[0] - p1[0]) * e.curveness ]; } edge.setLayout(points); } // Update layout cb && cb(stopped); }); }; graphSeries.forceLayout = forceInstance; graphSeries.preservedPoints = preservedPoints; // Step to get the layout forceInstance.step(); } else { // Remove prev injected forceLayout instance graphSeries.forceLayout = null; } }); }; /***/ }, /* 215 */ /***/ function(module, exports, __webpack_require__) { var vec2 = __webpack_require__(10); var scaleAndAdd = vec2.scaleAndAdd; // function adjacentNode(n, e) { // return e.n1 === n ? e.n2 : e.n1; // } module.exports = function (nodes, edges, opts) { var rect = opts.rect; var width = rect.width; var height = rect.height; var center = [rect.x + width / 2, rect.y + height / 2]; // var scale = opts.scale || 1; var gravity = opts.gravity == null ? 0.1 : opts.gravity; // for (var i = 0; i < edges.length; i++) { // var e = edges[i]; // var n1 = e.n1; // var n2 = e.n2; // n1.edges = n1.edges || []; // n2.edges = n2.edges || []; // n1.edges.push(e); // n2.edges.push(e); // } // Init position for (var i = 0; i < nodes.length; i++) { var n = nodes[i]; if (!n.p) { // Use the position from first adjecent node with defined position // Or use a random position // From d3 // if (n.edges) { // var j = -1; // while (++j < n.edges.length) { // var e = n.edges[j]; // var other = adjacentNode(n, e); // if (other.p) { // n.p = vec2.clone(other.p); // break; // } // } // } // if (!n.p) { n.p = vec2.create( width * (Math.random() - 0.5) + center[0], height * (Math.random() - 0.5) + center[1] ); // } } n.pp = vec2.clone(n.p); n.edges = null; } // Formula in 'Graph Drawing by Force-directed Placement' // var k = scale * Math.sqrt(width * height / nodes.length); // var k2 = k * k; var friction = 0.6; return { warmUp: function () { friction = 0.5; }, setFixed: function (idx) { nodes[idx].fixed = true; }, setUnfixed: function (idx) { nodes[idx].fixed = false; }, step: function (cb) { var v12 = []; var nLen = nodes.length; for (var i = 0; i < edges.length; i++) { var e = edges[i]; var n1 = e.n1; var n2 = e.n2; vec2.sub(v12, n2.p, n1.p); var d = vec2.len(v12) - e.d; var w = n2.w / (n1.w + n2.w); vec2.normalize(v12, v12); !n1.fixed && scaleAndAdd(n1.p, n1.p, v12, w * d * friction); !n2.fixed && scaleAndAdd(n2.p, n2.p, v12, -(1 - w) * d * friction); } // Gravity for (var i = 0; i < nLen; i++) { var n = nodes[i]; if (!n.fixed) { vec2.sub(v12, center, n.p); // var d = vec2.len(v12); // vec2.scale(v12, v12, 1 / d); // var gravityFactor = gravity; vec2.scaleAndAdd(n.p, n.p, v12, gravity * friction); } } // Repulsive // PENDING for (var i = 0; i < nLen; i++) { var n1 = nodes[i]; for (var j = i + 1; j < nLen; j++) { var n2 = nodes[j]; vec2.sub(v12, n2.p, n1.p); var d = vec2.len(v12); if (d === 0) { // Random repulse vec2.set(v12, Math.random() - 0.5, Math.random() - 0.5); d = 1; } var repFact = (n1.rep + n2.rep) / d / d; !n1.fixed && scaleAndAdd(n1.pp, n1.pp, v12, repFact); !n2.fixed && scaleAndAdd(n2.pp, n2.pp, v12, -repFact); } } var v = []; for (var i = 0; i < nLen; i++) { var n = nodes[i]; if (!n.fixed) { vec2.sub(v, n.p, n.pp); vec2.scaleAndAdd(n.p, n.p, v, friction); vec2.copy(n.pp, n.p); } } friction = friction * 0.992; cb && cb(nodes, edges, friction < 0.01); } }; }; /***/ }, /* 216 */ /***/ function(module, exports, __webpack_require__) { // FIXME Where to create the simple view coordinate system var View = __webpack_require__(170); var layout = __webpack_require__(21); var bbox = __webpack_require__(51); function getViewRect(seriesModel, api, aspect) { var option = seriesModel.getBoxLayoutParams(); option.aspect = aspect; return layout.getLayoutRect(option, { width: api.getWidth(), height: api.getHeight() }); } module.exports = function (ecModel, api) { var viewList = []; ecModel.eachSeriesByType('graph', function (seriesModel) { var coordSysType = seriesModel.get('coordinateSystem'); if (!coordSysType || coordSysType === 'view') { var data = seriesModel.getData(); var positions = data.mapArray(function (idx) { var itemModel = data.getItemModel(idx); return [+itemModel.get('x'), +itemModel.get('y')]; }); var min = []; var max = []; bbox.fromPoints(positions, min, max); // If width or height is 0 if (max[0] - min[0] === 0) { max[0] += 1; min[0] -= 1; } if (max[1] - min[1] === 0) { max[1] += 1; min[1] -= 1; } var aspect = (max[0] - min[0]) / (max[1] - min[1]); // FIXME If get view rect after data processed? var viewRect = getViewRect(seriesModel, api, aspect); // Position may be NaN, use view rect instead if (isNaN(aspect)) { min = [viewRect.x, viewRect.y]; max = [viewRect.x + viewRect.width, viewRect.y + viewRect.height]; } var bbWidth = max[0] - min[0]; var bbHeight = max[1] - min[1]; var viewWidth = viewRect.width; var viewHeight = viewRect.height; var viewCoordSys = seriesModel.coordinateSystem = new View(); viewCoordSys.zoomLimit = seriesModel.get('scaleLimit'); viewCoordSys.setBoundingRect( min[0], min[1], bbWidth, bbHeight ); viewCoordSys.setViewRect( viewRect.x, viewRect.y, viewWidth, viewHeight ); // Update roam info viewCoordSys.setCenter(seriesModel.get('center')); viewCoordSys.setZoom(seriesModel.get('zoom')); viewList.push(viewCoordSys); } }); return viewList; }; /***/ }, /* 217 */ /***/ function(module, exports, __webpack_require__) { __webpack_require__(218); __webpack_require__(219); /***/ }, /* 218 */ /***/ function(module, exports, __webpack_require__) { var List = __webpack_require__(98); var SeriesModel = __webpack_require__(28); var zrUtil = __webpack_require__(4); var GaugeSeries = SeriesModel.extend({ type: 'series.gauge', getInitialData: function (option, ecModel) { var list = new List(['value'], this); var dataOpt = option.data || []; if (!zrUtil.isArray(dataOpt)) { dataOpt = [dataOpt]; } // Only use the first data item list.initData(dataOpt); return list; }, defaultOption: { zlevel: 0, z: 2, // 默认全局居中 center: ['50%', '50%'], legendHoverLink: true, radius: '75%', startAngle: 225, endAngle: -45, clockwise: true, // 最小值 min: 0, // 最大值 max: 100, // 分割段数,默认为10 splitNumber: 10, // 坐标轴线 axisLine: { // 默认显示,属性show控制显示与否 show: true, lineStyle: { // 属性lineStyle控制线条样式 color: [[0.2, '#91c7ae'], [0.8, '#63869e'], [1, '#c23531']], width: 30 } }, // 分隔线 splitLine: { // 默认显示,属性show控制显示与否 show: true, // 属性length控制线长 length: 30, // 属性lineStyle(详见lineStyle)控制线条样式 lineStyle: { color: '#eee', width: 2, type: 'solid' } }, // 坐标轴小标记 axisTick: { // 属性show控制显示与否,默认不显示 show: true, // 每份split细分多少段 splitNumber: 5, // 属性length控制线长 length: 8, // 属性lineStyle控制线条样式 lineStyle: { color: '#eee', width: 1, type: 'solid' } }, axisLabel: { show: true, distance: 5, // formatter: null, textStyle: { // 其余属性默认使用全局文本样式,详见TEXTSTYLE color: 'auto' } }, pointer: { show: true, length: '80%', width: 8 }, itemStyle: { normal: { color: 'auto' } }, title: { show: true, // x, y,单位px offsetCenter: [0, '-40%'], // 其余属性默认使用全局文本样式,详见TEXTSTYLE textStyle: { color: '#333', fontSize: 15 } }, detail: { show: true, backgroundColor: 'rgba(0,0,0,0)', borderWidth: 0, borderColor: '#ccc', width: 100, height: 40, // x, y,单位px offsetCenter: [0, '40%'], // formatter: null, // 其余属性默认使用全局文本样式,详见TEXTSTYLE textStyle: { color: 'auto', fontSize: 30 } } } }); module.exports = GaugeSeries; /***/ }, /* 219 */ /***/ function(module, exports, __webpack_require__) { var PointerPath = __webpack_require__(220); var graphic = __webpack_require__(43); var numberUtil = __webpack_require__(7); var parsePercent = numberUtil.parsePercent; function parsePosition(seriesModel, api) { var center = seriesModel.get('center'); var width = api.getWidth(); var height = api.getHeight(); var size = Math.min(width, height); var cx = parsePercent(center[0], api.getWidth()); var cy = parsePercent(center[1], api.getHeight()); var r = parsePercent(seriesModel.get('radius'), size / 2); return { cx: cx, cy: cy, r: r }; } function formatLabel(label, labelFormatter) { if (labelFormatter) { if (typeof labelFormatter === 'string') { label = labelFormatter.replace('{value}', label != null ? label : ''); } else if (typeof labelFormatter === 'function') { label = labelFormatter(label); } } return label; } var PI2 = Math.PI * 2; var GaugeView = __webpack_require__(42).extend({ type: 'gauge', render: function (seriesModel, ecModel, api) { this.group.removeAll(); var colorList = seriesModel.get('axisLine.lineStyle.color'); var posInfo = parsePosition(seriesModel, api); this._renderMain( seriesModel, ecModel, api, colorList, posInfo ); }, dispose: function () {}, _renderMain: function (seriesModel, ecModel, api, colorList, posInfo) { var group = this.group; var axisLineModel = seriesModel.getModel('axisLine'); var lineStyleModel = axisLineModel.getModel('lineStyle'); var clockwise = seriesModel.get('clockwise'); var startAngle = -seriesModel.get('startAngle') / 180 * Math.PI; var endAngle = -seriesModel.get('endAngle') / 180 * Math.PI; var angleRangeSpan = (endAngle - startAngle) % PI2; var prevEndAngle = startAngle; var axisLineWidth = lineStyleModel.get('width'); for (var i = 0; i < colorList.length; i++) { // Clamp var percent = Math.min(Math.max(colorList[i][0], 0), 1); var endAngle = startAngle + angleRangeSpan * percent; var sector = new graphic.Sector({ shape: { startAngle: prevEndAngle, endAngle: endAngle, cx: posInfo.cx, cy: posInfo.cy, clockwise: clockwise, r0: posInfo.r - axisLineWidth, r: posInfo.r }, silent: true }); sector.setStyle({ fill: colorList[i][1] }); sector.setStyle(lineStyleModel.getLineStyle( // Because we use sector to simulate arc // so the properties for stroking are useless ['color', 'borderWidth', 'borderColor'] )); group.add(sector); prevEndAngle = endAngle; } var getColor = function (percent) { // Less than 0 if (percent <= 0) { return colorList[0][1]; } for (var i = 0; i < colorList.length; i++) { if (colorList[i][0] >= percent && (i === 0 ? 0 : colorList[i - 1][0]) < percent ) { return colorList[i][1]; } } // More than 1 return colorList[i - 1][1]; }; if (!clockwise) { var tmp = startAngle; startAngle = endAngle; endAngle = tmp; } this._renderTicks( seriesModel, ecModel, api, getColor, posInfo, startAngle, endAngle, clockwise ); this._renderPointer( seriesModel, ecModel, api, getColor, posInfo, startAngle, endAngle, clockwise ); this._renderTitle( seriesModel, ecModel, api, getColor, posInfo ); this._renderDetail( seriesModel, ecModel, api, getColor, posInfo ); }, _renderTicks: function ( seriesModel, ecModel, api, getColor, posInfo, startAngle, endAngle, clockwise ) { var group = this.group; var cx = posInfo.cx; var cy = posInfo.cy; var r = posInfo.r; var minVal = seriesModel.get('min'); var maxVal = seriesModel.get('max'); var splitLineModel = seriesModel.getModel('splitLine'); var tickModel = seriesModel.getModel('axisTick'); var labelModel = seriesModel.getModel('axisLabel'); var splitNumber = seriesModel.get('splitNumber'); var subSplitNumber = tickModel.get('splitNumber'); var splitLineLen = parsePercent( splitLineModel.get('length'), r ); var tickLen = parsePercent( tickModel.get('length'), r ); var angle = startAngle; var step = (endAngle - startAngle) / splitNumber; var subStep = step / subSplitNumber; var splitLineStyle = splitLineModel.getModel('lineStyle').getLineStyle(); var tickLineStyle = tickModel.getModel('lineStyle').getLineStyle(); var textStyleModel = labelModel.getModel('textStyle'); for (var i = 0; i <= splitNumber; i++) { var unitX = Math.cos(angle); var unitY = Math.sin(angle); // Split line if (splitLineModel.get('show')) { var splitLine = new graphic.Line({ shape: { x1: unitX * r + cx, y1: unitY * r + cy, x2: unitX * (r - splitLineLen) + cx, y2: unitY * (r - splitLineLen) + cy }, style: splitLineStyle, silent: true }); if (splitLineStyle.stroke === 'auto') { splitLine.setStyle({ stroke: getColor(i / splitNumber) }); } group.add(splitLine); } // Label if (labelModel.get('show')) { var label = formatLabel( numberUtil.round(i / splitNumber * (maxVal - minVal) + minVal), labelModel.get('formatter') ); var distance = labelModel.get('distance'); var text = new graphic.Text({ style: { text: label, x: unitX * (r - splitLineLen - distance) + cx, y: unitY * (r - splitLineLen - distance) + cy, fill: textStyleModel.getTextColor(), textFont: textStyleModel.getFont(), textVerticalAlign: unitY < -0.4 ? 'top' : (unitY > 0.4 ? 'bottom' : 'middle'), textAlign: unitX < -0.4 ? 'left' : (unitX > 0.4 ? 'right' : 'center') }, silent: true }); if (text.style.fill === 'auto') { text.setStyle({ fill: getColor(i / splitNumber) }); } group.add(text); } // Axis tick if (tickModel.get('show') && i !== splitNumber) { for (var j = 0; j <= subSplitNumber; j++) { var unitX = Math.cos(angle); var unitY = Math.sin(angle); var tickLine = new graphic.Line({ shape: { x1: unitX * r + cx, y1: unitY * r + cy, x2: unitX * (r - tickLen) + cx, y2: unitY * (r - tickLen) + cy }, silent: true, style: tickLineStyle }); if (tickLineStyle.stroke === 'auto') { tickLine.setStyle({ stroke: getColor((i + j / subSplitNumber) / splitNumber) }); } group.add(tickLine); angle += subStep; } angle -= subStep; } else { angle += step; } } }, _renderPointer: function ( seriesModel, ecModel, api, getColor, posInfo, startAngle, endAngle, clockwise ) { var valueExtent = [+seriesModel.get('min'), +seriesModel.get('max')]; var angleExtent = [startAngle, endAngle]; var data = seriesModel.getData(); var oldData = this._data; var group = this.group; data.diff(oldData) .add(function (idx) { var pointer = new PointerPath({ shape: { angle: startAngle } }); graphic.updateProps(pointer, { shape: { angle: numberUtil.linearMap(data.get('value', idx), valueExtent, angleExtent, true) } }, seriesModel); group.add(pointer); data.setItemGraphicEl(idx, pointer); }) .update(function (newIdx, oldIdx) { var pointer = oldData.getItemGraphicEl(oldIdx); graphic.updateProps(pointer, { shape: { angle: numberUtil.linearMap(data.get('value', newIdx), valueExtent, angleExtent, true) } }, seriesModel); group.add(pointer); data.setItemGraphicEl(newIdx, pointer); }) .remove(function (idx) { var pointer = oldData.getItemGraphicEl(idx); group.remove(pointer); }) .execute(); data.eachItemGraphicEl(function (pointer, idx) { var itemModel = data.getItemModel(idx); var pointerModel = itemModel.getModel('pointer'); pointer.setShape({ x: posInfo.cx, y: posInfo.cy, width: parsePercent( pointerModel.get('width'), posInfo.r ), r: parsePercent(pointerModel.get('length'), posInfo.r) }); pointer.useStyle(itemModel.getModel('itemStyle.normal').getItemStyle()); if (pointer.style.fill === 'auto') { pointer.setStyle('fill', getColor( (data.get('value', idx) - valueExtent[0]) / (valueExtent[1] - valueExtent[0]) )); } graphic.setHoverStyle( pointer, itemModel.getModel('itemStyle.emphasis').getItemStyle() ); }); this._data = data; }, _renderTitle: function ( seriesModel, ecModel, api, getColor, posInfo ) { var titleModel = seriesModel.getModel('title'); if (titleModel.get('show')) { var textStyleModel = titleModel.getModel('textStyle'); var offsetCenter = titleModel.get('offsetCenter'); var x = posInfo.cx + parsePercent(offsetCenter[0], posInfo.r); var y = posInfo.cy + parsePercent(offsetCenter[1], posInfo.r); var text = new graphic.Text({ style: { x: x, y: y, // FIXME First data name ? text: seriesModel.getData().getName(0), fill: textStyleModel.getTextColor(), textFont: textStyleModel.getFont(), textAlign: 'center', textVerticalAlign: 'middle' } }); this.group.add(text); } }, _renderDetail: function ( seriesModel, ecModel, api, getColor, posInfo ) { var detailModel = seriesModel.getModel('detail'); var minVal = seriesModel.get('min'); var maxVal = seriesModel.get('max'); if (detailModel.get('show')) { var textStyleModel = detailModel.getModel('textStyle'); var offsetCenter = detailModel.get('offsetCenter'); var x = posInfo.cx + parsePercent(offsetCenter[0], posInfo.r); var y = posInfo.cy + parsePercent(offsetCenter[1], posInfo.r); var width = parsePercent(detailModel.get('width'), posInfo.r); var height = parsePercent(detailModel.get('height'), posInfo.r); var value = seriesModel.getData().get('value', 0); var rect = new graphic.Rect({ shape: { x: x - width / 2, y: y - height / 2, width: width, height: height }, style: { text: formatLabel( // FIXME First data name ? value, detailModel.get('formatter') ), fill: detailModel.get('backgroundColor'), textFill: textStyleModel.getTextColor(), textFont: textStyleModel.getFont() } }); if (rect.style.textFill === 'auto') { rect.setStyle('textFill', getColor( numberUtil.linearMap(value, [minVal, maxVal], [0, 1], true) )); } rect.setStyle(detailModel.getItemStyle(['color'])); this.group.add(rect); } } }); module.exports = GaugeView; /***/ }, /* 220 */ /***/ function(module, exports, __webpack_require__) { module.exports = __webpack_require__(45).extend({ type: 'echartsGaugePointer', shape: { angle: 0, width: 10, r: 10, x: 0, y: 0 }, buildPath: function (ctx, shape) { var mathCos = Math.cos; var mathSin = Math.sin; var r = shape.r; var width = shape.width; var angle = shape.angle; var x = shape.x - mathCos(angle) * width * (width >= r / 3 ? 1 : 2); var y = shape.y - mathSin(angle) * width * (width >= r / 3 ? 1 : 2); angle = shape.angle - Math.PI / 2; ctx.moveTo(x, y); ctx.lineTo( shape.x + mathCos(angle) * width, shape.y + mathSin(angle) * width ); ctx.lineTo( shape.x + mathCos(shape.angle) * r, shape.y + mathSin(shape.angle) * r ); ctx.lineTo( shape.x - mathCos(angle) * width, shape.y - mathSin(angle) * width ); ctx.lineTo(x, y); return; } }); /***/ }, /* 221 */ /***/ function(module, exports, __webpack_require__) { var zrUtil = __webpack_require__(4); var echarts = __webpack_require__(1); __webpack_require__(222); __webpack_require__(223); echarts.registerVisual(zrUtil.curry(__webpack_require__(145), 'funnel')); echarts.registerLayout(__webpack_require__(224)); echarts.registerProcessor(zrUtil.curry(__webpack_require__(148), 'funnel')); /***/ }, /* 222 */ /***/ function(module, exports, __webpack_require__) { 'use strict'; var List = __webpack_require__(98); var modelUtil = __webpack_require__(5); var completeDimensions = __webpack_require__(103); var FunnelSeries = __webpack_require__(1).extendSeriesModel({ type: 'series.funnel', init: function (option) { FunnelSeries.superApply(this, 'init', arguments); // Enable legend selection for each data item // Use a function instead of direct access because data reference may changed this.legendDataProvider = function () { return this._dataBeforeProcessed; }; // Extend labelLine emphasis this._defaultLabelLine(option); }, getInitialData: function (option, ecModel) { var dimensions = completeDimensions(['value'], option.data); var list = new List(dimensions, this); list.initData(option.data); return list; }, _defaultLabelLine: function (option) { // Extend labelLine emphasis modelUtil.defaultEmphasis(option.labelLine, ['show']); var labelLineNormalOpt = option.labelLine.normal; var labelLineEmphasisOpt = option.labelLine.emphasis; // Not show label line if `label.normal.show = false` labelLineNormalOpt.show = labelLineNormalOpt.show && option.label.normal.show; labelLineEmphasisOpt.show = labelLineEmphasisOpt.show && option.label.emphasis.show; }, defaultOption: { zlevel: 0, // 一级层叠 z: 2, // 二级层叠 legendHoverLink: true, left: 80, top: 60, right: 80, bottom: 60, // width: {totalWidth} - left - right, // height: {totalHeight} - top - bottom, // 默认取数据最小最大值 // min: 0, // max: 100, minSize: '0%', maxSize: '100%', sort: 'descending', // 'ascending', 'descending' gap: 0, funnelAlign: 'center', label: { normal: { show: true, position: 'outer' // formatter: 标签文本格式器,同Tooltip.formatter,不支持异步回调 // textStyle: null // 默认使用全局文本样式,详见TEXTSTYLE }, emphasis: { show: true } }, labelLine: { normal: { show: true, length: 20, lineStyle: { // color: 各异, width: 1, type: 'solid' } }, emphasis: {} }, itemStyle: { normal: { // color: 各异, borderColor: '#fff', borderWidth: 1 }, emphasis: { // color: 各异, } } } }); module.exports = FunnelSeries; /***/ }, /* 223 */ /***/ function(module, exports, __webpack_require__) { var graphic = __webpack_require__(43); var zrUtil = __webpack_require__(4); /** * Piece of pie including Sector, Label, LabelLine * @constructor * @extends {module:zrender/graphic/Group} */ function FunnelPiece(data, idx) { graphic.Group.call(this); var polygon = new graphic.Polygon(); var labelLine = new graphic.Polyline(); var text = new graphic.Text(); this.add(polygon); this.add(labelLine); this.add(text); this.updateData(data, idx, true); // Hover to change label and labelLine function onEmphasis() { labelLine.ignore = labelLine.hoverIgnore; text.ignore = text.hoverIgnore; } function onNormal() { labelLine.ignore = labelLine.normalIgnore; text.ignore = text.normalIgnore; } this.on('emphasis', onEmphasis) .on('normal', onNormal) .on('mouseover', onEmphasis) .on('mouseout', onNormal); } var funnelPieceProto = FunnelPiece.prototype; function getLabelStyle(data, idx, state, labelModel) { var textStyleModel = labelModel.getModel('textStyle'); var position = labelModel.get('position'); var isLabelInside = position === 'inside' || position === 'inner' || position === 'center'; return { fill: textStyleModel.getTextColor() || (isLabelInside ? '#fff' : data.getItemVisual(idx, 'color')), textFont: textStyleModel.getFont(), text: zrUtil.retrieve( data.hostModel.getFormattedLabel(idx, state), data.getName(idx) ) }; } var opacityAccessPath = ['itemStyle', 'normal', 'opacity']; funnelPieceProto.updateData = function (data, idx, firstCreate) { var polygon = this.childAt(0); var seriesModel = data.hostModel; var itemModel = data.getItemModel(idx); var layout = data.getItemLayout(idx); var opacity = data.getItemModel(idx).get(opacityAccessPath); opacity = opacity == null ? 1 : opacity; // Reset style polygon.useStyle({}); if (firstCreate) { polygon.setShape({ points: layout.points }); polygon.setStyle({ opacity : 0 }); graphic.initProps(polygon, { style: { opacity: opacity } }, seriesModel, idx); } else { graphic.updateProps(polygon, { style: { opacity: opacity }, shape: { points: layout.points } }, seriesModel, idx); } // Update common style var itemStyleModel = itemModel.getModel('itemStyle'); var visualColor = data.getItemVisual(idx, 'color'); polygon.setStyle( zrUtil.defaults( { lineJoin: 'round', fill: visualColor }, itemStyleModel.getModel('normal').getItemStyle(['opacity']) ) ); polygon.hoverStyle = itemStyleModel.getModel('emphasis').getItemStyle(); this._updateLabel(data, idx); graphic.setHoverStyle(this); }; funnelPieceProto._updateLabel = function (data, idx) { var labelLine = this.childAt(1); var labelText = this.childAt(2); var seriesModel = data.hostModel; var itemModel = data.getItemModel(idx); var layout = data.getItemLayout(idx); var labelLayout = layout.label; var visualColor = data.getItemVisual(idx, 'color'); graphic.updateProps(labelLine, { shape: { points: labelLayout.linePoints || labelLayout.linePoints } }, seriesModel, idx); graphic.updateProps(labelText, { style: { x: labelLayout.x, y: labelLayout.y } }, seriesModel, idx); labelText.attr({ style: { textAlign: labelLayout.textAlign, textVerticalAlign: labelLayout.verticalAlign, textFont: labelLayout.font }, rotation: labelLayout.rotation, origin: [labelLayout.x, labelLayout.y], z2: 10 }); var labelModel = itemModel.getModel('label.normal'); var labelHoverModel = itemModel.getModel('label.emphasis'); var labelLineModel = itemModel.getModel('labelLine.normal'); var labelLineHoverModel = itemModel.getModel('labelLine.emphasis'); labelText.setStyle(getLabelStyle(data, idx, 'normal', labelModel)); labelText.ignore = labelText.normalIgnore = !labelModel.get('show'); labelText.hoverIgnore = !labelHoverModel.get('show'); labelLine.ignore = labelLine.normalIgnore = !labelLineModel.get('show'); labelLine.hoverIgnore = !labelLineHoverModel.get('show'); // Default use item visual color labelLine.setStyle({ stroke: visualColor }); labelLine.setStyle(labelLineModel.getModel('lineStyle').getLineStyle()); labelText.hoverStyle = getLabelStyle(data, idx, 'emphasis', labelHoverModel); labelLine.hoverStyle = labelLineHoverModel.getModel('lineStyle').getLineStyle(); }; zrUtil.inherits(FunnelPiece, graphic.Group); var Funnel = __webpack_require__(42).extend({ type: 'funnel', render: function (seriesModel, ecModel, api) { var data = seriesModel.getData(); var oldData = this._data; var group = this.group; data.diff(oldData) .add(function (idx) { var funnelPiece = new FunnelPiece(data, idx); data.setItemGraphicEl(idx, funnelPiece); group.add(funnelPiece); }) .update(function (newIdx, oldIdx) { var piePiece = oldData.getItemGraphicEl(oldIdx); piePiece.updateData(data, newIdx); group.add(piePiece); data.setItemGraphicEl(newIdx, piePiece); }) .remove(function (idx) { var piePiece = oldData.getItemGraphicEl(idx); group.remove(piePiece); }) .execute(); this._data = data; }, remove: function () { this.group.removeAll(); this._data = null; }, dispose: function () {} }); module.exports = Funnel; /***/ }, /* 224 */ /***/ function(module, exports, __webpack_require__) { var layout = __webpack_require__(21); var number = __webpack_require__(7); var parsePercent = number.parsePercent; function getViewRect(seriesModel, api) { return layout.getLayoutRect( seriesModel.getBoxLayoutParams(), { width: api.getWidth(), height: api.getHeight() } ); } function getSortedIndices(data, sort) { var valueArr = data.mapArray('value', function (val) { return val; }); var indices = []; var isAscending = sort === 'ascending'; for (var i = 0, len = data.count(); i < len; i++) { indices[i] = i; } indices.sort(function (a, b) { return isAscending ? valueArr[a] - valueArr[b] : valueArr[b] - valueArr[a]; }); return indices; } function labelLayout (data) { data.each(function (idx) { var itemModel = data.getItemModel(idx); var labelModel = itemModel.getModel('label.normal'); var labelPosition = labelModel.get('position'); var labelLineModel = itemModel.getModel('labelLine.normal'); var layout = data.getItemLayout(idx); var points = layout.points; var isLabelInside = labelPosition === 'inner' || labelPosition === 'inside' || labelPosition === 'center'; var textAlign; var textX; var textY; var linePoints; if (isLabelInside) { textX = (points[0][0] + points[1][0] + points[2][0] + points[3][0]) / 4; textY = (points[0][1] + points[1][1] + points[2][1] + points[3][1]) / 4; textAlign = 'center'; linePoints = [ [textX, textY], [textX, textY] ]; } else { var x1; var y1; var x2; var labelLineLen = labelLineModel.get('length'); if (labelPosition === 'left') { // Left side x1 = (points[3][0] + points[0][0]) / 2; y1 = (points[3][1] + points[0][1]) / 2; x2 = x1 - labelLineLen; textX = x2 - 5; textAlign = 'right'; } else { // Right side x1 = (points[1][0] + points[2][0]) / 2; y1 = (points[1][1] + points[2][1]) / 2; x2 = x1 + labelLineLen; textX = x2 + 5; textAlign = 'left'; } var y2 = y1; linePoints = [[x1, y1], [x2, y2]]; textY = y2; } layout.label = { linePoints: linePoints, x: textX, y: textY, verticalAlign: 'middle', textAlign: textAlign, inside: isLabelInside }; }); } module.exports = function (ecModel, api, payload) { ecModel.eachSeriesByType('funnel', function (seriesModel) { var data = seriesModel.getData(); var sort = seriesModel.get('sort'); var viewRect = getViewRect(seriesModel, api); var indices = getSortedIndices(data, sort); var sizeExtent = [ parsePercent(seriesModel.get('minSize'), viewRect.width), parsePercent(seriesModel.get('maxSize'), viewRect.width) ]; var dataExtent = data.getDataExtent('value'); var min = seriesModel.get('min'); var max = seriesModel.get('max'); if (min == null) { min = Math.min(dataExtent[0], 0); } if (max == null) { max = dataExtent[1]; } var funnelAlign = seriesModel.get('funnelAlign'); var gap = seriesModel.get('gap'); var itemHeight = (viewRect.height - gap * (data.count() - 1)) / data.count(); var y = viewRect.y; var getLinePoints = function (idx, offY) { // End point index is data.count() and we assign it 0 var val = data.get('value', idx) || 0; var itemWidth = number.linearMap(val, [min, max], sizeExtent, true); var x0; switch (funnelAlign) { case 'left': x0 = viewRect.x; break; case 'center': x0 = viewRect.x + (viewRect.width - itemWidth) / 2; break; case 'right': x0 = viewRect.x + viewRect.width - itemWidth; break; } return [ [x0, offY], [x0 + itemWidth, offY] ]; }; if (sort === 'ascending') { // From bottom to top itemHeight = -itemHeight; gap = -gap; y += viewRect.height; indices = indices.reverse(); } for (var i = 0; i < indices.length; i++) { var idx = indices[i]; var nextIdx = indices[i + 1]; var start = getLinePoints(idx, y); var end = getLinePoints(nextIdx, y + itemHeight); y += itemHeight + gap; data.setItemLayout(idx, { points: start.concat(end.slice().reverse()) }); } labelLayout(data); }); }; /***/ }, /* 225 */ /***/ function(module, exports, __webpack_require__) { var echarts = __webpack_require__(1); __webpack_require__(226); __webpack_require__(237); __webpack_require__(238); echarts.registerVisual(__webpack_require__(239)); /***/ }, /* 226 */ /***/ function(module, exports, __webpack_require__) { __webpack_require__(227); __webpack_require__(230); __webpack_require__(232); var echarts = __webpack_require__(1); var zrUtil = __webpack_require__(4); var CLICK_THRESHOLD = 5; // > 4 // Parallel view echarts.extendComponentView({ type: 'parallel', render: function (parallelModel, ecModel, api) { var zr = api.getZr(); if (!this.__onMouseDown) { // FIXME // click: mousemove check. otherwise confilct with drag brush. var mousedownPoint; zr.on('mousedown', this.__onMouseDown = function (e) { mousedownPoint = [e.offsetX, e.offsetY]; }); zr.on('mouseup', this.__onMouseUp = function (e) { var point = [e.offsetX, e.offsetY]; var dist = Math.pow(mousedownPoint[0] - point[0], 2) + Math.pow(mousedownPoint[1] - point[1], 2); if (!parallelModel.get('axisExpandable') || dist > CLICK_THRESHOLD) { return; } var coordSys = parallelModel.coordinateSystem; var closestDim = coordSys.findClosestAxisDim(point); if (closestDim) { var axisIndex = zrUtil.indexOf(coordSys.dimensions, closestDim); api.dispatchAction({ type: 'parallelAxisExpand', axisExpandCenter: axisIndex }); } }); } }, dispose: function (ecModel, api) { api.getZr().off(this.__onMouseDown); api.getZr().off(this.__onMouseUp); } }); echarts.registerPreprocessor( __webpack_require__(236) ); /***/ }, /* 227 */ /***/ function(module, exports, __webpack_require__) { /** * Parallel coordinate system creater. */ var Parallel = __webpack_require__(228); function create(ecModel, api) { var coordSysList = []; ecModel.eachComponent('parallel', function (parallelModel, idx) { var coordSys = new Parallel(parallelModel, ecModel, api); coordSys.name = 'parallel_' + idx; coordSys.resize(parallelModel, api); parallelModel.coordinateSystem = coordSys; coordSys.model = parallelModel; coordSysList.push(coordSys); }); // Inject the coordinateSystems into seriesModel ecModel.eachSeries(function (seriesModel) { if (seriesModel.get('coordinateSystem') === 'parallel') { var parallelModel = ecModel.queryComponents({ mainType: 'parallel', index: seriesModel.get('parallelIndex'), id: seriesModel.get('parallelId') })[0]; seriesModel.coordinateSystem = parallelModel.coordinateSystem; } }); return coordSysList; } __webpack_require__(26).register('parallel', {create: create}); /***/ }, /* 228 */ /***/ function(module, exports, __webpack_require__) { /** * Parallel Coordinates * */ var layout = __webpack_require__(21); var axisHelper = __webpack_require__(115); var zrUtil = __webpack_require__(4); var ParallelAxis = __webpack_require__(229); var graphic = __webpack_require__(43); var matrix = __webpack_require__(11); var each = zrUtil.each; var PI = Math.PI; function Parallel(parallelModel, ecModel, api) { /** * key: dimension * @type {Object.} * @private */ this._axesMap = {}; /** * key: dimension * value: {position: [], rotation, } * @type {Object.} * @private */ this._axesLayout = {}; /** * Always follow axis order. * @type {Array.} * @readOnly */ this.dimensions = parallelModel.dimensions; /** * @type {module:zrender/core/BoundingRect} */ this._rect; /** * @type {module:echarts/coord/parallel/ParallelModel} */ this._model = parallelModel; this._init(parallelModel, ecModel, api); } Parallel.prototype = { type: 'parallel', constructor: Parallel, /** * Initialize cartesian coordinate systems * @private */ _init: function (parallelModel, ecModel, api) { var dimensions = parallelModel.dimensions; var parallelAxisIndex = parallelModel.parallelAxisIndex; each(dimensions, function (dim, idx) { var axisIndex = parallelAxisIndex[idx]; var axisModel = ecModel.getComponent('parallelAxis', axisIndex); var axis = this._axesMap[dim] = new ParallelAxis( dim, axisHelper.createScaleByModel(axisModel), [0, 0], axisModel.get('type'), axisIndex ); var isCategory = axis.type === 'category'; axis.onBand = isCategory && axisModel.get('boundaryGap'); axis.inverse = axisModel.get('inverse'); // Inject axis into axisModel axisModel.axis = axis; // Inject axisModel into axis axis.model = axisModel; }, this); }, /** * Update axis scale after data processed * @param {module:echarts/model/Global} ecModel * @param {module:echarts/ExtensionAPI} api */ update: function (ecModel, api) { this._updateAxesFromSeries(this._model, ecModel); }, /** * Update properties from series * @private */ _updateAxesFromSeries: function (parallelModel, ecModel) { ecModel.eachSeries(function (seriesModel) { if (!parallelModel.contains(seriesModel, ecModel)) { return; } var data = seriesModel.getData(); each(this.dimensions, function (dim) { var axis = this._axesMap[dim]; axis.scale.unionExtent(data.getDataExtent(dim)); axisHelper.niceScaleExtent(axis, axis.model); }, this); }, this); }, /** * Resize the parallel coordinate system. * @param {module:echarts/coord/parallel/ParallelModel} parallelModel * @param {module:echarts/ExtensionAPI} api */ resize: function (parallelModel, api) { this._rect = layout.getLayoutRect( parallelModel.getBoxLayoutParams(), { width: api.getWidth(), height: api.getHeight() } ); this._layoutAxes(parallelModel); }, /** * @return {module:zrender/core/BoundingRect} */ getRect: function () { return this._rect; }, /** * @private */ _layoutAxes: function (parallelModel) { var rect = this._rect; var layout = parallelModel.get('layout'); var axes = this._axesMap; var dimensions = this.dimensions; var size = [rect.width, rect.height]; var sizeIdx = layout === 'horizontal' ? 0 : 1; var layoutLength = size[sizeIdx]; var axisLength = size[1 - sizeIdx]; var axisExtent = [0, axisLength]; each(axes, function (axis) { var idx = axis.inverse ? 1 : 0; axis.setExtent(axisExtent[idx], axisExtent[1 - idx]); }); var axisExpandable = parallelModel.get('axisExpandable'); var axisExpandWidth = parallelModel.get('axisExpandWidth'); var axisExpandCenter = parallelModel.get('axisExpandCenter'); var axisExpandCount = parallelModel.get('axisExpandCount') || 0; var axisExpandWindow; if (axisExpandCenter != null) { // Clamp var left = Math.max(0, Math.floor(axisExpandCenter - (axisExpandCount - 1) / 2)); var right = left + axisExpandCount - 1; if (right >= dimensions.length) { right = dimensions.length - 1; left = Math.max(0, Math.floor(right - axisExpandCount + 1)); } axisExpandWindow = [left, right]; } var calcPos = (axisExpandable && axisExpandWindow && axisExpandWidth) ? function (axisIndex, layoutLength, axisCount) { var peekIntervalCount = axisExpandWindow[1] - axisExpandWindow[0]; var otherWidth = ( layoutLength - axisExpandWidth * peekIntervalCount ) / (axisCount - 1 - peekIntervalCount); var position; if (axisIndex < axisExpandWindow[0]) { position = (axisIndex - 1) * otherWidth; } else if (axisIndex <= axisExpandWindow[1]) { position = axisExpandWindow[0] * otherWidth + (axisIndex - axisExpandWindow[0]) * axisExpandWidth; } else if (axisIndex === axisCount - 1) { position = layoutLength; } else { position = axisExpandWindow[0] * otherWidth + peekIntervalCount * axisExpandWidth + (axisIndex - axisExpandWindow[1]) * otherWidth; } return { position: position, axisNameAvailableWidth: ( axisExpandWindow[0] < axisIndex && axisIndex < axisExpandWindow[1] ) ? axisExpandWidth : otherWidth }; } : function (axisIndex, layoutLength, axisCount) { var step = layoutLength / (axisCount - 1); return { position: step * axisIndex, axisNameAvailableWidth: step }; }; each(dimensions, function (dim, idx) { var posInfo = calcPos(idx, layoutLength, dimensions.length); var positionTable = { horizontal: { x: posInfo.position, y: axisLength }, vertical: { x: 0, y: posInfo.position } }; var rotationTable = { horizontal: PI / 2, vertical: 0 }; var position = [ positionTable[layout].x + rect.x, positionTable[layout].y + rect.y ]; var rotation = rotationTable[layout]; var transform = matrix.create(); matrix.rotate(transform, transform, rotation); matrix.translate(transform, transform, position); // TODO // tick等排布信息。 // TODO // 根据axis order 更新 dimensions顺序。 this._axesLayout[dim] = { position: position, rotation: rotation, transform: transform, axisNameAvailableWidth: posInfo.axisNameAvailableWidth, tickDirection: 1, labelDirection: 1, axisExpandWindow: axisExpandWindow }; }, this); }, /** * Get axis by dim. * @param {string} dim * @return {module:echarts/coord/parallel/ParallelAxis} [description] */ getAxis: function (dim) { return this._axesMap[dim]; }, /** * Convert a dim value of a single item of series data to Point. * @param {*} value * @param {string} dim * @return {Array} */ dataToPoint: function (value, dim) { return this.axisCoordToPoint( this._axesMap[dim].dataToCoord(value), dim ); }, /** * Travel data for one time, get activeState of each data item. * @param {module:echarts/data/List} data * @param {Functio} cb param: {string} activeState 'active' or 'inactive' or 'normal' * {number} dataIndex * @param {Object} context */ eachActiveState: function (data, callback, context) { var dimensions = this.dimensions; var axesMap = this._axesMap; var hasActiveSet = this.hasAxisbrushed(); for (var i = 0, len = data.count(); i < len; i++) { var values = data.getValues(dimensions, i); var activeState; if (!hasActiveSet) { activeState = 'normal'; } else { activeState = 'active'; for (var j = 0, lenj = dimensions.length; j < lenj; j++) { var dimName = dimensions[j]; var state = axesMap[dimName].model.getActiveState(values[j], j); if (state === 'inactive') { activeState = 'inactive'; break; } } } callback.call(context, activeState, i); } }, /** * Whether has any activeSet. * @return {boolean} */ hasAxisbrushed: function () { var dimensions = this.dimensions; var axesMap = this._axesMap; var hasActiveSet = false; for (var j = 0, lenj = dimensions.length; j < lenj; j++) { if (axesMap[dimensions[j]].model.getActiveState() !== 'normal') { hasActiveSet = true; } } return hasActiveSet; }, /** * Convert coords of each axis to Point. * Return point. For example: [10, 20] * @param {Array.} coords * @param {string} dim * @return {Array.} */ axisCoordToPoint: function (coord, dim) { var axisLayout = this._axesLayout[dim]; return graphic.applyTransform([coord, 0], axisLayout.transform); }, /** * Get axis layout. */ getAxisLayout: function (dim) { return zrUtil.clone(this._axesLayout[dim]); }, findClosestAxisDim: function (point) { var axisDim; var minDist = Infinity; zrUtil.each(this._axesLayout, function (axisLayout, dim) { var localPoint = graphic.applyTransform(point, axisLayout.transform, true); var extent = this._axesMap[dim].getExtent(); if (localPoint[0] < extent[0] || localPoint[0] > extent[1]) { return; } var dist = Math.abs(localPoint[1]); if (dist < minDist) { minDist = dist; axisDim = dim; } }, this); return axisDim; } }; module.exports = Parallel; /***/ }, /* 229 */ /***/ function(module, exports, __webpack_require__) { var zrUtil = __webpack_require__(4); var Axis = __webpack_require__(124); /** * @constructor module:echarts/coord/parallel/ParallelAxis * @extends {module:echarts/coord/Axis} * @param {string} dim * @param {*} scale * @param {Array.} coordExtent * @param {string} axisType */ var ParallelAxis = function (dim, scale, coordExtent, axisType, axisIndex) { Axis.call(this, dim, scale, coordExtent); /** * Axis type * - 'category' * - 'value' * - 'time' * - 'log' * @type {string} */ this.type = axisType || 'value'; /** * @type {number} * @readOnly */ this.axisIndex = axisIndex; }; ParallelAxis.prototype = { constructor: ParallelAxis, /** * Axis model * @param {module:echarts/coord/parallel/AxisModel} */ model: null }; zrUtil.inherits(ParallelAxis, Axis); module.exports = ParallelAxis; /***/ }, /* 230 */ /***/ function(module, exports, __webpack_require__) { var zrUtil = __webpack_require__(4); var Component = __webpack_require__(19); __webpack_require__(231); Component.extend({ type: 'parallel', dependencies: ['parallelAxis'], /** * @type {module:echarts/coord/parallel/Parallel} */ coordinateSystem: null, /** * Each item like: 'dim0', 'dim1', 'dim2', ... * @type {Array.} * @readOnly */ dimensions: null, /** * Coresponding to dimensions. * @type {Array.} * @readOnly */ parallelAxisIndex: null, layoutMode: 'box', defaultOption: { zlevel: 0, z: 0, left: 80, top: 60, right: 80, bottom: 60, // width: {totalWidth} - left - right, // height: {totalHeight} - top - bottom, layout: 'horizontal', // 'horizontal' or 'vertical' // FIXME // naming? axisExpandable: false, axisExpandCenter: null, axisExpandCount: 0, axisExpandWidth: 50, // FIXME '10%' ? parallelAxisDefault: null }, /** * @override */ init: function () { Component.prototype.init.apply(this, arguments); this.mergeOption({}); }, /** * @override */ mergeOption: function (newOption) { var thisOption = this.option; newOption && zrUtil.merge(thisOption, newOption, true); this._initDimensions(); }, /** * Whether series or axis is in this coordinate system. * @param {module:echarts/model/Series|module:echarts/coord/parallel/AxisModel} model * @param {module:echarts/model/Global} ecModel */ contains: function (model, ecModel) { var parallelIndex = model.get('parallelIndex'); return parallelIndex != null && ecModel.getComponent('parallel', parallelIndex) === this; }, setAxisExpand: function (opt) { zrUtil.each( ['axisExpandable', 'axisExpandCenter', 'axisExpandCount', 'axisExpandWidth'], function (name) { if (opt.hasOwnProperty(name)) { this.option[name] = opt[name]; } }, this ); }, /** * @private */ _initDimensions: function () { var dimensions = this.dimensions = []; var parallelAxisIndex = this.parallelAxisIndex = []; var axisModels = zrUtil.filter(this.dependentModels.parallelAxis, function (axisModel) { // Can not use this.contains here, because // initialization has not been completed yet. return axisModel.get('parallelIndex') === this.componentIndex; }); zrUtil.each(axisModels, function (axisModel) { dimensions.push('dim' + axisModel.get('dim')); parallelAxisIndex.push(axisModel.componentIndex); }); } }); /***/ }, /* 231 */ /***/ function(module, exports, __webpack_require__) { var ComponentModel = __webpack_require__(19); var zrUtil = __webpack_require__(4); var makeStyleMapper = __webpack_require__(15); var axisModelCreator = __webpack_require__(128); var numberUtil = __webpack_require__(7); var AxisModel = ComponentModel.extend({ type: 'baseParallelAxis', /** * @type {module:echarts/coord/parallel/Axis} */ axis: null, /** * @type {Array.} * @readOnly */ activeIntervals: [], /** * @return {Object} */ getAreaSelectStyle: function () { return makeStyleMapper( [ ['fill', 'color'], ['lineWidth', 'borderWidth'], ['stroke', 'borderColor'], ['width', 'width'], ['opacity', 'opacity'] ] ).call(this.getModel('areaSelectStyle')); }, /** * The code of this feature is put on AxisModel but not ParallelAxis, * because axisModel can be alive after echarts updating but instance of * ParallelAxis having been disposed. this._activeInterval should be kept * when action dispatched (i.e. legend click). * * @param {Array.>} intervals interval.length === 0 * means set all active. * @public */ setActiveIntervals: function (intervals) { var activeIntervals = this.activeIntervals = zrUtil.clone(intervals); // Normalize if (activeIntervals) { for (var i = activeIntervals.length - 1; i >= 0; i--) { numberUtil.asc(activeIntervals[i]); } } }, /** * @param {number|string} [value] When attempting to detect 'no activeIntervals set', * value can not be input. * @return {string} 'normal': no activeIntervals set, * 'active', * 'inactive'. * @public */ getActiveState: function (value) { var activeIntervals = this.activeIntervals; if (!activeIntervals.length) { return 'normal'; } if (value == null) { return 'inactive'; } for (var i = 0, len = activeIntervals.length; i < len; i++) { if (activeIntervals[i][0] <= value && value <= activeIntervals[i][1]) { return 'active'; } } return 'inactive'; } }); var defaultOption = { type: 'value', /** * @type {Array.} */ dim: null, // 0, 1, 2, ... // parallelIndex: null, areaSelectStyle: { width: 20, borderWidth: 1, borderColor: 'rgba(160,197,232)', color: 'rgba(160,197,232)', opacity: 0.3 }, realtime: true, // Whether realtime update view when select. z: 10 }; zrUtil.merge(AxisModel.prototype, __webpack_require__(130)); function getAxisType(axisName, option) { return option.type || (option.data ? 'category' : 'value'); } axisModelCreator('parallel', AxisModel, getAxisType, defaultOption); module.exports = AxisModel; /***/ }, /* 232 */ /***/ function(module, exports, __webpack_require__) { __webpack_require__(227); __webpack_require__(233); __webpack_require__(234); /***/ }, /* 233 */ /***/ function(module, exports, __webpack_require__) { var echarts = __webpack_require__(1); /** * @payload * @property {string} parallelAxisId * @property {Array.>} intervals */ var actionInfo = { type: 'axisAreaSelect', event: 'axisAreaSelected', update: 'updateVisual' }; echarts.registerAction(actionInfo, function (payload, ecModel) { ecModel.eachComponent( {mainType: 'parallelAxis', query: payload}, function (parallelAxisModel) { parallelAxisModel.axis.model.setActiveIntervals(payload.intervals); } ); }); /** * @payload */ echarts.registerAction('parallelAxisExpand', function (payload, ecModel) { ecModel.eachComponent( {mainType: 'parallel', query: payload}, function (parallelModel) { parallelModel.setAxisExpand(payload); } ); }); /***/ }, /* 234 */ /***/ function(module, exports, __webpack_require__) { var zrUtil = __webpack_require__(4); var AxisBuilder = __webpack_require__(134); var BrushController = __webpack_require__(235); var graphic = __webpack_require__(43); var elementList = ['axisLine', 'axisLabel', 'axisTick', 'axisName']; var AxisView = __webpack_require__(1).extendComponentView({ type: 'parallelAxis', /** * @override */ init: function (ecModel, api) { AxisView.superApply(this, 'init', arguments); /** * @type {module:echarts/component/helper/BrushController} */ (this._brushController = new BrushController(api.getZr())) .on('brush', zrUtil.bind(this._onBrush, this)); }, /** * @override */ render: function (axisModel, ecModel, api, payload) { if (fromAxisAreaSelect(axisModel, ecModel, payload)) { return; } this.axisModel = axisModel; this.api = api; this.group.removeAll(); var oldAxisGroup = this._axisGroup; this._axisGroup = new graphic.Group(); this.group.add(this._axisGroup); if (!axisModel.get('show')) { return; } var coordSys = ecModel.getComponent( 'parallel', axisModel.get('parallelIndex') ).coordinateSystem; var areaSelectStyle = axisModel.getAreaSelectStyle(); var areaWidth = areaSelectStyle.width; var dim = axisModel.axis.dim; var axisLayout = coordSys.getAxisLayout(dim); // Fetch from axisModel by default. var axisLabelShow; var axisIndex = zrUtil.indexOf(coordSys.dimensions, dim); var axisExpandWindow = axisLayout.axisExpandWindow; if (axisExpandWindow && (axisIndex <= axisExpandWindow[0] || axisIndex >= axisExpandWindow[1]) ) { axisLabelShow = false; } var builderOpt = zrUtil.extend( { axisLabelShow: axisLabelShow, strokeContainThreshold: areaWidth }, axisLayout ); var axisBuilder = new AxisBuilder(axisModel, builderOpt); zrUtil.each(elementList, axisBuilder.add, axisBuilder); this._axisGroup.add(axisBuilder.getGroup()); this._refreshBrushController(builderOpt, areaSelectStyle, axisModel, areaWidth); graphic.groupTransition(oldAxisGroup, this._axisGroup, axisModel); }, _refreshBrushController: function (builderOpt, areaSelectStyle, axisModel, areaWidth) { // After filtering, axis may change, select area needs to be update. var axis = axisModel.axis; var coverInfoList = zrUtil.map(axisModel.activeIntervals, function (interval) { return { brushType: 'lineX', panelId: 'pl', range: [ axis.dataToCoord(interval[0], true), axis.dataToCoord(interval[1], true) ] }; }); var extent = axis.getExtent(); var extentLen = extent[1] - extent[0]; var extra = Math.min(30, Math.abs(extentLen) * 0.1); // Arbitrary value. // width/height might be negative, which will be // normalized in BoundingRect. var rect = graphic.BoundingRect.create({ x: extent[0], y: -areaWidth / 2, width: extentLen, height: areaWidth }); rect.x -= extra; rect.width += 2 * extra; this._brushController .mount({ enableGlobalPan: true, rotation: builderOpt.rotation, position: builderOpt.position }) .setPanels([{ panelId: 'pl', rect: rect }]) .enableBrush({ brushType: 'lineX', brushStyle: areaSelectStyle, removeOnClick: true }) .updateCovers(coverInfoList); }, _onBrush: function (coverInfoList, opt) { // Do not cache these object, because the mey be changed. var axisModel = this.axisModel; var axis = axisModel.axis; var intervals = zrUtil.map(coverInfoList, function (coverInfo) { return [ axis.coordToData(coverInfo.range[0], true), axis.coordToData(coverInfo.range[1], true) ]; }); // If realtime is true, action is not dispatched on drag end, because // the drag end emits the same params with the last drag move event, // and may have some delay when using touch pad. if (!axisModel.option.realtime === opt.isEnd || opt.removeOnClick) { // jshint ignore:line this.api.dispatchAction({ type: 'axisAreaSelect', parallelAxisId: axisModel.id, intervals: intervals }); } }, /** * @override */ dispose: function () { this._brushController.dispose(); } }); function fromAxisAreaSelect(axisModel, ecModel, payload) { return payload && payload.type === 'axisAreaSelect' && ecModel.findComponents( {mainType: 'parallelAxis', query: payload} )[0] === axisModel; } module.exports = AxisView; /***/ }, /* 235 */ /***/ function(module, exports, __webpack_require__) { /** * Box selection tool. * * @module echarts/component/helper/BrushController */ var Eventful = __webpack_require__(33); var zrUtil = __webpack_require__(4); var BoundingRect = __webpack_require__(9); var graphic = __webpack_require__(43); var interactionMutex = __webpack_require__(177); var DataDiffer = __webpack_require__(99); var curry = zrUtil.curry; var each = zrUtil.each; var map = zrUtil.map; var mathMin = Math.min; var mathMax = Math.max; var mathPow = Math.pow; var COVER_Z = 10000; var UNSELECT_THRESHOLD = 6; var MIN_RESIZE_LINE_WIDTH = 6; var MUTEX_RESOURCE_KEY = 'globalPan'; var DIRECTION_MAP = { w: [0, 0], e: [0, 1], n: [1, 0], s: [1, 1] }; var CURSOR_MAP = { w: 'ew', e: 'ew', n: 'ns', s: 'ns', ne: 'nesw', sw: 'nesw', nw: 'nwse', se: 'nwse' }; var DEFAULT_BRUSH_OPT = { brushStyle: { lineWidth: 2, stroke: 'rgba(0,0,0,0.3)', fill: 'rgba(0,0,0,0.1)' }, transformable: true, brushMode: 'single', removeOnClick: false }; var baseUID = 0; /** * @alias module:echarts/component/helper/BrushController * @constructor * @mixin {module:zrender/mixin/Eventful} * @event module:echarts/component/helper/BrushController#brush * params: * areas: Array., coord relates to container group, * If no container specified, to global. * opt { * isEnd: boolean, * removeOnClick: boolean * } * * @param {module:zrender/zrender~ZRender} zr */ function BrushController(zr) { if (true) { zrUtil.assert(zr); } Eventful.call(this); /** * @type {module:zrender/zrender~ZRender} * @private */ this._zr = zr; /** * @type {module:zrender/container/Group} * @readOnly */ this.group = new graphic.Group(); /** * Only for drawing (after enabledBrush). * @private * @type {string} */ this._brushType; /** * Only for drawing (after enabledBrush). * @private * @type {Object} */ this._brushOption; /** * @private * @type {Object} */ this._panels; /** * @private * @type {Array.} */ this._track = []; /** * @private * @type {boolean} */ this._dragging; /** * @private * @type {Array} */ this._covers = []; /** * @private * @type {moudule:zrender/container/Group} */ this._creatingCover; /** * true means global panel * @private * @type {module:zrender/container/Group|boolean} */ this._creatingPanel; /** * @private * @type {boolean} */ this._enableGlobalPan; /** * @private * @type {boolean} */ if (true) { this._mounted; } /** * @private * @type {string} */ this._uid = 'brushController_' + baseUID++; /** * @private * @type {Object} */ this._handlers = {}; each(mouseHandlers, function (handler, eventName) { this._handlers[eventName] = zrUtil.bind(handler, this); }, this); } BrushController.prototype = { constructor: BrushController, /** * If set to null/undefined/false, select disabled. * @param {Object} brushOption * @param {string|boolean} brushOption.brushType 'line', 'rect', 'polygon' or false * If pass false/null/undefined, disable brush. * @param {number} [brushOption.brushMode='single'] 'single' or 'multiple' * @param {boolean} [brushOption.transformable=true] * @param {boolean} [brushOption.removeOnClick=false] * @param {Object} [brushOption.brushStyle] * @param {number} [brushOption.brushStyle.width] * @param {number} [brushOption.brushStyle.lineWidth] * @param {string} [brushOption.brushStyle.stroke] * @param {string} [brushOption.brushStyle.fill] */ enableBrush: function (brushOption) { if (true) { zrUtil.assert(this._mounted); } this._brushType && doDisableBrush(this); brushOption.brushType && doEnableBrush(this, brushOption); return this; }, /** * @param {Array.} panelOpts If not pass, it is global brush. * Each items: {panelId, rect} */ setPanels: function (panelOpts) { var oldPanels = this._panels || {}; var newPanels = this._panels = panelOpts && panelOpts.length && {}; var thisGroup = this.group; newPanels && each(panelOpts, function (panelOpt) { var panelId = panelOpt.panelId; var panel = oldPanels[panelId]; if (!panel) { panel = new graphic.Rect({ silent: true, invisible: true }); thisGroup.add(panel); } var rect = panelOpt.rect; // Using BoundingRect to normalize negative width/height. if (!(rect instanceof BoundingRect)) { rect = BoundingRect.create(rect); } panel.attr('shape', rect.plain()); panel.__brushPanelId = panelId; newPanels[panelId] = panel; oldPanels[panelId] = null; }); each(oldPanels, function (panel) { panel && thisGroup.remove(panel); }); return this; }, /** * @param {Object} [opt] * @return {boolean} [opt.enableGlobalPan=false] * @return {boolean} [opt.position=[0, 0]] * @return {boolean} [opt.rotation=0] * @return {boolean} [opt.scale=[1, 1]] */ mount: function (opt) { opt = opt || {}; if (true) { this._mounted = true; // should be at first. } this._enableGlobalPan = opt.enableGlobalPan; var thisGroup = this.group; this._zr.add(thisGroup); thisGroup.attr({ position: opt.position || [0, 0], rotation: opt.rotation || 0, scale: opt.scale || [1, 1] }); return this; }, eachCover: function (cb, context) { each(this._covers, cb, context); }, /** * Update covers. * @param {Array.} brushOptionList Like: * [ * {id: 'xx', brushType: 'line', range: [23, 44], brushStyle, transformable}, * {id: 'yy', brushType: 'rect', range: [[23, 44], [23, 54]]}, * ... * ] * `brushType` is required in each cover info. * `id` is not mandatory. * `brushStyle`, `transformable` is not mandatory, use DEFAULT_BRUSH_OPT by default. * If brushOptionList is null/undefined, all covers removed. */ updateCovers: function (brushOptionList) { if (true) { zrUtil.assert(this._mounted); } brushOptionList = zrUtil.map(brushOptionList, function (brushOption) { return zrUtil.merge(zrUtil.clone(DEFAULT_BRUSH_OPT), brushOption, true); }); var tmpIdPrefix = '\0-brush-index-'; var oldCovers = this._covers; var newCovers = this._covers = []; var controller = this; var creatingCover = this._creatingCover; (new DataDiffer(oldCovers, brushOptionList, oldGetKey, getKey)) .add(addOrUpdate) .update(addOrUpdate) .remove(remove) .execute(); return this; function getKey(brushOption, index) { return (brushOption.id != null ? brushOption.id : tmpIdPrefix + index) + '-' + brushOption.brushType; } function oldGetKey(cover, index) { return getKey(cover.__brushOption, index); } function addOrUpdate(newIndex, oldIndex) { var newBrushOption = brushOptionList[newIndex]; // Consider setOption in event listener of brushSelect, // where updating cover when creating should be forbiden. if (oldIndex != null && oldCovers[oldIndex] === creatingCover) { newCovers[newIndex] = oldCovers[oldIndex]; } else { var cover = newCovers[newIndex] = oldIndex != null ? ( oldCovers[oldIndex].__brushOption = newBrushOption, oldCovers[oldIndex] ) : endCreating(controller, createCover(controller, newBrushOption)); updateCoverAfterCreation(controller, cover); } } function remove(oldIndex) { if (oldCovers[oldIndex] !== creatingCover) { controller.group.remove(oldCovers[oldIndex]); } } }, unmount: function () { this.enableBrush(false); // container may 'removeAll' outside. clearCovers(this); this._zr.remove(this.group); if (true) { this._mounted = false; // should be at last. } return this; }, dispose: function () { this.unmount(); this.off(); } }; zrUtil.mixin(BrushController, Eventful); function doEnableBrush(controller, brushOption) { var zr = controller._zr; // Consider roam, which takes globalPan too. if (!controller._enableGlobalPan) { interactionMutex.take(zr, MUTEX_RESOURCE_KEY, controller._uid); } each(controller._handlers, function (handler, eventName) { zr.on(eventName, handler); }); controller._brushType = brushOption.brushType; controller._brushOption = zrUtil.merge(zrUtil.clone(DEFAULT_BRUSH_OPT), brushOption, true); } function doDisableBrush(controller) { var zr = controller._zr; interactionMutex.release(zr, MUTEX_RESOURCE_KEY, controller._uid); each(controller._handlers, function (handler, eventName) { zr.off(eventName, handler); }); controller._brushType = controller._brushOption = null; } function createCover(controller, brushOption) { var cover = coverRenderers[brushOption.brushType].createCover(controller, brushOption); updateZ(cover); cover.__brushOption = brushOption; controller.group.add(cover); return cover; } function endCreating(controller, creatingCover) { var coverRenderer = getCoverRenderer(creatingCover); if (coverRenderer.endCreating) { coverRenderer.endCreating(controller, creatingCover); updateZ(creatingCover); } return creatingCover; } function updateCoverShape(controller, cover) { var brushOption = cover.__brushOption; getCoverRenderer(cover).updateCoverShape( controller, cover, brushOption.range, brushOption ); } function updateZ(group) { group.traverse(function (el) { el.z = COVER_Z; el.z2 = COVER_Z; // Consider in given container. }); } function updateCoverAfterCreation(controller, cover) { getCoverRenderer(cover).updateCommon(controller, cover); updateCoverShape(controller, cover); } function getCoverRenderer(cover) { return coverRenderers[cover.__brushOption.brushType]; } function getPanelByPoint(controller, x, y) { var panels = controller._panels; if (!panels) { return true; // Global panel } var panel; each(panels, function (pn) { pn.contain(x, y) && (panel = pn); }); return panel; } function getPanelByCover(controller, cover) { var panels = controller._panels; if (!panels) { return true; // Global panel } var panelId = cover.__brushOption.panelId; // User may give cover without coord sys info, // which is then treated as global panel. return panelId != null ? panels[panelId] : true; } function clearCovers(controller) { var covers = controller._covers; var originalLength = covers.length; each(covers, function (cover) { controller.group.remove(cover); }, controller); covers.length = 0; return !!originalLength; } function trigger(controller, opt) { var areas = map(controller._covers, function (cover) { var brushOption = cover.__brushOption; var range = zrUtil.clone(brushOption.range); return { brushType: brushOption.brushType, panelId: brushOption.panelId, range: range }; }); controller.trigger('brush', areas, { isEnd: !!opt.isEnd, removeOnClick: !!opt.removeOnClick }); } function shouldShowCover(controller) { var track = controller._track; if (!track.length) { return false; } var p2 = track[track.length - 1]; var p1 = track[0]; var dx = p2[0] - p1[0]; var dy = p2[1] - p1[1]; var dist = mathPow(dx * dx + dy * dy, 0.5); return dist > UNSELECT_THRESHOLD; } function getTrackEnds(track) { var tail = track.length - 1; tail < 0 && (tail = 0); return [track[0], track[tail]]; } function createBaseRectCover(doDrift, controller, brushOption, edgeNames) { var cover = new graphic.Group(); cover.add(new graphic.Rect({ name: 'main', style: makeStyle(brushOption), silent: true, draggable: true, cursor: 'move', drift: curry(doDrift, controller, cover, 'nswe'), ondragend: curry(trigger, controller, {isEnd: true}) })); each( edgeNames, function (name) { cover.add(new graphic.Rect({ name: name, style: {opacity: 0}, draggable: true, silent: true, invisible: true, drift: curry(doDrift, controller, cover, name), ondragend: curry(trigger, controller, {isEnd: true}) })); } ); return cover; } function updateBaseRect(controller, cover, localRange, brushOption) { var lineWidth = brushOption.brushStyle.lineWidth || 0; var handleSize = mathMax(lineWidth, MIN_RESIZE_LINE_WIDTH); var x = localRange[0][0]; var y = localRange[1][0]; var xa = x - lineWidth / 2; var ya = y - lineWidth / 2; var x2 = localRange[0][1]; var y2 = localRange[1][1]; var x2a = x2 - handleSize + lineWidth / 2; var y2a = y2 - handleSize + lineWidth / 2; var width = x2 - x; var height = y2 - y; var widtha = width + lineWidth; var heighta = height + lineWidth; updateRectShape(controller, cover, 'main', x, y, width, height); if (brushOption.transformable) { updateRectShape(controller, cover, 'w', xa, ya, handleSize, heighta); updateRectShape(controller, cover, 'e', x2a, ya, handleSize, heighta); updateRectShape(controller, cover, 'n', xa, ya, widtha, handleSize); updateRectShape(controller, cover, 's', xa, y2a, widtha, handleSize); updateRectShape(controller, cover, 'nw', xa, ya, handleSize, handleSize); updateRectShape(controller, cover, 'ne', x2a, ya, handleSize, handleSize); updateRectShape(controller, cover, 'sw', xa, y2a, handleSize, handleSize); updateRectShape(controller, cover, 'se', x2a, y2a, handleSize, handleSize); } } function updateCommon(controller, cover) { var brushOption = cover.__brushOption; var transformable = brushOption.transformable; var mainEl = cover.childAt(0); mainEl.useStyle(makeStyle(brushOption)); mainEl.attr({ silent: !transformable, cursor: transformable ? 'move' : 'default' }); each( ['w', 'e', 'n', 's', 'se', 'sw', 'ne', 'nw'], function (name) { var el = cover.childOfName(name); var globalDir = getGlobalDirection(controller, name); el && el.attr({ silent: !transformable, invisible: !transformable, cursor: transformable ? CURSOR_MAP[globalDir] + '-resize' : null }); } ); } function updateRectShape(controller, cover, name, x, y, w, h) { var el = cover.childOfName(name); el && el.setShape(pointsToRect( clipByPanel(controller, cover, [[x, y], [x + w, y + h]]) )); } function makeStyle(brushOption) { return zrUtil.defaults({strokeNoScale: true}, brushOption.brushStyle); } function formatRectRange(x, y, x2, y2) { var min = [mathMin(x, x2), mathMin(y, y2)]; var max = [mathMax(x, x2), mathMax(y, y2)]; return [ [min[0], max[0]], // x range [min[1], max[1]] // y range ]; } function getTransform(controller) { return graphic.getTransform(controller.group); } function getGlobalDirection(controller, localDirection) { if (localDirection.length > 1) { localDirection = localDirection.split(''); var globalDir = [ getGlobalDirection(controller, localDirection[0]), getGlobalDirection(controller, localDirection[1]) ]; (globalDir[0] === 'e' || globalDir[0] === 'w') && globalDir.reverse(); return globalDir.join(''); } else { var map = {w: 'left', e: 'right', n: 'top', s: 'bottom'}; var inverseMap = {left: 'w', right: 'e', top: 'n', bottom: 's'}; var globalDir = graphic.transformDirection( map[localDirection], getTransform(controller) ); return inverseMap[globalDir]; } } function driftRect(toRectRange, fromRectRange, controller, cover, name, dx, dy, e) { var brushOption = cover.__brushOption; var rectRange = toRectRange(brushOption.range); var localDelta = toLocalDelta(controller, dx, dy); each(name.split(''), function (namePart) { var ind = DIRECTION_MAP[namePart]; rectRange[ind[0]][ind[1]] += localDelta[ind[0]]; }); brushOption.range = fromRectRange(formatRectRange( rectRange[0][0], rectRange[1][0], rectRange[0][1], rectRange[1][1] )); updateCoverAfterCreation(controller, cover); trigger(controller, {isEnd: false}); } function driftPolygon(controller, cover, dx, dy, e) { var range = cover.__brushOption.range; var localDelta = toLocalDelta(controller, dx, dy); each(range, function (point) { point[0] += localDelta[0]; point[1] += localDelta[1]; }); updateCoverAfterCreation(controller, cover); trigger(controller, {isEnd: false}); } function toLocalDelta(controller, dx, dy) { var thisGroup = controller.group; var localD = thisGroup.transformCoordToLocal(dx, dy); var localZero = thisGroup.transformCoordToLocal(0, 0); return [localD[0] - localZero[0], localD[1] - localZero[1]]; } function clipByPanel(controller, cover, data) { var panel = getPanelByCover(controller, cover); if (panel === true) { // Global panel return zrUtil.clone(data); } var panelRect = panel.getBoundingRect(); return zrUtil.map(data, function (point) { var x = point[0]; x = mathMax(x, panelRect.x); x = mathMin(x, panelRect.x + panelRect.width); var y = point[1]; y = mathMax(y, panelRect.y); y = mathMin(y, panelRect.y + panelRect.height); return [x, y]; }); } function pointsToRect(points) { var xmin = mathMin(points[0][0], points[1][0]); var ymin = mathMin(points[0][1], points[1][1]); var xmax = mathMax(points[0][0], points[1][0]); var ymax = mathMax(points[0][1], points[1][1]); return { x: xmin, y: ymin, width: xmax - xmin, height: ymax - ymin }; } function resetCursor(controller, e) { var x = e.offsetX; var y = e.offsetY; var zr = controller._zr; if (controller._brushType) { // If active var panels = controller._panels; var covers = controller._covers; var inCover; for (var i = 0; i < covers.length; i++) { if (coverRenderers[covers[i].__brushOption.brushType].contain(covers[i], x, y)) { inCover = true; break; } } if (!inCover) { if (panels) { // Brush on panels each(panels, function (panel) { panel.contain(x, y) && zr.setCursorStyle('crosshair'); }); } else { // Global brush zr.setCursorStyle('crosshair'); } } } } function preventDefault(e) { var rawE = e.event; rawE.preventDefault && rawE.preventDefault(); } function mainShapeContain(cover, x, y) { return cover.childOfName('main').contain(x, y); } function updateCoverByMouse(controller, e, isEnd) { var x = e.offsetX; var y = e.offsetY; var creatingCover = controller._creatingCover; var panel = controller._creatingPanel; var thisBrushOption = controller._brushOption; var eventParams; controller._track.push(controller.group.transformCoordToLocal(x, y)); if (shouldShowCover(controller) || creatingCover) { if (panel && !creatingCover) { thisBrushOption.brushMode === 'single' && clearCovers(controller); var brushOption = zrUtil.clone(thisBrushOption); brushOption.panelId = panel === true ? null : panel.__brushPanelId; creatingCover = controller._creatingCover = createCover(controller, brushOption); controller._covers.push(creatingCover); } if (creatingCover) { var coverRenderer = coverRenderers[controller._brushType]; var coverBrushOption = creatingCover.__brushOption; coverBrushOption.range = coverRenderer.getCreatingRange( clipByPanel(controller, creatingCover, controller._track) ); if (isEnd) { endCreating(controller, creatingCover); coverRenderer.updateCommon(controller, creatingCover); } updateCoverShape(controller, creatingCover); eventParams = {isEnd: isEnd}; } } else if ( isEnd && thisBrushOption.brushMode === 'single' && thisBrushOption.removeOnClick ) { // Help user to remove covers easily, only by a tiny drag, in 'single' mode. // But a single click do not clear covers, because user may have casual // clicks (for example, click on other component and do not expect covers // disappear). // Only some cover removed, trigger action, but not every click trigger action. if (getPanelByPoint(controller, x, y) && clearCovers(controller)) { eventParams = {isEnd: isEnd, removeOnClick: true}; } } return eventParams; } var mouseHandlers = { mousedown: function (e) { if (this._dragging) { // In case some browser do not support globalOut, // and release mose out side the browser. handleDragEnd.call(this, e); } else if (!e.target || !e.target.draggable) { preventDefault(e); var x = e.offsetX; var y = e.offsetY; this._creatingCover = null; var panel = this._creatingPanel = getPanelByPoint(this, x, y); if (panel) { this._dragging = true; this._track = [this.group.transformCoordToLocal(x, y)]; } } }, mousemove: function (e) { // set Cursor resetCursor(this, e); if (this._dragging) { preventDefault(e); var eventParams = updateCoverByMouse(this, e, false); eventParams && trigger(this, eventParams); } }, mouseup: handleDragEnd //, // FIXME // in tooltip, globalout should not be triggered. // globalout: handleDragEnd }; function handleDragEnd(e) { if (this._dragging) { preventDefault(e); var eventParams = updateCoverByMouse(this, e, true); this._dragging = false; this._track = []; this._creatingCover = null; // trigger event shoule be at final, after procedure will be nested. eventParams && trigger(this, eventParams); } } /** * key: brushType * @type {Object} */ var coverRenderers = { lineX: getLineRenderer(0), lineY: getLineRenderer(1), rect: { createCover: function (controller, brushOption) { return createBaseRectCover( curry( driftRect, function (range) { return range; }, function (range) { return range; } ), controller, brushOption, ['w', 'e', 'n', 's', 'se', 'sw', 'ne', 'nw'] ); }, getCreatingRange: function (localTrack) { var ends = getTrackEnds(localTrack); return formatRectRange(ends[1][0], ends[1][1], ends[0][0], ends[0][1]); }, updateCoverShape: function (controller, cover, localRange, brushOption) { updateBaseRect(controller, cover, localRange, brushOption); }, updateCommon: updateCommon, contain: mainShapeContain }, polygon: { createCover: function (controller, brushOption) { var cover = new graphic.Group(); // Do not use graphic.Polygon because graphic.Polyline do not close the // border of the shape when drawing, which is a better experience for user. cover.add(new graphic.Polyline({ name: 'main', style: makeStyle(brushOption), silent: true })); return cover; }, getCreatingRange: function (localTrack) { return localTrack; }, endCreating: function (controller, cover) { cover.remove(cover.childAt(0)); // Use graphic.Polygon close the shape. cover.add(new graphic.Polygon({ name: 'main', draggable: true, drift: curry(driftPolygon, controller, cover), ondragend: curry(trigger, controller, {isEnd: true}) })); }, updateCoverShape: function (controller, cover, localRange, brushOption) { cover.childAt(0).setShape({ points: clipByPanel(controller, cover, localRange) }); }, updateCommon: updateCommon, contain: mainShapeContain } }; function getLineRenderer(xyIndex) { return { createCover: function (controller, brushOption) { return createBaseRectCover( curry( driftRect, function (range) { var rectRange = [range, [0, 100]]; xyIndex && rectRange.reverse(); return rectRange; }, function (rectRange) { return rectRange[xyIndex]; } ), controller, brushOption, [['w', 'e'], ['n', 's']][xyIndex] ); }, getCreatingRange: function (localTrack) { var ends = getTrackEnds(localTrack); var min = mathMin(ends[0][xyIndex], ends[1][xyIndex]); var max = mathMax(ends[0][xyIndex], ends[1][xyIndex]); return [min, max]; }, updateCoverShape: function (controller, cover, localRange, brushOption) { var brushWidth = brushOption.brushStyle.width; var otherExtent; // If brushWidth not specified, fit the panel. if (brushWidth == null) { var panel = getPanelByCover(controller, cover); var base = 0; if (panel !== true) { var rect = panel.getBoundingRect(); brushWidth = xyIndex ? rect.width : rect.height; base = xyIndex ? rect.x : rect.y; } // FIXME // do not support global panel yet. otherExtent = [base, base + (brushWidth || 0)]; } else { otherExtent = [-brushWidth / 2, brushWidth / 2]; } var rectRange = [localRange, otherExtent]; xyIndex && rectRange.reverse(); updateBaseRect(controller, cover, rectRange, brushOption); }, updateCommon: updateCommon, contain: mainShapeContain }; } module.exports = BrushController; /***/ }, /* 236 */ /***/ function(module, exports, __webpack_require__) { var zrUtil = __webpack_require__(4); var modelUtil = __webpack_require__(5); module.exports = function (option) { createParallelIfNeeded(option); mergeAxisOptionFromParallel(option); }; /** * Create a parallel coordinate if not exists. * @inner */ function createParallelIfNeeded(option) { if (option.parallel) { return; } var hasParallelSeries = false; zrUtil.each(option.series, function (seriesOpt) { if (seriesOpt && seriesOpt.type === 'parallel') { hasParallelSeries = true; } }); if (hasParallelSeries) { option.parallel = [{}]; } } /** * Merge aixs definition from parallel option (if exists) to axis option. * @inner */ function mergeAxisOptionFromParallel(option) { var axes = modelUtil.normalizeToArray(option.parallelAxis); zrUtil.each(axes, function (axisOption) { if (!zrUtil.isObject(axisOption)) { return; } var parallelIndex = axisOption.parallelIndex || 0; var parallelOption = modelUtil.normalizeToArray(option.parallel)[parallelIndex]; if (parallelOption && parallelOption.parallelAxisDefault) { zrUtil.merge(axisOption, parallelOption.parallelAxisDefault, false); } }); } /***/ }, /* 237 */ /***/ function(module, exports, __webpack_require__) { var List = __webpack_require__(98); var zrUtil = __webpack_require__(4); var SeriesModel = __webpack_require__(28); var completeDimensions = __webpack_require__(103); module.exports = SeriesModel.extend({ type: 'series.parallel', dependencies: ['parallel'], getInitialData: function (option, ecModel) { var parallelModel = ecModel.getComponent( 'parallel', this.get('parallelIndex') ); var parallelAxisIndices = parallelModel.parallelAxisIndex; var rawData = option.data; var modelDims = parallelModel.dimensions; var dataDims = generateDataDims(modelDims, rawData); var dataDimsInfo = zrUtil.map(dataDims, function (dim, dimIndex) { var modelDimsIndex = zrUtil.indexOf(modelDims, dim); var axisModel = modelDimsIndex >= 0 && ecModel.getComponent( 'parallelAxis', parallelAxisIndices[modelDimsIndex] ); if (axisModel && axisModel.get('type') === 'category') { translateCategoryValue(axisModel, dim, rawData); return {name: dim, type: 'ordinal'}; } else if (modelDimsIndex < 0) { return completeDimensions.guessOrdinal(rawData, dimIndex) ? {name: dim, type: 'ordinal'} : dim; } else { return dim; } }); var list = new List(dataDimsInfo, this); list.initData(rawData); // Anication is forbiden in progressive data mode. if (this.option.progressive) { this.option.animation = false; } return list; }, /** * User can get data raw indices on 'axisAreaSelected' event received. * * @public * @param {string} activeState 'active' or 'inactive' or 'normal' * @return {Array.} Raw indices */ getRawIndicesByActiveState: function (activeState) { var coordSys = this.coordinateSystem; var data = this.getData(); var indices = []; coordSys.eachActiveState(data, function (theActiveState, dataIndex) { if (activeState === theActiveState) { indices.push(data.getRawIndex(dataIndex)); } }); return indices; }, defaultOption: { zlevel: 0, // 一级层叠 z: 2, // 二级层叠 coordinateSystem: 'parallel', parallelIndex: 0, label: { normal: { show: false }, emphasis: { show: false } }, inactiveOpacity: 0.05, activeOpacity: 1, lineStyle: { normal: { width: 1, opacity: 0.45, type: 'solid' } }, progressive: false, // 100 smooth: false, animationEasing: 'linear' } }); function translateCategoryValue(axisModel, dim, rawData) { var axisData = axisModel.get('data'); var numberDim = convertDimNameToNumber(dim); if (axisData && axisData.length) { zrUtil.each(rawData, function (dataItem) { if (!dataItem) { return; } // FIXME // time consuming, should use hash? var index = zrUtil.indexOf(axisData, dataItem[numberDim]); dataItem[numberDim] = index >= 0 ? index : NaN; }); } // FIXME // 如果没有设置axis data, 应自动算出,或者提示。 } function convertDimNameToNumber(dimName) { return +dimName.replace('dim', ''); } function generateDataDims(modelDims, rawData) { // parallelModel.dimension should not be regarded as data // dimensions. Consider dimensions = ['dim4', 'dim2', 'dim6']; // We detect max dim by parallelModel.dimensions and fist // item in rawData arbitrarily. var maxDimNum = 0; zrUtil.each(modelDims, function (dimName) { var numberDim = convertDimNameToNumber(dimName); numberDim > maxDimNum && (maxDimNum = numberDim); }); var firstItem = rawData[0]; if (firstItem && firstItem.length - 1 > maxDimNum) { maxDimNum = firstItem.length - 1; } var dataDims = []; for (var i = 0; i <= maxDimNum; i++) { dataDims.push('dim' + i); } return dataDims; } /***/ }, /* 238 */ /***/ function(module, exports, __webpack_require__) { var graphic = __webpack_require__(43); var zrUtil = __webpack_require__(4); var SMOOTH = 0.3; var ParallelView = __webpack_require__(42).extend({ type: 'parallel', init: function () { /** * @type {module:zrender/container/Group} * @private */ this._dataGroup = new graphic.Group(); this.group.add(this._dataGroup); /** * @type {module:echarts/data/List} */ this._data; }, /** * @override */ render: function (seriesModel, ecModel, api, payload) { this._renderForNormal(seriesModel); // this[ // seriesModel.option.progressive // ? '_renderForProgressive' // : '_renderForNormal' // ](seriesModel); }, dispose: function () {}, /** * @private */ _renderForNormal: function (seriesModel) { var dataGroup = this._dataGroup; var data = seriesModel.getData(); var oldData = this._data; var coordSys = seriesModel.coordinateSystem; var dimensions = coordSys.dimensions; var option = seriesModel.option; var smooth = option.smooth ? SMOOTH : null; // Consider switch between progressive and not. // oldData && oldData.__plProgressive && dataGroup.removeAll(); data.diff(oldData) .add(add) .update(update) .remove(remove) .execute(); // Update style updateElCommon(data, smooth); // First create if (!this._data) { var clipPath = createGridClipShape( coordSys, seriesModel, function () { // Callback will be invoked immediately if there is no animation setTimeout(function () { dataGroup.removeClipPath(); }); } ); dataGroup.setClipPath(clipPath); } this._data = data; function add(newDataIndex) { addEl(data, dataGroup, newDataIndex, dimensions, coordSys, null, smooth); } function update(newDataIndex, oldDataIndex) { var line = oldData.getItemGraphicEl(oldDataIndex); var points = createLinePoints(data, newDataIndex, dimensions, coordSys); data.setItemGraphicEl(newDataIndex, line); graphic.updateProps(line, {shape: {points: points}}, seriesModel, newDataIndex); } function remove(oldDataIndex) { var line = oldData.getItemGraphicEl(oldDataIndex); dataGroup.remove(line); } }, /** * @private */ // _renderForProgressive: function (seriesModel) { // var dataGroup = this._dataGroup; // var data = seriesModel.getData(); // var oldData = this._data; // var coordSys = seriesModel.coordinateSystem; // var dimensions = coordSys.dimensions; // var option = seriesModel.option; // var progressive = option.progressive; // var smooth = option.smooth ? SMOOTH : null; // // In progressive animation is disabled, so use simple data diff, // // which effects performance less. // // (Typically performance for data with length 7000+ like: // // simpleDiff: 60ms, addEl: 184ms, // // in RMBP 2.4GHz intel i7, OSX 10.9 chrome 50.0.2661.102 (64-bit)) // if (simpleDiff(oldData, data, dimensions)) { // dataGroup.removeAll(); // data.each(function (dataIndex) { // addEl(data, dataGroup, dataIndex, dimensions, coordSys); // }); // } // updateElCommon(data, progressive, smooth); // // Consider switch between progressive and not. // data.__plProgressive = true; // this._data = data; // }, /** * @override */ remove: function () { this._dataGroup && this._dataGroup.removeAll(); this._data = null; } }); function createGridClipShape(coordSys, seriesModel, cb) { var parallelModel = coordSys.model; var rect = coordSys.getRect(); var rectEl = new graphic.Rect({ shape: { x: rect.x, y: rect.y, width: rect.width, height: rect.height } }); var dim = parallelModel.get('layout') === 'horizontal' ? 'width' : 'height'; rectEl.setShape(dim, 0); graphic.initProps(rectEl, { shape: { width: rect.width, height: rect.height } }, seriesModel, cb); return rectEl; } function createLinePoints(data, dataIndex, dimensions, coordSys) { var points = []; for (var i = 0; i < dimensions.length; i++) { var dimName = dimensions[i]; var value = data.get(dimName, dataIndex); if (!isEmptyValue(value, coordSys.getAxis(dimName).type)) { points.push(coordSys.dataToPoint(value, dimName)); } } return points; } function addEl(data, dataGroup, dataIndex, dimensions, coordSys) { var points = createLinePoints(data, dataIndex, dimensions, coordSys); var line = new graphic.Polyline({ shape: {points: points}, silent: true, z2: 10 }); dataGroup.add(line); data.setItemGraphicEl(dataIndex, line); } function updateElCommon(data, smooth) { var seriesStyleModel = data.hostModel.getModel('lineStyle.normal'); var lineStyle = seriesStyleModel.getLineStyle(); data.eachItemGraphicEl(function (line, dataIndex) { if (data.hasItemOption) { var itemModel = data.getItemModel(dataIndex); var lineStyleModel = itemModel.getModel('lineStyle.normal', seriesStyleModel); lineStyle = lineStyleModel.getLineStyle(); } line.useStyle(zrUtil.extend( lineStyle, { fill: null, stroke: data.getItemVisual(dataIndex, 'color'), opacity: data.getItemVisual(dataIndex, 'opacity') } )); line.shape.smooth = smooth; }); } // function simpleDiff(oldData, newData, dimensions) { // var oldLen; // if (!oldData // || !oldData.__plProgressive // || (oldLen = oldData.count()) !== newData.count() // ) { // return true; // } // var dimLen = dimensions.length; // for (var i = 0; i < oldLen; i++) { // for (var j = 0; j < dimLen; j++) { // if (oldData.get(dimensions[j], i) !== newData.get(dimensions[j], i)) { // return true; // } // } // } // return false; // } // FIXME // 公用方法? function isEmptyValue(val, axisType) { return axisType === 'category' ? val == null : (val == null || isNaN(val)); // axisType === 'value' } module.exports = ParallelView; /***/ }, /* 239 */ /***/ function(module, exports) { module.exports = function (ecModel) { ecModel.eachSeriesByType('parallel', function (seriesModel) { var itemStyleModel = seriesModel.getModel('itemStyle.normal'); var lineStyleModel = seriesModel.getModel('lineStyle.normal'); var globalColors = ecModel.get('color'); var color = lineStyleModel.get('color') || itemStyleModel.get('color') || globalColors[seriesModel.seriesIndex % globalColors.length]; var inactiveOpacity = seriesModel.get('inactiveOpacity'); var activeOpacity = seriesModel.get('activeOpacity'); var lineStyle = seriesModel.getModel('lineStyle.normal').getLineStyle(); var coordSys = seriesModel.coordinateSystem; var data = seriesModel.getData(); var opacityMap = { normal: lineStyle.opacity, active: activeOpacity, inactive: inactiveOpacity }; coordSys.eachActiveState(data, function (activeState, dataIndex) { data.setItemVisual(dataIndex, 'opacity', opacityMap[activeState]); }); data.setVisual('color', color); }); }; /***/ }, /* 240 */ /***/ function(module, exports, __webpack_require__) { var echarts = __webpack_require__(1); __webpack_require__(241); __webpack_require__(242); echarts.registerLayout(__webpack_require__(243)); echarts.registerVisual(__webpack_require__(245)); /***/ }, /* 241 */ /***/ function(module, exports, __webpack_require__) { /** * @file Get initial data and define sankey view's series model * @author Deqing Li(annong035@gmail.com) */ var SeriesModel = __webpack_require__(28); var createGraphFromNodeEdge = __webpack_require__(198); var SankeySeries = SeriesModel.extend({ type: 'series.sankey', layoutInfo: null, /** * Init a graph data structure from data in option series * * @param {Object} option the object used to config echarts view * @return {module:echarts/data/List} storage initial data */ getInitialData: function (option) { var links = option.edges || option.links; var nodes = option.data || option.nodes; if (nodes && links) { var graph = createGraphFromNodeEdge(nodes, links, this, true); return graph.data; } }, /** * Return the graphic data structure * * @return {module:echarts/data/Graph} graphic data structure */ getGraph: function () { return this.getData().graph; }, /** * Get edge data of graphic data structure * * @return {module:echarts/data/List} data structure of list */ getEdgeData: function () { return this.getGraph().edgeData; }, /** * @override */ formatTooltip: function (dataIndex, multipleSeries, dataType) { // dataType === 'node' or empty do not show tooltip by default if (dataType === 'edge') { var params = this.getDataParams(dataIndex, dataType); var rawDataOpt = params.data; var html = rawDataOpt.source + ' -- ' + rawDataOpt.target; if (params.value) { html += ' : ' + params.value; } return html; } return SankeySeries.superCall(this, 'formatTooltip', dataIndex, multipleSeries); }, defaultOption: { zlevel: 0, z: 2, coordinateSystem: 'view', layout: null, // the position of the whole view left: '5%', top: '5%', right: '20%', bottom: '5%', // the dx of the node nodeWidth: 20, // the vertical distance between two nodes nodeGap: 8, // the number of iterations to change the position of the node layoutIterations: 32, label: { normal: { show: true, position: 'right', textStyle: { color: '#000', fontSize: 12 } }, emphasis: { show: true } }, itemStyle: { normal: { borderWidth: 1, borderColor: '#333' } }, lineStyle: { normal: { color: '#314656', opacity: 0.2, curveness: 0.5 }, emphasis: { opacity: 0.6 } }, animationEasing: 'linear', animationDuration: 1000 } }); module.exports = SankeySeries; /***/ }, /* 242 */ /***/ function(module, exports, __webpack_require__) { /** * @file The file used to draw sankey view * @author Deqing Li(annong035@gmail.com) */ var graphic = __webpack_require__(43); var zrUtil = __webpack_require__(4); var SankeyShape = graphic.extendShape({ shape: { x1: 0, y1: 0, x2: 0, y2: 0, cpx1: 0, cpy1: 0, cpx2: 0, cpy2: 0, extent: 0 }, buildPath: function (ctx, shape) { var halfExtent = shape.extent / 2; ctx.moveTo(shape.x1, shape.y1 - halfExtent); ctx.bezierCurveTo( shape.cpx1, shape.cpy1 - halfExtent, shape.cpx2, shape.cpy2 - halfExtent, shape.x2, shape.y2 - halfExtent ); ctx.lineTo(shape.x2, shape.y2 + halfExtent); ctx.bezierCurveTo( shape.cpx2, shape.cpy2 + halfExtent, shape.cpx1, shape.cpy1 + halfExtent, shape.x1, shape.y1 + halfExtent ); ctx.closePath(); } }); module.exports = __webpack_require__(1).extendChartView({ type: 'sankey', /** * @private * @type {module:echarts/chart/sankey/SankeySeries} */ _model: null, render: function (seriesModel, ecModel, api) { var graph = seriesModel.getGraph(); var group = this.group; var layoutInfo = seriesModel.layoutInfo; var nodeData = seriesModel.getData(); var edgeData = seriesModel.getData('edge'); this._model = seriesModel; group.removeAll(); group.position = [layoutInfo.x, layoutInfo.y]; // generate a bezire Curve for each edge graph.eachEdge(function (edge) { var curve = new SankeyShape(); curve.dataIndex = edge.dataIndex; curve.seriesIndex = seriesModel.seriesIndex; curve.dataType = 'edge'; var lineStyleModel = edge.getModel('lineStyle.normal'); var curvature = lineStyleModel.get('curveness'); var n1Layout = edge.node1.getLayout(); var n2Layout = edge.node2.getLayout(); var edgeLayout = edge.getLayout(); curve.shape.extent = Math.max(1, edgeLayout.dy); var x1 = n1Layout.x + n1Layout.dx; var y1 = n1Layout.y + edgeLayout.sy + edgeLayout.dy / 2; var x2 = n2Layout.x; var y2 = n2Layout.y + edgeLayout.ty + edgeLayout.dy / 2; var cpx1 = x1 * (1 - curvature) + x2 * curvature; var cpy1 = y1; var cpx2 = x1 * curvature + x2 * (1 - curvature); var cpy2 = y2; curve.setShape({ x1: x1, y1: y1, x2: x2, y2: y2, cpx1: cpx1, cpy1: cpy1, cpx2: cpx2, cpy2: cpy2 }); curve.setStyle(lineStyleModel.getItemStyle()); // Special color, use source node color or target node color switch (curve.style.fill) { case 'source': curve.style.fill = edge.node1.getVisual('color'); break; case 'target': curve.style.fill = edge.node2.getVisual('color'); break; } graphic.setHoverStyle(curve, edge.getModel('lineStyle.emphasis').getItemStyle()); group.add(curve); edgeData.setItemGraphicEl(edge.dataIndex, curve); }); // generate a rect for each node graph.eachNode(function (node) { var layout = node.getLayout(); var itemModel = node.getModel(); var labelModel = itemModel.getModel('label.normal'); var textStyleModel = labelModel.getModel('textStyle'); var labelHoverModel = itemModel.getModel('label.emphasis'); var textStyleHoverModel = labelHoverModel.getModel('textStyle'); var rect = new graphic.Rect({ shape: { x: layout.x, y: layout.y, width: node.getLayout().dx, height: node.getLayout().dy }, style: { // Get formatted label in label.normal option // Use node id if it is not specified text: labelModel.get('show') ? seriesModel.getFormattedLabel(node.dataIndex, 'normal') || node.id // Use empty string to hide the label : '', textFont: textStyleModel.getFont(), textFill: textStyleModel.getTextColor(), textPosition: labelModel.get('position') } }); rect.setStyle(zrUtil.defaults( { fill: node.getVisual('color') }, itemModel.getModel('itemStyle.normal').getItemStyle() )); graphic.setHoverStyle(rect, zrUtil.extend( node.getModel('itemStyle.emphasis'), { text: labelHoverModel.get('show') ? seriesModel.getFormattedLabel(node.dataIndex, 'emphasis') || node.id : '', textFont: textStyleHoverModel.getFont(), textFill: textStyleHoverModel.getTextColor(), textPosition: labelHoverModel.get('position') } )); group.add(rect); nodeData.setItemGraphicEl(node.dataIndex, rect); rect.dataType = 'node'; }); if (!this._data && seriesModel.get('animation')) { group.setClipPath(createGridClipShape(group.getBoundingRect(), seriesModel, function () { group.removeClipPath(); })); } this._data = seriesModel.getData(); }, dispose: function () {} }); // add animation to the view function createGridClipShape(rect, seriesModel, cb) { var rectEl = new graphic.Rect({ shape: { x: rect.x - 10, y: rect.y - 10, width: 0, height: rect.height + 20 } }); graphic.initProps(rectEl, { shape: { width: rect.width + 20, height: rect.height + 20 } }, seriesModel, cb); return rectEl; } /***/ }, /* 243 */ /***/ function(module, exports, __webpack_require__) { /** * @file The layout algorithm of sankey view * @author Deqing Li(annong035@gmail.com) */ var layout = __webpack_require__(21); var nest = __webpack_require__(244); var zrUtil = __webpack_require__(4); module.exports = function (ecModel, api, payload) { ecModel.eachSeriesByType('sankey', function (seriesModel) { var nodeWidth = seriesModel.get('nodeWidth'); var nodeGap = seriesModel.get('nodeGap'); var layoutInfo = getViewRect(seriesModel, api); seriesModel.layoutInfo = layoutInfo; var width = layoutInfo.width; var height = layoutInfo.height; var graph = seriesModel.getGraph(); var nodes = graph.nodes; var edges = graph.edges; computeNodeValues(nodes); var filteredNodes = nodes.filter(function (node) { return node.getLayout().value === 0; }); var iterations = filteredNodes.length !== 0 ? 0 : seriesModel.get('layoutIterations'); layoutSankey(nodes, edges, nodeWidth, nodeGap, width, height, iterations); }); }; /** * Get the layout position of the whole view * * @param {module:echarts/model/Series} seriesModel the model object of sankey series * @param {module:echarts/ExtensionAPI} api provide the API list that the developer can call * @return {module:zrender/core/BoundingRect} size of rect to draw the sankey view */ function getViewRect(seriesModel, api) { return layout.getLayoutRect( seriesModel.getBoxLayoutParams(), { width: api.getWidth(), height: api.getHeight() } ); } function layoutSankey(nodes, edges, nodeWidth, nodeGap, width, height, iterations) { computeNodeBreadths(nodes, nodeWidth, width); computeNodeDepths(nodes, edges, height, nodeGap, iterations); computeEdgeDepths(nodes); } /** * Compute the value of each node by summing the associated edge's value * * @param {module:echarts/data/Graph~Node} nodes node of sankey view */ function computeNodeValues(nodes) { zrUtil.each(nodes, function (node) { var value1 = sum(node.outEdges, getEdgeValue); var value2 = sum(node.inEdges, getEdgeValue); var value = Math.max(value1, value2); node.setLayout({value: value}, true); }); } /** * Compute the x-position for each node * * @param {module:echarts/data/Graph~Node} nodes node of sankey view * @param {number} nodeWidth the dx of the node * @param {number} width the whole width of the area to draw the view */ function computeNodeBreadths(nodes, nodeWidth, width) { var remainNodes = nodes; var nextNode = null; var x = 0; var kx = 0; while (remainNodes.length) { nextNode = []; for (var i = 0, len = remainNodes.length; i < len; i++) { var node = remainNodes[i]; node.setLayout({x: x}, true); node.setLayout({dx: nodeWidth}, true); for (var j = 0, lenj = node.outEdges.length; j < lenj; j++) { nextNode.push(node.outEdges[j].node2); } } remainNodes = nextNode; ++x; } moveSinksRight(nodes, x); kx = (width - nodeWidth) / (x - 1); scaleNodeBreadths(nodes, kx); } /** * All the node without outEgdes are assigned maximum x-position and * be aligned in the last column. * * @param {module:echarts/data/Graph~Node} nodes node of sankey view * @param {number} x value (x-1) use to assign to node without outEdges * as x-position */ function moveSinksRight(nodes, x) { zrUtil.each(nodes, function (node) { if (!node.outEdges.length) { node.setLayout({x: x - 1}, true); } }); } /** * Scale node x-position to the width * * @param {module:echarts/data/Graph~Node} nodes node of sankey view * @param {number} kx multiple used to scale nodes */ function scaleNodeBreadths(nodes, kx) { zrUtil.each(nodes, function (node) { var nodeX = node.getLayout().x * kx; node.setLayout({x: nodeX}, true); }); } /** * Using Gauss-Seidel iterations method to compute the node depth(y-position) * * @param {module:echarts/data/Graph~Node} nodes node of sankey view * @param {module:echarts/data/Graph~Edge} edges edge of sankey view * @param {number} height the whole height of the area to draw the view * @param {numbber} nodeGap the vertical distance between two nodes * in the same column. * @param {number} iterations the number of iterations for the algorithm */ function computeNodeDepths(nodes, edges, height, nodeGap, iterations) { var nodesByBreadth = nest() .key(function (d) { return d.getLayout().x; }) .sortKeys(ascending) .entries(nodes) .map(function (d) { return d.values; }); initializeNodeDepth(nodes, nodesByBreadth, edges, height, nodeGap); resolveCollisions(nodesByBreadth, nodeGap, height); for (var alpha = 1; iterations > 0; iterations--) { // 0.99 is a experience parameter, ensure that each iterations of // changes as small as possible. alpha *= 0.99; relaxRightToLeft(nodesByBreadth, alpha); resolveCollisions(nodesByBreadth, nodeGap, height); relaxLeftToRight(nodesByBreadth, alpha); resolveCollisions(nodesByBreadth, nodeGap, height); } } /** * Compute the original y-position for each node * * @param {module:echarts/data/Graph~Node} nodes node of sankey view * @param {Array.>} nodesByBreadth * group by the array of all sankey nodes based on the nodes x-position. * @param {module:echarts/data/Graph~Edge} edges edge of sankey view * @param {number} height the whole height of the area to draw the view * @param {number} nodeGap the vertical distance between two nodes */ function initializeNodeDepth(nodes, nodesByBreadth, edges, height, nodeGap) { var kyArray = []; zrUtil.each(nodesByBreadth, function (nodes) { var n = nodes.length; var sum = 0; zrUtil.each(nodes, function (node) { sum += node.getLayout().value; }); var ky = (height - (n - 1) * nodeGap) / sum; kyArray.push(ky); }); kyArray.sort(function (a, b) { return a - b; }); var ky0 = kyArray[0]; zrUtil.each(nodesByBreadth, function (nodes) { zrUtil.each(nodes, function (node, i) { node.setLayout({y: i}, true); var nodeDy = node.getLayout().value * ky0; node.setLayout({dy: nodeDy}, true); }); }); zrUtil.each(edges, function (edge) { var edgeDy = +edge.getValue() * ky0; edge.setLayout({dy: edgeDy}, true); }); } /** * Resolve the collision of initialized depth (y-position) * * @param {Array.>} nodesByBreadth * group by the array of all sankey nodes based on the nodes x-position. * @param {number} nodeGap the vertical distance between two nodes * @param {number} height the whole height of the area to draw the view */ function resolveCollisions(nodesByBreadth, nodeGap, height) { zrUtil.each(nodesByBreadth, function (nodes) { var node; var dy; var y0 = 0; var n = nodes.length; var i; nodes.sort(ascendingDepth); for (i = 0; i < n; i++) { node = nodes[i]; dy = y0 - node.getLayout().y; if (dy > 0) { var nodeY = node.getLayout().y + dy; node.setLayout({y: nodeY}, true); } y0 = node.getLayout().y + node.getLayout().dy + nodeGap; } // if the bottommost node goes outside the bounds, push it back up dy = y0 - nodeGap - height; if (dy > 0) { var nodeY = node.getLayout().y - dy; node.setLayout({y: nodeY}, true); y0 = node.getLayout().y; for (i = n - 2; i >= 0; --i) { node = nodes[i]; dy = node.getLayout().y + node.getLayout().dy + nodeGap - y0; if (dy > 0) { nodeY = node.getLayout().y - dy; node.setLayout({y: nodeY}, true); } y0 = node.getLayout().y; } } }); } /** * Change the y-position of the nodes, except most the right side nodes * * @param {Array.>} nodesByBreadth * group by the array of all sankey nodes based on the node x-position. * @param {number} alpha parameter used to adjust the nodes y-position */ function relaxRightToLeft(nodesByBreadth, alpha) { zrUtil.each(nodesByBreadth.slice().reverse(), function (nodes) { zrUtil.each(nodes, function (node) { if (node.outEdges.length) { var y = sum(node.outEdges, weightedTarget) / sum(node.outEdges, getEdgeValue); var nodeY = node.getLayout().y + (y - center(node)) * alpha; node.setLayout({y: nodeY}, true); } }); }); } function weightedTarget(edge) { return center(edge.node2) * edge.getValue(); } /** * Change the y-position of the nodes, except most the left side nodes * * @param {Array.>} nodesByBreadth * group by the array of all sankey nodes based on the node x-position. * @param {number} alpha parameter used to adjust the nodes y-position */ function relaxLeftToRight(nodesByBreadth, alpha) { zrUtil.each(nodesByBreadth, function (nodes) { zrUtil.each(nodes, function (node) { if (node.inEdges.length) { var y = sum(node.inEdges, weightedSource) / sum(node.inEdges, getEdgeValue); var nodeY = node.getLayout().y + (y - center(node)) * alpha; node.setLayout({y: nodeY}, true); } }); }); } function weightedSource(edge) { return center(edge.node1) * edge.getValue(); } /** * Compute the depth(y-position) of each edge * * @param {module:echarts/data/Graph~Node} nodes node of sankey view */ function computeEdgeDepths(nodes) { zrUtil.each(nodes, function (node) { node.outEdges.sort(ascendingTargetDepth); node.inEdges.sort(ascendingSourceDepth); }); zrUtil.each(nodes, function (node) { var sy = 0; var ty = 0; zrUtil.each(node.outEdges, function (edge) { edge.setLayout({sy: sy}, true); sy += edge.getLayout().dy; }); zrUtil.each(node.inEdges, function (edge) { edge.setLayout({ty: ty}, true); ty += edge.getLayout().dy; }); }); } function ascendingTargetDepth(a, b) { return a.node2.getLayout().y - b.node2.getLayout().y; } function ascendingSourceDepth(a, b) { return a.node1.getLayout().y - b.node1.getLayout().y; } function sum(array, f) { var sum = 0; var len = array.length; var i = -1; while (++i < len) { var value = +f.call(array, array[i], i); if (!isNaN(value)) { sum += value; } } return sum; } function center(node) { return node.getLayout().y + node.getLayout().dy / 2; } function ascendingDepth(a, b) { return a.getLayout().y - b.getLayout().y; } function ascending(a, b) { return a < b ? -1 : a > b ? 1 : a === b ? 0 : NaN; } function getEdgeValue(edge) { return edge.getValue(); } /***/ }, /* 244 */ /***/ function(module, exports, __webpack_require__) { var zrUtil = __webpack_require__(4); /** * nest helper used to group by the array. * can specified the keys and sort the keys. */ function nest() { var keysFunction = []; var sortKeysFunction = []; /** * map an Array into the mapObject. * @param {Array} array * @param {number} depth */ function map(array, depth) { if (depth >= keysFunction.length) { return array; } var i = -1; var n = array.length; var keyFunction = keysFunction[depth++]; var mapObject = {}; var valuesByKey = {}; while (++i < n) { var keyValue = keyFunction(array[i]); var values = valuesByKey[keyValue]; if (values) { values.push(array[i]); } else { valuesByKey[keyValue] = [array[i]]; } } zrUtil.each(valuesByKey, function (value, key) { mapObject[key] = map(value, depth); }); return mapObject; } /** * transform the Map Object to multidimensional Array * @param {Object} map * @param {number} depth */ function entriesMap(mapObject, depth) { if (depth >= keysFunction.length) { return mapObject; } var array = []; var sortKeyFunction = sortKeysFunction[depth++]; zrUtil.each(mapObject, function (value, key) { array.push({ key: key, values: entriesMap(value, depth) }); }); if (sortKeyFunction) { return array.sort(function (a, b) { return sortKeyFunction(a.key, b.key); }); } else { return array; } } return { /** * specified the key to groupby the arrays. * users can specified one more keys. * @param {Function} d */ key: function (d) { keysFunction.push(d); return this; }, /** * specified the comparator to sort the keys * @param {Function} order */ sortKeys: function (order) { sortKeysFunction[keysFunction.length - 1] = order; return this; }, /** * the array to be grouped by. * @param {Array} array */ entries: function (array) { return entriesMap(map(array, 0), 0); } }; } module.exports = nest; /***/ }, /* 245 */ /***/ function(module, exports, __webpack_require__) { /** * @file Visual encoding for sankey view * @author Deqing Li(annong035@gmail.com) */ var VisualMapping = __webpack_require__(194); var zrUtil = __webpack_require__(4); module.exports = function (ecModel, payload) { ecModel.eachSeriesByType('sankey', function (seriesModel) { var graph = seriesModel.getGraph(); var nodes = graph.nodes; nodes.sort(function (a, b) { return a.getLayout().value - b.getLayout().value; }); var minValue = nodes[0].getLayout().value; var maxValue = nodes[nodes.length - 1].getLayout().value; zrUtil.each(nodes, function (node) { var mapping = new VisualMapping({ type: 'color', mappingMethod: 'linear', dataExtent: [minValue, maxValue], visual: seriesModel.get('color') }); var mapValueToColor = mapping.mapValueToVisual(node.getLayout().value); node.setVisual('color', mapValueToColor); // If set itemStyle.normal.color var itemModel = node.getModel(); var customColor = itemModel.get('itemStyle.normal.color'); if (customColor != null) { node.setVisual('color', customColor); } }); }); }; /***/ }, /* 246 */ /***/ function(module, exports, __webpack_require__) { var echarts = __webpack_require__(1); __webpack_require__(247); __webpack_require__(250); echarts.registerVisual(__webpack_require__(251)); echarts.registerLayout(__webpack_require__(252)); /***/ }, /* 247 */ /***/ function(module, exports, __webpack_require__) { 'use strict'; var zrUtil = __webpack_require__(4); var SeriesModel = __webpack_require__(28); var whiskerBoxCommon = __webpack_require__(248); var BoxplotSeries = SeriesModel.extend({ type: 'series.boxplot', dependencies: ['xAxis', 'yAxis', 'grid'], // TODO // box width represents group size, so dimension should have 'size'. /** * @see * The meanings of 'min' and 'max' depend on user, * and echarts do not need to know it. * @readOnly */ valueDimensions: ['min', 'Q1', 'median', 'Q3', 'max'], /** * @type {Array.} * @readOnly */ dimensions: null, /** * @override */ defaultOption: { zlevel: 0, // 一级层叠 z: 2, // 二级层叠 coordinateSystem: 'cartesian2d', legendHoverLink: true, hoverAnimation: true, // xAxisIndex: 0, // yAxisIndex: 0, layout: null, // 'horizontal' or 'vertical' boxWidth: [7, 50], // [min, max] can be percent of band width. itemStyle: { normal: { color: '#fff', borderWidth: 1 }, emphasis: { borderWidth: 2, shadowBlur: 5, shadowOffsetX: 2, shadowOffsetY: 2, shadowColor: 'rgba(0,0,0,0.4)' } }, animationEasing: 'elasticOut', animationDuration: 800 } }); zrUtil.mixin(BoxplotSeries, whiskerBoxCommon.seriesModelMixin, true); module.exports = BoxplotSeries; /***/ }, /* 248 */ /***/ function(module, exports, __webpack_require__) { 'use strict'; var List = __webpack_require__(98); var completeDimensions = __webpack_require__(103); var WhiskerBoxDraw = __webpack_require__(249); var zrUtil = __webpack_require__(4); function getItemValue(item) { return item.value == null ? item : item.value; } var seriesModelMixin = { /** * @private * @type {string} */ _baseAxisDim: null, /** * @override */ getInitialData: function (option, ecModel) { // When both types of xAxis and yAxis are 'value', layout is // needed to be specified by user. Otherwise, layout can be // judged by which axis is category. var categories; var xAxisModel = ecModel.getComponent('xAxis', this.get('xAxisIndex')); var yAxisModel = ecModel.getComponent('yAxis', this.get('yAxisIndex')); var xAxisType = xAxisModel.get('type'); var yAxisType = yAxisModel.get('type'); var addOrdinal; // FIXME // 考虑时间轴 if (xAxisType === 'category') { option.layout = 'horizontal'; categories = xAxisModel.getCategories(); addOrdinal = true; } else if (yAxisType === 'category') { option.layout = 'vertical'; categories = yAxisModel.getCategories(); addOrdinal = true; } else { option.layout = option.layout || 'horizontal'; } this._baseAxisDim = option.layout === 'horizontal' ? 'x' : 'y'; var data = option.data; var dimensions = this.dimensions = ['base'].concat(this.valueDimensions); completeDimensions(dimensions, data); var list = new List(dimensions, this); list.initData(data, categories ? categories.slice() : null, function (dataItem, dimName, idx, dimIdx) { var value = getItemValue(dataItem); return addOrdinal ? (dimName === 'base' ? idx : value[dimIdx - 1]) : value[dimIdx]; }); return list; }, /** * Used by Gird. * @param {string} axisDim 'x' or 'y' * @return {Array.} dimensions on the axis. */ coordDimToDataDim: function (axisDim) { var dims = this.valueDimensions.slice(); var baseDim = ['base']; var map = { horizontal: {x: baseDim, y: dims}, vertical: {x: dims, y: baseDim} }; return map[this.get('layout')][axisDim]; }, /** * @override * @param {string|number} dataDim * @return {string} coord dimension */ dataDimToCoordDim: function (dataDim) { var dim; zrUtil.each(['x', 'y'], function (coordDim, index) { var dataDims = this.coordDimToDataDim(coordDim); if (zrUtil.indexOf(dataDims, dataDim) >= 0) { dim = coordDim; } }, this); return dim; }, /** * If horizontal, base axis is x, otherwise y. * @override */ getBaseAxis: function () { var dim = this._baseAxisDim; return this.ecModel.getComponent(dim + 'Axis', this.get(dim + 'AxisIndex')).axis; } }; var viewMixin = { init: function () { /** * Old data. * @private * @type {module:echarts/chart/helper/WhiskerBoxDraw} */ var whiskerBoxDraw = this._whiskerBoxDraw = new WhiskerBoxDraw( this.getStyleUpdater() ); this.group.add(whiskerBoxDraw.group); }, render: function (seriesModel, ecModel, api) { this._whiskerBoxDraw.updateData(seriesModel.getData()); }, remove: function (ecModel) { this._whiskerBoxDraw.remove(); } }; module.exports = { seriesModelMixin: seriesModelMixin, viewMixin: viewMixin }; /***/ }, /* 249 */ /***/ function(module, exports, __webpack_require__) { /** * @module echarts/chart/helper/Symbol */ var zrUtil = __webpack_require__(4); var graphic = __webpack_require__(43); var Path = __webpack_require__(45); var WhiskerPath = Path.extend({ type: 'whiskerInBox', shape: {}, buildPath: function (ctx, shape) { for (var i in shape) { if (shape.hasOwnProperty(i) && i.indexOf('ends') === 0) { var pts = shape[i]; ctx.moveTo(pts[0][0], pts[0][1]); ctx.lineTo(pts[1][0], pts[1][1]); } } } }); /** * @constructor * @alias {module:echarts/chart/helper/WhiskerBox} * @param {module:echarts/data/List} data * @param {number} idx * @param {Function} styleUpdater * @param {boolean} isInit * @extends {module:zrender/graphic/Group} */ function WhiskerBox(data, idx, styleUpdater, isInit) { graphic.Group.call(this); /** * @type {number} * @readOnly */ this.bodyIndex; /** * @type {number} * @readOnly */ this.whiskerIndex; /** * @type {Function} */ this.styleUpdater = styleUpdater; this._createContent(data, idx, isInit); this.updateData(data, idx, isInit); /** * Last series model. * @type {module:echarts/model/Series} */ this._seriesModel; } var whiskerBoxProto = WhiskerBox.prototype; whiskerBoxProto._createContent = function (data, idx, isInit) { var itemLayout = data.getItemLayout(idx); var constDim = itemLayout.chartLayout === 'horizontal' ? 1 : 0; var count = 0; // Whisker element. this.add(new graphic.Polygon({ shape: { points: isInit ? transInit(itemLayout.bodyEnds, constDim, itemLayout) : itemLayout.bodyEnds }, style: {strokeNoScale: true}, z2: 100 })); this.bodyIndex = count++; // Box element. var whiskerEnds = zrUtil.map(itemLayout.whiskerEnds, function (ends) { return isInit ? transInit(ends, constDim, itemLayout) : ends; }); this.add(new WhiskerPath({ shape: makeWhiskerEndsShape(whiskerEnds), style: {strokeNoScale: true}, z2: 100 })); this.whiskerIndex = count++; }; function transInit(points, dim, itemLayout) { return zrUtil.map(points, function (point) { point = point.slice(); point[dim] = itemLayout.initBaseline; return point; }); } function makeWhiskerEndsShape(whiskerEnds) { // zr animation only support 2-dim array. var shape = {}; zrUtil.each(whiskerEnds, function (ends, i) { shape['ends' + i] = ends; }); return shape; } /** * Update symbol properties * @param {module:echarts/data/List} data * @param {number} idx */ whiskerBoxProto.updateData = function (data, idx, isInit) { var seriesModel = this._seriesModel = data.hostModel; var itemLayout = data.getItemLayout(idx); var updateMethod = graphic[isInit ? 'initProps' : 'updateProps']; // this.childAt(this.bodyIndex).stopAnimation(true); // this.childAt(this.whiskerIndex).stopAnimation(true); updateMethod( this.childAt(this.bodyIndex), {shape: {points: itemLayout.bodyEnds}}, seriesModel, idx ); updateMethod( this.childAt(this.whiskerIndex), {shape: makeWhiskerEndsShape(itemLayout.whiskerEnds)}, seriesModel, idx ); this.styleUpdater.call(null, this, data, idx); }; zrUtil.inherits(WhiskerBox, graphic.Group); /** * @constructor * @alias module:echarts/chart/helper/WhiskerBoxDraw */ function WhiskerBoxDraw(styleUpdater) { this.group = new graphic.Group(); this.styleUpdater = styleUpdater; } var whiskerBoxDrawProto = WhiskerBoxDraw.prototype; /** * Update symbols draw by new data * @param {module:echarts/data/List} data */ whiskerBoxDrawProto.updateData = function (data) { var group = this.group; var oldData = this._data; var styleUpdater = this.styleUpdater; data.diff(oldData) .add(function (newIdx) { if (data.hasValue(newIdx)) { var symbolEl = new WhiskerBox(data, newIdx, styleUpdater, true); data.setItemGraphicEl(newIdx, symbolEl); group.add(symbolEl); } }) .update(function (newIdx, oldIdx) { var symbolEl = oldData.getItemGraphicEl(oldIdx); // Empty data if (!data.hasValue(newIdx)) { group.remove(symbolEl); return; } if (!symbolEl) { symbolEl = new WhiskerBox(data, newIdx, styleUpdater); } else { symbolEl.updateData(data, newIdx); } // Add back group.add(symbolEl); data.setItemGraphicEl(newIdx, symbolEl); }) .remove(function (oldIdx) { var el = oldData.getItemGraphicEl(oldIdx); el && group.remove(el); }) .execute(); this._data = data; }; /** * Remove symbols. * @param {module:echarts/data/List} data */ whiskerBoxDrawProto.remove = function () { var group = this.group; var data = this._data; this._data = null; data && data.eachItemGraphicEl(function (el) { el && group.remove(el); }); }; module.exports = WhiskerBoxDraw; /***/ }, /* 250 */ /***/ function(module, exports, __webpack_require__) { 'use strict'; var zrUtil = __webpack_require__(4); var ChartView = __webpack_require__(42); var graphic = __webpack_require__(43); var whiskerBoxCommon = __webpack_require__(248); var BoxplotView = ChartView.extend({ type: 'boxplot', getStyleUpdater: function () { return updateStyle; }, dispose: zrUtil.noop }); zrUtil.mixin(BoxplotView, whiskerBoxCommon.viewMixin, true); // Update common properties var normalStyleAccessPath = ['itemStyle', 'normal']; var emphasisStyleAccessPath = ['itemStyle', 'emphasis']; function updateStyle(itemGroup, data, idx) { var itemModel = data.getItemModel(idx); var normalItemStyleModel = itemModel.getModel(normalStyleAccessPath); var borderColor = data.getItemVisual(idx, 'color'); // Exclude borderColor. var itemStyle = normalItemStyleModel.getItemStyle(['borderColor']); var whiskerEl = itemGroup.childAt(itemGroup.whiskerIndex); whiskerEl.style.set(itemStyle); whiskerEl.style.stroke = borderColor; whiskerEl.dirty(); var bodyEl = itemGroup.childAt(itemGroup.bodyIndex); bodyEl.style.set(itemStyle); bodyEl.style.stroke = borderColor; bodyEl.dirty(); var hoverStyle = itemModel.getModel(emphasisStyleAccessPath).getItemStyle(); graphic.setHoverStyle(itemGroup, hoverStyle); } module.exports = BoxplotView; /***/ }, /* 251 */ /***/ function(module, exports) { var borderColorQuery = ['itemStyle', 'normal', 'borderColor']; module.exports = function (ecModel, api) { var globalColors = ecModel.get('color'); ecModel.eachRawSeriesByType('boxplot', function (seriesModel) { var defaulColor = globalColors[seriesModel.seriesIndex % globalColors.length]; var data = seriesModel.getData(); data.setVisual({ legendSymbol: 'roundRect', // Use name 'color' but not 'borderColor' for legend usage and // visual coding from other component like dataRange. color: seriesModel.get(borderColorQuery) || defaulColor }); // Only visible series has each data be visual encoded if (!ecModel.isSeriesFiltered(seriesModel)) { data.each(function (idx) { var itemModel = data.getItemModel(idx); data.setItemVisual( idx, {color: itemModel.get(borderColorQuery, true)} ); }); } }); }; /***/ }, /* 252 */ /***/ function(module, exports, __webpack_require__) { var zrUtil = __webpack_require__(4); var numberUtil = __webpack_require__(7); var parsePercent = numberUtil.parsePercent; var each = zrUtil.each; module.exports = function (ecModel) { var groupResult = groupSeriesByAxis(ecModel); each(groupResult, function (groupItem) { var seriesModels = groupItem.seriesModels; if (!seriesModels.length) { return; } calculateBase(groupItem); each(seriesModels, function (seriesModel, idx) { layoutSingleSeries( seriesModel, groupItem.boxOffsetList[idx], groupItem.boxWidthList[idx] ); }); }); }; /** * Group series by axis. */ function groupSeriesByAxis(ecModel) { var result = []; var axisList = []; ecModel.eachSeriesByType('boxplot', function (seriesModel) { var baseAxis = seriesModel.getBaseAxis(); var idx = zrUtil.indexOf(axisList, baseAxis); if (idx < 0) { idx = axisList.length; axisList[idx] = baseAxis; result[idx] = {axis: baseAxis, seriesModels: []}; } result[idx].seriesModels.push(seriesModel); }); return result; } /** * Calculate offset and box width for each series. */ function calculateBase(groupItem) { var extent; var baseAxis = groupItem.axis; var seriesModels = groupItem.seriesModels; var seriesCount = seriesModels.length; var boxWidthList = groupItem.boxWidthList = []; var boxOffsetList = groupItem.boxOffsetList = []; var boundList = []; var bandWidth; if (baseAxis.type === 'category') { bandWidth = baseAxis.getBandWidth(); } else { var maxDataCount = 0; each(seriesModels, function (seriesModel) { maxDataCount = Math.max(maxDataCount, seriesModel.getData().count()); }); extent = baseAxis.getExtent(), Math.abs(extent[1] - extent[0]) / maxDataCount; } each(seriesModels, function (seriesModel) { var boxWidthBound = seriesModel.get('boxWidth'); if (!zrUtil.isArray(boxWidthBound)) { boxWidthBound = [boxWidthBound, boxWidthBound]; } boundList.push([ parsePercent(boxWidthBound[0], bandWidth) || 0, parsePercent(boxWidthBound[1], bandWidth) || 0 ]); }); var availableWidth = bandWidth * 0.8 - 2; var boxGap = availableWidth / seriesCount * 0.3; var boxWidth = (availableWidth - boxGap * (seriesCount - 1)) / seriesCount; var base = boxWidth / 2 - availableWidth / 2; each(seriesModels, function (seriesModel, idx) { boxOffsetList.push(base); base += boxGap + boxWidth; boxWidthList.push( Math.min(Math.max(boxWidth, boundList[idx][0]), boundList[idx][1]) ); }); } /** * Calculate points location for each series. */ function layoutSingleSeries(seriesModel, offset, boxWidth) { var coordSys = seriesModel.coordinateSystem; var data = seriesModel.getData(); var dimensions = seriesModel.dimensions; var chartLayout = seriesModel.get('layout'); var halfWidth = boxWidth / 2; data.each(dimensions, function () { var args = arguments; var dimLen = dimensions.length; var axisDimVal = args[0]; var idx = args[dimLen]; var variableDim = chartLayout === 'horizontal' ? 0 : 1; var constDim = 1 - variableDim; var median = getPoint(args[3]); var end1 = getPoint(args[1]); var end5 = getPoint(args[5]); var whiskerEnds = [ [end1, getPoint(args[2])], [end5, getPoint(args[4])] ]; layEndLine(end1); layEndLine(end5); layEndLine(median); var bodyEnds = []; addBodyEnd(whiskerEnds[0][1], 0); addBodyEnd(whiskerEnds[1][1], 1); data.setItemLayout(idx, { chartLayout: chartLayout, initBaseline: median[constDim], median: median, bodyEnds: bodyEnds, whiskerEnds: whiskerEnds }); function getPoint(val) { var p = []; p[variableDim] = axisDimVal; p[constDim] = val; var point; if (isNaN(axisDimVal) || isNaN(val)) { point = [NaN, NaN]; } else { point = coordSys.dataToPoint(p); point[variableDim] += offset; } return point; } function addBodyEnd(point, start) { var point1 = point.slice(); var point2 = point.slice(); point1[variableDim] += halfWidth; point2[variableDim] -= halfWidth; start ? bodyEnds.push(point1, point2) : bodyEnds.push(point2, point1); } function layEndLine(endCenter) { var line = [endCenter.slice(), endCenter.slice()]; line[0][variableDim] -= halfWidth; line[1][variableDim] += halfWidth; whiskerEnds.push(line); } }); } /***/ }, /* 253 */ /***/ function(module, exports, __webpack_require__) { var echarts = __webpack_require__(1); __webpack_require__(254); __webpack_require__(255); echarts.registerPreprocessor( __webpack_require__(256) ); echarts.registerVisual(__webpack_require__(257)); echarts.registerLayout(__webpack_require__(258)); /***/ }, /* 254 */ /***/ function(module, exports, __webpack_require__) { 'use strict'; var zrUtil = __webpack_require__(4); var SeriesModel = __webpack_require__(28); var whiskerBoxCommon = __webpack_require__(248); var formatUtil = __webpack_require__(6); var encodeHTML = formatUtil.encodeHTML; var addCommas = formatUtil.addCommas; var CandlestickSeries = SeriesModel.extend({ type: 'series.candlestick', dependencies: ['xAxis', 'yAxis', 'grid'], /** * @readOnly */ valueDimensions: ['open', 'close', 'lowest', 'highest'], /** * @type {Array.} * @readOnly */ dimensions: null, /** * @override */ defaultOption: { zlevel: 0, // 一级层叠 z: 2, // 二级层叠 coordinateSystem: 'cartesian2d', legendHoverLink: true, hoverAnimation: true, // xAxisIndex: 0, // yAxisIndex: 0, layout: null, // 'horizontal' or 'vertical' itemStyle: { normal: { color: '#c23531', // 阳线 positive color0: '#314656', // 阴线 negative '#c23531', '#314656' borderWidth: 1, // FIXME // ec2中使用的是lineStyle.color 和 lineStyle.color0 borderColor: '#c23531', borderColor0: '#314656' }, emphasis: { borderWidth: 2 } }, animationUpdate: false, animationEasing: 'linear', animationDuration: 300 }, /** * Get dimension for shadow in dataZoom * @return {string} dimension name */ getShadowDim: function () { return 'open'; }, /** * @override */ formatTooltip: function (dataIndex, mutipleSeries) { // It rearly use mutiple candlestick series in one cartesian, // so only consider one series in this default tooltip. var valueHTMLArr = zrUtil.map(this.valueDimensions, function (dim) { return dim + ': ' + addCommas(this._data.get(dim, dataIndex)); }, this); return encodeHTML(this.name) + '
' + valueHTMLArr.join('
'); }, brushSelector: function (itemLayout, selectors) { return selectors.rect(itemLayout.brushRect); } }); zrUtil.mixin(CandlestickSeries, whiskerBoxCommon.seriesModelMixin, true); module.exports = CandlestickSeries; /***/ }, /* 255 */ /***/ function(module, exports, __webpack_require__) { 'use strict'; var zrUtil = __webpack_require__(4); var ChartView = __webpack_require__(42); var graphic = __webpack_require__(43); var whiskerBoxCommon = __webpack_require__(248); var CandlestickView = ChartView.extend({ type: 'candlestick', getStyleUpdater: function () { return updateStyle; }, dispose: zrUtil.noop }); zrUtil.mixin(CandlestickView, whiskerBoxCommon.viewMixin, true); // Update common properties var normalStyleAccessPath = ['itemStyle', 'normal']; var emphasisStyleAccessPath = ['itemStyle', 'emphasis']; function updateStyle(itemGroup, data, idx) { var itemModel = data.getItemModel(idx); var normalItemStyleModel = itemModel.getModel(normalStyleAccessPath); var color = data.getItemVisual(idx, 'color'); var borderColor = data.getItemVisual(idx, 'borderColor') || color; // Color must be excluded. // Because symbol provide setColor individually to set fill and stroke var itemStyle = normalItemStyleModel.getItemStyle( ['color', 'color0', 'borderColor', 'borderColor0'] ); var whiskerEl = itemGroup.childAt(itemGroup.whiskerIndex); whiskerEl.useStyle(itemStyle); whiskerEl.style.stroke = borderColor; var bodyEl = itemGroup.childAt(itemGroup.bodyIndex); bodyEl.useStyle(itemStyle); bodyEl.style.fill = color; bodyEl.style.stroke = borderColor; var hoverStyle = itemModel.getModel(emphasisStyleAccessPath).getItemStyle(); graphic.setHoverStyle(itemGroup, hoverStyle); } module.exports = CandlestickView; /***/ }, /* 256 */ /***/ function(module, exports, __webpack_require__) { var zrUtil = __webpack_require__(4); module.exports = function (option) { if (!option || !zrUtil.isArray(option.series)) { return; } // Translate 'k' to 'candlestick'. zrUtil.each(option.series, function (seriesItem) { if (zrUtil.isObject(seriesItem) && seriesItem.type === 'k') { seriesItem.type = 'candlestick'; } }); }; /***/ }, /* 257 */ /***/ function(module, exports) { var positiveBorderColorQuery = ['itemStyle', 'normal', 'borderColor']; var negativeBorderColorQuery = ['itemStyle', 'normal', 'borderColor0']; var positiveColorQuery = ['itemStyle', 'normal', 'color']; var negativeColorQuery = ['itemStyle', 'normal', 'color0']; module.exports = function (ecModel, api) { ecModel.eachRawSeriesByType('candlestick', function (seriesModel) { var data = seriesModel.getData(); data.setVisual({ legendSymbol: 'roundRect' }); // Only visible series has each data be visual encoded if (!ecModel.isSeriesFiltered(seriesModel)) { data.each(function (idx) { var itemModel = data.getItemModel(idx); var sign = data.getItemLayout(idx).sign; data.setItemVisual( idx, { color: itemModel.get( sign > 0 ? positiveColorQuery : negativeColorQuery ), borderColor: itemModel.get( sign > 0 ? positiveBorderColorQuery : negativeBorderColorQuery ) } ); }); } }); }; /***/ }, /* 258 */ /***/ function(module, exports) { var CANDLE_MIN_WIDTH = 2; var CANDLE_MIN_NICE_WIDTH = 5; var GPA_MIN = 4; module.exports = function (ecModel) { ecModel.eachSeriesByType('candlestick', function (seriesModel) { var coordSys = seriesModel.coordinateSystem; var data = seriesModel.getData(); var dimensions = seriesModel.dimensions; var chartLayout = seriesModel.get('layout'); var candleWidth = calculateCandleWidth(seriesModel, data); data.each(dimensions, function () { var args = arguments; var dimLen = dimensions.length; var axisDimVal = args[0]; var idx = args[dimLen]; var variableDim = chartLayout === 'horizontal' ? 0 : 1; var constDim = 1 - variableDim; var openVal = args[1]; var closeVal = args[2]; var lowestVal = args[3]; var highestVal = args[4]; var ocLow = Math.min(openVal, closeVal); var ocHigh = Math.max(openVal, closeVal); var ocLowPoint = getPoint(ocLow); var ocHighPoint = getPoint(ocHigh); var lowestPoint = getPoint(lowestVal); var highestPoint = getPoint(highestVal); var whiskerEnds = [ [highestPoint, ocHighPoint], [lowestPoint, ocLowPoint] ]; var bodyEnds = []; addBodyEnd(ocHighPoint, 0); addBodyEnd(ocLowPoint, 1); data.setItemLayout(idx, { chartLayout: chartLayout, sign: openVal > closeVal ? -1 : openVal < closeVal ? 1 : 0, initBaseline: openVal > closeVal ? ocHighPoint[constDim] : ocLowPoint[constDim], // open point. bodyEnds: bodyEnds, whiskerEnds: whiskerEnds, brushRect: makeBrushRect() }); function getPoint(val) { var p = []; p[variableDim] = axisDimVal; p[constDim] = val; return (isNaN(axisDimVal) || isNaN(val)) ? [NaN, NaN] : coordSys.dataToPoint(p); } function addBodyEnd(point, start) { var point1 = point.slice(); var point2 = point.slice(); point1[variableDim] += candleWidth / 2; point2[variableDim] -= candleWidth / 2; start ? bodyEnds.push(point1, point2) : bodyEnds.push(point2, point1); } function makeBrushRect() { var pmin = getPoint(Math.min(openVal, closeVal, lowestVal, highestVal)); var pmax = getPoint(Math.max(openVal, closeVal, lowestVal, highestVal)); pmin[variableDim] -= candleWidth / 2; pmax[variableDim] -= candleWidth / 2; return { x: pmin[0], y: pmin[1], width: constDim ? candleWidth : pmax[0] - pmin[0], height: constDim ? pmax[1] - pmin[1] : candleWidth }; } }, true); }); }; function calculateCandleWidth(seriesModel, data) { var baseAxis = seriesModel.getBaseAxis(); var extent; var bandWidth = baseAxis.type === 'category' ? baseAxis.getBandWidth() : ( extent = baseAxis.getExtent(), Math.abs(extent[1] - extent[0]) / data.count() ); // Half band width is perfect when space is enouph, otherwise // try not to be smaller than CANDLE_MIN_NICE_WIDTH (and only // gap is compressed), otherwise ensure not to be smaller than // CANDLE_MIN_WIDTH in spite of overlap. return bandWidth / 2 - 2 > CANDLE_MIN_NICE_WIDTH // "- 2" is minus border width ? bandWidth / 2 - 2 : bandWidth - CANDLE_MIN_NICE_WIDTH > GPA_MIN ? CANDLE_MIN_NICE_WIDTH : Math.max(bandWidth - GPA_MIN, CANDLE_MIN_WIDTH); } /***/ }, /* 259 */ /***/ function(module, exports, __webpack_require__) { var zrUtil = __webpack_require__(4); var echarts = __webpack_require__(1); __webpack_require__(260); __webpack_require__(261); echarts.registerVisual(zrUtil.curry( __webpack_require__(110), 'effectScatter', 'circle', null )); echarts.registerLayout(zrUtil.curry( __webpack_require__(111), 'effectScatter' )); /***/ }, /* 260 */ /***/ function(module, exports, __webpack_require__) { 'use strict'; var createListFromArray = __webpack_require__(102); var SeriesModel = __webpack_require__(28); module.exports = SeriesModel.extend({ type: 'series.effectScatter', dependencies: ['grid', 'polar'], getInitialData: function (option, ecModel) { var list = createListFromArray(option.data, this, ecModel); return list; }, brushSelector: 'point', defaultOption: { coordinateSystem: 'cartesian2d', zlevel: 0, z: 2, legendHoverLink: true, effectType: 'ripple', progressive: 0, // When to show the effect, option: 'render'|'emphasis' showEffectOn: 'render', // Ripple effect config rippleEffect: { period: 4, // Scale of ripple scale: 2.5, // Brush type can be fill or stroke brushType: 'fill' }, // Cartesian coordinate system // xAxisIndex: 0, // yAxisIndex: 0, // Polar coordinate system // polarIndex: 0, // Geo coordinate system // geoIndex: 0, // symbol: null, // 图形类型 symbolSize: 10 // 图形大小,半宽(半径)参数,当图形为方向或菱形则总宽度为symbolSize * 2 // symbolRotate: null, // 图形旋转控制 // large: false, // Available when large is true // largeThreshold: 2000, // itemStyle: { // normal: { // opacity: 1 // } // } } }); /***/ }, /* 261 */ /***/ function(module, exports, __webpack_require__) { var SymbolDraw = __webpack_require__(105); var EffectSymbol = __webpack_require__(262); __webpack_require__(1).extendChartView({ type: 'effectScatter', init: function () { this._symbolDraw = new SymbolDraw(EffectSymbol); }, render: function (seriesModel, ecModel, api) { var data = seriesModel.getData(); var effectSymbolDraw = this._symbolDraw; effectSymbolDraw.updateData(data); this.group.add(effectSymbolDraw.group); }, updateLayout: function () { this._symbolDraw.updateLayout(); }, remove: function (ecModel, api) { this._symbolDraw && this._symbolDraw.remove(api); }, dispose: function () {} }); /***/ }, /* 262 */ /***/ function(module, exports, __webpack_require__) { /** * Symbol with ripple effect * @module echarts/chart/helper/EffectSymbol */ var zrUtil = __webpack_require__(4); var symbolUtil = __webpack_require__(107); var graphic = __webpack_require__(43); var numberUtil = __webpack_require__(7); var Symbol = __webpack_require__(106); var Group = graphic.Group; var EFFECT_RIPPLE_NUMBER = 3; function normalizeSymbolSize(symbolSize) { if (!zrUtil.isArray(symbolSize)) { symbolSize = [+symbolSize, +symbolSize]; } return symbolSize; } function updateRipplePath(rippleGroup, effectCfg) { rippleGroup.eachChild(function (ripplePath) { ripplePath.attr({ z: effectCfg.z, zlevel: effectCfg.zlevel, style: { stroke: effectCfg.brushType === 'stroke' ? effectCfg.color : null, fill: effectCfg.brushType === 'fill' ? effectCfg.color : null } }); }); } /** * @constructor * @param {module:echarts/data/List} data * @param {number} idx * @extends {module:zrender/graphic/Group} */ function EffectSymbol(data, idx) { Group.call(this); var symbol = new Symbol(data, idx); var rippleGroup = new Group(); this.add(symbol); this.add(rippleGroup); rippleGroup.beforeUpdate = function () { this.attr(symbol.getScale()); }; this.updateData(data, idx); } var effectSymbolProto = EffectSymbol.prototype; effectSymbolProto.stopEffectAnimation = function () { this.childAt(1).removeAll(); }; effectSymbolProto.startEffectAnimation = function (effectCfg) { var symbolType = effectCfg.symbolType; var color = effectCfg.color; var rippleGroup = this.childAt(1); for (var i = 0; i < EFFECT_RIPPLE_NUMBER; i++) { // var ripplePath = symbolUtil.createSymbol( // symbolType, -0.5, -0.5, 1, 1, color // ); // If width/height are set too small (e.g., set to 1) on ios10 // and macOS Sierra, a circle stroke become a rect, no matter what // the scale is set. So we set width/height as 2. See #4136. var ripplePath = symbolUtil.createSymbol( symbolType, -1, -1, 2, 2, color ); ripplePath.attr({ style: { strokeNoScale: true }, z2: 99, silent: true, scale: [0.5, 0.5] }); var delay = -i / EFFECT_RIPPLE_NUMBER * effectCfg.period + effectCfg.effectOffset; // TODO Configurable effectCfg.period ripplePath.animate('', true) .when(effectCfg.period, { scale: [effectCfg.rippleScale / 2, effectCfg.rippleScale / 2] }) .delay(delay) .start(); ripplePath.animateStyle(true) .when(effectCfg.period, { opacity: 0 }) .delay(delay) .start(); rippleGroup.add(ripplePath); } updateRipplePath(rippleGroup, effectCfg); }; /** * Update effect symbol */ effectSymbolProto.updateEffectAnimation = function (effectCfg) { var oldEffectCfg = this._effectCfg; var rippleGroup = this.childAt(1); // Must reinitialize effect if following configuration changed var DIFFICULT_PROPS = ['symbolType', 'period', 'rippleScale']; for (var i = 0; i < DIFFICULT_PROPS; i++) { var propName = DIFFICULT_PROPS[i]; if (oldEffectCfg[propName] !== effectCfg[propName]) { this.stopEffectAnimation(); this.startEffectAnimation(effectCfg); return; } } updateRipplePath(rippleGroup, effectCfg); }; /** * Highlight symbol */ effectSymbolProto.highlight = function () { this.trigger('emphasis'); }; /** * Downplay symbol */ effectSymbolProto.downplay = function () { this.trigger('normal'); }; /** * Update symbol properties * @param {module:echarts/data/List} data * @param {number} idx */ effectSymbolProto.updateData = function (data, idx) { var seriesModel = data.hostModel; this.childAt(0).updateData(data, idx); var rippleGroup = this.childAt(1); var itemModel = data.getItemModel(idx); var symbolType = data.getItemVisual(idx, 'symbol'); var symbolSize = normalizeSymbolSize(data.getItemVisual(idx, 'symbolSize')); var color = data.getItemVisual(idx, 'color'); rippleGroup.attr('scale', symbolSize); rippleGroup.traverse(function (ripplePath) { ripplePath.attr({ fill: color }); }); var symbolOffset = itemModel.getShallow('symbolOffset'); if (symbolOffset) { var pos = rippleGroup.position; pos[0] = numberUtil.parsePercent(symbolOffset[0], symbolSize[0]); pos[1] = numberUtil.parsePercent(symbolOffset[1], symbolSize[1]); } rippleGroup.rotation = (itemModel.getShallow('symbolRotate') || 0) * Math.PI / 180 || 0; var effectCfg = {}; effectCfg.showEffectOn = seriesModel.get('showEffectOn'); effectCfg.rippleScale = itemModel.get('rippleEffect.scale'); effectCfg.brushType = itemModel.get('rippleEffect.brushType'); effectCfg.period = itemModel.get('rippleEffect.period') * 1000; effectCfg.effectOffset = idx / data.count(); effectCfg.z = itemModel.getShallow('z') || 0; effectCfg.zlevel = itemModel.getShallow('zlevel') || 0; effectCfg.symbolType = symbolType; effectCfg.color = color; this.off('mouseover').off('mouseout').off('emphasis').off('normal'); if (effectCfg.showEffectOn === 'render') { this._effectCfg ? this.updateEffectAnimation(effectCfg) : this.startEffectAnimation(effectCfg); this._effectCfg = effectCfg; } else { // Not keep old effect config this._effectCfg = null; this.stopEffectAnimation(); var symbol = this.childAt(0); var onEmphasis = function () { symbol.trigger('emphasis'); if (effectCfg.showEffectOn !== 'render') { this.startEffectAnimation(effectCfg); } }; var onNormal = function () { symbol.trigger('normal'); if (effectCfg.showEffectOn !== 'render') { this.stopEffectAnimation(); } }; this.on('mouseover', onEmphasis, this) .on('mouseout', onNormal, this) .on('emphasis', onEmphasis, this) .on('normal', onNormal, this); } this._effectCfg = effectCfg; }; effectSymbolProto.fadeOut = function (cb) { this.off('mouseover').off('mouseout').off('emphasis').off('normal'); cb && cb(); }; zrUtil.inherits(EffectSymbol, Group); module.exports = EffectSymbol; /***/ }, /* 263 */ /***/ function(module, exports, __webpack_require__) { __webpack_require__(264); __webpack_require__(265); var echarts = __webpack_require__(1); echarts.registerLayout( __webpack_require__(270) ); /***/ }, /* 264 */ /***/ function(module, exports, __webpack_require__) { 'use strict'; var SeriesModel = __webpack_require__(28); var List = __webpack_require__(98); var zrUtil = __webpack_require__(4); var CoordinateSystem = __webpack_require__(26); // Convert [ [{coord: []}, {coord: []}] ] // to [ { coords: [[]] } ] function preprocessOption (seriesOpt) { var data = seriesOpt.data; if (data && data[0] && data[0][0] && data[0][0].coord) { if (true) { console.warn('Lines data configuration has been changed to' + ' { coords:[[1,2],[2,3]] }'); } seriesOpt.data = zrUtil.map(data, function (itemOpt) { var coords = [ itemOpt[0].coord, itemOpt[1].coord ]; var target = { coords: coords }; if (itemOpt[0].name) { target.fromName = itemOpt[0].name; } if (itemOpt[1].name) { target.toName = itemOpt[1].name; } return zrUtil.mergeAll([target, itemOpt[0], itemOpt[1]]); }); } } var LinesSeries = SeriesModel.extend({ type: 'series.lines', dependencies: ['grid', 'polar'], visualColorAccessPath: 'lineStyle.normal.color', init: function (option) { // Not using preprocessor because mergeOption may not have series.type preprocessOption(option); LinesSeries.superApply(this, 'init', arguments); }, mergeOption: function (option) { preprocessOption(option); LinesSeries.superApply(this, 'mergeOption', arguments); }, getInitialData: function (option, ecModel) { if (true) { var CoordSys = CoordinateSystem.get(option.coordinateSystem); if (!CoordSys) { throw new Error('Unkown coordinate system ' + option.coordinateSystem); } } var lineData = new List(['value'], this); lineData.hasItemOption = false; lineData.initData(option.data, [], function (dataItem, dimName, dataIndex, dimIndex) { // dataItem is simply coords if (dataItem instanceof Array) { return NaN; } else { lineData.hasItemOption = true; var value = dataItem.value; if (value != null) { return value instanceof Array ? value[dimIndex] : value; } } }); return lineData; }, formatTooltip: function (dataIndex) { var data = this.getData(); var itemModel = data.getItemModel(dataIndex); var name = itemModel.get('name'); if (name) { return name; } var fromName = itemModel.get('fromName'); var toName = itemModel.get('toName'); return fromName + ' > ' + toName; }, defaultOption: { coordinateSystem: 'geo', zlevel: 0, z: 2, legendHoverLink: true, hoverAnimation: true, // Cartesian coordinate system xAxisIndex: 0, yAxisIndex: 0, // Geo coordinate system geoIndex: 0, effect: { show: false, period: 4, // Animation delay. support callback // delay: 0, // If move with constant speed px/sec // period will be ignored if this property is > 0, constantSpeed: 0, symbol: 'circle', symbolSize: 3, loop: true, // Length of trail, 0 - 1 trailLength: 0.2 // Same with lineStyle.normal.color // color }, large: false, // Available when large is true largeThreshold: 2000, // If lines are polyline // polyline not support curveness, label, animation polyline: false, label: { normal: { show: false, position: 'end' // distance: 5, // formatter: 标签文本格式器,同Tooltip.formatter,不支持异步回调 } }, lineStyle: { normal: { opacity: 0.5 } } } }); /***/ }, /* 265 */ /***/ function(module, exports, __webpack_require__) { var LineDraw = __webpack_require__(201); var EffectLine = __webpack_require__(266); var Line = __webpack_require__(202); var Polyline = __webpack_require__(267); var EffectPolyline = __webpack_require__(268); var LargeLineDraw = __webpack_require__(269); __webpack_require__(1).extendChartView({ type: 'lines', init: function () {}, render: function (seriesModel, ecModel, api) { var data = seriesModel.getData(); var lineDraw = this._lineDraw; var hasEffect = seriesModel.get('effect.show'); var isPolyline = seriesModel.get('polyline'); var isLarge = seriesModel.get('large') && data.count() >= seriesModel.get('largeThreshold'); if (true) { if (hasEffect && isLarge) { console.warn('Large lines not support effect'); } } if (hasEffect !== this._hasEffet || isPolyline !== this._isPolyline || isLarge !== this._isLarge) { if (lineDraw) { lineDraw.remove(); } lineDraw = this._lineDraw = isLarge ? new LargeLineDraw() : new LineDraw( isPolyline ? (hasEffect ? EffectPolyline : Polyline) : (hasEffect ? EffectLine : Line) ); this._hasEffet = hasEffect; this._isPolyline = isPolyline; this._isLarge = isLarge; } var zlevel = seriesModel.get('zlevel'); var trailLength = seriesModel.get('effect.trailLength'); var zr = api.getZr(); // Avoid the drag cause ghost shadow // FIXME Better way ? zr.painter.getLayer(zlevel).clear(true); // Config layer with motion blur if (this._lastZlevel != null) { zr.configLayer(this._lastZlevel, { motionBlur: false }); } if (hasEffect && trailLength) { if (true) { var notInIndividual = false; ecModel.eachSeries(function (otherSeriesModel) { if (otherSeriesModel !== seriesModel && otherSeriesModel.get('zlevel') === zlevel) { notInIndividual = true; } }); notInIndividual && console.warn('Lines with trail effect should have an individual zlevel'); } zr.configLayer(zlevel, { motionBlur: true, lastFrameAlpha: Math.max(Math.min(trailLength / 10 + 0.9, 1), 0) }); } this.group.add(lineDraw.group); lineDraw.updateData(data); this._lastZlevel = zlevel; }, updateLayout: function (seriesModel, ecModel, api) { this._lineDraw.updateLayout(seriesModel); // Not use motion when dragging or zooming var zr = api.getZr(); zr.painter.getLayer(this._lastZlevel).clear(true); }, remove: function (ecModel, api) { this._lineDraw && this._lineDraw.remove(api, true); }, dispose: function () {} }); /***/ }, /* 266 */ /***/ function(module, exports, __webpack_require__) { /** * Provide effect for line * @module echarts/chart/helper/EffectLine */ var graphic = __webpack_require__(43); var Line = __webpack_require__(202); var zrUtil = __webpack_require__(4); var symbolUtil = __webpack_require__(107); var vec2 = __webpack_require__(10); var curveUtil = __webpack_require__(50); /** * @constructor * @extends {module:zrender/graphic/Group} * @alias {module:echarts/chart/helper/Line} */ function EffectLine(lineData, idx, seriesScope) { graphic.Group.call(this); this.add(this.createLine(lineData, idx, seriesScope)); this._updateEffectSymbol(lineData, idx); } var effectLineProto = EffectLine.prototype; effectLineProto.createLine = function (lineData, idx, seriesScope) { return new Line(lineData, idx, seriesScope); }; effectLineProto._updateEffectSymbol = function (lineData, idx) { var itemModel = lineData.getItemModel(idx); var effectModel = itemModel.getModel('effect'); var size = effectModel.get('symbolSize'); var symbolType = effectModel.get('symbol'); if (!zrUtil.isArray(size)) { size = [size, size]; } var color = effectModel.get('color') || lineData.getItemVisual(idx, 'color'); var symbol = this.childAt(1); if (this._symbolType !== symbolType) { // Remove previous this.remove(symbol); symbol = symbolUtil.createSymbol( symbolType, -0.5, -0.5, 1, 1, color ); symbol.z2 = 100; symbol.culling = true; this.add(symbol); } // Symbol may be removed if loop is false if (!symbol) { return; } // Shadow color is same with color in default symbol.setStyle('shadowColor', color); symbol.setStyle(effectModel.getItemStyle(['color'])); symbol.attr('scale', size); symbol.setColor(color); symbol.attr('scale', size); this._symbolType = symbolType; this._updateEffectAnimation(lineData, effectModel, idx); }; effectLineProto._updateEffectAnimation = function (lineData, effectModel, idx) { var symbol = this.childAt(1); if (!symbol) { return; } var self = this; var points = lineData.getItemLayout(idx); var period = effectModel.get('period') * 1000; var loop = effectModel.get('loop'); var constantSpeed = effectModel.get('constantSpeed'); var delayExpr = zrUtil.retrieve(effectModel.get('delay'), function (idx) { return idx / lineData.count() * period / 3; }); var isDelayFunc = typeof delayExpr === 'function'; // Ignore when updating symbol.ignore = true; this.updateAnimationPoints(symbol, points); if (constantSpeed > 0) { period = this.getLineLength(symbol) / constantSpeed * 1000; } if (period !== this._period || loop !== this._loop) { symbol.stopAnimation(); var delay = delayExpr; if (isDelayFunc) { delay = delayExpr(idx); } if (symbol.__t > 0) { delay = -period * symbol.__t; } symbol.__t = 0; var animator = symbol.animate('', loop) .when(period, { __t: 1 }) .delay(delay) .during(function () { self.updateSymbolPosition(symbol); }); if (!loop) { animator.done(function () { self.remove(symbol); }); } animator.start(); } this._period = period; this._loop = loop; }; effectLineProto.getLineLength = function (symbol) { // Not so accurate return (vec2.dist(symbol.__p1, symbol.__cp1) + vec2.dist(symbol.__cp1, symbol.__p2)); }; effectLineProto.updateAnimationPoints = function (symbol, points) { symbol.__p1 = points[0]; symbol.__p2 = points[1]; symbol.__cp1 = points[2] || [ (points[0][0] + points[1][0]) / 2, (points[0][1] + points[1][1]) / 2 ]; }; effectLineProto.updateData = function (lineData, idx, seriesScope) { this.childAt(0).updateData(lineData, idx, seriesScope); this._updateEffectSymbol(lineData, idx); }; effectLineProto.updateSymbolPosition = function (symbol) { var p1 = symbol.__p1; var p2 = symbol.__p2; var cp1 = symbol.__cp1; var t = symbol.__t; var pos = symbol.position; var quadraticAt = curveUtil.quadraticAt; var quadraticDerivativeAt = curveUtil.quadraticDerivativeAt; pos[0] = quadraticAt(p1[0], cp1[0], p2[0], t); pos[1] = quadraticAt(p1[1], cp1[1], p2[1], t); // Tangent var tx = quadraticDerivativeAt(p1[0], cp1[0], p2[0], t); var ty = quadraticDerivativeAt(p1[1], cp1[1], p2[1], t); symbol.rotation = -Math.atan2(ty, tx) - Math.PI / 2; symbol.ignore = false; }; effectLineProto.updateLayout = function (lineData, idx) { this.childAt(0).updateLayout(lineData, idx); var effectModel = lineData.getItemModel(idx).getModel('effect'); this._updateEffectAnimation(lineData, effectModel, idx); }; zrUtil.inherits(EffectLine, graphic.Group); module.exports = EffectLine; /***/ }, /* 267 */ /***/ function(module, exports, __webpack_require__) { /** * @module echarts/chart/helper/Line */ var graphic = __webpack_require__(43); var zrUtil = __webpack_require__(4); /** * @constructor * @extends {module:zrender/graphic/Group} * @alias {module:echarts/chart/helper/Polyline} */ function Polyline(lineData, idx, seriesScope) { graphic.Group.call(this); this._createPolyline(lineData, idx, seriesScope); } var polylineProto = Polyline.prototype; polylineProto._createPolyline = function (lineData, idx, seriesScope) { // var seriesModel = lineData.hostModel; var points = lineData.getItemLayout(idx); var line = new graphic.Polyline({ shape: { points: points } }); this.add(line); this._updateCommonStl(lineData, idx, seriesScope); }; polylineProto.updateData = function (lineData, idx, seriesScope) { var seriesModel = lineData.hostModel; var line = this.childAt(0); var target = { shape: { points: lineData.getItemLayout(idx) } }; graphic.updateProps(line, target, seriesModel, idx); this._updateCommonStl(lineData, idx, seriesScope); }; polylineProto._updateCommonStl = function (lineData, idx, seriesScope) { var line = this.childAt(0); var itemModel = lineData.getItemModel(idx); var visualColor = lineData.getItemVisual(idx, 'color'); var lineStyle = seriesScope && seriesScope.lineStyle; var hoverLineStyle = seriesScope && seriesScope.hoverLineStyle; if (!seriesScope || lineData.hasItemOption) { lineStyle = itemModel.getModel('lineStyle.normal').getLineStyle(); hoverLineStyle = itemModel.getModel('lineStyle.emphasis').getLineStyle(); } line.useStyle(zrUtil.defaults( { strokeNoScale: true, fill: 'none', stroke: visualColor }, lineStyle )); line.hoverStyle = hoverLineStyle; graphic.setHoverStyle(this); }; polylineProto.updateLayout = function (lineData, idx) { var polyline = this.childAt(0); polyline.setShape('points', lineData.getItemLayout(idx)); }; zrUtil.inherits(Polyline, graphic.Group); module.exports = Polyline; /***/ }, /* 268 */ /***/ function(module, exports, __webpack_require__) { /** * Provide effect for line * @module echarts/chart/helper/EffectLine */ var Polyline = __webpack_require__(267); var zrUtil = __webpack_require__(4); var EffectLine = __webpack_require__(266); var vec2 = __webpack_require__(10); /** * @constructor * @extends {module:echarts/chart/helper/EffectLine} * @alias {module:echarts/chart/helper/Polyline} */ function EffectPolyline(lineData, idx, seriesScope) { EffectLine.call(this, lineData, idx, seriesScope); this._lastFrame = 0; this._lastFramePercent = 0; } var effectPolylineProto = EffectPolyline.prototype; // Overwrite effectPolylineProto.createLine = function (lineData, idx, seriesScope) { return new Polyline(lineData, idx, seriesScope); }; // Overwrite effectPolylineProto.updateAnimationPoints = function (symbol, points) { this._points = points; var accLenArr = [0]; var len = 0; for (var i = 1; i < points.length; i++) { var p1 = points[i - 1]; var p2 = points[i]; len += vec2.dist(p1, p2); accLenArr.push(len); } if (len === 0) { return; } for (var i = 0; i < accLenArr.length; i++) { accLenArr[i] /= len; } this._offsets = accLenArr; this._length = len; }; // Overwrite effectPolylineProto.getLineLength = function (symbol) { return this._length; }; // Overwrite effectPolylineProto.updateSymbolPosition = function (symbol) { var t = symbol.__t; var points = this._points; var offsets = this._offsets; var len = points.length; if (!offsets) { // Has length 0 return; } var lastFrame = this._lastFrame; var frame; if (t < this._lastFramePercent) { // Start from the next frame // PENDING start from lastFrame ? var start = Math.min(lastFrame + 1, len - 1); for (frame = start; frame >= 0; frame--) { if (offsets[frame] <= t) { break; } } // PENDING really need to do this ? frame = Math.min(frame, len - 2); } else { for (var frame = lastFrame; frame < len; frame++) { if (offsets[frame] > t) { break; } } frame = Math.min(frame - 1, len - 2); } vec2.lerp( symbol.position, points[frame], points[frame + 1], (t - offsets[frame]) / (offsets[frame + 1] - offsets[frame]) ); var tx = points[frame + 1][0] - points[frame][0]; var ty = points[frame + 1][1] - points[frame][1]; symbol.rotation = -Math.atan2(ty, tx) - Math.PI / 2; this._lastFrame = frame; this._lastFramePercent = t; symbol.ignore = false; }; zrUtil.inherits(EffectPolyline, EffectLine); module.exports = EffectPolyline; /***/ }, /* 269 */ /***/ function(module, exports, __webpack_require__) { // TODO Batch by color var graphic = __webpack_require__(43); var quadraticContain = __webpack_require__(55); var lineContain = __webpack_require__(53); var LargeLineShape = graphic.extendShape({ shape: { polyline: false, segs: [] }, buildPath: function (path, shape) { var segs = shape.segs; var isPolyline = shape.polyline; for (var i = 0; i < segs.length; i++) { var seg = segs[i]; if (isPolyline) { path.moveTo(seg[0][0], seg[0][1]); for (var j = 1; j < seg.length; j++) { path.lineTo(seg[j][0], seg[j][1]); } } else { path.moveTo(seg[0][0], seg[0][1]); if (seg.length > 2) { path.quadraticCurveTo(seg[2][0], seg[2][1], seg[1][0], seg[1][1]); } else { path.lineTo(seg[1][0], seg[1][1]); } } } }, findDataIndex: function (x, y) { var shape = this.shape; var segs = shape.segs; var isPolyline = shape.polyline; var lineWidth = Math.max(this.style.lineWidth, 1); // Not consider transform for (var i = 0; i < segs.length; i++) { var seg = segs[i]; if (isPolyline) { for (var j = 1; j < seg.length; j++) { if (lineContain.containStroke( seg[j - 1][0], seg[j - 1][1], seg[j][0], seg[j][1], lineWidth, x, y )) { return i; } } } else { if (seg.length > 2) { if (quadraticContain.containStroke( seg[0][0], seg[0][1], seg[2][0], seg[2][1], seg[1][0], seg[1][1], lineWidth, x, y )) { return i; } } else { if (lineContain.containStroke( seg[0][0], seg[0][1], seg[1][0], seg[1][1], lineWidth, x, y )) { return i; } } } } return -1; } }); function LargeLineDraw() { this.group = new graphic.Group(); this._lineEl = new LargeLineShape(); } var largeLineProto = LargeLineDraw.prototype; /** * Update symbols draw by new data * @param {module:echarts/data/List} data */ largeLineProto.updateData = function (data) { this.group.removeAll(); var lineEl = this._lineEl; var seriesModel = data.hostModel; lineEl.setShape({ segs: data.mapArray(data.getItemLayout), polyline: seriesModel.get('polyline') }); lineEl.useStyle( seriesModel.getModel('lineStyle.normal').getLineStyle() ); var visualColor = data.getVisual('color'); if (visualColor) { lineEl.setStyle('stroke', visualColor); } lineEl.setStyle('fill'); // Enable tooltip // PENDING May have performance issue when path is extremely large lineEl.seriesIndex = seriesModel.seriesIndex; lineEl.on('mousemove', function (e) { lineEl.dataIndex = null; var dataIndex = lineEl.findDataIndex(e.offsetX, e.offsetY); if (dataIndex > 0) { // Provide dataIndex for tooltip lineEl.dataIndex = dataIndex; } }); // Add back this.group.add(lineEl); }; largeLineProto.updateLayout = function (seriesModel) { var data = seriesModel.getData(); this._lineEl.setShape({ segs: data.mapArray(data.getItemLayout) }); }; largeLineProto.remove = function () { this.group.removeAll(); }; module.exports = LargeLineDraw; /***/ }, /* 270 */ /***/ function(module, exports, __webpack_require__) { module.exports = function (ecModel) { ecModel.eachSeriesByType('lines', function (seriesModel) { var coordSys = seriesModel.coordinateSystem; var lineData = seriesModel.getData(); // FIXME Use data dimensions ? lineData.each(function (idx) { var itemModel = lineData.getItemModel(idx); // TODO Support pure array var coords = (itemModel.option instanceof Array) ? itemModel.option : itemModel.get('coords'); if (true) { if (!(coords instanceof Array && coords.length > 0 && coords[0] instanceof Array)) { throw new Error('Invalid coords ' + JSON.stringify(coords) + '. Lines must have 2d coords array in data item.'); } } var pts = []; if (seriesModel.get('polyline')) { for (var i = 0; i < coords.length; i++) { pts.push(coordSys.dataToPoint(coords[i])); } } else { pts[0] = coordSys.dataToPoint(coords[0]); pts[1] = coordSys.dataToPoint(coords[1]); var curveness = itemModel.get('lineStyle.normal.curveness'); if (+curveness) { pts[2] = [ (pts[0][0] + pts[1][0]) / 2 - (pts[0][1] - pts[1][1]) * curveness, (pts[0][1] + pts[1][1]) / 2 - (pts[1][0] - pts[0][0]) * curveness ]; } } lineData.setItemLayout(idx, pts); }); }); }; /***/ }, /* 271 */ /***/ function(module, exports, __webpack_require__) { __webpack_require__(272); __webpack_require__(273); /***/ }, /* 272 */ /***/ function(module, exports, __webpack_require__) { var SeriesModel = __webpack_require__(28); var createListFromArray = __webpack_require__(102); module.exports = SeriesModel.extend({ type: 'series.heatmap', getInitialData: function (option, ecModel) { return createListFromArray(option.data, this, ecModel); }, defaultOption: { // Cartesian2D or geo coordinateSystem: 'cartesian2d', zlevel: 0, z: 2, // Cartesian coordinate system // xAxisIndex: 0, // yAxisIndex: 0, // Geo coordinate system geoIndex: 0, blurSize: 30, pointSize: 20, maxOpacity: 1, minOpacity: 0 } }); /***/ }, /* 273 */ /***/ function(module, exports, __webpack_require__) { var graphic = __webpack_require__(43); var HeatmapLayer = __webpack_require__(274); var zrUtil = __webpack_require__(4); function getIsInPiecewiseRange(dataExtent, pieceList, selected) { var dataSpan = dataExtent[1] - dataExtent[0]; pieceList = zrUtil.map(pieceList, function (piece) { return { interval: [ (piece.interval[0] - dataExtent[0]) / dataSpan, (piece.interval[1] - dataExtent[0]) / dataSpan ] }; }); var len = pieceList.length; var lastIndex = 0; return function (val) { // Try to find in the location of the last found for (var i = lastIndex; i < len; i++) { var interval = pieceList[i].interval; if (interval[0] <= val && val <= interval[1]) { lastIndex = i; break; } } if (i === len) { // Not found, back interation for (var i = lastIndex - 1; i >= 0; i--) { var interval = pieceList[i].interval; if (interval[0] <= val && val <= interval[1]) { lastIndex = i; break; } } } return i >= 0 && i < len && selected[i]; }; } function getIsInContinuousRange(dataExtent, range) { var dataSpan = dataExtent[1] - dataExtent[0]; range = [ (range[0] - dataExtent[0]) / dataSpan, (range[1] - dataExtent[0]) / dataSpan ]; return function (val) { return val >= range[0] && val <= range[1]; }; } function isGeoCoordSys(coordSys) { var dimensions = coordSys.dimensions; // Not use coorSys.type === 'geo' because coordSys maybe extended return dimensions[0] === 'lng' && dimensions[1] === 'lat'; } module.exports = __webpack_require__(1).extendChartView({ type: 'heatmap', render: function (seriesModel, ecModel, api) { var visualMapOfThisSeries; ecModel.eachComponent('visualMap', function (visualMap) { visualMap.eachTargetSeries(function (targetSeries) { if (targetSeries === seriesModel) { visualMapOfThisSeries = visualMap; } }); }); if (true) { if (!visualMapOfThisSeries) { throw new Error('Heatmap must use with visualMap'); } } this.group.removeAll(); var coordSys = seriesModel.coordinateSystem; if (coordSys.type === 'cartesian2d') { this._renderOnCartesian(coordSys, seriesModel, api); } else if (isGeoCoordSys(coordSys)) { this._renderOnGeo( coordSys, seriesModel, visualMapOfThisSeries, api ); } }, dispose: function () {}, _renderOnCartesian: function (cartesian, seriesModel, api) { var xAxis = cartesian.getAxis('x'); var yAxis = cartesian.getAxis('y'); var group = this.group; if (true) { if (!(xAxis.type === 'category' && yAxis.type === 'category')) { throw new Error('Heatmap on cartesian must have two category axes'); } if (!(xAxis.onBand && yAxis.onBand)) { throw new Error('Heatmap on cartesian must have two axes with boundaryGap true'); } } var width = xAxis.getBandWidth(); var height = yAxis.getBandWidth(); var data = seriesModel.getData(); var itemStyleQuery = 'itemStyle.normal'; var hoverItemStyleQuery = 'itemStyle.emphasis'; var labelQuery = 'label.normal'; var hoverLabelQuery = 'label.emphasis'; var style = seriesModel.getModel(itemStyleQuery).getItemStyle(['color']); var hoverStl = seriesModel.getModel(hoverItemStyleQuery).getItemStyle(); var labelModel = seriesModel.getModel('label.normal'); var hoverLabelModel = seriesModel.getModel('label.emphasis'); data.each(['x', 'y', 'z'], function (x, y, z, idx) { var itemModel = data.getItemModel(idx); var point = cartesian.dataToPoint([x, y]); // Ignore empty data if (isNaN(z)) { return; } var rect = new graphic.Rect({ shape: { x: point[0] - width / 2, y: point[1] - height / 2, width: width, height: height }, style: { fill: data.getItemVisual(idx, 'color'), opacity: data.getItemVisual(idx, 'opacity') } }); // Optimization for large datset if (data.hasItemOption) { style = itemModel.getModel(itemStyleQuery).getItemStyle(['color']); hoverStl = itemModel.getModel(hoverItemStyleQuery).getItemStyle(); labelModel = itemModel.getModel(labelQuery); hoverLabelModel = itemModel.getModel(hoverLabelQuery); } var rawValue = seriesModel.getRawValue(idx); var defaultText = '-'; if (rawValue && rawValue[2] != null) { defaultText = rawValue[2]; } if (labelModel.getShallow('show')) { graphic.setText(style, labelModel); style.text = seriesModel.getFormattedLabel(idx, 'normal') || defaultText; } if (hoverLabelModel.getShallow('show')) { graphic.setText(hoverStl, hoverLabelModel); hoverStl.text = seriesModel.getFormattedLabel(idx, 'emphasis') || defaultText; } rect.setStyle(style); graphic.setHoverStyle(rect, data.hasItemOption ? hoverStl : zrUtil.extend({}, hoverStl)); group.add(rect); data.setItemGraphicEl(idx, rect); }); }, _renderOnGeo: function (geo, seriesModel, visualMapModel, api) { var inRangeVisuals = visualMapModel.targetVisuals.inRange; var outOfRangeVisuals = visualMapModel.targetVisuals.outOfRange; // if (!visualMapping) { // throw new Error('Data range must have color visuals'); // } var data = seriesModel.getData(); var hmLayer = this._hmLayer || (this._hmLayer || new HeatmapLayer()); hmLayer.blurSize = seriesModel.get('blurSize'); hmLayer.pointSize = seriesModel.get('pointSize'); hmLayer.minOpacity = seriesModel.get('minOpacity'); hmLayer.maxOpacity = seriesModel.get('maxOpacity'); var rect = geo.getViewRect().clone(); var roamTransform = geo.getRoamTransform().transform; rect.applyTransform(roamTransform); // Clamp on viewport var x = Math.max(rect.x, 0); var y = Math.max(rect.y, 0); var x2 = Math.min(rect.width + rect.x, api.getWidth()); var y2 = Math.min(rect.height + rect.y, api.getHeight()); var width = x2 - x; var height = y2 - y; var points = data.mapArray(['lng', 'lat', 'value'], function (lng, lat, value) { var pt = geo.dataToPoint([lng, lat]); pt[0] -= x; pt[1] -= y; pt.push(value); return pt; }); var dataExtent = visualMapModel.getExtent(); var isInRange = visualMapModel.type === 'visualMap.continuous' ? getIsInContinuousRange(dataExtent, visualMapModel.option.range) : getIsInPiecewiseRange( dataExtent, visualMapModel.getPieceList(), visualMapModel.option.selected ); hmLayer.update( points, width, height, inRangeVisuals.color.getNormalizer(), { inRange: inRangeVisuals.color.getColorMapper(), outOfRange: outOfRangeVisuals.color.getColorMapper() }, isInRange ); var img = new graphic.Image({ style: { width: width, height: height, x: x, y: y, image: hmLayer.canvas }, silent: true }); this.group.add(img); } }); /***/ }, /* 274 */ /***/ function(module, exports, __webpack_require__) { /** * @file defines echarts Heatmap Chart * @author Ovilia (me@zhangwenli.com) * Inspired by https://github.com/mourner/simpleheat * * @module */ var GRADIENT_LEVELS = 256; var zrUtil = __webpack_require__(4); /** * Heatmap Chart * * @class */ function Heatmap() { var canvas = zrUtil.createCanvas(); this.canvas = canvas; this.blurSize = 30; this.pointSize = 20; this.maxOpacity = 1; this.minOpacity = 0; this._gradientPixels = {}; } Heatmap.prototype = { /** * Renders Heatmap and returns the rendered canvas * @param {Array} data array of data, each has x, y, value * @param {number} width canvas width * @param {number} height canvas height */ update: function(data, width, height, normalize, colorFunc, isInRange) { var brush = this._getBrush(); var gradientInRange = this._getGradient(data, colorFunc, 'inRange'); var gradientOutOfRange = this._getGradient(data, colorFunc, 'outOfRange'); var r = this.pointSize + this.blurSize; var canvas = this.canvas; var ctx = canvas.getContext('2d'); var len = data.length; canvas.width = width; canvas.height = height; for (var i = 0; i < len; ++i) { var p = data[i]; var x = p[0]; var y = p[1]; var value = p[2]; // calculate alpha using value var alpha = normalize(value); // draw with the circle brush with alpha ctx.globalAlpha = alpha; ctx.drawImage(brush, x - r, y - r); } // colorize the canvas using alpha value and set with gradient var imageData = ctx.getImageData(0, 0, canvas.width, canvas.height); var pixels = imageData.data; var offset = 0; var pixelLen = pixels.length; var minOpacity = this.minOpacity; var maxOpacity = this.maxOpacity; var diffOpacity = maxOpacity - minOpacity; while(offset < pixelLen) { var alpha = pixels[offset + 3] / 256; var gradientOffset = Math.floor(alpha * (GRADIENT_LEVELS - 1)) * 4; // Simple optimize to ignore the empty data if (alpha > 0) { var gradient = isInRange(alpha) ? gradientInRange : gradientOutOfRange; // Any alpha > 0 will be mapped to [minOpacity, maxOpacity] alpha > 0 && (alpha = alpha * diffOpacity + minOpacity); pixels[offset++] = gradient[gradientOffset]; pixels[offset++] = gradient[gradientOffset + 1]; pixels[offset++] = gradient[gradientOffset + 2]; pixels[offset++] = gradient[gradientOffset + 3] * alpha * 256; } else { offset += 4; } } ctx.putImageData(imageData, 0, 0); return canvas; }, /** * get canvas of a black circle brush used for canvas to draw later * @private * @returns {Object} circle brush canvas */ _getBrush: function() { var brushCanvas = this._brushCanvas || (this._brushCanvas = zrUtil.createCanvas()); // set brush size var r = this.pointSize + this.blurSize; var d = r * 2; brushCanvas.width = d; brushCanvas.height = d; var ctx = brushCanvas.getContext('2d'); ctx.clearRect(0, 0, d, d); // in order to render shadow without the distinct circle, // draw the distinct circle in an invisible place, // and use shadowOffset to draw shadow in the center of the canvas ctx.shadowOffsetX = d; ctx.shadowBlur = this.blurSize; // draw the shadow in black, and use alpha and shadow blur to generate // color in color map ctx.shadowColor = '#000'; // draw circle in the left to the canvas ctx.beginPath(); ctx.arc(-r, r, this.pointSize, 0, Math.PI * 2, true); ctx.closePath(); ctx.fill(); return brushCanvas; }, /** * get gradient color map * @private */ _getGradient: function (data, colorFunc, state) { var gradientPixels = this._gradientPixels; var pixelsSingleState = gradientPixels[state] || (gradientPixels[state] = new Uint8ClampedArray(256 * 4)); var color = []; var off = 0; for (var i = 0; i < 256; i++) { colorFunc[state](i / 255, true, color); pixelsSingleState[off++] = color[0]; pixelsSingleState[off++] = color[1]; pixelsSingleState[off++] = color[2]; pixelsSingleState[off++] = color[3]; } return pixelsSingleState; } }; module.exports = Heatmap; /***/ }, /* 275 */ /***/ function(module, exports, __webpack_require__) { var echarts = __webpack_require__(1); var zrUtil = __webpack_require__(4); var modelUtil = __webpack_require__(5); var graphicUtil = __webpack_require__(43); var formatUtil = __webpack_require__(6); var layoutUtil = __webpack_require__(21); // Preprocessor echarts.registerPreprocessor(function (option) { var graphicOption = option && option.graphic; // Convert // {graphic: [{left: 10, type: 'circle'}, ...]} // or // {graphic: {left: 10, type: 'circle'}} // to // {graphic: [{elements: [{left: 10, type: 'circle'}, ...]}]} if (zrUtil.isArray(graphicOption)) { if (!graphicOption[0] || !graphicOption[0].elements) { option.graphic = [{elements: graphicOption}]; } else { // Only one graphic instance can be instantiated. (We dont // want that too many views created in echarts._viewMap) option.graphic = [option.graphic[0]]; } } else if (graphicOption && !graphicOption.elements) { option.graphic = [{elements: [graphicOption]}]; } }); // Model var GraphicModel = echarts.extendComponentModel({ type: 'graphic', defaultOption: { // Extra properties for each elements: // // left/right/top/bottom: (like 12, '22%', 'center', default undefined) // If left/rigth is set, shape.x/shape.cx/position is not used. // If top/bottom is set, shape.y/shape.cy/position is not used. // This mechanism is useful when you want position a group/element // against the right side or center of this container. // // width/height: (can only pixel value, default 0) // Only be used to specify contianer(group) size, if needed. And // can not be percentage value (like '33%'). See the reason in the // layout algorithm below. // // bounding: (enum: 'all' (default) | 'raw') // Specify how to calculate boundingRect when locating. // 'all': Get uioned and transformed boundingRect // from both itself and its descendants. // This mode simplies confine a group of elements in the bounding // of their ancester container (e.g., using 'right: 0'). // 'raw': Only use not transformed boundingRect of itself. // This mode likes css behavior, useful when you want a // element can overflow its container. (Consider a rotated // circle needs to be located in a corner.) // Note: elements is always behind its ancestors in elements array. elements: [], parentId: null }, /** * Save for performance (only update needed graphics). * The order is the same as those in option. (ancesters -> descendants) * @private * @type {Array.} */ _elOptionsToUpdate: null, /** * @override */ mergeOption: function (option) { // Prevent default merge to elements var elements = this.option.elements; this.option.elements = null; GraphicModel.superApply(this, 'mergeOption', arguments); this.option.elements = elements; }, /** * @override */ optionUpdated: function (newOption, isInit) { var thisOption = this.option; var newList = (isInit ? thisOption : newOption).elements; var existList = thisOption.elements = isInit ? [] : thisOption.elements; var flattenedList = []; this._flatten(newList, flattenedList); var mappingResult = modelUtil.mappingToExists(existList, flattenedList); modelUtil.makeIdAndName(mappingResult); // Clear elOptionsToUpdate var elOptionsToUpdate = this._elOptionsToUpdate = []; zrUtil.each(mappingResult, function (resultItem, index) { var existElOption = resultItem.exist; var newElOption = resultItem.option; if (true) { zrUtil.assert( zrUtil.isObject(newElOption) || existElOption, 'Empty graphic option definition' ); } if (!newElOption) { return; } // Set id and parent id after id assigned. newElOption.id = resultItem.keyInfo.id; var newElParentId = newElOption.parentId; var newElParentOption = newElOption.parentOption; var existElParentId = existElOption && existElOption.parentId; !newElOption.type && existElOption && (newElOption.type = existElOption.type); newElOption.parentId = newElParentId // parent id specified ? newElParentId : newElParentOption ? newElParentOption.id : existElParentId // parent not specified ? existElParentId : null; newElOption.parentOption = null; // Clear elOptionsToUpdate.push(newElOption); // Update existing options, for `getOption` feature. var newElOptCopy = zrUtil.extend({}, newElOption); // Avoid modified. var $action = newElOption.$action; if (!$action || $action === 'merge') { if (existElOption) { if (true) { var newType = newElOption.type; zrUtil.assert( !newType || existElOption.type === newType, 'Please set $action: "replace" to change `type`' ); } // We can ensure that newElOptCopy and existElOption are not // the same object, so merge will not change newElOptCopy. zrUtil.merge(existElOption, newElOptCopy, true); // Rigid body, use ignoreSize. layoutUtil.mergeLayoutParam(existElOption, newElOptCopy, {ignoreSize: true}); // Will be used in render. layoutUtil.copyLayoutParams(newElOption, existElOption); } else { existList[index] = newElOptCopy; } } else if ($action === 'replace') { existList[index] = newElOptCopy; } else if ($action === 'remove') { // null will be cleaned later. existElOption && (existList[index] = null); } if (existList[index]) { existList[index].hv = newElOption.hv = [ isSetLoc(newElOption, ['left', 'right']), // Rigid body, dont care `width`. isSetLoc(newElOption, ['top', 'bottom']) // Rigid body, Dont care `height`. ]; // Given defualt group size, otherwise may layout error. if (existList[index].type === 'group') { existList[index].width == null && (existList[index].width = newElOption.width = 0); existList[index].height == null && (existList[index].height = newElOption.height = 0); } } }, this); // Clean for (var i = existList.length - 1; i >= 0; i--) { if (existList[i] == null) { existList.splice(i, 1); } else { // $action should be volatile, otherwise option gotten from // `getOption` will contain unexpected $action. delete existList[i].$action; } } }, /** * Convert * [{ * type: 'group', * id: 'xx', * children: [{type: 'circle'}, {type: 'polygon'}] * }] * to * [ * {type: 'group', id: 'xx'}, * {type: 'circle', parentId: 'xx'}, * {type: 'polygon', parentId: 'xx'} * ] * @private */ _flatten: function (optionList, result, parentOption) { zrUtil.each(optionList, function (option) { if (option) { if (parentOption) { option.parentOption = parentOption; } result.push(option); var children = option.children; if (option.type === 'group' && children) { this._flatten(children, result, option); } // For JSON output, and do not affect group creation. delete option.children; } }, this); }, // FIXME // Pass to view using payload? setOption has a payload? useElOptionsToUpdate: function () { var els = this._elOptionsToUpdate; // Clear to avoid render duplicately when zooming. this._elOptionsToUpdate = null; return els; } }); // View echarts.extendComponentView({ type: 'graphic', /** * @override */ init: function (ecModel, api) { /** * @type {Object} */ this._elMap = {}; /** * @type {module:echarts/graphic/GraphicModel} */ this._lastGraphicModel; }, /** * @override */ render: function (graphicModel, ecModel, api) { // Having leveraged use case and algorithm complexity, a very simple // layout mechanism is used: // The size(width/height) can be determined by itself or its parent (not // implemented yet), but can not by its children. (Top-down travel) // The location(x/y) can be determined by the bounding rect of itself // (can including its descendants or not) and the size of its parent. // (Bottom-up travel) // When chart.clear() or chart.setOption({...}, true) with the same id, // view will be reused. if (graphicModel !== this._lastGraphicModel) { this._clear(); } this._lastGraphicModel = graphicModel; this._updateElements(graphicModel, api); this._relocate(graphicModel, api); }, /** * @private */ _updateElements: function (graphicModel, api) { var elOptionsToUpdate = graphicModel.useElOptionsToUpdate(); if (!elOptionsToUpdate) { return; } var elMap = this._elMap; var rootGroup = this.group; // Top-down tranverse to assign graphic settings to each elements. zrUtil.each(elOptionsToUpdate, function (elOption) { var $action = elOption.$action; var id = elOption.id; var existEl = elMap[id]; var parentId = elOption.parentId; var targetElParent = parentId != null ? elMap[parentId] : rootGroup; // In top/bottom mode, textVertical should not be used. But // textBaseline should not be 'alphabetic', which is not precise. if (elOption.hv && elOption.hv[1] && elOption.type === 'text') { elOption.style = zrUtil.defaults({textBaseline: 'middle'}, elOption.style); elOption.style.textVerticalAlign = null; } // Remove unnecessary props to avoid potential problem. var elOptionCleaned = getCleanedElOption(elOption); // For simple, do not support parent change, otherwise reorder is needed. if (true) { existEl && zrUtil.assert( targetElParent === existEl.parent, 'Changing parent is not supported.' ); } if (!$action || $action === 'merge') { existEl ? existEl.attr(elOptionCleaned) : createEl(id, targetElParent, elOptionCleaned, elMap); } else if ($action === 'replace') { removeEl(existEl, elMap); createEl(id, targetElParent, elOptionCleaned, elMap); } else if ($action === 'remove') { removeEl(existEl, elMap); } if (elMap[id]) { elMap[id].__ecGraphicWidth = elOption.width; elMap[id].__ecGraphicHeight = elOption.height; } }); }, /** * @private */ _relocate: function (graphicModel, api) { var elOptions = graphicModel.option.elements; var rootGroup = this.group; var elMap = this._elMap; // Bottom-up tranvese all elements (consider when ec resize) to locate elements. for (var i = elOptions.length - 1; i >= 0; i--) { var elOption = elOptions[i]; var el = elMap[elOption.id]; if (!el) { continue; } var parentEl = el.parent; var containerInfo = parentEl === rootGroup ? { width: api.getWidth(), height: api.getHeight() } : { // Like 'position:absolut' in css, default 0. width: parentEl.__ecGraphicWidth || 0, height: parentEl.__ecGraphicHeight || 0 }; layoutUtil.positionElement( el, elOption, containerInfo, null, {hv: elOption.hv, boundingMode: elOption.bounding} ); } }, /** * @private */ _clear: function () { var elMap = this._elMap; zrUtil.each(elMap, function (el) { removeEl(el, elMap); }); this._elMap = {}; }, /** * @override */ dispose: function () { this._clear(); } }); function createEl(id, targetElParent, elOption, elMap) { var graphicType = elOption.type; if (true) { zrUtil.assert(graphicType, 'graphic type MUST be set'); } var Clz = graphicUtil[graphicType.charAt(0).toUpperCase() + graphicType.slice(1)]; if (true) { zrUtil.assert(Clz, 'graphic type can not be found'); } var el = new Clz(elOption); targetElParent.add(el); elMap[id] = el; el.__ecGraphicId = id; } function removeEl(existEl, elMap) { var existElParent = existEl && existEl.parent; if (existElParent) { existEl.type === 'group' && existEl.traverse(function (el) { removeEl(el, elMap); }); delete elMap[existEl.__ecGraphicId]; existElParent.remove(existEl); } } // Remove unnecessary props to avoid potential problem. function getCleanedElOption(elOption) { elOption = zrUtil.extend({}, elOption); zrUtil.each( ['id', 'parentId', '$action', 'hv', 'bounding'].concat(layoutUtil.LOCATION_PARAMS), function (name) { delete elOption[name]; } ); return elOption; } function isSetLoc(obj, props) { var isSet; zrUtil.each(props, function (prop) { obj[prop] != null && obj[prop] !== 'auto' && (isSet = true); }); return isSet; } /***/ }, /* 276 */ /***/ function(module, exports, __webpack_require__) { /** * Legend component entry file8 */ __webpack_require__(277); __webpack_require__(278); __webpack_require__(279); var echarts = __webpack_require__(1); // Series Filter echarts.registerProcessor(__webpack_require__(281)); /***/ }, /* 277 */ /***/ function(module, exports, __webpack_require__) { 'use strict'; var zrUtil = __webpack_require__(4); var Model = __webpack_require__(12); var LegendModel = __webpack_require__(1).extendComponentModel({ type: 'legend', dependencies: ['series'], layoutMode: { type: 'box', ignoreSize: true }, init: function (option, parentModel, ecModel) { this.mergeDefaultAndTheme(option, ecModel); option.selected = option.selected || {}; }, mergeOption: function (option) { LegendModel.superCall(this, 'mergeOption', option); }, optionUpdated: function () { this._updateData(this.ecModel); var legendData = this._data; // If selectedMode is single, try to select one if (legendData[0] && this.get('selectedMode') === 'single') { var hasSelected = false; // If has any selected in option.selected for (var i = 0; i < legendData.length; i++) { var name = legendData[i].get('name'); if (this.isSelected(name)) { // Force to unselect others this.select(name); hasSelected = true; break; } } // Try select the first if selectedMode is single !hasSelected && this.select(legendData[0].get('name')); } }, _updateData: function (ecModel) { var legendData = zrUtil.map(this.get('data') || [], function (dataItem) { // Can be string or number if (typeof dataItem === 'string' || typeof dataItem === 'number') { dataItem = { name: dataItem }; } return new Model(dataItem, this, this.ecModel); }, this); this._data = legendData; var availableNames = zrUtil.map(ecModel.getSeries(), function (series) { return series.name; }); ecModel.eachSeries(function (seriesModel) { if (seriesModel.legendDataProvider) { var data = seriesModel.legendDataProvider(); availableNames = availableNames.concat(data.mapArray(data.getName)); } }); /** * @type {Array.} * @private */ this._availableNames = availableNames; }, /** * @return {Array.} */ getData: function () { return this._data; }, /** * @param {string} name */ select: function (name) { var selected = this.option.selected; var selectedMode = this.get('selectedMode'); if (selectedMode === 'single') { var data = this._data; zrUtil.each(data, function (dataItem) { selected[dataItem.get('name')] = false; }); } selected[name] = true; }, /** * @param {string} name */ unSelect: function (name) { if (this.get('selectedMode') !== 'single') { this.option.selected[name] = false; } }, /** * @param {string} name */ toggleSelected: function (name) { var selected = this.option.selected; // Default is true if (!selected.hasOwnProperty(name)) { selected[name] = true; } this[selected[name] ? 'unSelect' : 'select'](name); }, /** * @param {string} name */ isSelected: function (name) { var selected = this.option.selected; return !(selected.hasOwnProperty(name) && !selected[name]) && zrUtil.indexOf(this._availableNames, name) >= 0; }, defaultOption: { // 一级层叠 zlevel: 0, // 二级层叠 z: 4, show: true, // 布局方式,默认为水平布局,可选为: // 'horizontal' | 'vertical' orient: 'horizontal', left: 'center', // right: 'center', top: 'top', // bottom: 'top', // 水平对齐 // 'auto' | 'left' | 'right' // 默认为 'auto', 根据 x 的位置判断是左对齐还是右对齐 align: 'auto', backgroundColor: 'rgba(0,0,0,0)', // 图例边框颜色 borderColor: '#ccc', // 图例边框线宽,单位px,默认为0(无边框) borderWidth: 0, // 图例内边距,单位px,默认各方向内边距为5, // 接受数组分别设定上右下左边距,同css padding: 5, // 各个item之间的间隔,单位px,默认为10, // 横向布局时为水平间隔,纵向布局时为纵向间隔 itemGap: 10, // 图例图形宽度 itemWidth: 25, // 图例图形高度 itemHeight: 14, // 图例关闭时候的颜色 inactiveColor: '#ccc', textStyle: { // 图例文字颜色 color: '#333' }, // formatter: '', // 选择模式,默认开启图例开关 selectedMode: true, // 配置默认选中状态,可配合LEGEND.SELECTED事件做动态数据载入 // selected: null, // 图例内容(详见legend.data,数组中每一项代表一个item // data: [], // Tooltip 相关配置 tooltip: { show: false } } }); module.exports = LegendModel; /***/ }, /* 278 */ /***/ function(module, exports, __webpack_require__) { /** * @file Legend action */ var echarts = __webpack_require__(1); var zrUtil = __webpack_require__(4); function legendSelectActionHandler(methodName, payload, ecModel) { var selectedMap = {}; var isToggleSelect = methodName === 'toggleSelected'; var isSelected; // Update all legend components ecModel.eachComponent('legend', function (legendModel) { if (isToggleSelect && isSelected != null) { // Force other legend has same selected status // Or the first is toggled to true and other are toggled to false // In the case one legend has some item unSelected in option. And if other legend // doesn't has the item, they will assume it is selected. legendModel[isSelected ? 'select' : 'unSelect'](payload.name); } else { legendModel[methodName](payload.name); isSelected = legendModel.isSelected(payload.name); } var legendData = legendModel.getData(); zrUtil.each(legendData, function (model) { var name = model.get('name'); // Wrap element if (name === '\n' || name === '') { return; } var isItemSelected = legendModel.isSelected(name); if (name in selectedMap) { // Unselected if any legend is unselected selectedMap[name] = selectedMap[name] && isItemSelected; } else { selectedMap[name] = isItemSelected; } }); }); // Return the event explicitly return { name: payload.name, selected: selectedMap }; } /** * @event legendToggleSelect * @type {Object} * @property {string} type 'legendToggleSelect' * @property {string} [from] * @property {string} name Series name or data item name */ echarts.registerAction( 'legendToggleSelect', 'legendselectchanged', zrUtil.curry(legendSelectActionHandler, 'toggleSelected') ); /** * @event legendSelect * @type {Object} * @property {string} type 'legendSelect' * @property {string} name Series name or data item name */ echarts.registerAction( 'legendSelect', 'legendselected', zrUtil.curry(legendSelectActionHandler, 'select') ); /** * @event legendUnSelect * @type {Object} * @property {string} type 'legendUnSelect' * @property {string} name Series name or data item name */ echarts.registerAction( 'legendUnSelect', 'legendunselected', zrUtil.curry(legendSelectActionHandler, 'unSelect') ); /***/ }, /* 279 */ /***/ function(module, exports, __webpack_require__) { var zrUtil = __webpack_require__(4); var symbolCreator = __webpack_require__(107); var graphic = __webpack_require__(43); var listComponentHelper = __webpack_require__(280); var curry = zrUtil.curry; function dispatchSelectAction(name, api) { api.dispatchAction({ type: 'legendToggleSelect', name: name }); } function dispatchHighlightAction(seriesModel, dataName, api) { // If element hover will move to a hoverLayer. var el = api.getZr().storage.getDisplayList()[0]; if (!(el && el.useHoverLayer)) { seriesModel.get('legendHoverLink') && api.dispatchAction({ type: 'highlight', seriesName: seriesModel.name, name: dataName }); } } function dispatchDownplayAction(seriesModel, dataName, api) { // If element hover will move to a hoverLayer. var el = api.getZr().storage.getDisplayList()[0]; if (!(el && el.useHoverLayer)) { seriesModel.get('legendHoverLink') && api.dispatchAction({ type: 'downplay', seriesName: seriesModel.name, name: dataName }); } } module.exports = __webpack_require__(1).extendComponentView({ type: 'legend', init: function () { this._symbolTypeStore = {}; }, render: function (legendModel, ecModel, api) { var group = this.group; group.removeAll(); if (!legendModel.get('show')) { return; } var selectMode = legendModel.get('selectedMode'); var itemAlign = legendModel.get('align'); if (itemAlign === 'auto') { itemAlign = (legendModel.get('left') === 'right' && legendModel.get('orient') === 'vertical') ? 'right' : 'left'; } var legendDrawedMap = {}; zrUtil.each(legendModel.getData(), function (itemModel) { var name = itemModel.get('name'); // Use empty string or \n as a newline string if (name === '' || name === '\n') { group.add(new graphic.Group({ newline: true })); return; } var seriesModel = ecModel.getSeriesByName(name)[0]; if (legendDrawedMap[name]) { // Have been drawed return; } // Series legend if (seriesModel) { var data = seriesModel.getData(); var color = data.getVisual('color'); // If color is a callback function if (typeof color === 'function') { // Use the first data color = color(seriesModel.getDataParams(0)); } // Using rect symbol defaultly var legendSymbolType = data.getVisual('legendSymbol') || 'roundRect'; var symbolType = data.getVisual('symbol'); var itemGroup = this._createItem( name, itemModel, legendModel, legendSymbolType, symbolType, itemAlign, color, selectMode ); itemGroup.on('click', curry(dispatchSelectAction, name, api)) .on('mouseover', curry(dispatchHighlightAction, seriesModel, null, api)) .on('mouseout', curry(dispatchDownplayAction, seriesModel, null, api)); legendDrawedMap[name] = true; } else { // Data legend of pie, funnel ecModel.eachRawSeries(function (seriesModel) { // In case multiple series has same data name if (legendDrawedMap[name]) { return; } if (seriesModel.legendDataProvider) { var data = seriesModel.legendDataProvider(); var idx = data.indexOfName(name); if (idx < 0) { return; } var color = data.getItemVisual(idx, 'color'); var legendSymbolType = 'roundRect'; var itemGroup = this._createItem( name, itemModel, legendModel, legendSymbolType, null, itemAlign, color, selectMode ); itemGroup.on('click', curry(dispatchSelectAction, name, api)) // FIXME Should not specify the series name .on('mouseover', curry(dispatchHighlightAction, seriesModel, name, api)) .on('mouseout', curry(dispatchDownplayAction, seriesModel, name, api)); legendDrawedMap[name] = true; } }, this); } if (true) { if (!legendDrawedMap[name]) { console.warn(name + ' series not exists. Legend data should be same with series name or data name.'); } } }, this); listComponentHelper.layout(group, legendModel, api); // Render background after group is layout // FIXME listComponentHelper.addBackground(group, legendModel); }, _createItem: function ( name, itemModel, legendModel, legendSymbolType, symbolType, itemAlign, color, selectMode ) { var itemWidth = legendModel.get('itemWidth'); var itemHeight = legendModel.get('itemHeight'); var inactiveColor = legendModel.get('inactiveColor'); var isSelected = legendModel.isSelected(name); var itemGroup = new graphic.Group(); var textStyleModel = itemModel.getModel('textStyle'); var itemIcon = itemModel.get('icon'); var tooltipModel = itemModel.getModel('tooltip'); var legendGlobalTooltipModel = tooltipModel.parentModel; // Use user given icon first legendSymbolType = itemIcon || legendSymbolType; itemGroup.add(symbolCreator.createSymbol( legendSymbolType, 0, 0, itemWidth, itemHeight, isSelected ? color : inactiveColor )); // Compose symbols // PENDING if (!itemIcon && symbolType // At least show one symbol, can't be all none && ((symbolType !== legendSymbolType) || symbolType == 'none') ) { var size = itemHeight * 0.8; if (symbolType === 'none') { symbolType = 'circle'; } // Put symbol in the center itemGroup.add(symbolCreator.createSymbol( symbolType, (itemWidth - size) / 2, (itemHeight - size) / 2, size, size, isSelected ? color : inactiveColor )); } // Text var textX = itemAlign === 'left' ? itemWidth + 5 : -5; var textAlign = itemAlign; var formatter = legendModel.get('formatter'); var content = name; if (typeof formatter === 'string' && formatter) { content = formatter.replace('{name}', name != null ? name : ''); } else if (typeof formatter === 'function') { content = formatter(name); } var text = new graphic.Text({ style: { text: content, x: textX, y: itemHeight / 2, fill: isSelected ? textStyleModel.getTextColor() : inactiveColor, textFont: textStyleModel.getFont(), textAlign: textAlign, textVerticalAlign: 'middle' } }); itemGroup.add(text); // Add a invisible rect to increase the area of mouse hover var hitRect = new graphic.Rect({ shape: itemGroup.getBoundingRect(), invisible: true, tooltip: tooltipModel.get('show') ? zrUtil.extend({ content: name, // Defaul formatter formatter: legendGlobalTooltipModel.get('formatter', true) || function () { return name; }, formatterParams: { componentType: 'legend', legendIndex: legendModel.componentIndex, name: name, $vars: ['name'] } }, tooltipModel.option) : null }); itemGroup.add(hitRect); itemGroup.eachChild(function (child) { child.silent = true; }); hitRect.silent = !selectMode; this.group.add(itemGroup); graphic.setHoverStyle(itemGroup); return itemGroup; } }); /***/ }, /* 280 */ /***/ function(module, exports, __webpack_require__) { // List layout var layout = __webpack_require__(21); var formatUtil = __webpack_require__(6); var graphic = __webpack_require__(43); function positionGroup(group, model, api) { layout.positionElement( group, model.getBoxLayoutParams(), { width: api.getWidth(), height: api.getHeight() }, model.get('padding') ); } module.exports = { /** * Layout list like component. * It will box layout each items in group of component and then position the whole group in the viewport * @param {module:zrender/group/Group} group * @param {module:echarts/model/Component} componentModel * @param {module:echarts/ExtensionAPI} */ layout: function (group, componentModel, api) { var rect = layout.getLayoutRect(componentModel.getBoxLayoutParams(), { width: api.getWidth(), height: api.getHeight() }, componentModel.get('padding')); layout.box( componentModel.get('orient'), group, componentModel.get('itemGap'), rect.width, rect.height ); positionGroup(group, componentModel, api); }, addBackground: function (group, componentModel) { var padding = formatUtil.normalizeCssArray( componentModel.get('padding') ); var boundingRect = group.getBoundingRect(); var style = componentModel.getItemStyle(['color', 'opacity']); style.fill = componentModel.get('backgroundColor'); var rect = new graphic.Rect({ shape: { x: boundingRect.x - padding[3], y: boundingRect.y - padding[0], width: boundingRect.width + padding[1] + padding[3], height: boundingRect.height + padding[0] + padding[2] }, style: style, silent: true, z2: -1 }); graphic.subPixelOptimizeRect(rect); group.add(rect); } }; /***/ }, /* 281 */ /***/ function(module, exports) { module.exports = function (ecModel) { var legendModels = ecModel.findComponents({ mainType: 'legend' }); if (legendModels && legendModels.length) { ecModel.filterSeries(function (series) { // If in any legend component the status is not selected. // Because in legend series is assumed selected when it is not in the legend data. for (var i = 0; i < legendModels.length; i++) { if (!legendModels[i].isSelected(series.name)) { return false; } } return true; }); } }; /***/ }, /* 282 */ /***/ function(module, exports, __webpack_require__) { // FIXME Better way to pack data in graphic element __webpack_require__(283); __webpack_require__(284); // Show tip action /** * @action * @property {string} type * @property {number} seriesIndex * @property {number} dataIndex * @property {number} [x] * @property {number} [y] */ __webpack_require__(1).registerAction( { type: 'showTip', event: 'showTip', update: 'none' }, // noop function () {} ); // Hide tip action __webpack_require__(1).registerAction( { type: 'hideTip', event: 'hideTip', update: 'none' }, // noop function () {} ); /***/ }, /* 283 */ /***/ function(module, exports, __webpack_require__) { __webpack_require__(1).extendComponentModel({ type: 'tooltip', defaultOption: { zlevel: 0, z: 8, show: true, // tooltip主体内容 showContent: true, // 触发类型,默认数据触发,见下图,可选为:'item' ¦ 'axis' trigger: 'item', // 触发条件,支持 'click' | 'mousemove' | 'none' triggerOn: 'mousemove', // 是否永远显示 content alwaysShowContent: false, // 位置 {Array} | {Function} // position: null // 是否约束 content 在 viewRect 中。默认 false 是为了兼容以前版本。 confine: false, // 内容格式器:{string}(Template) ¦ {Function} // formatter: null showDelay: 0, // 隐藏延迟,单位ms hideDelay: 100, // 动画变换时间,单位s transitionDuration: 0.4, enterable: false, // 提示背景颜色,默认为透明度为0.7的黑色 backgroundColor: 'rgba(50,50,50,0.7)', // 提示边框颜色 borderColor: '#333', // 提示边框圆角,单位px,默认为4 borderRadius: 4, // 提示边框线宽,单位px,默认为0(无边框) borderWidth: 0, // 提示内边距,单位px,默认各方向内边距为5, // 接受数组分别设定上右下左边距,同css padding: 5, // Extra css text extraCssText: '', // 坐标轴指示器,坐标轴触发有效 axisPointer: { // 默认为直线 // 可选为:'line' | 'shadow' | 'cross' type: 'line', // type 为 line 的时候有效,指定 tooltip line 所在的轴,可选 // 可选 'x' | 'y' | 'angle' | 'radius' | 'auto' // 默认 'auto',会选择类型为 cateogry 的轴,对于双数值轴,笛卡尔坐标系会默认选择 x 轴 // 极坐标系会默认选择 angle 轴 axis: 'auto', animation: true, animationDurationUpdate: 200, animationEasingUpdate: 'exponentialOut', // 直线指示器样式设置 lineStyle: { color: '#555', width: 1, type: 'solid' }, crossStyle: { color: '#555', width: 1, type: 'dashed', // TODO formatter textStyle: {} }, // 阴影指示器样式设置 shadowStyle: { color: 'rgba(150,150,150,0.3)' } }, textStyle: { color: '#fff', fontSize: 14 } } }); /***/ }, /* 284 */ /***/ function(module, exports, __webpack_require__) { var TooltipContent = __webpack_require__(285); var graphic = __webpack_require__(43); var zrUtil = __webpack_require__(4); var formatUtil = __webpack_require__(6); var numberUtil = __webpack_require__(7); var modelUtil = __webpack_require__(5); var parsePercent = numberUtil.parsePercent; var env = __webpack_require__(2); var Model = __webpack_require__(12); function dataEqual(a, b) { if (!a || !b) { return false; } var round = numberUtil.round; return round(a[0]) === round(b[0]) && round(a[1]) === round(b[1]); } /** * @inner */ function makeLineShape(x1, y1, x2, y2) { return { x1: x1, y1: y1, x2: x2, y2: y2 }; } /** * @inner */ function makeRectShape(x, y, width, height) { return { x: x, y: y, width: width, height: height }; } /** * @inner */ function makeSectorShape(cx, cy, r0, r, startAngle, endAngle) { return { cx: cx, cy: cy, r0: r0, r: r, startAngle: startAngle, endAngle: endAngle, clockwise: true }; } function refixTooltipPosition(x, y, el, viewWidth, viewHeight) { var width = el.clientWidth; var height = el.clientHeight; var gap = 20; if (x + width + gap > viewWidth) { x -= width + gap; } else { x += gap; } if (y + height + gap > viewHeight) { y -= height + gap; } else { y += gap; } return [x, y]; } function confineTooltipPosition(x, y, el, viewWidth, viewHeight) { var width = el.clientWidth; var height = el.clientHeight; x = Math.min(x + width, viewWidth) - width; y = Math.min(y + height, viewHeight) - height; x = Math.max(x, 0); y = Math.max(y, 0); return [x, y]; } function calcTooltipPosition(position, rect, dom) { var domWidth = dom.clientWidth; var domHeight = dom.clientHeight; var gap = 5; var x = 0; var y = 0; var rectWidth = rect.width; var rectHeight = rect.height; switch (position) { case 'inside': x = rect.x + rectWidth / 2 - domWidth / 2; y = rect.y + rectHeight / 2 - domHeight / 2; break; case 'top': x = rect.x + rectWidth / 2 - domWidth / 2; y = rect.y - domHeight - gap; break; case 'bottom': x = rect.x + rectWidth / 2 - domWidth / 2; y = rect.y + rectHeight + gap; break; case 'left': x = rect.x - domWidth - gap; y = rect.y + rectHeight / 2 - domHeight / 2; break; case 'right': x = rect.x + rectWidth + gap; y = rect.y + rectHeight / 2 - domHeight / 2; } return [x, y]; } /** * @param {string|Function|Array.} positionExpr * @param {number} x Mouse x * @param {number} y Mouse y * @param {boolean} confine Whether confine tooltip content in view rect. * @param {module:echarts/component/tooltip/TooltipContent} content * @param {Object|} params * @param {module:zrender/Element} el target element * @param {module:echarts/ExtensionAPI} api * @return {Array.} */ function updatePosition(positionExpr, x, y, confine, content, params, el, api) { var viewWidth = api.getWidth(); var viewHeight = api.getHeight(); var rect = el && el.getBoundingRect().clone(); el && rect.applyTransform(el.transform); if (typeof positionExpr === 'function') { // Callback of position can be an array or a string specify the position positionExpr = positionExpr([x, y], params, content.el, rect); } if (zrUtil.isArray(positionExpr)) { x = parsePercent(positionExpr[0], viewWidth); y = parsePercent(positionExpr[1], viewHeight); } // Specify tooltip position by string 'top' 'bottom' 'left' 'right' around graphic element else if (typeof positionExpr === 'string' && el) { var pos = calcTooltipPosition( positionExpr, rect, content.el ); x = pos[0]; y = pos[1]; } else { var pos = refixTooltipPosition( x, y, content.el, viewWidth, viewHeight ); x = pos[0]; y = pos[1]; } if (confine) { var pos = confineTooltipPosition( x, y, content.el, viewWidth, viewHeight ); x = pos[0]; y = pos[1]; } content.moveTo(x, y); } function ifSeriesSupportAxisTrigger(seriesModel) { var coordSys = seriesModel.coordinateSystem; var trigger = seriesModel.get('tooltip.trigger', true); // Ignore series use item tooltip trigger and series coordinate system is not cartesian or return !(!coordSys || (coordSys.type !== 'cartesian2d' && coordSys.type !== 'polar' && coordSys.type !== 'singleAxis') || trigger === 'item'); } __webpack_require__(1).extendComponentView({ type: 'tooltip', _axisPointers: {}, init: function (ecModel, api) { if (env.node) { return; } var tooltipContent = new TooltipContent(api.getDom(), api); this._tooltipContent = tooltipContent; api.on('showTip', this._manuallyShowTip, this); api.on('hideTip', this._manuallyHideTip, this); }, render: function (tooltipModel, ecModel, api) { if (env.node) { return; } // Reset this.group.removeAll(); /** * @type {Object} * @private */ this._axisPointers = {}; /** * @private * @type {module:echarts/component/tooltip/TooltipModel} */ this._tooltipModel = tooltipModel; /** * @private * @type {module:echarts/model/Global} */ this._ecModel = ecModel; /** * @private * @type {module:echarts/ExtensionAPI} */ this._api = api; /** * @type {Object} * @private */ this._lastHover = { // data // payloadBatch }; var tooltipContent = this._tooltipContent; tooltipContent.update(); tooltipContent.enterable = tooltipModel.get('enterable'); this._alwaysShowContent = tooltipModel.get('alwaysShowContent'); /** * @type {Object.} */ this._seriesGroupByAxis = this._prepareAxisTriggerData( tooltipModel, ecModel ); var crossText = this._crossText; if (crossText) { this.group.add(crossText); } var triggerOn = tooltipModel.get('triggerOn'); // Try to keep the tooltip show when refreshing if (this._lastX != null && this._lastY != null // When user is willing to control tooltip totally using API, // self._manuallyShowTip({x, y}) might cause tooltip hide, // which is not expected. && triggerOn !== 'none' ) { var self = this; clearTimeout(this._refreshUpdateTimeout); this._refreshUpdateTimeout = setTimeout(function () { // Show tip next tick after other charts are rendered // In case highlight action has wrong result // FIXME self._manuallyShowTip({ x: self._lastX, y: self._lastY }); }); } var zr = this._api.getZr(); zr.off('click', this._tryShow); zr.off('mousemove', this._mousemove); zr.off('mouseout', this._hide); zr.off('globalout', this._hide); if (triggerOn === 'click') { zr.on('click', this._tryShow, this); } else if (triggerOn === 'mousemove') { zr.on('mousemove', this._mousemove, this); zr.on('mouseout', this._hide, this); zr.on('globalout', this._hide, this); } // else triggerOn is 'none', which enable user // to control tooltip totally using API. }, _mousemove: function (e) { var showDelay = this._tooltipModel.get('showDelay'); var self = this; clearTimeout(this._showTimeout); if (showDelay > 0) { this._showTimeout = setTimeout(function () { self._tryShow(e); }, showDelay); } else { this._tryShow(e); } }, /** * Show tip manually by * dispatchAction({ * type: 'showTip', * x: 10, * y: 10 * }); * Or * dispatchAction({ * type: 'showTip', * seriesIndex: 0, * dataIndex or dataIndexInside or name * }); * * TODO Batch */ _manuallyShowTip: function (event) { // From self if (event.from === this.uid) { return; } var ecModel = this._ecModel; var seriesIndex = event.seriesIndex; var seriesModel = ecModel.getSeriesByIndex(seriesIndex); var api = this._api; var isTriggerAxis = this._tooltipModel.get('trigger') === 'axis'; function seriesHaveDataOnIndex(_series) { var data = _series.getData(); var dataIndex = modelUtil.queryDataIndex(data, event); // Have single dataIndex if (dataIndex != null && !zrUtil.isArray(dataIndex) && data.hasValue(dataIndex) ) { return true; } } if (event.x == null || event.y == null) { if (isTriggerAxis) { // Find another series. if (seriesModel && !seriesHaveDataOnIndex(seriesModel)) { seriesModel = null; } if (!seriesModel) { // Find the first series can use axis trigger And data is not null ecModel.eachSeries(function (_series) { if (ifSeriesSupportAxisTrigger(_series) && !seriesModel) { if (seriesHaveDataOnIndex(_series)) { seriesModel = _series; } } }); } } else { // Use the first series by default. seriesModel = seriesModel || ecModel.getSeriesByIndex(0); } if (seriesModel) { var data = seriesModel.getData(); var dataIndex = modelUtil.queryDataIndex(data, event); if (dataIndex == null || zrUtil.isArray(dataIndex)) { return; } var el = data.getItemGraphicEl(dataIndex); var cx; var cy; // Try to get the point in coordinate system var coordSys = seriesModel.coordinateSystem; if (seriesModel.getTooltipPosition) { var point = seriesModel.getTooltipPosition(dataIndex) || []; cx = point[0]; cy = point[1]; } else if (coordSys && coordSys.dataToPoint) { var point = coordSys.dataToPoint( data.getValues( zrUtil.map(coordSys.dimensions, function (dim) { return seriesModel.coordDimToDataDim(dim)[0]; }), dataIndex, true ) ); cx = point && point[0]; cy = point && point[1]; } else if (el) { // Use graphic bounding rect var rect = el.getBoundingRect().clone(); rect.applyTransform(el.transform); cx = rect.x + rect.width / 2; cy = rect.y + rect.height / 2; } if (cx != null && cy != null) { this._tryShow({ offsetX: cx, offsetY: cy, position: event.position, target: el, event: {} }); } } } else { var el = api.getZr().handler.findHover(event.x, event.y); this._tryShow({ offsetX: event.x, offsetY: event.y, position: event.position, target: el, event: {} }); } }, _manuallyHideTip: function (e) { if (e.from === this.uid) { return; } this._hide(); }, _prepareAxisTriggerData: function (tooltipModel, ecModel) { // Prepare data for axis trigger var seriesGroupByAxis = {}; ecModel.eachSeries(function (seriesModel) { if (ifSeriesSupportAxisTrigger(seriesModel)) { var coordSys = seriesModel.coordinateSystem; var baseAxis; var key; // Only cartesian2d, polar and single support axis trigger if (coordSys.type === 'cartesian2d') { // FIXME `axisPointer.axis` is not baseAxis baseAxis = coordSys.getBaseAxis(); key = baseAxis.dim + baseAxis.index; } else if (coordSys.type === 'singleAxis') { baseAxis = coordSys.getAxis(); key = baseAxis.dim + baseAxis.type; } else { baseAxis = coordSys.getBaseAxis(); key = baseAxis.dim + coordSys.name; } seriesGroupByAxis[key] = seriesGroupByAxis[key] || { coordSys: [], series: [] }; seriesGroupByAxis[key].coordSys.push(coordSys); seriesGroupByAxis[key].series.push(seriesModel); } }, this); return seriesGroupByAxis; }, /** * mousemove handler * @param {Object} e * @private */ _tryShow: function (e) { var el = e.target; var tooltipModel = this._tooltipModel; var globalTrigger = tooltipModel.get('trigger'); var ecModel = this._ecModel; var api = this._api; if (!tooltipModel) { return; } // Save mouse x, mouse y. So we can try to keep showing the tip if chart is refreshed this._lastX = e.offsetX; this._lastY = e.offsetY; // Always show item tooltip if mouse is on the element with dataIndex if (el && el.dataIndex != null) { // Use dataModel in element if possible // Used when mouseover on a element like markPoint or edge // In which case, the data is not main data in series. var dataModel = el.dataModel || ecModel.getSeriesByIndex(el.seriesIndex); var dataIndex = el.dataIndex; var itemModel = dataModel.getData().getItemModel(dataIndex); // Series or single data may use item trigger when global is axis trigger if ((itemModel.get('tooltip.trigger') || globalTrigger) === 'axis') { this._showAxisTooltip(tooltipModel, ecModel, e); } else { // Reset ticket this._ticket = ''; // If either single data or series use item trigger this._hideAxisPointer(); // Reset last hover and dispatch downplay action this._resetLastHover(); this._showItemTooltipContent(dataModel, dataIndex, el.dataType, e); } api.dispatchAction({ type: 'showTip', from: this.uid, dataIndexInside: el.dataIndex, seriesIndex: el.seriesIndex }); } // Tooltip provided directly. Like legend else if (el && el.tooltip) { var tooltipOpt = el.tooltip; if (typeof tooltipOpt === 'string') { var content = tooltipOpt; tooltipOpt = { content: content, // Fixed formatter formatter: content }; } var subTooltipModel = new Model(tooltipOpt, tooltipModel); var defaultHtml = subTooltipModel.get('content'); var asyncTicket = Math.random(); this._showTooltipContent( // TODO params subTooltipModel, defaultHtml, subTooltipModel.get('formatterParams') || {}, asyncTicket, e.offsetX, e.offsetY, e.position, el, api ); } else { if (globalTrigger === 'item') { this._hide(); } else { // Try show axis tooltip this._showAxisTooltip(tooltipModel, ecModel, e); } // Action of cross pointer // other pointer types will trigger action in _dispatchAndShowSeriesTooltipContent method if (tooltipModel.get('axisPointer.type') === 'cross') { api.dispatchAction({ type: 'showTip', from: this.uid, x: e.offsetX, y: e.offsetY }); } } }, /** * Show tooltip on axis * @param {module:echarts/component/tooltip/TooltipModel} tooltipModel * @param {module:echarts/model/Global} ecModel * @param {Object} e * @private */ _showAxisTooltip: function (tooltipModel, ecModel, e) { var axisPointerModel = tooltipModel.getModel('axisPointer'); var axisPointerType = axisPointerModel.get('type'); if (axisPointerType === 'cross') { var el = e.target; if (el && el.dataIndex != null) { var seriesModel = ecModel.getSeriesByIndex(el.seriesIndex); var dataIndex = el.dataIndex; this._showItemTooltipContent(seriesModel, dataIndex, el.dataType, e); } } this._showAxisPointer(); var allNotShow = true; zrUtil.each(this._seriesGroupByAxis, function (seriesCoordSysSameAxis) { // Try show the axis pointer var allCoordSys = seriesCoordSysSameAxis.coordSys; var coordSys = allCoordSys[0]; // If mouse position is not in the grid or polar var point = [e.offsetX, e.offsetY]; if (!coordSys.containPoint(point)) { // Hide axis pointer this._hideAxisPointer(coordSys.name); return; } allNotShow = false; // Make sure point is discrete on cateogry axis var dimensions = coordSys.dimensions; var value = coordSys.pointToData(point, true); point = coordSys.dataToPoint(value); var baseAxis = coordSys.getBaseAxis(); var axisType = axisPointerModel.get('axis'); if (axisType === 'auto') { axisType = baseAxis.dim; } var contentNotChange = false; var lastHover = this._lastHover; if (axisPointerType === 'cross') { // If hover data not changed // Possible when two axes are all category if (dataEqual(lastHover.data, value)) { contentNotChange = true; } lastHover.data = value; } else { var valIndex = zrUtil.indexOf(dimensions, axisType); // If hover data not changed on the axis dimension if (lastHover.data === value[valIndex]) { contentNotChange = true; } lastHover.data = value[valIndex]; } var enableAnimation = tooltipModel.get('animation'); if (coordSys.type === 'cartesian2d' && !contentNotChange) { this._showCartesianPointer( axisPointerModel, coordSys, axisType, point, enableAnimation ); } else if (coordSys.type === 'polar' && !contentNotChange) { this._showPolarPointer( axisPointerModel, coordSys, axisType, point, enableAnimation ); } else if (coordSys.type === 'singleAxis' && !contentNotChange) { this._showSinglePointer( axisPointerModel, coordSys, axisType, point, enableAnimation ); } if (axisPointerType !== 'cross') { this._dispatchAndShowSeriesTooltipContent( coordSys, seriesCoordSysSameAxis.series, point, value, contentNotChange, e.position ); } }, this); if (!this._tooltipModel.get('show')) { this._hideAxisPointer(); } if (allNotShow) { this._hide(); } }, /** * Show tooltip on axis of cartesian coordinate * @param {module:echarts/model/Model} axisPointerModel * @param {module:echarts/coord/cartesian/Cartesian2D} cartesians * @param {string} axisType * @param {Array.} point * @private */ _showCartesianPointer: function (axisPointerModel, cartesian, axisType, point, enableAnimation) { var self = this; var axisPointerType = axisPointerModel.get('type'); var baseAxis = cartesian.getBaseAxis(); var moveAnimation = enableAnimation && axisPointerType !== 'cross' && baseAxis.type === 'category' && baseAxis.getBandWidth() > 20; if (axisPointerType === 'cross') { moveGridLine('x', point, cartesian.getAxis('y').getGlobalExtent()); moveGridLine('y', point, cartesian.getAxis('x').getGlobalExtent()); this._updateCrossText(cartesian, point, axisPointerModel); } else { var otherAxis = cartesian.getAxis(axisType === 'x' ? 'y' : 'x'); var otherExtent = otherAxis.getGlobalExtent(); if (cartesian.type === 'cartesian2d') { (axisPointerType === 'line' ? moveGridLine : moveGridShadow)( axisType, point, otherExtent ); } } /** * @inner */ function moveGridLine(axisType, point, otherExtent) { var targetShape = axisType === 'x' ? makeLineShape(point[0], otherExtent[0], point[0], otherExtent[1]) : makeLineShape(otherExtent[0], point[1], otherExtent[1], point[1]); var pointerEl = self._getPointerElement( cartesian, axisPointerModel, axisType, targetShape ); graphic.subPixelOptimizeLine({ shape: targetShape, style: pointerEl.style }); moveAnimation ? graphic.updateProps(pointerEl, { shape: targetShape }, axisPointerModel) : pointerEl.attr({ shape: targetShape }); } /** * @inner */ function moveGridShadow(axisType, point, otherExtent) { var axis = cartesian.getAxis(axisType); var bandWidth = axis.getBandWidth(); var span = otherExtent[1] - otherExtent[0]; var targetShape = axisType === 'x' ? makeRectShape(point[0] - bandWidth / 2, otherExtent[0], bandWidth, span) : makeRectShape(otherExtent[0], point[1] - bandWidth / 2, span, bandWidth); var pointerEl = self._getPointerElement( cartesian, axisPointerModel, axisType, targetShape ); moveAnimation ? graphic.updateProps(pointerEl, { shape: targetShape }, axisPointerModel) : pointerEl.attr({ shape: targetShape }); } }, _showSinglePointer: function (axisPointerModel, single, axisType, point, enableAnimation) { var self = this; var axisPointerType = axisPointerModel.get('type'); var moveAnimation = enableAnimation && axisPointerType !== 'cross' && single.getBaseAxis().type === 'category'; var rect = single.getRect(); var otherExtent = [rect.y, rect.y + rect.height]; moveSingleLine(axisType, point, otherExtent); /** * @inner */ function moveSingleLine(axisType, point, otherExtent) { var axis = single.getAxis(); var orient = axis.orient; var targetShape = orient === 'horizontal' ? makeLineShape(point[0], otherExtent[0], point[0], otherExtent[1]) : makeLineShape(otherExtent[0], point[1], otherExtent[1], point[1]); var pointerEl = self._getPointerElement( single, axisPointerModel, axisType, targetShape ); moveAnimation ? graphic.updateProps(pointerEl, { shape: targetShape }, axisPointerModel) : pointerEl.attr({ shape: targetShape }); } }, /** * Show tooltip on axis of polar coordinate * @param {module:echarts/model/Model} axisPointerModel * @param {Array.} polar * @param {string} axisType * @param {Array.} point */ _showPolarPointer: function (axisPointerModel, polar, axisType, point, enableAnimation) { var self = this; var axisPointerType = axisPointerModel.get('type'); var angleAxis = polar.getAngleAxis(); var radiusAxis = polar.getRadiusAxis(); var moveAnimation = enableAnimation && axisPointerType !== 'cross' && polar.getBaseAxis().type === 'category'; if (axisPointerType === 'cross') { movePolarLine('angle', point, radiusAxis.getExtent()); movePolarLine('radius', point, angleAxis.getExtent()); this._updateCrossText(polar, point, axisPointerModel); } else { var otherAxis = polar.getAxis(axisType === 'radius' ? 'angle' : 'radius'); var otherExtent = otherAxis.getExtent(); (axisPointerType === 'line' ? movePolarLine : movePolarShadow)( axisType, point, otherExtent ); } /** * @inner */ function movePolarLine(axisType, point, otherExtent) { var mouseCoord = polar.pointToCoord(point); var targetShape; if (axisType === 'angle') { var p1 = polar.coordToPoint([otherExtent[0], mouseCoord[1]]); var p2 = polar.coordToPoint([otherExtent[1], mouseCoord[1]]); targetShape = makeLineShape(p1[0], p1[1], p2[0], p2[1]); } else { targetShape = { cx: polar.cx, cy: polar.cy, r: mouseCoord[0] }; } var pointerEl = self._getPointerElement( polar, axisPointerModel, axisType, targetShape ); moveAnimation ? graphic.updateProps(pointerEl, { shape: targetShape }, axisPointerModel) : pointerEl.attr({ shape: targetShape }); } /** * @inner */ function movePolarShadow(axisType, point, otherExtent) { var axis = polar.getAxis(axisType); var bandWidth = axis.getBandWidth(); var mouseCoord = polar.pointToCoord(point); var targetShape; var radian = Math.PI / 180; if (axisType === 'angle') { targetShape = makeSectorShape( polar.cx, polar.cy, otherExtent[0], otherExtent[1], // In ECharts y is negative if angle is positive (-mouseCoord[1] - bandWidth / 2) * radian, (-mouseCoord[1] + bandWidth / 2) * radian ); } else { targetShape = makeSectorShape( polar.cx, polar.cy, mouseCoord[0] - bandWidth / 2, mouseCoord[0] + bandWidth / 2, 0, Math.PI * 2 ); } var pointerEl = self._getPointerElement( polar, axisPointerModel, axisType, targetShape ); moveAnimation ? graphic.updateProps(pointerEl, { shape: targetShape }, axisPointerModel) : pointerEl.attr({ shape: targetShape }); } }, _updateCrossText: function (coordSys, point, axisPointerModel) { var crossStyleModel = axisPointerModel.getModel('crossStyle'); var textStyleModel = crossStyleModel.getModel('textStyle'); var tooltipModel = this._tooltipModel; var text = this._crossText; if (!text) { text = this._crossText = new graphic.Text({ style: { textAlign: 'left', textVerticalAlign: 'bottom' } }); this.group.add(text); } var value = coordSys.pointToData(point); var dims = coordSys.dimensions; value = zrUtil.map(value, function (val, idx) { var axis = coordSys.getAxis(dims[idx]); if (axis.type === 'category' || axis.type === 'time') { val = axis.scale.getLabel(val); } else { val = formatUtil.addCommas( val.toFixed(axis.getPixelPrecision()) ); } return val; }); text.setStyle({ fill: textStyleModel.getTextColor() || crossStyleModel.get('color'), textFont: textStyleModel.getFont(), text: value.join(', '), x: point[0] + 5, y: point[1] - 5 }); text.z = tooltipModel.get('z'); text.zlevel = tooltipModel.get('zlevel'); }, _getPointerElement: function (coordSys, pointerModel, axisType, initShape) { var tooltipModel = this._tooltipModel; var z = tooltipModel.get('z'); var zlevel = tooltipModel.get('zlevel'); var axisPointers = this._axisPointers; var coordSysName = coordSys.name; axisPointers[coordSysName] = axisPointers[coordSysName] || {}; if (axisPointers[coordSysName][axisType]) { return axisPointers[coordSysName][axisType]; } // Create if not exists var pointerType = pointerModel.get('type'); var styleModel = pointerModel.getModel(pointerType + 'Style'); var isShadow = pointerType === 'shadow'; var style = styleModel[isShadow ? 'getAreaStyle' : 'getLineStyle'](); var elementType = coordSys.type === 'polar' ? (isShadow ? 'Sector' : (axisType === 'radius' ? 'Circle' : 'Line')) : (isShadow ? 'Rect' : 'Line'); isShadow ? (style.stroke = null) : (style.fill = null); var el = axisPointers[coordSysName][axisType] = new graphic[elementType]({ style: style, z: z, zlevel: zlevel, silent: true, shape: initShape }); this.group.add(el); return el; }, /** * Dispatch actions and show tooltip on series * @param {Array.} seriesList * @param {Array.} point * @param {Array.} value * @param {boolean} contentNotChange * @param {Array.|string|Function} [positionExpr] */ _dispatchAndShowSeriesTooltipContent: function ( coordSys, seriesList, point, value, contentNotChange, positionExpr ) { var rootTooltipModel = this._tooltipModel; var baseAxis = coordSys.getBaseAxis(); var baseDimIndex = baseAxis.dim === 'x' || baseAxis.dim === 'radius' ? 0 : 1; var payloadBatch = zrUtil.map(seriesList, function (series) { return { seriesIndex: series.seriesIndex, dataIndexInside: series.getAxisTooltipDataIndex ? series.getAxisTooltipDataIndex(series.coordDimToDataDim(baseAxis.dim), value, baseAxis) : series.getData().indexOfNearest( series.coordDimToDataDim(baseAxis.dim)[0], value[baseDimIndex], // Add a threshold to avoid find the wrong dataIndex when data length is not same false, baseAxis.type === 'category' ? 0.5 : null ) }; }); var sampleSeriesIndex; zrUtil.each(payloadBatch, function (payload, idx) { if (seriesList[idx].getData().hasValue(payload.dataIndexInside)) { sampleSeriesIndex = idx; } }); // Fallback to 0. sampleSeriesIndex = sampleSeriesIndex || 0; var lastHover = this._lastHover; var api = this._api; // Dispatch downplay action if (lastHover.payloadBatch && !contentNotChange) { api.dispatchAction({ type: 'downplay', batch: lastHover.payloadBatch }); } // Dispatch highlight action if (!contentNotChange) { api.dispatchAction({ type: 'highlight', batch: payloadBatch }); lastHover.payloadBatch = payloadBatch; } // Dispatch showTip action api.dispatchAction({ type: 'showTip', dataIndexInside: payloadBatch[sampleSeriesIndex].dataIndexInside, seriesIndex: payloadBatch[sampleSeriesIndex].seriesIndex, from: this.uid }); if (baseAxis && rootTooltipModel.get('showContent') && rootTooltipModel.get('show')) { var paramsList = zrUtil.map(seriesList, function (series, index) { return series.getDataParams(payloadBatch[index].dataIndexInside); }); if (!contentNotChange) { // Update html content var firstDataIndex = payloadBatch[sampleSeriesIndex].dataIndexInside; // Default tooltip content // FIXME // (1) shold be the first data which has name? // (2) themeRiver, firstDataIndex is array, and first line is unnecessary. var firstLine = baseAxis.type === 'time' ? baseAxis.scale.getLabel(value[baseDimIndex]) : seriesList[sampleSeriesIndex].getData().getName(firstDataIndex); var defaultHtml = (firstLine ? firstLine + '
' : '') + zrUtil.map(seriesList, function (series, index) { return series.formatTooltip(payloadBatch[index].dataIndexInside, true); }).join('
'); var asyncTicket = 'axis_' + coordSys.name + '_' + firstDataIndex; this._showTooltipContent( rootTooltipModel, defaultHtml, paramsList, asyncTicket, point[0], point[1], positionExpr, null, api ); } else { updatePosition( positionExpr || rootTooltipModel.get('position'), point[0], point[1], rootTooltipModel.get('confine'), this._tooltipContent, paramsList, null, api ); } } }, /** * Show tooltip on item * @param {module:echarts/model/Series} seriesModel * @param {number} dataIndex * @param {string} dataType * @param {Object} e */ _showItemTooltipContent: function (seriesModel, dataIndex, dataType, e) { // FIXME Graph data var api = this._api; var data = seriesModel.getData(dataType); var itemModel = data.getItemModel(dataIndex); var tooltipOpt = itemModel.get('tooltip', true); if (typeof tooltipOpt === 'string') { // In each data item tooltip can be simply write: // { // value: 10, // tooltip: 'Something you need to know' // } var tooltipContent = tooltipOpt; tooltipOpt = { formatter: tooltipContent }; } var rootTooltipModel = this._tooltipModel; var seriesTooltipModel = seriesModel.getModel( 'tooltip', rootTooltipModel ); var tooltipModel = new Model(tooltipOpt, seriesTooltipModel, seriesTooltipModel.ecModel); var params = seriesModel.getDataParams(dataIndex, dataType); var defaultHtml = seriesModel.formatTooltip(dataIndex, false, dataType); var asyncTicket = 'item_' + seriesModel.name + '_' + dataIndex; this._showTooltipContent( tooltipModel, defaultHtml, params, asyncTicket, e.offsetX, e.offsetY, e.position, e.target, api ); }, _showTooltipContent: function ( tooltipModel, defaultHtml, params, asyncTicket, x, y, positionExpr, target, api ) { // Reset ticket this._ticket = ''; if (tooltipModel.get('showContent') && tooltipModel.get('show')) { var tooltipContent = this._tooltipContent; var confine = tooltipModel.get('confine'); var formatter = tooltipModel.get('formatter'); positionExpr = positionExpr || tooltipModel.get('position'); var html = defaultHtml; if (formatter) { if (typeof formatter === 'string') { html = formatUtil.formatTpl(formatter, params); } else if (typeof formatter === 'function') { var self = this; var ticket = asyncTicket; var callback = function (cbTicket, html) { if (cbTicket === self._ticket) { tooltipContent.setContent(html); updatePosition( positionExpr, x, y, confine, tooltipContent, params, target, api ); } }; self._ticket = ticket; html = formatter(params, ticket, callback); } } tooltipContent.show(tooltipModel); tooltipContent.setContent(html); updatePosition( positionExpr, x, y, confine, tooltipContent, params, target, api ); } }, /** * Show axis pointer * @param {string} [coordSysName] */ _showAxisPointer: function (coordSysName) { if (coordSysName) { var axisPointers = this._axisPointers[coordSysName]; axisPointers && zrUtil.each(axisPointers, function (el) { el.show(); }); } else { this.group.eachChild(function (child) { child.show(); }); this.group.show(); } }, _resetLastHover: function () { var lastHover = this._lastHover; if (lastHover.payloadBatch) { this._api.dispatchAction({ type: 'downplay', batch: lastHover.payloadBatch }); } // Reset lastHover this._lastHover = {}; }, /** * Hide axis pointer * @param {string} [coordSysName] */ _hideAxisPointer: function (coordSysName) { if (coordSysName) { var axisPointers = this._axisPointers[coordSysName]; axisPointers && zrUtil.each(axisPointers, function (el) { el.hide(); }); } else { if (this.group.children().length) { this.group.hide(); } } }, _hide: function () { clearTimeout(this._showTimeout); this._hideAxisPointer(); this._resetLastHover(); if (!this._alwaysShowContent) { this._tooltipContent.hideLater(this._tooltipModel.get('hideDelay')); } this._api.dispatchAction({ type: 'hideTip', from: this.uid }); this._lastX = this._lastY = null; }, dispose: function (ecModel, api) { if (env.node) { return; } var zr = api.getZr(); this._tooltipContent.hide(); zr.off('click', this._tryShow); zr.off('mousemove', this._mousemove); zr.off('mouseout', this._hide); zr.off('globalout', this._hide); api.off('showTip', this._manuallyShowTip); api.off('hideTip', this._manuallyHideTip); } }); /***/ }, /* 285 */ /***/ function(module, exports, __webpack_require__) { /** * @module echarts/component/tooltip/TooltipContent */ var zrUtil = __webpack_require__(4); var zrColor = __webpack_require__(39); var eventUtil = __webpack_require__(88); var formatUtil = __webpack_require__(6); var each = zrUtil.each; var toCamelCase = formatUtil.toCamelCase; var env = __webpack_require__(2); var vendors = ['', '-webkit-', '-moz-', '-o-']; var gCssText = 'position:absolute;display:block;border-style:solid;white-space:nowrap;z-index:9999999;'; /** * @param {number} duration * @return {string} * @inner */ function assembleTransition(duration) { var transitionCurve = 'cubic-bezier(0.23, 1, 0.32, 1)'; var transitionText = 'left ' + duration + 's ' + transitionCurve + ',' + 'top ' + duration + 's ' + transitionCurve; return zrUtil.map(vendors, function (vendorPrefix) { return vendorPrefix + 'transition:' + transitionText; }).join(';'); } /** * @param {Object} textStyle * @return {string} * @inner */ function assembleFont(textStyleModel) { var cssText = []; var fontSize = textStyleModel.get('fontSize'); var color = textStyleModel.getTextColor(); color && cssText.push('color:' + color); cssText.push('font:' + textStyleModel.getFont()); fontSize && cssText.push('line-height:' + Math.round(fontSize * 3 / 2) + 'px'); each(['decoration', 'align'], function (name) { var val = textStyleModel.get(name); val && cssText.push('text-' + name + ':' + val); }); return cssText.join(';'); } /** * @param {Object} tooltipModel * @return {string} * @inner */ function assembleCssText(tooltipModel) { tooltipModel = tooltipModel; var cssText = []; var transitionDuration = tooltipModel.get('transitionDuration'); var backgroundColor = tooltipModel.get('backgroundColor'); var textStyleModel = tooltipModel.getModel('textStyle'); var padding = tooltipModel.get('padding'); // Animation transition transitionDuration && cssText.push(assembleTransition(transitionDuration)); if (backgroundColor) { if (env.canvasSupported) { cssText.push('background-Color:' + backgroundColor); } else { // for ie cssText.push( 'background-Color:#' + zrColor.toHex(backgroundColor) ); cssText.push('filter:alpha(opacity=70)'); } } // Border style each(['width', 'color', 'radius'], function (name) { var borderName = 'border-' + name; var camelCase = toCamelCase(borderName); var val = tooltipModel.get(camelCase); val != null && cssText.push(borderName + ':' + val + (name === 'color' ? '' : 'px')); }); // Text style cssText.push(assembleFont(textStyleModel)); // Padding if (padding != null) { cssText.push('padding:' + formatUtil.normalizeCssArray(padding).join('px ') + 'px'); } return cssText.join(';') + ';'; } /** * @alias module:echarts/component/tooltip/TooltipContent * @constructor */ function TooltipContent(container, api) { var el = document.createElement('div'); var zr = api.getZr(); this.el = el; this._x = api.getWidth() / 2; this._y = api.getHeight() / 2; container.appendChild(el); this._container = container; this._show = false; /** * @private */ this._hideTimeout; var self = this; el.onmouseenter = function () { // clear the timeout in hideLater and keep showing tooltip if (self.enterable) { clearTimeout(self._hideTimeout); self._show = true; } self._inContent = true; }; el.onmousemove = function (e) { e = e || window.event; if (!self.enterable) { // Try trigger zrender event to avoid mouse // in and out shape too frequently var handler = zr.handler; eventUtil.normalizeEvent(container, e, true); handler.dispatch('mousemove', e); } }; el.onmouseleave = function () { if (self.enterable) { if (self._show) { self.hideLater(self._hideDelay); } } self._inContent = false; }; } TooltipContent.prototype = { constructor: TooltipContent, enterable: true, /** * Update when tooltip is rendered */ update: function () { var container = this._container; var stl = container.currentStyle || document.defaultView.getComputedStyle(container); var domStyle = container.style; if (domStyle.position !== 'absolute' && stl.position !== 'absolute') { domStyle.position = 'relative'; } // Hide the tooltip // PENDING // this.hide(); }, show: function (tooltipModel) { clearTimeout(this._hideTimeout); var el = this.el; el.style.cssText = gCssText + assembleCssText(tooltipModel) // http://stackoverflow.com/questions/21125587/css3-transition-not-working-in-chrome-anymore + ';left:' + this._x + 'px;top:' + this._y + 'px;' + (tooltipModel.get('extraCssText') || ''); el.style.display = el.innerHTML ? 'block' : 'none'; this._show = true; }, setContent: function (content) { var el = this.el; el.innerHTML = content; el.style.display = content ? 'block' : 'none'; }, moveTo: function (x, y) { var style = this.el.style; style.left = x + 'px'; style.top = y + 'px'; this._x = x; this._y = y; }, hide: function () { this.el.style.display = 'none'; this._show = false; }, // showLater: function () hideLater: function (time) { if (this._show && !(this._inContent && this.enterable)) { if (time) { this._hideDelay = time; // Set show false to avoid invoke hideLater mutiple times this._show = false; this._hideTimeout = setTimeout(zrUtil.bind(this.hide, this), time); } else { this.hide(); } } }, isShow: function () { return this._show; } }; module.exports = TooltipContent; /***/ }, /* 286 */ /***/ function(module, exports, __webpack_require__) { 'use strict'; __webpack_require__(287); __webpack_require__(293); __webpack_require__(295); // Polar view __webpack_require__(1).extendComponentView({ type: 'polar' }); /***/ }, /* 287 */ /***/ function(module, exports, __webpack_require__) { // TODO Axis scale var Polar = __webpack_require__(288); var numberUtil = __webpack_require__(7); var zrUtil = __webpack_require__(4); var axisHelper = __webpack_require__(115); var niceScaleExtent = axisHelper.niceScaleExtent; // 依赖 PolarModel 做预处理 __webpack_require__(291); /** * Resize method bound to the polar * @param {module:echarts/coord/polar/PolarModel} polarModel * @param {module:echarts/ExtensionAPI} api */ function resizePolar(polarModel, api) { var center = polarModel.get('center'); var radius = polarModel.get('radius'); var width = api.getWidth(); var height = api.getHeight(); var parsePercent = numberUtil.parsePercent; this.cx = parsePercent(center[0], width); this.cy = parsePercent(center[1], height); var radiusAxis = this.getRadiusAxis(); var size = Math.min(width, height) / 2; // var idx = radiusAxis.inverse ? 1 : 0; radiusAxis.setExtent(0, parsePercent(radius, size)); } /** * Update polar */ function updatePolarScale(ecModel, api) { var polar = this; var angleAxis = polar.getAngleAxis(); var radiusAxis = polar.getRadiusAxis(); // Reset scale angleAxis.scale.setExtent(Infinity, -Infinity); radiusAxis.scale.setExtent(Infinity, -Infinity); ecModel.eachSeries(function (seriesModel) { if (seriesModel.coordinateSystem === polar) { var data = seriesModel.getData(); radiusAxis.scale.unionExtent( data.getDataExtent('radius', radiusAxis.type !== 'category') ); angleAxis.scale.unionExtent( data.getDataExtent('angle', angleAxis.type !== 'category') ); } }); niceScaleExtent(angleAxis, angleAxis.model); niceScaleExtent(radiusAxis, radiusAxis.model); // Fix extent of category angle axis if (angleAxis.type === 'category' && !angleAxis.onBand) { var extent = angleAxis.getExtent(); var diff = 360 / angleAxis.scale.count(); angleAxis.inverse ? (extent[1] += diff) : (extent[1] -= diff); angleAxis.setExtent(extent[0], extent[1]); } } /** * Set common axis properties * @param {module:echarts/coord/polar/AngleAxis|module:echarts/coord/polar/RadiusAxis} * @param {module:echarts/coord/polar/AxisModel} * @inner */ function setAxis(axis, axisModel) { axis.type = axisModel.get('type'); axis.scale = axisHelper.createScaleByModel(axisModel); axis.onBand = axisModel.get('boundaryGap') && axis.type === 'category'; // FIXME Radius axis not support inverse axis if (axisModel.mainType === 'angleAxis') { var startAngle = axisModel.get('startAngle'); axis.inverse = axisModel.get('inverse') ^ axisModel.get('clockwise'); axis.setExtent(startAngle, startAngle + (axis.inverse ? -360 : 360)); } // Inject axis instance axisModel.axis = axis; axis.model = axisModel; } var polarCreator = { dimensions: Polar.prototype.dimensions, create: function (ecModel, api) { var polarList = []; ecModel.eachComponent('polar', function (polarModel, idx) { var polar = new Polar(idx); // Inject resize and update method polar.resize = resizePolar; polar.update = updatePolarScale; var radiusAxis = polar.getRadiusAxis(); var angleAxis = polar.getAngleAxis(); var radiusAxisModel = polarModel.findAxisModel('radiusAxis'); var angleAxisModel = polarModel.findAxisModel('angleAxis'); setAxis(radiusAxis, radiusAxisModel); setAxis(angleAxis, angleAxisModel); polar.resize(polarModel, api); polarList.push(polar); polarModel.coordinateSystem = polar; }); // Inject coordinateSystem to series ecModel.eachSeries(function (seriesModel) { if (seriesModel.get('coordinateSystem') === 'polar') { var polarModel = ecModel.queryComponents({ mainType: 'polar', index: seriesModel.get('polarIndex'), id: seriesModel.get('polarId') })[0]; if (true) { if (!polarModel) { throw new Error( 'Polar "' + zrUtil.retrieve( seriesModel.get('polarIndex'), seriesModel.get('polarId'), 0 ) + '" not found' ); } } seriesModel.coordinateSystem = polarModel.coordinateSystem; } }); return polarList; } }; __webpack_require__(26).register('polar', polarCreator); /***/ }, /* 288 */ /***/ function(module, exports, __webpack_require__) { 'use strict'; /** * @module echarts/coord/polar/Polar */ var RadiusAxis = __webpack_require__(289); var AngleAxis = __webpack_require__(290); /** * @alias {module:echarts/coord/polar/Polar} * @constructor * @param {string} name */ var Polar = function (name) { /** * @type {string} */ this.name = name || ''; /** * x of polar center * @type {number} */ this.cx = 0; /** * y of polar center * @type {number} */ this.cy = 0; /** * @type {module:echarts/coord/polar/RadiusAxis} * @private */ this._radiusAxis = new RadiusAxis(); /** * @type {module:echarts/coord/polar/AngleAxis} * @private */ this._angleAxis = new AngleAxis(); }; Polar.prototype = { constructor: Polar, type: 'polar', /** * @param {Array.} * @readOnly */ dimensions: ['radius', 'angle'], /** * If contain coord * @param {Array.} point * @return {boolean} */ containPoint: function (point) { var coord = this.pointToCoord(point); return this._radiusAxis.contain(coord[0]) && this._angleAxis.contain(coord[1]); }, /** * If contain data * @param {Array.} data * @return {boolean} */ containData: function (data) { return this._radiusAxis.containData(data[0]) && this._angleAxis.containData(data[1]); }, /** * @param {string} axisType * @return {module:echarts/coord/polar/AngleAxis|module:echarts/coord/polar/RadiusAxis} */ getAxis: function (axisType) { return this['_' + axisType + 'Axis']; }, /** * Get axes by type of scale * @param {string} scaleType * @return {module:echarts/coord/polar/AngleAxis|module:echarts/coord/polar/RadiusAxis} */ getAxesByScale: function (scaleType) { var axes = []; var angleAxis = this._angleAxis; var radiusAxis = this._radiusAxis; angleAxis.scale.type === scaleType && axes.push(angleAxis); radiusAxis.scale.type === scaleType && axes.push(radiusAxis); return axes; }, /** * @return {module:echarts/coord/polar/AngleAxis} */ getAngleAxis: function () { return this._angleAxis; }, /** * @return {module:echarts/coord/polar/RadiusAxis} */ getRadiusAxis: function () { return this._radiusAxis; }, /** * @param {module:echarts/coord/polar/Axis} * @return {module:echarts/coord/polar/Axis} */ getOtherAxis: function (axis) { var angleAxis = this._angleAxis; return axis === angleAxis ? this._radiusAxis : angleAxis; }, /** * Base axis will be used on stacking. * * @return {module:echarts/coord/polar/Axis} */ getBaseAxis: function () { return this.getAxesByScale('ordinal')[0] || this.getAxesByScale('time')[0] || this.getAngleAxis(); }, /** * Convert series data to a list of (x, y) points * @param {module:echarts/data/List} data * @return {Array} * Return list of coordinates. For example: * `[[10, 10], [20, 20], [30, 30]]` */ dataToPoints: function (data) { return data.mapArray(this.dimensions, function (radius, angle) { return this.dataToPoint([radius, angle]); }, this); }, /** * Convert a single data item to (x, y) point. * Parameter data is an array which the first element is radius and the second is angle * @param {Array.} data * @param {boolean} [clamp=false] * @return {Array.} */ dataToPoint: function (data, clamp) { return this.coordToPoint([ this._radiusAxis.dataToRadius(data[0], clamp), this._angleAxis.dataToAngle(data[1], clamp) ]); }, /** * Convert a (x, y) point to data * @param {Array.} point * @param {boolean} [clamp=false] * @return {Array.} */ pointToData: function (point, clamp) { var coord = this.pointToCoord(point); return [ this._radiusAxis.radiusToData(coord[0], clamp), this._angleAxis.angleToData(coord[1], clamp) ]; }, /** * Convert a (x, y) point to (radius, angle) coord * @param {Array.} point * @return {Array.} */ pointToCoord: function (point) { var dx = point[0] - this.cx; var dy = point[1] - this.cy; var angleAxis = this.getAngleAxis(); var extent = angleAxis.getExtent(); var minAngle = Math.min(extent[0], extent[1]); var maxAngle = Math.max(extent[0], extent[1]); // Fix fixed extent in polarCreator // FIXME angleAxis.inverse ? (minAngle = maxAngle - 360) : (maxAngle = minAngle + 360); var radius = Math.sqrt(dx * dx + dy * dy); dx /= radius; dy /= radius; var radian = Math.atan2(-dy, dx) / Math.PI * 180; // move to angleExtent var dir = radian < minAngle ? 1 : -1; while (radian < minAngle || radian > maxAngle) { radian += dir * 360; } return [radius, radian]; }, /** * Convert a (radius, angle) coord to (x, y) point * @param {Array.} coord * @return {Array.} */ coordToPoint: function (coord) { var radius = coord[0]; var radian = coord[1] / 180 * Math.PI; var x = Math.cos(radian) * radius + this.cx; // Inverse the y var y = -Math.sin(radian) * radius + this.cy; return [x, y]; } }; module.exports = Polar; /***/ }, /* 289 */ /***/ function(module, exports, __webpack_require__) { 'use strict'; var zrUtil = __webpack_require__(4); var Axis = __webpack_require__(124); function RadiusAxis(scale, radiusExtent) { Axis.call(this, 'radius', scale, radiusExtent); /** * Axis type * - 'category' * - 'value' * - 'time' * - 'log' * @type {string} */ this.type = 'category'; } RadiusAxis.prototype = { constructor: RadiusAxis, dataToRadius: Axis.prototype.dataToCoord, radiusToData: Axis.prototype.coordToData }; zrUtil.inherits(RadiusAxis, Axis); module.exports = RadiusAxis; /***/ }, /* 290 */ /***/ function(module, exports, __webpack_require__) { 'use strict'; var zrUtil = __webpack_require__(4); var Axis = __webpack_require__(124); function AngleAxis(scale, angleExtent) { angleExtent = angleExtent || [0, 360]; Axis.call(this, 'angle', scale, angleExtent); /** * Axis type * - 'category' * - 'value' * - 'time' * - 'log' * @type {string} */ this.type = 'category'; } AngleAxis.prototype = { constructor: AngleAxis, dataToAngle: Axis.prototype.dataToCoord, angleToData: Axis.prototype.coordToData }; zrUtil.inherits(AngleAxis, Axis); module.exports = AngleAxis; /***/ }, /* 291 */ /***/ function(module, exports, __webpack_require__) { 'use strict'; __webpack_require__(292); __webpack_require__(1).extendComponentModel({ type: 'polar', dependencies: ['polarAxis', 'angleAxis'], /** * @type {module:echarts/coord/polar/Polar} */ coordinateSystem: null, /** * @param {string} axisType * @return {module:echarts/coord/polar/AxisModel} */ findAxisModel: function (axisType) { var foundAxisModel; var ecModel = this.ecModel; ecModel.eachComponent(axisType, function (axisModel) { var polarModel = ecModel.queryComponents({ mainType: 'polar', index: axisModel.getShallow('polarIndex'), id: axisModel.getShallow('polarId') })[0]; if(polarModel === this) { foundAxisModel = axisModel; } }, this); return foundAxisModel; }, defaultOption: { zlevel: 0, z: 0, center: ['50%', '50%'], radius: '80%' } }); /***/ }, /* 292 */ /***/ function(module, exports, __webpack_require__) { 'use strict'; var zrUtil = __webpack_require__(4); var ComponentModel = __webpack_require__(19); var axisModelCreator = __webpack_require__(128); var PolarAxisModel = ComponentModel.extend({ type: 'polarAxis', /** * @type {module:echarts/coord/polar/AngleAxis|module:echarts/coord/polar/RadiusAxis} */ axis: null }); zrUtil.merge(PolarAxisModel.prototype, __webpack_require__(130)); zrUtil.merge(PolarAxisModel.prototype, __webpack_require__(131)); var polarAxisDefaultExtendedOption = { angle: { // polarIndex: 0, // polarId: '', startAngle: 90, clockwise: true, splitNumber: 12, axisLabel: { rotate: false } }, radius: { // polarIndex: 0, // polarId: '', splitNumber: 5 } }; function getAxisType(axisDim, option) { // Default axis with data is category axis return option.type || (option.data ? 'category' : 'value'); } axisModelCreator('angle', PolarAxisModel, getAxisType, polarAxisDefaultExtendedOption.angle); axisModelCreator('radius', PolarAxisModel, getAxisType, polarAxisDefaultExtendedOption.radius); /***/ }, /* 293 */ /***/ function(module, exports, __webpack_require__) { 'use strict'; __webpack_require__(287); __webpack_require__(294); /***/ }, /* 294 */ /***/ function(module, exports, __webpack_require__) { 'use strict'; var zrUtil = __webpack_require__(4); var graphic = __webpack_require__(43); var Model = __webpack_require__(12); var elementList = ['axisLine', 'axisLabel', 'axisTick', 'splitLine', 'splitArea']; function getAxisLineShape(polar, r0, r, angle) { var start = polar.coordToPoint([r0, angle]); var end = polar.coordToPoint([r, angle]); return { x1: start[0], y1: start[1], x2: end[0], y2: end[1] }; } __webpack_require__(1).extendComponentView({ type: 'angleAxis', render: function (angleAxisModel, ecModel) { this.group.removeAll(); if (!angleAxisModel.get('show')) { return; } var polarModel = ecModel.getComponent('polar', angleAxisModel.get('polarIndex')); var angleAxis = angleAxisModel.axis; var polar = polarModel.coordinateSystem; var radiusExtent = polar.getRadiusAxis().getExtent(); var ticksAngles = angleAxis.getTicksCoords(); if (angleAxis.type !== 'category') { // Remove the last tick which will overlap the first tick ticksAngles.pop(); } zrUtil.each(elementList, function (name) { if (angleAxisModel.get(name +'.show')) { this['_' + name](angleAxisModel, polar, ticksAngles, radiusExtent); } }, this); }, /** * @private */ _axisLine: function (angleAxisModel, polar, ticksAngles, radiusExtent) { var lineStyleModel = angleAxisModel.getModel('axisLine.lineStyle'); var circle = new graphic.Circle({ shape: { cx: polar.cx, cy: polar.cy, r: radiusExtent[1] }, style: lineStyleModel.getLineStyle(), z2: 1, silent: true }); circle.style.fill = null; this.group.add(circle); }, /** * @private */ _axisTick: function (angleAxisModel, polar, ticksAngles, radiusExtent) { var tickModel = angleAxisModel.getModel('axisTick'); var tickLen = (tickModel.get('inside') ? -1 : 1) * tickModel.get('length'); var lines = zrUtil.map(ticksAngles, function (tickAngle) { return new graphic.Line({ shape: getAxisLineShape(polar, radiusExtent[1], radiusExtent[1] + tickLen, tickAngle) }); }); this.group.add(graphic.mergePath( lines, { style: zrUtil.defaults( tickModel.getModel('lineStyle').getLineStyle(), { stroke: angleAxisModel.get('axisLine.lineStyle.color') } ) } )); }, /** * @private */ _axisLabel: function (angleAxisModel, polar, ticksAngles, radiusExtent) { var axis = angleAxisModel.axis; var categoryData = angleAxisModel.get('data'); var labelModel = angleAxisModel.getModel('axisLabel'); var axisTextStyleModel = labelModel.getModel('textStyle'); var labels = angleAxisModel.getFormattedLabels(); var labelMargin = labelModel.get('margin'); var labelsAngles = axis.getLabelsCoords(); // Use length of ticksAngles because it may remove the last tick to avoid overlapping for (var i = 0; i < ticksAngles.length; i++) { var r = radiusExtent[1]; var p = polar.coordToPoint([r + labelMargin, labelsAngles[i]]); var cx = polar.cx; var cy = polar.cy; var labelTextAlign = Math.abs(p[0] - cx) / r < 0.3 ? 'center' : (p[0] > cx ? 'left' : 'right'); var labelTextBaseline = Math.abs(p[1] - cy) / r < 0.3 ? 'middle' : (p[1] > cy ? 'top' : 'bottom'); var textStyleModel = axisTextStyleModel; if (categoryData && categoryData[i] && categoryData[i].textStyle) { textStyleModel = new Model( categoryData[i].textStyle, axisTextStyleModel ); } this.group.add(new graphic.Text({ style: { x: p[0], y: p[1], fill: textStyleModel.getTextColor() || angleAxisModel.get('axisLine.lineStyle.color'), text: labels[i], textAlign: labelTextAlign, textVerticalAlign: labelTextBaseline, textFont: textStyleModel.getFont() }, silent: true })); } }, /** * @private */ _splitLine: function (angleAxisModel, polar, ticksAngles, radiusExtent) { var splitLineModel = angleAxisModel.getModel('splitLine'); var lineStyleModel = splitLineModel.getModel('lineStyle'); var lineColors = lineStyleModel.get('color'); var lineCount = 0; lineColors = lineColors instanceof Array ? lineColors : [lineColors]; var splitLines = []; for (var i = 0; i < ticksAngles.length; i++) { var colorIndex = (lineCount++) % lineColors.length; splitLines[colorIndex] = splitLines[colorIndex] || []; splitLines[colorIndex].push(new graphic.Line({ shape: getAxisLineShape(polar, radiusExtent[0], radiusExtent[1], ticksAngles[i]) })); } // Simple optimization // Batching the lines if color are the same for (var i = 0; i < splitLines.length; i++) { this.group.add(graphic.mergePath(splitLines[i], { style: zrUtil.defaults({ stroke: lineColors[i % lineColors.length] }, lineStyleModel.getLineStyle()), silent: true, z: angleAxisModel.get('z') })); } }, /** * @private */ _splitArea: function (angleAxisModel, polar, ticksAngles, radiusExtent) { var splitAreaModel = angleAxisModel.getModel('splitArea'); var areaStyleModel = splitAreaModel.getModel('areaStyle'); var areaColors = areaStyleModel.get('color'); var lineCount = 0; areaColors = areaColors instanceof Array ? areaColors : [areaColors]; var splitAreas = []; var RADIAN = Math.PI / 180; var prevAngle = -ticksAngles[0] * RADIAN; var r0 = Math.min(radiusExtent[0], radiusExtent[1]); var r1 = Math.max(radiusExtent[0], radiusExtent[1]); var clockwise = angleAxisModel.get('clockwise'); for (var i = 1; i < ticksAngles.length; i++) { var colorIndex = (lineCount++) % areaColors.length; splitAreas[colorIndex] = splitAreas[colorIndex] || []; splitAreas[colorIndex].push(new graphic.Sector({ shape: { cx: polar.cx, cy: polar.cy, r0: r0, r: r1, startAngle: prevAngle, endAngle: -ticksAngles[i] * RADIAN, clockwise: clockwise }, silent: true })); prevAngle = -ticksAngles[i] * RADIAN; } // Simple optimization // Batching the lines if color are the same for (var i = 0; i < splitAreas.length; i++) { this.group.add(graphic.mergePath(splitAreas[i], { style: zrUtil.defaults({ fill: areaColors[i % areaColors.length] }, areaStyleModel.getAreaStyle()), silent: true })); } } }); /***/ }, /* 295 */ /***/ function(module, exports, __webpack_require__) { __webpack_require__(287); __webpack_require__(296); /***/ }, /* 296 */ /***/ function(module, exports, __webpack_require__) { 'use strict'; var zrUtil = __webpack_require__(4); var graphic = __webpack_require__(43); var AxisBuilder = __webpack_require__(134); var axisBuilderAttrs = [ 'axisLine', 'axisLabel', 'axisTick', 'axisName' ]; var selfBuilderAttrs = [ 'splitLine', 'splitArea' ]; __webpack_require__(1).extendComponentView({ type: 'radiusAxis', render: function (radiusAxisModel, ecModel) { this.group.removeAll(); if (!radiusAxisModel.get('show')) { return; } var polarModel = ecModel.getComponent('polar', radiusAxisModel.get('polarIndex')); var angleAxis = polarModel.coordinateSystem.getAngleAxis(); var radiusAxis = radiusAxisModel.axis; var polar = polarModel.coordinateSystem; var ticksCoords = radiusAxis.getTicksCoords(); var axisAngle = angleAxis.getExtent()[0]; var radiusExtent = radiusAxis.getExtent(); var layout = layoutAxis(polar, radiusAxisModel, axisAngle); var axisBuilder = new AxisBuilder(radiusAxisModel, layout); zrUtil.each(axisBuilderAttrs, axisBuilder.add, axisBuilder); this.group.add(axisBuilder.getGroup()); zrUtil.each(selfBuilderAttrs, function (name) { if (radiusAxisModel.get(name +'.show')) { this['_' + name](radiusAxisModel, polar, axisAngle, radiusExtent, ticksCoords); } }, this); }, /** * @private */ _splitLine: function (radiusAxisModel, polar, axisAngle, radiusExtent, ticksCoords) { var splitLineModel = radiusAxisModel.getModel('splitLine'); var lineStyleModel = splitLineModel.getModel('lineStyle'); var lineColors = lineStyleModel.get('color'); var lineCount = 0; lineColors = lineColors instanceof Array ? lineColors : [lineColors]; var splitLines = []; for (var i = 0; i < ticksCoords.length; i++) { var colorIndex = (lineCount++) % lineColors.length; splitLines[colorIndex] = splitLines[colorIndex] || []; splitLines[colorIndex].push(new graphic.Circle({ shape: { cx: polar.cx, cy: polar.cy, r: ticksCoords[i] }, silent: true })); } // Simple optimization // Batching the lines if color are the same for (var i = 0; i < splitLines.length; i++) { this.group.add(graphic.mergePath(splitLines[i], { style: zrUtil.defaults({ stroke: lineColors[i % lineColors.length], fill: null }, lineStyleModel.getLineStyle()), silent: true })); } }, /** * @private */ _splitArea: function (radiusAxisModel, polar, axisAngle, radiusExtent, ticksCoords) { var splitAreaModel = radiusAxisModel.getModel('splitArea'); var areaStyleModel = splitAreaModel.getModel('areaStyle'); var areaColors = areaStyleModel.get('color'); var lineCount = 0; areaColors = areaColors instanceof Array ? areaColors : [areaColors]; var splitAreas = []; var prevRadius = ticksCoords[0]; for (var i = 1; i < ticksCoords.length; i++) { var colorIndex = (lineCount++) % areaColors.length; splitAreas[colorIndex] = splitAreas[colorIndex] || []; splitAreas[colorIndex].push(new graphic.Sector({ shape: { cx: polar.cx, cy: polar.cy, r0: prevRadius, r: ticksCoords[i], startAngle: 0, endAngle: Math.PI * 2 }, silent: true })); prevRadius = ticksCoords[i]; } // Simple optimization // Batching the lines if color are the same for (var i = 0; i < splitAreas.length; i++) { this.group.add(graphic.mergePath(splitAreas[i], { style: zrUtil.defaults({ fill: areaColors[i % areaColors.length] }, areaStyleModel.getAreaStyle()), silent: true })); } } }); /** * @inner */ function layoutAxis(polar, radiusAxisModel, axisAngle) { return { position: [polar.cx, polar.cy], rotation: axisAngle / 180 * Math.PI, labelDirection: -1, tickDirection: -1, nameDirection: 1, labelRotation: radiusAxisModel.getModel('axisLabel').get('rotate'), // Over splitLine and splitArea z2: 1 }; } /***/ }, /* 297 */ /***/ function(module, exports, __webpack_require__) { __webpack_require__(298); __webpack_require__(165); __webpack_require__(299); __webpack_require__(178); var echarts = __webpack_require__(1); var zrUtil = __webpack_require__(4); function makeAction(method, actionInfo) { actionInfo.update = 'updateView'; echarts.registerAction(actionInfo, function (payload, ecModel) { var selected = {}; ecModel.eachComponent( { mainType: 'geo', query: payload}, function (geoModel) { geoModel[method](payload.name); var geo = geoModel.coordinateSystem; zrUtil.each(geo.regions, function (region) { selected[region.name] = geoModel.isSelected(region.name) || false; }); } ); return { selected: selected, name: payload.name } }); } makeAction('toggleSelected', { type: 'geoToggleSelect', event: 'geoselectchanged' }); makeAction('select', { type: 'geoSelect', event: 'geoselected' }); makeAction('unSelect', { type: 'geoUnSelect', event: 'geounselected' }); /***/ }, /* 298 */ /***/ function(module, exports, __webpack_require__) { 'use strict'; var modelUtil = __webpack_require__(5); var ComponentModel = __webpack_require__(19); var Model = __webpack_require__(12); var zrUtil = __webpack_require__(4); var selectableMixin = __webpack_require__(142); var geoCreator = __webpack_require__(165); var GeoModel = ComponentModel.extend({ type: 'geo', /** * @type {module:echarts/coord/geo/Geo} */ coordinateSystem: null, layoutMode: 'box', init: function (option) { ComponentModel.prototype.init.apply(this, arguments); // Default label emphasis `position` and `show` modelUtil.defaultEmphasis( option.label, ['position', 'show', 'textStyle', 'distance', 'formatter'] ); }, optionUpdated: function () { var option = this.option; var self = this; option.regions = geoCreator.getFilledRegions(option.regions, option.map); this._optionModelMap = zrUtil.reduce(option.regions || [], function (obj, regionOpt) { if (regionOpt.name) { obj[regionOpt.name] = new Model(regionOpt, self); } return obj; }, {}); this.updateSelectedMap(option.regions); }, defaultOption: { zlevel: 0, z: 0, show: true, left: 'center', top: 'center', // width:, // height:, // right // bottom // Aspect is width / height. Inited to be geoJson bbox aspect // This parameter is used for scale this aspect aspectScale: 0.75, ///// Layout with center and size // If you wan't to put map in a fixed size box with right aspect ratio // This two properties may more conveninet // layoutCenter: [50%, 50%] // layoutSize: 100 silent: false, // Map type map: '', // Default on center of map center: null, zoom: 1, scaleLimit: null, // selectedMode: false label: { normal: { show: false, textStyle: { color: '#000' } }, emphasis: { show: true, textStyle: { color: 'rgb(100,0,0)' } } }, itemStyle: { normal: { // color: 各异, borderWidth: 0.5, borderColor: '#444', color: '#eee' }, emphasis: { // 也是选中样式 color: 'rgba(255,215,0,0.8)' } }, regions: [] }, /** * Get model of region * @param {string} name * @return {module:echarts/model/Model} */ getRegionModel: function (name) { return this._optionModelMap[name]; }, /** * Format label * @param {string} name Region name * @param {string} [status='normal'] 'normal' or 'emphasis' * @return {string} */ getFormattedLabel: function (name, status) { var formatter = this.get('label.' + status + '.formatter'); var params = { name: name }; if (typeof formatter === 'function') { params.status = status; return formatter(params); } else if (typeof formatter === 'string') { var serName = params.seriesName; return formatter.replace('{a}', serName != null ? serName : ''); } }, setZoom: function (zoom) { this.option.zoom = zoom; }, setCenter: function (center) { this.option.center = center; } }); zrUtil.mixin(GeoModel, selectableMixin); module.exports = GeoModel; /***/ }, /* 299 */ /***/ function(module, exports, __webpack_require__) { 'use strict'; var MapDraw = __webpack_require__(175); module.exports = __webpack_require__(1).extendComponentView({ type: 'geo', init: function (ecModel, api) { var mapDraw = new MapDraw(api, true); this._mapDraw = mapDraw; this.group.add(mapDraw.group); }, render: function (geoModel, ecModel, api, payload) { // Not render if it is an toggleSelect action from self if (payload && payload.type === 'geoToggleSelect' && payload.from === this.uid ) { return; } var mapDraw = this._mapDraw; if (geoModel.get('show')) { mapDraw.draw(geoModel, ecModel, api, this, payload); } else { this._mapDraw.group.removeAll(); } this.group.silent = geoModel.get('silent'); }, dispose: function () { this._mapDraw && this._mapDraw.remove(); } }); /***/ }, /* 300 */ /***/ function(module, exports, __webpack_require__) { __webpack_require__(301); __webpack_require__(304); __webpack_require__(305); var echarts = __webpack_require__(1); echarts.extendComponentView({ type: 'single' }); /***/ }, /* 301 */ /***/ function(module, exports, __webpack_require__) { /** * Single coordinate system creator. */ var Single = __webpack_require__(302); /** * Create single coordinate system and inject it into seriesModel. * * @param {module:echarts/model/Global} ecModel * @param {module:echarts/ExtensionAPI} api * @return {Array.} */ function create(ecModel, api) { var singles = []; ecModel.eachComponent('singleAxis', function(axisModel, idx) { var single = new Single(axisModel, ecModel, api); single.name = 'single_' + idx; single.resize(axisModel, api); axisModel.coordinateSystem = single; singles.push(single); }); ecModel.eachSeries(function (seriesModel) { if (seriesModel.get('coordinateSystem') === 'singleAxis') { var singleAxisModel = ecModel.queryComponents({ mainType: 'singleAxis', index: seriesModel.get('singleAxisIndex'), id: seriesModel.get('singleAxisId') })[0]; seriesModel.coordinateSystem = singleAxisModel.coordinateSystem; } }); return singles; } __webpack_require__(26).register('single', { create: create, dimensions: Single.prototype.dimensions }); /***/ }, /* 302 */ /***/ function(module, exports, __webpack_require__) { /** * Single coordinates system. */ var SingleAxis = __webpack_require__(303); var axisHelper = __webpack_require__(115); var layout = __webpack_require__(21); /** * Create a single coordinates system. * * @param {module:echarts/coord/single/AxisModel} axisModel * @param {module:echarts/model/Global} ecModel * @param {module:echarts/ExtensionAPI} api */ function Single(axisModel, ecModel, api) { /** * @type {string} * @readOnly */ this.dimension = 'x'; /** * Add it just for draw tooltip. * * @type {Array.} * @readOnly */ this.dimensions = ['x']; /** * @private * @type {module:echarts/coord/single/SingleAxis}. */ this._axis = null; /** * @private * @type {module:zrender/core/BoundingRect} */ this._rect; this._init(axisModel, ecModel, api); /** * @type {module:echarts/coord/single/AxisModel} */ this._model = axisModel; } Single.prototype = { type: 'singleAxis', constructor: Single, /** * Initialize single coordinate system. * * @param {module:echarts/coord/single/AxisModel} axisModel * @param {module:echarts/model/Global} ecModel * @param {module:echarts/ExtensionAPI} api * @private */ _init: function (axisModel, ecModel, api) { var dim = this.dimension; var axis = new SingleAxis( dim, axisHelper.createScaleByModel(axisModel), [0, 0], axisModel.get('type'), axisModel.get('position') ); var isCategory = axis.type === 'category'; axis.onBand = isCategory && axisModel.get('boundaryGap'); axis.inverse = axisModel.get('inverse'); axis.orient = axisModel.get('orient'); axisModel.axis = axis; axis.model = axisModel; this._axis = axis; }, /** * Update axis scale after data processed * @param {module:echarts/model/Global} ecModel * @param {module:echarts/ExtensionAPI} api */ update: function (ecModel, api) { this._updateAxisFromSeries(ecModel); }, /** * Update the axis extent from series. * * @param {module:echarts/model/Global} ecModel * @private */ _updateAxisFromSeries: function (ecModel) { ecModel.eachSeries(function (seriesModel) { var data = seriesModel.getData(); var dim = this.dimension; this._axis.scale.unionExtent( data.getDataExtent(seriesModel.coordDimToDataDim(dim)) ); axisHelper.niceScaleExtent(this._axis, this._axis.model); }, this); }, /** * Resize the single coordinate system. * * @param {module:echarts/coord/single/AxisModel} axisModel * @param {module:echarts/ExtensionAPI} api */ resize: function (axisModel, api) { this._rect = layout.getLayoutRect( { left: axisModel.get('left'), top: axisModel.get('top'), right: axisModel.get('right'), bottom: axisModel.get('bottom'), width: axisModel.get('width'), height: axisModel.get('height') }, { width: api.getWidth(), height: api.getHeight() } ); this._adjustAxis(); }, /** * @return {module:zrender/core/BoundingRect} */ getRect: function () { return this._rect; }, /** * @private */ _adjustAxis: function () { var rect = this._rect; var axis = this._axis; var isHorizontal = axis.isHorizontal(); var extent = isHorizontal ? [0, rect.width] : [0, rect.height]; var idx = axis.reverse ? 1 : 0; axis.setExtent(extent[idx], extent[1 - idx]); this._updateAxisTransform(axis, isHorizontal ? rect.x : rect.y); }, /** * @param {module:echarts/coord/single/SingleAxis} axis * @param {number} coordBase */ _updateAxisTransform: function (axis, coordBase) { var axisExtent = axis.getExtent(); var extentSum = axisExtent[0] + axisExtent[1]; var isHorizontal = axis.isHorizontal(); axis.toGlobalCoord = isHorizontal ? function (coord) { return coord + coordBase; } : function (coord) { return extentSum - coord + coordBase; }; axis.toLocalCoord = isHorizontal ? function (coord) { return coord - coordBase; } : function (coord) { return extentSum - coord + coordBase; }; }, /** * Get axis. * * @return {module:echarts/coord/single/SingleAxis} */ getAxis: function () { return this._axis; }, /** * Get axis, add it just for draw tooltip. * * @return {[type]} [description] */ getBaseAxis: function () { return this._axis; }, /** * If contain point. * * @param {Array.} point * @return {boolean} */ containPoint: function (point) { var rect = this.getRect(); var axis = this.getAxis(); var orient = axis.orient; if (orient === 'horizontal') { return axis.contain(axis.toLocalCoord(point[0])) && (point[1] >= rect.y && point[1] <= (rect.y + rect.height)); } else { return axis.contain(axis.toLocalCoord(point[1])) && (point[0] >= rect.y && point[0] <= (rect.y + rect.height)); } }, /** * @param {Array.} point * @return {Array.} */ pointToData: function (point) { var axis = this.getAxis(); return [axis.coordToData(axis.toLocalCoord( point[axis.orient === 'horizontal' ? 0 : 1] ))]; }, /** * Convert the series data to concrete point. * * @param {number|Array.} val * @return {Array.} */ dataToPoint: function (val) { var axis = this.getAxis(); var rect = this.getRect(); var pt = []; var idx = axis.orient === 'horizontal' ? 0 : 1; pt[idx] = axis.toGlobalCoord(axis.dataToCoord(+val)); pt[1 - idx] = idx === 0 ? (rect.y + rect.height / 2) : (rect.x + rect.width / 2); return pt; } }; module.exports = Single; /***/ }, /* 303 */ /***/ function(module, exports, __webpack_require__) { var zrUtil = __webpack_require__(4); var Axis = __webpack_require__(124); var axisHelper = __webpack_require__(115); /** * @constructor module:echarts/coord/single/SingleAxis * @extends {module:echarts/coord/Axis} * @param {string} dim * @param {*} scale * @param {Array.} coordExtent * @param {string} axisType * @param {string} position */ var SingleAxis = function (dim, scale, coordExtent, axisType, position) { Axis.call(this, dim, scale, coordExtent); /** * Axis type * - 'category' * - 'value' * - 'time' * - 'log' * @type {string} */ this.type = axisType || 'value'; /** * Axis position * - 'top' * - 'bottom' * - 'left' * - 'right' * @type {string} */ this.position = position || 'bottom'; /** * Axis orient * - 'horizontal' * - 'vertical' * @type {[type]} */ this.orient = null; /** * @type {number} */ this._labelInterval = null; }; SingleAxis.prototype = { constructor: SingleAxis, /** * Axis model * @type {module:echarts/coord/single/AxisModel} */ model: null, /** * Judge the orient of the axis. * @return {boolean} */ isHorizontal: function () { var position = this.position; return position === 'top' || position === 'bottom'; }, /** * Get interval of the axis label. * @return {number} */ getLabelInterval: function () { var labelInterval = this._labelInterval; if (!labelInterval) { var axisModel = this.model; var labelModel = axisModel.getModel('axisLabel'); var interval = labelModel.get('interval'); if (!(this.type === 'category' && interval === 'auto')) { labelInterval = this._labelInterval = interval === 'auto' ? 0 : interval; return labelInterval; } labelInterval = this._labelInterval = axisHelper.getAxisLabelInterval( zrUtil.map(this.scale.getTicks(), this.dataToCoord, this), axisModel.getFormattedLabels(), labelModel.getModel('textStyle').getFont(), this.isHorizontal() ); } return labelInterval; }, /** * Convert the local coord(processed by dataToCoord()) * to global coord(concrete pixel coord). * designated by module:echarts/coord/single/Single. * @type {Function} */ toGlobalCoord: null, /** * Convert the global coord to local coord. * designated by module:echarts/coord/single/Single. * @type {Function} */ toLocalCoord: null }; zrUtil.inherits(SingleAxis, Axis); module.exports = SingleAxis; /***/ }, /* 304 */ /***/ function(module, exports, __webpack_require__) { var AxisBuilder = __webpack_require__(134); var zrUtil = __webpack_require__(4); var graphic = __webpack_require__(43); var getInterval = AxisBuilder.getInterval; var ifIgnoreOnTick = AxisBuilder.ifIgnoreOnTick; var axisBuilderAttrs = [ 'axisLine', 'axisLabel', 'axisTick', 'axisName' ]; var selfBuilderAttr = 'splitLine'; var AxisView = __webpack_require__(1).extendComponentView({ type: 'singleAxis', render: function (axisModel, ecModel) { var group = this.group; group.removeAll(); var layout = axisLayout(axisModel); var axisBuilder = new AxisBuilder(axisModel, layout); zrUtil.each(axisBuilderAttrs, axisBuilder.add, axisBuilder); group.add(axisBuilder.getGroup()); if (axisModel.get(selfBuilderAttr + '.show')) { this['_' + selfBuilderAttr](axisModel, layout.labelInterval); } }, _splitLine: function(axisModel, labelInterval) { var axis = axisModel.axis; var splitLineModel = axisModel.getModel('splitLine'); var lineStyleModel = splitLineModel.getModel('lineStyle'); var lineWidth = lineStyleModel.get('width'); var lineColors = lineStyleModel.get('color'); var lineInterval = getInterval(splitLineModel, labelInterval); lineColors = lineColors instanceof Array ? lineColors : [lineColors]; var gridRect = axisModel.coordinateSystem.getRect(); var isHorizontal = axis.isHorizontal(); var splitLines = []; var lineCount = 0; var ticksCoords = axis.getTicksCoords(); var p1 = []; var p2 = []; for (var i = 0; i < ticksCoords.length; ++i) { if (ifIgnoreOnTick(axis, i, lineInterval)) { continue; } var tickCoord = axis.toGlobalCoord(ticksCoords[i]); if (isHorizontal) { p1[0] = tickCoord; p1[1] = gridRect.y; p2[0] = tickCoord; p2[1] = gridRect.y + gridRect.height; } else { p1[0] = gridRect.x; p1[1] = tickCoord; p2[0] = gridRect.x + gridRect.width; p2[1] = tickCoord; } var colorIndex = (lineCount++) % lineColors.length; splitLines[colorIndex] = splitLines[colorIndex] || []; splitLines[colorIndex].push(new graphic.Line( graphic.subPixelOptimizeLine({ shape: { x1: p1[0], y1: p1[1], x2: p2[0], y2: p2[1] }, style: { lineWidth: lineWidth }, silent: true }))); } for (var i = 0; i < splitLines.length; ++i) { this.group.add(graphic.mergePath(splitLines[i], { style: { stroke: lineColors[i % lineColors.length], lineDash: lineStyleModel.getLineDash(lineWidth), lineWidth: lineWidth }, silent: true })); } } }); function axisLayout(axisModel) { var single = axisModel.coordinateSystem; var axis = axisModel.axis; var layout = {}; var axisPosition = axis.position; var orient = axis.orient; var rect = single.getRect(); var rectBound = [rect.x, rect.x + rect.width, rect.y, rect.y + rect.height]; var positionMap = { horizontal: {top: rectBound[2], bottom: rectBound[3]}, vertical: {left: rectBound[0], right: rectBound[1]} }; layout.position = [ orient === 'vertical' ? positionMap.vertical[axisPosition] : rectBound[0], orient === 'horizontal' ? positionMap.horizontal[axisPosition] : rectBound[3] ]; var r = {horizontal: 0, vertical: 1}; layout.rotation = Math.PI / 2 * r[orient]; var directionMap = {top: -1, bottom: 1, right: 1, left: -1}; layout.labelDirection = layout.tickDirection = layout.nameDirection = directionMap[axisPosition]; if (axisModel.getModel('axisTick').get('inside')) { layout.tickDirection = -layout.tickDirection; } if (axisModel.getModel('axisLabel').get('inside')) { layout.labelDirection = -layout.labelDirection; } var labelRotation = axisModel.getModel('axisLabel').get('rotate'); layout.labelRotation = axisPosition === 'top' ? -labelRotation : labelRotation; layout.labelInterval = axis.getLabelInterval(); layout.z2 = 1; return layout; } module.exports = AxisView; /***/ }, /* 305 */ /***/ function(module, exports, __webpack_require__) { var ComponentModel = __webpack_require__(19); var axisModelCreator = __webpack_require__(128); var zrUtil = __webpack_require__(4); var AxisModel = ComponentModel.extend({ type: 'singleAxis', layoutMode: 'box', /** * @type {module:echarts/coord/single/SingleAxis} */ axis: null, /** * @type {module:echarts/coord/single/Single} */ coordinateSystem: null }); var defaultOption = { left: '5%', top: '5%', right: '5%', bottom: '5%', type: 'value', position: 'bottom', orient: 'horizontal', axisLine: { show: true, lineStyle: { width: 2, type: 'solid' } }, axisTick: { show: true, length: 6, lineStyle: { width: 2 } }, axisLabel: { show: true, interval: 'auto' }, splitLine: { show: true, lineStyle: { type: 'dashed', opacity: 0.2 } } }; function getAxisType(axisName, option) { return option.type || (option.data ? 'category' : 'value'); } zrUtil.merge(AxisModel.prototype, __webpack_require__(130)); axisModelCreator('single', AxisModel, getAxisType, defaultOption); module.exports = AxisModel; /***/ }, /* 306 */ /***/ function(module, exports, __webpack_require__) { /** * Brush component entry */ __webpack_require__(1).registerPreprocessor( __webpack_require__(307) ); __webpack_require__(308); __webpack_require__(312); __webpack_require__(313); __webpack_require__(314); __webpack_require__(315); /***/ }, /* 307 */ /***/ function(module, exports, __webpack_require__) { /** * @file brush preprocessor */ var zrUtil = __webpack_require__(4); var DEFAULT_TOOLBOX_BTNS = ['rect', 'polygon', 'keep', 'clear']; module.exports = function (option, isNew) { var brushComponents = option && option.brush; if (!zrUtil.isArray(brushComponents)) { brushComponents = brushComponents ? [brushComponents] : []; } if (!brushComponents.length) { return; } var brushComponentSpecifiedBtns = []; zrUtil.each(brushComponents, function (brushOpt) { var tbs = brushOpt.hasOwnProperty('toolbox') ? brushOpt.toolbox : []; if (tbs instanceof Array) { brushComponentSpecifiedBtns = brushComponentSpecifiedBtns.concat(tbs); } }); var toolbox = option && option.toolbox; if (zrUtil.isArray(toolbox)) { toolbox = toolbox[0]; } if (!toolbox) { toolbox = {feature: {}}; option.toolbox = [toolbox]; } var toolboxFeature = (toolbox.feature || (toolbox.feature = {})); var toolboxBrush = toolboxFeature.brush || (toolboxFeature.brush = {}); var brushTypes = toolboxBrush.type || (toolboxBrush.type = []); brushTypes.push.apply(brushTypes, brushComponentSpecifiedBtns); removeDuplicate(brushTypes); if (isNew && !brushTypes.length) { brushTypes.push.apply(brushTypes, DEFAULT_TOOLBOX_BTNS); } }; function removeDuplicate(arr) { var map = {}; zrUtil.each(arr, function (val) { map[val] = 1; }); arr.length = 0; zrUtil.each(map, function (flag, val) { arr.push(val); }); } /***/ }, /* 308 */ /***/ function(module, exports, __webpack_require__) { /** * @file Brush visual coding. */ var echarts = __webpack_require__(1); var visualSolution = __webpack_require__(309); var zrUtil = __webpack_require__(4); var BoundingRect = __webpack_require__(9); var selector = __webpack_require__(310); var throttle = __webpack_require__(81); var brushHelper = __webpack_require__(311); var STATE_LIST = ['inBrush', 'outOfBrush']; var DISPATCH_METHOD = '__ecBrushSelect'; var DISPATCH_FLAG = '__ecInBrushSelectEvent'; var PRIORITY_BRUSH = echarts.PRIORITY.VISUAL.BRUSH; /** * Layout for visual, the priority higher than other layout, and before brush visual. */ echarts.registerLayout(PRIORITY_BRUSH, function (ecModel, api, payload) { ecModel.eachComponent({mainType: 'brush'}, function (brushModel) { payload && payload.type === 'takeGlobalCursor' && brushModel.setBrushOption( payload.key === 'brush' ? payload.brushOption : {brushType: false} ); brushModel.coordInfoList = brushHelper.makeCoordInfoList(brushModel.option, ecModel); brushHelper.parseInputRanges(brushModel, ecModel); }); }); /** * Register the visual encoding if this modules required. */ echarts.registerVisual(PRIORITY_BRUSH, function (ecModel, api, payload) { var brushSelected = []; var throttleType; var throttleDelay; ecModel.eachComponent({mainType: 'brush'}, function (brushModel, brushIndex) { var thisBrushSelected = { brushId: brushModel.id, brushIndex: brushIndex, brushName: brushModel.name, areas: zrUtil.clone(brushModel.areas), selected: [] }; // Every brush component exists in event params, convenient // for user to find by index. brushSelected.push(thisBrushSelected); var brushOption = brushModel.option; var brushLink = brushOption.brushLink; var linkedSeriesMap = []; var selectedDataIndexForLink = []; var rangeInfoBySeries = []; var hasBrushExists = 0; if (!brushIndex) { // Only the first throttle setting works. throttleType = brushOption.throttleType; throttleDelay = brushOption.throttleDelay; } // Add boundingRect and selectors to range. var areas = zrUtil.map(brushModel.areas, function (area) { return bindSelector( zrUtil.defaults( {boundingRect: boundingRectBuilders[area.brushType](area)}, area ) ); }); var visualMappings = visualSolution.createVisualMappings( brushModel.option, STATE_LIST, function (mappingOption) { mappingOption.mappingMethod = 'fixed'; } ); zrUtil.isArray(brushLink) && zrUtil.each(brushLink, function (seriesIndex) { linkedSeriesMap[seriesIndex] = 1; }); function linkOthers(seriesIndex) { return brushLink === 'all' || linkedSeriesMap[seriesIndex]; } // If no supported brush or no brush on the series, // all visuals should be in original state. function brushed(rangeInfoList) { return !!rangeInfoList.length; } /** * Logic for each series: (If the logic has to be modified one day, do it carefully!) * * ( brushed ┬ && ┬hasBrushExist ┬ && linkOthers ) => StepA: ┬record, ┬ StepB: ┬visualByRecord. * !brushed┘ ├hasBrushExist ┤ └nothing,┘ ├visualByRecord. * └!hasBrushExist┘ └nothing. * ( !brushed && ┬hasBrushExist ┬ && linkOthers ) => StepA: nothing, StepB: ┬visualByRecord. * └!hasBrushExist┘ └nothing. * ( brushed ┬ && !linkOthers ) => StepA: nothing, StepB: ┬visualByCheck. * !brushed┘ └nothing. * ( !brushed && !linkOthers ) => StepA: nothing, StepB: nothing. */ // Step A ecModel.eachSeries(function (seriesModel, seriesIndex) { var rangeInfoList = rangeInfoBySeries[seriesIndex] = []; seriesModel.subType === 'parallel' ? stepAParallel(seriesModel, seriesIndex, rangeInfoList) : stepAOthers(seriesModel, seriesIndex, rangeInfoList); }); function stepAParallel(seriesModel, seriesIndex) { var coordSys = seriesModel.coordinateSystem; hasBrushExists |= coordSys.hasAxisbrushed(); linkOthers(seriesIndex) && coordSys.eachActiveState( seriesModel.getData(), function (activeState, dataIndex) { activeState === 'active' && (selectedDataIndexForLink[dataIndex] = 1); } ); } function stepAOthers(seriesModel, seriesIndex, rangeInfoList) { var selectorsByBrushType = getSelectorsByBrushType(seriesModel); if (!selectorsByBrushType || brushModelNotControll(brushModel, seriesIndex)) { return; } zrUtil.each(areas, function (area) { selectorsByBrushType[area.brushType] && brushHelper.controlSeries(area, brushModel, seriesModel) && rangeInfoList.push(area); hasBrushExists |= brushed(rangeInfoList); }); if (linkOthers(seriesIndex) && brushed(rangeInfoList)) { var data = seriesModel.getData(); data.each(function (dataIndex) { if (checkInRange(selectorsByBrushType, rangeInfoList, data, dataIndex)) { selectedDataIndexForLink[dataIndex] = 1; } }); } } // Step B ecModel.eachSeries(function (seriesModel, seriesIndex) { var seriesBrushSelected = { seriesId: seriesModel.id, seriesIndex: seriesIndex, seriesName: seriesModel.name, dataIndex: [] }; // Every series exists in event params, convenient // for user to find series by seriesIndex. thisBrushSelected.selected.push(seriesBrushSelected); var selectorsByBrushType = getSelectorsByBrushType(seriesModel); var rangeInfoList = rangeInfoBySeries[seriesIndex]; var data = seriesModel.getData(); var getValueState = linkOthers(seriesIndex) ? function (dataIndex) { return selectedDataIndexForLink[dataIndex] ? (seriesBrushSelected.dataIndex.push(data.getRawIndex(dataIndex)), 'inBrush') : 'outOfBrush'; } : function (dataIndex) { return checkInRange(selectorsByBrushType, rangeInfoList, data, dataIndex) ? (seriesBrushSelected.dataIndex.push(data.getRawIndex(dataIndex)), 'inBrush') : 'outOfBrush'; }; // If no supported brush or no brush, all visuals are in original state. (linkOthers(seriesIndex) ? hasBrushExists : brushed(rangeInfoList)) && visualSolution.applyVisual( STATE_LIST, visualMappings, data, getValueState ); }); }); dispatchAction(api, throttleType, throttleDelay, brushSelected, payload); }); function dispatchAction(api, throttleType, throttleDelay, brushSelected, payload) { // This event will not be triggered when `setOpion`, otherwise dead lock may // triggered when do `setOption` in event listener, which we do not find // satisfactory way to solve yet. Some considered resolutions: // (a) Diff with prevoius selected data ant only trigger event when changed. // But store previous data and diff precisely (i.e., not only by dataIndex, but // also detect value changes in selected data) might bring complexity or fragility. // (b) Use spectial param like `silent` to suppress event triggering. // But such kind of volatile param may be weird in `setOption`. if (!payload) { return; } var zr = api.getZr(); if (zr[DISPATCH_FLAG]) { return; } if (!zr[DISPATCH_METHOD]) { zr[DISPATCH_METHOD] = doDispatch; } var fn = throttle.createOrUpdate(zr, DISPATCH_METHOD, throttleDelay, throttleType); fn(api, brushSelected); } function doDispatch(api, brushSelected) { if (!api.isDisposed()) { var zr = api.getZr(); zr[DISPATCH_FLAG] = true; api.dispatchAction({ type: 'brushSelect', batch: brushSelected }); zr[DISPATCH_FLAG] = false; } } function checkInRange(selectorsByBrushType, rangeInfoList, data, dataIndex) { var itemLayout = data.getItemLayout(dataIndex); for (var i = 0, len = rangeInfoList.length; i < len; i++) { var area = rangeInfoList[i]; if (selectorsByBrushType[area.brushType]( itemLayout, area.selectors, area )) { return true; } } } function getSelectorsByBrushType(seriesModel) { var brushSelector = seriesModel.brushSelector; if (zrUtil.isString(brushSelector)) { var sels = []; zrUtil.each(selector, function (selectorsByElementType, brushType) { sels[brushType] = selectorsByElementType[brushSelector]; }); return sels; } else if (zrUtil.isFunction(brushSelector)) { var bSelector = {}; zrUtil.each(selector, function (sel, brushType) { bSelector[brushType] = brushSelector; }); return bSelector; } return brushSelector; } function brushModelNotControll(brushModel, seriesIndex) { var seriesIndices = brushModel.option.seriesIndex; return seriesIndices != null && seriesIndices !== 'all' && ( zrUtil.isArray(seriesIndices) ? zrUtil.indexOf(seriesIndices, seriesIndex) < 0 : seriesIndex !== seriesIndices ); } function bindSelector(area) { var selectors = area.selectors = {}; zrUtil.each(selector[area.brushType], function (selFn, elType) { // Do not use function binding or curry for performance. selectors[elType] = function (itemLayout) { return selFn(itemLayout, selectors, area); }; }); return area; } var boundingRectBuilders = { lineX: zrUtil.noop, lineY: zrUtil.noop, rect: function (area) { return getBoundingRectFromMinMax(area.range); }, polygon: function (area) { var minMax; var range = area.range; for (var i = 0, len = range.length; i < len; i++) { minMax = minMax || [[Infinity, -Infinity], [Infinity, -Infinity]]; var rg = range[i]; rg[0] < minMax[0][0] && (minMax[0][0] = rg[0]); rg[0] > minMax[0][1] && (minMax[0][1] = rg[0]); rg[1] < minMax[1][0] && (minMax[1][0] = rg[1]); rg[1] > minMax[1][1] && (minMax[1][1] = rg[1]); } return minMax && getBoundingRectFromMinMax(minMax); } }; function getBoundingRectFromMinMax(minMax) { return new BoundingRect( minMax[0][0], minMax[1][0], minMax[0][1] - minMax[0][0], minMax[1][1] - minMax[1][0] ); } /***/ }, /* 309 */ /***/ function(module, exports, __webpack_require__) { /** * @file Visual solution, for consistent option specification. */ var zrUtil = __webpack_require__(4); var VisualMapping = __webpack_require__(194); var each = zrUtil.each; function hasKeys(obj) { if (obj) { for (var name in obj){ if (obj.hasOwnProperty(name)) { return true; } } } } var visualSolution = { /** * @param {Object} option * @param {Array.} stateList * @param {Function} [supplementVisualOption] * @return {Object} visualMappings > */ createVisualMappings: function (option, stateList, supplementVisualOption) { var visualMappings = {}; each(stateList, function (state) { var mappings = visualMappings[state] = createMappings(); each(option[state], function (visualData, visualType) { if (!VisualMapping.isValidType(visualType)) { return; } var mappingOption = { type: visualType, visual: visualData }; supplementVisualOption && supplementVisualOption(mappingOption, state); mappings[visualType] = new VisualMapping(mappingOption); // Prepare a alpha for opacity, for some case that opacity // is not supported, such as rendering using gradient color. if (visualType === 'opacity') { mappingOption = zrUtil.clone(mappingOption); mappingOption.type = 'colorAlpha'; mappings.__hidden.__alphaForOpacity = new VisualMapping(mappingOption); } }); }); return visualMappings; function createMappings() { var Creater = function () {}; // Make sure hidden fields will not be visited by // object iteration (with hasOwnProperty checking). Creater.prototype.__hidden = Creater.prototype; var obj = new Creater(); return obj; } }, /** * @param {Object} thisOption * @param {Object} newOption * @param {Array.} keys */ replaceVisualOption: function (thisOption, newOption, keys) { // Visual attributes merge is not supported, otherwise it // brings overcomplicated merge logic. See #2853. So if // newOption has anyone of these keys, all of these keys // will be reset. Otherwise, all keys remain. var has; zrUtil.each(keys, function (key) { if (newOption.hasOwnProperty(key) && hasKeys(newOption[key])) { has = true; } }); has && zrUtil.each(keys, function (key) { if (newOption.hasOwnProperty(key) && hasKeys(newOption[key])) { thisOption[key] = zrUtil.clone(newOption[key]); } else { delete thisOption[key]; } }); }, /** * @param {Array.} stateList * @param {Object} visualMappings > * @param {module:echarts/data/List} list * @param {Function} getValueState param: valueOrIndex, return: state. * @param {object} [scope] Scope for getValueState * @param {string} [dimension] Concrete dimension, if used. */ applyVisual: function (stateList, visualMappings, data, getValueState, scope, dimension) { var visualTypesMap = {}; zrUtil.each(stateList, function (state) { var visualTypes = VisualMapping.prepareVisualTypes(visualMappings[state]); visualTypesMap[state] = visualTypes; }); var dataIndex; function getVisual(key) { return data.getItemVisual(dataIndex, key); } function setVisual(key, value) { data.setItemVisual(dataIndex, key, value); } if (dimension == null) { data.each(eachItem, true); } else { data.each([dimension], eachItem, true); } function eachItem(valueOrIndex, index) { dataIndex = dimension == null ? valueOrIndex : index; var valueState = getValueState.call(scope, valueOrIndex); var mappings = visualMappings[valueState]; var visualTypes = visualTypesMap[valueState]; for (var i = 0, len = visualTypes.length; i < len; i++) { var type = visualTypes[i]; mappings[type] && mappings[type].applyVisual( valueOrIndex, getVisual, setVisual ); } } } }; module.exports = visualSolution; /***/ }, /* 310 */ /***/ function(module, exports, __webpack_require__) { var polygonContain = __webpack_require__(169).contain; var BoundingRect = __webpack_require__(9); // Key of the first level is brushType: `line`, `rect`, `polygon`. // Key of the second level is chart element type: `point`, `rect`. // See moudule:echarts/component/helper/BrushController // function param: // {Object} itemLayout fetch from data.getItemLayout(dataIndex) // {Object} selectors {point: selector, rect: selector, ...} // {Object} area {range: [[], [], ..], boudingRect} // function return: // {boolean} Whether in the given brush. var selector = { lineX: getLineSelectors(0), lineY: getLineSelectors(1), rect: { point: function (itemLayout, selectors, area) { return area.boundingRect.contain(itemLayout[0], itemLayout[1]); }, rect: function (itemLayout, selectors, area) { return area.boundingRect.intersect(itemLayout); } }, polygon: { point: function (itemLayout, selectors, area) { return area.boundingRect.contain(itemLayout[0], itemLayout[1]) && polygonContain(area.range, itemLayout[0], itemLayout[1]); }, rect: function (itemLayout, selectors, area) { // FIXME // 随意写的,没有考察过效率。 var points = area.range; if (points.length <= 1) { return false; } var x = itemLayout.x; var y = itemLayout.y; var width = itemLayout.width; var height = itemLayout.height; var p = points[0]; if (polygonContain(points, x, y) || polygonContain(points, x + width, y) || polygonContain(points, x, y + height) || polygonContain(points, x + width, y + height) || BoundingRect.create(itemLayout).contain(p[0], p[1]) || lineIntersectPolygon(x, y, x + width, y, points) || lineIntersectPolygon(x, y, x, y + height, points) || lineIntersectPolygon(x + width, y, x + width, y + height, points) || lineIntersectPolygon(x, y + height, x + width, y + height, points) ) { return true; } } } }; function getLineSelectors(xyIndex) { var xy = ['x', 'y']; var wh = ['width', 'height']; return { point: function (itemLayout, selectors, area) { var range = area.range; var p = itemLayout[xyIndex]; return inLineRange(p, range); }, rect: function (itemLayout, selectors, area) { var range = area.range; return inLineRange(itemLayout[xy[xyIndex]], range) || inLineRange(itemLayout[xy[xyIndex]] + itemLayout[wh[xyIndex]], range); } }; } function inLineRange(p, range) { return range[0] <= p && p <= range[1]; } // FIXME // 随意写的,没考察过效率。 function lineIntersectPolygon(lx, ly, l2x, l2y, points) { for (var i = 0, p2 = points[points.length - 1]; i < points.length; i++) { var p = points[i]; if (lineIntersect(lx, ly, l2x, l2y, p[0], p[1], p2[0], p2[1])) { return true; } p2 = p; } } // Code from with some fix. // See function lineIntersect(a1x, a1y, a2x, a2y, b1x, b1y, b2x, b2y) { var delta = determinant(a2x - a1x, b1x - b2x, a2y - a1y, b1y - b2y); if (nearZero(delta)) { // parallel return false; } var namenda = determinant(b1x - a1x, b1x - b2x, b1y - a1y, b1y - b2y) / delta; if (namenda < 0 || namenda > 1) { return false; } var miu = determinant(a2x - a1x, b1x - a1x, a2y - a1y, b1y - a1y) / delta; if (miu < 0 || miu > 1) { return false; } return true; } function nearZero(val) { return val <= (1e-6) && val >= -(1e-6); } function determinant(v1, v2, v3, v4) { return v1 * v4 - v2 * v3; } module.exports = selector; /***/ }, /* 311 */ /***/ function(module, exports, __webpack_require__) { var zrUtil = __webpack_require__(4); var graphic = __webpack_require__(43); var each = zrUtil.each; var helper = {}; var COMPONENT_NAMES = ['geo', 'xAxis', 'yAxis']; var PANEL_ID_SPLIT = '--'; var COORD_CONVERTS = ['dataToPoint', 'pointToData']; helper.parseOutputRanges = function (areas, coordInfoList, ecModel, rangesCoordInfo) { each(areas, function (area, index) { var panelId = area.panelId; if (panelId) { panelId = panelId.split(PANEL_ID_SPLIT); area[panelId[0] + 'Index'] = +panelId[1]; var coordInfo = findCoordInfo(area, coordInfoList); area.coordRange = coordConvert[area.brushType]( 1, coordInfo, area.range ); rangesCoordInfo && (rangesCoordInfo[index] = coordInfo); } }); }; helper.parseInputRanges = function (brushModel, ecModel) { each(brushModel.areas, function (area) { var coordInfo = findCoordInfo(area, brushModel.coordInfoList); if (true) { zrUtil.assert( !coordInfo || coordInfo === true || area.coordRange, 'coordRange must be specified when coord index specified.' ); zrUtil.assert( !coordInfo || coordInfo !== true || area.range, 'range must be specified.' ); } area.range = area.range || []; // convert coordRange to global range and set panelId. if (coordInfo && coordInfo !== true) { area.range = coordConvert[area.brushType]( 0, coordInfo, area.coordRange ); area.panelId = coordInfo.panelId; } }); }; helper.makePanelOpts = function (coordInfoList) { var panelOpts = []; each(coordInfoList, function (coordInfo) { var coordSys = coordInfo.coordSys; var rect; if (coordInfo.geoIndex >= 0) { rect = coordSys.getBoundingRect().clone(); // geo roam and zoom transform rect.applyTransform(graphic.getTransform(coordSys)); } else { // xAxis or yAxis // grid is not Transformable. rect = coordSys.grid.getRect().clone(); } panelOpts.push({panelId: coordInfo.panelId, rect: rect}); }); return panelOpts; }; /** * @param {Object} option {xAxisIndex, yAxisIndex, geoIndex} * @param {module:echarts/model/Global} ecModel * @return {Array.} coordInfoList */ helper.makeCoordInfoList = function (option, ecModel) { var coordInfoList = []; each(COMPONENT_NAMES, function (componentName) { var componentIndices = option[componentName + 'Index']; if (componentIndices == null || componentIndices === 'none') { return; } if (componentIndices !== 'all' && !zrUtil.isArray(componentIndices)) { componentIndices = [componentIndices]; } ecModel.eachComponent({mainType: componentName}, function (componentModel, index) { if (componentIndices !== 'all' && zrUtil.indexOf(componentIndices, index) < 0) { return; } var grid; var coordSys; (componentName === 'xAxis' || componentName === 'yAxis') ? (grid = componentModel.axis.grid) : (coordSys = componentModel.coordinateSystem); // geo var coordInfo; // Check duplicate and find cartesian when tranval to yAxis. for (var i = 0, len = coordInfoList.length; i < len; i++) { var cInfo = coordInfoList[i]; if (true) { zrUtil.assert( cInfo[componentName + 'Index'] != index, 'Coord should not be defined duplicately: ' + componentName + index ); } // CoordSys is always required for `rect brush` or `polygon brush`. // If both xAxisIndex and yAxisIndex specified, fetch cartesian by them. if (componentName === 'yAxis' && !cInfo.yAxis && cInfo.xAxis) { var aCoordSys = grid.getCartesian(cInfo.xAxisIndex, index); if (aCoordSys) { // The yAxis and xAxis are in the same cartesian. coordSys = aCoordSys; coordInfo = cInfo; break; } } } !coordInfo && coordInfoList.push(coordInfo = {}); coordInfo[componentName] = componentModel; coordInfo[componentName + 'Index'] = index; // If both xAxisIndex and yAxisIndex specified, panelId only use yAxisIndex, // which is enough to index panel. coordInfo.panelId = componentName + PANEL_ID_SPLIT + index; coordInfo.coordSys = coordSys // If only xAxisIndex or only yAxisIndex specified, find its first cartesian. || grid.getCartesian(coordInfo.xAxisIndex, coordInfo.yAxisIndex); coordInfo.coordSys ? (coordInfoList[componentName + 'Has'] = true) : coordInfoList.pop(); // If a coordInfo exists originally, existance of coordSys is ensured. }); }); return coordInfoList; }; helper.controlSeries = function (area, brushModel, seriesModel) { // Check whether area is bound in coord, and series do not belong to that coord. // If do not do this check, some brush (like lineX) will controll all axes. var coordInfo = findCoordInfo(area, brushModel.coordInfoList); return coordInfo === true || (coordInfo && coordInfo.coordSys === seriesModel.coordinateSystem); }; function formatMinMax(minMax) { minMax[0] > minMax[1] && minMax.reverse(); return minMax; } /** * If return Object, a coord found. * If reutrn true, global found. * Otherwise nothing found. * * @param {Object} area {Index} * @param {Array} coordInfoList * @return {Obejct|boolean} */ function findCoordInfo(area, coordInfoList) { var isGlobal = true; for (var j = 0; j < COMPONENT_NAMES.length; j++) { var indexAttr = COMPONENT_NAMES[j] + 'Index'; if (area[indexAttr] >= 0) { isGlobal = false; for (var i = 0; i < coordInfoList.length; i++) { if (coordInfoList[i][indexAttr] === area[indexAttr]) { return coordInfoList[i]; } } } } return isGlobal; } function axisConvert(axisName, to, coordInfo, coordRange) { var axis = coordInfo.coordSys.getAxis(axisName); if (true) { zrUtil.assert(axis, 'line brush is only available in cartesian (grid).'); } return formatMinMax(zrUtil.map([0, 1], function (i) { return to ? axis.coordToData(axis.toLocalCoord(coordRange[i])) : axis.toGlobalCoord(axis.dataToCoord(coordRange[i])); })); } var coordConvert = { lineX: zrUtil.curry(axisConvert, 'x'), lineY: zrUtil.curry(axisConvert, 'y'), rect: function (to, coordInfo, coordRange) { var coordSys = coordInfo.coordSys; var xminymin = coordSys[COORD_CONVERTS[to]]([coordRange[0][0], coordRange[1][0]]); var xmaxymax = coordSys[COORD_CONVERTS[to]]([coordRange[0][1], coordRange[1][1]]); return [ formatMinMax([xminymin[0], xmaxymax[0]]), formatMinMax([xminymin[1], xmaxymax[1]]) ]; }, polygon: function (to, coordInfo, coordRange) { var coordSys = coordInfo.coordSys; return zrUtil.map(coordRange, coordSys[COORD_CONVERTS[to]], coordSys); } }; module.exports = helper; /***/ }, /* 312 */ /***/ function(module, exports, __webpack_require__) { /** * @file Brush model */ var echarts = __webpack_require__(1); var zrUtil = __webpack_require__(4); var visualSolution = __webpack_require__(309); var Model = __webpack_require__(12); var DEFAULT_OUT_OF_BRUSH_COLOR = ['#ddd']; var BrushModel = echarts.extendComponentModel({ type: 'brush', dependencies: ['geo', 'grid', 'xAxis', 'yAxis', 'parallel', 'series'], /** * @protected */ defaultOption: { // inBrush: null, // outOfBrush: null, toolbox: null, // Default value see preprocessor. brushLink: null, // Series indices array, broadcast using dataIndex. // or 'all', which means all series. 'none' or null means no series. seriesIndex: 'all', // seriesIndex array, specify series controlled by this brush component. geoIndex: null, // xAxisIndex: null, yAxisIndex: null, brushType: 'rect', // Default brushType, see BrushController. brushMode: 'single', // Default brushMode, 'single' or 'multiple' transformable: true, // Default transformable. brushStyle: { // Default brushStyle borderWidth: 1, color: 'rgba(120,140,180,0.3)', borderColor: 'rgba(120,140,180,0.8)', width: null // do not use bursh width in line brush, but fetch from grid. }, throttleType: 'fixRate',// Throttle in brushSelected event. 'fixRate' or 'debounce'. // If null, no throttle. Valid only in the first brush component throttleDelay: 0, // Unit: ms, 0 means every event will be triggered. // FIXME // 试验效果 removeOnClick: true }, /** * @readOnly * @type {Array.} */ areas: [], /** * Current activated brush type. * If null, brush is inactived. * see module:echarts/component/helper/BrushController * @readOnly * @type {string} */ brushType: null, /** * Current brush opt. * see module:echarts/component/helper/BrushController * @readOnly * @type {Object} */ brushOption: {}, /** * @readOnly * @type {Array.} */ coordInfoList: [], optionUpdated: function (newOption, isInit) { var thisOption = this.option; !isInit && visualSolution.replaceVisualOption( thisOption, newOption, ['inBrush', 'outOfBrush'] ); thisOption.inBrush = thisOption.inBrush || {}; // Always give default visual, consider setOption at the second time. thisOption.outOfBrush = thisOption.outOfBrush || {color: DEFAULT_OUT_OF_BRUSH_COLOR}; }, /** * If ranges is null/undefined, range state remain. * * @param {Array.} [ranges] */ setAreas: function (areas) { if (true) { zrUtil.assert(zrUtil.isArray(areas)); zrUtil.each(areas, function (area) { zrUtil.assert(area.brushType, 'Illegal areas'); }); } // If ranges is null/undefined, range state remain. // This helps user to dispatchAction({type: 'brush'}) with no areas // set but just want to get the current brush select info from a `brush` event. if (!areas) { return; } this.areas = zrUtil.map(areas, function (area) { return this._mergeBrushOption(area); }, this); }, /** * see module:echarts/component/helper/BrushController * @param {Object} brushOption */ setBrushOption: function (brushOption) { this.brushOption = this._mergeBrushOption(brushOption); this.brushType = this.brushOption.brushType; }, /** * @private */ _mergeBrushOption: function (brushOption) { var option = this.option; return zrUtil.merge( { brushType: option.brushType, brushMode: option.brushMode, transformable: option.transformable, brushStyle: new Model(option.brushStyle).getItemStyle(), removeOnClick: option.removeOnClick }, brushOption, true ); } }); module.exports = BrushModel; /***/ }, /* 313 */ /***/ function(module, exports, __webpack_require__) { var zrUtil = __webpack_require__(4); var BrushController = __webpack_require__(235); var echarts = __webpack_require__(1); var brushHelper = __webpack_require__(311); module.exports = echarts.extendComponentView({ type: 'brush', init: function (ecModel, api) { /** * @readOnly * @type {module:echarts/model/Global} */ this.ecModel = ecModel; /** * @readOnly * @type {module:echarts/ExtensionAPI} */ this.api = api; /** * @readOnly * @type {module:echarts/component/brush/BrushModel} */ this.model; /** * @private * @type {module:echarts/component/helper/BrushController} */ (this._brushController = new BrushController(api.getZr())) .on('brush', zrUtil.bind(this._onBrush, this)) .mount(); }, /** * @override */ render: function (brushModel) { this.model = brushModel; return updateController.apply(this, arguments); }, /** * @override */ updateView: updateController, /** * @override */ updateLayout: updateController, /** * @override */ updateVisual: updateController, /** * @override */ dispose: function () { this._brushController.dispose(); }, /** * @private */ _onBrush: function (areas, opt) { var modelId = this.model.id; brushHelper.parseOutputRanges(areas, this.model.coordInfoList, this.ecModel); // Action is not dispatched on drag end, because the drag end // emits the same params with the last drag move event, and // may have some delay when using touch pad, which makes // animation not smooth (when using debounce). (!opt.isEnd || opt.removeOnClick) && this.api.dispatchAction({ type: 'brush', brushId: modelId, areas: zrUtil.clone(areas), $from: modelId }); } }); function updateController(brushModel, ecModel, api, payload) { // Do not update controller when drawing. (!payload || payload.$from !== brushModel.id) && this._brushController .setPanels(brushHelper.makePanelOpts(brushModel.coordInfoList)) .enableBrush(brushModel.brushOption) .updateCovers(brushModel.areas.slice()); } /***/ }, /* 314 */ /***/ function(module, exports, __webpack_require__) { /** * @file Brush action */ var echarts = __webpack_require__(1); /** * payload: { * brushIndex: number, or, * brushId: string, or, * brushName: string, * globalRanges: Array * } */ echarts.registerAction( {type: 'brush', event: 'brush', update: 'updateView'}, function (payload, ecModel) { ecModel.eachComponent({mainType: 'brush', query: payload}, function (brushModel) { brushModel.setAreas(payload.areas); }); } ); /** * payload: { * brushComponents: [ * { * brushId, * brushIndex, * brushName, * series: [ * { * seriesId, * seriesIndex, * seriesName, * rawIndices: [21, 34, ...] * }, * ... * ] * }, * ... * ] * } */ echarts.registerAction( {type: 'brushSelect', event: 'brushSelected', update: 'none'}, function () {} ); /***/ }, /* 315 */ /***/ function(module, exports, __webpack_require__) { 'use strict'; var featureManager = __webpack_require__(316); var zrUtil = __webpack_require__(4); function Brush(model, ecModel, api) { this.model = model; this.ecModel = ecModel; this.api = api; /** * @private * @type {string} */ this._brushType; /** * @private * @type {string} */ this._brushMode; } Brush.defaultOption = { show: true, type: ['rect', 'polygon', 'lineX', 'lineY', 'keep', 'clear'], icon: { rect: 'M7.3,34.7 M0.4,10V-0.2h9.8 M89.6,10V-0.2h-9.8 M0.4,60v10.2h9.8 M89.6,60v10.2h-9.8 M12.3,22.4V10.5h13.1 M33.6,10.5h7.8 M49.1,10.5h7.8 M77.5,22.4V10.5h-13 M12.3,31.1v8.2 M77.7,31.1v8.2 M12.3,47.6v11.9h13.1 M33.6,59.5h7.6 M49.1,59.5 h7.7 M77.5,47.6v11.9h-13', // jshint ignore:line polygon: 'M55.2,34.9c1.7,0,3.1,1.4,3.1,3.1s-1.4,3.1-3.1,3.1 s-3.1-1.4-3.1-3.1S53.5,34.9,55.2,34.9z M50.4,51c1.7,0,3.1,1.4,3.1,3.1c0,1.7-1.4,3.1-3.1,3.1c-1.7,0-3.1-1.4-3.1-3.1 C47.3,52.4,48.7,51,50.4,51z M55.6,37.1l1.5-7.8 M60.1,13.5l1.6-8.7l-7.8,4 M59,19l-1,5.3 M24,16.1l6.4,4.9l6.4-3.3 M48.5,11.6 l-5.9,3.1 M19.1,12.8L9.7,5.1l1.1,7.7 M13.4,29.8l1,7.3l6.6,1.6 M11.6,18.4l1,6.1 M32.8,41.9 M26.6,40.4 M27.3,40.2l6.1,1.6 M49.9,52.1l-5.6-7.6l-4.9-1.2', // jshint ignore:line lineX: 'M15.2,30 M19.7,15.6V1.9H29 M34.8,1.9H40.4 M55.3,15.6V1.9H45.9 M19.7,44.4V58.1H29 M34.8,58.1H40.4 M55.3,44.4 V58.1H45.9 M12.5,20.3l-9.4,9.6l9.6,9.8 M3.1,29.9h16.5 M62.5,20.3l9.4,9.6L62.3,39.7 M71.9,29.9H55.4', // jshint ignore:line lineY: 'M38.8,7.7 M52.7,12h13.2v9 M65.9,26.6V32 M52.7,46.3h13.2v-9 M24.9,12H11.8v9 M11.8,26.6V32 M24.9,46.3H11.8v-9 M48.2,5.1l-9.3-9l-9.4,9.2 M38.9-3.9V12 M48.2,53.3l-9.3,9l-9.4-9.2 M38.9,62.3V46.4', // jshint ignore:line keep: 'M4,10.5V1h10.3 M20.7,1h6.1 M33,1h6.1 M55.4,10.5V1H45.2 M4,17.3v6.6 M55.6,17.3v6.6 M4,30.5V40h10.3 M20.7,40 h6.1 M33,40h6.1 M55.4,30.5V40H45.2 M21,18.9h62.9v48.6H21V18.9z', // jshint ignore:line clear: 'M22,14.7l30.9,31 M52.9,14.7L22,45.7 M4.7,16.8V4.2h13.1 M26,4.2h7.8 M41.6,4.2h7.8 M70.3,16.8V4.2H57.2 M4.7,25.9v8.6 M70.3,25.9v8.6 M4.7,43.2v12.6h13.1 M26,55.8h7.8 M41.6,55.8h7.8 M70.3,43.2v12.6H57.2' // jshint ignore:line }, title: { rect: '矩形选择', polygon: '圈选', lineX: '横向选择', lineY: '纵向选择', keep: '保持选择', clear: '清除选择' } }; var proto = Brush.prototype; proto.render = proto.updateView = proto.updateLayout = function (featureModel, ecModel, api) { var brushType; var brushMode; var isBrushed; ecModel.eachComponent({mainType: 'brush'}, function (brushModel) { brushType = brushModel.brushType; brushMode = brushModel.brushOption.brushMode || 'single'; isBrushed |= brushModel.areas.length; }); this._brushType = brushType; this._brushMode = brushMode; zrUtil.each(featureModel.get('type', true), function (type) { featureModel.setIconStatus( type, ( type === 'keep' ? brushMode === 'multiple' : type === 'clear' ? isBrushed : type === brushType ) ? 'emphasis' : 'normal' ); }); }; proto.getIcons = function () { var model = this.model; var availableIcons = model.get('icon', true); var icons = {}; zrUtil.each(model.get('type', true), function (type) { if (availableIcons[type]) { icons[type] = availableIcons[type]; } }); return icons; }; proto.onclick = function (ecModel, api, type) { var api = this.api; var brushType = this._brushType; var brushMode = this._brushMode; if (type === 'clear') { api.dispatchAction({ type: 'brush', // Clear all areas of all brush components. areas: [] }); } else { api.dispatchAction({ type: 'takeGlobalCursor', key: 'brush', brushOption: { brushType: type === 'keep' ? brushType : (brushType === type ? false : type), brushMode: type === 'keep' ? (brushMode === 'multiple' ? 'single' : 'multiple') : brushMode } }); } }; featureManager.register('brush', Brush); module.exports = Brush; /***/ }, /* 316 */ /***/ function(module, exports) { 'use strict'; var features = {}; module.exports = { register: function (name, ctor) { features[name] = ctor; }, get: function (name) { return features[name]; } }; /***/ }, /* 317 */ /***/ function(module, exports, __webpack_require__) { 'use strict'; var echarts = __webpack_require__(1); var graphic = __webpack_require__(43); var layout = __webpack_require__(21); // Model echarts.extendComponentModel({ type: 'title', layoutMode: {type: 'box', ignoreSize: true}, defaultOption: { // 一级层叠 zlevel: 0, // 二级层叠 z: 6, show: true, text: '', // 超链接跳转 // link: null, // 仅支持self | blank target: 'blank', subtext: '', // 超链接跳转 // sublink: null, // 仅支持self | blank subtarget: 'blank', // 'center' ¦ 'left' ¦ 'right' // ¦ {number}(x坐标,单位px) left: 0, // 'top' ¦ 'bottom' ¦ 'center' // ¦ {number}(y坐标,单位px) top: 0, // 水平对齐 // 'auto' | 'left' | 'right' | 'center' // 默认根据 left 的位置判断是左对齐还是右对齐 // textAlign: null // // 垂直对齐 // 'auto' | 'top' | 'bottom' | 'middle' // 默认根据 top 位置判断是上对齐还是下对齐 // textBaseline: null backgroundColor: 'rgba(0,0,0,0)', // 标题边框颜色 borderColor: '#ccc', // 标题边框线宽,单位px,默认为0(无边框) borderWidth: 0, // 标题内边距,单位px,默认各方向内边距为5, // 接受数组分别设定上右下左边距,同css padding: 5, // 主副标题纵向间隔,单位px,默认为10, itemGap: 10, textStyle: { fontSize: 18, fontWeight: 'bolder', color: '#333' }, subtextStyle: { color: '#aaa' } } }); // View echarts.extendComponentView({ type: 'title', render: function (titleModel, ecModel, api) { this.group.removeAll(); if (!titleModel.get('show')) { return; } var group = this.group; var textStyleModel = titleModel.getModel('textStyle'); var subtextStyleModel = titleModel.getModel('subtextStyle'); var textAlign = titleModel.get('textAlign'); var textBaseline = titleModel.get('textBaseline'); var textEl = new graphic.Text({ style: { text: titleModel.get('text'), textFont: textStyleModel.getFont(), fill: textStyleModel.getTextColor() }, z2: 10 }); var textRect = textEl.getBoundingRect(); var subText = titleModel.get('subtext'); var subTextEl = new graphic.Text({ style: { text: subText, textFont: subtextStyleModel.getFont(), fill: subtextStyleModel.getTextColor(), y: textRect.height + titleModel.get('itemGap'), textBaseline: 'top' }, z2: 10 }); var link = titleModel.get('link'); var sublink = titleModel.get('sublink'); textEl.silent = !link; subTextEl.silent = !sublink; if (link) { textEl.on('click', function () { window.open(link, '_' + titleModel.get('target')); }); } if (sublink) { subTextEl.on('click', function () { window.open(sublink, '_' + titleModel.get('subtarget')); }); } group.add(textEl); subText && group.add(subTextEl); // If no subText, but add subTextEl, there will be an empty line. var groupRect = group.getBoundingRect(); var layoutOption = titleModel.getBoxLayoutParams(); layoutOption.width = groupRect.width; layoutOption.height = groupRect.height; var layoutRect = layout.getLayoutRect( layoutOption, { width: api.getWidth(), height: api.getHeight() }, titleModel.get('padding') ); // Adjust text align based on position if (!textAlign) { // Align left if title is on the left. center and right is same textAlign = titleModel.get('left') || titleModel.get('right'); if (textAlign === 'middle') { textAlign = 'center'; } // Adjust layout by text align if (textAlign === 'right') { layoutRect.x += layoutRect.width; } else if (textAlign === 'center') { layoutRect.x += layoutRect.width / 2; } } if (!textBaseline) { textBaseline = titleModel.get('top') || titleModel.get('bottom'); if (textBaseline === 'center') { textBaseline = 'middle'; } if (textBaseline === 'bottom') { layoutRect.y += layoutRect.height; } else if (textBaseline === 'middle') { layoutRect.y += layoutRect.height / 2; } textBaseline = textBaseline || 'top'; } group.attr('position', [layoutRect.x, layoutRect.y]); var alignStyle = { textAlign: textAlign, textVerticalAlign: textBaseline }; textEl.setStyle(alignStyle); subTextEl.setStyle(alignStyle); // Render background // Get groupRect again because textAlign has been changed groupRect = group.getBoundingRect(); var padding = layoutRect.margin; var style = titleModel.getItemStyle(['color', 'opacity']); style.fill = titleModel.get('backgroundColor'); var rect = new graphic.Rect({ shape: { x: groupRect.x - padding[3], y: groupRect.y - padding[0], width: groupRect.width + padding[1] + padding[3], height: groupRect.height + padding[0] + padding[2] }, style: style, silent: true }); graphic.subPixelOptimizeRect(rect); group.add(rect); } }); /***/ }, /* 318 */ /***/ function(module, exports, __webpack_require__) { /** * DataZoom component entry */ __webpack_require__(319); __webpack_require__(320); __webpack_require__(323); __webpack_require__(324); __webpack_require__(325); __webpack_require__(327); __webpack_require__(328); __webpack_require__(330); __webpack_require__(331); /***/ }, /* 319 */ /***/ function(module, exports, __webpack_require__) { __webpack_require__(19).registerSubTypeDefaulter('dataZoom', function (option) { // Default 'slider' when no type specified. return 'slider'; }); /***/ }, /* 320 */ /***/ function(module, exports, __webpack_require__) { /** * @file Data zoom model */ var zrUtil = __webpack_require__(4); var env = __webpack_require__(2); var echarts = __webpack_require__(1); var modelUtil = __webpack_require__(5); var helper = __webpack_require__(321); var AxisProxy = __webpack_require__(322); var each = zrUtil.each; var eachAxisDim = helper.eachAxisDim; var DataZoomModel = echarts.extendComponentModel({ type: 'dataZoom', dependencies: [ 'xAxis', 'yAxis', 'zAxis', 'radiusAxis', 'angleAxis', 'series' ], /** * @protected */ defaultOption: { zlevel: 0, z: 4, // Higher than normal component (z: 2). orient: null, // Default auto by axisIndex. Possible value: 'horizontal', 'vertical'. xAxisIndex: null, // Default the first horizontal category axis. yAxisIndex: null, // Default the first vertical category axis. filterMode: 'filter', // Possible values: 'filter' or 'empty'. // 'filter': data items which are out of window will be removed. // This option is applicable when filtering outliers. // 'empty': data items which are out of window will be set to empty. // This option is applicable when user should not neglect // that there are some data items out of window. // Taking line chart as an example, line will be broken in // the filtered points when filterModel is set to 'empty', but // be connected when set to 'filter'. throttle: null, // Dispatch action by the fixed rate, avoid frequency. // default 100. Do not throttle when use null/undefined. // If animation === true and animationDurationUpdate > 0, // default value is 100, otherwise 20. start: 0, // Start percent. 0 ~ 100 end: 100, // End percent. 0 ~ 100 startValue: null, // Start value. If startValue specified, start is ignored. endValue: null // End value. If endValue specified, end is ignored. }, /** * @override */ init: function (option, parentModel, ecModel) { /** * key like x_0, y_1 * @private * @type {Object} */ this._dataIntervalByAxis = {}; /** * @private */ this._dataInfo = {}; /** * key like x_0, y_1 * @private */ this._axisProxies = {}; /** * @readOnly */ this.textStyleModel; /** * @private */ this._autoThrottle = true; var rawOption = retrieveRaw(option); this.mergeDefaultAndTheme(option, ecModel); this.doInit(rawOption); }, /** * @override */ mergeOption: function (newOption) { var rawOption = retrieveRaw(newOption); //FIX #2591 zrUtil.merge(this.option, newOption, true); this.doInit(rawOption); }, /** * @protected */ doInit: function (rawOption) { var thisOption = this.option; // Disable realtime view update if canvas is not supported. if (!env.canvasSupported) { thisOption.realtime = false; } this._setDefaultThrottle(rawOption); processRangeProp('start', 'startValue', rawOption, thisOption); processRangeProp('end', 'endValue', rawOption, thisOption); this.textStyleModel = this.getModel('textStyle'); this._resetTarget(); this._giveAxisProxies(); }, /** * @private */ _giveAxisProxies: function () { var axisProxies = this._axisProxies; this.eachTargetAxis(function (dimNames, axisIndex, dataZoomModel, ecModel) { var axisModel = this.dependentModels[dimNames.axis][axisIndex]; // If exists, share axisProxy with other dataZoomModels. var axisProxy = axisModel.__dzAxisProxy || ( // Use the first dataZoomModel as the main model of axisProxy. axisModel.__dzAxisProxy = new AxisProxy( dimNames.name, axisIndex, this, ecModel ) ); // FIXME // dispose __dzAxisProxy axisProxies[dimNames.name + '_' + axisIndex] = axisProxy; }, this); }, /** * @private */ _resetTarget: function () { var thisOption = this.option; var autoMode = this._judgeAutoMode(); eachAxisDim(function (dimNames) { var axisIndexName = dimNames.axisIndex; thisOption[axisIndexName] = modelUtil.normalizeToArray( thisOption[axisIndexName] ); }, this); if (autoMode === 'axisIndex') { this._autoSetAxisIndex(); } else if (autoMode === 'orient') { this._autoSetOrient(); } }, /** * @private */ _judgeAutoMode: function () { // Auto set only works for setOption at the first time. // The following is user's reponsibility. So using merged // option is OK. var thisOption = this.option; var hasIndexSpecified = false; eachAxisDim(function (dimNames) { // When user set axisIndex as a empty array, we think that user specify axisIndex // but do not want use auto mode. Because empty array may be encountered when // some error occured. if (thisOption[dimNames.axisIndex] != null) { hasIndexSpecified = true; } }, this); var orient = thisOption.orient; if (orient == null && hasIndexSpecified) { return 'orient'; } else if (!hasIndexSpecified) { if (orient == null) { thisOption.orient = 'horizontal'; } return 'axisIndex'; } }, /** * @private */ _autoSetAxisIndex: function () { var autoAxisIndex = true; var orient = this.get('orient', true); var thisOption = this.option; if (autoAxisIndex) { // Find axis that parallel to dataZoom as default. var dimNames = orient === 'vertical' ? {dim: 'y', axisIndex: 'yAxisIndex', axis: 'yAxis'} : {dim: 'x', axisIndex: 'xAxisIndex', axis: 'xAxis'}; if (this.dependentModels[dimNames.axis].length) { thisOption[dimNames.axisIndex] = [0]; autoAxisIndex = false; } } if (autoAxisIndex) { // Find the first category axis as default. (consider polar) eachAxisDim(function (dimNames) { if (!autoAxisIndex) { return; } var axisIndices = []; var axisModels = this.dependentModels[dimNames.axis]; if (axisModels.length && !axisIndices.length) { for (var i = 0, len = axisModels.length; i < len; i++) { if (axisModels[i].get('type') === 'category') { axisIndices.push(i); } } } thisOption[dimNames.axisIndex] = axisIndices; if (axisIndices.length) { autoAxisIndex = false; } }, this); } if (autoAxisIndex) { // FIXME // 这里是兼容ec2的写法(没指定xAxisIndex和yAxisIndex时把scatter和双数值轴折柱纳入dataZoom控制), // 但是实际是否需要Grid.js#getScaleByOption来判断(考虑time,log等axis type)? // If both dataZoom.xAxisIndex and dataZoom.yAxisIndex is not specified, // dataZoom component auto adopts series that reference to // both xAxis and yAxis which type is 'value'. this.ecModel.eachSeries(function (seriesModel) { if (this._isSeriesHasAllAxesTypeOf(seriesModel, 'value')) { eachAxisDim(function (dimNames) { var axisIndices = thisOption[dimNames.axisIndex]; var axisIndex = seriesModel.get(dimNames.axisIndex); var axisId = seriesModel.get(dimNames.axisId); var axisModel = seriesModel.ecModel.queryComponents({ mainType: dimNames.axis, index: axisIndex, id: axisId })[0]; if (true) { if (!axisModel) { throw new Error( dimNames.axis + ' "' + zrUtil.retrieve( axisIndex, axisId, 0 ) + '" not found' ); } } axisIndex = axisModel.componentIndex; if (zrUtil.indexOf(axisIndices, axisIndex) < 0) { axisIndices.push(axisIndex); } }); } }, this); } }, /** * @private */ _autoSetOrient: function () { var dim; // Find the first axis this.eachTargetAxis(function (dimNames) { !dim && (dim = dimNames.name); }, this); this.option.orient = dim === 'y' ? 'vertical' : 'horizontal'; }, /** * @private */ _isSeriesHasAllAxesTypeOf: function (seriesModel, axisType) { // FIXME // 需要series的xAxisIndex和yAxisIndex都首先自动设置上。 // 例如series.type === scatter时。 var is = true; eachAxisDim(function (dimNames) { var seriesAxisIndex = seriesModel.get(dimNames.axisIndex); var axisModel = this.dependentModels[dimNames.axis][seriesAxisIndex]; if (!axisModel || axisModel.get('type') !== axisType) { is = false; } }, this); return is; }, /** * @private */ _setDefaultThrottle: function (rawOption) { // When first time user set throttle, auto throttle ends. if (rawOption.hasOwnProperty('throttle')) { this._autoThrottle = false; } if (this._autoThrottle) { var globalOption = this.ecModel.option; this.option.throttle = (globalOption.animation && globalOption.animationDurationUpdate > 0) ? 100 : 20; } }, /** * @public */ getFirstTargetAxisModel: function () { var firstAxisModel; eachAxisDim(function (dimNames) { if (firstAxisModel == null) { var indices = this.get(dimNames.axisIndex); if (indices.length) { firstAxisModel = this.dependentModels[dimNames.axis][indices[0]]; } } }, this); return firstAxisModel; }, /** * @public * @param {Function} callback param: axisModel, dimNames, axisIndex, dataZoomModel, ecModel */ eachTargetAxis: function (callback, context) { var ecModel = this.ecModel; eachAxisDim(function (dimNames) { each( this.get(dimNames.axisIndex), function (axisIndex) { callback.call(context, dimNames, axisIndex, this, ecModel); }, this ); }, this); }, getAxisProxy: function (dimName, axisIndex) { return this._axisProxies[dimName + '_' + axisIndex]; }, /** * If not specified, set to undefined. * * @public * @param {Object} opt * @param {number} [opt.start] * @param {number} [opt.end] * @param {number} [opt.startValue] * @param {number} [opt.endValue] */ setRawRange: function (opt) { each(['start', 'end', 'startValue', 'endValue'], function (name) { // If any of those prop is null/undefined, we should alos set // them, because only one pair between start/end and // startValue/endValue can work. this.option[name] = opt[name]; }, this); }, /** * @public * @return {Array.} [startPercent, endPercent] */ getPercentRange: function () { var axisProxy = this.findRepresentativeAxisProxy(); if (axisProxy) { return axisProxy.getDataPercentWindow(); } }, /** * @public * For example, chart.getModel().getComponent('dataZoom').getValueRange('y', 0); * * @param {string} [axisDimName] * @param {number} [axisIndex] * @return {Array.} [startValue, endValue] */ getValueRange: function (axisDimName, axisIndex) { if (axisDimName == null && axisIndex == null) { var axisProxy = this.findRepresentativeAxisProxy(); if (axisProxy) { return axisProxy.getDataValueWindow(); } } else { return this.getAxisProxy(axisDimName, axisIndex).getDataValueWindow(); } }, /** * @public * @return {module:echarts/component/dataZoom/AxisProxy} */ findRepresentativeAxisProxy: function () { // Find the first hosted axisProxy var axisProxies = this._axisProxies; for (var key in axisProxies) { if (axisProxies.hasOwnProperty(key) && axisProxies[key].hostedBy(this)) { return axisProxies[key]; } } // If no hosted axis find not hosted axisProxy. // Consider this case: dataZoomModel1 and dataZoomModel2 control the same axis, // and the option.start or option.end settings are different. The percentRange // should follow axisProxy. // (We encounter this problem in toolbox data zoom.) for (var key in axisProxies) { if (axisProxies.hasOwnProperty(key) && !axisProxies[key].hostedBy(this)) { return axisProxies[key]; } } } }); function retrieveRaw(option) { var ret = {}; each( ['start', 'end', 'startValue', 'endValue', 'throttle'], function (name) { option.hasOwnProperty(name) && (ret[name] = option[name]); } ); return ret; } function processRangeProp(percentProp, valueProp, rawOption, thisOption) { // start/end has higher priority over startValue/endValue, // but we should make chart.setOption({endValue: 1000}) effective, // rather than chart.setOption({endValue: 1000, end: null}). if (rawOption[valueProp] != null && rawOption[percentProp] == null) { thisOption[percentProp] = null; } // Otherwise do nothing and use the merge result. } module.exports = DataZoomModel; /***/ }, /* 321 */ /***/ function(module, exports, __webpack_require__) { var formatUtil = __webpack_require__(6); var zrUtil = __webpack_require__(4); var helper = {}; var AXIS_DIMS = ['x', 'y', 'z', 'radius', 'angle']; /** * Create "each" method to iterate names. * * @pubilc * @param {Array.} names * @param {Array.=} attrs * @return {Function} */ helper.createNameEach = function (names, attrs) { names = names.slice(); var capitalNames = zrUtil.map(names, formatUtil.capitalFirst); attrs = (attrs || []).slice(); var capitalAttrs = zrUtil.map(attrs, formatUtil.capitalFirst); return function (callback, context) { zrUtil.each(names, function (name, index) { var nameObj = {name: name, capital: capitalNames[index]}; for (var j = 0; j < attrs.length; j++) { nameObj[attrs[j]] = name + capitalAttrs[j]; } callback.call(context, nameObj); }); }; }; /** * Iterate each dimension name. * * @public * @param {Function} callback The parameter is like: * { * name: 'angle', * capital: 'Angle', * axis: 'angleAxis', * axisIndex: 'angleAixs', * index: 'angleIndex' * } * @param {Object} context */ helper.eachAxisDim = helper.createNameEach(AXIS_DIMS, ['axisIndex', 'axis', 'index', 'id']); /** * If tow dataZoomModels has the same axis controlled, we say that they are 'linked'. * dataZoomModels and 'links' make up one or more graphics. * This function finds the graphic where the source dataZoomModel is in. * * @public * @param {Function} forEachNode Node iterator. * @param {Function} forEachEdgeType edgeType iterator * @param {Function} edgeIdGetter Giving node and edgeType, return an array of edge id. * @return {Function} Input: sourceNode, Output: Like {nodes: [], dims: {}} */ helper.createLinkedNodesFinder = function (forEachNode, forEachEdgeType, edgeIdGetter) { return function (sourceNode) { var result = { nodes: [], records: {} // key: edgeType.name, value: Object (key: edge id, value: boolean). }; forEachEdgeType(function (edgeType) { result.records[edgeType.name] = {}; }); if (!sourceNode) { return result; } absorb(sourceNode, result); var existsLink; do { existsLink = false; forEachNode(processSingleNode); } while (existsLink); function processSingleNode(node) { if (!isNodeAbsorded(node, result) && isLinked(node, result)) { absorb(node, result); existsLink = true; } } return result; }; function isNodeAbsorded(node, result) { return zrUtil.indexOf(result.nodes, node) >= 0; } function isLinked(node, result) { var hasLink = false; forEachEdgeType(function (edgeType) { zrUtil.each(edgeIdGetter(node, edgeType) || [], function (edgeId) { result.records[edgeType.name][edgeId] && (hasLink = true); }); }); return hasLink; } function absorb(node, result) { result.nodes.push(node); forEachEdgeType(function (edgeType) { zrUtil.each(edgeIdGetter(node, edgeType) || [], function (edgeId) { result.records[edgeType.name][edgeId] = true; }); }); } }; module.exports = helper; /***/ }, /* 322 */ /***/ function(module, exports, __webpack_require__) { /** * @file Axis operator */ var zrUtil = __webpack_require__(4); var numberUtil = __webpack_require__(7); var each = zrUtil.each; var asc = numberUtil.asc; /** * Operate single axis. * One axis can only operated by one axis operator. * Different dataZoomModels may be defined to operate the same axis. * (i.e. 'inside' data zoom and 'slider' data zoom components) * So dataZoomModels share one axisProxy in that case. * * @class */ var AxisProxy = function (dimName, axisIndex, dataZoomModel, ecModel) { /** * @private * @type {string} */ this._dimName = dimName; /** * @private */ this._axisIndex = axisIndex; /** * @private * @type {Array.} */ this._valueWindow; /** * @private * @type {Array.} */ this._percentWindow; /** * @private * @type {Array.} */ this._dataExtent; /** * @readOnly * @type {module: echarts/model/Global} */ this.ecModel = ecModel; /** * @private * @type {module: echarts/component/dataZoom/DataZoomModel} */ this._dataZoomModel = dataZoomModel; }; AxisProxy.prototype = { constructor: AxisProxy, /** * Whether the axisProxy is hosted by dataZoomModel. * * @public * @param {module: echarts/component/dataZoom/DataZoomModel} dataZoomModel * @return {boolean} */ hostedBy: function (dataZoomModel) { return this._dataZoomModel === dataZoomModel; }, /** * @return {Array.} */ getDataExtent: function () { return this._dataExtent.slice(); }, /** * @return {Array.} */ getDataValueWindow: function () { return this._valueWindow.slice(); }, /** * @return {Array.} */ getDataPercentWindow: function () { return this._percentWindow.slice(); }, /** * @public * @param {number} axisIndex * @return {Array} seriesModels */ getTargetSeriesModels: function () { var seriesModels = []; var ecModel = this.ecModel; ecModel.eachSeries(function (seriesModel) { var coordSysName = seriesModel.get('coordinateSystem'); if (coordSysName === 'cartesian2d' || coordSysName === 'polar') { var dimName = this._dimName; var axisModel = ecModel.queryComponents({ mainType: dimName + 'Axis', index: seriesModel.get(dimName + 'AxisIndex'), id: seriesModel.get(dimName + 'AxisId') })[0]; if (this._axisIndex === (axisModel && axisModel.componentIndex)) { seriesModels.push(seriesModel); } } }, this); return seriesModels; }, getAxisModel: function () { return this.ecModel.getComponent(this._dimName + 'Axis', this._axisIndex); }, getOtherAxisModel: function () { var axisDim = this._dimName; var ecModel = this.ecModel; var axisModel = this.getAxisModel(); var isCartesian = axisDim === 'x' || axisDim === 'y'; var otherAxisDim; var coordSysIndexName; if (isCartesian) { coordSysIndexName = 'gridIndex'; otherAxisDim = axisDim === 'x' ? 'y' : 'x'; } else { coordSysIndexName = 'polarIndex'; otherAxisDim = axisDim === 'angle' ? 'radius' : 'angle'; } var foundOtherAxisModel; ecModel.eachComponent(otherAxisDim + 'Axis', function (otherAxisModel) { if ((otherAxisModel.get(coordSysIndexName) || 0) === (axisModel.get(coordSysIndexName) || 0) ) { foundOtherAxisModel = otherAxisModel; } }); return foundOtherAxisModel; }, /** * Only calculate by given range and dataExtent, do not change anything. * * @param {Object} opt * @param {number} [opt.start] * @param {number} [opt.end] * @param {number} [opt.startValue] * @param {number} [opt.endValue] * @param {Array.} dataExtent */ calculateDataWindow: function (opt, dataExtent) { var axisModel = this.getAxisModel(); var scale = axisModel.axis.scale; var percentExtent = [0, 100]; var percentWindow = [ opt.start, opt.end ]; var valueWindow = []; // In percent range is used and axis min/max/scale is set, // window should be based on min/max/0, but should not be // based on the extent of filtered data. dataExtent = dataExtent.slice(); fixExtendByAxis(dataExtent, axisModel, scale); each(['startValue', 'endValue'], function (prop) { valueWindow.push( opt[prop] != null ? scale.parse(opt[prop]) : null ); }); // Normalize bound. each([0, 1], function (idx) { var boundValue = valueWindow[idx]; var boundPercent = percentWindow[idx]; // start/end has higher priority over startValue/endValue, // because start/end can be consistent among different type // of axis but startValue/endValue not. if (boundPercent != null || boundValue == null) { if (boundPercent == null) { boundPercent = percentExtent[idx]; } // Use scale.parse to math round for category or time axis. boundValue = scale.parse(numberUtil.linearMap( boundPercent, percentExtent, dataExtent, true )); } else { // boundPercent == null && boundValue != null boundPercent = numberUtil.linearMap( boundValue, dataExtent, percentExtent, true ); } // valueWindow[idx] = round(boundValue); // percentWindow[idx] = round(boundPercent); valueWindow[idx] = boundValue; percentWindow[idx] = boundPercent; }); return { valueWindow: asc(valueWindow), percentWindow: asc(percentWindow) }; }, /** * Notice: reset should not be called before series.restoreData() called, * so it is recommanded to be called in "process stage" but not "model init * stage". * * @param {module: echarts/component/dataZoom/DataZoomModel} dataZoomModel */ reset: function (dataZoomModel) { if (dataZoomModel !== this._dataZoomModel) { return; } // Culculate data window and data extent, and record them. var dataExtent = this._dataExtent = calculateDataExtent( this._dimName, this.getTargetSeriesModels() ); var dataWindow = this.calculateDataWindow(dataZoomModel.option, dataExtent); this._valueWindow = dataWindow.valueWindow; this._percentWindow = dataWindow.percentWindow; // Update axis setting then. setAxisModel(this); }, /** * @param {module: echarts/component/dataZoom/DataZoomModel} dataZoomModel */ restore: function (dataZoomModel) { if (dataZoomModel !== this._dataZoomModel) { return; } this._valueWindow = this._percentWindow = null; setAxisModel(this, true); }, /** * @param {module: echarts/component/dataZoom/DataZoomModel} dataZoomModel */ filterData: function (dataZoomModel) { if (dataZoomModel !== this._dataZoomModel) { return; } var axisDim = this._dimName; var seriesModels = this.getTargetSeriesModels(); var filterMode = dataZoomModel.get('filterMode'); var valueWindow = this._valueWindow; // FIXME // Toolbox may has dataZoom injected. And if there are stacked bar chart // with NaN data, NaN will be filtered and stack will be wrong. // So we need to force the mode to be set empty. // In fect, it is not a big deal that do not support filterMode-'filter' // when using toolbox#dataZoom, utill tooltip#dataZoom support "single axis // selection" some day, which might need "adapt to data extent on the // otherAxis", which is disabled by filterMode-'empty'. var otherAxisModel = this.getOtherAxisModel(); if (dataZoomModel.get('$fromToolbox') && otherAxisModel && otherAxisModel.get('type') === 'category' ) { filterMode = 'empty'; } // Process series data each(seriesModels, function (seriesModel) { var seriesData = seriesModel.getData(); seriesData && each(seriesModel.coordDimToDataDim(axisDim), function (dim) { if (filterMode === 'empty') { seriesModel.setData( seriesData.map(dim, function (value) { return !isInWindow(value) ? NaN : value; }) ); } else { seriesData.filterSelf(dim, isInWindow); } }); }); function isInWindow(value) { return value >= valueWindow[0] && value <= valueWindow[1]; } } }; function calculateDataExtent(axisDim, seriesModels) { var dataExtent = [Infinity, -Infinity]; each(seriesModels, function (seriesModel) { var seriesData = seriesModel.getData(); if (seriesData) { each(seriesModel.coordDimToDataDim(axisDim), function (dim) { var seriesExtent = seriesData.getDataExtent(dim); seriesExtent[0] < dataExtent[0] && (dataExtent[0] = seriesExtent[0]); seriesExtent[1] > dataExtent[1] && (dataExtent[1] = seriesExtent[1]); }); } }, this); return dataExtent; } function fixExtendByAxis(dataExtent, axisModel, scale) { each(['min', 'max'], function (minMax, index) { var axisMax = axisModel.get(minMax, true); // Consider 'dataMin', 'dataMax' if (axisMax != null && (axisMax + '').toLowerCase() !== 'data' + minMax) { dataExtent[index] = scale.parse(axisMax); } }); if (!axisModel.get('scale', true)) { dataExtent[0] > 0 && (dataExtent[0] = 0); dataExtent[1] < 0 && (dataExtent[1] = 0); } return dataExtent; } function setAxisModel(axisProxy, isRestore) { var axisModel = axisProxy.getAxisModel(); var percentWindow = axisProxy._percentWindow; var valueWindow = axisProxy._valueWindow; if (!percentWindow) { return; } var isFull = isRestore || (percentWindow[0] === 0 && percentWindow[1] === 100); // [0, 500]: arbitrary value, guess axis extent. var precision = !isRestore && numberUtil.getPixelPrecision(valueWindow, [0, 500]); // toFixed() digits argument must be between 0 and 20 var invalidPrecision = !isRestore && !(precision < 20 && precision >= 0); var useOrigin = isRestore || isFull || invalidPrecision; axisModel.setRange && axisModel.setRange( useOrigin ? null : +valueWindow[0].toFixed(precision), useOrigin ? null : +valueWindow[1].toFixed(precision) ); } module.exports = AxisProxy; /***/ }, /* 323 */ /***/ function(module, exports, __webpack_require__) { var ComponentView = __webpack_require__(29); module.exports = ComponentView.extend({ type: 'dataZoom', render: function (dataZoomModel, ecModel, api, payload) { this.dataZoomModel = dataZoomModel; this.ecModel = ecModel; this.api = api; }, /** * Find the first target coordinate system. * * @protected * @return {Object} { * cartesians: [ * {model: coord0, axisModels: [axis1, axis3], coordIndex: 1}, * {model: coord1, axisModels: [axis0, axis2], coordIndex: 0}, * ... * ], // cartesians must not be null/undefined. * polars: [ * {model: coord0, axisModels: [axis4], coordIndex: 0}, * ... * ], // polars must not be null/undefined. * axisModels: [axis0, axis1, axis2, axis3, axis4] * // axisModels must not be null/undefined. * } */ getTargetInfo: function () { var dataZoomModel = this.dataZoomModel; var ecModel = this.ecModel; var cartesians = []; var polars = []; var axisModels = []; dataZoomModel.eachTargetAxis(function (dimNames, axisIndex) { var axisModel = ecModel.getComponent(dimNames.axis, axisIndex); if (axisModel) { axisModels.push(axisModel); var coordSysName; var axisName = dimNames.axis; if (axisName === 'xAxis' || axisName === 'yAxis') { coordSysName = 'grid'; } else if (axisName === 'angleAxis' || axisName === 'radiusAxis') { coordSysName = 'polar'; } var coordModel = coordSysName ? ecModel.queryComponents({ mainType: coordSysName, index: axisModel.get(coordSysName + 'Index'), id: axisModel.get(coordSysName + 'Id') })[0] : null; if (coordModel != null) { save( coordModel, axisModel, coordSysName === 'grid' ? cartesians : polars, coordModel.componentIndex ); } } }, this); function save(coordModel, axisModel, store, coordIndex) { var item; for (var i = 0; i < store.length; i++) { if (store[i].model === coordModel) { item = store[i]; break; } } if (!item) { store.push(item = { model: coordModel, axisModels: [], coordIndex: coordIndex }); } item.axisModels.push(axisModel); } return { cartesians: cartesians, polars: polars, axisModels: axisModels }; } }); /***/ }, /* 324 */ /***/ function(module, exports, __webpack_require__) { /** * @file Data zoom model */ var DataZoomModel = __webpack_require__(320); var SliderZoomModel = DataZoomModel.extend({ type: 'dataZoom.slider', layoutMode: 'box', /** * @protected */ defaultOption: { show: true, // ph => placeholder. Using placehoder here because // deault value can only be drived in view stage. right: 'ph', // Default align to grid rect. top: 'ph', // Default align to grid rect. width: 'ph', // Default align to grid rect. height: 'ph', // Default align to grid rect. left: null, // Default align to grid rect. bottom: null, // Default align to grid rect. backgroundColor: 'rgba(47,69,84,0)', // Background of slider zoom component. // dataBackgroundColor: '#ddd', // Background coor of data shadow and border of box, // highest priority, remain for compatibility of // previous version, but not recommended any more. dataBackground: { lineStyle: { color: '#2f4554', width: 0.5, opacity: 0.3 }, areaStyle: { color: 'rgba(47,69,84,0.3)', opacity: 0.3 } }, borderColor: '#ddd', // border color of the box. For compatibility, // if dataBackgroundColor is set, borderColor // is ignored. fillerColor: 'rgba(167,183,204,0.4)', // Color of selected area. // handleColor: 'rgba(89,170,216,0.95)', // Color of handle. // handleIcon: 'path://M4.9,17.8c0-1.4,4.5-10.5,5.5-12.4c0-0.1,0.6-1.1,0.9-1.1c0.4,0,0.9,1,0.9,1.1c1.1,2.2,5.4,11,5.4,12.4v17.8c0,1.5-0.6,2.1-1.3,2.1H6.1c-0.7,0-1.3-0.6-1.3-2.1V17.8z', handleIcon: 'M8.2,13.6V3.9H6.3v9.7H3.1v14.9h3.3v9.7h1.8v-9.7h3.3V13.6H8.2z M9.7,24.4H4.8v-1.4h4.9V24.4z M9.7,19.1H4.8v-1.4h4.9V19.1z', // Percent of the slider height handleSize: '100%', handleStyle: { color: '#a7b7cc' }, labelPrecision: null, labelFormatter: null, showDetail: true, showDataShadow: 'auto', // Default auto decision. realtime: true, zoomLock: false, // Whether disable zoom. textStyle: { color: '#333' } } }); module.exports = SliderZoomModel; /***/ }, /* 325 */ /***/ function(module, exports, __webpack_require__) { var zrUtil = __webpack_require__(4); var graphic = __webpack_require__(43); var throttle = __webpack_require__(81); var DataZoomView = __webpack_require__(323); var Rect = graphic.Rect; var numberUtil = __webpack_require__(7); var linearMap = numberUtil.linearMap; var layout = __webpack_require__(21); var sliderMove = __webpack_require__(326); var asc = numberUtil.asc; var bind = zrUtil.bind; // var mathMax = Math.max; var each = zrUtil.each; // Constants var DEFAULT_LOCATION_EDGE_GAP = 7; var DEFAULT_FRAME_BORDER_WIDTH = 1; var DEFAULT_FILLER_SIZE = 30; var HORIZONTAL = 'horizontal'; var VERTICAL = 'vertical'; var LABEL_GAP = 5; var SHOW_DATA_SHADOW_SERIES_TYPE = ['line', 'bar', 'candlestick', 'scatter']; var SliderZoomView = DataZoomView.extend({ type: 'dataZoom.slider', init: function (ecModel, api) { /** * @private * @type {Object} */ this._displayables = {}; /** * @private * @type {string} */ this._orient; /** * [0, 100] * @private */ this._range; /** * [coord of the first handle, coord of the second handle] * @private */ this._handleEnds; /** * [length, thick] * @private * @type {Array.} */ this._size; /** * @private * @type {number} */ this._handleWidth; /** * @private * @type {number} */ this._handleHeight; /** * @private */ this._location; /** * @private */ this._dragging; /** * @private */ this._dataShadowInfo; this.api = api; }, /** * @override */ render: function (dataZoomModel, ecModel, api, payload) { SliderZoomView.superApply(this, 'render', arguments); throttle.createOrUpdate( this, '_dispatchZoomAction', this.dataZoomModel.get('throttle'), 'fixRate' ); this._orient = dataZoomModel.get('orient'); if (this.dataZoomModel.get('show') === false) { this.group.removeAll(); return; } // Notice: this._resetInterval() should not be executed when payload.type // is 'dataZoom', origin this._range should be maintained, otherwise 'pan' // or 'zoom' info will be missed because of 'throttle' of this.dispatchAction, if (!payload || payload.type !== 'dataZoom' || payload.from !== this.uid) { this._buildView(); } this._updateView(); }, /** * @override */ remove: function () { SliderZoomView.superApply(this, 'remove', arguments); throttle.clear(this, '_dispatchZoomAction'); }, /** * @override */ dispose: function () { SliderZoomView.superApply(this, 'dispose', arguments); throttle.clear(this, '_dispatchZoomAction'); }, _buildView: function () { var thisGroup = this.group; thisGroup.removeAll(); this._resetLocation(); this._resetInterval(); var barGroup = this._displayables.barGroup = new graphic.Group(); this._renderBackground(); this._renderHandle(); this._renderDataShadow(); thisGroup.add(barGroup); this._positionGroup(); }, /** * @private */ _resetLocation: function () { var dataZoomModel = this.dataZoomModel; var api = this.api; // If some of x/y/width/height are not specified, // auto-adapt according to target grid. var coordRect = this._findCoordRect(); var ecSize = {width: api.getWidth(), height: api.getHeight()}; // Default align by coordinate system rect. var positionInfo = this._orient === HORIZONTAL ? { // Why using 'right', because right should be used in vertical, // and it is better to be consistent for dealing with position param merge. right: ecSize.width - coordRect.x - coordRect.width, top: (ecSize.height - DEFAULT_FILLER_SIZE - DEFAULT_LOCATION_EDGE_GAP), width: coordRect.width, height: DEFAULT_FILLER_SIZE } : { // vertical right: DEFAULT_LOCATION_EDGE_GAP, top: coordRect.y, width: DEFAULT_FILLER_SIZE, height: coordRect.height }; // Do not write back to option and replace value 'ph', because // the 'ph' value should be recalculated when resize. var layoutParams = layout.getLayoutParams(dataZoomModel.option); // Replace the placeholder value. zrUtil.each(['right', 'top', 'width', 'height'], function (name) { if (layoutParams[name] === 'ph') { layoutParams[name] = positionInfo[name]; } }); var layoutRect = layout.getLayoutRect( layoutParams, ecSize, dataZoomModel.padding ); this._location = {x: layoutRect.x, y: layoutRect.y}; this._size = [layoutRect.width, layoutRect.height]; this._orient === VERTICAL && this._size.reverse(); }, /** * @private */ _positionGroup: function () { var thisGroup = this.group; var location = this._location; var orient = this._orient; // Just use the first axis to determine mapping. var targetAxisModel = this.dataZoomModel.getFirstTargetAxisModel(); var inverse = targetAxisModel && targetAxisModel.get('inverse'); var barGroup = this._displayables.barGroup; var otherAxisInverse = (this._dataShadowInfo || {}).otherAxisInverse; // Transform barGroup. barGroup.attr( (orient === HORIZONTAL && !inverse) ? {scale: otherAxisInverse ? [1, 1] : [1, -1]} : (orient === HORIZONTAL && inverse) ? {scale: otherAxisInverse ? [-1, 1] : [-1, -1]} : (orient === VERTICAL && !inverse) ? {scale: otherAxisInverse ? [1, -1] : [1, 1], rotation: Math.PI / 2} // Dont use Math.PI, considering shadow direction. : {scale: otherAxisInverse ? [-1, -1] : [-1, 1], rotation: Math.PI / 2} ); // Position barGroup var rect = thisGroup.getBoundingRect([barGroup]); thisGroup.attr('position', [location.x - rect.x, location.y - rect.y]); }, /** * @private */ _getViewExtent: function () { return [0, this._size[0]]; }, _renderBackground : function () { var dataZoomModel = this.dataZoomModel; var size = this._size; this._displayables.barGroup.add(new Rect({ silent: true, shape: { x: 0, y: 0, width: size[0], height: size[1] }, style: { fill: dataZoomModel.get('backgroundColor') }, z2: -40 })); }, _renderDataShadow: function () { var info = this._dataShadowInfo = this._prepareDataShadowInfo(); if (!info) { return; } var size = this._size; var seriesModel = info.series; var data = seriesModel.getRawData(); var otherDim = seriesModel.getShadowDim ? seriesModel.getShadowDim() // @see candlestick : info.otherDim; var otherDataExtent = data.getDataExtent(otherDim); // Nice extent. var otherOffset = (otherDataExtent[1] - otherDataExtent[0]) * 0.3; otherDataExtent = [ otherDataExtent[0] - otherOffset, otherDataExtent[1] + otherOffset ]; var otherShadowExtent = [0, size[1]]; var thisShadowExtent = [0, size[0]]; var areaPoints = [[size[0], 0], [0, 0]]; var linePoints = []; var step = thisShadowExtent[1] / (data.count() - 1); var thisCoord = 0; // Optimize for large data shadow var stride = Math.round(data.count() / size[0]); var lastIsEmpty; data.each([otherDim], function (value, index) { if (stride > 0 && (index % stride)) { thisCoord += step; return; } // FIXME // Should consider axis.min/axis.max when drawing dataShadow. // FIXME // 应该使用统一的空判断?还是在list里进行空判断? var isEmpty = value == null || isNaN(value) || value === ''; // See #4235. var otherCoord = isEmpty ? 0 : linearMap(value, otherDataExtent, otherShadowExtent, true); // Attempt to draw data shadow precisely when there are empty value. if (isEmpty && !lastIsEmpty && index) { areaPoints.push([areaPoints[areaPoints.length - 1][0], 0]); linePoints.push([linePoints[linePoints.length - 1][0], 0]); } else if (!isEmpty && lastIsEmpty) { areaPoints.push([thisCoord, 0]); linePoints.push([thisCoord, 0]); } areaPoints.push([thisCoord, otherCoord]); linePoints.push([thisCoord, otherCoord]); thisCoord += step; lastIsEmpty = isEmpty; }); var dataZoomModel = this.dataZoomModel; // var dataBackgroundModel = dataZoomModel.getModel('dataBackground'); this._displayables.barGroup.add(new graphic.Polygon({ shape: {points: areaPoints}, style: zrUtil.defaults( {fill: dataZoomModel.get('dataBackgroundColor')}, dataZoomModel.getModel('dataBackground.areaStyle').getAreaStyle() ), silent: true, z2: -20 })); this._displayables.barGroup.add(new graphic.Polyline({ shape: {points: linePoints}, style: dataZoomModel.getModel('dataBackground.lineStyle').getLineStyle(), silent: true, z2: -19 })); }, _prepareDataShadowInfo: function () { var dataZoomModel = this.dataZoomModel; var showDataShadow = dataZoomModel.get('showDataShadow'); if (showDataShadow === false) { return; } // Find a representative series. var result; var ecModel = this.ecModel; dataZoomModel.eachTargetAxis(function (dimNames, axisIndex) { var seriesModels = dataZoomModel .getAxisProxy(dimNames.name, axisIndex) .getTargetSeriesModels(); zrUtil.each(seriesModels, function (seriesModel) { if (result) { return; } if (showDataShadow !== true && zrUtil.indexOf( SHOW_DATA_SHADOW_SERIES_TYPE, seriesModel.get('type') ) < 0 ) { return; } var otherDim = getOtherDim(dimNames.name); var thisAxis = ecModel.getComponent(dimNames.axis, axisIndex).axis; result = { thisAxis: thisAxis, series: seriesModel, thisDim: dimNames.name, otherDim: otherDim, otherAxisInverse: seriesModel .coordinateSystem.getOtherAxis(thisAxis).inverse }; }, this); }, this); return result; }, _renderHandle: function () { var displaybles = this._displayables; var handles = displaybles.handles = []; var handleLabels = displaybles.handleLabels = []; var barGroup = this._displayables.barGroup; var size = this._size; var dataZoomModel = this.dataZoomModel; barGroup.add(displaybles.filler = new Rect({ draggable: true, cursor: 'move', drift: bind(this._onDragMove, this, 'all'), ondragstart: bind(this._showDataInfo, this, true), ondragend: bind(this._onDragEnd, this), onmouseover: bind(this._showDataInfo, this, true), onmouseout: bind(this._showDataInfo, this, false), style: { fill: dataZoomModel.get('fillerColor'), textPosition : 'inside' } })); // Frame border. barGroup.add(new Rect(graphic.subPixelOptimizeRect({ silent: true, shape: { x: 0, y: 0, width: size[0], height: size[1] }, style: { stroke: dataZoomModel.get('dataBackgroundColor') || dataZoomModel.get('borderColor'), lineWidth: DEFAULT_FRAME_BORDER_WIDTH, fill: 'rgba(0,0,0,0)' } }))); var iconStr = dataZoomModel.get('handleIcon'); each([0, 1], function (handleIndex) { var path = graphic.makePath(iconStr, { style: { strokeNoScale: true }, rectHover: true, cursor: this._orient === 'vertical' ? 'ns-resize' : 'ew-resize', draggable: true, drift: bind(this._onDragMove, this, handleIndex), ondragend: bind(this._onDragEnd, this), onmouseover: bind(this._showDataInfo, this, true), onmouseout: bind(this._showDataInfo, this, false) }, { x: -0.5, y: 0, width: 1, height: 1 }, 'center'); var bRect = path.getBoundingRect(); this._handleHeight = numberUtil.parsePercent(dataZoomModel.get('handleSize'), this._size[1]); this._handleWidth = bRect.width / bRect.height * this._handleHeight; path.setStyle(dataZoomModel.getModel('handleStyle').getItemStyle()); var handleColor = dataZoomModel.get('handleColor'); // Compatitable with previous version if (handleColor != null) { path.style.fill = handleColor; } barGroup.add(handles[handleIndex] = path); var textStyleModel = dataZoomModel.textStyleModel; this.group.add( handleLabels[handleIndex] = new graphic.Text({ silent: true, invisible: true, style: { x: 0, y: 0, text: '', textVerticalAlign: 'middle', textAlign: 'center', fill: textStyleModel.getTextColor(), textFont: textStyleModel.getFont() }, z2: 10 })); }, this); }, /** * @private */ _resetInterval: function () { var range = this._range = this.dataZoomModel.getPercentRange(); var viewExtent = this._getViewExtent(); this._handleEnds = [ linearMap(range[0], [0, 100], viewExtent, true), linearMap(range[1], [0, 100], viewExtent, true) ]; }, /** * @private * @param {(number|string)} handleIndex 0 or 1 or 'all' * @param {number} dx * @param {number} dy */ _updateInterval: function (handleIndex, delta) { var handleEnds = this._handleEnds; var viewExtend = this._getViewExtent(); sliderMove( delta, handleEnds, viewExtend, (handleIndex === 'all' || this.dataZoomModel.get('zoomLock')) ? 'rigid' : 'cross', handleIndex ); this._range = asc([ linearMap(handleEnds[0], viewExtend, [0, 100], true), linearMap(handleEnds[1], viewExtend, [0, 100], true) ]); }, /** * @private */ _updateView: function (nonRealtime) { var displaybles = this._displayables; var handleEnds = this._handleEnds; var handleInterval = asc(handleEnds.slice()); var size = this._size; each([0, 1], function (handleIndex) { // Handles var handle = displaybles.handles[handleIndex]; var handleHeight = this._handleHeight; handle.attr({ scale: [handleHeight, handleHeight], position: [handleEnds[handleIndex], size[1] / 2 - handleHeight / 2] }); }, this); // Filler displaybles.filler.setShape({ x: handleInterval[0], y: 0, width: handleInterval[1] - handleInterval[0], height: size[1] }); this._updateDataInfo(nonRealtime); }, /** * @private */ _updateDataInfo: function (nonRealtime) { var dataZoomModel = this.dataZoomModel; var displaybles = this._displayables; var handleLabels = displaybles.handleLabels; var orient = this._orient; var labelTexts = ['', '']; // FIXME // date型,支持formatter,autoformatter(ec2 date.getAutoFormatter) if (dataZoomModel.get('showDetail')) { var axisProxy = dataZoomModel.findRepresentativeAxisProxy(); if (axisProxy) { var axis = axisProxy.getAxisModel().axis; var range = this._range; var dataInterval = nonRealtime // See #4434, data and axis are not processed and reset yet in non-realtime mode. ? axisProxy.calculateDataWindow( {start: range[0], end: range[1]}, axisProxy.getDataExtent() ).valueWindow : axisProxy.getDataValueWindow(); labelTexts = [ this._formatLabel(dataInterval[0], axis), this._formatLabel(dataInterval[1], axis) ]; } } var orderedHandleEnds = asc(this._handleEnds.slice()); setLabel.call(this, 0); setLabel.call(this, 1); function setLabel(handleIndex) { // Label // Text should not transform by barGroup. // Ignore handlers transform var barTransform = graphic.getTransform( displaybles.handles[handleIndex].parent, this.group ); var direction = graphic.transformDirection( handleIndex === 0 ? 'right' : 'left', barTransform ); var offset = this._handleWidth / 2 + LABEL_GAP; var textPoint = graphic.applyTransform( [ orderedHandleEnds[handleIndex] + (handleIndex === 0 ? -offset : offset), this._size[1] / 2 ], barTransform ); handleLabels[handleIndex].setStyle({ x: textPoint[0], y: textPoint[1], textVerticalAlign: orient === HORIZONTAL ? 'middle' : direction, textAlign: orient === HORIZONTAL ? direction : 'center', text: labelTexts[handleIndex] }); } }, /** * @private */ _formatLabel: function (value, axis) { var dataZoomModel = this.dataZoomModel; var labelFormatter = dataZoomModel.get('labelFormatter'); var labelPrecision = dataZoomModel.get('labelPrecision'); if (labelPrecision == null || labelPrecision === 'auto') { labelPrecision = axis.getPixelPrecision(); } var valueStr = (value == null && isNaN(value)) ? '' // FIXME Glue code : (axis.type === 'category' || axis.type === 'time') ? axis.scale.getLabel(Math.round(value)) // param of toFixed should less then 20. : value.toFixed(Math.min(labelPrecision, 20)); return zrUtil.isFunction(labelFormatter) ? labelFormatter(value, valueStr) : zrUtil.isString(labelFormatter) ? labelFormatter.replace('{value}', valueStr) : valueStr; }, /** * @private * @param {boolean} showOrHide true: show, false: hide */ _showDataInfo: function (showOrHide) { // Always show when drgging. showOrHide = this._dragging || showOrHide; var handleLabels = this._displayables.handleLabels; handleLabels[0].attr('invisible', !showOrHide); handleLabels[1].attr('invisible', !showOrHide); }, _onDragMove: function (handleIndex, dx, dy) { this._dragging = true; // Transform dx, dy to bar coordination. var vertex = this._applyBarTransform([dx, dy], true); this._updateInterval(handleIndex, vertex[0]); var realtime = this.dataZoomModel.get('realtime'); this._updateView(!realtime); if (realtime) { realtime && this._dispatchZoomAction(); } }, _onDragEnd: function () { this._dragging = false; this._showDataInfo(false); this._dispatchZoomAction(); }, /** * This action will be throttled. * @private */ _dispatchZoomAction: function () { var range = this._range; this.api.dispatchAction({ type: 'dataZoom', from: this.uid, dataZoomId: this.dataZoomModel.id, start: range[0], end: range[1] }); }, /** * @private */ _applyBarTransform: function (vertex, inverse) { var barTransform = this._displayables.barGroup.getLocalTransform(); return graphic.applyTransform(vertex, barTransform, inverse); }, /** * @private */ _findCoordRect: function () { // Find the grid coresponding to the first axis referred by dataZoom. var targetInfo = this.getTargetInfo(); // FIXME // 判断是catesian还是polar var rect; if (targetInfo.cartesians.length) { rect = targetInfo.cartesians[0].model.coordinateSystem.getRect(); } else { // Polar // FIXME // 暂时随便写的 var width = this.api.getWidth(); var height = this.api.getHeight(); rect = { x: width * 0.2, y: height * 0.2, width: width * 0.6, height: height * 0.6 }; } return rect; } }); function getOtherDim(thisDim) { // FIXME // 这个逻辑和getOtherAxis里一致,但是写在这里是否不好 return thisDim === 'x' ? 'y' : 'x'; } module.exports = SliderZoomView; /***/ }, /* 326 */ /***/ function(module, exports) { /** * Calculate slider move result. * * @param {number} delta Move length. * @param {Array.} handleEnds handleEnds[0] and be bigger then handleEnds[1]. * handleEnds will be modified in this method. * @param {Array.} extent handleEnds is restricted by extent. * extent[0] should less or equals than extent[1]. * @param {string} mode 'rigid': Math.abs(handleEnds[0] - handleEnds[1]) remain unchanged, * 'cross' handleEnds[0] can be bigger then handleEnds[1], * 'push' handleEnds[0] can not be bigger then handleEnds[1], * when they touch, one push other. * @param {number} handleIndex If mode is 'rigid', handleIndex is not required. * @param {Array.} The input handleEnds. */ module.exports = function (delta, handleEnds, extent, mode, handleIndex) { if (!delta) { return handleEnds; } if (mode === 'rigid') { delta = getRealDelta(delta, handleEnds, extent); handleEnds[0] += delta; handleEnds[1] += delta; } else { delta = getRealDelta(delta, handleEnds[handleIndex], extent); handleEnds[handleIndex] += delta; if (mode === 'push' && handleEnds[0] > handleEnds[1]) { handleEnds[1 - handleIndex] = handleEnds[handleIndex]; } } return handleEnds; function getRealDelta(delta, handleEnds, extent) { var handleMinMax = !handleEnds.length ? [handleEnds, handleEnds] : handleEnds.slice(); handleEnds[0] > handleEnds[1] && handleMinMax.reverse(); if (delta < 0 && handleMinMax[0] + delta < extent[0]) { delta = extent[0] - handleMinMax[0]; } if (delta > 0 && handleMinMax[1] + delta > extent[1]) { delta = extent[1] - handleMinMax[1]; } return delta; } }; /***/ }, /* 327 */ /***/ function(module, exports, __webpack_require__) { /** * @file Data zoom model */ module.exports = __webpack_require__(320).extend({ type: 'dataZoom.inside', /** * @protected */ defaultOption: { disabled: false, // Whether disable this inside zoom. zoomLock: false // Whether disable zoom but only pan. } }); /***/ }, /* 328 */ /***/ function(module, exports, __webpack_require__) { var DataZoomView = __webpack_require__(323); var zrUtil = __webpack_require__(4); var sliderMove = __webpack_require__(326); var roams = __webpack_require__(329); var bind = zrUtil.bind; var InsideZoomView = DataZoomView.extend({ type: 'dataZoom.inside', /** * @override */ init: function (ecModel, api) { /** * 'throttle' is used in this.dispatchAction, so we save range * to avoid missing some 'pan' info. * @private * @type {Array.} */ this._range; }, /** * @override */ render: function (dataZoomModel, ecModel, api, payload) { InsideZoomView.superApply(this, 'render', arguments); // Notice: origin this._range should be maintained, and should not be re-fetched // from dataZoomModel when payload.type is 'dataZoom', otherwise 'pan' or 'zoom' // info will be missed because of 'throttle' of this.dispatchAction. if (roams.shouldRecordRange(payload, dataZoomModel.id)) { this._range = dataZoomModel.getPercentRange(); } var targetInfo = this.getTargetInfo(); // Reset controllers. zrUtil.each(['cartesians', 'polars'], function (coordSysName) { var coordInfoList = targetInfo[coordSysName]; var allCoordIds = zrUtil.map(coordInfoList, function (coordInfo) { return roams.generateCoordId(coordInfo.model); }); zrUtil.each(coordInfoList, function (coordInfo) { var coordModel = coordInfo.model; var coordinateSystem = coordModel.coordinateSystem; roams.register( api, { coordId: roams.generateCoordId(coordModel), allCoordIds: allCoordIds, coordinateSystem: coordinateSystem, containsPoint: bind(operations[coordSysName].containsPoint, this, coordinateSystem), dataZoomId: dataZoomModel.id, throttleRate: dataZoomModel.get('throttle', true), panGetRange: bind(this._onPan, this, coordInfo, coordSysName), zoomGetRange: bind(this._onZoom, this, coordInfo, coordSysName) } ); }, this); }, this); }, /** * @override */ dispose: function () { roams.unregister(this.api, this.dataZoomModel.id); InsideZoomView.superApply(this, 'dispose', arguments); this._range = null; }, /** * @private */ _onPan: function (coordInfo, coordSysName, controller, dx, dy, oldX, oldY, newX, newY) { if (this.dataZoomModel.option.disabled) { return this._range; } var range = this._range.slice(); // Calculate transform by the first axis. var axisModel = coordInfo.axisModels[0]; if (!axisModel) { return; } var directionInfo = operations[coordSysName].getDirectionInfo( [oldX, oldY], [newX, newY], axisModel, controller, coordInfo ); var percentDelta = directionInfo.signal * (range[1] - range[0]) * directionInfo.pixel / directionInfo.pixelLength; sliderMove(percentDelta, range, [0, 100], 'rigid'); return (this._range = range); }, /** * @private */ _onZoom: function (coordInfo, coordSysName, controller, scale, mouseX, mouseY) { var option = this.dataZoomModel.option; if (option.disabled || option.zoomLock) { return this._range; } var range = this._range.slice(); // Calculate transform by the first axis. var axisModel = coordInfo.axisModels[0]; if (!axisModel) { return; } var directionInfo = operations[coordSysName].getDirectionInfo( null, [mouseX, mouseY], axisModel, controller, coordInfo ); var percentPoint = (directionInfo.pixel - directionInfo.pixelStart) / directionInfo.pixelLength * (range[1] - range[0]) + range[0]; scale = Math.max(1 / scale, 0); range[0] = (range[0] - percentPoint) * scale + percentPoint; range[1] = (range[1] - percentPoint) * scale + percentPoint; return (this._range = fixRange(range)); } }); var operations = { cartesians: { getDirectionInfo: function (oldPoint, newPoint, axisModel, controller, coordInfo) { var axis = axisModel.axis; var ret = {}; var rect = coordInfo.model.coordinateSystem.getRect(); oldPoint = oldPoint || [0, 0]; if (axis.dim === 'x') { ret.pixel = newPoint[0] - oldPoint[0]; ret.pixelLength = rect.width; ret.pixelStart = rect.x; ret.signal = axis.inverse ? 1 : -1; } else { // axis.dim === 'y' ret.pixel = newPoint[1] - oldPoint[1]; ret.pixelLength = rect.height; ret.pixelStart = rect.y; ret.signal = axis.inverse ? -1 : 1; } return ret; }, containsPoint: function (coordinateSystem, x, y) { return coordinateSystem.getRect().contain(x, y); } }, polars: { getDirectionInfo: function (oldPoint, newPoint, axisModel, controller, coordInfo) { var axis = axisModel.axis; var ret = {}; var polar = coordInfo.model.coordinateSystem; var radiusExtent = polar.getRadiusAxis().getExtent(); var angleExtent = polar.getAngleAxis().getExtent(); oldPoint = oldPoint ? polar.pointToCoord(oldPoint) : [0, 0]; newPoint = polar.pointToCoord(newPoint); if (axisModel.mainType === 'radiusAxis') { ret.pixel = newPoint[0] - oldPoint[0]; // ret.pixelLength = Math.abs(radiusExtent[1] - radiusExtent[0]); // ret.pixelStart = Math.min(radiusExtent[0], radiusExtent[1]); ret.pixelLength = radiusExtent[1] - radiusExtent[0]; ret.pixelStart = radiusExtent[0]; ret.signal = axis.inverse ? 1 : -1; } else { // 'angleAxis' ret.pixel = newPoint[1] - oldPoint[1]; // ret.pixelLength = Math.abs(angleExtent[1] - angleExtent[0]); // ret.pixelStart = Math.min(angleExtent[0], angleExtent[1]); ret.pixelLength = angleExtent[1] - angleExtent[0]; ret.pixelStart = angleExtent[0]; ret.signal = axis.inverse ? -1 : 1; } return ret; }, containsPoint: function (coordinateSystem, x, y) { var radius = coordinateSystem.getRadiusAxis().getExtent()[1]; var cx = coordinateSystem.cx; var cy = coordinateSystem.cy; return Math.pow(x - cx, 2) + Math.pow(y - cy, 2) <= Math.pow(radius, 2); } } }; function fixRange(range) { // Clamp, using !(<= or >=) to handle NaN. // jshint ignore:start var bound = [0, 100]; !(range[0] <= bound[1]) && (range[0] = bound[1]); !(range[1] <= bound[1]) && (range[1] = bound[1]); !(range[0] >= bound[0]) && (range[0] = bound[0]); !(range[1] >= bound[0]) && (range[1] = bound[0]); // jshint ignore:end return range; } module.exports = InsideZoomView; /***/ }, /* 329 */ /***/ function(module, exports, __webpack_require__) { /** * @file Roam controller manager. */ // Only create one roam controller for each coordinate system. // one roam controller might be refered by two inside data zoom // components (for example, one for x and one for y). When user // pan or zoom, only dispatch one action for those data zoom // components. var zrUtil = __webpack_require__(4); var RoamController = __webpack_require__(176); var throttle = __webpack_require__(81); var curry = zrUtil.curry; var ATTR = '\0_ec_dataZoom_roams'; var roams = { /** * @public * @param {module:echarts/ExtensionAPI} api * @param {Object} dataZoomInfo * @param {string} dataZoomInfo.coordId * @param {Function} dataZoomInfo.containsPoint * @param {Array.} dataZoomInfo.allCoordIds * @param {string} dataZoomInfo.dataZoomId * @param {number} dataZoomInfo.throttleRate * @param {Function} dataZoomInfo.panGetRange * @param {Function} dataZoomInfo.zoomGetRange */ register: function (api, dataZoomInfo) { var store = giveStore(api); var theDataZoomId = dataZoomInfo.dataZoomId; var theCoordId = dataZoomInfo.coordId; // Do clean when a dataZoom changes its target coordnate system. // Avoid memory leak, dispose all not-used-registered. zrUtil.each(store, function (record, coordId) { var dataZoomInfos = record.dataZoomInfos; if (dataZoomInfos[theDataZoomId] && zrUtil.indexOf(dataZoomInfo.allCoordIds, theCoordId) < 0 ) { delete dataZoomInfos[theDataZoomId]; record.count--; } }); cleanStore(store); var record = store[theCoordId]; // Create if needed. if (!record) { record = store[theCoordId] = { coordId: theCoordId, dataZoomInfos: {}, count: 0 }; record.controller = createController(api, dataZoomInfo, record); record.dispatchAction = zrUtil.curry(dispatchAction, api); } // Consider resize, area should be always updated. record.controller.setContainsPoint(dataZoomInfo.containsPoint); // Update throttle. throttle.createOrUpdate( record, 'dispatchAction', dataZoomInfo.throttleRate, 'fixRate' ); // Update reference of dataZoom. !(record.dataZoomInfos[theDataZoomId]) && record.count++; record.dataZoomInfos[theDataZoomId] = dataZoomInfo; }, /** * @public * @param {module:echarts/ExtensionAPI} api * @param {string} dataZoomId */ unregister: function (api, dataZoomId) { var store = giveStore(api); zrUtil.each(store, function (record) { record.controller.dispose(); var dataZoomInfos = record.dataZoomInfos; if (dataZoomInfos[dataZoomId]) { delete dataZoomInfos[dataZoomId]; record.count--; } }); cleanStore(store); }, /** * @public */ shouldRecordRange: function (payload, dataZoomId) { if (payload && payload.type === 'dataZoom' && payload.batch) { for (var i = 0, len = payload.batch.length; i < len; i++) { if (payload.batch[i].dataZoomId === dataZoomId) { return false; } } } return true; }, /** * @public */ generateCoordId: function (coordModel) { return coordModel.type + '\0_' + coordModel.id; } }; /** * Key: coordId, value: {dataZoomInfos: [], count, controller} * @type {Array.} */ function giveStore(api) { // Mount store on zrender instance, so that we do not // need to worry about dispose. var zr = api.getZr(); return zr[ATTR] || (zr[ATTR] = {}); } function createController(api, dataZoomInfo, newRecord) { var controller = new RoamController(api.getZr()); controller.enable(); controller.on('pan', curry(onPan, newRecord)); controller.on('zoom', curry(onZoom, newRecord)); return controller; } function cleanStore(store) { zrUtil.each(store, function (record, coordId) { if (!record.count) { record.controller.dispose(); delete store[coordId]; } }); } function onPan(record, dx, dy, oldX, oldY, newX, newY) { wrapAndDispatch(record, function (info) { return info.panGetRange(record.controller, dx, dy, oldX, oldY, newX, newY); }); } function onZoom(record, scale, mouseX, mouseY) { wrapAndDispatch(record, function (info) { return info.zoomGetRange(record.controller, scale, mouseX, mouseY); }); } function wrapAndDispatch(record, getRange) { var batch = []; zrUtil.each(record.dataZoomInfos, function (info) { var range = getRange(info); range && batch.push({ dataZoomId: info.dataZoomId, start: range[0], end: range[1] }); }); record.dispatchAction(batch); } /** * This action will be throttled. */ function dispatchAction(api, batch) { api.dispatchAction({ type: 'dataZoom', batch: batch }); } module.exports = roams; /***/ }, /* 330 */ /***/ function(module, exports, __webpack_require__) { /** * @file Data zoom processor */ var echarts = __webpack_require__(1); echarts.registerProcessor(function (ecModel, api) { ecModel.eachComponent('dataZoom', function (dataZoomModel) { // We calculate window and reset axis here but not in model // init stage and not after action dispatch handler, because // reset should be called after seriesData.restoreData. dataZoomModel.eachTargetAxis(resetSingleAxis); // Caution: data zoom filtering is order sensitive when using // percent range and no min/max/scale set on axis. // For example, we have dataZoom definition: // [ // {xAxisIndex: 0, start: 30, end: 70}, // {yAxisIndex: 0, start: 20, end: 80} // ] // In this case, [20, 80] of y-dataZoom should be based on data // that have filtered by x-dataZoom using range of [30, 70], // but should not be based on full raw data. Thus sliding // x-dataZoom will change both ranges of xAxis and yAxis, // while sliding y-dataZoom will only change the range of yAxis. // So we should filter x-axis after reset x-axis immediately, // and then reset y-axis and filter y-axis. dataZoomModel.eachTargetAxis(filterSingleAxis); }); ecModel.eachComponent('dataZoom', function (dataZoomModel) { // Fullfill all of the range props so that user // is able to get them from chart.getOption(). var axisProxy = dataZoomModel.findRepresentativeAxisProxy(); var percentRange = axisProxy.getDataPercentWindow(); var valueRange = axisProxy.getDataValueWindow(); dataZoomModel.setRawRange({ start: percentRange[0], end: percentRange[1], startValue: valueRange[0], endValue: valueRange[1] }); }); }); function resetSingleAxis(dimNames, axisIndex, dataZoomModel) { dataZoomModel.getAxisProxy(dimNames.name, axisIndex).reset(dataZoomModel); } function filterSingleAxis(dimNames, axisIndex, dataZoomModel) { dataZoomModel.getAxisProxy(dimNames.name, axisIndex).filterData(dataZoomModel); } /***/ }, /* 331 */ /***/ function(module, exports, __webpack_require__) { /** * @file Data zoom action */ var zrUtil = __webpack_require__(4); var helper = __webpack_require__(321); var echarts = __webpack_require__(1); echarts.registerAction('dataZoom', function (payload, ecModel) { var linkedNodesFinder = helper.createLinkedNodesFinder( zrUtil.bind(ecModel.eachComponent, ecModel, 'dataZoom'), helper.eachAxisDim, function (model, dimNames) { return model.get(dimNames.axisIndex); } ); var effectedModels = []; ecModel.eachComponent( {mainType: 'dataZoom', query: payload}, function (model, index) { effectedModels.push.apply( effectedModels, linkedNodesFinder(model).nodes ); } ); zrUtil.each(effectedModels, function (dataZoomModel, index) { dataZoomModel.setRawRange({ start: payload.start, end: payload.end, startValue: payload.startValue, endValue: payload.endValue }); }); }); /***/ }, /* 332 */ /***/ function(module, exports, __webpack_require__) { /** * visualMap component entry */ __webpack_require__(333); __webpack_require__(344); /***/ }, /* 333 */ /***/ function(module, exports, __webpack_require__) { /** * DataZoom component entry */ __webpack_require__(1).registerPreprocessor( __webpack_require__(334) ); __webpack_require__(335); __webpack_require__(336); __webpack_require__(337); __webpack_require__(340); __webpack_require__(343); /***/ }, /* 334 */ /***/ function(module, exports, __webpack_require__) { /** * @file VisualMap preprocessor */ var zrUtil = __webpack_require__(4); var each = zrUtil.each; module.exports = function (option) { var visualMap = option && option.visualMap; if (!zrUtil.isArray(visualMap)) { visualMap = visualMap ? [visualMap] : []; } each(visualMap, function (opt) { if (!opt) { return; } // rename splitList to pieces if (has(opt, 'splitList') && !has(opt, 'pieces')) { opt.pieces = opt.splitList; delete opt.splitList; } var pieces = opt.pieces; if (pieces && zrUtil.isArray(pieces)) { each(pieces, function (piece) { if (zrUtil.isObject(piece)) { if (has(piece, 'start') && !has(piece, 'min')) { piece.min = piece.start; } if (has(piece, 'end') && !has(piece, 'max')) { piece.max = piece.end; } } }); } }); }; function has(obj, name) { return obj && obj.hasOwnProperty && obj.hasOwnProperty(name); } /***/ }, /* 335 */ /***/ function(module, exports, __webpack_require__) { __webpack_require__(19).registerSubTypeDefaulter('visualMap', function (option) { // Compatible with ec2, when splitNumber === 0, continuous visualMap will be used. return ( !option.categories && ( !( option.pieces ? option.pieces.length > 0 : option.splitNumber > 0 ) || option.calculable ) ) ? 'continuous' : 'piecewise'; }); /***/ }, /* 336 */ /***/ function(module, exports, __webpack_require__) { /** * @file Data range visual coding. */ var echarts = __webpack_require__(1); var visualSolution = __webpack_require__(309); var VisualMapping = __webpack_require__(194); var zrUtil = __webpack_require__(4); echarts.registerVisual(echarts.PRIORITY.VISUAL.COMPONENT, function (ecModel) { ecModel.eachComponent('visualMap', function (visualMapModel) { processSingleVisualMap(visualMapModel, ecModel); }); prepareVisualMeta(ecModel); }); function processSingleVisualMap(visualMapModel, ecModel) { visualMapModel.eachTargetSeries(function (seriesModel) { var data = seriesModel.getData(); visualSolution.applyVisual( visualMapModel.stateList, visualMapModel.targetVisuals, data, visualMapModel.getValueState, visualMapModel, visualMapModel.getDataDimension(data) ); }); } // Only support color. function prepareVisualMeta(ecModel) { ecModel.eachSeries(function (seriesModel) { var data = seriesModel.getData(); var visualMetaList = []; ecModel.eachComponent('visualMap', function (visualMapModel) { if (visualMapModel.isTargetSeries(seriesModel)) { var visualMeta = visualMapModel.getVisualMeta( zrUtil.bind(getColorVisual, null, seriesModel, visualMapModel) ) || {stops: [], outerColors: []}; visualMeta.dimension = visualMapModel.getDataDimension(data); visualMetaList.push(visualMeta); } }); // console.log(JSON.stringify(visualMetaList.map(a => a.stops))); seriesModel.getData().setVisual('visualMeta', visualMetaList); }); } // FIXME // performance and export for heatmap? // value can be Infinity or -Infinity function getColorVisual(seriesModel, visualMapModel, value, valueState) { var mappings = visualMapModel.targetVisuals[valueState]; var visualTypes = VisualMapping.prepareVisualTypes(mappings); var resultVisual = { color: seriesModel.getData().getVisual('color') // default color. }; for (var i = 0, len = visualTypes.length; i < len; i++) { var type = visualTypes[i]; var mapping = mappings[ type === 'opacity' ? '__alphaForOpacity' : type ]; mapping && mapping.applyVisual(value, getVisual, setVisual); } return resultVisual.color; function getVisual(key) { return resultVisual[key]; } function setVisual(key, value) { resultVisual[key] = value; } } /***/ }, /* 337 */ /***/ function(module, exports, __webpack_require__) { /** * @file Data zoom model */ var VisualMapModel = __webpack_require__(338); var zrUtil = __webpack_require__(4); var numberUtil = __webpack_require__(7); // Constant var DEFAULT_BAR_BOUND = [20, 140]; var ContinuousModel = VisualMapModel.extend({ type: 'visualMap.continuous', /** * @protected */ defaultOption: { align: 'auto', // 'auto', 'left', 'right', 'top', 'bottom' calculable: false, // This prop effect default component type determine, // See echarts/component/visualMap/typeDefaulter. range: null, // selected range. In default case `range` is [min, max] // and can auto change along with modification of min max, // util use specifid a range. realtime: true, // Whether realtime update. itemHeight: null, // The length of the range control edge. itemWidth: null, // The length of the other side. hoverLink: true, // Enable hover highlight. hoverLinkDataSize: null,// The size of hovered data. hoverLinkOnHandle: true // Whether trigger hoverLink when hover handle. }, /** * @override */ optionUpdated: function (newOption, isInit) { ContinuousModel.superApply(this, 'optionUpdated', arguments); this.resetTargetSeries(); this.resetExtent(); this.resetVisual(function (mappingOption) { mappingOption.mappingMethod = 'linear'; mappingOption.dataExtent = this.getExtent(); }); this._resetRange(); }, /** * @protected * @override */ resetItemSize: function () { ContinuousModel.superApply(this, 'resetItemSize', arguments); var itemSize = this.itemSize; this._orient === 'horizontal' && itemSize.reverse(); (itemSize[0] == null || isNaN(itemSize[0])) && (itemSize[0] = DEFAULT_BAR_BOUND[0]); (itemSize[1] == null || isNaN(itemSize[1])) && (itemSize[1] = DEFAULT_BAR_BOUND[1]); }, /** * @private */ _resetRange: function () { var dataExtent = this.getExtent(); var range = this.option.range; if (!range || range.auto) { // `range` should always be array (so we dont use other // value like 'auto') for user-friend. (consider getOption). dataExtent.auto = 1; this.option.range = dataExtent; } else if (zrUtil.isArray(range)) { if (range[0] > range[1]) { range.reverse(); } range[0] = Math.max(range[0], dataExtent[0]); range[1] = Math.min(range[1], dataExtent[1]); } }, /** * @protected * @override */ completeVisualOption: function () { VisualMapModel.prototype.completeVisualOption.apply(this, arguments); zrUtil.each(this.stateList, function (state) { var symbolSize = this.option.controller[state].symbolSize; if (symbolSize && symbolSize[0] !== symbolSize[1]) { symbolSize[0] = 0; // For good looking. } }, this); }, /** * @override */ setSelected: function (selected) { this.option.range = selected.slice(); this._resetRange(); }, /** * @public */ getSelected: function () { var dataExtent = this.getExtent(); var dataInterval = numberUtil.asc( (this.get('range') || []).slice() ); // Clamp dataInterval[0] > dataExtent[1] && (dataInterval[0] = dataExtent[1]); dataInterval[1] > dataExtent[1] && (dataInterval[1] = dataExtent[1]); dataInterval[0] < dataExtent[0] && (dataInterval[0] = dataExtent[0]); dataInterval[1] < dataExtent[0] && (dataInterval[1] = dataExtent[0]); return dataInterval; }, /** * @override */ getValueState: function (value) { var range = this.option.range; var dataExtent = this.getExtent(); // When range[0] === dataExtent[0], any value larger than dataExtent[0] maps to 'inRange'. // range[1] is processed likewise. return ( (range[0] <= dataExtent[0] || range[0] <= value) && (range[1] >= dataExtent[1] || value <= range[1]) ) ? 'inRange' : 'outOfRange'; }, /** * @params {Array.} range target value: range[0] <= value && value <= range[1] * @return {Array.} [{seriesId, dataIndices: >}, ...] */ findTargetDataIndices: function (range) { var result = []; this.eachTargetSeries(function (seriesModel) { var dataIndices = []; var data = seriesModel.getData(); data.each(this.getDataDimension(data), function (value, dataIndex) { range[0] <= value && value <= range[1] && dataIndices.push(dataIndex); }, true, this); result.push({seriesId: seriesModel.id, dataIndex: dataIndices}); }, this); return result; }, /** * @implement */ getVisualMeta: function (getColorVisual) { var oVals = getColorStopValues(this, 'outOfRange', this.getExtent()); var iVals = getColorStopValues(this, 'inRange', this.option.range.slice()); var stops = []; function setStop(value, valueState) { stops.push({ value: value, color: getColorVisual(value, valueState) }); } // Format to: outOfRange -- inRange -- outOfRange. var iIdx = 0; var oIdx = 0; var iLen = iVals.length; var oLen = oVals.length; for (; oIdx < oLen && (!iVals.length || oVals[oIdx] <= iVals[0]); oIdx++) { // If oVal[oIdx] === iVals[iIdx], oVal[oIdx] should be ignored. if (oVals[oIdx] < iVals[iIdx]) { setStop(oVals[oIdx], 'outOfRange'); } } for (var first = 1; iIdx < iLen; iIdx++, first = 0) { // If range is full, value beyond min, max will be clamped. // make a singularity first && stops.length && setStop(iVals[iIdx], 'outOfRange'); setStop(iVals[iIdx], 'inRange'); } for (var first = 1; oIdx < oLen; oIdx++) { if (!iVals.length || iVals[iVals.length - 1] < oVals[oIdx]) { // make a singularity if (first) { stops.length && setStop(stops[stops.length - 1].value, 'outOfRange'); first = 0; } setStop(oVals[oIdx], 'outOfRange'); } } var stopsLen = stops.length; return { stops: stops, outerColors: [ stopsLen ? stops[0].color : 'transparent', stopsLen ? stops[stopsLen - 1].color : 'transparent' ] }; } }); function getColorStopValues(visualMapModel, valueState, dataExtent) { if (dataExtent[0] === dataExtent[1]) { return dataExtent.slice(); } // When using colorHue mapping, it is not linear color any more. // Moreover, canvas gradient seems not to be accurate linear. // FIXME // Should be arbitrary value 100? or based on pixel size? var count = 200; var step = (dataExtent[1] - dataExtent[0]) / count; var value = dataExtent[0]; var stopValues = []; for (var i = 0; i <= count && value < dataExtent[1]; i++) { stopValues.push(value); value += step; } stopValues.push(dataExtent[1]); return stopValues; } module.exports = ContinuousModel; /***/ }, /* 338 */ /***/ function(module, exports, __webpack_require__) { /** * @file Controller visual map model */ var echarts = __webpack_require__(1); var zrUtil = __webpack_require__(4); var env = __webpack_require__(2); var visualDefault = __webpack_require__(339); var VisualMapping = __webpack_require__(194); var visualSolution = __webpack_require__(309); var mapVisual = VisualMapping.mapVisual; var modelUtil = __webpack_require__(5); var eachVisual = VisualMapping.eachVisual; var numberUtil = __webpack_require__(7); var isArray = zrUtil.isArray; var each = zrUtil.each; var asc = numberUtil.asc; var linearMap = numberUtil.linearMap; var noop = zrUtil.noop; var DEFAULT_COLOR = ['#f6efa6', '#d88273', '#bf444c']; var VisualMapModel = echarts.extendComponentModel({ type: 'visualMap', dependencies: ['series'], /** * @readOnly * @type {Array.} */ stateList: ['inRange', 'outOfRange'], /** * @readOnly * @type {Array.} */ replacableOptionKeys: [ 'inRange', 'outOfRange', 'target', 'controller', 'color' ], /** * [lowerBound, upperBound] * * @readOnly * @type {Array.} */ dataBound: [-Infinity, Infinity], /** * @readOnly * @type {string|Object} */ layoutMode: {type: 'box', ignoreSize: true}, /** * @protected */ defaultOption: { show: true, zlevel: 0, z: 4, seriesIndex: null, // 所控制的series indices,默认所有有value的series. // set min: 0, max: 200, only for campatible with ec2. // In fact min max should not have default value. min: 0, // min value, must specified if pieces is not specified. max: 200, // max value, must specified if pieces is not specified. dimension: null, inRange: null, // 'color', 'colorHue', 'colorSaturation', 'colorLightness', 'colorAlpha', // 'symbol', 'symbolSize' outOfRange: null, // 'color', 'colorHue', 'colorSaturation', // 'colorLightness', 'colorAlpha', // 'symbol', 'symbolSize' left: 0, // 'center' ¦ 'left' ¦ 'right' ¦ {number} (px) right: null, // The same as left. top: null, // 'top' ¦ 'bottom' ¦ 'center' ¦ {number} (px) bottom: 0, // The same as top. itemWidth: null, itemHeight: null, inverse: false, orient: 'vertical', // 'horizontal' ¦ 'vertical' backgroundColor: 'rgba(0,0,0,0)', borderColor: '#ccc', // 值域边框颜色 contentColor: '#5793f3', inactiveColor: '#aaa', borderWidth: 0, // 值域边框线宽,单位px,默认为0(无边框) padding: 5, // 值域内边距,单位px,默认各方向内边距为5, // 接受数组分别设定上右下左边距,同css textGap: 10, // precision: 0, // 小数精度,默认为0,无小数点 color: null, //颜色(deprecated,兼容ec2,顺序同pieces,不同于inRange/outOfRange) formatter: null, text: null, // 文本,如['高', '低'],兼容ec2,text[0]对应高值,text[1]对应低值 textStyle: { color: '#333' // 值域文字颜色 } }, /** * @protected */ init: function (option, parentModel, ecModel) { /** * @private * @type {Array.} */ this._dataExtent; /** * @readOnly */ this.targetVisuals = {}; /** * @readOnly */ this.controllerVisuals = {}; /** * @readOnly */ this.textStyleModel; /** * [width, height] * @readOnly * @type {Array.} */ this.itemSize; this.mergeDefaultAndTheme(option, ecModel); }, /** * @protected */ optionUpdated: function (newOption, isInit) { var thisOption = this.option; // FIXME // necessary? // Disable realtime view update if canvas is not supported. if (!env.canvasSupported) { thisOption.realtime = false; } !isInit && visualSolution.replaceVisualOption( thisOption, newOption, this.replacableOptionKeys ); this.textStyleModel = this.getModel('textStyle'); this.resetItemSize(); this.completeVisualOption(); }, /** * @protected */ resetVisual: function (supplementVisualOption) { var stateList = this.stateList; supplementVisualOption = zrUtil.bind(supplementVisualOption, this); this.controllerVisuals = visualSolution.createVisualMappings( this.option.controller, stateList, supplementVisualOption ); this.targetVisuals = visualSolution.createVisualMappings( this.option.target, stateList, supplementVisualOption ); }, /** * @protected */ resetTargetSeries: function () { var thisOption = this.option; var allSeriesIndex = thisOption.seriesIndex == null; thisOption.seriesIndex = allSeriesIndex ? [] : modelUtil.normalizeToArray(thisOption.seriesIndex); allSeriesIndex && this.ecModel.eachSeries(function (seriesModel, index) { thisOption.seriesIndex.push(index); }); }, /** * @public */ eachTargetSeries: function (callback, context) { zrUtil.each(this.option.seriesIndex, function (seriesIndex) { callback.call(context, this.ecModel.getSeriesByIndex(seriesIndex)); }, this); }, /** * @pubilc */ isTargetSeries: function (seriesModel) { var is = false; this.eachTargetSeries(function (model) { model === seriesModel && (is = true); }); return is; }, /** * @example * this.formatValueText(someVal); // format single numeric value to text. * this.formatValueText(someVal, true); // format single category value to text. * this.formatValueText([min, max]); // format numeric min-max to text. * this.formatValueText([this.dataBound[0], max]); // using data lower bound. * this.formatValueText([min, this.dataBound[1]]); // using data upper bound. * * @param {number|Array.} value Real value, or this.dataBound[0 or 1]. * @param {boolean} [isCategory=false] Only available when value is number. * @param {Array.} edgeSymbols Open-close symbol when value is interval. * @return {string} * @protected */ formatValueText: function(value, isCategory, edgeSymbols) { var option = this.option; var precision = option.precision; var dataBound = this.dataBound; var formatter = option.formatter; var isMinMax; var textValue; edgeSymbols = edgeSymbols || ['<', '>']; if (zrUtil.isArray(value)) { value = value.slice(); isMinMax = true; } textValue = isCategory ? value : (isMinMax ? [toFixed(value[0]), toFixed(value[1])] : toFixed(value) ); if (zrUtil.isString(formatter)) { return formatter .replace('{value}', isMinMax ? textValue[0] : textValue) .replace('{value2}', isMinMax ? textValue[1] : textValue); } else if (zrUtil.isFunction(formatter)) { return isMinMax ? formatter(value[0], value[1]) : formatter(value); } if (isMinMax) { if (value[0] === dataBound[0]) { return edgeSymbols[0] + ' ' + textValue[1]; } else if (value[1] === dataBound[1]) { return edgeSymbols[1] + ' ' + textValue[0]; } else { return textValue[0] + ' - ' + textValue[1]; } } else { // Format single value (includes category case). return textValue; } function toFixed(val) { return val === dataBound[0] ? 'min' : val === dataBound[1] ? 'max' : (+val).toFixed(precision); } }, /** * @protected */ resetExtent: function () { var thisOption = this.option; // Can not calculate data extent by data here. // Because series and data may be modified in processing stage. // So we do not support the feature "auto min/max". var extent = asc([thisOption.min, thisOption.max]); this._dataExtent = extent; }, /** * @public * @param {module:echarts/data/List} list * @return {string} Concrete dimention. If return null/undefined, * no dimension used. */ getDataDimension: function (list) { var optDim = this.option.dimension; return optDim != null ? optDim : list.dimensions.length - 1; }, /** * @public * @override */ getExtent: function () { return this._dataExtent.slice(); }, /** * @protected */ completeVisualOption: function () { var thisOption = this.option; var base = {inRange: thisOption.inRange, outOfRange: thisOption.outOfRange}; var target = thisOption.target || (thisOption.target = {}); var controller = thisOption.controller || (thisOption.controller = {}); zrUtil.merge(target, base); // Do not override zrUtil.merge(controller, base); // Do not override var isCategory = this.isCategory(); completeSingle.call(this, target); completeSingle.call(this, controller); completeInactive.call(this, target, 'inRange', 'outOfRange'); // completeInactive.call(this, target, 'outOfRange', 'inRange'); completeController.call(this, controller); function completeSingle(base) { // Compatible with ec2 dataRange.color. // The mapping order of dataRange.color is: [high value, ..., low value] // whereas inRange.color and outOfRange.color is [low value, ..., high value] // Notice: ec2 has no inverse. if (isArray(thisOption.color) // If there has been inRange: {symbol: ...}, adding color is a mistake. // So adding color only when no inRange defined. && !base.inRange ) { base.inRange = {color: thisOption.color.slice().reverse()}; } // Compatible with previous logic, always give a defautl color, otherwise // simple config with no inRange and outOfRange will not work. // Originally we use visualMap.color as the default color, but setOption at // the second time the default color will be erased. So we change to use // constant DEFAULT_COLOR. // If user do not want the defualt color, set inRange: {color: null}. base.inRange = base.inRange || {color: DEFAULT_COLOR}; // If using shortcut like: {inRange: 'symbol'}, complete default value. each(this.stateList, function (state) { var visualType = base[state]; if (zrUtil.isString(visualType)) { var defa = visualDefault.get(visualType, 'active', isCategory); if (defa) { base[state] = {}; base[state][visualType] = defa; } else { // Mark as not specified. delete base[state]; } } }, this); } function completeInactive(base, stateExist, stateAbsent) { var optExist = base[stateExist]; var optAbsent = base[stateAbsent]; if (optExist && !optAbsent) { optAbsent = base[stateAbsent] = {}; each(optExist, function (visualData, visualType) { if (!VisualMapping.isValidType(visualType)) { return; } var defa = visualDefault.get(visualType, 'inactive', isCategory); if (defa != null) { optAbsent[visualType] = defa; // Compatibable with ec2: // Only inactive color to rgba(0,0,0,0) can not // make label transparent, so use opacity also. if (visualType === 'color' && !optAbsent.hasOwnProperty('opacity') && !optAbsent.hasOwnProperty('colorAlpha') ) { optAbsent.opacity = [0, 0]; } } }); } } function completeController(controller) { var symbolExists = (controller.inRange || {}).symbol || (controller.outOfRange || {}).symbol; var symbolSizeExists = (controller.inRange || {}).symbolSize || (controller.outOfRange || {}).symbolSize; var inactiveColor = this.get('inactiveColor'); each(this.stateList, function (state) { var itemSize = this.itemSize; var visuals = controller[state]; // Set inactive color for controller if no other color // attr (like colorAlpha) specified. if (!visuals) { visuals = controller[state] = { color: isCategory ? inactiveColor : [inactiveColor] }; } // Consistent symbol and symbolSize if not specified. if (visuals.symbol == null) { visuals.symbol = symbolExists && zrUtil.clone(symbolExists) || (isCategory ? 'roundRect' : ['roundRect']); } if (visuals.symbolSize == null) { visuals.symbolSize = symbolSizeExists && zrUtil.clone(symbolSizeExists) || (isCategory ? itemSize[0] : [itemSize[0], itemSize[0]]); } // Filter square and none. visuals.symbol = mapVisual(visuals.symbol, function (symbol) { return (symbol === 'none' || symbol === 'square') ? 'roundRect' : symbol; }); // Normalize symbolSize var symbolSize = visuals.symbolSize; if (symbolSize != null) { var max = -Infinity; // symbolSize can be object when categories defined. eachVisual(symbolSize, function (value) { value > max && (max = value); }); visuals.symbolSize = mapVisual(symbolSize, function (value) { return linearMap(value, [0, max], [0, itemSize[0]], true); }); } }, this); } }, /** * @protected */ resetItemSize: function () { this.itemSize = [ parseFloat(this.get('itemWidth')), parseFloat(this.get('itemHeight')) ]; }, /** * @public */ isCategory: function () { return !!this.option.categories; }, /** * @public * @abstract */ setSelected: noop, /** * @public * @abstract * @param {*|module:echarts/data/List} valueOrData * @param {number} dataIndex * @return {string} state See this.stateList */ getValueState: noop, /** * FIXME * Do not publish to thirt-part-dev temporarily * util the interface is stable. (Should it return * a function but not visual meta?) * * @pubilc * @abstract * @param {Function} getColorVisual * params: value, valueState * return: color * @return {Object} visualMeta * should includes {stops, outerColors} * outerColor means [colorBeyondMinValue, colorBeyondMaxValue] */ getVisualMeta: noop }); module.exports = VisualMapModel; /***/ }, /* 339 */ /***/ function(module, exports, __webpack_require__) { /** * @file Visual mapping. */ var zrUtil = __webpack_require__(4); var visualDefault = { /** * @public */ get: function (visualType, key, isCategory) { var value = zrUtil.clone( (defaultOption[visualType] || {})[key] ); return isCategory ? (zrUtil.isArray(value) ? value[value.length - 1] : value) : value; } }; var defaultOption = { color: { active: ['#006edd', '#e0ffff'], inactive: ['rgba(0,0,0,0)'] }, colorHue: { active: [0, 360], inactive: [0, 0] }, colorSaturation: { active: [0.3, 1], inactive: [0, 0] }, colorLightness: { active: [0.9, 0.5], inactive: [0, 0] }, colorAlpha: { active: [0.3, 1], inactive: [0, 0] }, opacity: { active: [0.3, 1], inactive: [0, 0] }, symbol: { active: ['circle', 'roundRect', 'diamond'], inactive: ['none'] }, symbolSize: { active: [10, 50], inactive: [0, 0] } }; module.exports = visualDefault; /***/ }, /* 340 */ /***/ function(module, exports, __webpack_require__) { var VisualMapView = __webpack_require__(341); var graphic = __webpack_require__(43); var zrUtil = __webpack_require__(4); var numberUtil = __webpack_require__(7); var sliderMove = __webpack_require__(326); var LinearGradient = __webpack_require__(78); var helper = __webpack_require__(342); var modelUtil = __webpack_require__(5); var linearMap = numberUtil.linearMap; var each = zrUtil.each; var mathMin = Math.min; var mathMax = Math.max; // Arbitrary value var HOVER_LINK_SIZE = 12; var HOVER_LINK_OUT = 6; // Notice: // Any "interval" should be by the order of [low, high]. // "handle0" (handleIndex === 0) maps to // low data value: this._dataInterval[0] and has low coord. // "handle1" (handleIndex === 1) maps to // high data value: this._dataInterval[1] and has high coord. // The logic of transform is implemented in this._createBarGroup. var ContinuousView = VisualMapView.extend({ type: 'visualMap.continuous', /** * @override */ init: function () { ContinuousView.superApply(this, 'init', arguments); /** * @private */ this._shapes = {}; /** * @private */ this._dataInterval = []; /** * @private */ this._handleEnds = []; /** * @private */ this._orient; /** * @private */ this._useHandle; /** * @private */ this._hoverLinkDataIndices = []; /** * @private */ this._dragging; /** * @private */ this._hovering; }, /** * @protected * @override */ doRender: function (visualMapModel, ecModel, api, payload) { if (!payload || payload.type !== 'selectDataRange' || payload.from !== this.uid) { this._buildView(); } }, /** * @private */ _buildView: function () { this.group.removeAll(); var visualMapModel = this.visualMapModel; var thisGroup = this.group; this._orient = visualMapModel.get('orient'); this._useHandle = visualMapModel.get('calculable'); this._resetInterval(); this._renderBar(thisGroup); var dataRangeText = visualMapModel.get('text'); this._renderEndsText(thisGroup, dataRangeText, 0); this._renderEndsText(thisGroup, dataRangeText, 1); // Do this for background size calculation. this._updateView(true); // After updating view, inner shapes is built completely, // and then background can be rendered. this.renderBackground(thisGroup); // Real update view this._updateView(); this._enableHoverLinkToSeries(); this._enableHoverLinkFromSeries(); this.positionGroup(thisGroup); }, /** * @private */ _renderEndsText: function (group, dataRangeText, endsIndex) { if (!dataRangeText) { return; } // Compatible with ec2, text[0] map to high value, text[1] map low value. var text = dataRangeText[1 - endsIndex]; text = text != null ? text + '' : ''; var visualMapModel = this.visualMapModel; var textGap = visualMapModel.get('textGap'); var itemSize = visualMapModel.itemSize; var barGroup = this._shapes.barGroup; var position = this._applyTransform( [ itemSize[0] / 2, endsIndex === 0 ? -textGap : itemSize[1] + textGap ], barGroup ); var align = this._applyTransform( endsIndex === 0 ? 'bottom' : 'top', barGroup ); var orient = this._orient; var textStyleModel = this.visualMapModel.textStyleModel; this.group.add(new graphic.Text({ style: { x: position[0], y: position[1], textVerticalAlign: orient === 'horizontal' ? 'middle' : align, textAlign: orient === 'horizontal' ? align : 'center', text: text, textFont: textStyleModel.getFont(), fill: textStyleModel.getTextColor() } })); }, /** * @private */ _renderBar: function (targetGroup) { var visualMapModel = this.visualMapModel; var shapes = this._shapes; var itemSize = visualMapModel.itemSize; var orient = this._orient; var useHandle = this._useHandle; var itemAlign = helper.getItemAlign(visualMapModel, this.api, itemSize); var barGroup = shapes.barGroup = this._createBarGroup(itemAlign); // Bar barGroup.add(shapes.outOfRange = createPolygon()); barGroup.add(shapes.inRange = createPolygon( null, useHandle ? 'move' : null, zrUtil.bind(this._dragHandle, this, 'all', false), zrUtil.bind(this._dragHandle, this, 'all', true) )); var textRect = visualMapModel.textStyleModel.getTextRect('国'); var textSize = mathMax(textRect.width, textRect.height); // Handle if (useHandle) { shapes.handleThumbs = []; shapes.handleLabels = []; shapes.handleLabelPoints = []; this._createHandle(barGroup, 0, itemSize, textSize, orient, itemAlign); this._createHandle(barGroup, 1, itemSize, textSize, orient, itemAlign); } this._createIndicator(barGroup, itemSize, textSize, orient); targetGroup.add(barGroup); }, /** * @private */ _createHandle: function (barGroup, handleIndex, itemSize, textSize, orient) { var onDrift = zrUtil.bind(this._dragHandle, this, handleIndex, false); var onDragEnd = zrUtil.bind(this._dragHandle, this, handleIndex, true); var handleThumb = createPolygon( createHandlePoints(handleIndex, textSize), 'move', onDrift, onDragEnd ); handleThumb.position[0] = itemSize[0]; barGroup.add(handleThumb); // Text is always horizontal layout but should not be effected by // transform (orient/inverse). So label is built separately but not // use zrender/graphic/helper/RectText, and is located based on view // group (according to handleLabelPoint) but not barGroup. var textStyleModel = this.visualMapModel.textStyleModel; var handleLabel = new graphic.Text({ draggable: true, drift: onDrift, ondragend: onDragEnd, style: { x: 0, y: 0, text: '', textFont: textStyleModel.getFont(), fill: textStyleModel.getTextColor() } }); this.group.add(handleLabel); var handleLabelPoint = [ orient === 'horizontal' ? textSize / 2 : textSize * 1.5, orient === 'horizontal' ? (handleIndex === 0 ? -(textSize * 1.5) : (textSize * 1.5)) : (handleIndex === 0 ? -textSize / 2 : textSize / 2) ]; var shapes = this._shapes; shapes.handleThumbs[handleIndex] = handleThumb; shapes.handleLabelPoints[handleIndex] = handleLabelPoint; shapes.handleLabels[handleIndex] = handleLabel; }, /** * @private */ _createIndicator: function (barGroup, itemSize, textSize, orient) { var indicator = createPolygon([[0, 0]], 'move'); indicator.position[0] = itemSize[0]; indicator.attr({invisible: true, silent: true}); barGroup.add(indicator); var textStyleModel = this.visualMapModel.textStyleModel; var indicatorLabel = new graphic.Text({ silent: true, invisible: true, style: { x: 0, y: 0, text: '', textFont: textStyleModel.getFont(), fill: textStyleModel.getTextColor() } }); this.group.add(indicatorLabel); var indicatorLabelPoint = [ orient === 'horizontal' ? textSize / 2 : HOVER_LINK_OUT + 3, 0 ]; var shapes = this._shapes; shapes.indicator = indicator; shapes.indicatorLabel = indicatorLabel; shapes.indicatorLabelPoint = indicatorLabelPoint; }, /** * @private */ _dragHandle: function (handleIndex, isEnd, dx, dy) { if (!this._useHandle) { return; } this._dragging = !isEnd; if (!isEnd) { // Transform dx, dy to bar coordination. var vertex = this._applyTransform([dx, dy], this._shapes.barGroup, true); this._updateInterval(handleIndex, vertex[1]); // Considering realtime, update view should be executed // before dispatch action. this._updateView(); } // dragEnd do not dispatch action when realtime. if (isEnd === !this.visualMapModel.get('realtime')) { // jshint ignore:line this.api.dispatchAction({ type: 'selectDataRange', from: this.uid, visualMapId: this.visualMapModel.id, selected: this._dataInterval.slice() }); } if (isEnd) { !this._hovering && this._clearHoverLinkToSeries(); } else if (useHoverLinkOnHandle(this.visualMapModel)) { this._doHoverLinkToSeries(this._handleEnds[handleIndex], false); } }, /** * @private */ _resetInterval: function () { var visualMapModel = this.visualMapModel; var dataInterval = this._dataInterval = visualMapModel.getSelected(); var dataExtent = visualMapModel.getExtent(); var sizeExtent = [0, visualMapModel.itemSize[1]]; this._handleEnds = [ linearMap(dataInterval[0], dataExtent, sizeExtent, true), linearMap(dataInterval[1], dataExtent, sizeExtent, true) ]; }, /** * @private * @param {(number|string)} handleIndex 0 or 1 or 'all' * @param {number} dx * @param {number} dy */ _updateInterval: function (handleIndex, delta) { delta = delta || 0; var visualMapModel = this.visualMapModel; var handleEnds = this._handleEnds; sliderMove( delta, handleEnds, [0, visualMapModel.itemSize[1]], handleIndex === 'all' ? 'rigid' : 'push', handleIndex ); var dataExtent = visualMapModel.getExtent(); var sizeExtent = [0, visualMapModel.itemSize[1]]; // Update data interval. this._dataInterval = [ linearMap(handleEnds[0], sizeExtent, dataExtent, true), linearMap(handleEnds[1], sizeExtent, dataExtent, true) ]; }, /** * @private */ _updateView: function (forSketch) { var visualMapModel = this.visualMapModel; var dataExtent = visualMapModel.getExtent(); var shapes = this._shapes; var outOfRangeHandleEnds = [0, visualMapModel.itemSize[1]]; var inRangeHandleEnds = forSketch ? outOfRangeHandleEnds : this._handleEnds; var visualInRange = this._createBarVisual( this._dataInterval, dataExtent, inRangeHandleEnds, 'inRange' ); var visualOutOfRange = this._createBarVisual( dataExtent, dataExtent, outOfRangeHandleEnds, 'outOfRange' ); shapes.inRange .setStyle({ fill: visualInRange.barColor, opacity: visualInRange.opacity }) .setShape('points', visualInRange.barPoints); shapes.outOfRange .setStyle({ fill: visualOutOfRange.barColor, opacity: visualOutOfRange.opacity }) .setShape('points', visualOutOfRange.barPoints); this._updateHandle(inRangeHandleEnds, visualInRange); }, /** * @private */ _createBarVisual: function (dataInterval, dataExtent, handleEnds, forceState) { var opts = { forceState: forceState, convertOpacityToAlpha: true }; var colorStops = this._makeColorGradient(dataInterval, opts); var symbolSizes = [ this.getControllerVisual(dataInterval[0], 'symbolSize', opts), this.getControllerVisual(dataInterval[1], 'symbolSize', opts) ]; var barPoints = this._createBarPoints(handleEnds, symbolSizes); return { barColor: new LinearGradient(0, 0, 0, 1, colorStops), barPoints: barPoints, handlesColor: [ colorStops[0].color, colorStops[colorStops.length - 1].color ] }; }, /** * @private */ _makeColorGradient: function (dataInterval, opts) { // Considering colorHue, which is not linear, so we have to sample // to calculate gradient color stops, but not only caculate head // and tail. var sampleNumber = 100; // Arbitrary value. var colorStops = []; var step = (dataInterval[1] - dataInterval[0]) / sampleNumber; colorStops.push({ color: this.getControllerVisual(dataInterval[0], 'color', opts), offset: 0 }); for (var i = 1; i < sampleNumber; i++) { var currValue = dataInterval[0] + step * i; if (currValue > dataInterval[1]) { break; } colorStops.push({ color: this.getControllerVisual(currValue, 'color', opts), offset: i / sampleNumber }); } colorStops.push({ color: this.getControllerVisual(dataInterval[1], 'color', opts), offset: 1 }); return colorStops; }, /** * @private */ _createBarPoints: function (handleEnds, symbolSizes) { var itemSize = this.visualMapModel.itemSize; return [ [itemSize[0] - symbolSizes[0], handleEnds[0]], [itemSize[0], handleEnds[0]], [itemSize[0], handleEnds[1]], [itemSize[0] - symbolSizes[1], handleEnds[1]] ]; }, /** * @private */ _createBarGroup: function (itemAlign) { var orient = this._orient; var inverse = this.visualMapModel.get('inverse'); return new graphic.Group( (orient === 'horizontal' && !inverse) ? {scale: itemAlign === 'bottom' ? [1, 1] : [-1, 1], rotation: Math.PI / 2} : (orient === 'horizontal' && inverse) ? {scale: itemAlign === 'bottom' ? [-1, 1] : [1, 1], rotation: -Math.PI / 2} : (orient === 'vertical' && !inverse) ? {scale: itemAlign === 'left' ? [1, -1] : [-1, -1]} : {scale: itemAlign === 'left' ? [1, 1] : [-1, 1]} ); }, /** * @private */ _updateHandle: function (handleEnds, visualInRange) { if (!this._useHandle) { return; } var shapes = this._shapes; var visualMapModel = this.visualMapModel; var handleThumbs = shapes.handleThumbs; var handleLabels = shapes.handleLabels; each([0, 1], function (handleIndex) { var handleThumb = handleThumbs[handleIndex]; handleThumb.setStyle('fill', visualInRange.handlesColor[handleIndex]); handleThumb.position[1] = handleEnds[handleIndex]; // Update handle label position. var textPoint = graphic.applyTransform( shapes.handleLabelPoints[handleIndex], graphic.getTransform(handleThumb, this.group) ); handleLabels[handleIndex].setStyle({ x: textPoint[0], y: textPoint[1], text: visualMapModel.formatValueText(this._dataInterval[handleIndex]), textVerticalAlign: 'middle', textAlign: this._applyTransform( this._orient === 'horizontal' ? (handleIndex === 0 ? 'bottom' : 'top') : 'left', shapes.barGroup ) }); }, this); }, /** * @private * @param {number} cursorValue * @param {number} textValue * @param {string} [rangeSymbol] * @param {number} [halfHoverLinkSize] */ _showIndicator: function (cursorValue, textValue, rangeSymbol, halfHoverLinkSize) { var visualMapModel = this.visualMapModel; var dataExtent = visualMapModel.getExtent(); var itemSize = visualMapModel.itemSize; var sizeExtent = [0, itemSize[1]]; var pos = linearMap(cursorValue, dataExtent, sizeExtent, true); var shapes = this._shapes; var indicator = shapes.indicator; if (!indicator) { return; } indicator.position[1] = pos; indicator.attr('invisible', false); indicator.setShape('points', createIndicatorPoints( !!rangeSymbol, halfHoverLinkSize, pos, itemSize[1] )); var opts = {convertOpacityToAlpha: true}; var color = this.getControllerVisual(cursorValue, 'color', opts); indicator.setStyle('fill', color); // Update handle label position. var textPoint = graphic.applyTransform( shapes.indicatorLabelPoint, graphic.getTransform(indicator, this.group) ); var indicatorLabel = shapes.indicatorLabel; indicatorLabel.attr('invisible', false); var align = this._applyTransform('left', shapes.barGroup); var orient = this._orient; indicatorLabel.setStyle({ text: (rangeSymbol ? rangeSymbol : '') + visualMapModel.formatValueText(textValue), textVerticalAlign: orient === 'horizontal' ? align : 'middle', textAlign: orient === 'horizontal' ? 'center' : align, x: textPoint[0], y: textPoint[1] }); }, /** * @private */ _enableHoverLinkToSeries: function () { var self = this; this._shapes.barGroup .on('mousemove', function (e) { self._hovering = true; if (!self._dragging) { var itemSize = self.visualMapModel.itemSize; var pos = self._applyTransform( [e.offsetX, e.offsetY], self._shapes.barGroup, true, true ); // For hover link show when hover handle, which might be // below or upper than sizeExtent. pos[1] = mathMin(mathMax(0, pos[1]), itemSize[1]); self._doHoverLinkToSeries( pos[1], 0 <= pos[0] && pos[0] <= itemSize[0] ); } }) .on('mouseout', function () { // When mouse is out of handle, hoverLink still need // to be displayed when realtime is set as false. self._hovering = false; !self._dragging && self._clearHoverLinkToSeries(); }); }, /** * @private */ _enableHoverLinkFromSeries: function () { var zr = this.api.getZr(); if (this.visualMapModel.option.hoverLink) { zr.on('mouseover', this._hoverLinkFromSeriesMouseOver, this); zr.on('mouseout', this._hideIndicator, this); } else { this._clearHoverLinkFromSeries(); } }, /** * @private */ _doHoverLinkToSeries: function (cursorPos, hoverOnBar) { var visualMapModel = this.visualMapModel; var itemSize = visualMapModel.itemSize; if (!visualMapModel.option.hoverLink) { return; } var sizeExtent = [0, itemSize[1]]; var dataExtent = visualMapModel.getExtent(); // For hover link show when hover handle, which might be below or upper than sizeExtent. cursorPos = mathMin(mathMax(sizeExtent[0], cursorPos), sizeExtent[1]); var halfHoverLinkSize = getHalfHoverLinkSize(visualMapModel, dataExtent, sizeExtent); var hoverRange = [cursorPos - halfHoverLinkSize, cursorPos + halfHoverLinkSize]; var cursorValue = linearMap(cursorPos, sizeExtent, dataExtent, true); var valueRange = [ linearMap(hoverRange[0], sizeExtent, dataExtent, true), linearMap(hoverRange[1], sizeExtent, dataExtent, true) ]; // Consider data range is out of visualMap range, see test/visualMap-continuous.html, // where china and india has very large population. hoverRange[0] < sizeExtent[0] && (valueRange[0] = -Infinity); hoverRange[1] > sizeExtent[1] && (valueRange[1] = Infinity); // Do not show indicator when mouse is over handle, // otherwise labels overlap, especially when dragging. if (hoverOnBar) { if (valueRange[0] === -Infinity) { this._showIndicator(cursorValue, valueRange[1], '< ', halfHoverLinkSize); } else if (valueRange[1] === Infinity) { this._showIndicator(cursorValue, valueRange[0], '> ', halfHoverLinkSize); } else { this._showIndicator(cursorValue, cursorValue, '≈ ', halfHoverLinkSize); } } // When realtime is set as false, handles, which are in barGroup, // also trigger hoverLink, which help user to realize where they // focus on when dragging. (see test/heatmap-large.html) // When realtime is set as true, highlight will not show when hover // handle, because the label on handle, which displays a exact value // but not range, might mislead users. var oldBatch = this._hoverLinkDataIndices; var newBatch = []; if (hoverOnBar || useHoverLinkOnHandle(visualMapModel)) { newBatch = this._hoverLinkDataIndices = visualMapModel.findTargetDataIndices(valueRange); } var resultBatches = modelUtil.compressBatches(oldBatch, newBatch); this._dispatchHighDown('downplay', helper.convertDataIndex(resultBatches[0])); this._dispatchHighDown('highlight', helper.convertDataIndex(resultBatches[1])); }, /** * @private */ _hoverLinkFromSeriesMouseOver: function (e) { var el = e.target; if (!el || el.dataIndex == null) { return; } var dataModel = el.dataModel || this.ecModel.getSeriesByIndex(el.seriesIndex); var data = dataModel.getData(el.dataType); var dim = data.getDimension(this.visualMapModel.getDataDimension(data)); var value = data.get(dim, el.dataIndex, true); if (!isNaN(value)) { this._showIndicator(value, value); } }, /** * @private */ _hideIndicator: function () { var shapes = this._shapes; shapes.indicator && shapes.indicator.attr('invisible', true); shapes.indicatorLabel && shapes.indicatorLabel.attr('invisible', true); }, /** * @private */ _clearHoverLinkToSeries: function () { this._hideIndicator(); var indices = this._hoverLinkDataIndices; this._dispatchHighDown('downplay', helper.convertDataIndex(indices)); indices.length = 0; }, /** * @private */ _clearHoverLinkFromSeries: function () { this._hideIndicator(); var zr = this.api.getZr(); zr.off('mouseover', this._hoverLinkFromSeriesMouseOver); zr.off('mouseout', this._hideIndicator); }, /** * @private */ _applyTransform: function (vertex, element, inverse, global) { var transform = graphic.getTransform(element, global ? null : this.group); return graphic[ zrUtil.isArray(vertex) ? 'applyTransform' : 'transformDirection' ](vertex, transform, inverse); }, /** * @private */ _dispatchHighDown: function (type, batch) { batch && batch.length && this.api.dispatchAction({ type: type, batch: batch }); }, /** * @override */ dispose: function () { this._clearHoverLinkFromSeries(); this._clearHoverLinkToSeries(); }, /** * @override */ remove: function () { this._clearHoverLinkFromSeries(); this._clearHoverLinkToSeries(); } }); function createPolygon(points, cursor, onDrift, onDragEnd) { return new graphic.Polygon({ shape: {points: points}, draggable: !!onDrift, cursor: cursor, drift: onDrift, ondragend: onDragEnd }); } function createHandlePoints(handleIndex, textSize) { return handleIndex === 0 ? [[0, 0], [textSize, 0], [textSize, -textSize]] : [[0, 0], [textSize, 0], [textSize, textSize]]; } function createIndicatorPoints(isRange, halfHoverLinkSize, pos, extentMax) { return isRange ? [ // indicate range [0, -mathMin(halfHoverLinkSize, mathMax(pos, 0))], [HOVER_LINK_OUT, 0], [0, mathMin(halfHoverLinkSize, mathMax(extentMax - pos, 0))] ] : [ // indicate single value [0, 0], [5, -5], [5, 5] ]; } function getHalfHoverLinkSize(visualMapModel, dataExtent, sizeExtent) { var halfHoverLinkSize = HOVER_LINK_SIZE / 2; var hoverLinkDataSize = visualMapModel.get('hoverLinkDataSize'); if (hoverLinkDataSize) { halfHoverLinkSize = linearMap(hoverLinkDataSize, dataExtent, sizeExtent, true) / 2; } return halfHoverLinkSize; } function useHoverLinkOnHandle(visualMapModel) { return !visualMapModel.get('realtime') && visualMapModel.get('hoverLinkOnHandle'); } module.exports = ContinuousView; /***/ }, /* 341 */ /***/ function(module, exports, __webpack_require__) { var zrUtil = __webpack_require__(4); var graphic = __webpack_require__(43); var formatUtil = __webpack_require__(6); var layout = __webpack_require__(21); var echarts = __webpack_require__(1); var VisualMapping = __webpack_require__(194); module.exports = echarts.extendComponentView({ type: 'visualMap', /** * @readOnly * @type {Object} */ autoPositionValues: {left: 1, right: 1, top: 1, bottom: 1}, init: function (ecModel, api) { /** * @readOnly * @type {module:echarts/model/Global} */ this.ecModel = ecModel; /** * @readOnly * @type {module:echarts/ExtensionAPI} */ this.api = api; /** * @readOnly * @type {module:echarts/component/visualMap/visualMapModel} */ this.visualMapModel; }, /** * @protected */ render: function (visualMapModel, ecModel, api, payload) { this.visualMapModel = visualMapModel; if (visualMapModel.get('show') === false) { this.group.removeAll(); return; } this.doRender.apply(this, arguments); }, /** * @protected */ renderBackground: function (group) { var visualMapModel = this.visualMapModel; var padding = formatUtil.normalizeCssArray(visualMapModel.get('padding') || 0); var rect = group.getBoundingRect(); group.add(new graphic.Rect({ z2: -1, // Lay background rect on the lowest layer. silent: true, shape: { x: rect.x - padding[3], y: rect.y - padding[0], width: rect.width + padding[3] + padding[1], height: rect.height + padding[0] + padding[2] }, style: { fill: visualMapModel.get('backgroundColor'), stroke: visualMapModel.get('borderColor'), lineWidth: visualMapModel.get('borderWidth') } })); }, /** * @protected * @param {number} targetValue can be Infinity or -Infinity * @param {string=} visualCluster Only can be 'color' 'opacity' 'symbol' 'symbolSize' * @param {Object} [opts] * @param {string=} [opts.forceState] Specify state, instead of using getValueState method. * @param {string=} [opts.convertOpacityToAlpha=false] For color gradient in controller widget. * @return {*} Visual value. */ getControllerVisual: function (targetValue, visualCluster, opts) { opts = opts || {}; var forceState = opts.forceState; var visualMapModel = this.visualMapModel; var visualObj = {}; // Default values. if (visualCluster === 'symbol') { visualObj.symbol = visualMapModel.get('itemSymbol'); } if (visualCluster === 'color') { var defaultColor = visualMapModel.get('contentColor'); visualObj.color = defaultColor; } function getter(key) { return visualObj[key]; } function setter(key, value) { visualObj[key] = value; } var mappings = visualMapModel.controllerVisuals[ forceState || visualMapModel.getValueState(targetValue) ]; var visualTypes = VisualMapping.prepareVisualTypes(mappings); zrUtil.each(visualTypes, function (type) { var visualMapping = mappings[type]; if (opts.convertOpacityToAlpha && type === 'opacity') { type = 'colorAlpha'; visualMapping = mappings.__alphaForOpacity; } if (VisualMapping.dependsOn(type, visualCluster)) { visualMapping && visualMapping.applyVisual( targetValue, getter, setter ); } }); return visualObj[visualCluster]; }, /** * @protected */ positionGroup: function (group) { var model = this.visualMapModel; var api = this.api; layout.positionElement( group, model.getBoxLayoutParams(), {width: api.getWidth(), height: api.getHeight()} ); }, /** * @protected * @abstract */ doRender: zrUtil.noop }); /***/ }, /* 342 */ /***/ function(module, exports, __webpack_require__) { var zrUtil = __webpack_require__(4); var layout = __webpack_require__(21); var helper = { /** * @param {module:echarts/component/visualMap/VisualMapModel} visualMapModel\ * @param {module:echarts/ExtensionAPI} api * @param {Array.} itemSize always [short, long] * @return {string} 'left' or 'right' or 'top' or 'bottom' */ getItemAlign: function (visualMapModel, api, itemSize) { var modelOption = visualMapModel.option; var itemAlign = modelOption.align; if (itemAlign != null && itemAlign !== 'auto') { return itemAlign; } // Auto decision align. var ecSize = {width: api.getWidth(), height: api.getHeight()}; var realIndex = modelOption.orient === 'horizontal' ? 1 : 0; var paramsSet = [ ['left', 'right', 'width'], ['top', 'bottom', 'height'] ]; var reals = paramsSet[realIndex]; var fakeValue = [0, null, 10]; var layoutInput = {}; for (var i = 0; i < 3; i++) { layoutInput[paramsSet[1 - realIndex][i]] = fakeValue[i]; layoutInput[reals[i]] = i === 2 ? itemSize[0] : modelOption[reals[i]]; } var rParam = [['x', 'width', 3], ['y', 'height', 0]][realIndex]; var rect = layout.getLayoutRect(layoutInput, ecSize, modelOption.padding); return reals[ (rect.margin[rParam[2]] || 0) + rect[rParam[0]] + rect[rParam[1]] * 0.5 < ecSize[rParam[1]] * 0.5 ? 0 : 1 ]; }, /** * Prepare dataIndex for outside usage, where dataIndex means rawIndex, and * dataIndexInside means filtered index. */ convertDataIndex: function (batch) { zrUtil.each(batch || [], function (batchItem) { if (batch.dataIndex != null) { batch.dataIndexInside = batch.dataIndex; batch.dataIndex = null; } }); return batch; } }; module.exports = helper; /***/ }, /* 343 */ /***/ function(module, exports, __webpack_require__) { /** * @file Data range action */ var echarts = __webpack_require__(1); var actionInfo = { type: 'selectDataRange', event: 'dataRangeSelected', // FIXME use updateView appears wrong update: 'update' }; echarts.registerAction(actionInfo, function (payload, ecModel) { ecModel.eachComponent({mainType: 'visualMap', query: payload}, function (model) { model.setSelected(payload.selected); }); }); /***/ }, /* 344 */ /***/ function(module, exports, __webpack_require__) { /** * DataZoom component entry */ __webpack_require__(1).registerPreprocessor( __webpack_require__(334) ); __webpack_require__(335); __webpack_require__(336); __webpack_require__(345); __webpack_require__(346); __webpack_require__(343); /***/ }, /* 345 */ /***/ function(module, exports, __webpack_require__) { var VisualMapModel = __webpack_require__(338); var zrUtil = __webpack_require__(4); var VisualMapping = __webpack_require__(194); var visualDefault = __webpack_require__(339); var reformIntervals = __webpack_require__(7).reformIntervals; var PiecewiseModel = VisualMapModel.extend({ type: 'visualMap.piecewise', /** * Order Rule: * * option.categories / option.pieces / option.text / option.selected: * If !option.inverse, * Order when vertical: ['top', ..., 'bottom']. * Order when horizontal: ['left', ..., 'right']. * If option.inverse, the meaning of * the order should be reversed. * * this._pieceList: * The order is always [low, ..., high]. * * Mapping from location to low-high: * If !option.inverse * When vertical, top is high. * When horizontal, right is high. * If option.inverse, reverse. */ /** * @protected */ defaultOption: { selected: null, // Object. If not specified, means selected. // When pieces and splitNumber: {'0': true, '5': true} // When categories: {'cate1': false, 'cate3': true} // When selected === false, means all unselected. minOpen: false, // Whether include values that smaller than `min`. maxOpen: false, // Whether include values that bigger than `max`. align: 'auto', // 'auto', 'left', 'right' itemWidth: 20, // When put the controller vertically, it is the length of // horizontal side of each item. Otherwise, vertical side. itemHeight: 14, // When put the controller vertically, it is the length of // vertical side of each item. Otherwise, horizontal side. itemSymbol: 'roundRect', pieceList: null, // Each item is Object, with some of those attrs: // {min, max, lt, gt, lte, gte, value, // color, colorSaturation, colorAlpha, opacity, // symbol, symbolSize}, which customize the range or visual // coding of the certain piece. Besides, see "Order Rule". categories: null, // category names, like: ['some1', 'some2', 'some3']. // Attr min/max are ignored when categories set. See "Order Rule" splitNumber: 5, // If set to 5, auto split five pieces equally. // If set to 0 and component type not set, component type will be // determined as "continuous". (It is less reasonable but for ec2 // compatibility, see echarts/component/visualMap/typeDefaulter) selectedMode: 'multiple', // Can be 'multiple' or 'single'. itemGap: 10, // The gap between two items, in px. hoverLink: true // Enable hover highlight. }, /** * @override */ optionUpdated: function (newOption, isInit) { PiecewiseModel.superApply(this, 'optionUpdated', arguments); /** * The order is always [low, ..., high]. * [{text: string, interval: Array.}, ...] * @private * @type {Array.} */ this._pieceList = []; this.resetTargetSeries(); this.resetExtent(); /** * 'pieces', 'categories', 'splitNumber' * @type {string} */ var mode = this._mode = this._determineMode(); resetMethods[this._mode].call(this); this._resetSelected(newOption, isInit); var categories = this.option.categories; this.resetVisual(function (mappingOption, state) { if (mode === 'categories') { mappingOption.mappingMethod = 'category'; mappingOption.categories = zrUtil.clone(categories); } else { mappingOption.dataExtent = this.getExtent(); mappingOption.mappingMethod = 'piecewise'; mappingOption.pieceList = zrUtil.map(this._pieceList, function (piece) { var piece = zrUtil.clone(piece); if (state !== 'inRange') { piece.visual = null; } return piece; }); } }); }, /** * @protected * @override */ completeVisualOption: function () { // Consider this case: // visualMap: { // pieces: [{symbol: 'circle', lt: 0}, {symbol: 'rect', gte: 0}] // } // where no inRange/outOfRange set but only pieces. So we should make // default inRange/outOfRange for this case, otherwise visuals that only // appear in `pieces` will not be taken into account in visual encoding. var option = this.option; var visualTypesInPieces = {}; var visualTypes = VisualMapping.listVisualTypes(); var isCategory = this.isCategory(); zrUtil.each(option.pieces, function (piece) { zrUtil.each(visualTypes, function (visualType) { if (piece.hasOwnProperty(visualType)) { visualTypesInPieces[visualType] = 1; } }); }); zrUtil.each(visualTypesInPieces, function (v, visualType) { var exists = 0; zrUtil.each(this.stateList, function (state) { exists |= has(option, state, visualType) || has(option.target, state, visualType); }, this); !exists && zrUtil.each(this.stateList, function (state) { (option[state] || (option[state] = {}))[visualType] = visualDefault.get( visualType, state === 'inRange' ? 'active' : 'inactive', isCategory ); }); }, this); function has(obj, state, visualType) { return obj && obj[state] && ( zrUtil.isObject(obj[state]) ? obj[state].hasOwnProperty(visualType) : obj[state] === visualType // e.g., inRange: 'symbol' ); } VisualMapModel.prototype.completeVisualOption.apply(this, arguments); }, _resetSelected: function (newOption, isInit) { var thisOption = this.option; var pieceList = this._pieceList; // Selected do not merge but all override. var selected = (isInit ? thisOption : newOption).selected || {}; thisOption.selected = selected; // Consider 'not specified' means true. zrUtil.each(pieceList, function (piece, index) { var key = this.getSelectedMapKey(piece); if (!selected.hasOwnProperty(key)) { selected[key] = true; } }, this); if (thisOption.selectedMode === 'single') { // Ensure there is only one selected. var hasSel = false; zrUtil.each(pieceList, function (piece, index) { var key = this.getSelectedMapKey(piece); if (selected[key]) { hasSel ? (selected[key] = false) : (hasSel = true); } }, this); } // thisOption.selectedMode === 'multiple', default: all selected. }, /** * @public */ getSelectedMapKey: function (piece) { return this._mode === 'categories' ? piece.value + '' : piece.index + ''; }, /** * @public */ getPieceList: function () { return this._pieceList; }, /** * @private * @return {string} */ _determineMode: function () { var option = this.option; return option.pieces && option.pieces.length > 0 ? 'pieces' : this.option.categories ? 'categories' : 'splitNumber'; }, /** * @public * @override */ setSelected: function (selected) { this.option.selected = zrUtil.clone(selected); }, /** * @public * @override */ getValueState: function (value) { var index = VisualMapping.findPieceIndex(value, this._pieceList); return index != null ? (this.option.selected[this.getSelectedMapKey(this._pieceList[index])] ? 'inRange' : 'outOfRange' ) : 'outOfRange'; }, /** * @public * @params {number} pieceIndex piece index in visualMapModel.getPieceList() * @return {Array.} [{seriesId, dataIndices: >}, ...] */ findTargetDataIndices: function (pieceIndex) { var result = []; this.eachTargetSeries(function (seriesModel) { var dataIndices = []; var data = seriesModel.getData(); data.each(this.getDataDimension(data), function (value, dataIndex) { // Should always base on model pieceList, because it is order sensitive. var pIdx = VisualMapping.findPieceIndex(value, this._pieceList); pIdx === pieceIndex && dataIndices.push(dataIndex); }, true, this); result.push({seriesId: seriesModel.id, dataIndex: dataIndices}); }, this); return result; }, /** * @private * @param {Object} piece piece.value or piece.interval is required. * @return {number} Can be Infinity or -Infinity */ getRepresentValue: function (piece) { var representValue; if (this.isCategory()) { representValue = piece.value; } else { if (piece.value != null) { representValue = piece.value; } else { var pieceInterval = piece.interval || []; representValue = (pieceInterval[0] === -Infinity && pieceInterval[1] === Infinity) ? 0 : (pieceInterval[0] + pieceInterval[1]) / 2; } } return representValue; }, getVisualMeta: function (getColorVisual) { // Do not support category. (category axis is ordinal, numerical) if (this.isCategory()) { return; } var stops = []; var outerColors = []; var visualMapModel = this; function setStop(interval, valueState) { var representValue = visualMapModel.getRepresentValue({interval: interval}); if (!valueState) { valueState = visualMapModel.getValueState(representValue); } var color = getColorVisual(representValue, valueState); if (interval[0] === -Infinity) { outerColors[0] = color; } else if (interval[1] === Infinity) { outerColors[1] = color; } else { stops.push( {value: interval[0], color: color}, {value: interval[1], color: color} ); } } // Suplement var pieceList = this._pieceList.slice(); if (!pieceList.length) { pieceList.push({interval: [-Infinity, Infinity]}); } else { var edge = pieceList[0].interval[0]; edge !== -Infinity && pieceList.unshift({interval: [-Infinity, edge]}); edge = pieceList[pieceList.length - 1].interval[1]; edge !== Infinity && pieceList.push({interval: [edge, Infinity]}); } var curr = -Infinity; zrUtil.each(pieceList, function (piece) { var interval = piece.interval; if (interval) { // Fulfill gap. interval[0] > curr && setStop([curr, interval[0]], 'outOfRange'); setStop(interval.slice()); curr = interval[1]; } }, this); return {stops: stops, outerColors: outerColors}; } }); /** * Key is this._mode * @type {Object} * @this {module:echarts/component/viusalMap/PiecewiseMode} */ var resetMethods = { splitNumber: function () { var thisOption = this.option; var pieceList = this._pieceList; var precision = thisOption.precision; var dataExtent = this.getExtent(); var splitNumber = thisOption.splitNumber; splitNumber = Math.max(parseInt(splitNumber, 10), 1); thisOption.splitNumber = splitNumber; var splitStep = (dataExtent[1] - dataExtent[0]) / splitNumber; // Precision auto-adaption while (+splitStep.toFixed(precision) !== splitStep && precision < 5) { precision++; } thisOption.precision = precision; splitStep = +splitStep.toFixed(precision); var index = 0; if (thisOption.minOpen) { pieceList.push({ index: index++, interval: [-Infinity, dataExtent[0]], close: [0, 0] }); } for ( var curr = dataExtent[0], len = index + splitNumber; index < len; curr += splitStep ) { var max = index === splitNumber - 1 ? dataExtent[1] : (curr + splitStep); pieceList.push({ index: index++, interval: [curr, max], close: [1, 1] }); } if (thisOption.maxOpen) { pieceList.push({ index: index++, interval: [dataExtent[1], Infinity], close: [0, 0] }); } reformIntervals(pieceList); zrUtil.each(pieceList, function (piece) { piece.text = this.formatValueText(piece.interval); }, this); }, categories: function () { var thisOption = this.option; zrUtil.each(thisOption.categories, function (cate) { // FIXME category模式也使用pieceList,但在visualMapping中不是使用pieceList。 // 是否改一致。 this._pieceList.push({ text: this.formatValueText(cate, true), value: cate }); }, this); // See "Order Rule". normalizeReverse(thisOption, this._pieceList); }, pieces: function () { var thisOption = this.option; var pieceList = this._pieceList; zrUtil.each(thisOption.pieces, function (pieceListItem, index) { if (!zrUtil.isObject(pieceListItem)) { pieceListItem = {value: pieceListItem}; } var item = {text: '', index: index}; if (pieceListItem.label != null) { item.text = pieceListItem.label; } if (pieceListItem.hasOwnProperty('value')) { var value = item.value = pieceListItem.value; item.interval = [value, value]; item.close = [1, 1]; } else { // `min` `max` is legacy option. // `lt` `gt` `lte` `gte` is recommanded. var interval = item.interval = []; var close = item.close = [0, 0]; var closeList = [1, 0, 1]; var infinityList = [-Infinity, Infinity]; var useMinMax = []; for (var lg = 0; lg < 2; lg++) { var names = [['gte', 'gt', 'min'], ['lte', 'lt', 'max']][lg]; for (var i = 0; i < 3 && interval[lg] == null; i++) { interval[lg] = pieceListItem[names[i]]; close[lg] = closeList[i]; useMinMax[lg] = i === 2; } interval[lg] == null && (interval[lg] = infinityList[lg]); } useMinMax[0] && interval[1] === Infinity && (close[0] = 0); useMinMax[1] && interval[0] === -Infinity && (close[1] = 0); if (true) { if (interval[0] > interval[1]) { console.warn( 'Piece ' + index + 'is illegal: ' + interval + ' lower bound should not greater then uppper bound.' ); } } if (interval[0] === interval[1] && close[0] && close[1]) { // Consider: [{min: 5, max: 5, visual: {...}}, {min: 0, max: 5}], // we use value to lift the priority when min === max item.value = interval[0]; } } item.visual = VisualMapping.retrieveVisuals(pieceListItem); pieceList.push(item); }, this); // See "Order Rule". normalizeReverse(thisOption, pieceList); // Only pieces reformIntervals(pieceList); zrUtil.each(pieceList, function (piece) { var close = piece.close; var edgeSymbols = [['<', '≤'][close[1]], ['>', '≥'][close[0]]]; piece.text = piece.text || this.formatValueText( piece.value != null ? piece.value : piece.interval, false, edgeSymbols ); }, this); } }; function normalizeReverse(thisOption, pieceList) { var inverse = thisOption.inverse; if (thisOption.orient === 'vertical' ? !inverse : inverse) { pieceList.reverse(); } } module.exports = PiecewiseModel; /***/ }, /* 346 */ /***/ function(module, exports, __webpack_require__) { var VisualMapView = __webpack_require__(341); var zrUtil = __webpack_require__(4); var graphic = __webpack_require__(43); var symbolCreators = __webpack_require__(107); var layout = __webpack_require__(21); var helper = __webpack_require__(342); var PiecewiseVisualMapView = VisualMapView.extend({ type: 'visualMap.piecewise', /** * @protected * @override */ doRender: function () { var thisGroup = this.group; thisGroup.removeAll(); var visualMapModel = this.visualMapModel; var textGap = visualMapModel.get('textGap'); var textStyleModel = visualMapModel.textStyleModel; var textFont = textStyleModel.getFont(); var textFill = textStyleModel.getTextColor(); var itemAlign = this._getItemAlign(); var itemSize = visualMapModel.itemSize; var viewData = this._getViewData(); var showLabel = !viewData.endsText; var showEndsText = !showLabel; showEndsText && this._renderEndsText(thisGroup, viewData.endsText[0], itemSize); zrUtil.each(viewData.viewPieceList, renderItem, this); showEndsText && this._renderEndsText(thisGroup, viewData.endsText[1], itemSize); layout.box( visualMapModel.get('orient'), thisGroup, visualMapModel.get('itemGap') ); this.renderBackground(thisGroup); this.positionGroup(thisGroup); function renderItem(item) { var piece = item.piece; var itemGroup = new graphic.Group(); itemGroup.onclick = zrUtil.bind(this._onItemClick, this, piece); this._enableHoverLink(itemGroup, item.indexInModelPieceList); var representValue = visualMapModel.getRepresentValue(piece); this._createItemSymbol( itemGroup, representValue, [0, 0, itemSize[0], itemSize[1]] ); if (showLabel) { var visualState = this.visualMapModel.getValueState(representValue); itemGroup.add(new graphic.Text({ style: { x: itemAlign === 'right' ? -textGap : itemSize[0] + textGap, y: itemSize[1] / 2, text: piece.text, textVerticalAlign: 'middle', textAlign: itemAlign, textFont: textFont, fill: textFill, opacity: visualState === 'outOfRange' ? 0.5 : 1 } })); } thisGroup.add(itemGroup); } }, /** * @private */ _enableHoverLink: function (itemGroup, pieceIndex) { itemGroup .on('mouseover', zrUtil.bind(onHoverLink, this, 'highlight')) .on('mouseout', zrUtil.bind(onHoverLink, this, 'downplay')); function onHoverLink(method) { var visualMapModel = this.visualMapModel; visualMapModel.option.hoverLink && this.api.dispatchAction({ type: method, batch: helper.convertDataIndex( visualMapModel.findTargetDataIndices(pieceIndex) ) }); } }, /** * @private */ _getItemAlign: function () { var visualMapModel = this.visualMapModel; var modelOption = visualMapModel.option; if (modelOption.orient === 'vertical') { return helper.getItemAlign( visualMapModel, this.api, visualMapModel.itemSize ); } else { // horizontal, most case left unless specifying right. var align = modelOption.align; if (!align || align === 'auto') { align = 'left'; } return align; } }, /** * @private */ _renderEndsText: function (group, text, itemSize) { if (!text) { return; } var itemGroup = new graphic.Group(); var textStyleModel = this.visualMapModel.textStyleModel; itemGroup.add(new graphic.Text({ style: { x: itemSize[0] / 2, y: itemSize[1] / 2, textVerticalAlign: 'middle', textAlign: 'center', text: text, textFont: textStyleModel.getFont(), fill: textStyleModel.getTextColor() } })); group.add(itemGroup); }, /** * @private * @return {Object} {peiceList, endsText} The order is the same as screen pixel order. */ _getViewData: function () { var visualMapModel = this.visualMapModel; var viewPieceList = zrUtil.map(visualMapModel.getPieceList(), function (piece, index) { return {piece: piece, indexInModelPieceList: index}; }); var endsText = visualMapModel.get('text'); // Consider orient and inverse. var orient = visualMapModel.get('orient'); var inverse = visualMapModel.get('inverse'); // Order of model pieceList is always [low, ..., high] if (orient === 'horizontal' ? inverse : !inverse) { viewPieceList.reverse(); } // Origin order of endsText is [high, low] else if (endsText) { endsText = endsText.slice().reverse(); } return {viewPieceList: viewPieceList, endsText: endsText}; }, /** * @private */ _createItemSymbol: function (group, representValue, shapeParam) { group.add(symbolCreators.createSymbol( this.getControllerVisual(representValue, 'symbol'), shapeParam[0], shapeParam[1], shapeParam[2], shapeParam[3], this.getControllerVisual(representValue, 'color') )); }, /** * @private */ _onItemClick: function (piece) { var visualMapModel = this.visualMapModel; var option = visualMapModel.option; var selected = zrUtil.clone(option.selected); var newKey = visualMapModel.getSelectedMapKey(piece); if (option.selectedMode === 'single') { selected[newKey] = true; zrUtil.each(selected, function (o, key) { selected[key] = key === newKey; }); } else { selected[newKey] = !selected[newKey]; } this.api.dispatchAction({ type: 'selectDataRange', from: this.uid, visualMapId: this.visualMapModel.id, selected: selected }); } }); module.exports = PiecewiseVisualMapView; /***/ }, /* 347 */ /***/ function(module, exports, __webpack_require__) { // HINT Markpoint can't be used too much __webpack_require__(348); __webpack_require__(350); __webpack_require__(1).registerPreprocessor(function (opt) { // Make sure markPoint component is enabled opt.markPoint = opt.markPoint || {}; }); /***/ }, /* 348 */ /***/ function(module, exports, __webpack_require__) { module.exports = __webpack_require__(349).extend({ type: 'markPoint', defaultOption: { zlevel: 0, z: 5, symbol: 'pin', symbolSize: 50, //symbolRotate: 0, //symbolOffset: [0, 0] tooltip: { trigger: 'item' }, label: { normal: { show: true, position: 'inside' }, emphasis: { show: true } }, itemStyle: { normal: { borderWidth: 2 } } } }); /***/ }, /* 349 */ /***/ function(module, exports, __webpack_require__) { var modelUtil = __webpack_require__(5); var zrUtil = __webpack_require__(4); var env = __webpack_require__(2); var formatUtil = __webpack_require__(6); var addCommas = formatUtil.addCommas; var encodeHTML = formatUtil.encodeHTML; function fillLabel(opt) { modelUtil.defaultEmphasis( opt.label, modelUtil.LABEL_OPTIONS ); } var MarkerModel = __webpack_require__(1).extendComponentModel({ type: 'marker', dependencies: ['series', 'grid', 'polar', 'geo'], /** * @overrite */ init: function (option, parentModel, ecModel, extraOpt) { if (true) { if (this.type === 'marker') { throw new Error('Marker component is abstract component. Use markLine, markPoint, markArea instead.'); } } this.mergeDefaultAndTheme(option, ecModel); this.mergeOption(option, ecModel, extraOpt.createdBySelf, true); }, /** * @return {boolean} */ ifEnableAnimation: function () { if (env.node) { return false; } var hostSeries = this.__hostSeries; return this.getShallow('animation') && hostSeries && hostSeries.ifEnableAnimation(); }, mergeOption: function (newOpt, ecModel, createdBySelf, isInit) { var MarkerModel = this.constructor; var modelPropName = this.mainType + 'Model'; if (!createdBySelf) { ecModel.eachSeries(function (seriesModel) { var markerOpt = seriesModel.get(this.mainType); var markerModel = seriesModel[modelPropName]; if (!markerOpt || !markerOpt.data) { seriesModel[modelPropName] = null; return; } if (!markerModel) { if (isInit) { // Default label emphasis `position` and `show` fillLabel(markerOpt); } zrUtil.each(markerOpt.data, function (item) { // FIXME Overwrite fillLabel method ? if (item instanceof Array) { fillLabel(item[0]); fillLabel(item[1]); } else { fillLabel(item); } }); markerModel = new MarkerModel( markerOpt, this, ecModel ); zrUtil.extend(markerModel, { mainType: this.mainType, // Use the same series index and name seriesIndex: seriesModel.seriesIndex, name: seriesModel.name, createdBySelf: true }); markerModel.__hostSeries = seriesModel; } else { markerModel.mergeOption(markerOpt, ecModel, true); } seriesModel[modelPropName] = markerModel; }, this); } }, formatTooltip: function (dataIndex) { var data = this.getData(); var value = this.getRawValue(dataIndex); var formattedValue = zrUtil.isArray(value) ? zrUtil.map(value, addCommas).join(', ') : addCommas(value); var name = data.getName(dataIndex); var html = this.name; if (value != null || name) { html += '
'; } if (name) { html += encodeHTML(name); if (value != null) { html += ' : '; } } if (value != null) { html += formattedValue; } return html; }, getData: function () { return this._data; }, setData: function (data) { this._data = data; } }); zrUtil.mixin(MarkerModel, modelUtil.dataFormatMixin); module.exports = MarkerModel; /***/ }, /* 350 */ /***/ function(module, exports, __webpack_require__) { var SymbolDraw = __webpack_require__(105); var zrUtil = __webpack_require__(4); var numberUtil = __webpack_require__(7); var List = __webpack_require__(98); var markerHelper = __webpack_require__(351); function updateMarkerLayout(mpData, seriesModel, api) { var coordSys = seriesModel.coordinateSystem; mpData.each(function (idx) { var itemModel = mpData.getItemModel(idx); var point; var xPx = numberUtil.parsePercent(itemModel.get('x'), api.getWidth()); var yPx = numberUtil.parsePercent(itemModel.get('y'), api.getHeight()); if (!isNaN(xPx) && !isNaN(yPx)) { point = [xPx, yPx]; } // Chart like bar may have there own marker positioning logic else if (seriesModel.getMarkerPosition) { // Use the getMarkerPoisition point = seriesModel.getMarkerPosition( mpData.getValues(mpData.dimensions, idx) ); } else if (coordSys) { var x = mpData.get(coordSys.dimensions[0], idx); var y = mpData.get(coordSys.dimensions[1], idx); point = coordSys.dataToPoint([x, y]); } // Use x, y if has any if (!isNaN(xPx)) { point[0] = xPx; } if (!isNaN(yPx)) { point[1] = yPx; } mpData.setItemLayout(idx, point); }); } __webpack_require__(352).extend({ type: 'markPoint', updateLayout: function (markPointModel, ecModel, api) { ecModel.eachSeries(function (seriesModel) { var mpModel = seriesModel.markPointModel; if (mpModel) { updateMarkerLayout(mpModel.getData(), seriesModel, api); this.markerGroupMap[seriesModel.name].updateLayout(mpModel); } }, this); }, renderSeries: function (seriesModel, mpModel, ecModel, api) { var coordSys = seriesModel.coordinateSystem; var seriesName = seriesModel.name; var seriesData = seriesModel.getData(); var symbolDrawMap = this.markerGroupMap; var symbolDraw = symbolDrawMap[seriesName]; if (!symbolDraw) { symbolDraw = symbolDrawMap[seriesName] = new SymbolDraw(); } var mpData = createList(coordSys, seriesModel, mpModel); // FIXME mpModel.setData(mpData); updateMarkerLayout(mpModel.getData(), seriesModel, api); mpData.each(function (idx) { var itemModel = mpData.getItemModel(idx); var symbolSize = itemModel.getShallow('symbolSize'); if (typeof symbolSize === 'function') { // FIXME 这里不兼容 ECharts 2.x,2.x 貌似参数是整个数据? symbolSize = symbolSize( mpModel.getRawValue(idx), mpModel.getDataParams(idx) ); } mpData.setItemVisual(idx, { symbolSize: symbolSize, color: itemModel.get('itemStyle.normal.color') || seriesData.getVisual('color'), symbol: itemModel.getShallow('symbol') }); }); // TODO Text are wrong symbolDraw.updateData(mpData); this.group.add(symbolDraw.group); // Set host model for tooltip // FIXME mpData.eachItemGraphicEl(function (el) { el.traverse(function (child) { child.dataModel = mpModel; }); }); symbolDraw.__keep = true; symbolDraw.group.silent = mpModel.get('silent') || seriesModel.get('silent'); } }); /** * @inner * @param {module:echarts/coord/*} [coordSys] * @param {module:echarts/model/Series} seriesModel * @param {module:echarts/model/Model} mpModel */ function createList(coordSys, seriesModel, mpModel) { var coordDimsInfos; if (coordSys) { coordDimsInfos = zrUtil.map(coordSys && coordSys.dimensions, function (coordDim) { var info = seriesModel.getData().getDimensionInfo( seriesModel.coordDimToDataDim(coordDim)[0] ) || {}; // In map series data don't have lng and lat dimension. Fallback to same with coordSys info.name = coordDim; return info; }); } else { coordDimsInfos =[{ name: 'value', type: 'float' }]; } var mpData = new List(coordDimsInfos, mpModel); var dataOpt = zrUtil.map(mpModel.get('data'), zrUtil.curry( markerHelper.dataTransform, seriesModel )); if (coordSys) { dataOpt = zrUtil.filter( dataOpt, zrUtil.curry(markerHelper.dataFilter, coordSys) ); } mpData.initData(dataOpt, null, coordSys ? markerHelper.dimValueGetter : function (item) { return item.value; } ); return mpData; } /***/ }, /* 351 */ /***/ function(module, exports, __webpack_require__) { var zrUtil = __webpack_require__(4); var numberUtil = __webpack_require__(7); var indexOf = zrUtil.indexOf; function hasXOrY(item) { return !(isNaN(parseFloat(item.x)) && isNaN(parseFloat(item.y))); } function hasXAndY(item) { return !isNaN(parseFloat(item.x)) && !isNaN(parseFloat(item.y)); } function getPrecision(data, valueAxisDim, dataIndex) { var precision = -1; do { precision = Math.max( numberUtil.getPrecision(data.get( valueAxisDim, dataIndex )), precision ); data = data.stackedOn; } while (data); return precision; } function markerTypeCalculatorWithExtent( mlType, data, otherDataDim, targetDataDim, otherCoordIndex, targetCoordIndex ) { var coordArr = []; var value = numCalculate(data, targetDataDim, mlType); var dataIndex = data.indexOfNearest(targetDataDim, value, true); coordArr[otherCoordIndex] = data.get(otherDataDim, dataIndex, true); coordArr[targetCoordIndex] = data.get(targetDataDim, dataIndex, true); var precision = getPrecision(data, targetDataDim, dataIndex); if (precision >= 0) { coordArr[targetCoordIndex] = +coordArr[targetCoordIndex].toFixed(precision); } return coordArr; } var curry = zrUtil.curry; // TODO Specified percent var markerTypeCalculator = { /** * @method * @param {module:echarts/data/List} data * @param {string} baseAxisDim * @param {string} valueAxisDim */ min: curry(markerTypeCalculatorWithExtent, 'min'), /** * @method * @param {module:echarts/data/List} data * @param {string} baseAxisDim * @param {string} valueAxisDim */ max: curry(markerTypeCalculatorWithExtent, 'max'), /** * @method * @param {module:echarts/data/List} data * @param {string} baseAxisDim * @param {string} valueAxisDim */ average: curry(markerTypeCalculatorWithExtent, 'average') }; /** * Transform markPoint data item to format used in List by do the following * 1. Calculate statistic like `max`, `min`, `average` * 2. Convert `item.xAxis`, `item.yAxis` to `item.coord` array * @param {module:echarts/model/Series} seriesModel * @param {module:echarts/coord/*} [coordSys] * @param {Object} item * @return {Object} */ var dataTransform = function (seriesModel, item) { var data = seriesModel.getData(); var coordSys = seriesModel.coordinateSystem; // 1. If not specify the position with pixel directly // 2. If `coord` is not a data array. Which uses `xAxis`, // `yAxis` to specify the coord on each dimension // parseFloat first because item.x and item.y can be percent string like '20%' if (item && !hasXAndY(item) && !zrUtil.isArray(item.coord) && coordSys) { var dims = coordSys.dimensions; var axisInfo = getAxisInfo(item, data, coordSys, seriesModel); // Clone the option // Transform the properties xAxis, yAxis, radiusAxis, angleAxis, geoCoord to value item = zrUtil.clone(item); if (item.type && markerTypeCalculator[item.type] && axisInfo.baseAxis && axisInfo.valueAxis ) { var otherCoordIndex = indexOf(dims, axisInfo.baseAxis.dim); var targetCoordIndex = indexOf(dims, axisInfo.valueAxis.dim); item.coord = markerTypeCalculator[item.type]( data, axisInfo.baseDataDim, axisInfo.valueDataDim, otherCoordIndex, targetCoordIndex ); // Force to use the value of calculated value. item.value = item.coord[targetCoordIndex]; } else { // FIXME Only has one of xAxis and yAxis. var coord = [ item.xAxis != null ? item.xAxis : item.radiusAxis, item.yAxis != null ? item.yAxis : item.angleAxis ]; // Each coord support max, min, average for (var i = 0; i < 2; i++) { if (markerTypeCalculator[coord[i]]) { var dataDim = seriesModel.coordDimToDataDim(dims[i])[0]; coord[i] = numCalculate(data, dataDim, coord[i]); } } item.coord = coord; } } return item; }; var getAxisInfo = function (item, data, coordSys, seriesModel) { var ret = {}; if (item.valueIndex != null || item.valueDim != null) { ret.valueDataDim = item.valueIndex != null ? data.getDimension(item.valueIndex) : item.valueDim; ret.valueAxis = coordSys.getAxis(seriesModel.dataDimToCoordDim(ret.valueDataDim)); ret.baseAxis = coordSys.getOtherAxis(ret.valueAxis); ret.baseDataDim = seriesModel.coordDimToDataDim(ret.baseAxis.dim)[0]; } else { ret.baseAxis = seriesModel.getBaseAxis(); ret.valueAxis = coordSys.getOtherAxis(ret.baseAxis); ret.baseDataDim = seriesModel.coordDimToDataDim(ret.baseAxis.dim)[0]; ret.valueDataDim = seriesModel.coordDimToDataDim(ret.valueAxis.dim)[0]; } return ret; }; /** * Filter data which is out of coordinateSystem range * [dataFilter description] * @param {module:echarts/coord/*} [coordSys] * @param {Object} item * @return {boolean} */ var dataFilter = function (coordSys, item) { // Alwalys return true if there is no coordSys return (coordSys && coordSys.containData && item.coord && !hasXOrY(item)) ? coordSys.containData(item.coord) : true; }; var dimValueGetter = function (item, dimName, dataIndex, dimIndex) { // x, y, radius, angle if (dimIndex < 2) { return item.coord && item.coord[dimIndex]; } return item.value; }; var numCalculate = function (data, valueDataDim, type) { if (type === 'average') { var sum = 0; var count = 0; data.each(valueDataDim, function (val, idx) { if (!isNaN(val)) { sum += val; count++; } }, true); return sum / count; } else { return data.getDataExtent(valueDataDim, true)[type === 'max' ? 1 : 0]; } }; module.exports = { dataTransform: dataTransform, dataFilter: dataFilter, dimValueGetter: dimValueGetter, getAxisInfo: getAxisInfo, numCalculate: numCalculate }; /***/ }, /* 352 */ /***/ function(module, exports, __webpack_require__) { module.exports = __webpack_require__(1).extendComponentView({ type: 'marker', init: function () { /** * Markline grouped by series * @private * @type {Object} */ this.markerGroupMap = {}; }, render: function (markerModel, ecModel, api) { var markerGroupMap = this.markerGroupMap; for (var name in markerGroupMap) { if (markerGroupMap.hasOwnProperty(name)) { markerGroupMap[name].__keep = false; } } var markerModelKey = this.type + 'Model'; ecModel.eachSeries(function (seriesModel) { var markerModel = seriesModel[markerModelKey]; markerModel && this.renderSeries(seriesModel, markerModel, ecModel, api); }, this); for (var name in markerGroupMap) { if (markerGroupMap.hasOwnProperty(name) && !markerGroupMap[name].__keep) { this.group.remove(markerGroupMap[name].group); } } }, renderSeries: function () {} }); /***/ }, /* 353 */ /***/ function(module, exports, __webpack_require__) { __webpack_require__(354); __webpack_require__(355); __webpack_require__(1).registerPreprocessor(function (opt) { // Make sure markLine component is enabled opt.markLine = opt.markLine || {}; }); /***/ }, /* 354 */ /***/ function(module, exports, __webpack_require__) { module.exports = __webpack_require__(349).extend({ type: 'markLine', defaultOption: { zlevel: 0, z: 5, symbol: ['circle', 'arrow'], symbolSize: [8, 16], //symbolRotate: 0, precision: 2, tooltip: { trigger: 'item' }, label: { normal: { show: true, position: 'end' }, emphasis: { show: true } }, lineStyle: { normal: { type: 'dashed' }, emphasis: { width: 3 } }, animationEasing: 'linear' } }); /***/ }, /* 355 */ /***/ function(module, exports, __webpack_require__) { var zrUtil = __webpack_require__(4); var List = __webpack_require__(98); var numberUtil = __webpack_require__(7); var markerHelper = __webpack_require__(351); var LineDraw = __webpack_require__(201); var markLineTransform = function (seriesModel, coordSys, mlModel, item) { var data = seriesModel.getData(); // Special type markLine like 'min', 'max', 'average' var mlType = item.type; if (!zrUtil.isArray(item) && ( mlType === 'min' || mlType === 'max' || mlType === 'average' // In case // data: [{ // yAxis: 10 // }] || (item.xAxis != null || item.yAxis != null) ) ) { var valueAxis; var valueDataDim; var value; if (item.yAxis != null || item.xAxis != null) { valueDataDim = item.yAxis != null ? 'y' : 'x'; valueAxis = coordSys.getAxis(valueDataDim); value = zrUtil.retrieve(item.yAxis, item.xAxis); } else { var axisInfo = markerHelper.getAxisInfo(item, data, coordSys, seriesModel); valueDataDim = axisInfo.valueDataDim; valueAxis = axisInfo.valueAxis; value = markerHelper.numCalculate(data, valueDataDim, mlType); } var valueIndex = valueDataDim === 'x' ? 0 : 1; var baseIndex = 1 - valueIndex; var mlFrom = zrUtil.clone(item); var mlTo = {}; mlFrom.type = null; mlFrom.coord = []; mlTo.coord = []; mlFrom.coord[baseIndex] = -Infinity; mlTo.coord[baseIndex] = Infinity; var precision = mlModel.get('precision'); if (precision >= 0 && typeof value === 'number') { value = +value.toFixed(precision); } mlFrom.coord[valueIndex] = mlTo.coord[valueIndex] = value; item = [mlFrom, mlTo, { // Extra option for tooltip and label type: mlType, valueIndex: item.valueIndex, // Force to use the value of calculated value. value: value }]; } item = [ markerHelper.dataTransform(seriesModel, item[0]), markerHelper.dataTransform(seriesModel, item[1]), zrUtil.extend({}, item[2]) ]; // Avoid line data type is extended by from(to) data type item[2].type = item[2].type || ''; // Merge from option and to option into line option zrUtil.merge(item[2], item[0]); zrUtil.merge(item[2], item[1]); return item; }; function isInifinity(val) { return !isNaN(val) && !isFinite(val); } // If a markLine has one dim function ifMarkLineHasOnlyDim(dimIndex, fromCoord, toCoord, coordSys) { var otherDimIndex = 1 - dimIndex; var dimName = coordSys.dimensions[dimIndex]; return isInifinity(fromCoord[otherDimIndex]) && isInifinity(toCoord[otherDimIndex]) && fromCoord[dimIndex] === toCoord[dimIndex] && coordSys.getAxis(dimName).containData(fromCoord[dimIndex]); } function markLineFilter(coordSys, item) { if (coordSys.type === 'cartesian2d') { var fromCoord = item[0].coord; var toCoord = item[1].coord; // In case // { // markLine: { // data: [{ yAxis: 2 }] // } // } if ( fromCoord && toCoord && (ifMarkLineHasOnlyDim(1, fromCoord, toCoord, coordSys) || ifMarkLineHasOnlyDim(0, fromCoord, toCoord, coordSys)) ) { return true; } } return markerHelper.dataFilter(coordSys, item[0]) && markerHelper.dataFilter(coordSys, item[1]); } function updateSingleMarkerEndLayout( data, idx, isFrom, seriesModel, api ) { var coordSys = seriesModel.coordinateSystem; var itemModel = data.getItemModel(idx); var point; var xPx = numberUtil.parsePercent(itemModel.get('x'), api.getWidth()); var yPx = numberUtil.parsePercent(itemModel.get('y'), api.getHeight()); if (!isNaN(xPx) && !isNaN(yPx)) { point = [xPx, yPx]; } else { // Chart like bar may have there own marker positioning logic if (seriesModel.getMarkerPosition) { // Use the getMarkerPoisition point = seriesModel.getMarkerPosition( data.getValues(data.dimensions, idx) ); } else { var dims = coordSys.dimensions; var x = data.get(dims[0], idx); var y = data.get(dims[1], idx); point = coordSys.dataToPoint([x, y]); } // Expand line to the edge of grid if value on one axis is Inifnity // In case // markLine: { // data: [{ // yAxis: 2 // // or // type: 'average' // }] // } if (coordSys.type === 'cartesian2d') { var xAxis = coordSys.getAxis('x'); var yAxis = coordSys.getAxis('y'); var dims = coordSys.dimensions; if (isInifinity(data.get(dims[0], idx))) { point[0] = xAxis.toGlobalCoord(xAxis.getExtent()[isFrom ? 0 : 1]); } else if (isInifinity(data.get(dims[1], idx))) { point[1] = yAxis.toGlobalCoord(yAxis.getExtent()[isFrom ? 0 : 1]); } } // Use x, y if has any if (!isNaN(xPx)) { point[0] = xPx; } if (!isNaN(yPx)) { point[1] = yPx; } } data.setItemLayout(idx, point); } __webpack_require__(352).extend({ type: 'markLine', updateLayout: function (markLineModel, ecModel, api) { ecModel.eachSeries(function (seriesModel) { var mlModel = seriesModel.markLineModel; if (mlModel) { var mlData = mlModel.getData(); var fromData = mlModel.__from; var toData = mlModel.__to; // Update visual and layout of from symbol and to symbol fromData.each(function (idx) { updateSingleMarkerEndLayout(fromData, idx, true, seriesModel, api); updateSingleMarkerEndLayout(toData, idx, false, seriesModel, api); }); // Update layout of line mlData.each(function (idx) { mlData.setItemLayout(idx, [ fromData.getItemLayout(idx), toData.getItemLayout(idx) ]); }); this.markerGroupMap[seriesModel.name].updateLayout(); } }, this); }, renderSeries: function (seriesModel, mlModel, ecModel, api) { var coordSys = seriesModel.coordinateSystem; var seriesName = seriesModel.name; var seriesData = seriesModel.getData(); var lineDrawMap = this.markerGroupMap; var lineDraw = lineDrawMap[seriesName]; if (!lineDraw) { lineDraw = lineDrawMap[seriesName] = new LineDraw(); } this.group.add(lineDraw.group); var mlData = createList(coordSys, seriesModel, mlModel); var fromData = mlData.from; var toData = mlData.to; var lineData = mlData.line; mlModel.__from = fromData; mlModel.__to = toData; // Line data for tooltip and formatter mlModel.setData(lineData); var symbolType = mlModel.get('symbol'); var symbolSize = mlModel.get('symbolSize'); if (!zrUtil.isArray(symbolType)) { symbolType = [symbolType, symbolType]; } if (typeof symbolSize === 'number') { symbolSize = [symbolSize, symbolSize]; } // Update visual and layout of from symbol and to symbol mlData.from.each(function (idx) { updateDataVisualAndLayout(fromData, idx, true); updateDataVisualAndLayout(toData, idx, false); }); // Update visual and layout of line lineData.each(function (idx) { var lineColor = lineData.getItemModel(idx).get('lineStyle.normal.color'); lineData.setItemVisual(idx, { color: lineColor || fromData.getItemVisual(idx, 'color') }); lineData.setItemLayout(idx, [ fromData.getItemLayout(idx), toData.getItemLayout(idx) ]); lineData.setItemVisual(idx, { 'fromSymbolSize': fromData.getItemVisual(idx, 'symbolSize'), 'fromSymbol': fromData.getItemVisual(idx, 'symbol'), 'toSymbolSize': toData.getItemVisual(idx, 'symbolSize'), 'toSymbol': toData.getItemVisual(idx, 'symbol') }); }); lineDraw.updateData(lineData); // Set host model for tooltip // FIXME mlData.line.eachItemGraphicEl(function (el, idx) { el.traverse(function (child) { child.dataModel = mlModel; }); }); function updateDataVisualAndLayout(data, idx, isFrom) { var itemModel = data.getItemModel(idx); updateSingleMarkerEndLayout( data, idx, isFrom, seriesModel, api ); data.setItemVisual(idx, { symbolSize: itemModel.get('symbolSize') || symbolSize[isFrom ? 0 : 1], symbol: itemModel.get('symbol', true) || symbolType[isFrom ? 0 : 1], color: itemModel.get('itemStyle.normal.color') || seriesData.getVisual('color') }); } lineDraw.__keep = true; lineDraw.group.silent = mlModel.get('silent') || seriesModel.get('silent'); } }); /** * @inner * @param {module:echarts/coord/*} coordSys * @param {module:echarts/model/Series} seriesModel * @param {module:echarts/model/Model} mpModel */ function createList(coordSys, seriesModel, mlModel) { var coordDimsInfos; if (coordSys) { coordDimsInfos = zrUtil.map(coordSys && coordSys.dimensions, function (coordDim) { var info = seriesModel.getData().getDimensionInfo( seriesModel.coordDimToDataDim(coordDim)[0] ) || {}; // In map series data don't have lng and lat dimension. Fallback to same with coordSys info.name = coordDim; return info; }); } else { coordDimsInfos =[{ name: 'value', type: 'float' }]; } var fromData = new List(coordDimsInfos, mlModel); var toData = new List(coordDimsInfos, mlModel); // No dimensions var lineData = new List([], mlModel); var optData = zrUtil.map(mlModel.get('data'), zrUtil.curry( markLineTransform, seriesModel, coordSys, mlModel )); if (coordSys) { optData = zrUtil.filter( optData, zrUtil.curry(markLineFilter, coordSys) ); } var dimValueGetter = coordSys ? markerHelper.dimValueGetter : function (item) { return item.value; }; fromData.initData( zrUtil.map(optData, function (item) { return item[0]; }), null, dimValueGetter ); toData.initData( zrUtil.map(optData, function (item) { return item[1]; }), null, dimValueGetter ); lineData.initData( zrUtil.map(optData, function (item) { return item[2]; }) ); lineData.hasItemOption = true; return { from: fromData, to: toData, line: lineData }; } /***/ }, /* 356 */ /***/ function(module, exports, __webpack_require__) { __webpack_require__(357); __webpack_require__(358); __webpack_require__(1).registerPreprocessor(function (opt) { // Make sure markArea component is enabled opt.markArea = opt.markArea || {}; }); /***/ }, /* 357 */ /***/ function(module, exports, __webpack_require__) { module.exports = __webpack_require__(349).extend({ type: 'markArea', defaultOption: { zlevel: 0, // PENDING z: 1, tooltip: { trigger: 'item' }, // markArea should fixed on the coordinate system animation: false, label: { normal: { show: true, position: 'top' }, emphasis: { show: true, position: 'top' } }, itemStyle: { normal: { // color and borderColor default to use color from series // color: 'auto' // borderColor: 'auto' borderWidth: 0 } } } }); /***/ }, /* 358 */ /***/ function(module, exports, __webpack_require__) { // TODO Better on polar var zrUtil = __webpack_require__(4); var List = __webpack_require__(98); var numberUtil = __webpack_require__(7); var graphic = __webpack_require__(43); var colorUtil = __webpack_require__(39); var markerHelper = __webpack_require__(351); var markAreaTransform = function (seriesModel, coordSys, maModel, item) { var lt = markerHelper.dataTransform(seriesModel, item[0]); var rb = markerHelper.dataTransform(seriesModel, item[1]); var retrieve = zrUtil.retrieve; // FIXME make sure lt is less than rb var ltCoord = lt.coord; var rbCoord = rb.coord; ltCoord[0] = retrieve(ltCoord[0], -Infinity); ltCoord[1] = retrieve(ltCoord[1], -Infinity); rbCoord[0] = retrieve(rbCoord[0], Infinity); rbCoord[1] = retrieve(rbCoord[1], Infinity); // Merge option into one var result = zrUtil.mergeAll([{}, lt, rb]); result.coord = [ lt.coord, rb.coord ]; result.x0 = lt.x; result.y0 = lt.y; result.x1 = rb.x; result.y1 = rb.y; return result; }; function isInifinity(val) { return !isNaN(val) && !isFinite(val); } // If a markArea has one dim function ifMarkLineHasOnlyDim(dimIndex, fromCoord, toCoord, coordSys) { var otherDimIndex = 1 - dimIndex; return isInifinity(fromCoord[otherDimIndex]) && isInifinity(toCoord[otherDimIndex]); } function markAreaFilter(coordSys, item) { var fromCoord = item.coord[0]; var toCoord = item.coord[1]; if (coordSys.type === 'cartesian2d') { // In case // { // markArea: { // data: [{ yAxis: 2 }] // } // } if ( fromCoord && toCoord && (ifMarkLineHasOnlyDim(1, fromCoord, toCoord, coordSys) || ifMarkLineHasOnlyDim(0, fromCoord, toCoord, coordSys)) ) { return true; } } return markerHelper.dataFilter(coordSys, { coord: fromCoord, x: item.x0, y: item.y0 }) || markerHelper.dataFilter(coordSys, { coord: toCoord, x: item.x1, y: item.y1 }); } // dims can be ['x0', 'y0'], ['x1', 'y1'], ['x0', 'y1'], ['x1', 'y0'] function getSingleMarkerEndPoint(data, idx, dims, seriesModel, api) { var coordSys = seriesModel.coordinateSystem; var itemModel = data.getItemModel(idx); var point; var xPx = numberUtil.parsePercent(itemModel.get(dims[0]), api.getWidth()); var yPx = numberUtil.parsePercent(itemModel.get(dims[1]), api.getHeight()); if (!isNaN(xPx) && !isNaN(yPx)) { point = [xPx, yPx]; } else { // Chart like bar may have there own marker positioning logic if (seriesModel.getMarkerPosition) { // Use the getMarkerPoisition point = seriesModel.getMarkerPosition( data.getValues(dims, idx) ); } else { var x = data.get(dims[0], idx); var y = data.get(dims[1], idx); point = coordSys.dataToPoint([x, y], true); } if (coordSys.type === 'cartesian2d') { var xAxis = coordSys.getAxis('x'); var yAxis = coordSys.getAxis('y'); var x = data.get(dims[0], idx); var y = data.get(dims[1], idx); if (isInifinity(x)) { point[0] = xAxis.toGlobalCoord(xAxis.getExtent()[dims[0] === 'x0' ? 0 : 1]); } else if (isInifinity(y)) { point[1] = yAxis.toGlobalCoord(yAxis.getExtent()[dims[1] === 'y0' ? 0 : 1]); } } // Use x, y if has any if (!isNaN(xPx)) { point[0] = xPx; } if (!isNaN(yPx)) { point[1] = yPx; } } return point; } var dimPermutations = [['x0', 'y0'], ['x1', 'y0'], ['x1', 'y1'], ['x0', 'y1']]; __webpack_require__(352).extend({ type: 'markArea', updateLayout: function (markAreaModel, ecModel, api) { ecModel.eachSeries(function (seriesModel) { var maModel = seriesModel.markAreaModel; if (maModel) { var areaData = maModel.getData(); areaData.each(function (idx) { var points = zrUtil.map(dimPermutations, function (dim) { return getSingleMarkerEndPoint(areaData, idx, dim, seriesModel, api); }); // Layout areaData.setItemLayout(idx, points); var el = areaData.getItemGraphicEl(idx); el.setShape('points', points); }); } }, this); }, renderSeries: function (seriesModel, maModel, ecModel, api) { var coordSys = seriesModel.coordinateSystem; var seriesName = seriesModel.name; var seriesData = seriesModel.getData(); var areaGroupMap = this.markerGroupMap; var polygonGroup = areaGroupMap[seriesName]; if (!polygonGroup) { polygonGroup = areaGroupMap[seriesName] = { group: new graphic.Group() }; } this.group.add(polygonGroup.group); polygonGroup.__keep = true; var areaData = createList(coordSys, seriesModel, maModel); // Line data for tooltip and formatter maModel.setData(areaData); // Update visual and layout of line areaData.each(function (idx) { // Layout areaData.setItemLayout(idx, zrUtil.map(dimPermutations, function (dim) { return getSingleMarkerEndPoint(areaData, idx, dim, seriesModel, api); })); // Visual areaData.setItemVisual(idx, { color: seriesData.getVisual('color') }); }); areaData.diff(polygonGroup.__data) .add(function (idx) { var polygon = new graphic.Polygon({ shape: { points: areaData.getItemLayout(idx) } }); areaData.setItemGraphicEl(idx, polygon); polygonGroup.group.add(polygon); }) .update(function (newIdx, oldIdx) { var polygon = polygonGroup.__data.getItemGraphicEl(oldIdx); graphic.updateProps(polygon, { shape: { points: areaData.getItemLayout(newIdx) } }, maModel, newIdx); polygonGroup.group.add(polygon); areaData.setItemGraphicEl(newIdx, polygon); }) .remove(function (idx) { var polygon = polygonGroup.__data.getItemGraphicEl(idx); polygonGroup.group.remove(polygon); }) .execute(); areaData.eachItemGraphicEl(function (polygon, idx) { var itemModel = areaData.getItemModel(idx); var labelModel = itemModel.getModel('label.normal'); var labelHoverModel = itemModel.getModel('label.emphasis'); var color = areaData.getItemVisual(idx, 'color'); polygon.useStyle( zrUtil.defaults( itemModel.getModel('itemStyle.normal').getItemStyle(), { fill: colorUtil.modifyAlpha(color, 0.4), stroke: color } ) ); polygon.hoverStyle = itemModel.getModel('itemStyle.normal').getItemStyle(); var defaultValue = areaData.getName(idx) || ''; var textColor = color || polygon.style.fill; graphic.setText(polygon.style, labelModel, textColor); polygon.style.text = zrUtil.retrieve( maModel.getFormattedLabel(idx, 'normal'), defaultValue ); graphic.setText(polygon.hoverStyle, labelHoverModel, textColor); polygon.hoverStyle.text = zrUtil.retrieve( maModel.getFormattedLabel(idx, 'emphasis'), defaultValue ); graphic.setHoverStyle(polygon, {}); polygon.dataModel = maModel; }); polygonGroup.__data = areaData; polygonGroup.group.silent = maModel.get('silent') || seriesModel.get('silent'); } }); /** * @inner * @param {module:echarts/coord/*} coordSys * @param {module:echarts/model/Series} seriesModel * @param {module:echarts/model/Model} mpModel */ function createList(coordSys, seriesModel, maModel) { var coordDimsInfos; var areaData; var dims = ['x0', 'y0', 'x1', 'y1']; if (coordSys) { coordDimsInfos = zrUtil.map(coordSys && coordSys.dimensions, function (coordDim) { var info = seriesModel.getData().getDimensionInfo( seriesModel.coordDimToDataDim(coordDim)[0] ) || {}; // In map series data don't have lng and lat dimension. Fallback to same with coordSys info.name = coordDim; return info; }); areaData = new List(zrUtil.map(dims, function (dim, idx) { return { name: dim, type: coordDimsInfos[idx % 2].type }; }), maModel); } else { coordDimsInfos =[{ name: 'value', type: 'float' }]; areaData = new List(coordDimsInfos, maModel); } var optData = zrUtil.map(maModel.get('data'), zrUtil.curry( markAreaTransform, seriesModel, coordSys, maModel )); if (coordSys) { optData = zrUtil.filter( optData, zrUtil.curry(markAreaFilter, coordSys) ); } var dimValueGetter = coordSys ? function (item, dimName, dataIndex, dimIndex) { return item.coord[Math.floor(dimIndex / 2)][dimIndex % 2]; } : function (item) { return item.value; }; areaData.initData(optData, null, dimValueGetter); areaData.hasItemOption = true; return areaData; } /***/ }, /* 359 */ /***/ function(module, exports, __webpack_require__) { /** * DataZoom component entry */ var echarts = __webpack_require__(1); echarts.registerPreprocessor(__webpack_require__(360)); __webpack_require__(361); __webpack_require__(362); __webpack_require__(363); __webpack_require__(365); /***/ }, /* 360 */ /***/ function(module, exports, __webpack_require__) { /** * @file Timeline preprocessor */ var zrUtil = __webpack_require__(4); module.exports = function (option) { var timelineOpt = option && option.timeline; if (!zrUtil.isArray(timelineOpt)) { timelineOpt = timelineOpt ? [timelineOpt] : []; } zrUtil.each(timelineOpt, function (opt) { if (!opt) { return; } compatibleEC2(opt); }); }; function compatibleEC2(opt) { var type = opt.type; var ec2Types = {'number': 'value', 'time': 'time'}; // Compatible with ec2 if (ec2Types[type]) { opt.axisType = ec2Types[type]; delete opt.type; } transferItem(opt); if (has(opt, 'controlPosition')) { var controlStyle = opt.controlStyle || (opt.controlStyle = {}); if (!has(controlStyle, 'position')) { controlStyle.position = opt.controlPosition; } if (controlStyle.position === 'none' && !has(controlStyle, 'show')) { controlStyle.show = false; delete controlStyle.position; } delete opt.controlPosition; } zrUtil.each(opt.data || [], function (dataItem) { if (zrUtil.isObject(dataItem) && !zrUtil.isArray(dataItem)) { if (!has(dataItem, 'value') && has(dataItem, 'name')) { // In ec2, using name as value. dataItem.value = dataItem.name; } transferItem(dataItem); } }); } function transferItem(opt) { var itemStyle = opt.itemStyle || (opt.itemStyle = {}); var itemStyleEmphasis = itemStyle.emphasis || (itemStyle.emphasis = {}); // Transfer label out var label = opt.label || (opt.label || {}); var labelNormal = label.normal || (label.normal = {}); var excludeLabelAttr = {normal: 1, emphasis: 1}; zrUtil.each(label, function (value, name) { if (!excludeLabelAttr[name] && !has(labelNormal, name)) { labelNormal[name] = value; } }); if (itemStyleEmphasis.label && !has(label, 'emphasis')) { label.emphasis = itemStyleEmphasis.label; delete itemStyleEmphasis.label; } } function has(obj, attr) { return obj.hasOwnProperty(attr); } /***/ }, /* 361 */ /***/ function(module, exports, __webpack_require__) { __webpack_require__(19).registerSubTypeDefaulter('timeline', function () { // Only slider now. return 'slider'; }); /***/ }, /* 362 */ /***/ function(module, exports, __webpack_require__) { /** * @file Timeilne action */ var echarts = __webpack_require__(1); var zrUtil = __webpack_require__(4); echarts.registerAction( {type: 'timelineChange', event: 'timelineChanged', update: 'prepareAndUpdate'}, function (payload, ecModel) { var timelineModel = ecModel.getComponent('timeline'); if (timelineModel && payload.currentIndex != null) { timelineModel.setCurrentIndex(payload.currentIndex); if (!timelineModel.get('loop', true) && timelineModel.isIndexMax()) { timelineModel.setPlayState(false); } } // Set normalized currentIndex to payload. ecModel.resetOption('timeline'); return zrUtil.defaults({ currentIndex: timelineModel.option.currentIndex }, payload); } ); echarts.registerAction( {type: 'timelinePlayChange', event: 'timelinePlayChanged', update: 'update'}, function (payload, ecModel) { var timelineModel = ecModel.getComponent('timeline'); if (timelineModel && payload.playState != null) { timelineModel.setPlayState(payload.playState); } } ); /***/ }, /* 363 */ /***/ function(module, exports, __webpack_require__) { /** * @file Silder timeline model */ var TimelineModel = __webpack_require__(364); var zrUtil = __webpack_require__(4); var modelUtil = __webpack_require__(5); var SliderTimelineModel = TimelineModel.extend({ type: 'timeline.slider', /** * @protected */ defaultOption: { backgroundColor: 'rgba(0,0,0,0)', // 时间轴背景颜色 borderColor: '#ccc', // 时间轴边框颜色 borderWidth: 0, // 时间轴边框线宽,单位px,默认为0(无边框) orient: 'horizontal', // 'vertical' inverse: false, tooltip: { // boolean or Object trigger: 'item' // data item may also have tootip attr. }, symbol: 'emptyCircle', symbolSize: 10, lineStyle: { show: true, width: 2, color: '#304654' }, label: { // 文本标签 position: 'auto', // auto left right top bottom // When using number, label position is not // restricted by viewRect. // positive: right/bottom, negative: left/top normal: { show: true, interval: 'auto', rotate: 0, // formatter: null, textStyle: { // 其余属性默认使用全局文本样式,详见TEXTSTYLE color: '#304654' } }, emphasis: { show: true, textStyle: { // 其余属性默认使用全局文本样式,详见TEXTSTYLE color: '#c23531' } } }, itemStyle: { normal: { color: '#304654', borderWidth: 1 }, emphasis: { color: '#c23531' } }, checkpointStyle: { symbol: 'circle', symbolSize: 13, color: '#c23531', borderWidth: 5, borderColor: 'rgba(194,53,49, 0.5)', animation: true, animationDuration: 300, animationEasing: 'quinticInOut' }, controlStyle: { show: true, showPlayBtn: true, showPrevBtn: true, showNextBtn: true, itemSize: 22, itemGap: 12, position: 'left', // 'left' 'right' 'top' 'bottom' 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 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 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 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 normal: { color: '#304654', borderColor: '#304654', borderWidth: 1 }, emphasis: { color: '#c23531', borderColor: '#c23531', borderWidth: 2 } }, data: [] } }); zrUtil.mixin(SliderTimelineModel, modelUtil.dataFormatMixin); module.exports = SliderTimelineModel; /***/ }, /* 364 */ /***/ function(module, exports, __webpack_require__) { /** * @file Timeline model */ var ComponentModel = __webpack_require__(19); var List = __webpack_require__(98); var zrUtil = __webpack_require__(4); var modelUtil = __webpack_require__(5); var TimelineModel = ComponentModel.extend({ type: 'timeline', layoutMode: 'box', /** * @protected */ defaultOption: { zlevel: 0, // 一级层叠 z: 4, // 二级层叠 show: true, axisType: 'time', // 模式是时间类型,支持 value, category realtime: true, left: '20%', top: null, right: '20%', bottom: 0, width: null, height: 40, padding: 5, controlPosition: 'left', // 'left' 'right' 'top' 'bottom' 'none' autoPlay: false, rewind: false, // 反向播放 loop: true, playInterval: 2000, // 播放时间间隔,单位ms currentIndex: 0, itemStyle: { normal: {}, emphasis: {} }, label: { normal: { textStyle: { color: '#000' } }, emphasis: {} }, data: [] }, /** * @override */ init: function (option, parentModel, ecModel) { /** * @private * @type {module:echarts/data/List} */ this._data; /** * @private * @type {Array.} */ this._names; this.mergeDefaultAndTheme(option, ecModel); this._initData(); }, /** * @override */ mergeOption: function (option) { TimelineModel.superApply(this, 'mergeOption', arguments); this._initData(); }, /** * @param {number} [currentIndex] */ setCurrentIndex: function (currentIndex) { if (currentIndex == null) { currentIndex = this.option.currentIndex; } var count = this._data.count(); if (this.option.loop) { currentIndex = (currentIndex % count + count) % count; } else { currentIndex >= count && (currentIndex = count - 1); currentIndex < 0 && (currentIndex = 0); } this.option.currentIndex = currentIndex; }, /** * @return {number} currentIndex */ getCurrentIndex: function () { return this.option.currentIndex; }, /** * @return {boolean} */ isIndexMax: function () { return this.getCurrentIndex() >= this._data.count() - 1; }, /** * @param {boolean} state true: play, false: stop */ setPlayState: function (state) { this.option.autoPlay = !!state; }, /** * @return {boolean} true: play, false: stop */ getPlayState: function () { return !!this.option.autoPlay; }, /** * @private */ _initData: function () { var thisOption = this.option; var dataArr = thisOption.data || []; var axisType = thisOption.axisType; var names = this._names = []; if (axisType === 'category') { var idxArr = []; zrUtil.each(dataArr, function (item, index) { var value = modelUtil.getDataItemValue(item); var newItem; if (zrUtil.isObject(item)) { newItem = zrUtil.clone(item); newItem.value = index; } else { newItem = index; } idxArr.push(newItem); if (!zrUtil.isString(value) && (value == null || isNaN(value))) { value = ''; } names.push(value + ''); }); dataArr = idxArr; } var dimType = ({category: 'ordinal', time: 'time'})[axisType] || 'number'; var data = this._data = new List([{name: 'value', type: dimType}], this); data.initData(dataArr, names); }, getData: function () { return this._data; }, /** * @public * @return {Array.} categoreis */ getCategories: function () { if (this.get('axisType') === 'category') { return this._names.slice(); } } }); module.exports = TimelineModel; /***/ }, /* 365 */ /***/ function(module, exports, __webpack_require__) { /** * @file Silder timeline view */ var zrUtil = __webpack_require__(4); var graphic = __webpack_require__(43); var layout = __webpack_require__(21); var TimelineView = __webpack_require__(366); var TimelineAxis = __webpack_require__(367); var symbolUtil = __webpack_require__(107); var axisHelper = __webpack_require__(115); var BoundingRect = __webpack_require__(9); var matrix = __webpack_require__(11); var numberUtil = __webpack_require__(7); var formatUtil = __webpack_require__(6); var encodeHTML = formatUtil.encodeHTML; var bind = zrUtil.bind; var each = zrUtil.each; var PI = Math.PI; module.exports = TimelineView.extend({ type: 'timeline.slider', init: function (ecModel, api) { this.api = api; /** * @private * @type {module:echarts/component/timeline/TimelineAxis} */ this._axis; /** * @private * @type {module:zrender/core/BoundingRect} */ this._viewRect; /** * @type {number} */ this._timer; /** * @type {module:zrende/Element} */ this._currentPointer; /** * @type {module:zrender/container/Group} */ this._mainGroup; /** * @type {module:zrender/container/Group} */ this._labelGroup; }, /** * @override */ render: function (timelineModel, ecModel, api, payload) { this.model = timelineModel; this.api = api; this.ecModel = ecModel; this.group.removeAll(); if (timelineModel.get('show', true)) { var layoutInfo = this._layout(timelineModel, api); var mainGroup = this._createGroup('mainGroup'); var labelGroup = this._createGroup('labelGroup'); /** * @private * @type {module:echarts/component/timeline/TimelineAxis} */ var axis = this._axis = this._createAxis(layoutInfo, timelineModel); timelineModel.formatTooltip = function (dataIndex) { return encodeHTML(axis.scale.getLabel(dataIndex)); }; each( ['AxisLine', 'AxisTick', 'Control', 'CurrentPointer'], function (name) { this['_render' + name](layoutInfo, mainGroup, axis, timelineModel); }, this ); this._renderAxisLabel(layoutInfo, labelGroup, axis, timelineModel); this._position(layoutInfo, timelineModel); } this._doPlayStop(); }, /** * @override */ remove: function () { this._clearTimer(); this.group.removeAll(); }, /** * @override */ dispose: function () { this._clearTimer(); }, _layout: function (timelineModel, api) { var labelPosOpt = timelineModel.get('label.normal.position'); var orient = timelineModel.get('orient'); var viewRect = getViewRect(timelineModel, api); // Auto label offset. if (labelPosOpt == null || labelPosOpt === 'auto') { labelPosOpt = orient === 'horizontal' ? ((viewRect.y + viewRect.height / 2) < api.getHeight() / 2 ? '-' : '+') : ((viewRect.x + viewRect.width / 2) < api.getWidth() / 2 ? '+' : '-'); } else if (isNaN(labelPosOpt)) { labelPosOpt = ({ horizontal: {top: '-', bottom: '+'}, vertical: {left: '-', right: '+'} })[orient][labelPosOpt]; } // FIXME // 暂没有实现用户传入 // var labelAlign = timelineModel.get('label.normal.textStyle.align'); // var labelBaseline = timelineModel.get('label.normal.textStyle.baseline'); var labelAlignMap = { horizontal: 'center', vertical: (labelPosOpt >= 0 || labelPosOpt === '+') ? 'left' : 'right' }; var labelBaselineMap = { horizontal: (labelPosOpt >= 0 || labelPosOpt === '+') ? 'top' : 'bottom', vertical: 'middle' }; var rotationMap = { horizontal: 0, vertical: PI / 2 }; // Position var mainLength = orient === 'vertical' ? viewRect.height : viewRect.width; var controlModel = timelineModel.getModel('controlStyle'); var showControl = controlModel.get('show'); var controlSize = showControl ? controlModel.get('itemSize') : 0; var controlGap = showControl ? controlModel.get('itemGap') : 0; var sizePlusGap = controlSize + controlGap; // Special label rotate. var labelRotation = timelineModel.get('label.normal.rotate') || 0; labelRotation = labelRotation * PI / 180; // To radian. var playPosition; var prevBtnPosition; var nextBtnPosition; var axisExtent; var controlPosition = controlModel.get('position', true); var showControl = controlModel.get('show', true); var showPlayBtn = showControl && controlModel.get('showPlayBtn', true); var showPrevBtn = showControl && controlModel.get('showPrevBtn', true); var showNextBtn = showControl && controlModel.get('showNextBtn', true); var xLeft = 0; var xRight = mainLength; // position[0] means left, position[1] means middle. if (controlPosition === 'left' || controlPosition === 'bottom') { showPlayBtn && (playPosition = [0, 0], xLeft += sizePlusGap); showPrevBtn && (prevBtnPosition = [xLeft, 0], xLeft += sizePlusGap); showNextBtn && (nextBtnPosition = [xRight - controlSize, 0], xRight -= sizePlusGap); } else { // 'top' 'right' showPlayBtn && (playPosition = [xRight - controlSize, 0], xRight -= sizePlusGap); showPrevBtn && (prevBtnPosition = [0, 0], xLeft += sizePlusGap); showNextBtn && (nextBtnPosition = [xRight - controlSize, 0], xRight -= sizePlusGap); } axisExtent = [xLeft, xRight]; if (timelineModel.get('inverse')) { axisExtent.reverse(); } return { viewRect: viewRect, mainLength: mainLength, orient: orient, rotation: rotationMap[orient], labelRotation: labelRotation, labelPosOpt: labelPosOpt, labelAlign: labelAlignMap[orient], labelBaseline: labelBaselineMap[orient], // Based on mainGroup. playPosition: playPosition, prevBtnPosition: prevBtnPosition, nextBtnPosition: nextBtnPosition, axisExtent: axisExtent, controlSize: controlSize, controlGap: controlGap }; }, _position: function (layoutInfo, timelineModel) { // Position is be called finally, because bounding rect is needed for // adapt content to fill viewRect (auto adapt offset). // Timeline may be not all in the viewRect when 'offset' is specified // as a number, because it is more appropriate that label aligns at // 'offset' but not the other edge defined by viewRect. var mainGroup = this._mainGroup; var labelGroup = this._labelGroup; var viewRect = layoutInfo.viewRect; if (layoutInfo.orient === 'vertical') { // transfrom to horizontal, inverse rotate by left-top point. var m = matrix.create(); var rotateOriginX = viewRect.x; var rotateOriginY = viewRect.y + viewRect.height; matrix.translate(m, m, [-rotateOriginX, -rotateOriginY]); matrix.rotate(m, m, -PI / 2); matrix.translate(m, m, [rotateOriginX, rotateOriginY]); viewRect = viewRect.clone(); viewRect.applyTransform(m); } var viewBound = getBound(viewRect); var mainBound = getBound(mainGroup.getBoundingRect()); var labelBound = getBound(labelGroup.getBoundingRect()); var mainPosition = mainGroup.position; var labelsPosition = labelGroup.position; labelsPosition[0] = mainPosition[0] = viewBound[0][0]; var labelPosOpt = layoutInfo.labelPosOpt; if (isNaN(labelPosOpt)) { // '+' or '-' var mainBoundIdx = labelPosOpt === '+' ? 0 : 1; toBound(mainPosition, mainBound, viewBound, 1, mainBoundIdx); toBound(labelsPosition, labelBound, viewBound, 1, 1 - mainBoundIdx); } else { var mainBoundIdx = labelPosOpt >= 0 ? 0 : 1; toBound(mainPosition, mainBound, viewBound, 1, mainBoundIdx); labelsPosition[1] = mainPosition[1] + labelPosOpt; } mainGroup.attr('position', mainPosition); labelGroup.attr('position', labelsPosition); mainGroup.rotation = labelGroup.rotation = layoutInfo.rotation; setOrigin(mainGroup); setOrigin(labelGroup); function setOrigin(targetGroup) { var pos = targetGroup.position; targetGroup.origin = [ viewBound[0][0] - pos[0], viewBound[1][0] - pos[1] ]; } function getBound(rect) { // [[xmin, xmax], [ymin, ymax]] return [ [rect.x, rect.x + rect.width], [rect.y, rect.y + rect.height] ]; } function toBound(fromPos, from, to, dimIdx, boundIdx) { fromPos[dimIdx] += to[dimIdx][boundIdx] - from[dimIdx][boundIdx]; } }, _createAxis: function (layoutInfo, timelineModel) { var data = timelineModel.getData(); var axisType = timelineModel.get('axisType'); var scale = axisHelper.createScaleByModel(timelineModel, axisType); var dataExtent = data.getDataExtent('value'); scale.setExtent(dataExtent[0], dataExtent[1]); this._customizeScale(scale, data); scale.niceTicks(); var axis = new TimelineAxis('value', scale, layoutInfo.axisExtent, axisType); axis.model = timelineModel; return axis; }, _customizeScale: function (scale, data) { scale.getTicks = function () { return data.mapArray(['value'], function (value) { return value; }); }; scale.getTicksLabels = function () { return zrUtil.map(this.getTicks(), scale.getLabel, scale); }; }, _createGroup: function (name) { var newGroup = this['_' + name] = new graphic.Group(); this.group.add(newGroup); return newGroup; }, _renderAxisLine: function (layoutInfo, group, axis, timelineModel) { var axisExtent = axis.getExtent(); if (!timelineModel.get('lineStyle.show')) { return; } group.add(new graphic.Line({ shape: { x1: axisExtent[0], y1: 0, x2: axisExtent[1], y2: 0 }, style: zrUtil.extend( {lineCap: 'round'}, timelineModel.getModel('lineStyle').getLineStyle() ), silent: true, z2: 1 })); }, /** * @private */ _renderAxisTick: function (layoutInfo, group, axis, timelineModel) { var data = timelineModel.getData(); var ticks = axis.scale.getTicks(); each(ticks, function (value, dataIndex) { var tickCoord = axis.dataToCoord(value); var itemModel = data.getItemModel(dataIndex); var itemStyleModel = itemModel.getModel('itemStyle.normal'); var hoverStyleModel = itemModel.getModel('itemStyle.emphasis'); var symbolOpt = { position: [tickCoord, 0], onclick: bind(this._changeTimeline, this, dataIndex) }; var el = giveSymbol(itemModel, itemStyleModel, group, symbolOpt); graphic.setHoverStyle(el, hoverStyleModel.getItemStyle()); if (itemModel.get('tooltip')) { el.dataIndex = dataIndex; el.dataModel = timelineModel; } else { el.dataIndex = el.dataModel = null; } }, this); }, /** * @private */ _renderAxisLabel: function (layoutInfo, group, axis, timelineModel) { var labelModel = timelineModel.getModel('label.normal'); if (!labelModel.get('show')) { return; } var data = timelineModel.getData(); var ticks = axis.scale.getTicks(); var labels = axisHelper.getFormattedLabels( axis, labelModel.get('formatter') ); var labelInterval = axis.getLabelInterval(); each(ticks, function (tick, dataIndex) { if (axis.isLabelIgnored(dataIndex, labelInterval)) { return; } var itemModel = data.getItemModel(dataIndex); var itemTextStyleModel = itemModel.getModel('label.normal.textStyle'); var hoverTextStyleModel = itemModel.getModel('label.emphasis.textStyle'); var tickCoord = axis.dataToCoord(tick); var textEl = new graphic.Text({ style: { text: labels[dataIndex], textAlign: layoutInfo.labelAlign, textVerticalAlign: layoutInfo.labelBaseline, textFont: itemTextStyleModel.getFont(), fill: itemTextStyleModel.getTextColor() }, position: [tickCoord, 0], rotation: layoutInfo.labelRotation - layoutInfo.rotation, onclick: bind(this._changeTimeline, this, dataIndex), silent: false }); group.add(textEl); graphic.setHoverStyle(textEl, hoverTextStyleModel.getItemStyle()); }, this); }, /** * @private */ _renderControl: function (layoutInfo, group, axis, timelineModel) { var controlSize = layoutInfo.controlSize; var rotation = layoutInfo.rotation; var itemStyle = timelineModel.getModel('controlStyle.normal').getItemStyle(); var hoverStyle = timelineModel.getModel('controlStyle.emphasis').getItemStyle(); var rect = [0, -controlSize / 2, controlSize, controlSize]; var playState = timelineModel.getPlayState(); var inverse = timelineModel.get('inverse', true); makeBtn( layoutInfo.nextBtnPosition, 'controlStyle.nextIcon', bind(this._changeTimeline, this, inverse ? '-' : '+') ); makeBtn( layoutInfo.prevBtnPosition, 'controlStyle.prevIcon', bind(this._changeTimeline, this, inverse ? '+' : '-') ); makeBtn( layoutInfo.playPosition, 'controlStyle.' + (playState ? 'stopIcon' : 'playIcon'), bind(this._handlePlayClick, this, !playState), true ); function makeBtn(position, iconPath, onclick, willRotate) { if (!position) { return; } var opt = { position: position, origin: [controlSize / 2, 0], rotation: willRotate ? -rotation : 0, rectHover: true, style: itemStyle, onclick: onclick }; var btn = makeIcon(timelineModel, iconPath, rect, opt); group.add(btn); graphic.setHoverStyle(btn, hoverStyle); } }, _renderCurrentPointer: function (layoutInfo, group, axis, timelineModel) { var data = timelineModel.getData(); var currentIndex = timelineModel.getCurrentIndex(); var pointerModel = data.getItemModel(currentIndex).getModel('checkpointStyle'); var me = this; var callback = { onCreate: function (pointer) { pointer.draggable = true; pointer.drift = bind(me._handlePointerDrag, me); pointer.ondragend = bind(me._handlePointerDragend, me); pointerMoveTo(pointer, currentIndex, axis, timelineModel, true); }, onUpdate: function (pointer) { pointerMoveTo(pointer, currentIndex, axis, timelineModel); } }; // Reuse when exists, for animation and drag. this._currentPointer = giveSymbol( pointerModel, pointerModel, this._mainGroup, {}, this._currentPointer, callback ); }, _handlePlayClick: function (nextState) { this._clearTimer(); this.api.dispatchAction({ type: 'timelinePlayChange', playState: nextState, from: this.uid }); }, _handlePointerDrag: function (dx, dy, e) { this._clearTimer(); this._pointerChangeTimeline([e.offsetX, e.offsetY]); }, _handlePointerDragend: function (e) { this._pointerChangeTimeline([e.offsetX, e.offsetY], true); }, _pointerChangeTimeline: function (mousePos, trigger) { var toCoord = this._toAxisCoord(mousePos)[0]; var axis = this._axis; var axisExtent = numberUtil.asc(axis.getExtent().slice()); toCoord > axisExtent[1] && (toCoord = axisExtent[1]); toCoord < axisExtent[0] && (toCoord = axisExtent[0]); this._currentPointer.position[0] = toCoord; this._currentPointer.dirty(); var targetDataIndex = this._findNearestTick(toCoord); var timelineModel = this.model; if (trigger || ( targetDataIndex !== timelineModel.getCurrentIndex() && timelineModel.get('realtime') )) { this._changeTimeline(targetDataIndex); } }, _doPlayStop: function () { this._clearTimer(); if (this.model.getPlayState()) { this._timer = setTimeout( bind(handleFrame, this), this.model.get('playInterval') ); } function handleFrame() { // Do not cache var timelineModel = this.model; this._changeTimeline( timelineModel.getCurrentIndex() + (timelineModel.get('rewind', true) ? -1 : 1) ); } }, _toAxisCoord: function (vertex) { var trans = this._mainGroup.getLocalTransform(); return graphic.applyTransform(vertex, trans, true); }, _findNearestTick: function (axisCoord) { var data = this.model.getData(); var dist = Infinity; var targetDataIndex; var axis = this._axis; data.each(['value'], function (value, dataIndex) { var coord = axis.dataToCoord(value); var d = Math.abs(coord - axisCoord); if (d < dist) { dist = d; targetDataIndex = dataIndex; } }); return targetDataIndex; }, _clearTimer: function () { if (this._timer) { clearTimeout(this._timer); this._timer = null; } }, _changeTimeline: function (nextIndex) { var currentIndex = this.model.getCurrentIndex(); if (nextIndex === '+') { nextIndex = currentIndex + 1; } else if (nextIndex === '-') { nextIndex = currentIndex - 1; } this.api.dispatchAction({ type: 'timelineChange', currentIndex: nextIndex, from: this.uid }); } }); function getViewRect(model, api) { return layout.getLayoutRect( model.getBoxLayoutParams(), { width: api.getWidth(), height: api.getHeight() }, model.get('padding') ); } function makeIcon(timelineModel, objPath, rect, opts) { var icon = graphic.makePath( timelineModel.get(objPath).replace(/^path:\/\//, ''), zrUtil.clone(opts || {}), new BoundingRect(rect[0], rect[1], rect[2], rect[3]), 'center' ); return icon; } /** * Create symbol or update symbol * opt: basic position and event handlers */ function giveSymbol(hostModel, itemStyleModel, group, opt, symbol, callback) { var color = itemStyleModel.get('color'); if (!symbol) { var symbolType = hostModel.get('symbol'); symbol = symbolUtil.createSymbol(symbolType, -1, -1, 2, 2, color); symbol.setStyle('strokeNoScale', true); group.add(symbol); callback && callback.onCreate(symbol); } else { symbol.setColor(color); group.add(symbol); // Group may be new, also need to add. callback && callback.onUpdate(symbol); } // Style var itemStyle = itemStyleModel.getItemStyle(['color', 'symbol', 'symbolSize']); symbol.setStyle(itemStyle); // Transform and events. opt = zrUtil.merge({ rectHover: true, z2: 100 }, opt, true); var symbolSize = hostModel.get('symbolSize'); symbolSize = symbolSize instanceof Array ? symbolSize.slice() : [+symbolSize, +symbolSize]; symbolSize[0] /= 2; symbolSize[1] /= 2; opt.scale = symbolSize; var symbolOffset = hostModel.get('symbolOffset'); if (symbolOffset) { var pos = opt.position = opt.position || [0, 0]; pos[0] += numberUtil.parsePercent(symbolOffset[0], symbolSize[0]); pos[1] += numberUtil.parsePercent(symbolOffset[1], symbolSize[1]); } var symbolRotate = hostModel.get('symbolRotate'); opt.rotation = (symbolRotate || 0) * Math.PI / 180 || 0; symbol.attr(opt); // FIXME // (1) When symbol.style.strokeNoScale is true and updateTransform is not performed, // getBoundingRect will return wrong result. // (This is supposed to be resolved in zrender, but it is a little difficult to // leverage performance and auto updateTransform) // (2) All of ancesters of symbol do not scale, so we can just updateTransform symbol. symbol.updateTransform(); return symbol; } function pointerMoveTo(pointer, dataIndex, axis, timelineModel, noAnimation) { if (pointer.dragging) { return; } var pointerModel = timelineModel.getModel('checkpointStyle'); var toCoord = axis.dataToCoord(timelineModel.getData().get(['value'], dataIndex)); if (noAnimation || !pointerModel.get('animation', true)) { pointer.attr({position: [toCoord, 0]}); } else { pointer.stopAnimation(true); pointer.animateTo( {position: [toCoord, 0]}, pointerModel.get('animationDuration', true), pointerModel.get('animationEasing', true) ); } } /***/ }, /* 366 */ /***/ function(module, exports, __webpack_require__) { /** * @file Timeline view */ // var zrUtil = require('zrender/lib/core/util'); // var graphic = require('../../util/graphic'); var ComponentView = __webpack_require__(29); module.exports = ComponentView.extend({ type: 'timeline' }); /***/ }, /* 367 */ /***/ function(module, exports, __webpack_require__) { var zrUtil = __webpack_require__(4); var Axis = __webpack_require__(124); var axisHelper = __webpack_require__(115); /** * Extend axis 2d * @constructor module:echarts/coord/cartesian/Axis2D * @extends {module:echarts/coord/cartesian/Axis} * @param {string} dim * @param {*} scale * @param {Array.} coordExtent * @param {string} axisType * @param {string} position */ var TimelineAxis = function (dim, scale, coordExtent, axisType) { Axis.call(this, dim, scale, coordExtent); /** * Axis type * - 'category' * - 'value' * - 'time' * - 'log' * @type {string} */ this.type = axisType || 'value'; /** * @private * @type {number} */ this._autoLabelInterval; /** * Axis model * @param {module:echarts/component/TimelineModel} */ this.model = null; }; TimelineAxis.prototype = { constructor: TimelineAxis, /** * @public * @return {number} */ getLabelInterval: function () { var timelineModel = this.model; var labelModel = timelineModel.getModel('label.normal'); var labelInterval = labelModel.get('interval'); if (labelInterval != null && labelInterval != 'auto') { return labelInterval; } var labelInterval = this._autoLabelInterval; if (!labelInterval) { labelInterval = this._autoLabelInterval = axisHelper.getAxisLabelInterval( zrUtil.map(this.scale.getTicks(), this.dataToCoord, this), axisHelper.getFormattedLabels(this, labelModel.get('formatter')), labelModel.getModel('textStyle').getFont(), timelineModel.get('orient') === 'horizontal' ); } return labelInterval; }, /** * If label is ignored. * Automatically used when axis is category and label can not be all shown * @public * @param {number} idx * @return {boolean} */ isLabelIgnored: function (idx) { if (this.type === 'category') { var labelInterval = this.getLabelInterval(); return ((typeof labelInterval === 'function') && !labelInterval(idx, this.scale.getLabel(idx))) || idx % (labelInterval + 1); } } }; zrUtil.inherits(TimelineAxis, Axis); module.exports = TimelineAxis; /***/ }, /* 368 */ /***/ function(module, exports, __webpack_require__) { __webpack_require__(369); __webpack_require__(370); __webpack_require__(372); __webpack_require__(373); __webpack_require__(374); __webpack_require__(375); __webpack_require__(380); /***/ }, /* 369 */ /***/ function(module, exports, __webpack_require__) { var featureManager = __webpack_require__(316); var zrUtil = __webpack_require__(4); var ToolboxModel = __webpack_require__(1).extendComponentModel({ type: 'toolbox', layoutMode: { type: 'box', ignoreSize: true }, mergeDefaultAndTheme: function (option) { ToolboxModel.superApply(this, 'mergeDefaultAndTheme', arguments); zrUtil.each(this.option.feature, function (featureOpt, featureName) { var Feature = featureManager.get(featureName); Feature && zrUtil.merge(featureOpt, Feature.defaultOption); }); }, defaultOption: { show: true, z: 6, zlevel: 0, orient: 'horizontal', left: 'right', top: 'top', // right // bottom backgroundColor: 'transparent', borderColor: '#ccc', borderWidth: 0, padding: 5, itemSize: 15, itemGap: 8, showTitle: true, iconStyle: { normal: { borderColor: '#666', color: 'none' }, emphasis: { borderColor: '#3E98C5' } } // textStyle: {}, // feature } }); module.exports = ToolboxModel; /***/ }, /* 370 */ /***/ function(module, exports, __webpack_require__) { /* WEBPACK VAR INJECTION */(function(process) { var featureManager = __webpack_require__(316); var zrUtil = __webpack_require__(4); var graphic = __webpack_require__(43); var Model = __webpack_require__(12); var DataDiffer = __webpack_require__(99); var listComponentHelper = __webpack_require__(280); var textContain = __webpack_require__(8); module.exports = __webpack_require__(1).extendComponentView({ type: 'toolbox', render: function (toolboxModel, ecModel, api, payload) { var group = this.group; group.removeAll(); if (!toolboxModel.get('show')) { return; } var itemSize = +toolboxModel.get('itemSize'); var featureOpts = toolboxModel.get('feature') || {}; var features = this._features || (this._features = {}); var featureNames = []; zrUtil.each(featureOpts, function (opt, name) { featureNames.push(name); }); (new DataDiffer(this._featureNames || [], featureNames)) .add(process) .update(process) .remove(zrUtil.curry(process, null)) .execute(); // Keep for diff. this._featureNames = featureNames; function process(newIndex, oldIndex) { var featureName = featureNames[newIndex]; var oldName = featureNames[oldIndex]; var featureOpt = featureOpts[featureName]; var featureModel = new Model(featureOpt, toolboxModel, toolboxModel.ecModel); var feature; if (featureName && !oldName) { // Create if (isUserFeatureName(featureName)) { feature = { model: featureModel, onclick: featureModel.option.onclick, featureName: featureName }; } else { var Feature = featureManager.get(featureName); if (!Feature) { return; } feature = new Feature(featureModel, ecModel, api); } features[featureName] = feature; } else { feature = features[oldName]; // If feature does not exsit. if (!feature) { return; } feature.model = featureModel; feature.ecModel = ecModel; feature.api = api; } if (!featureName && oldName) { feature.dispose && feature.dispose(ecModel, api); return; } if (!featureModel.get('show') || feature.unusable) { feature.remove && feature.remove(ecModel, api); return; } createIconPaths(featureModel, feature, featureName); featureModel.setIconStatus = function (iconName, status) { var option = this.option; var iconPaths = this.iconPaths; option.iconStatus = option.iconStatus || {}; option.iconStatus[iconName] = status; // FIXME iconPaths[iconName] && iconPaths[iconName].trigger(status); }; if (feature.render) { feature.render(featureModel, ecModel, api, payload); } } function createIconPaths(featureModel, feature, featureName) { var iconStyleModel = featureModel.getModel('iconStyle'); // If one feature has mutiple icon. they are orginaized as // { // icon: { // foo: '', // bar: '' // }, // title: { // foo: '', // bar: '' // } // } var icons = feature.getIcons ? feature.getIcons() : featureModel.get('icon'); var titles = featureModel.get('title') || {}; if (typeof icons === 'string') { var icon = icons; var title = titles; icons = {}; titles = {}; icons[featureName] = icon; titles[featureName] = title; } var iconPaths = featureModel.iconPaths = {}; zrUtil.each(icons, function (icon, iconName) { var normalStyle = iconStyleModel.getModel('normal').getItemStyle(); var hoverStyle = iconStyleModel.getModel('emphasis').getItemStyle(); var style = { x: -itemSize / 2, y: -itemSize / 2, width: itemSize, height: itemSize }; var path = icon.indexOf('image://') === 0 ? ( style.image = icon.slice(8), new graphic.Image({style: style}) ) : graphic.makePath( icon.replace('path://', ''), { style: normalStyle, hoverStyle: hoverStyle, rectHover: true }, style, 'center' ); graphic.setHoverStyle(path); if (toolboxModel.get('showTitle')) { path.__title = titles[iconName]; path.on('mouseover', function () { // Should not reuse above hoverStyle, which might be modified. var hoverStyle = iconStyleModel.getModel('emphasis').getItemStyle(); path.setStyle({ text: titles[iconName], textPosition: hoverStyle.textPosition || 'bottom', textFill: hoverStyle.fill || hoverStyle.stroke || '#000', textAlign: hoverStyle.textAlign || 'center' }); }) .on('mouseout', function () { path.setStyle({ textFill: null }); }); } path.trigger(featureModel.get('iconStatus.' + iconName) || 'normal'); group.add(path); path.on('click', zrUtil.bind( feature.onclick, feature, ecModel, api, iconName )); iconPaths[iconName] = path; }); } listComponentHelper.layout(group, toolboxModel, api); // Render background after group is layout // FIXME listComponentHelper.addBackground(group, toolboxModel); // Adjust icon title positions to avoid them out of screen group.eachChild(function (icon) { var titleText = icon.__title; var hoverStyle = icon.hoverStyle; // May be background element if (hoverStyle && titleText) { var rect = textContain.getBoundingRect( titleText, hoverStyle.font ); var offsetX = icon.position[0] + group.position[0]; var offsetY = icon.position[1] + group.position[1] + itemSize; var needPutOnTop = false; if (offsetY + rect.height > api.getHeight()) { hoverStyle.textPosition = 'top'; needPutOnTop = true; } var topOffset = needPutOnTop ? (-5 - rect.height) : (itemSize + 8); if (offsetX + rect.width / 2 > api.getWidth()) { hoverStyle.textPosition = ['100%', topOffset]; hoverStyle.textAlign = 'right'; } else if (offsetX - rect.width / 2 < 0) { hoverStyle.textPosition = [0, topOffset]; hoverStyle.textAlign = 'left'; } } }); }, updateView: function (toolboxModel, ecModel, api, payload) { zrUtil.each(this._features, function (feature) { feature.updateView && feature.updateView(feature.model, ecModel, api, payload); }); }, updateLayout: function (toolboxModel, ecModel, api, payload) { zrUtil.each(this._features, function (feature) { feature.updateLayout && feature.updateLayout(feature.model, ecModel, api, payload); }); }, remove: function (ecModel, api) { zrUtil.each(this._features, function (feature) { feature.remove && feature.remove(ecModel, api); }); this.group.removeAll(); }, dispose: function (ecModel, api) { zrUtil.each(this._features, function (feature) { feature.dispose && feature.dispose(ecModel, api); }); } }); function isUserFeatureName(featureName) { return featureName.indexOf('my') === 0; } /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(371))) /***/ }, /* 371 */ /***/ function(module, exports) { // shim for using process in browser var process = module.exports = {}; // cached from whatever global is present so that test runners that stub it // don't break things. But we need to wrap it in a try catch in case it is // wrapped in strict mode code which doesn't define any globals. It's inside a // function because try/catches deoptimize in certain engines. var cachedSetTimeout; var cachedClearTimeout; function defaultSetTimout() { throw new Error('setTimeout has not been defined'); } function defaultClearTimeout () { throw new Error('clearTimeout has not been defined'); } (function () { try { if (typeof setTimeout === 'function') { cachedSetTimeout = setTimeout; } else { cachedSetTimeout = defaultSetTimout; } } catch (e) { cachedSetTimeout = defaultSetTimout; } try { if (typeof clearTimeout === 'function') { cachedClearTimeout = clearTimeout; } else { cachedClearTimeout = defaultClearTimeout; } } catch (e) { cachedClearTimeout = defaultClearTimeout; } } ()) function runTimeout(fun) { if (cachedSetTimeout === setTimeout) { //normal enviroments in sane situations return setTimeout(fun, 0); } // if setTimeout wasn't available but was latter defined if ((cachedSetTimeout === defaultSetTimout || !cachedSetTimeout) && setTimeout) { cachedSetTimeout = setTimeout; return setTimeout(fun, 0); } try { // when when somebody has screwed with setTimeout but no I.E. maddness return cachedSetTimeout(fun, 0); } catch(e){ try { // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally return cachedSetTimeout.call(null, fun, 0); } catch(e){ // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error return cachedSetTimeout.call(this, fun, 0); } } } function runClearTimeout(marker) { if (cachedClearTimeout === clearTimeout) { //normal enviroments in sane situations return clearTimeout(marker); } // if clearTimeout wasn't available but was latter defined if ((cachedClearTimeout === defaultClearTimeout || !cachedClearTimeout) && clearTimeout) { cachedClearTimeout = clearTimeout; return clearTimeout(marker); } try { // when when somebody has screwed with setTimeout but no I.E. maddness return cachedClearTimeout(marker); } catch (e){ try { // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally return cachedClearTimeout.call(null, marker); } catch (e){ // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error. // Some versions of I.E. have different rules for clearTimeout vs setTimeout return cachedClearTimeout.call(this, marker); } } } var queue = []; var draining = false; var currentQueue; var queueIndex = -1; function cleanUpNextTick() { if (!draining || !currentQueue) { return; } draining = false; if (currentQueue.length) { queue = currentQueue.concat(queue); } else { queueIndex = -1; } if (queue.length) { drainQueue(); } } function drainQueue() { if (draining) { return; } var timeout = runTimeout(cleanUpNextTick); draining = true; var len = queue.length; while(len) { currentQueue = queue; queue = []; while (++queueIndex < len) { if (currentQueue) { currentQueue[queueIndex].run(); } } queueIndex = -1; len = queue.length; } currentQueue = null; draining = false; runClearTimeout(timeout); } process.nextTick = function (fun) { var args = new Array(arguments.length - 1); if (arguments.length > 1) { for (var i = 1; i < arguments.length; i++) { args[i - 1] = arguments[i]; } } queue.push(new Item(fun, args)); if (queue.length === 1 && !draining) { runTimeout(drainQueue); } }; // v8 likes predictible objects function Item(fun, array) { this.fun = fun; this.array = array; } Item.prototype.run = function () { this.fun.apply(null, this.array); }; process.title = 'browser'; process.browser = true; process.env = {}; process.argv = []; process.version = ''; // empty string to avoid regexp issues process.versions = {}; function noop() {} process.on = noop; process.addListener = noop; process.once = noop; process.off = noop; process.removeListener = noop; process.removeAllListeners = noop; process.emit = noop; process.binding = function (name) { throw new Error('process.binding is not supported'); }; process.cwd = function () { return '/' }; process.chdir = function (dir) { throw new Error('process.chdir is not supported'); }; process.umask = function() { return 0; }; /***/ }, /* 372 */ /***/ function(module, exports, __webpack_require__) { var env = __webpack_require__(2); function SaveAsImage (model) { this.model = model; } SaveAsImage.defaultOption = { show: true, 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', title: '保存为图片', type: 'png', // Default use option.backgroundColor // backgroundColor: '#fff', name: '', excludeComponents: ['toolbox'], pixelRatio: 1, lang: ['右键另存为图片'] }; SaveAsImage.prototype.unusable = !env.canvasSupported; var proto = SaveAsImage.prototype; proto.onclick = function (ecModel, api) { var model = this.model; var title = model.get('name') || ecModel.get('title.0.text') || 'echarts'; var $a = document.createElement('a'); var type = model.get('type', true) || 'png'; $a.download = title + '.' + type; $a.target = '_blank'; var url = api.getConnectedDataURL({ type: type, backgroundColor: model.get('backgroundColor', true) || ecModel.get('backgroundColor') || '#fff', excludeComponents: model.get('excludeComponents'), pixelRatio: model.get('pixelRatio') }); $a.href = url; // Chrome and Firefox if (typeof MouseEvent === 'function' && !env.browser.ie && !env.browser.edge) { var evt = new MouseEvent('click', { view: window, bubbles: true, cancelable: false }); $a.dispatchEvent(evt); } // IE else { var lang = model.get('lang'); var html = '' + '' + '' + ''; var tab = window.open(); tab.document.write(html); } }; __webpack_require__(316).register( 'saveAsImage', SaveAsImage ); module.exports = SaveAsImage; /***/ }, /* 373 */ /***/ function(module, exports, __webpack_require__) { 'use strict'; var zrUtil = __webpack_require__(4); function MagicType(model) { this.model = model; } MagicType.defaultOption = { show: true, type: [], // Icon group icon: { line: 'M4.1,28.9h7.1l9.3-22l7.4,38l9.7-19.7l3,12.8h14.9M4.1,58h51.4', bar: 'M6.7,22.9h10V48h-10V22.9zM24.9,13h10v35h-10V13zM43.2,2h10v46h-10V2zM3.1,58h53.7', 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 tiled: 'M2.3,2.2h22.8V25H2.3V2.2z M35,2.2h22.8V25H35V2.2zM2.3,35h22.8v22.8H2.3V35z M35,35h22.8v22.8H35V35z' }, title: { line: '切换为折线图', bar: '切换为柱状图', stack: '切换为堆叠', tiled: '切换为平铺' }, option: {}, seriesIndex: {} }; var proto = MagicType.prototype; proto.getIcons = function () { var model = this.model; var availableIcons = model.get('icon'); var icons = {}; zrUtil.each(model.get('type'), function (type) { if (availableIcons[type]) { icons[type] = availableIcons[type]; } }); return icons; }; var seriesOptGenreator = { 'line': function (seriesType, seriesId, seriesModel, model) { if (seriesType === 'bar') { return zrUtil.merge({ id: seriesId, type: 'line', // Preserve data related option data: seriesModel.get('data'), stack: seriesModel.get('stack'), markPoint: seriesModel.get('markPoint'), markLine: seriesModel.get('markLine') }, model.get('option.line') || {}, true); } }, 'bar': function (seriesType, seriesId, seriesModel, model) { if (seriesType === 'line') { return zrUtil.merge({ id: seriesId, type: 'bar', // Preserve data related option data: seriesModel.get('data'), stack: seriesModel.get('stack'), markPoint: seriesModel.get('markPoint'), markLine: seriesModel.get('markLine') }, model.get('option.bar') || {}, true); } }, 'stack': function (seriesType, seriesId, seriesModel, model) { if (seriesType === 'line' || seriesType === 'bar') { return zrUtil.merge({ id: seriesId, stack: '__ec_magicType_stack__' }, model.get('option.stack') || {}, true); } }, 'tiled': function (seriesType, seriesId, seriesModel, model) { if (seriesType === 'line' || seriesType === 'bar') { return zrUtil.merge({ id: seriesId, stack: '' }, model.get('option.tiled') || {}, true); } } }; var radioTypes = [ ['line', 'bar'], ['stack', 'tiled'] ]; proto.onclick = function (ecModel, api, type) { var model = this.model; var seriesIndex = model.get('seriesIndex.' + type); // Not supported magicType if (!seriesOptGenreator[type]) { return; } var newOption = { series: [] }; var generateNewSeriesTypes = function (seriesModel) { var seriesType = seriesModel.subType; var seriesId = seriesModel.id; var newSeriesOpt = seriesOptGenreator[type]( seriesType, seriesId, seriesModel, model ); if (newSeriesOpt) { // PENDING If merge original option? zrUtil.defaults(newSeriesOpt, seriesModel.option); newOption.series.push(newSeriesOpt); } // Modify boundaryGap var coordSys = seriesModel.coordinateSystem; if (coordSys && coordSys.type === 'cartesian2d' && (type === 'line' || type === 'bar')) { var categoryAxis = coordSys.getAxesByScale('ordinal')[0]; if (categoryAxis) { var axisDim = categoryAxis.dim; var axisType = axisDim + 'Axis'; var axisModel = ecModel.queryComponents({ mainType: axisType, index: seriesModel.get(name + 'Index'), id: seriesModel.get(name + 'Id') })[0]; var axisIndex = axisModel.componentIndex; newOption[axisType] = newOption[axisType] || []; for (var i = 0; i <= axisIndex; i++) { newOption[axisType][axisIndex] = newOption[axisType][axisIndex] || {}; } newOption[axisType][axisIndex].boundaryGap = type === 'bar' ? true : false; } } }; zrUtil.each(radioTypes, function (radio) { if (zrUtil.indexOf(radio, type) >= 0) { zrUtil.each(radio, function (item) { model.setIconStatus(item, 'normal'); }); } }); model.setIconStatus(type, 'emphasis'); ecModel.eachComponent( { mainType: 'series', query: seriesIndex == null ? null : { seriesIndex: seriesIndex } }, generateNewSeriesTypes ); api.dispatchAction({ type: 'changeMagicType', currentType: type, newOption: newOption }); }; var echarts = __webpack_require__(1); echarts.registerAction({ type: 'changeMagicType', event: 'magicTypeChanged', update: 'prepareAndUpdate' }, function (payload, ecModel) { ecModel.mergeOption(payload.newOption); }); __webpack_require__(316).register('magicType', MagicType); module.exports = MagicType; /***/ }, /* 374 */ /***/ function(module, exports, __webpack_require__) { /** * @module echarts/component/toolbox/feature/DataView */ var zrUtil = __webpack_require__(4); var eventTool = __webpack_require__(88); var BLOCK_SPLITER = new Array(60).join('-'); var ITEM_SPLITER = '\t'; /** * Group series into two types * 1. on category axis, like line, bar * 2. others, like scatter, pie * @param {module:echarts/model/Global} ecModel * @return {Object} * @inner */ function groupSeries(ecModel) { var seriesGroupByCategoryAxis = {}; var otherSeries = []; var meta = []; ecModel.eachRawSeries(function (seriesModel) { var coordSys = seriesModel.coordinateSystem; if (coordSys && (coordSys.type === 'cartesian2d' || coordSys.type === 'polar')) { var baseAxis = coordSys.getBaseAxis(); if (baseAxis.type === 'category') { var key = baseAxis.dim + '_' + baseAxis.index; if (!seriesGroupByCategoryAxis[key]) { seriesGroupByCategoryAxis[key] = { categoryAxis: baseAxis, valueAxis: coordSys.getOtherAxis(baseAxis), series: [] }; meta.push({ axisDim: baseAxis.dim, axisIndex: baseAxis.index }); } seriesGroupByCategoryAxis[key].series.push(seriesModel); } else { otherSeries.push(seriesModel); } } else { otherSeries.push(seriesModel); } }); return { seriesGroupByCategoryAxis: seriesGroupByCategoryAxis, other: otherSeries, meta: meta }; } /** * Assemble content of series on cateogory axis * @param {Array.} series * @return {string} * @inner */ function assembleSeriesWithCategoryAxis(series) { var tables = []; zrUtil.each(series, function (group, key) { var categoryAxis = group.categoryAxis; var valueAxis = group.valueAxis; var valueAxisDim = valueAxis.dim; var headers = [' '].concat(zrUtil.map(group.series, function (series) { return series.name; })); var columns = [categoryAxis.model.getCategories()]; zrUtil.each(group.series, function (series) { columns.push(series.getRawData().mapArray(valueAxisDim, function (val) { return val; })); }); // Assemble table content var lines = [headers.join(ITEM_SPLITER)]; for (var i = 0; i < columns[0].length; i++) { var items = []; for (var j = 0; j < columns.length; j++) { items.push(columns[j][i]); } lines.push(items.join(ITEM_SPLITER)); } tables.push(lines.join('\n')); }); return tables.join('\n\n' + BLOCK_SPLITER + '\n\n'); } /** * Assemble content of other series * @param {Array.} series * @return {string} * @inner */ function assembleOtherSeries(series) { return zrUtil.map(series, function (series) { var data = series.getRawData(); var lines = [series.name]; var vals = []; data.each(data.dimensions, function () { var argLen = arguments.length; var dataIndex = arguments[argLen - 1]; var name = data.getName(dataIndex); for (var i = 0; i < argLen - 1; i++) { vals[i] = arguments[i]; } lines.push((name ? (name + ITEM_SPLITER) : '') + vals.join(ITEM_SPLITER)); }); return lines.join('\n'); }).join('\n\n' + BLOCK_SPLITER + '\n\n'); } /** * @param {module:echarts/model/Global} * @return {string} * @inner */ function getContentFromModel(ecModel) { var result = groupSeries(ecModel); return { value: zrUtil.filter([ assembleSeriesWithCategoryAxis(result.seriesGroupByCategoryAxis), assembleOtherSeries(result.other) ], function (str) { return str.replace(/[\n\t\s]/g, ''); }).join('\n\n' + BLOCK_SPLITER + '\n\n'), meta: result.meta }; } function trim(str) { return str.replace(/^\s\s*/, '').replace(/\s\s*$/, ''); } /** * If a block is tsv format */ function isTSVFormat(block) { // Simple method to find out if a block is tsv format var firstLine = block.slice(0, block.indexOf('\n')); if (firstLine.indexOf(ITEM_SPLITER) >= 0) { return true; } } var itemSplitRegex = new RegExp('[' + ITEM_SPLITER + ']+', 'g'); /** * @param {string} tsv * @return {Array.} */ function parseTSVContents(tsv) { var tsvLines = tsv.split(/\n+/g); var headers = trim(tsvLines.shift()).split(itemSplitRegex); var categories = []; var series = zrUtil.map(headers, function (header) { return { name: header, data: [] }; }); for (var i = 0; i < tsvLines.length; i++) { var items = trim(tsvLines[i]).split(itemSplitRegex); categories.push(items.shift()); for (var j = 0; j < items.length; j++) { series[j] && (series[j].data[i] = items[j]); } } return { series: series, categories: categories }; } /** * @param {string} str * @return {Array.} * @inner */ function parseListContents(str) { var lines = str.split(/\n+/g); var seriesName = trim(lines.shift()); var data = []; for (var i = 0; i < lines.length; i++) { var items = trim(lines[i]).split(itemSplitRegex); var name = ''; var value; var hasName = false; if (isNaN(items[0])) { // First item is name hasName = true; name = items[0]; items = items.slice(1); data[i] = { name: name, value: [] }; value = data[i].value; } else { value = data[i] = []; } for (var j = 0; j < items.length; j++) { value.push(+items[j]); } if (value.length === 1) { hasName ? (data[i].value = value[0]) : (data[i] = value[0]); } } return { name: seriesName, data: data }; } /** * @param {string} str * @param {Array.} blockMetaList * @return {Object} * @inner */ function parseContents(str, blockMetaList) { var blocks = str.split(new RegExp('\n*' + BLOCK_SPLITER + '\n*', 'g')); var newOption = { series: [] }; zrUtil.each(blocks, function (block, idx) { if (isTSVFormat(block)) { var result = parseTSVContents(block); var blockMeta = blockMetaList[idx]; var axisKey = blockMeta.axisDim + 'Axis'; if (blockMeta) { newOption[axisKey] = newOption[axisKey] || []; newOption[axisKey][blockMeta.axisIndex] = { data: result.categories }; newOption.series = newOption.series.concat(result.series); } } else { var result = parseListContents(block); newOption.series.push(result); } }); return newOption; } /** * @alias {module:echarts/component/toolbox/feature/DataView} * @constructor * @param {module:echarts/model/Model} model */ function DataView(model) { this._dom = null; this.model = model; } DataView.defaultOption = { show: true, readOnly: false, optionToContent: null, contentToOption: null, 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', title: '数据视图', lang: ['数据视图', '关闭', '刷新'], backgroundColor: '#fff', textColor: '#000', textareaColor: '#fff', textareaBorderColor: '#333', buttonColor: '#c23531', buttonTextColor: '#fff' }; DataView.prototype.onclick = function (ecModel, api) { var container = api.getDom(); var model = this.model; if (this._dom) { container.removeChild(this._dom); } var root = document.createElement('div'); root.style.cssText = 'position:absolute;left:5px;top:5px;bottom:5px;right:5px;'; root.style.backgroundColor = model.get('backgroundColor') || '#fff'; // Create elements var header = document.createElement('h4'); var lang = model.get('lang') || []; header.innerHTML = lang[0] || model.get('title'); header.style.cssText = 'margin: 10px 20px;'; header.style.color = model.get('textColor'); var viewMain = document.createElement('div'); var textarea = document.createElement('textarea'); viewMain.style.cssText = 'display:block;width:100%;overflow:hidden;'; var optionToContent = model.get('optionToContent'); var contentToOption = model.get('contentToOption'); var result = getContentFromModel(ecModel); if (typeof optionToContent === 'function') { var htmlOrDom = optionToContent(api.getOption()); if (typeof htmlOrDom === 'string') { viewMain.innerHTML = htmlOrDom; } else if (zrUtil.isDom(htmlOrDom)) { viewMain.appendChild(htmlOrDom); } } else { // Use default textarea viewMain.appendChild(textarea); textarea.readOnly = model.get('readOnly'); textarea.style.cssText = 'width:100%;height:100%;font-family:monospace;font-size:14px;line-height:1.6rem;'; textarea.style.color = model.get('textColor'); textarea.style.borderColor = model.get('textareaBorderColor'); textarea.style.backgroundColor = model.get('textareaColor'); textarea.value = result.value; } var blockMetaList = result.meta; var buttonContainer = document.createElement('div'); buttonContainer.style.cssText = 'position:absolute;bottom:0;left:0;right:0;'; var buttonStyle = 'float:right;margin-right:20px;border:none;' + 'cursor:pointer;padding:2px 5px;font-size:12px;border-radius:3px'; var closeButton = document.createElement('div'); var refreshButton = document.createElement('div'); buttonStyle += ';background-color:' + model.get('buttonColor'); buttonStyle += ';color:' + model.get('buttonTextColor'); var self = this; function close() { container.removeChild(root); self._dom = null; } eventTool.addEventListener(closeButton, 'click', close); eventTool.addEventListener(refreshButton, 'click', function () { var newOption; try { if (typeof contentToOption === 'function') { newOption = contentToOption(viewMain, api.getOption()); } else { newOption = parseContents(textarea.value, blockMetaList); } } catch (e) { close(); throw new Error('Data view format error ' + e); } if (newOption) { api.dispatchAction({ type: 'changeDataView', newOption: newOption }); } close(); }); closeButton.innerHTML = lang[1]; refreshButton.innerHTML = lang[2]; refreshButton.style.cssText = buttonStyle; closeButton.style.cssText = buttonStyle; !model.get('readOnly') && buttonContainer.appendChild(refreshButton); buttonContainer.appendChild(closeButton); // http://stackoverflow.com/questions/6637341/use-tab-to-indent-in-textarea eventTool.addEventListener(textarea, 'keydown', function (e) { if ((e.keyCode || e.which) === 9) { // get caret position/selection var val = this.value; var start = this.selectionStart; var end = this.selectionEnd; // set textarea value to: text before caret + tab + text after caret this.value = val.substring(0, start) + ITEM_SPLITER + val.substring(end); // put caret at right position again this.selectionStart = this.selectionEnd = start + 1; // prevent the focus lose eventTool.stop(e); } }); root.appendChild(header); root.appendChild(viewMain); root.appendChild(buttonContainer); viewMain.style.height = (container.clientHeight - 80) + 'px'; container.appendChild(root); this._dom = root; }; DataView.prototype.remove = function (ecModel, api) { this._dom && api.getDom().removeChild(this._dom); }; DataView.prototype.dispose = function (ecModel, api) { this.remove(ecModel, api); }; /** * @inner */ function tryMergeDataOption(newData, originalData) { return zrUtil.map(newData, function (newVal, idx) { var original = originalData && originalData[idx]; if (zrUtil.isObject(original) && !zrUtil.isArray(original)) { if (zrUtil.isObject(newVal) && !zrUtil.isArray(newVal)) { newVal = newVal.value; } // Original data has option return zrUtil.defaults({ value: newVal }, original); } else { return newVal; } }); } __webpack_require__(316).register('dataView', DataView); __webpack_require__(1).registerAction({ type: 'changeDataView', event: 'dataViewChanged', update: 'prepareAndUpdate' }, function (payload, ecModel) { var newSeriesOptList = []; zrUtil.each(payload.newOption.series, function (seriesOpt) { var seriesModel = ecModel.getSeriesByName(seriesOpt.name)[0]; if (!seriesModel) { // New created series // Geuss the series type newSeriesOptList.push(zrUtil.extend({ // Default is scatter type: 'scatter' }, seriesOpt)); } else { var originalData = seriesModel.get('data'); newSeriesOptList.push({ name: seriesOpt.name, data: tryMergeDataOption(seriesOpt.data, originalData) }); } }); ecModel.mergeOption(zrUtil.defaults({ series: newSeriesOptList }, payload.newOption)); }); module.exports = DataView; /***/ }, /* 375 */ /***/ function(module, exports, __webpack_require__) { 'use strict'; var zrUtil = __webpack_require__(4); var BrushController = __webpack_require__(235); var brushHelper = __webpack_require__(311); var history = __webpack_require__(376); var each = zrUtil.each; // Use dataZoomSelect __webpack_require__(377); // Spectial component id start with \0ec\0, see echarts/model/Global.js~hasInnerId var DATA_ZOOM_ID_BASE = '\0_ec_\0toolbox-dataZoom_'; function DataZoom(model, ecModel, api) { /** * @private * @type {module:echarts/component/helper/BrushController} */ (this._brushController = new BrushController(api.getZr())) .on('brush', zrUtil.bind(this._onBrush, this)) .mount(); /** * @private * @type {boolean} */ this._isZoomActive; } DataZoom.defaultOption = { show: true, // Icon group icon: { zoom: 'M0,13.5h26.9 M13.5,26.9V0 M32.1,13.5H58V58H13.5 V32.1', back: 'M22,1.4L9.9,13.5l12.3,12.3 M10.3,13.5H54.9v44.6 H10.3v-26' }, title: { zoom: '区域缩放', back: '区域缩放还原' } }; var proto = DataZoom.prototype; proto.render = function (featureModel, ecModel, api, payload) { this.model = featureModel; this.ecModel = ecModel; this.api = api; updateZoomBtnStatus(featureModel, ecModel, this, payload); updateBackBtnStatus(featureModel, ecModel); }; proto.onclick = function (ecModel, api, type) { handlers[type].call(this); }; proto.remove = function (ecModel, api) { this._brushController.unmount(); }; proto.dispose = function (ecModel, api) { this._brushController.dispose(); }; /** * @private */ var handlers = { zoom: function () { var nextActive = !this._isZoomActive; this.api.dispatchAction({ type: 'takeGlobalCursor', key: 'dataZoomSelect', dataZoomSelectActive: nextActive }); }, back: function () { this._dispatchZoomAction(history.pop(this.ecModel)); } }; /** * @private */ proto._onBrush = function (areas, opt) { if (!opt.isEnd || !areas.length) { return; } var snapshot = {}; var ecModel = this.ecModel; this._brushController.updateCovers([]); // remove cover var coordInfoList = brushHelper.makeCoordInfoList( retrieveAxisSetting(this.model.option), ecModel ); var rangesCoordInfoList = []; brushHelper.parseOutputRanges(areas, coordInfoList, ecModel, rangesCoordInfoList); var area = areas[0]; // dataZoom can not multiple area. var coordInfo = rangesCoordInfoList[0]; var coordRange = area.coordRange; var brushType = area.brushType; if (coordInfo && coordRange) { if (brushType === 'rect') { setBatch('xAxis', coordRange[0], coordInfo); setBatch('yAxis', coordRange[1], coordInfo); } else { var axisNames = {lineX: 'xAxis', lineY: 'yAxis'}; setBatch(axisNames[brushType], coordRange, coordInfo); } } history.push(ecModel, snapshot); this._dispatchZoomAction(snapshot); function setBatch(axisName, minMax, coordInfo) { var dataZoomModel = findDataZoom(axisName, coordInfo[axisName], ecModel); if (dataZoomModel) { snapshot[dataZoomModel.id] = { dataZoomId: dataZoomModel.id, startValue: minMax[0], endValue: minMax[1] }; } } function findDataZoom(axisName, axisModel, ecModel) { var dataZoomModel; ecModel.eachComponent( {mainType: 'dataZoom', subType: 'select'}, function (dzModel, dataZoomIndex) { var axisIndex = dzModel.get(axisName + 'Index'); if (axisIndex != null && ecModel.getComponent(axisName, axisIndex) === axisModel ) { dataZoomModel = dzModel; } } ); return dataZoomModel; } }; /** * @private */ proto._dispatchZoomAction = function (snapshot) { var batch = []; // Convert from hash map to array. each(snapshot, function (batchItem, dataZoomId) { batch.push(zrUtil.clone(batchItem)); }); batch.length && this.api.dispatchAction({ type: 'dataZoom', from: this.uid, batch: batch }); }; function retrieveAxisSetting(option) { var setting = {}; // Compatible with previous setting: null => all axis, false => no axis. zrUtil.each(['xAxisIndex', 'yAxisIndex'], function (name) { setting[name] = option[name]; setting[name] == null && (setting[name] = 'all'); (setting[name] === false || setting[name] === 'none') && (setting[name] = []); }); return setting; } function updateBackBtnStatus(featureModel, ecModel) { featureModel.setIconStatus( 'back', history.count(ecModel) > 1 ? 'emphasis' : 'normal' ); } function updateZoomBtnStatus(featureModel, ecModel, view, payload) { var zoomActive = view._isZoomActive; if (payload && payload.type === 'takeGlobalCursor') { zoomActive = payload.key === 'dataZoomSelect' ? payload.dataZoomSelectActive : false; } view._isZoomActive = zoomActive; featureModel.setIconStatus('zoom', zoomActive ? 'emphasis' : 'normal'); var coordInfoList = brushHelper.makeCoordInfoList( retrieveAxisSetting(featureModel.option), ecModel ); var brushType = (coordInfoList.xAxisHas && !coordInfoList.yAxisHas) ? 'lineX' : (!coordInfoList.xAxisHas && coordInfoList.yAxisHas) ? 'lineY' : 'rect'; view._brushController .setPanels(brushHelper.makePanelOpts(coordInfoList)) .enableBrush( zoomActive ? { brushType: brushType, brushStyle: { // FIXME user customized? lineWidth: 0, // stroke: '#333', fill: 'rgba(0,0,0,0.2)' } } : false ); } __webpack_require__(316).register('dataZoom', DataZoom); // Create special dataZoom option for select __webpack_require__(1).registerPreprocessor(function (option) { if (!option) { return; } var dataZoomOpts = option.dataZoom || (option.dataZoom = []); if (!zrUtil.isArray(dataZoomOpts)) { option.dataZoom = dataZoomOpts = [dataZoomOpts]; } var toolboxOpt = option.toolbox; if (toolboxOpt) { // Assume there is only one toolbox if (zrUtil.isArray(toolboxOpt)) { toolboxOpt = toolboxOpt[0]; } if (toolboxOpt && toolboxOpt.feature) { var dataZoomOpt = toolboxOpt.feature.dataZoom; addForAxis('xAxis', dataZoomOpt); addForAxis('yAxis', dataZoomOpt); } } function addForAxis(axisName, dataZoomOpt) { if (!dataZoomOpt) { return; } // Try not to modify model, because it is not merged yet. var axisIndicesName = axisName + 'Index'; var givenAxisIndices = dataZoomOpt[axisIndicesName]; if (givenAxisIndices != null && givenAxisIndices != 'all' && !zrUtil.isArray(givenAxisIndices) ) { givenAxisIndices = (givenAxisIndices === false || givenAxisIndices === 'none') ? [] : [givenAxisIndices]; } forEachComponent(axisName, function (axisOpt, axisIndex) { if (givenAxisIndices != null && givenAxisIndices != 'all' && zrUtil.indexOf(givenAxisIndices, axisIndex) === -1 ) { return; } var newOpt = { type: 'select', $fromToolbox: true, // Id for merge mapping. id: DATA_ZOOM_ID_BASE + axisName + axisIndex }; // FIXME // Only support one axis now. newOpt[axisIndicesName] = axisIndex; dataZoomOpts.push(newOpt); }); } function forEachComponent(mainType, cb) { var opts = option[mainType]; if (!zrUtil.isArray(opts)) { opts = opts ? [opts] : []; } each(opts, cb); } }); module.exports = DataZoom; /***/ }, /* 376 */ /***/ function(module, exports, __webpack_require__) { /** * @file History manager. */ var zrUtil = __webpack_require__(4); var each = zrUtil.each; var ATTR = '\0_ec_hist_store'; var history = { /** * @public * @param {module:echarts/model/Global} ecModel * @param {Object} newSnapshot {dataZoomId, batch: [payloadInfo, ...]} */ push: function (ecModel, newSnapshot) { var store = giveStore(ecModel); // If previous dataZoom can not be found, // complete an range with current range. each(newSnapshot, function (batchItem, dataZoomId) { var i = store.length - 1; for (; i >= 0; i--) { var snapshot = store[i]; if (snapshot[dataZoomId]) { break; } } if (i < 0) { // No origin range set, create one by current range. var dataZoomModel = ecModel.queryComponents( {mainType: 'dataZoom', subType: 'select', id: dataZoomId} )[0]; if (dataZoomModel) { var percentRange = dataZoomModel.getPercentRange(); store[0][dataZoomId] = { dataZoomId: dataZoomId, start: percentRange[0], end: percentRange[1] }; } } }); store.push(newSnapshot); }, /** * @public * @param {module:echarts/model/Global} ecModel * @return {Object} snapshot */ pop: function (ecModel) { var store = giveStore(ecModel); var head = store[store.length - 1]; store.length > 1 && store.pop(); // Find top for all dataZoom. var snapshot = {}; each(head, function (batchItem, dataZoomId) { for (var i = store.length - 1; i >= 0; i--) { var batchItem = store[i][dataZoomId]; if (batchItem) { snapshot[dataZoomId] = batchItem; break; } } }); return snapshot; }, /** * @public */ clear: function (ecModel) { ecModel[ATTR] = null; }, /** * @public * @param {module:echarts/model/Global} ecModel * @return {number} records. always >= 1. */ count: function (ecModel) { return giveStore(ecModel).length; } }; /** * [{key: dataZoomId, value: {dataZoomId, range}}, ...] * History length of each dataZoom may be different. * this._history[0] is used to store origin range. * @type {Array.} */ function giveStore(ecModel) { var store = ecModel[ATTR]; if (!store) { store = ecModel[ATTR] = [{}]; } return store; } module.exports = history; /***/ }, /* 377 */ /***/ function(module, exports, __webpack_require__) { /** * DataZoom component entry */ __webpack_require__(319); __webpack_require__(320); __webpack_require__(323); __webpack_require__(378); __webpack_require__(379); __webpack_require__(330); __webpack_require__(331); /***/ }, /* 378 */ /***/ function(module, exports, __webpack_require__) { /** * @file Data zoom model */ var DataZoomModel = __webpack_require__(320); module.exports = DataZoomModel.extend({ type: 'dataZoom.select' }); /***/ }, /* 379 */ /***/ function(module, exports, __webpack_require__) { module.exports = __webpack_require__(323).extend({ type: 'dataZoom.select' }); /***/ }, /* 380 */ /***/ function(module, exports, __webpack_require__) { 'use strict'; var history = __webpack_require__(376); function Restore(model) { this.model = model; } Restore.defaultOption = { show: true, 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', title: '还原' }; var proto = Restore.prototype; proto.onclick = function (ecModel, api, type) { history.clear(ecModel); api.dispatchAction({ type: 'restore', from: this.uid }); }; __webpack_require__(316).register('restore', Restore); __webpack_require__(1).registerAction( {type: 'restore', event: 'restore', update: 'prepareAndUpdate'}, function (payload, ecModel) { ecModel.resetOption('recreate'); } ); module.exports = Restore; /***/ }, /* 381 */ /***/ function(module, exports, __webpack_require__) { __webpack_require__(382); __webpack_require__(82).registerPainter('vml', __webpack_require__(384)); /***/ }, /* 382 */ /***/ function(module, exports, __webpack_require__) { // http://www.w3.org/TR/NOTE-VML // TODO Use proxy like svg instead of overwrite brush methods if (!__webpack_require__(2).canvasSupported) { var vec2 = __webpack_require__(10); var BoundingRect = __webpack_require__(9); var CMD = __webpack_require__(49).CMD; var colorTool = __webpack_require__(39); var textContain = __webpack_require__(8); var RectText = __webpack_require__(48); var Displayable = __webpack_require__(46); var ZImage = __webpack_require__(61); var Text = __webpack_require__(63); var Path = __webpack_require__(45); var Gradient = __webpack_require__(79); var vmlCore = __webpack_require__(383); var round = Math.round; var sqrt = Math.sqrt; var abs = Math.abs; var cos = Math.cos; var sin = Math.sin; var mathMax = Math.max; var applyTransform = vec2.applyTransform; var comma = ','; var imageTransformPrefix = 'progid:DXImageTransform.Microsoft'; var Z = 21600; var Z2 = Z / 2; var ZLEVEL_BASE = 100000; var Z_BASE = 1000; var initRootElStyle = function (el) { el.style.cssText = 'position:absolute;left:0;top:0;width:1px;height:1px;'; el.coordsize = Z + ',' + Z; el.coordorigin = '0,0'; }; var encodeHtmlAttribute = function (s) { return String(s).replace(/&/g, '&').replace(/"/g, '"'); }; var rgb2Str = function (r, g, b) { return 'rgb(' + [r, g, b].join(',') + ')'; }; var append = function (parent, child) { if (child && parent && child.parentNode !== parent) { parent.appendChild(child); } }; var remove = function (parent, child) { if (child && parent && child.parentNode === parent) { parent.removeChild(child); } }; var getZIndex = function (zlevel, z, z2) { // z 的取值范围为 [0, 1000] return (parseFloat(zlevel) || 0) * ZLEVEL_BASE + (parseFloat(z) || 0) * Z_BASE + z2; }; var parsePercent = function (value, maxValue) { if (typeof value === 'string') { if (value.lastIndexOf('%') >= 0) { return parseFloat(value) / 100 * maxValue; } return parseFloat(value); } return value; }; /*************************************************** * PATH **************************************************/ var setColorAndOpacity = function (el, color, opacity) { var colorArr = colorTool.parse(color); opacity = +opacity; if (isNaN(opacity)) { opacity = 1; } if (colorArr) { el.color = rgb2Str(colorArr[0], colorArr[1], colorArr[2]); el.opacity = opacity * colorArr[3]; } }; var getColorAndAlpha = function (color) { var colorArr = colorTool.parse(color); return [ rgb2Str(colorArr[0], colorArr[1], colorArr[2]), colorArr[3] ]; }; var updateFillNode = function (el, style, zrEl) { // TODO pattern var fill = style.fill; if (fill != null) { // Modified from excanvas if (fill instanceof Gradient) { var gradientType; var angle = 0; var focus = [0, 0]; // additional offset var shift = 0; // scale factor for offset var expansion = 1; var rect = zrEl.getBoundingRect(); var rectWidth = rect.width; var rectHeight = rect.height; if (fill.type === 'linear') { gradientType = 'gradient'; var transform = zrEl.transform; var p0 = [fill.x * rectWidth, fill.y * rectHeight]; var p1 = [fill.x2 * rectWidth, fill.y2 * rectHeight]; if (transform) { applyTransform(p0, p0, transform); applyTransform(p1, p1, transform); } var dx = p1[0] - p0[0]; var dy = p1[1] - p0[1]; angle = Math.atan2(dx, dy) * 180 / Math.PI; // The angle should be a non-negative number. if (angle < 0) { angle += 360; } // Very small angles produce an unexpected result because they are // converted to a scientific notation string. if (angle < 1e-6) { angle = 0; } } else { gradientType = 'gradientradial'; var p0 = [fill.x * rectWidth, fill.y * rectHeight]; var transform = zrEl.transform; var scale = zrEl.scale; var width = rectWidth; var height = rectHeight; focus = [ // Percent in bounding rect (p0[0] - rect.x) / width, (p0[1] - rect.y) / height ]; if (transform) { applyTransform(p0, p0, transform); } width /= scale[0] * Z; height /= scale[1] * Z; var dimension = mathMax(width, height); shift = 2 * 0 / dimension; expansion = 2 * fill.r / dimension - shift; } // We need to sort the color stops in ascending order by offset, // otherwise IE won't interpret it correctly. var stops = fill.colorStops.slice(); stops.sort(function(cs1, cs2) { return cs1.offset - cs2.offset; }); var length = stops.length; // Color and alpha list of first and last stop var colorAndAlphaList = []; var colors = []; for (var i = 0; i < length; i++) { var stop = stops[i]; var colorAndAlpha = getColorAndAlpha(stop.color); colors.push(stop.offset * expansion + shift + ' ' + colorAndAlpha[0]); if (i === 0 || i === length - 1) { colorAndAlphaList.push(colorAndAlpha); } } if (length >= 2) { var color1 = colorAndAlphaList[0][0]; var color2 = colorAndAlphaList[1][0]; var opacity1 = colorAndAlphaList[0][1] * style.opacity; var opacity2 = colorAndAlphaList[1][1] * style.opacity; el.type = gradientType; el.method = 'none'; el.focus = '100%'; el.angle = angle; el.color = color1; el.color2 = color2; el.colors = colors.join(','); // When colors attribute is used, the meanings of opacity and o:opacity2 // are reversed. el.opacity = opacity2; // FIXME g_o_:opacity ? el.opacity2 = opacity1; } if (gradientType === 'radial') { el.focusposition = focus.join(','); } } else { // FIXME Change from Gradient fill to color fill setColorAndOpacity(el, fill, style.opacity); } } }; var updateStrokeNode = function (el, style) { // if (style.lineJoin != null) { // el.joinstyle = style.lineJoin; // } // if (style.miterLimit != null) { // el.miterlimit = style.miterLimit * Z; // } // if (style.lineCap != null) { // el.endcap = style.lineCap; // } if (style.lineDash != null) { el.dashstyle = style.lineDash.join(' '); } if (style.stroke != null && !(style.stroke instanceof Gradient)) { setColorAndOpacity(el, style.stroke, style.opacity); } }; var updateFillAndStroke = function (vmlEl, type, style, zrEl) { var isFill = type == 'fill'; var el = vmlEl.getElementsByTagName(type)[0]; // Stroke must have lineWidth if (style[type] != null && style[type] !== 'none' && (isFill || (!isFill && style.lineWidth))) { vmlEl[isFill ? 'filled' : 'stroked'] = 'true'; // FIXME Remove before updating, or set `colors` will throw error if (style[type] instanceof Gradient) { remove(vmlEl, el); } if (!el) { el = vmlCore.createNode(type); } isFill ? updateFillNode(el, style, zrEl) : updateStrokeNode(el, style); append(vmlEl, el); } else { vmlEl[isFill ? 'filled' : 'stroked'] = 'false'; remove(vmlEl, el); } }; var points = [[], [], []]; var pathDataToString = function (data, m) { var M = CMD.M; var C = CMD.C; var L = CMD.L; var A = CMD.A; var Q = CMD.Q; var str = []; var nPoint; var cmdStr; var cmd; var i; var xi; var yi; for (i = 0; i < data.length;) { cmd = data[i++]; cmdStr = ''; nPoint = 0; switch (cmd) { case M: cmdStr = ' m '; nPoint = 1; xi = data[i++]; yi = data[i++]; points[0][0] = xi; points[0][1] = yi; break; case L: cmdStr = ' l '; nPoint = 1; xi = data[i++]; yi = data[i++]; points[0][0] = xi; points[0][1] = yi; break; case Q: case C: cmdStr = ' c '; nPoint = 3; var x1 = data[i++]; var y1 = data[i++]; var x2 = data[i++]; var y2 = data[i++]; var x3; var y3; if (cmd === Q) { // Convert quadratic to cubic using degree elevation x3 = x2; y3 = y2; x2 = (x2 + 2 * x1) / 3; y2 = (y2 + 2 * y1) / 3; x1 = (xi + 2 * x1) / 3; y1 = (yi + 2 * y1) / 3; } else { x3 = data[i++]; y3 = data[i++]; } points[0][0] = x1; points[0][1] = y1; points[1][0] = x2; points[1][1] = y2; points[2][0] = x3; points[2][1] = y3; xi = x3; yi = y3; break; case A: var x = 0; var y = 0; var sx = 1; var sy = 1; var angle = 0; if (m) { // Extract SRT from matrix x = m[4]; y = m[5]; sx = sqrt(m[0] * m[0] + m[1] * m[1]); sy = sqrt(m[2] * m[2] + m[3] * m[3]); angle = Math.atan2(-m[1] / sy, m[0] / sx); } var cx = data[i++]; var cy = data[i++]; var rx = data[i++]; var ry = data[i++]; var startAngle = data[i++] + angle; var endAngle = data[i++] + startAngle + angle; // FIXME // var psi = data[i++]; i++; var clockwise = data[i++]; var x0 = cx + cos(startAngle) * rx; var y0 = cy + sin(startAngle) * ry; var x1 = cx + cos(endAngle) * rx; var y1 = cy + sin(endAngle) * ry; var type = clockwise ? ' wa ' : ' at '; if (Math.abs(x0 - x1) < 1e-10) { // IE won't render arches drawn counter clockwise if x0 == x1. if (Math.abs(endAngle - startAngle) > 1e-2) { // Offset x0 by 1/80 of a pixel. Use something // that can be represented in binary if (clockwise) { x0 += 270 / Z; } } else { // Avoid case draw full circle if (Math.abs(y0 - cy) < 1e-10) { if ((clockwise && x0 < cx) || (!clockwise && x0 > cx)) { y1 -= 270 / Z; } else { y1 += 270 / Z; } } else if ((clockwise && y0 < cy) || (!clockwise && y0 > cy)) { x1 += 270 / Z; } else { x1 -= 270 / Z; } } } str.push( type, round(((cx - rx) * sx + x) * Z - Z2), comma, round(((cy - ry) * sy + y) * Z - Z2), comma, round(((cx + rx) * sx + x) * Z - Z2), comma, round(((cy + ry) * sy + y) * Z - Z2), comma, round((x0 * sx + x) * Z - Z2), comma, round((y0 * sy + y) * Z - Z2), comma, round((x1 * sx + x) * Z - Z2), comma, round((y1 * sy + y) * Z - Z2) ); xi = x1; yi = y1; break; case CMD.R: var p0 = points[0]; var p1 = points[1]; // x0, y0 p0[0] = data[i++]; p0[1] = data[i++]; // x1, y1 p1[0] = p0[0] + data[i++]; p1[1] = p0[1] + data[i++]; if (m) { applyTransform(p0, p0, m); applyTransform(p1, p1, m); } p0[0] = round(p0[0] * Z - Z2); p1[0] = round(p1[0] * Z - Z2); p0[1] = round(p0[1] * Z - Z2); p1[1] = round(p1[1] * Z - Z2); str.push( // x0, y0 ' m ', p0[0], comma, p0[1], // x1, y0 ' l ', p1[0], comma, p0[1], // x1, y1 ' l ', p1[0], comma, p1[1], // x0, y1 ' l ', p0[0], comma, p1[1] ); break; case CMD.Z: // FIXME Update xi, yi str.push(' x '); } if (nPoint > 0) { str.push(cmdStr); for (var k = 0; k < nPoint; k++) { var p = points[k]; m && applyTransform(p, p, m); // 不 round 会非常慢 str.push( round(p[0] * Z - Z2), comma, round(p[1] * Z - Z2), k < nPoint - 1 ? comma : '' ); } } } return str.join(''); }; // Rewrite the original path method Path.prototype.brushVML = function (vmlRoot) { var style = this.style; var vmlEl = this._vmlEl; if (!vmlEl) { vmlEl = vmlCore.createNode('shape'); initRootElStyle(vmlEl); this._vmlEl = vmlEl; } updateFillAndStroke(vmlEl, 'fill', style, this); updateFillAndStroke(vmlEl, 'stroke', style, this); var m = this.transform; var needTransform = m != null; var strokeEl = vmlEl.getElementsByTagName('stroke')[0]; if (strokeEl) { var lineWidth = style.lineWidth; // Get the line scale. // Determinant of this.m_ means how much the area is enlarged by the // transformation. So its square root can be used as a scale factor // for width. if (needTransform && !style.strokeNoScale) { var det = m[0] * m[3] - m[1] * m[2]; lineWidth *= sqrt(abs(det)); } strokeEl.weight = lineWidth + 'px'; } var path = this.path; if (this.__dirtyPath) { path.beginPath(); this.buildPath(path, this.shape); path.toStatic(); this.__dirtyPath = false; } vmlEl.path = pathDataToString(path.data, this.transform); vmlEl.style.zIndex = getZIndex(this.zlevel, this.z, this.z2); // Append to root append(vmlRoot, vmlEl); // Text if (style.text != null) { this.drawRectText(vmlRoot, this.getBoundingRect()); } else { this.removeRectText(vmlRoot); } }; Path.prototype.onRemove = function (vmlRoot) { remove(vmlRoot, this._vmlEl); this.removeRectText(vmlRoot); }; Path.prototype.onAdd = function (vmlRoot) { append(vmlRoot, this._vmlEl); this.appendRectText(vmlRoot); }; /*************************************************** * IMAGE **************************************************/ var isImage = function (img) { // FIXME img instanceof Image 如果 img 是一个字符串的时候,IE8 下会报错 return (typeof img === 'object') && img.tagName && img.tagName.toUpperCase() === 'IMG'; // return img instanceof Image; }; // Rewrite the original path method ZImage.prototype.brushVML = function (vmlRoot) { var style = this.style; var image = style.image; // Image original width, height var ow; var oh; if (isImage(image)) { var src = image.src; if (src === this._imageSrc) { ow = this._imageWidth; oh = this._imageHeight; } else { var imageRuntimeStyle = image.runtimeStyle; var oldRuntimeWidth = imageRuntimeStyle.width; var oldRuntimeHeight = imageRuntimeStyle.height; imageRuntimeStyle.width = 'auto'; imageRuntimeStyle.height = 'auto'; // get the original size ow = image.width; oh = image.height; // and remove overides imageRuntimeStyle.width = oldRuntimeWidth; imageRuntimeStyle.height = oldRuntimeHeight; // Caching image original width, height and src this._imageSrc = src; this._imageWidth = ow; this._imageHeight = oh; } image = src; } else { if (image === this._imageSrc) { ow = this._imageWidth; oh = this._imageHeight; } } if (!image) { return; } var x = style.x || 0; var y = style.y || 0; var dw = style.width; var dh = style.height; var sw = style.sWidth; var sh = style.sHeight; var sx = style.sx || 0; var sy = style.sy || 0; var hasCrop = sw && sh; var vmlEl = this._vmlEl; if (!vmlEl) { // FIXME 使用 group 在 left, top 都不是 0 的时候就无法显示了。 // vmlEl = vmlCore.createNode('group'); vmlEl = vmlCore.doc.createElement('div'); initRootElStyle(vmlEl); this._vmlEl = vmlEl; } var vmlElStyle = vmlEl.style; var hasRotation = false; var m; var scaleX = 1; var scaleY = 1; if (this.transform) { m = this.transform; scaleX = sqrt(m[0] * m[0] + m[1] * m[1]); scaleY = sqrt(m[2] * m[2] + m[3] * m[3]); hasRotation = m[1] || m[2]; } if (hasRotation) { // If filters are necessary (rotation exists), create them // filters are bog-slow, so only create them if abbsolutely necessary // The following check doesn't account for skews (which don't exist // in the canvas spec (yet) anyway. // From excanvas var p0 = [x, y]; var p1 = [x + dw, y]; var p2 = [x, y + dh]; var p3 = [x + dw, y + dh]; applyTransform(p0, p0, m); applyTransform(p1, p1, m); applyTransform(p2, p2, m); applyTransform(p3, p3, m); var maxX = mathMax(p0[0], p1[0], p2[0], p3[0]); var maxY = mathMax(p0[1], p1[1], p2[1], p3[1]); var transformFilter = []; transformFilter.push('M11=', m[0] / scaleX, comma, 'M12=', m[2] / scaleY, comma, 'M21=', m[1] / scaleX, comma, 'M22=', m[3] / scaleY, comma, 'Dx=', round(x * scaleX + m[4]), comma, 'Dy=', round(y * scaleY + m[5])); vmlElStyle.padding = '0 ' + round(maxX) + 'px ' + round(maxY) + 'px 0'; // FIXME DXImageTransform 在 IE11 的兼容模式下不起作用 vmlElStyle.filter = imageTransformPrefix + '.Matrix(' + transformFilter.join('') + ', SizingMethod=clip)'; } else { if (m) { x = x * scaleX + m[4]; y = y * scaleY + m[5]; } vmlElStyle.filter = ''; vmlElStyle.left = round(x) + 'px'; vmlElStyle.top = round(y) + 'px'; } var imageEl = this._imageEl; var cropEl = this._cropEl; if (!imageEl) { imageEl = vmlCore.doc.createElement('div'); this._imageEl = imageEl; } var imageELStyle = imageEl.style; if (hasCrop) { // Needs know image original width and height if (! (ow && oh)) { var tmpImage = new Image(); var self = this; tmpImage.onload = function () { tmpImage.onload = null; ow = tmpImage.width; oh = tmpImage.height; // Adjust image width and height to fit the ratio destinationSize / sourceSize imageELStyle.width = round(scaleX * ow * dw / sw) + 'px'; imageELStyle.height = round(scaleY * oh * dh / sh) + 'px'; // Caching image original width, height and src self._imageWidth = ow; self._imageHeight = oh; self._imageSrc = image; }; tmpImage.src = image; } else { imageELStyle.width = round(scaleX * ow * dw / sw) + 'px'; imageELStyle.height = round(scaleY * oh * dh / sh) + 'px'; } if (! cropEl) { cropEl = vmlCore.doc.createElement('div'); cropEl.style.overflow = 'hidden'; this._cropEl = cropEl; } var cropElStyle = cropEl.style; cropElStyle.width = round((dw + sx * dw / sw) * scaleX); cropElStyle.height = round((dh + sy * dh / sh) * scaleY); cropElStyle.filter = imageTransformPrefix + '.Matrix(Dx=' + (-sx * dw / sw * scaleX) + ',Dy=' + (-sy * dh / sh * scaleY) + ')'; if (! cropEl.parentNode) { vmlEl.appendChild(cropEl); } if (imageEl.parentNode != cropEl) { cropEl.appendChild(imageEl); } } else { imageELStyle.width = round(scaleX * dw) + 'px'; imageELStyle.height = round(scaleY * dh) + 'px'; vmlEl.appendChild(imageEl); if (cropEl && cropEl.parentNode) { vmlEl.removeChild(cropEl); this._cropEl = null; } } var filterStr = ''; var alpha = style.opacity; if (alpha < 1) { filterStr += '.Alpha(opacity=' + round(alpha * 100) + ') '; } filterStr += imageTransformPrefix + '.AlphaImageLoader(src=' + image + ', SizingMethod=scale)'; imageELStyle.filter = filterStr; vmlEl.style.zIndex = getZIndex(this.zlevel, this.z, this.z2); // Append to root append(vmlRoot, vmlEl); // Text if (style.text != null) { this.drawRectText(vmlRoot, this.getBoundingRect()); } }; ZImage.prototype.onRemove = function (vmlRoot) { remove(vmlRoot, this._vmlEl); this._vmlEl = null; this._cropEl = null; this._imageEl = null; this.removeRectText(vmlRoot); }; ZImage.prototype.onAdd = function (vmlRoot) { append(vmlRoot, this._vmlEl); this.appendRectText(vmlRoot); }; /*************************************************** * TEXT **************************************************/ var DEFAULT_STYLE_NORMAL = 'normal'; var fontStyleCache = {}; var fontStyleCacheCount = 0; var MAX_FONT_CACHE_SIZE = 100; var fontEl = document.createElement('div'); var getFontStyle = function (fontString) { var fontStyle = fontStyleCache[fontString]; if (!fontStyle) { // Clear cache if (fontStyleCacheCount > MAX_FONT_CACHE_SIZE) { fontStyleCacheCount = 0; fontStyleCache = {}; } var style = fontEl.style; var fontFamily; try { style.font = fontString; fontFamily = style.fontFamily.split(',')[0]; } catch (e) { } fontStyle = { style: style.fontStyle || DEFAULT_STYLE_NORMAL, variant: style.fontVariant || DEFAULT_STYLE_NORMAL, weight: style.fontWeight || DEFAULT_STYLE_NORMAL, size: parseFloat(style.fontSize || 12) | 0, family: fontFamily || 'Microsoft YaHei' }; fontStyleCache[fontString] = fontStyle; fontStyleCacheCount++; } return fontStyle; }; var textMeasureEl; // Overwrite measure text method textContain.measureText = function (text, textFont) { var doc = vmlCore.doc; if (!textMeasureEl) { textMeasureEl = doc.createElement('div'); textMeasureEl.style.cssText = 'position:absolute;top:-20000px;left:0;' + 'padding:0;margin:0;border:none;white-space:pre;'; vmlCore.doc.body.appendChild(textMeasureEl); } try { textMeasureEl.style.font = textFont; } catch (ex) { // Ignore failures to set to invalid font. } textMeasureEl.innerHTML = ''; // Don't use innerHTML or innerText because they allow markup/whitespace. textMeasureEl.appendChild(doc.createTextNode(text)); return { width: textMeasureEl.offsetWidth }; }; var tmpRect = new BoundingRect(); var drawRectText = function (vmlRoot, rect, textRect, fromTextEl) { var style = this.style; var text = style.text; // Convert to string text != null && (text += ''); if (!text) { return; } var x; var y; var align = style.textAlign; var fontStyle = getFontStyle(style.textFont); // FIXME encodeHtmlAttribute ? var font = fontStyle.style + ' ' + fontStyle.variant + ' ' + fontStyle.weight + ' ' + fontStyle.size + 'px "' + fontStyle.family + '"'; var baseline = style.textBaseline; var verticalAlign = style.textVerticalAlign; textRect = textRect || textContain.getBoundingRect(text, font, align, baseline); // Transform rect to view space var m = this.transform; // Ignore transform for text in other element if (m && !fromTextEl) { tmpRect.copy(rect); tmpRect.applyTransform(m); rect = tmpRect; } if (!fromTextEl) { var textPosition = style.textPosition; var distance = style.textDistance; // Text position represented by coord if (textPosition instanceof Array) { x = rect.x + parsePercent(textPosition[0], rect.width); y = rect.y + parsePercent(textPosition[1], rect.height); align = align || 'left'; baseline = baseline || 'top'; } else { var res = textContain.adjustTextPositionOnRect( textPosition, rect, textRect, distance ); x = res.x; y = res.y; // Default align and baseline when has textPosition align = align || res.textAlign; baseline = baseline || res.textBaseline; } } else { x = rect.x; y = rect.y; } if (verticalAlign) { switch (verticalAlign) { case 'middle': y -= textRect.height / 2; break; case 'bottom': y -= textRect.height; break; // 'top' } // Ignore baseline baseline = 'top'; } var fontSize = fontStyle.size; // 1.75 is an arbitrary number, as there is no info about the text baseline switch (baseline) { case 'hanging': case 'top': y += fontSize / 1.75; break; case 'middle': break; default: // case null: // case 'alphabetic': // case 'ideographic': // case 'bottom': y -= fontSize / 2.25; break; } switch (align) { case 'left': break; case 'center': x -= textRect.width / 2; break; case 'right': x -= textRect.width; break; // case 'end': // align = elementStyle.direction == 'ltr' ? 'right' : 'left'; // break; // case 'start': // align = elementStyle.direction == 'rtl' ? 'right' : 'left'; // break; // default: // align = 'left'; } var createNode = vmlCore.createNode; var textVmlEl = this._textVmlEl; var pathEl; var textPathEl; var skewEl; if (!textVmlEl) { textVmlEl = createNode('line'); pathEl = createNode('path'); textPathEl = createNode('textpath'); skewEl = createNode('skew'); // FIXME Why here is not cammel case // Align 'center' seems wrong textPathEl.style['v-text-align'] = 'left'; initRootElStyle(textVmlEl); pathEl.textpathok = true; textPathEl.on = true; textVmlEl.from = '0 0'; textVmlEl.to = '1000 0.05'; append(textVmlEl, skewEl); append(textVmlEl, pathEl); append(textVmlEl, textPathEl); this._textVmlEl = textVmlEl; } else { // 这里是在前面 appendChild 保证顺序的前提下 skewEl = textVmlEl.firstChild; pathEl = skewEl.nextSibling; textPathEl = pathEl.nextSibling; } var coords = [x, y]; var textVmlElStyle = textVmlEl.style; // Ignore transform for text in other element if (m && fromTextEl) { applyTransform(coords, coords, m); skewEl.on = true; skewEl.matrix = m[0].toFixed(3) + comma + m[2].toFixed(3) + comma + m[1].toFixed(3) + comma + m[3].toFixed(3) + ',0,0'; // Text position skewEl.offset = (round(coords[0]) || 0) + ',' + (round(coords[1]) || 0); // Left top point as origin skewEl.origin = '0 0'; textVmlElStyle.left = '0px'; textVmlElStyle.top = '0px'; } else { skewEl.on = false; textVmlElStyle.left = round(x) + 'px'; textVmlElStyle.top = round(y) + 'px'; } textPathEl.string = encodeHtmlAttribute(text); // TODO try { textPathEl.style.font = font; } // Error font format catch (e) {} updateFillAndStroke(textVmlEl, 'fill', { fill: fromTextEl ? style.fill : style.textFill, opacity: style.opacity }, this); updateFillAndStroke(textVmlEl, 'stroke', { stroke: fromTextEl ? style.stroke : style.textStroke, opacity: style.opacity, lineDash: style.lineDash }, this); textVmlEl.style.zIndex = getZIndex(this.zlevel, this.z, this.z2); // Attached to root append(vmlRoot, textVmlEl); }; var removeRectText = function (vmlRoot) { remove(vmlRoot, this._textVmlEl); this._textVmlEl = null; }; var appendRectText = function (vmlRoot) { append(vmlRoot, this._textVmlEl); }; var list = [RectText, Displayable, ZImage, Path, Text]; // In case Displayable has been mixed in RectText for (var i = 0; i < list.length; i++) { var proto = list[i].prototype; proto.drawRectText = drawRectText; proto.removeRectText = removeRectText; proto.appendRectText = appendRectText; } Text.prototype.brushVML = function (vmlRoot) { var style = this.style; if (style.text != null) { this.drawRectText(vmlRoot, { x: style.x || 0, y: style.y || 0, width: 0, height: 0 }, this.getBoundingRect(), true); } else { this.removeRectText(vmlRoot); } }; Text.prototype.onRemove = function (vmlRoot) { this.removeRectText(vmlRoot); }; Text.prototype.onAdd = function (vmlRoot) { this.appendRectText(vmlRoot); }; } /***/ }, /* 383 */ /***/ function(module, exports, __webpack_require__) { if (!__webpack_require__(2).canvasSupported) { var urn = 'urn:schemas-microsoft-com:vml'; var createNode; var win = window; var doc = win.document; var vmlInited = false; try { !doc.namespaces.zrvml && doc.namespaces.add('zrvml', urn); createNode = function (tagName) { return doc.createElement(''); }; } catch (e) { createNode = function (tagName) { return doc.createElement('<' + tagName + ' xmlns="' + urn + '" class="zrvml">'); }; } // From raphael var initVML = function () { if (vmlInited) { return; } vmlInited = true; var styleSheets = doc.styleSheets; if (styleSheets.length < 31) { doc.createStyleSheet().addRule('.zrvml', 'behavior:url(#default#VML)'); } else { // http://msdn.microsoft.com/en-us/library/ms531194%28VS.85%29.aspx styleSheets[0].addRule('.zrvml', 'behavior:url(#default#VML)'); } }; // Not useing return to avoid error when converting to CommonJS module module.exports = { doc: doc, initVML: initVML, createNode: createNode }; } /***/ }, /* 384 */ /***/ function(module, exports, __webpack_require__) { /** * VML Painter. * * @module zrender/vml/Painter */ var zrLog = __webpack_require__(40); var vmlCore = __webpack_require__(383); function parseInt10(val) { return parseInt(val, 10); } /** * @alias module:zrender/vml/Painter */ function VMLPainter(root, storage) { vmlCore.initVML(); this.root = root; this.storage = storage; var vmlViewport = document.createElement('div'); var vmlRoot = document.createElement('div'); vmlViewport.style.cssText = 'display:inline-block;overflow:hidden;position:relative;width:300px;height:150px;'; vmlRoot.style.cssText = 'position:absolute;left:0;top:0;'; root.appendChild(vmlViewport); this._vmlRoot = vmlRoot; this._vmlViewport = vmlViewport; this.resize(); // Modify storage var oldDelFromMap = storage.delFromMap; var oldAddToMap = storage.addToMap; storage.delFromMap = function (elId) { var el = storage.get(elId); oldDelFromMap.call(storage, elId); if (el) { el.onRemove && el.onRemove(vmlRoot); } }; storage.addToMap = function (el) { // Displayable already has a vml node el.onAdd && el.onAdd(vmlRoot); oldAddToMap.call(storage, el); }; this._firstPaint = true; } VMLPainter.prototype = { constructor: VMLPainter, /** * @return {HTMLDivElement} */ getViewportRoot: function () { return this._vmlViewport; }, /** * 刷新 */ refresh: function () { var list = this.storage.getDisplayList(true, true); this._paintList(list); }, _paintList: function (list) { var vmlRoot = this._vmlRoot; for (var i = 0; i < list.length; i++) { var el = list[i]; if (el.invisible || el.ignore) { if (!el.__alreadyNotVisible) { el.onRemove(vmlRoot); } // Set as already invisible el.__alreadyNotVisible = true; } else { if (el.__alreadyNotVisible) { el.onAdd(vmlRoot); } el.__alreadyNotVisible = false; if (el.__dirty) { el.beforeBrush && el.beforeBrush(); (el.brushVML || el.brush).call(el, vmlRoot); el.afterBrush && el.afterBrush(); } } el.__dirty = false; } if (this._firstPaint) { // Detached from document at first time // to avoid page refreshing too many times // FIXME 如果每次都先 removeChild 可能会导致一些填充和描边的效果改变 this._vmlViewport.appendChild(vmlRoot); this._firstPaint = false; } }, resize: function (width, height) { var width = width == null ? this._getWidth() : width; var height = height == null ? this._getHeight() : height; if (this._width != width || this._height != height) { this._width = width; this._height = height; var vmlViewportStyle = this._vmlViewport.style; vmlViewportStyle.width = width + 'px'; vmlViewportStyle.height = height + 'px'; } }, dispose: function () { this.root.innerHTML = ''; this._vmlRoot = this._vmlViewport = this.storage = null; }, getWidth: function () { return this._width; }, getHeight: function () { return this._height; }, clear: function () { if (this._vmlViewport) { this.root.removeChild(this._vmlViewport); } }, _getWidth: function () { var root = this.root; var stl = root.currentStyle; return ((root.clientWidth || parseInt10(stl.width)) - parseInt10(stl.paddingLeft) - parseInt10(stl.paddingRight)) | 0; }, _getHeight: function () { var root = this.root; var stl = root.currentStyle; return ((root.clientHeight || parseInt10(stl.height)) - parseInt10(stl.paddingTop) - parseInt10(stl.paddingBottom)) | 0; } }; // Not supported methods function createMethodNotSupport(method) { return function () { zrLog('In IE8.0 VML mode painter not support method "' + method + '"'); }; } var notSupportedMethods = [ 'getLayer', 'insertLayer', 'eachLayer', 'eachBuildinLayer', 'eachOtherLayer', 'getLayers', 'modLayer', 'delLayer', 'clearLayer', 'toDataURL', 'pathToImage' ]; for (var i = 0; i < notSupportedMethods.length; i++) { var name = notSupportedMethods[i]; VMLPainter.prototype[name] = createMethodNotSupport(name); } module.exports = VMLPainter; /***/ } /******/ ]) }); ;