echarts 4.5.0 → 4.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (154) hide show
  1. package/dist/echarts-en.common.js +1790 -774
  2. package/dist/echarts-en.common.min.js +1 -1
  3. package/dist/echarts-en.js +2029 -849
  4. package/dist/echarts-en.js.map +1 -1
  5. package/dist/echarts-en.min.js +1 -1
  6. package/dist/echarts-en.simple.js +1676 -691
  7. package/dist/echarts-en.simple.min.js +1 -1
  8. package/dist/echarts.common.js +1790 -774
  9. package/dist/echarts.common.min.js +1 -1
  10. package/dist/echarts.js +2029 -849
  11. package/dist/echarts.js.map +1 -1
  12. package/dist/echarts.min.js +1 -1
  13. package/dist/echarts.simple.js +1676 -691
  14. package/dist/echarts.simple.min.js +1 -1
  15. package/lib/chart/bar/BarView.js +11 -1
  16. package/lib/chart/bar/BaseBarSeries.js +3 -1
  17. package/lib/chart/effectScatter/EffectScatterSeries.js +3 -1
  18. package/lib/chart/funnel/FunnelSeries.js +15 -5
  19. package/lib/chart/gauge/GaugeSeries.js +0 -2
  20. package/lib/chart/graph/GraphSeries.js +9 -4
  21. package/lib/chart/graph/GraphView.js +28 -8
  22. package/lib/chart/heatmap/HeatmapView.js +4 -4
  23. package/lib/chart/helper/createListFromArray.js +14 -8
  24. package/lib/chart/helper/whiskerBoxCommon.js +22 -16
  25. package/lib/chart/line/LineSeries.js +3 -1
  26. package/lib/chart/line/LineView.js +8 -2
  27. package/lib/chart/map/MapSeries.js +8 -1
  28. package/lib/chart/pie/PieSeries.js +27 -6
  29. package/lib/chart/pie/PieView.js +1 -1
  30. package/lib/chart/pie/labelLayout.js +102 -19
  31. package/lib/chart/pie/pieLayout.js +19 -7
  32. package/lib/chart/radar/RadarSeries.js +3 -3
  33. package/lib/chart/sankey/SankeyView.js +28 -9
  34. package/lib/chart/scatter/ScatterSeries.js +3 -1
  35. package/lib/chart/themeRiver/ThemeRiverSeries.js +3 -3
  36. package/lib/chart/tree/TreeSeries.js +15 -1
  37. package/lib/component/axis/AngleAxisView.js +64 -7
  38. package/lib/component/axis/AxisBuilder.js +63 -24
  39. package/lib/component/axis/CartesianAxisView.js +55 -11
  40. package/lib/component/axis/RadiusAxisView.js +36 -4
  41. package/lib/component/dataZoom/SliderZoomView.js +4 -10
  42. package/lib/component/helper/BrushController.js +33 -43
  43. package/lib/component/legend/LegendModel.js +3 -3
  44. package/lib/component/legend/LegendView.js +17 -13
  45. package/lib/component/toolbox/ToolboxView.js +5 -1
  46. package/lib/component/toolbox/feature/MagicType.js +19 -14
  47. package/lib/coord/Axis.js +30 -2
  48. package/lib/coord/axisDefault.js +21 -2
  49. package/lib/data/DataDimensionInfo.js +157 -0
  50. package/lib/data/List.js +25 -19
  51. package/lib/data/Tree.js +2 -1
  52. package/lib/data/helper/completeDimensions.js +43 -32
  53. package/lib/data/helper/createDimensions.js +2 -0
  54. package/lib/data/helper/sourceHelper.js +214 -114
  55. package/lib/echarts.js +2 -2
  56. package/lib/layout/barGrid.js +2 -3
  57. package/lib/model/Series.js +3 -3
  58. package/lib/model/referHelper.js +40 -12
  59. package/lib/scale/Interval.js +87 -2
  60. package/lib/scale/Log.js +9 -2
  61. package/lib/scale/helper.js +1 -43
  62. package/lib/theme/dark.js +3 -0
  63. package/lib/util/graphic.js +1 -2
  64. package/lib/visual/LegendVisualProvider.js +75 -0
  65. package/lib/visual/dataColor.js +2 -12
  66. package/lib/visual/seriesColor.js +15 -7
  67. package/map/json/province/tianjin.json +1 -1
  68. package/package.json +3 -2
  69. package/src/chart/bar/BarView.js +12 -2
  70. package/src/chart/bar/BaseBarSeries.js +1 -1
  71. package/src/chart/effectScatter/EffectScatterSeries.js +1 -1
  72. package/src/chart/funnel/FunnelSeries.js +11 -4
  73. package/src/chart/gauge/GaugeSeries.js +0 -1
  74. package/src/chart/graph/GraphSeries.js +8 -3
  75. package/src/chart/graph/GraphView.js +26 -8
  76. package/src/chart/heatmap/HeatmapView.js +4 -4
  77. package/src/chart/helper/createListFromArray.js +13 -8
  78. package/src/chart/helper/whiskerBoxCommon.js +21 -16
  79. package/src/chart/line/LineSeries.js +1 -1
  80. package/src/chart/line/LineView.js +6 -1
  81. package/src/chart/map/MapSeries.js +5 -1
  82. package/src/chart/pie/PieSeries.js +26 -5
  83. package/src/chart/pie/PieView.js +1 -1
  84. package/src/chart/pie/labelLayout.js +114 -22
  85. package/src/chart/pie/pieLayout.js +20 -7
  86. package/src/chart/radar/RadarSeries.js +5 -3
  87. package/src/chart/sankey/SankeyView.js +26 -9
  88. package/src/chart/scatter/ScatterSeries.js +1 -1
  89. package/src/chart/themeRiver/ThemeRiverSeries.js +4 -3
  90. package/src/chart/tree/TreeSeries.js +12 -1
  91. package/src/component/axis/AngleAxisView.js +75 -7
  92. package/src/component/axis/AxisBuilder.js +78 -33
  93. package/src/component/axis/CartesianAxisView.js +58 -11
  94. package/src/component/axis/RadiusAxisView.js +37 -4
  95. package/src/component/dataZoom/SliderZoomView.js +4 -9
  96. package/src/component/helper/BrushController.js +40 -47
  97. package/src/component/legend/LegendModel.js +3 -3
  98. package/src/component/legend/LegendView.js +18 -12
  99. package/src/component/toolbox/ToolboxView.js +5 -0
  100. package/src/component/toolbox/feature/MagicType.js +18 -13
  101. package/src/coord/Axis.js +29 -2
  102. package/src/coord/axisDefault.js +25 -1
  103. package/src/data/DataDimensionInfo.js +135 -0
  104. package/src/data/List.js +29 -16
  105. package/src/data/Tree.js +3 -1
  106. package/src/data/helper/completeDimensions.js +49 -30
  107. package/src/data/helper/createDimensions.js +2 -0
  108. package/src/data/helper/sourceHelper.js +216 -124
  109. package/src/echarts.js +2 -2
  110. package/src/layout/barGrid.js +6 -3
  111. package/src/model/Series.js +3 -3
  112. package/src/model/referHelper.js +34 -11
  113. package/src/scale/Interval.js +84 -4
  114. package/src/scale/Log.js +9 -2
  115. package/src/scale/helper.js +1 -39
  116. package/src/theme/dark.js +3 -0
  117. package/src/util/graphic.js +1 -2
  118. package/src/visual/LegendVisualProvider.js +55 -0
  119. package/src/visual/dataColor.js +0 -13
  120. package/src/visual/seriesColor.js +13 -7
  121. package/theme/azul.js +163 -0
  122. package/theme/bee-inspired.js +178 -0
  123. package/theme/blue.js +178 -0
  124. package/theme/caravan.js +178 -0
  125. package/theme/carp.js +163 -0
  126. package/theme/cool.js +180 -0
  127. package/theme/dark-blue.js +168 -0
  128. package/theme/dark-bold.js +168 -0
  129. package/theme/dark-digerati.js +168 -0
  130. package/theme/dark-fresh-cut.js +168 -0
  131. package/theme/dark-mushroom.js +168 -0
  132. package/theme/dark.js +69 -62
  133. package/theme/eduardo.js +178 -0
  134. package/theme/forest.js +163 -0
  135. package/theme/fresh-cut.js +163 -0
  136. package/theme/fruit.js +178 -0
  137. package/theme/gray.js +220 -0
  138. package/theme/green.js +222 -0
  139. package/theme/helianthus.js +263 -0
  140. package/theme/infographic.js +72 -57
  141. package/theme/inspired.js +163 -0
  142. package/theme/jazz.js +163 -0
  143. package/theme/london.js +163 -0
  144. package/theme/macarons.js +80 -57
  145. package/theme/macarons2.js +251 -0
  146. package/theme/mint.js +155 -0
  147. package/theme/red-velvet.js +163 -0
  148. package/theme/red.js +225 -0
  149. package/theme/roma.js +55 -22
  150. package/theme/royal.js +163 -0
  151. package/theme/sakura.js +140 -0
  152. package/theme/shine.js +52 -45
  153. package/theme/tech-blue.js +180 -0
  154. package/theme/vintage.js +37 -23
@@ -208,12 +208,17 @@ function detect(ua) {
208
208
  // default, so we dont check navigator.maxTouchPoints for them here.
209
209
  touchEventsSupported: 'ontouchstart' in window && !browser.ie && !browser.edge,
210
210
  // <http://caniuse.com/#search=pointer%20event>.
211
- pointerEventsSupported: 'onpointerdown' in window
212
- // Firefox supports pointer but not by default, only MS browsers are reliable on pointer
211
+ pointerEventsSupported:
212
+ // (1) Firefox supports pointer but not by default, only MS browsers are reliable on pointer
213
213
  // events currently. So we dont use that on other browsers unless tested sufficiently.
214
- // Although IE 10 supports pointer event, it use old style and is different from the
214
+ // For example, in iOS 13 Mobile Chromium 78, if the touching behavior starts page
215
+ // scroll, the `pointermove` event can not be fired any more. That will break some
216
+ // features like "pan horizontally to move something and pan vertically to page scroll".
217
+ // The horizontal pan probably be interrupted by the casually triggered page scroll.
218
+ // (2) Although IE 10 supports pointer event, it use old style and is different from the
215
219
  // standard. So we exclude that. (IE 10 is hardly used on touch device)
216
- && (browser.edge || (browser.ie && browser.version >= 11)),
220
+ 'onpointerdown' in window
221
+ && (browser.edge || (browser.ie && browser.version >= 11)),
217
222
  // passiveSupported: detectPassiveSupport()
218
223
  domSupported: typeof document !== 'undefined'
219
224
  };
@@ -1149,7 +1154,11 @@ function Draggable() {
1149
1154
  this.on('mousedown', this._dragStart, this);
1150
1155
  this.on('mousemove', this._drag, this);
1151
1156
  this.on('mouseup', this._dragEnd, this);
1152
- this.on('globalout', this._dragEnd, this);
1157
+ // `mosuemove` and `mouseup` can be continue to fire when dragging.
1158
+ // See [Drag outside] in `Handler.js`. So we do not need to trigger
1159
+ // `_dragEnd` when globalout. That would brings better user experience.
1160
+ // this.on('globalout', this._dragEnd, this);
1161
+
1153
1162
  // this._dropTarget = null;
1154
1163
  // this._draggingTarget = null;
1155
1164
 
@@ -1250,7 +1259,7 @@ var arrySlice = Array.prototype.slice;
1250
1259
  * param: {string} eventType
1251
1260
  * param: {string|Object} query
1252
1261
  * return: {boolean}
1253
- * @param {Function} [eventProcessor.afterTrigger] Call after all handlers called.
1262
+ * @param {Function} [eventProcessor.afterTrigger] Called after all handlers called.
1254
1263
  * param: {string} eventType
1255
1264
  */
1256
1265
  var Eventful = function (eventProcessor) {
@@ -1300,8 +1309,10 @@ Eventful.prototype = {
1300
1309
  /**
1301
1310
  * Unbind a event.
1302
1311
  *
1303
- * @param {string} event The event name.
1312
+ * @param {string} [event] The event name.
1313
+ * If no `event` input, "off" all listeners.
1304
1314
  * @param {Function} [handler] The event handler.
1315
+ * If no `handler` input, "off" all listeners of the `event`.
1305
1316
  */
1306
1317
  off: function (event, handler) {
1307
1318
  var _h = this._$handlers;
@@ -1459,6 +1470,7 @@ Eventful.prototype = {
1459
1470
  }
1460
1471
  };
1461
1472
 
1473
+
1462
1474
  function normalizeQuery(host, query) {
1463
1475
  var eventProcessor = host._$eventProcessor;
1464
1476
  if (query != null && eventProcessor && eventProcessor.normalizeQuery) {
@@ -1776,6 +1788,18 @@ function preparePointerTransformer(markers, saved) {
1776
1788
  );
1777
1789
  }
1778
1790
 
1791
+ /**
1792
+ * Find native event compat for legency IE.
1793
+ * Should be called at the begining of a native event listener.
1794
+ *
1795
+ * @param {Event} [e] Mouse event or touch event or pointer event.
1796
+ * For lagency IE, we use `window.event` is used.
1797
+ * @return {Event} The native event.
1798
+ */
1799
+ function getNativeEvent(e) {
1800
+ return e || window.event;
1801
+ }
1802
+
1779
1803
  /**
1780
1804
  * Normalize the coordinates of the input event.
1781
1805
  *
@@ -1790,14 +1814,14 @@ function preparePointerTransformer(markers, saved) {
1790
1814
  * between the result coords and the parameters `el` and `calculate`.
1791
1815
  *
1792
1816
  * @param {HTMLElement} el DOM element.
1793
- * @param {Event} [e] Mouse event or touch event. For lagency IE,
1794
- * do not need to input it and `window.event` is used.
1817
+ * @param {Event} [e] See `getNativeEvent`.
1795
1818
  * @param {boolean} [calculate=false] Whether to force calculate
1796
1819
  * the coordinates but not use ones provided by browser.
1820
+ * @return {UIEvent} The normalized native UIEvent.
1797
1821
  */
1798
1822
  function normalizeEvent(el, e, calculate) {
1799
1823
 
1800
- e = e || window.event;
1824
+ e = getNativeEvent(e);
1801
1825
 
1802
1826
  if (e.zrX != null) {
1803
1827
  return e;
@@ -1837,8 +1861,11 @@ function normalizeEvent(el, e, calculate) {
1837
1861
  * @param {HTMLElement} el
1838
1862
  * @param {string} name
1839
1863
  * @param {Function} handler
1864
+ * @param {Object|boolean} opt If boolean, means `opt.capture`
1865
+ * @param {boolean} [opt.capture=false]
1866
+ * @param {boolean} [opt.passive=false]
1840
1867
  */
1841
- function addEventListener(el, name, handler) {
1868
+ function addEventListener(el, name, handler, opt) {
1842
1869
  if (isDomLevel2) {
1843
1870
  // Reproduct the console warning:
1844
1871
  // [Violation] Added non-passive event listener to a scroll-blocking <some> event.
@@ -1861,16 +1888,24 @@ function addEventListener(el, name, handler) {
1861
1888
  // // By default, the third param of el.addEventListener is `capture: false`.
1862
1889
  // : void 0;
1863
1890
  // el.addEventListener(name, handler /* , opts */);
1864
- el.addEventListener(name, handler);
1891
+ el.addEventListener(name, handler, opt);
1865
1892
  }
1866
1893
  else {
1894
+ // For simplicity, do not implement `setCapture` for IE9-.
1867
1895
  el.attachEvent('on' + name, handler);
1868
1896
  }
1869
1897
  }
1870
1898
 
1871
- function removeEventListener(el, name, handler) {
1899
+ /**
1900
+ * Parameter are the same as `addEventListener`.
1901
+ *
1902
+ * Notice that if a listener is registered twice, one with capture and one without,
1903
+ * remove each one separately. Removal of a capturing listener does not affect a
1904
+ * non-capturing version of the same listener, and vice versa.
1905
+ */
1906
+ function removeEventListener(el, name, handler, opt) {
1872
1907
  if (isDomLevel2) {
1873
- el.removeEventListener(name, handler);
1908
+ el.removeEventListener(name, handler, opt);
1874
1909
  }
1875
1910
  else {
1876
1911
  el.detachEvent('on' + name, handler);
@@ -2023,6 +2058,65 @@ var recognizers = {
2023
2058
  // Only pinch currently.
2024
2059
  };
2025
2060
 
2061
+ /**
2062
+ * [The interface between `Handler` and `HandlerProxy`]:
2063
+ *
2064
+ * The default `HandlerProxy` only support the common standard web environment
2065
+ * (e.g., standalone browser, headless browser, embed browser in mobild APP, ...).
2066
+ * But `HandlerProxy` can be replaced to support more non-standard environment
2067
+ * (e.g., mini app), or to support more feature that the default `HandlerProxy`
2068
+ * not provided (like echarts-gl did).
2069
+ * So the interface between `Handler` and `HandlerProxy` should be stable. Do not
2070
+ * make break changes util inevitable. The interface include the public methods
2071
+ * of `Handler` and the events listed in `handlerNames` below, by which `HandlerProxy`
2072
+ * drives `Handler`.
2073
+ */
2074
+
2075
+ /**
2076
+ * [Drag outside]:
2077
+ *
2078
+ * That is, triggering `mousemove` and `mouseup` event when the pointer is out of the
2079
+ * zrender area when dragging. That is important for the improvement of the user experience
2080
+ * when dragging something near the boundary without being terminated unexpectedly.
2081
+ *
2082
+ * We originally consider to introduce new events like `pagemovemove` and `pagemouseup`
2083
+ * to resolve this issue. But some drawbacks of it is described in
2084
+ * https://github.com/ecomfe/zrender/pull/536#issuecomment-560286899
2085
+ *
2086
+ * Instead, we referenced the specifications:
2087
+ * https://www.w3.org/TR/touch-events/#the-touchmove-event
2088
+ * https://www.w3.org/TR/2014/WD-DOM-Level-3-Events-20140925/#event-type-mousemove
2089
+ * where the the mousemove/touchmove can be continue to fire if the user began a drag
2090
+ * operation and the pointer has left the boundary. (for the mouse event, browsers
2091
+ * only do it on `document` and when the pointer has left the boundary of the browser.)
2092
+ *
2093
+ * So the default `HandlerProxy` supports this feature similarly: if it is in the dragging
2094
+ * state (see `pointerCapture` in `HandlerProxy`), the `mousemove` and `mouseup` continue
2095
+ * to fire until release the pointer. That is implemented by listen to those event on
2096
+ * `document`.
2097
+ * If we implement some other `HandlerProxy` only for touch device, that would be easier.
2098
+ * The touch event support this feature by default.
2099
+ *
2100
+ * Note:
2101
+ * There might be some cases that the mouse event can not be
2102
+ * received on `document`. For example,
2103
+ * (A) `useCapture` is not supported and some user defined event listeners on the ancestor
2104
+ * of zr dom throw Error .
2105
+ * (B) `useCapture` is not supported Some user defined event listeners on the ancestor of
2106
+ * zr dom call `stopPropagation`.
2107
+ * In these cases, the `mousemove` event might be keep triggered event
2108
+ * if the mouse is released. We try to reduce the side-effect in those cases.
2109
+ * That is, do nothing (especially, `findHover`) in those cases. See `isOutsideBoundary`.
2110
+ *
2111
+ * Note:
2112
+ * If `HandlerProxy` listens to `document` with `useCapture`, `HandlerProxy` needs to
2113
+ * make sure `stopPropagation` and `preventDefault` doing nothing if and only if the event
2114
+ * target is not zrender dom. Becuase it is dangerous to enable users to call them in
2115
+ * `document` capture phase to prevent the propagation to any listener of the webpage.
2116
+ * But they are needed to work when the pointer inside the zrender dom.
2117
+ */
2118
+
2119
+
2026
2120
  var SILENT = 'silent';
2027
2121
 
2028
2122
  function makeEventPacket(eveType, targetInfo, event) {
@@ -2047,17 +2141,19 @@ function makeEventPacket(eveType, targetInfo, event) {
2047
2141
  };
2048
2142
  }
2049
2143
 
2050
- function stopEvent(event) {
2144
+ function stopEvent() {
2051
2145
  stop(this.event);
2052
2146
  }
2053
2147
 
2054
2148
  function EmptyProxy() {}
2055
2149
  EmptyProxy.prototype.dispose = function () {};
2056
2150
 
2151
+
2057
2152
  var handlerNames = [
2058
2153
  'click', 'dblclick', 'mousewheel', 'mouseout',
2059
2154
  'mouseup', 'mousedown', 'mousemove', 'contextmenu'
2060
2155
  ];
2156
+
2061
2157
  /**
2062
2158
  * @alias module:zrender/Handler
2063
2159
  * @constructor
@@ -2114,7 +2210,6 @@ var Handler = function (storage, painter, proxy, painterRoot) {
2114
2210
  */
2115
2211
  this._gestureMgr;
2116
2212
 
2117
-
2118
2213
  Draggable.call(this);
2119
2214
 
2120
2215
  this.setHandlerProxy(proxy);
@@ -2143,6 +2238,8 @@ Handler.prototype = {
2143
2238
  var x = event.zrX;
2144
2239
  var y = event.zrY;
2145
2240
 
2241
+ var isOutside = isOutsideBoundary(this, x, y);
2242
+
2146
2243
  var lastHovered = this._hovered;
2147
2244
  var lastHoveredTarget = lastHovered.target;
2148
2245
 
@@ -2155,7 +2252,7 @@ Handler.prototype = {
2155
2252
  lastHoveredTarget = lastHovered.target;
2156
2253
  }
2157
2254
 
2158
- var hovered = this._hovered = this.findHover(x, y);
2255
+ var hovered = this._hovered = isOutside ? {x: x, y: y} : this.findHover(x, y);
2159
2256
  var hoveredTarget = hovered.target;
2160
2257
 
2161
2258
  var proxy = this.proxy;
@@ -2176,23 +2273,18 @@ Handler.prototype = {
2176
2273
  },
2177
2274
 
2178
2275
  mouseout: function (event) {
2179
- this.dispatchToElement(this._hovered, 'mouseout', event);
2276
+ var eventControl = event.zrEventControl;
2277
+ var zrIsToLocalDOM = event.zrIsToLocalDOM;
2180
2278
 
2181
- // There might be some doms created by upper layer application
2182
- // at the same level of painter.getViewportRoot() (e.g., tooltip
2183
- // dom created by echarts), where 'globalout' event should not
2184
- // be triggered when mouse enters these doms. (But 'mouseout'
2185
- // should be triggered at the original hovered element as usual).
2186
- var element = event.toElement || event.relatedTarget;
2187
- var innerDom;
2188
- do {
2189
- element = element && element.parentNode;
2279
+ if (eventControl !== 'only_globalout') {
2280
+ this.dispatchToElement(this._hovered, 'mouseout', event);
2190
2281
  }
2191
- while (element && element.nodeType !== 9 && !(
2192
- innerDom = element === this.painterRoot
2193
- ));
2194
2282
 
2195
- !innerDom && this.trigger('globalout', {event: event});
2283
+ if (eventControl !== 'no_globalout') {
2284
+ // FIXME: if the pointer moving from the extra doms to realy "outside",
2285
+ // the `globalout` should have been triggered. But currently not.
2286
+ !zrIsToLocalDOM && this.trigger('globalout', {type: 'globalout', event: event});
2287
+ }
2196
2288
  },
2197
2289
 
2198
2290
  /**
@@ -2338,9 +2430,18 @@ Handler.prototype = {
2338
2430
  // Common handlers
2339
2431
  each$1(['click', 'mousedown', 'mouseup', 'mousewheel', 'dblclick', 'contextmenu'], function (name) {
2340
2432
  Handler.prototype[name] = function (event) {
2341
- // Find hover again to avoid click event is dispatched manually. Or click is triggered without mouseover
2342
- var hovered = this.findHover(event.zrX, event.zrY);
2343
- var hoveredTarget = hovered.target;
2433
+ var x = event.zrX;
2434
+ var y = event.zrY;
2435
+ var isOutside = isOutsideBoundary(this, x, y);
2436
+
2437
+ var hovered;
2438
+ var hoveredTarget;
2439
+
2440
+ if (name !== 'mouseup' || !isOutside) {
2441
+ // Find hover again to avoid click event is dispatched manually. Or click is triggered without mouseover
2442
+ hovered = this.findHover(x, y);
2443
+ hoveredTarget = hovered.target;
2444
+ }
2344
2445
 
2345
2446
  if (name === 'mousedown') {
2346
2447
  this._downEl = hoveredTarget;
@@ -2392,6 +2493,14 @@ function isHover(displayable, x, y) {
2392
2493
  return false;
2393
2494
  }
2394
2495
 
2496
+ /**
2497
+ * See [Drag outside].
2498
+ */
2499
+ function isOutsideBoundary(handlerInstance, x, y) {
2500
+ var painter = handlerInstance.painter;
2501
+ return x < 0 || x > painter.getWidth() || y < 0 || y > painter.getHeight();
2502
+ }
2503
+
2395
2504
  mixin(Handler, Eventful);
2396
2505
  mixin(Handler, Draggable);
2397
2506
 
@@ -10511,30 +10620,55 @@ Animation.prototype = {
10511
10620
 
10512
10621
  mixin(Animation, Eventful);
10513
10622
 
10623
+ /* global document */
10624
+
10514
10625
  var TOUCH_CLICK_DELAY = 300;
10515
10626
 
10516
- var mouseHandlerNames = [
10517
- 'click', 'dblclick', 'mousewheel', 'mouseout',
10518
- 'mouseup', 'mousedown', 'mousemove', 'contextmenu'
10519
- ];
10627
+ var globalEventSupported = env$1.domSupported;
10520
10628
 
10521
- var touchHandlerNames = [
10522
- 'touchstart', 'touchend', 'touchmove'
10523
- ];
10524
10629
 
10525
- var pointerEventNames = {
10526
- pointerdown: 1, pointerup: 1, pointermove: 1, pointerout: 1
10630
+ var localNativeListenerNames = (function () {
10631
+ var mouseHandlerNames = [
10632
+ 'click', 'dblclick', 'mousewheel', 'mouseout',
10633
+ 'mouseup', 'mousedown', 'mousemove', 'contextmenu'
10634
+ ];
10635
+ var touchHandlerNames = [
10636
+ 'touchstart', 'touchend', 'touchmove'
10637
+ ];
10638
+ var pointerEventNameMap = {
10639
+ pointerdown: 1, pointerup: 1, pointermove: 1, pointerout: 1
10640
+ };
10641
+ var pointerHandlerNames = map(mouseHandlerNames, function (name) {
10642
+ var nm = name.replace('mouse', 'pointer');
10643
+ return pointerEventNameMap.hasOwnProperty(nm) ? nm : name;
10644
+ });
10645
+
10646
+ return {
10647
+ mouse: mouseHandlerNames,
10648
+ touch: touchHandlerNames,
10649
+ pointer: pointerHandlerNames
10650
+ };
10651
+ })();
10652
+
10653
+ var globalNativeListenerNames = {
10654
+ mouse: ['mousemove', 'mouseup'],
10655
+ pointer: ['pointermove', 'pointerup']
10527
10656
  };
10528
10657
 
10529
- var pointerHandlerNames = map(mouseHandlerNames, function (name) {
10530
- var nm = name.replace('mouse', 'pointer');
10531
- return pointerEventNames[nm] ? nm : name;
10532
- });
10533
10658
 
10534
10659
  function eventNameFix(name) {
10535
10660
  return (name === 'mousewheel' && env$1.browser.firefox) ? 'DOMMouseScroll' : name;
10536
10661
  }
10537
10662
 
10663
+ function isPointerFromTouch(event) {
10664
+ var pointerType = event.pointerType;
10665
+ return pointerType === 'pen' || pointerType === 'touch';
10666
+ }
10667
+
10668
+ // function useMSGuesture(handlerProxy, event) {
10669
+ // return isPointerFromTouch(event) && !!handlerProxy._msGesture;
10670
+ // }
10671
+
10538
10672
  // function onMSGestureChange(proxy, event) {
10539
10673
  // if (event.translationX || event.translationY) {
10540
10674
  // // mousemove is carried by MSGesture to reduce the sensitivity.
@@ -10554,117 +10688,174 @@ function eventNameFix(name) {
10554
10688
  * 1. Mobile browsers dispatch mouse events 300ms after touchend.
10555
10689
  * 2. Chrome for Android dispatch mousedown for long-touch about 650ms
10556
10690
  * Result: Blocking Mouse Events for 700ms.
10691
+ *
10692
+ * @param {DOMHandlerScope} scope
10557
10693
  */
10558
- function setTouchTimer(instance) {
10559
- instance._touching = true;
10560
- clearTimeout(instance._touchTimer);
10561
- instance._touchTimer = setTimeout(function () {
10562
- instance._touching = false;
10694
+ function setTouchTimer(scope) {
10695
+ scope.touching = true;
10696
+ if (scope.touchTimer != null) {
10697
+ clearTimeout(scope.touchTimer);
10698
+ scope.touchTimer = null;
10699
+ }
10700
+ scope.touchTimer = setTimeout(function () {
10701
+ scope.touching = false;
10702
+ scope.touchTimer = null;
10563
10703
  }, 700);
10564
10704
  }
10565
10705
 
10706
+ // Mark touch, which is useful in distinguish touch and
10707
+ // mouse event in upper applicatoin.
10708
+ function markTouch(event) {
10709
+ event && (event.zrByTouch = true);
10710
+ }
10711
+
10712
+
10713
+ // function markTriggeredFromLocal(event) {
10714
+ // event && (event.__zrIsFromLocal = true);
10715
+ // }
10716
+
10717
+ // function isTriggeredFromLocal(instance, event) {
10718
+ // return !!(event && event.__zrIsFromLocal);
10719
+ // }
10720
+
10721
+ function normalizeGlobalEvent(instance, event) {
10722
+ // offsetX, offsetY still need to be calculated. They are necessary in the event
10723
+ // handlers of the upper applications. Set `true` to force calculate them.
10724
+ return normalizeEvent(instance.dom, new FakeGlobalEvent(instance, event), true);
10725
+ }
10726
+
10727
+ /**
10728
+ * Detect whether the given el is in `painterRoot`.
10729
+ */
10730
+ function isLocalEl(instance, el) {
10731
+ var isLocal = false;
10732
+ do {
10733
+ el = el && el.parentNode;
10734
+ }
10735
+ while (el && el.nodeType !== 9 && !(
10736
+ isLocal = el === instance.painterRoot
10737
+ ));
10738
+ return isLocal;
10739
+ }
10740
+
10741
+ /**
10742
+ * Make a fake event but not change the original event,
10743
+ * becuase the global event probably be used by other
10744
+ * listeners not belonging to zrender.
10745
+ * @class
10746
+ */
10747
+ function FakeGlobalEvent(instance, event) {
10748
+ this.type = event.type;
10749
+ this.target = this.currentTarget = instance.dom;
10750
+ this.pointerType = event.pointerType;
10751
+ // Necessray for the force calculation of zrX, zrY
10752
+ this.clientX = event.clientX;
10753
+ this.clientY = event.clientY;
10754
+ // Because we do not mount global listeners to touch events,
10755
+ // we do not copy `targetTouches` and `changedTouches` here.
10756
+ }
10757
+ var fakeGlobalEventProto = FakeGlobalEvent.prototype;
10758
+ // we make the default methods on the event do nothing,
10759
+ // otherwise it is dangerous. See more details in
10760
+ // [Drag outside] in `Handler.js`.
10761
+ fakeGlobalEventProto.stopPropagation =
10762
+ fakeGlobalEventProto.stopImmediatePropagation =
10763
+ fakeGlobalEventProto.preventDefault = noop;
10764
+
10765
+
10766
+ /**
10767
+ * Local DOM Handlers
10768
+ * @this {HandlerProxy}
10769
+ */
10770
+ var localDOMHandlers = {
10771
+
10772
+ mousedown: function (event) {
10773
+ event = normalizeEvent(this.dom, event);
10774
+
10775
+ this._mayPointerCapture = [event.zrX, event.zrY];
10776
+
10777
+ this.trigger('mousedown', event);
10778
+ },
10566
10779
 
10567
- var domHandlers = {
10568
- /**
10569
- * Mouse move handler
10570
- * @inner
10571
- * @param {Event} event
10572
- */
10573
10780
  mousemove: function (event) {
10574
10781
  event = normalizeEvent(this.dom, event);
10575
10782
 
10783
+ var downPoint = this._mayPointerCapture;
10784
+ if (downPoint && (event.zrX !== downPoint[0] || event.zrY !== downPoint[1])) {
10785
+ togglePointerCapture(this, true);
10786
+ }
10787
+
10576
10788
  this.trigger('mousemove', event);
10577
10789
  },
10578
10790
 
10579
- /**
10580
- * Mouse out handler
10581
- * @inner
10582
- * @param {Event} event
10583
- */
10584
- mouseout: function (event) {
10791
+ mouseup: function (event) {
10585
10792
  event = normalizeEvent(this.dom, event);
10586
10793
 
10587
- var element = event.toElement || event.relatedTarget;
10588
- if (element !== this.dom) {
10589
- while (element && element.nodeType !== 9) {
10590
- // 忽略包含在root中的dom引起的mouseOut
10591
- if (element === this.dom) {
10592
- return;
10593
- }
10794
+ togglePointerCapture(this, false);
10594
10795
 
10595
- element = element.parentNode;
10596
- }
10796
+ this.trigger('mouseup', event);
10797
+ },
10798
+
10799
+ mouseout: function (event) {
10800
+ event = normalizeEvent(this.dom, event);
10801
+
10802
+ // Similarly to the browser did on `document` and touch event,
10803
+ // `globalout` will be delayed to final pointer cature release.
10804
+ if (this._pointerCapturing) {
10805
+ event.zrEventControl = 'no_globalout';
10597
10806
  }
10598
10807
 
10808
+ // There might be some doms created by upper layer application
10809
+ // at the same level of painter.getViewportRoot() (e.g., tooltip
10810
+ // dom created by echarts), where 'globalout' event should not
10811
+ // be triggered when mouse enters these doms. (But 'mouseout'
10812
+ // should be triggered at the original hovered element as usual).
10813
+ var element = event.toElement || event.relatedTarget;
10814
+ event.zrIsToLocalDOM = isLocalEl(this, element);
10815
+
10599
10816
  this.trigger('mouseout', event);
10600
10817
  },
10601
10818
 
10602
- /**
10603
- * Touch开始响应函数
10604
- * @inner
10605
- * @param {Event} event
10606
- */
10607
10819
  touchstart: function (event) {
10608
10820
  // Default mouse behaviour should not be disabled here.
10609
10821
  // For example, page may needs to be slided.
10610
10822
  event = normalizeEvent(this.dom, event);
10611
10823
 
10612
- // Mark touch, which is useful in distinguish touch and
10613
- // mouse event in upper applicatoin.
10614
- event.zrByTouch = true;
10824
+ markTouch(event);
10615
10825
 
10616
10826
  this._lastTouchMoment = new Date();
10617
10827
 
10618
10828
  this.handler.processGesture(event, 'start');
10619
10829
 
10620
- // In touch device, trigger `mousemove`(`mouseover`) should
10621
- // be triggered, and must before `mousedown` triggered.
10622
- domHandlers.mousemove.call(this, event);
10623
-
10624
- domHandlers.mousedown.call(this, event);
10625
-
10626
- setTouchTimer(this);
10830
+ // For consistent event listener for both touch device and mouse device,
10831
+ // we simulate "mouseover-->mousedown" in touch device. So we trigger
10832
+ // `mousemove` here (to trigger `mouseover` inside), and then trigger
10833
+ // `mousedown`.
10834
+ localDOMHandlers.mousemove.call(this, event);
10835
+ localDOMHandlers.mousedown.call(this, event);
10627
10836
  },
10628
10837
 
10629
- /**
10630
- * Touch移动响应函数
10631
- * @inner
10632
- * @param {Event} event
10633
- */
10634
10838
  touchmove: function (event) {
10635
-
10636
10839
  event = normalizeEvent(this.dom, event);
10637
10840
 
10638
- // Mark touch, which is useful in distinguish touch and
10639
- // mouse event in upper applicatoin.
10640
- event.zrByTouch = true;
10841
+ markTouch(event);
10641
10842
 
10642
10843
  this.handler.processGesture(event, 'change');
10643
10844
 
10644
10845
  // Mouse move should always be triggered no matter whether
10645
10846
  // there is gestrue event, because mouse move and pinch may
10646
10847
  // be used at the same time.
10647
- domHandlers.mousemove.call(this, event);
10648
-
10649
- setTouchTimer(this);
10848
+ localDOMHandlers.mousemove.call(this, event);
10650
10849
  },
10651
10850
 
10652
- /**
10653
- * Touch结束响应函数
10654
- * @inner
10655
- * @param {Event} event
10656
- */
10657
10851
  touchend: function (event) {
10658
-
10659
10852
  event = normalizeEvent(this.dom, event);
10660
10853
 
10661
- // Mark touch, which is useful in distinguish touch and
10662
- // mouse event in upper applicatoin.
10663
- event.zrByTouch = true;
10854
+ markTouch(event);
10664
10855
 
10665
10856
  this.handler.processGesture(event, 'end');
10666
10857
 
10667
- domHandlers.mouseup.call(this, event);
10858
+ localDOMHandlers.mouseup.call(this, event);
10668
10859
 
10669
10860
  // Do not trigger `mouseout` here, in spite of `mousemove`(`mouseover`) is
10670
10861
  // triggered in `touchstart`. This seems to be illogical, but by this mechanism,
@@ -10677,14 +10868,12 @@ var domHandlers = {
10677
10868
  // click event should always be triggered no matter whether
10678
10869
  // there is gestrue event. System click can not be prevented.
10679
10870
  if (+new Date() - this._lastTouchMoment < TOUCH_CLICK_DELAY) {
10680
- domHandlers.click.call(this, event);
10871
+ localDOMHandlers.click.call(this, event);
10681
10872
  }
10682
-
10683
- setTouchTimer(this);
10684
10873
  },
10685
10874
 
10686
10875
  pointerdown: function (event) {
10687
- domHandlers.mousedown.call(this, event);
10876
+ localDOMHandlers.mousedown.call(this, event);
10688
10877
 
10689
10878
  // if (useMSGuesture(this, event)) {
10690
10879
  // this._msGesture.addPointer(event.pointerId);
@@ -10698,12 +10887,12 @@ var domHandlers = {
10698
10887
  // upper application. So, we dont support mousemove on MS touch
10699
10888
  // device yet.
10700
10889
  if (!isPointerFromTouch(event)) {
10701
- domHandlers.mousemove.call(this, event);
10890
+ localDOMHandlers.mousemove.call(this, event);
10702
10891
  }
10703
10892
  },
10704
10893
 
10705
10894
  pointerup: function (event) {
10706
- domHandlers.mouseup.call(this, event);
10895
+ localDOMHandlers.mouseup.call(this, event);
10707
10896
  },
10708
10897
 
10709
10898
  pointerout: function (event) {
@@ -10711,80 +10900,77 @@ var domHandlers = {
10711
10900
  // (IE11+/Edge on MS Surface) after click event triggered,
10712
10901
  // which is inconsistent with the mousout behavior we defined
10713
10902
  // in touchend. So we unify them.
10714
- // (check domHandlers.touchend for detailed explanation)
10903
+ // (check localDOMHandlers.touchend for detailed explanation)
10715
10904
  if (!isPointerFromTouch(event)) {
10716
- domHandlers.mouseout.call(this, event);
10905
+ localDOMHandlers.mouseout.call(this, event);
10717
10906
  }
10718
10907
  }
10719
- };
10720
-
10721
- function isPointerFromTouch(event) {
10722
- var pointerType = event.pointerType;
10723
- return pointerType === 'pen' || pointerType === 'touch';
10724
- }
10725
10908
 
10726
- // function useMSGuesture(handlerProxy, event) {
10727
- // return isPointerFromTouch(event) && !!handlerProxy._msGesture;
10728
- // }
10909
+ };
10729
10910
 
10730
- // Common handlers
10731
- each$1(['click', 'mousedown', 'mouseup', 'mousewheel', 'dblclick', 'contextmenu'], function (name) {
10732
- domHandlers[name] = function (event) {
10911
+ /**
10912
+ * Othere DOM UI Event handlers for zr dom.
10913
+ * @this {HandlerProxy}
10914
+ */
10915
+ each$1(['click', 'mousewheel', 'dblclick', 'contextmenu'], function (name) {
10916
+ localDOMHandlers[name] = function (event) {
10733
10917
  event = normalizeEvent(this.dom, event);
10734
10918
  this.trigger(name, event);
10735
10919
  };
10736
10920
  });
10737
10921
 
10922
+
10738
10923
  /**
10739
- * 为控制类实例初始化dom 事件处理函数
10924
+ * DOM UI Event handlers for global page.
10740
10925
  *
10741
- * @inner
10742
- * @param {module:zrender/Handler} instance 控制类实例
10926
+ * [Caution]:
10927
+ * those handlers should both support in capture phase and bubble phase!
10928
+ *
10929
+ * @this {HandlerProxy}
10743
10930
  */
10744
- function initDomHandler(instance) {
10745
- each$1(touchHandlerNames, function (name) {
10746
- instance._handlers[name] = bind(domHandlers[name], instance);
10747
- });
10931
+ var globalDOMHandlers = {
10748
10932
 
10749
- each$1(pointerHandlerNames, function (name) {
10750
- instance._handlers[name] = bind(domHandlers[name], instance);
10751
- });
10933
+ pointermove: function (event) {
10934
+ // FIXME
10935
+ // pointermove is so sensitive that it always triggered when
10936
+ // tap(click) on touch screen, which affect some judgement in
10937
+ // upper application. So, we dont support mousemove on MS touch
10938
+ // device yet.
10939
+ if (!isPointerFromTouch(event)) {
10940
+ globalDOMHandlers.mousemove.call(this, event);
10941
+ }
10942
+ },
10752
10943
 
10753
- each$1(mouseHandlerNames, function (name) {
10754
- instance._handlers[name] = makeMouseHandler(domHandlers[name], instance);
10755
- });
10944
+ pointerup: function (event) {
10945
+ globalDOMHandlers.mouseup.call(this, event);
10946
+ },
10756
10947
 
10757
- function makeMouseHandler(fn, instance) {
10758
- return function () {
10759
- if (instance._touching) {
10760
- return;
10761
- }
10762
- return fn.apply(instance, arguments);
10763
- };
10764
- }
10765
- }
10948
+ mousemove: function (event) {
10949
+ this.trigger('mousemove', event);
10950
+ },
10766
10951
 
10952
+ mouseup: function (event) {
10953
+ var pointerCaptureReleasing = this._pointerCapturing;
10767
10954
 
10768
- function HandlerDomProxy(dom) {
10769
- Eventful.call(this);
10955
+ togglePointerCapture(this, false);
10770
10956
 
10771
- this.dom = dom;
10957
+ this.trigger('mouseup', event);
10772
10958
 
10773
- /**
10774
- * @private
10775
- * @type {boolean}
10776
- */
10777
- this._touching = false;
10959
+ if (pointerCaptureReleasing) {
10960
+ event.zrEventControl = 'only_globalout';
10961
+ this.trigger('mouseout', event);
10962
+ }
10963
+ }
10778
10964
 
10779
- /**
10780
- * @private
10781
- * @type {number}
10782
- */
10783
- this._touchTimer;
10965
+ };
10784
10966
 
10785
- this._handlers = {};
10786
10967
 
10787
- initDomHandler(this);
10968
+ /**
10969
+ * @param {HandlerProxy} instance
10970
+ * @param {DOMHandlerScope} scope
10971
+ */
10972
+ function mountLocalDOMEventListeners(instance, scope) {
10973
+ var domHandlers = scope.domHandlers;
10788
10974
 
10789
10975
  if (env$1.pointerEventsSupported) { // Only IE11+/Edge
10790
10976
  // 1. On devices that both enable touch and mouse (e.g., MS Surface and lenovo X240),
@@ -10793,7 +10979,12 @@ function HandlerDomProxy(dom) {
10793
10979
  // 2. On MS Surface, it probablely only trigger mousedown but no mouseup when tap on
10794
10980
  // screen, which do not occurs in pointer event.
10795
10981
  // So we use pointer event to both detect touch gesture and mouse behavior.
10796
- mountHandlers(pointerHandlerNames, this);
10982
+ each$1(localNativeListenerNames.pointer, function (nativeEventName) {
10983
+ mountSingleDOMEventListener(scope, nativeEventName, function (event) {
10984
+ // markTriggeredFromLocal(event);
10985
+ domHandlers[nativeEventName].call(instance, event);
10986
+ });
10987
+ });
10797
10988
 
10798
10989
  // FIXME
10799
10990
  // Note: MS Gesture require CSS touch-action set. But touch-action is not reliable,
@@ -10812,7 +11003,13 @@ function HandlerDomProxy(dom) {
10812
11003
  }
10813
11004
  else {
10814
11005
  if (env$1.touchEventsSupported) {
10815
- mountHandlers(touchHandlerNames, this);
11006
+ each$1(localNativeListenerNames.touch, function (nativeEventName) {
11007
+ mountSingleDOMEventListener(scope, nativeEventName, function (event) {
11008
+ // markTriggeredFromLocal(event);
11009
+ domHandlers[nativeEventName].call(instance, event);
11010
+ setTouchTimer(scope);
11011
+ });
11012
+ });
10816
11013
  // Handler of 'mouseout' event is needed in touch mode, which will be mounted below.
10817
11014
  // addEventListener(root, 'mouseout', this._mouseoutHandler);
10818
11015
  }
@@ -10822,23 +11019,145 @@ function HandlerDomProxy(dom) {
10822
11019
  // mouse event can not be handle in those devices.
10823
11020
  // 2. On MS Surface, Chrome will trigger both touch event and mouse event. How to prevent
10824
11021
  // mouseevent after touch event triggered, see `setTouchTimer`.
10825
- mountHandlers(mouseHandlerNames, this);
11022
+ each$1(localNativeListenerNames.mouse, function (nativeEventName) {
11023
+ mountSingleDOMEventListener(scope, nativeEventName, function (event) {
11024
+ event = getNativeEvent(event);
11025
+ if (!scope.touching) {
11026
+ // markTriggeredFromLocal(event);
11027
+ domHandlers[nativeEventName].call(instance, event);
11028
+ }
11029
+ });
11030
+ });
11031
+ }
11032
+ }
11033
+
11034
+ /**
11035
+ * @param {HandlerProxy} instance
11036
+ * @param {DOMHandlerScope} scope
11037
+ */
11038
+ function mountGlobalDOMEventListeners(instance, scope) {
11039
+ // Only IE11+/Edge. See the comment in `mountLocalDOMEventListeners`.
11040
+ if (env$1.pointerEventsSupported) {
11041
+ each$1(globalNativeListenerNames.pointer, mount);
11042
+ }
11043
+ // Touch event has implemented "drag outside" so we do not mount global listener for touch event.
11044
+ // (see https://www.w3.org/TR/touch-events/#the-touchmove-event)
11045
+ // We do not consider "both-support-touch-and-mouse device" for this feature (see the comment of
11046
+ // `mountLocalDOMEventListeners`) to avoid bugs util some requirements come.
11047
+ else if (!env$1.touchEventsSupported) {
11048
+ each$1(globalNativeListenerNames.mouse, mount);
11049
+ }
11050
+
11051
+ function mount(nativeEventName) {
11052
+ function nativeEventListener(event) {
11053
+ event = getNativeEvent(event);
11054
+ // See the reason in [Drag outside] in `Handler.js`
11055
+ // This checking supports both `useCapture` or not.
11056
+ // PENDING: if there is performance issue in some devices,
11057
+ // we probably can not use `useCapture` and change a easier
11058
+ // to judes whether local (mark).
11059
+ if (!isLocalEl(instance, event.target)) {
11060
+ event = normalizeGlobalEvent(instance, event);
11061
+ scope.domHandlers[nativeEventName].call(instance, event);
11062
+ }
11063
+ }
11064
+ mountSingleDOMEventListener(
11065
+ scope, nativeEventName, nativeEventListener,
11066
+ {capture: true} // See [Drag Outside] in `Handler.js`
11067
+ );
11068
+ }
11069
+ }
11070
+
11071
+ function mountSingleDOMEventListener(scope, nativeEventName, listener, opt) {
11072
+ scope.mounted[nativeEventName] = listener;
11073
+ scope.listenerOpts[nativeEventName] = opt;
11074
+ addEventListener(scope.domTarget, eventNameFix(nativeEventName), listener, opt);
11075
+ }
11076
+
11077
+ function unmountDOMEventListeners(scope) {
11078
+ var mounted = scope.mounted;
11079
+ for (var nativeEventName in mounted) {
11080
+ if (mounted.hasOwnProperty(nativeEventName)) {
11081
+ removeEventListener(
11082
+ scope.domTarget, eventNameFix(nativeEventName), mounted[nativeEventName],
11083
+ scope.listenerOpts[nativeEventName]
11084
+ );
11085
+ }
11086
+ }
11087
+ scope.mounted = {};
11088
+ }
11089
+
11090
+ /**
11091
+ * See [Drag Outside] in `Handler.js`.
11092
+ * @implement
11093
+ * @param {boolean} isPointerCapturing Should never be `null`/`undefined`.
11094
+ * `true`: start to capture pointer if it is not capturing.
11095
+ * `false`: end the capture if it is capturing.
11096
+ */
11097
+ function togglePointerCapture(instance, isPointerCapturing) {
11098
+ instance._mayPointerCapture = null;
11099
+
11100
+ if (globalEventSupported && (instance._pointerCapturing ^ isPointerCapturing)) {
11101
+ instance._pointerCapturing = isPointerCapturing;
11102
+
11103
+ var globalHandlerScope = instance._globalHandlerScope;
11104
+ isPointerCapturing
11105
+ ? mountGlobalDOMEventListeners(instance, globalHandlerScope)
11106
+ : unmountDOMEventListeners(globalHandlerScope);
10826
11107
  }
11108
+ }
11109
+
11110
+ /**
11111
+ * @inner
11112
+ * @class
11113
+ */
11114
+ function DOMHandlerScope(domTarget, domHandlers) {
11115
+ this.domTarget = domTarget;
11116
+ this.domHandlers = domHandlers;
11117
+
11118
+ // Key: eventName, value: mounted handler funcitons.
11119
+ // Used for unmount.
11120
+ this.mounted = {};
11121
+ this.listenerOpts = {};
11122
+
11123
+ this.touchTimer = null;
11124
+ this.touching = false;
11125
+ }
11126
+
11127
+ /**
11128
+ * @public
11129
+ * @class
11130
+ */
11131
+ function HandlerDomProxy(dom, painterRoot) {
11132
+ Eventful.call(this);
11133
+
11134
+ this.dom = dom;
11135
+ this.painterRoot = painterRoot;
10827
11136
 
10828
- function mountHandlers(handlerNames, instance) {
10829
- each$1(handlerNames, function (name) {
10830
- addEventListener(dom, eventNameFix(name), instance._handlers[name]);
10831
- }, instance);
11137
+ this._localHandlerScope = new DOMHandlerScope(dom, localDOMHandlers);
11138
+
11139
+ if (globalEventSupported) {
11140
+ this._globalHandlerScope = new DOMHandlerScope(document, globalDOMHandlers);
10832
11141
  }
11142
+
11143
+ /**
11144
+ * @type {boolean}
11145
+ */
11146
+ this._pointerCapturing = false;
11147
+ /**
11148
+ * @type {Array.<number>} [x, y] or null.
11149
+ */
11150
+ this._mayPointerCapture = null;
11151
+
11152
+ mountLocalDOMEventListeners(this, this._localHandlerScope);
10833
11153
  }
10834
11154
 
10835
11155
  var handlerDomProxyProto = HandlerDomProxy.prototype;
10836
- handlerDomProxyProto.dispose = function () {
10837
- var handlerNames = mouseHandlerNames.concat(touchHandlerNames);
10838
11156
 
10839
- for (var i = 0; i < handlerNames.length; i++) {
10840
- var name = handlerNames[i];
10841
- removeEventListener(this.dom, eventNameFix(name), this._handlers[name]);
11157
+ handlerDomProxyProto.dispose = function () {
11158
+ unmountDOMEventListeners(this._localHandlerScope);
11159
+ if (globalEventSupported) {
11160
+ unmountDOMEventListeners(this._globalHandlerScope);
10842
11161
  }
10843
11162
  };
10844
11163
 
@@ -10846,6 +11165,7 @@ handlerDomProxyProto.setCursor = function (cursorStyle) {
10846
11165
  this.dom.style && (this.dom.style.cursor = cursorStyle || 'default');
10847
11166
  };
10848
11167
 
11168
+
10849
11169
  mixin(HandlerDomProxy, Eventful);
10850
11170
 
10851
11171
  /*!
@@ -10867,7 +11187,7 @@ var painterCtors = {
10867
11187
  /**
10868
11188
  * @type {string}
10869
11189
  */
10870
- var version$1 = '4.1.2';
11190
+ var version$1 = '4.2.0';
10871
11191
 
10872
11192
  /**
10873
11193
  * Initializing a zrender instance
@@ -10946,7 +11266,7 @@ var ZRender = function (id, dom, opts) {
10946
11266
  this.storage = storage;
10947
11267
  this.painter = painter;
10948
11268
 
10949
- var handerProxy = (!env$1.node && !env$1.worker) ? new HandlerDomProxy(painter.getViewportRoot()) : null;
11269
+ var handerProxy = (!env$1.node && !env$1.worker) ? new HandlerDomProxy(painter.getViewportRoot(), painter.root) : null;
10950
11270
  this.handler = new Handler(storage, painter, handerProxy, painter.root);
10951
11271
 
10952
11272
  /**
@@ -17425,8 +17745,7 @@ function rollbackDefaultTextStyle(style) {
17425
17745
  }
17426
17746
 
17427
17747
  function getFont(opt, ecModel) {
17428
- // ecModel or default text style model.
17429
- var gTextStyleModel = ecModel || ecModel.getModel('textStyle');
17748
+ var gTextStyleModel = ecModel && ecModel.getModel('textStyle');
17430
17749
  return trim([
17431
17750
  // FIXME in node-canvas fontWeight is before fontStyle
17432
17751
  opt.fontStyle || gTextStyleModel && gTextStyleModel.getShallow('fontStyle') || '',
@@ -19946,178 +20265,6 @@ var colorPaletteMixin = {
19946
20265
  * under the License.
19947
20266
  */
19948
20267
 
19949
- /**
19950
- * Helper for model references.
19951
- * There are many manners to refer axis/coordSys.
19952
- */
19953
-
19954
- // TODO
19955
- // merge relevant logic to this file?
19956
- // check: "modelHelper" of tooltip and "BrushTargetManager".
19957
-
19958
- /**
19959
- * @return {Object} For example:
19960
- * {
19961
- * coordSysName: 'cartesian2d',
19962
- * coordSysDims: ['x', 'y', ...],
19963
- * axisMap: HashMap({
19964
- * x: xAxisModel,
19965
- * y: yAxisModel
19966
- * }),
19967
- * categoryAxisMap: HashMap({
19968
- * x: xAxisModel,
19969
- * y: undefined
19970
- * }),
19971
- * // It also indicate that whether there is category axis.
19972
- * firstCategoryDimIndex: 1,
19973
- * // To replace user specified encode.
19974
- * }
19975
- */
19976
- function getCoordSysDefineBySeries(seriesModel) {
19977
- var coordSysName = seriesModel.get('coordinateSystem');
19978
- var result = {
19979
- coordSysName: coordSysName,
19980
- coordSysDims: [],
19981
- axisMap: createHashMap(),
19982
- categoryAxisMap: createHashMap()
19983
- };
19984
- var fetch = fetchers[coordSysName];
19985
- if (fetch) {
19986
- fetch(seriesModel, result, result.axisMap, result.categoryAxisMap);
19987
- return result;
19988
- }
19989
- }
19990
-
19991
- var fetchers = {
19992
-
19993
- cartesian2d: function (seriesModel, result, axisMap, categoryAxisMap) {
19994
- var xAxisModel = seriesModel.getReferringComponents('xAxis')[0];
19995
- var yAxisModel = seriesModel.getReferringComponents('yAxis')[0];
19996
-
19997
- if (__DEV__) {
19998
- if (!xAxisModel) {
19999
- throw new Error('xAxis "' + retrieve(
20000
- seriesModel.get('xAxisIndex'),
20001
- seriesModel.get('xAxisId'),
20002
- 0
20003
- ) + '" not found');
20004
- }
20005
- if (!yAxisModel) {
20006
- throw new Error('yAxis "' + retrieve(
20007
- seriesModel.get('xAxisIndex'),
20008
- seriesModel.get('yAxisId'),
20009
- 0
20010
- ) + '" not found');
20011
- }
20012
- }
20013
-
20014
- result.coordSysDims = ['x', 'y'];
20015
- axisMap.set('x', xAxisModel);
20016
- axisMap.set('y', yAxisModel);
20017
-
20018
- if (isCategory(xAxisModel)) {
20019
- categoryAxisMap.set('x', xAxisModel);
20020
- result.firstCategoryDimIndex = 0;
20021
- }
20022
- if (isCategory(yAxisModel)) {
20023
- categoryAxisMap.set('y', yAxisModel);
20024
- result.firstCategoryDimIndex = 1;
20025
- }
20026
- },
20027
-
20028
- singleAxis: function (seriesModel, result, axisMap, categoryAxisMap) {
20029
- var singleAxisModel = seriesModel.getReferringComponents('singleAxis')[0];
20030
-
20031
- if (__DEV__) {
20032
- if (!singleAxisModel) {
20033
- throw new Error('singleAxis should be specified.');
20034
- }
20035
- }
20036
-
20037
- result.coordSysDims = ['single'];
20038
- axisMap.set('single', singleAxisModel);
20039
-
20040
- if (isCategory(singleAxisModel)) {
20041
- categoryAxisMap.set('single', singleAxisModel);
20042
- result.firstCategoryDimIndex = 0;
20043
- }
20044
- },
20045
-
20046
- polar: function (seriesModel, result, axisMap, categoryAxisMap) {
20047
- var polarModel = seriesModel.getReferringComponents('polar')[0];
20048
- var radiusAxisModel = polarModel.findAxisModel('radiusAxis');
20049
- var angleAxisModel = polarModel.findAxisModel('angleAxis');
20050
-
20051
- if (__DEV__) {
20052
- if (!angleAxisModel) {
20053
- throw new Error('angleAxis option not found');
20054
- }
20055
- if (!radiusAxisModel) {
20056
- throw new Error('radiusAxis option not found');
20057
- }
20058
- }
20059
-
20060
- result.coordSysDims = ['radius', 'angle'];
20061
- axisMap.set('radius', radiusAxisModel);
20062
- axisMap.set('angle', angleAxisModel);
20063
-
20064
- if (isCategory(radiusAxisModel)) {
20065
- categoryAxisMap.set('radius', radiusAxisModel);
20066
- result.firstCategoryDimIndex = 0;
20067
- }
20068
- if (isCategory(angleAxisModel)) {
20069
- categoryAxisMap.set('angle', angleAxisModel);
20070
- result.firstCategoryDimIndex = 1;
20071
- }
20072
- },
20073
-
20074
- geo: function (seriesModel, result, axisMap, categoryAxisMap) {
20075
- result.coordSysDims = ['lng', 'lat'];
20076
- },
20077
-
20078
- parallel: function (seriesModel, result, axisMap, categoryAxisMap) {
20079
- var ecModel = seriesModel.ecModel;
20080
- var parallelModel = ecModel.getComponent(
20081
- 'parallel', seriesModel.get('parallelIndex')
20082
- );
20083
- var coordSysDims = result.coordSysDims = parallelModel.dimensions.slice();
20084
-
20085
- each$1(parallelModel.parallelAxisIndex, function (axisIndex, index) {
20086
- var axisModel = ecModel.getComponent('parallelAxis', axisIndex);
20087
- var axisDim = coordSysDims[index];
20088
- axisMap.set(axisDim, axisModel);
20089
-
20090
- if (isCategory(axisModel) && result.firstCategoryDimIndex == null) {
20091
- categoryAxisMap.set(axisDim, axisModel);
20092
- result.firstCategoryDimIndex = index;
20093
- }
20094
- });
20095
- }
20096
- };
20097
-
20098
- function isCategory(axisModel) {
20099
- return axisModel.get('type') === 'category';
20100
- }
20101
-
20102
- /*
20103
- * Licensed to the Apache Software Foundation (ASF) under one
20104
- * or more contributor license agreements. See the NOTICE file
20105
- * distributed with this work for additional information
20106
- * regarding copyright ownership. The ASF licenses this file
20107
- * to you under the Apache License, Version 2.0 (the
20108
- * "License"); you may not use this file except in compliance
20109
- * with the License. You may obtain a copy of the License at
20110
- *
20111
- * http://www.apache.org/licenses/LICENSE-2.0
20112
- *
20113
- * Unless required by applicable law or agreed to in writing,
20114
- * software distributed under the License is distributed on an
20115
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
20116
- * KIND, either express or implied. See the License for the
20117
- * specific language governing permissions and limitations
20118
- * under the License.
20119
- */
20120
-
20121
20268
  // Avoid typo.
20122
20269
  var SOURCE_FORMAT_ORIGINAL = 'original';
20123
20270
  var SOURCE_FORMAT_ARRAY_ROWS = 'arrayRows';
@@ -20287,6 +20434,13 @@ enableClassCheck(Source);
20287
20434
  * under the License.
20288
20435
  */
20289
20436
 
20437
+ // The result of `guessOrdinal`.
20438
+ var BE_ORDINAL = {
20439
+ Must: 1, // Encounter string but not '-' and not number-like.
20440
+ Might: 2, // Encounter string but number-like.
20441
+ Not: 3 // Other cases
20442
+ };
20443
+
20290
20444
  var inner$3 = makeInner();
20291
20445
 
20292
20446
  /**
@@ -20420,14 +20574,6 @@ function prepareSource(seriesModel) {
20420
20574
  data, sourceFormat, seriesLayoutBy, sourceHeader, dimensionsDefine
20421
20575
  );
20422
20576
 
20423
- // Note: dataset option does not have `encode`.
20424
- var encodeDefine = seriesOption.encode;
20425
- if (!encodeDefine && datasetModel) {
20426
- encodeDefine = makeDefaultEncode(
20427
- seriesModel, datasetModel, data, sourceFormat, seriesLayoutBy, completeResult
20428
- );
20429
- }
20430
-
20431
20577
  inner$3(seriesModel).source = new Source({
20432
20578
  data: data,
20433
20579
  fromDataset: fromDataset,
@@ -20436,7 +20582,8 @@ function prepareSource(seriesModel) {
20436
20582
  dimensionsDefine: completeResult.dimensionsDefine,
20437
20583
  startIndex: completeResult.startIndex,
20438
20584
  dimensionsDetectCount: completeResult.dimensionsDetectCount,
20439
- encodeDefine: encodeDefine
20585
+ // Note: dataset option does not have `encode`.
20586
+ encodeDefine: seriesOption.encode
20440
20587
  });
20441
20588
  }
20442
20589
 
@@ -20448,7 +20595,6 @@ function completeBySourceData(data, sourceFormat, seriesLayoutBy, sourceHeader,
20448
20595
 
20449
20596
  var dimensionsDetectCount;
20450
20597
  var startIndex;
20451
- var findPotentialName;
20452
20598
 
20453
20599
  if (sourceFormat === SOURCE_FORMAT_ARRAY_ROWS) {
20454
20600
  // Rule: Most of the first line are string: it is header.
@@ -20491,13 +20637,11 @@ function completeBySourceData(data, sourceFormat, seriesLayoutBy, sourceHeader,
20491
20637
  else if (sourceFormat === SOURCE_FORMAT_OBJECT_ROWS) {
20492
20638
  if (!dimensionsDefine) {
20493
20639
  dimensionsDefine = objectRowsCollectDimensions(data);
20494
- findPotentialName = true;
20495
20640
  }
20496
20641
  }
20497
20642
  else if (sourceFormat === SOURCE_FORMAT_KEYED_COLUMNS) {
20498
20643
  if (!dimensionsDefine) {
20499
20644
  dimensionsDefine = [];
20500
- findPotentialName = true;
20501
20645
  each$1(data, function (colArr, key) {
20502
20646
  dimensionsDefine.push(key);
20503
20647
  });
@@ -20513,21 +20657,10 @@ function completeBySourceData(data, sourceFormat, seriesLayoutBy, sourceHeader,
20513
20657
  }
20514
20658
  }
20515
20659
 
20516
- var potentialNameDimIndex;
20517
- if (findPotentialName) {
20518
- each$1(dimensionsDefine, function (dim, idx) {
20519
- if ((isObject$1(dim) ? dim.name : dim) === 'name') {
20520
- potentialNameDimIndex = idx;
20521
- }
20522
- });
20523
- }
20524
-
20525
20660
  return {
20526
20661
  startIndex: startIndex,
20527
20662
  dimensionsDefine: normalizeDimensionsDefine(dimensionsDefine),
20528
- dimensionsDetectCount: dimensionsDetectCount,
20529
- potentialNameDimIndex: potentialNameDimIndex
20530
- // TODO: potentialIdDimIdx
20663
+ dimensionsDetectCount: dimensionsDetectCount
20531
20664
  };
20532
20665
  }
20533
20666
 
@@ -20601,107 +20734,202 @@ function objectRowsCollectDimensions(data) {
20601
20734
  }
20602
20735
  }
20603
20736
 
20604
- // ??? TODO merge to completedimensions, where also has
20605
- // default encode making logic. And the default rule
20606
- // should depends on series? consider 'map'.
20607
- function makeDefaultEncode(
20608
- seriesModel, datasetModel, data, sourceFormat, seriesLayoutBy, completeResult
20609
- ) {
20610
- var coordSysDefine = getCoordSysDefineBySeries(seriesModel);
20737
+ /**
20738
+ * [The strategy of the arrengment of data dimensions for dataset]:
20739
+ * "value way": all axes are non-category axes. So series one by one take
20740
+ * several (the number is coordSysDims.length) dimensions from dataset.
20741
+ * The result of data arrengment of data dimensions like:
20742
+ * | ser0_x | ser0_y | ser1_x | ser1_y | ser2_x | ser2_y |
20743
+ * "category way": at least one axis is category axis. So the the first data
20744
+ * dimension is always mapped to the first category axis and shared by
20745
+ * all of the series. The other data dimensions are taken by series like
20746
+ * "value way" does.
20747
+ * The result of data arrengment of data dimensions like:
20748
+ * | ser_shared_x | ser0_y | ser1_y | ser2_y |
20749
+ *
20750
+ * @param {Array.<Object|string>} coordDimensions [{name: <string>, type: <string>, dimsDef: <Array>}, ...]
20751
+ * @param {module:model/Series} seriesModel
20752
+ * @param {module:data/Source} source
20753
+ * @return {Object} encode Never be `null/undefined`.
20754
+ */
20755
+ function makeSeriesEncodeForAxisCoordSys(coordDimensions, seriesModel, source) {
20611
20756
  var encode = {};
20612
- // var encodeTooltip = [];
20613
- // var encodeLabel = [];
20757
+
20758
+ var datasetModel = getDatasetModel(seriesModel);
20759
+ // Currently only make default when using dataset, util more reqirements occur.
20760
+ if (!datasetModel || !coordDimensions) {
20761
+ return encode;
20762
+ }
20763
+
20614
20764
  var encodeItemName = [];
20615
20765
  var encodeSeriesName = [];
20616
- var seriesType = seriesModel.subType;
20617
-
20618
- // ??? TODO refactor: provide by series itself.
20619
- // Consider the case: 'map' series is based on geo coordSys,
20620
- // 'graph', 'heatmap' can be based on cartesian. But can not
20621
- // give default rule simply here.
20622
- var nSeriesMap = createHashMap(['pie', 'map', 'funnel']);
20623
- var cSeriesMap = createHashMap([
20624
- 'line', 'bar', 'pictorialBar', 'scatter', 'effectScatter', 'candlestick', 'boxplot'
20625
- ]);
20626
-
20627
- // Usually in this case series will use the first data
20628
- // dimension as the "value" dimension, or other default
20629
- // processes respectively.
20630
- if (coordSysDefine && cSeriesMap.get(seriesType) != null) {
20631
- var ecModel = seriesModel.ecModel;
20632
- var datasetMap = inner$3(ecModel).datasetMap;
20633
- var key = datasetModel.uid + '_' + seriesLayoutBy;
20634
- var datasetRecord = datasetMap.get(key)
20635
- || datasetMap.set(key, {categoryWayDim: 1, valueWayDim: 0});
20636
20766
 
20637
- // TODO
20638
- // Auto detect first time axis and do arrangement.
20639
- each$1(coordSysDefine.coordSysDims, function (coordDim) {
20640
- // In value way.
20641
- if (coordSysDefine.firstCategoryDimIndex == null) {
20642
- var dataDim = datasetRecord.valueWayDim++;
20643
- encode[coordDim] = dataDim;
20644
-
20645
- // ??? TODO give a better default series name rule?
20646
- // especially when encode x y specified.
20647
- // consider: when mutiple series share one dimension
20648
- // category axis, series name should better use
20649
- // the other dimsion name. On the other hand, use
20650
- // both dimensions name.
20651
-
20652
- encodeSeriesName.push(dataDim);
20653
- // encodeTooltip.push(dataDim);
20654
- // encodeLabel.push(dataDim);
20655
- }
20656
- // In category way, category axis.
20657
- else if (coordSysDefine.categoryAxisMap.get(coordDim)) {
20658
- encode[coordDim] = 0;
20659
- encodeItemName.push(0);
20660
- }
20661
- // In category way, non-category axis.
20662
- else {
20663
- var dataDim = datasetRecord.categoryWayDim++;
20664
- encode[coordDim] = dataDim;
20665
- // encodeTooltip.push(dataDim);
20666
- // encodeLabel.push(dataDim);
20667
- encodeSeriesName.push(dataDim);
20668
- }
20669
- });
20767
+ var ecModel = seriesModel.ecModel;
20768
+ var datasetMap = inner$3(ecModel).datasetMap;
20769
+ var key = datasetModel.uid + '_' + source.seriesLayoutBy;
20770
+
20771
+ var baseCategoryDimIndex;
20772
+ var categoryWayValueDimStart;
20773
+ coordDimensions = coordDimensions.slice();
20774
+ each$1(coordDimensions, function (coordDimInfo, coordDimIdx) {
20775
+ !isObject$1(coordDimInfo) && (coordDimensions[coordDimIdx] = {name: coordDimInfo});
20776
+ if (coordDimInfo.type === 'ordinal' && baseCategoryDimIndex == null) {
20777
+ baseCategoryDimIndex = coordDimIdx;
20778
+ categoryWayValueDimStart = getDataDimCountOnCoordDim(coordDimensions[coordDimIdx]);
20779
+ }
20780
+ encode[coordDimInfo.name] = [];
20781
+ });
20782
+
20783
+ var datasetRecord = datasetMap.get(key)
20784
+ || datasetMap.set(key, {categoryWayDim: categoryWayValueDimStart, valueWayDim: 0});
20785
+
20786
+ // TODO
20787
+ // Auto detect first time axis and do arrangement.
20788
+ each$1(coordDimensions, function (coordDimInfo, coordDimIdx) {
20789
+ var coordDimName = coordDimInfo.name;
20790
+ var count = getDataDimCountOnCoordDim(coordDimInfo);
20791
+
20792
+ // In value way.
20793
+ if (baseCategoryDimIndex == null) {
20794
+ var start = datasetRecord.valueWayDim;
20795
+ pushDim(encode[coordDimName], start, count);
20796
+ pushDim(encodeSeriesName, start, count);
20797
+ datasetRecord.valueWayDim += count;
20798
+
20799
+ // ??? TODO give a better default series name rule?
20800
+ // especially when encode x y specified.
20801
+ // consider: when mutiple series share one dimension
20802
+ // category axis, series name should better use
20803
+ // the other dimsion name. On the other hand, use
20804
+ // both dimensions name.
20805
+ }
20806
+ // In category way, the first category axis.
20807
+ else if (baseCategoryDimIndex === coordDimIdx) {
20808
+ pushDim(encode[coordDimName], 0, count);
20809
+ pushDim(encodeItemName, 0, count);
20810
+ }
20811
+ // In category way, the other axis.
20812
+ else {
20813
+ var start = datasetRecord.categoryWayDim;
20814
+ pushDim(encode[coordDimName], start, count);
20815
+ pushDim(encodeSeriesName, start, count);
20816
+ datasetRecord.categoryWayDim += count;
20817
+ }
20818
+ });
20819
+
20820
+ function pushDim(dimIdxArr, idxFrom, idxCount) {
20821
+ for (var i = 0; i < idxCount; i++) {
20822
+ dimIdxArr.push(idxFrom + i);
20823
+ }
20670
20824
  }
20671
- // Do not make a complex rule! Hard to code maintain and not necessary.
20672
- // ??? TODO refactor: provide by series itself.
20673
- // [{name: ..., value: ...}, ...] like:
20674
- else if (nSeriesMap.get(seriesType) != null) {
20675
- // Find the first not ordinal. (5 is an experience value)
20676
- var firstNotOrdinal;
20677
- for (var i = 0; i < 5 && firstNotOrdinal == null; i++) {
20678
- if (!doGuessOrdinal(
20679
- data, sourceFormat, seriesLayoutBy,
20680
- completeResult.dimensionsDefine, completeResult.startIndex, i
20681
- )) {
20682
- firstNotOrdinal = i;
20683
- }
20684
- }
20685
- if (firstNotOrdinal != null) {
20686
- encode.value = firstNotOrdinal;
20687
- var nameDimIndex = completeResult.potentialNameDimIndex
20688
- || Math.max(firstNotOrdinal - 1, 0);
20689
- // By default, label use itemName in charts.
20690
- // So we dont set encodeLabel here.
20691
- encodeSeriesName.push(nameDimIndex);
20692
- encodeItemName.push(nameDimIndex);
20693
- // encodeTooltip.push(firstNotOrdinal);
20694
- }
20695
- }
20696
-
20697
- // encodeTooltip.length && (encode.tooltip = encodeTooltip);
20698
- // encodeLabel.length && (encode.label = encodeLabel);
20825
+
20826
+ function getDataDimCountOnCoordDim(coordDimInfo) {
20827
+ var dimsDef = coordDimInfo.dimsDef;
20828
+ return dimsDef ? dimsDef.length : 1;
20829
+ }
20830
+
20699
20831
  encodeItemName.length && (encode.itemName = encodeItemName);
20700
20832
  encodeSeriesName.length && (encode.seriesName = encodeSeriesName);
20701
20833
 
20702
20834
  return encode;
20703
20835
  }
20704
20836
 
20837
+ /**
20838
+ * Work for data like [{name: ..., value: ...}, ...].
20839
+ *
20840
+ * @param {module:model/Series} seriesModel
20841
+ * @param {module:data/Source} source
20842
+ * @return {Object} encode Never be `null/undefined`.
20843
+ */
20844
+ function makeSeriesEncodeForNameBased(seriesModel, source, dimCount) {
20845
+ var encode = {};
20846
+
20847
+ var datasetModel = getDatasetModel(seriesModel);
20848
+ // Currently only make default when using dataset, util more reqirements occur.
20849
+ if (!datasetModel) {
20850
+ return encode;
20851
+ }
20852
+
20853
+ var sourceFormat = source.sourceFormat;
20854
+ var dimensionsDefine = source.dimensionsDefine;
20855
+
20856
+ var potentialNameDimIndex;
20857
+ if (sourceFormat === SOURCE_FORMAT_OBJECT_ROWS || sourceFormat === SOURCE_FORMAT_KEYED_COLUMNS) {
20858
+ each$1(dimensionsDefine, function (dim, idx) {
20859
+ if ((isObject$1(dim) ? dim.name : dim) === 'name') {
20860
+ potentialNameDimIndex = idx;
20861
+ }
20862
+ });
20863
+ }
20864
+
20865
+ // idxResult: {v, n}.
20866
+ var idxResult = (function () {
20867
+
20868
+ var idxRes0 = {};
20869
+ var idxRes1 = {};
20870
+ var guessRecords = [];
20871
+
20872
+ // 5 is an experience value.
20873
+ for (var i = 0, len = Math.min(5, dimCount); i < len; i++) {
20874
+ var guessResult = doGuessOrdinal(
20875
+ source.data, sourceFormat, source.seriesLayoutBy,
20876
+ dimensionsDefine, source.startIndex, i
20877
+ );
20878
+ guessRecords.push(guessResult);
20879
+ var isPureNumber = guessResult === BE_ORDINAL.Not;
20880
+
20881
+ // [Strategy of idxRes0]: find the first BE_ORDINAL.Not as the value dim,
20882
+ // and then find a name dim with the priority:
20883
+ // "BE_ORDINAL.Might|BE_ORDINAL.Must" > "other dim" > "the value dim itself".
20884
+ if (isPureNumber && idxRes0.v == null && i !== potentialNameDimIndex) {
20885
+ idxRes0.v = i;
20886
+ }
20887
+ if (idxRes0.n == null
20888
+ || (idxRes0.n === idxRes0.v)
20889
+ || (!isPureNumber && guessRecords[idxRes0.n] === BE_ORDINAL.Not)
20890
+ ) {
20891
+ idxRes0.n = i;
20892
+ }
20893
+ if (fulfilled(idxRes0) && guessRecords[idxRes0.n] !== BE_ORDINAL.Not) {
20894
+ return idxRes0;
20895
+ }
20896
+
20897
+ // [Strategy of idxRes1]: if idxRes0 not satisfied (that is, no BE_ORDINAL.Not),
20898
+ // find the first BE_ORDINAL.Might as the value dim,
20899
+ // and then find a name dim with the priority:
20900
+ // "other dim" > "the value dim itself".
20901
+ // That is for backward compat: number-like (e.g., `'3'`, `'55'`) can be
20902
+ // treated as number.
20903
+ if (!isPureNumber) {
20904
+ if (guessResult === BE_ORDINAL.Might && idxRes1.v == null && i !== potentialNameDimIndex) {
20905
+ idxRes1.v = i;
20906
+ }
20907
+ if (idxRes1.n == null || (idxRes1.n === idxRes1.v)) {
20908
+ idxRes1.n = i;
20909
+ }
20910
+ }
20911
+ }
20912
+
20913
+ function fulfilled(idxResult) {
20914
+ return idxResult.v != null && idxResult.n != null;
20915
+ }
20916
+
20917
+ return fulfilled(idxRes0) ? idxRes0 : fulfilled(idxRes1) ? idxRes1 : null;
20918
+ })();
20919
+
20920
+ if (idxResult) {
20921
+ encode.value = idxResult.v;
20922
+ // `potentialNameDimIndex` has highest priority.
20923
+ var nameDimIndex = potentialNameDimIndex != null ? potentialNameDimIndex : idxResult.n;
20924
+ // By default, label use itemName in charts.
20925
+ // So we dont set encodeLabel here.
20926
+ encode.itemName = [nameDimIndex];
20927
+ encode.seriesName = [nameDimIndex];
20928
+ }
20929
+
20930
+ return encode;
20931
+ }
20932
+
20705
20933
  /**
20706
20934
  * If return null/undefined, indicate that should not use datasetModel.
20707
20935
  */
@@ -20725,7 +20953,7 @@ function getDatasetModel(seriesModel) {
20725
20953
  *
20726
20954
  * @param {module:echars/data/Source} source
20727
20955
  * @param {number} dimIndex
20728
- * @return {boolean} Whether ordinal.
20956
+ * @return {BE_ORDINAL} guess result.
20729
20957
  */
20730
20958
  function guessOrdinal(source, dimIndex) {
20731
20959
  return doGuessOrdinal(
@@ -20739,6 +20967,7 @@ function guessOrdinal(source, dimIndex) {
20739
20967
  }
20740
20968
 
20741
20969
  // dimIndex may be overflow source data.
20970
+ // return {BE_ORDINAL}
20742
20971
  function doGuessOrdinal(
20743
20972
  data, sourceFormat, seriesLayoutBy, dimensionsDefine, startIndex, dimIndex
20744
20973
  ) {
@@ -20747,15 +20976,26 @@ function doGuessOrdinal(
20747
20976
  var maxLoop = 5;
20748
20977
 
20749
20978
  if (isTypedArray(data)) {
20750
- return false;
20979
+ return BE_ORDINAL.Not;
20751
20980
  }
20752
20981
 
20753
20982
  // When sourceType is 'objectRows' or 'keyedColumns', dimensionsDefine
20754
20983
  // always exists in source.
20755
20984
  var dimName;
20985
+ var dimType;
20756
20986
  if (dimensionsDefine) {
20757
- dimName = dimensionsDefine[dimIndex];
20758
- dimName = isObject$1(dimName) ? dimName.name : dimName;
20987
+ var dimDefItem = dimensionsDefine[dimIndex];
20988
+ if (isObject$1(dimDefItem)) {
20989
+ dimName = dimDefItem.name;
20990
+ dimType = dimDefItem.type;
20991
+ }
20992
+ else if (isString(dimDefItem)) {
20993
+ dimName = dimDefItem;
20994
+ }
20995
+ }
20996
+
20997
+ if (dimType != null) {
20998
+ return dimType === 'ordinal' ? BE_ORDINAL.Must : BE_ORDINAL.Not;
20759
20999
  }
20760
21000
 
20761
21001
  if (sourceFormat === SOURCE_FORMAT_ARRAY_ROWS) {
@@ -20778,7 +21018,7 @@ function doGuessOrdinal(
20778
21018
  }
20779
21019
  else if (sourceFormat === SOURCE_FORMAT_OBJECT_ROWS) {
20780
21020
  if (!dimName) {
20781
- return;
21021
+ return BE_ORDINAL.Not;
20782
21022
  }
20783
21023
  for (var i = 0; i < data.length && i < maxLoop; i++) {
20784
21024
  var item = data[i];
@@ -20789,11 +21029,11 @@ function doGuessOrdinal(
20789
21029
  }
20790
21030
  else if (sourceFormat === SOURCE_FORMAT_KEYED_COLUMNS) {
20791
21031
  if (!dimName) {
20792
- return;
21032
+ return BE_ORDINAL.Not;
20793
21033
  }
20794
21034
  var sample = data[dimName];
20795
21035
  if (!sample || isTypedArray(sample)) {
20796
- return false;
21036
+ return BE_ORDINAL.Not;
20797
21037
  }
20798
21038
  for (var i = 0; i < sample.length && i < maxLoop; i++) {
20799
21039
  if ((result = detectValue(sample[i])) != null) {
@@ -20806,7 +21046,7 @@ function doGuessOrdinal(
20806
21046
  var item = data[i];
20807
21047
  var val = getDataItemValue(item);
20808
21048
  if (!isArray(val)) {
20809
- return false;
21049
+ return BE_ORDINAL.Not;
20810
21050
  }
20811
21051
  if ((result = detectValue(val[dimIndex])) != null) {
20812
21052
  return result;
@@ -20815,17 +21055,18 @@ function doGuessOrdinal(
20815
21055
  }
20816
21056
 
20817
21057
  function detectValue(val) {
21058
+ var beStr = isString(val);
20818
21059
  // Consider usage convenience, '1', '2' will be treated as "number".
20819
21060
  // `isFinit('')` get `true`.
20820
21061
  if (val != null && isFinite(val) && val !== '') {
20821
- return false;
21062
+ return beStr ? BE_ORDINAL.Might : BE_ORDINAL.Not;
20822
21063
  }
20823
- else if (isString(val) && val !== '-') {
20824
- return true;
21064
+ else if (beStr && val !== '-') {
21065
+ return BE_ORDINAL.Must;
20825
21066
  }
20826
21067
  }
20827
21068
 
20828
- return false;
21069
+ return BE_ORDINAL.Not;
20829
21070
  }
20830
21071
 
20831
21072
  /*
@@ -23572,11 +23813,11 @@ var SeriesModel = ComponentModel.extend({
23572
23813
  defaultOption: null,
23573
23814
 
23574
23815
  /**
23575
- * Data provided for legend
23576
- * @type {Function}
23816
+ * legend visual provider to the legend component
23817
+ * @type {Object}
23577
23818
  */
23578
23819
  // PENDING
23579
- legendDataProvider: null,
23820
+ legendVisualProvider: null,
23580
23821
 
23581
23822
  /**
23582
23823
  * Access path of color for visual
@@ -24665,25 +24906,30 @@ var seriesColor = {
24665
24906
  reset: function (seriesModel, ecModel) {
24666
24907
  var data = seriesModel.getData();
24667
24908
  var colorAccessPath = (seriesModel.visualColorAccessPath || 'itemStyle.color').split('.');
24668
- var color = seriesModel.get(colorAccessPath) // Set in itemStyle
24669
- || seriesModel.getColorFromPalette(
24909
+ // Set in itemStyle
24910
+ var color = seriesModel.get(colorAccessPath);
24911
+ var colorCallback = (isFunction$1(color) && !(color instanceof Gradient))
24912
+ ? color : null;
24913
+ // Default color
24914
+ if (!color || colorCallback) {
24915
+ color = seriesModel.getColorFromPalette(
24670
24916
  // TODO series count changed.
24671
24917
  seriesModel.name, null, ecModel.getSeriesCount()
24672
- ); // Default color
24918
+ );
24919
+ }
24673
24920
 
24674
- // FIXME Set color function or use the platte color
24675
24921
  data.setVisual('color', color);
24676
-
24922
+
24677
24923
  var borderColorAccessPath = (seriesModel.visualBorderColorAccessPath || 'itemStyle.borderColor').split('.');
24678
24924
  var borderColor = seriesModel.get(borderColorAccessPath);
24679
24925
  data.setVisual('borderColor', borderColor);
24680
24926
 
24681
24927
  // Only visible series has each data be visual encoded
24682
24928
  if (!ecModel.isSeriesFiltered(seriesModel)) {
24683
- if (typeof color === 'function' && !(color instanceof Gradient)) {
24929
+ if (colorCallback) {
24684
24930
  data.each(function (idx) {
24685
24931
  data.setItemVisual(
24686
- idx, 'color', color(seriesModel.getDataParams(idx))
24932
+ idx, 'color', colorCallback(seriesModel.getDataParams(idx))
24687
24933
  );
24688
24934
  });
24689
24935
  }
@@ -25742,6 +25988,9 @@ var theme = {
25742
25988
  },
25743
25989
  crossStyle: {
25744
25990
  color: contrastColor
25991
+ },
25992
+ label: {
25993
+ color: '#000'
25745
25994
  }
25746
25995
  }
25747
25996
  },
@@ -26712,10 +26961,10 @@ var isFunction = isFunction$1;
26712
26961
  var isObject = isObject$1;
26713
26962
  var parseClassType = ComponentModel.parseClassType;
26714
26963
 
26715
- var version = '4.5.0';
26964
+ var version = '4.6.0';
26716
26965
 
26717
26966
  var dependencies = {
26718
- zrender: '4.1.2'
26967
+ zrender: '4.2.0'
26719
26968
  };
26720
26969
 
26721
26970
  var TEST_FRAME_REMAIN_TIME = 1;
@@ -29422,6 +29671,138 @@ function mayLabelDimType(dimType) {
29422
29671
  * under the License.
29423
29672
  */
29424
29673
 
29674
+ /**
29675
+ * @class
29676
+ * @param {Object|DataDimensionInfo} [opt] All of the fields will be shallow copied.
29677
+ */
29678
+ function DataDimensionInfo(opt) {
29679
+ if (opt != null) {
29680
+ extend(this, opt);
29681
+ }
29682
+
29683
+ /**
29684
+ * Dimension name.
29685
+ * Mandatory.
29686
+ * @type {string}
29687
+ */
29688
+ // this.name;
29689
+
29690
+ /**
29691
+ * The origin name in dimsDef, see source helper.
29692
+ * If displayName given, the tooltip will displayed vertically.
29693
+ * Optional.
29694
+ * @type {string}
29695
+ */
29696
+ // this.displayName;
29697
+
29698
+ /**
29699
+ * Which coordSys dimension this dimension mapped to.
29700
+ * A `coordDim` can be a "coordSysDim" that the coordSys required
29701
+ * (for example, an item in `coordSysDims` of `model/referHelper#CoordSysInfo`),
29702
+ * or an generated "extra coord name" if does not mapped to any "coordSysDim"
29703
+ * (That is determined by whether `isExtraCoord` is `true`).
29704
+ * Mandatory.
29705
+ * @type {string}
29706
+ */
29707
+ // this.coordDim;
29708
+
29709
+ /**
29710
+ * The index of this dimension in `series.encode[coordDim]`.
29711
+ * Mandatory.
29712
+ * @type {number}
29713
+ */
29714
+ // this.coordDimIndex;
29715
+
29716
+ /**
29717
+ * Dimension type. The enumerable values are the key of
29718
+ * `dataCtors` of `data/List`.
29719
+ * Optional.
29720
+ * @type {string}
29721
+ */
29722
+ // this.type;
29723
+
29724
+ /**
29725
+ * This index of this dimension info in `data/List#_dimensionInfos`.
29726
+ * Mandatory after added to `data/List`.
29727
+ * @type {number}
29728
+ */
29729
+ // this.index;
29730
+
29731
+ /**
29732
+ * The format of `otherDims` is:
29733
+ * ```js
29734
+ * {
29735
+ * tooltip: number optional,
29736
+ * label: number optional,
29737
+ * itemName: number optional,
29738
+ * seriesName: number optional,
29739
+ * }
29740
+ * ```
29741
+ *
29742
+ * A `series.encode` can specified these fields:
29743
+ * ```js
29744
+ * encode: {
29745
+ * // "3, 1, 5" is the index of data dimension.
29746
+ * tooltip: [3, 1, 5],
29747
+ * label: [0, 3],
29748
+ * ...
29749
+ * }
29750
+ * ```
29751
+ * `otherDims` is the parse result of the `series.encode` above, like:
29752
+ * ```js
29753
+ * // Suppose the index of this data dimension is `3`.
29754
+ * this.otherDims = {
29755
+ * // `3` is at the index `0` of the `encode.tooltip`
29756
+ * tooltip: 0,
29757
+ * // `3` is at the index `1` of the `encode.tooltip`
29758
+ * label: 1
29759
+ * };
29760
+ * ```
29761
+ *
29762
+ * This prop should never be `null`/`undefined` after initialized.
29763
+ * @type {Object}
29764
+ */
29765
+ this.otherDims = {};
29766
+
29767
+ /**
29768
+ * Be `true` if this dimension is not mapped to any "coordSysDim" that the
29769
+ * "coordSys" required.
29770
+ * Mandatory.
29771
+ * @type {boolean}
29772
+ */
29773
+ // this.isExtraCoord;
29774
+
29775
+ /**
29776
+ * @type {module:data/OrdinalMeta}
29777
+ */
29778
+ // this.ordinalMeta;
29779
+
29780
+ /**
29781
+ * Whether to create inverted indices.
29782
+ * @type {boolean}
29783
+ */
29784
+ // this.createInvertedIndices;
29785
+ }
29786
+
29787
+ /*
29788
+ * Licensed to the Apache Software Foundation (ASF) under one
29789
+ * or more contributor license agreements. See the NOTICE file
29790
+ * distributed with this work for additional information
29791
+ * regarding copyright ownership. The ASF licenses this file
29792
+ * to you under the Apache License, Version 2.0 (the
29793
+ * "License"); you may not use this file except in compliance
29794
+ * with the License. You may obtain a copy of the License at
29795
+ *
29796
+ * http://www.apache.org/licenses/LICENSE-2.0
29797
+ *
29798
+ * Unless required by applicable law or agreed to in writing,
29799
+ * software distributed under the License is distributed on an
29800
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
29801
+ * KIND, either express or implied. See the License for the
29802
+ * specific language governing permissions and limitations
29803
+ * under the License.
29804
+ */
29805
+
29425
29806
  /* global Float64Array, Int32Array, Uint32Array, Uint16Array */
29426
29807
 
29427
29808
  /**
@@ -29499,13 +29880,9 @@ function transferProperties(target, source) {
29499
29880
  * @constructor
29500
29881
  * @alias module:echarts/data/List
29501
29882
  *
29502
- * @param {Array.<string|Object>} dimensions
29883
+ * @param {Array.<string|Object|module:data/DataDimensionInfo>} dimensions
29503
29884
  * For example, ['someDimName', {name: 'someDimName', type: 'someDimType'}, ...].
29504
29885
  * Dimensions should be concrete names like x, y, z, lng, lat, angle, radius
29505
- * Spetial fields: {
29506
- * ordinalMeta: <module:echarts/data/OrdinalMeta>
29507
- * createInvertedIndices: <boolean>
29508
- * }
29509
29886
  * @param {module:echarts/model/Model} hostModel
29510
29887
  */
29511
29888
  var List = function (dimensions, hostModel) {
@@ -29521,7 +29898,10 @@ var List = function (dimensions, hostModel) {
29521
29898
  var dimensionInfo = dimensions[i];
29522
29899
 
29523
29900
  if (isString(dimensionInfo)) {
29524
- dimensionInfo = {name: dimensionInfo};
29901
+ dimensionInfo = new DataDimensionInfo({name: dimensionInfo});
29902
+ }
29903
+ else if (!(dimensionInfo instanceof DataDimensionInfo)) {
29904
+ dimensionInfo = new DataDimensionInfo(dimensionInfo);
29525
29905
  }
29526
29906
 
29527
29907
  var dimensionName = dimensionInfo.name;
@@ -30541,7 +30921,8 @@ listProto.indexOfRawIndex = function (rawIndex) {
30541
30921
  * @param {string} dim
30542
30922
  * @param {number} value
30543
30923
  * @param {number} [maxDistance=Infinity]
30544
- * @return {Array.<number>} Considere multiple points has the same value.
30924
+ * @return {Array.<number>} If and only if multiple indices has
30925
+ * the same value, they are put to the result.
30545
30926
  */
30546
30927
  listProto.indicesOfNearest = function (dim, value, maxDistance) {
30547
30928
  var storage = this._storage;
@@ -30556,23 +30937,35 @@ listProto.indicesOfNearest = function (dim, value, maxDistance) {
30556
30937
  maxDistance = Infinity;
30557
30938
  }
30558
30939
 
30559
- var minDist = Number.MAX_VALUE;
30940
+ var minDist = Infinity;
30560
30941
  var minDiff = -1;
30942
+ var nearestIndicesLen = 0;
30943
+
30944
+ // Check the test case of `test/ut/spec/data/List.js`.
30561
30945
  for (var i = 0, len = this.count(); i < len; i++) {
30562
- var diff = value - this.get(dim, i /*, stack */);
30946
+ var diff = value - this.get(dim, i);
30563
30947
  var dist = Math.abs(diff);
30564
- if (diff <= maxDistance && dist <= minDist) {
30565
- // For the case of two data are same on xAxis, which has sequence data.
30566
- // Show the nearest index
30567
- // https://github.com/ecomfe/echarts/issues/2869
30568
- if (dist < minDist || (diff >= 0 && minDiff < 0)) {
30948
+ if (dist <= maxDistance) {
30949
+ // When the `value` is at the middle of `this.get(dim, i)` and `this.get(dim, i+1)`,
30950
+ // we'd better not push both of them to `nearestIndices`, otherwise it is easy to
30951
+ // get more than one item in `nearestIndices` (more specifically, in `tooltip`).
30952
+ // So we chose the one that `diff >= 0` in this csae.
30953
+ // But if `this.get(dim, i)` and `this.get(dim, j)` get the same value, both of them
30954
+ // should be push to `nearestIndices`.
30955
+ if (dist < minDist
30956
+ || (dist === minDist && diff >= 0 && minDiff < 0)
30957
+ ) {
30569
30958
  minDist = dist;
30570
30959
  minDiff = diff;
30571
- nearestIndices.length = 0;
30960
+ nearestIndicesLen = 0;
30961
+ }
30962
+ if (diff === minDiff) {
30963
+ nearestIndices[nearestIndicesLen++] = i;
30572
30964
  }
30573
- nearestIndices.push(i);
30574
30965
  }
30575
30966
  }
30967
+ nearestIndices.length = nearestIndicesLen;
30968
+
30576
30969
  return nearestIndices;
30577
30970
  };
30578
30971
 
@@ -31446,8 +31839,12 @@ listProto.CHANGABLE_METHODS = ['filterSelf', 'selectRange'];
31446
31839
  /**
31447
31840
  * @see {module:echarts/test/ut/spec/data/completeDimensions}
31448
31841
  *
31449
- * Complete the dimensions array, by user defined `dimension` and `encode`,
31450
- * and guessing from the data structure.
31842
+ * This method builds the relationship between:
31843
+ * + "what the coord sys or series requires (see `sysDims`)",
31844
+ * + "what the user defines (in `encode` and `dimensions`, see `opt.dimsDef` and `opt.encodeDef`)"
31845
+ * + "what the data source provids (see `source`)".
31846
+ *
31847
+ * Some guess strategy will be adapted if user does not define something.
31451
31848
  * If no 'value' dimension specified, the first no-named dimension will be
31452
31849
  * named as 'value'.
31453
31850
  *
@@ -31463,32 +31860,20 @@ listProto.CHANGABLE_METHODS = ['filterSelf', 'selectRange'];
31463
31860
  * @param {Array.<Object|string>} [opt.dimsDef] option.series.dimensions User defined dimensions
31464
31861
  * For example: ['asdf', {name, type}, ...].
31465
31862
  * @param {Object|HashMap} [opt.encodeDef] option.series.encode {x: 2, y: [3, 1], tooltip: [1, 2], label: 3}
31863
+ * @param {Function} [opt.encodeDefaulter] Called if no `opt.encodeDef` exists.
31864
+ * If not specified, auto find the next available data dim.
31865
+ * param source {module:data/Source}
31866
+ * param dimCount {number}
31867
+ * return {Object} encode Never be `null/undefined`.
31466
31868
  * @param {string} [opt.generateCoord] Generate coord dim with the given name.
31467
- * If not specified, extra dim names will be:
31468
- * 'value', 'value0', 'value1', ...
31869
+ * If not specified, extra dim names will be:
31870
+ * 'value', 'value0', 'value1', ...
31469
31871
  * @param {number} [opt.generateCoordCount] By default, the generated dim name is `generateCoord`.
31470
- * If `generateCoordCount` specified, the generated dim names will be:
31471
- * `generateCoord` + 0, `generateCoord` + 1, ...
31472
- * can be Infinity, indicate that use all of the remain columns.
31872
+ * If `generateCoordCount` specified, the generated dim names will be:
31873
+ * `generateCoord` + 0, `generateCoord` + 1, ...
31874
+ * can be Infinity, indicate that use all of the remain columns.
31473
31875
  * @param {number} [opt.dimCount] If not specified, guess by the first data item.
31474
- * @param {number} [opt.encodeDefaulter] If not specified, auto find the next available data dim.
31475
- * @return {Array.<Object>} [{
31476
- * name: string mandatory,
31477
- * displayName: string, the origin name in dimsDef, see source helper.
31478
- * If displayName given, the tooltip will displayed vertically.
31479
- * coordDim: string mandatory,
31480
- * coordDimIndex: number mandatory,
31481
- * type: string optional,
31482
- * otherDims: { never null/undefined
31483
- * tooltip: number optional,
31484
- * label: number optional,
31485
- * itemName: number optional,
31486
- * seriesName: number optional,
31487
- * },
31488
- * isExtraCoord: boolean true if coord is generated
31489
- * (not specified in encode and not series specified)
31490
- * other props ...
31491
- * }]
31876
+ * @return {Array.<module:data/DataDimensionInfo>}
31492
31877
  */
31493
31878
  function completeDimensions(sysDims, source, opt) {
31494
31879
  if (!Source.isInstance(source)) {
@@ -31498,7 +31883,6 @@ function completeDimensions(sysDims, source, opt) {
31498
31883
  opt = opt || {};
31499
31884
  sysDims = (sysDims || []).slice();
31500
31885
  var dimsDef = (opt.dimsDef || []).slice();
31501
- var encodeDef = createHashMap(opt.encodeDef);
31502
31886
  var dataDimNameMap = createHashMap();
31503
31887
  var coordDimNameMap = createHashMap();
31504
31888
  // var valueCandidate;
@@ -31512,7 +31896,7 @@ function completeDimensions(sysDims, source, opt) {
31512
31896
  {}, isObject$1(dimsDef[i]) ? dimsDef[i] : {name: dimsDef[i]}
31513
31897
  );
31514
31898
  var userDimName = dimDefItem.name;
31515
- var resultItem = result[i] = {otherDims: {}};
31899
+ var resultItem = result[i] = new DataDimensionInfo();
31516
31900
  // Name will be applied later for avoiding duplication.
31517
31901
  if (userDimName != null && dataDimNameMap.get(userDimName) == null) {
31518
31902
  // Only if `series.dimensions` is defined in option
@@ -31525,6 +31909,12 @@ function completeDimensions(sysDims, source, opt) {
31525
31909
  dimDefItem.displayName != null && (resultItem.displayName = dimDefItem.displayName);
31526
31910
  }
31527
31911
 
31912
+ var encodeDef = opt.encodeDef;
31913
+ if (!encodeDef && opt.encodeDefaulter) {
31914
+ encodeDef = opt.encodeDefaulter(source, dimCount);
31915
+ }
31916
+ encodeDef = createHashMap(encodeDef);
31917
+
31528
31918
  // Set `coordDim` and `coordDimIndex` by `encodeDef` and normalize `encodeDef`.
31529
31919
  encodeDef.each(function (dataDims, coordDim) {
31530
31920
  dataDims = normalizeToArray(dataDims).slice();
@@ -31626,7 +32016,7 @@ function completeDimensions(sysDims, source, opt) {
31626
32016
 
31627
32017
  // Set dim `name` and other `coordDim` and other props.
31628
32018
  for (var resultDimIdx = 0; resultDimIdx < dimCount; resultDimIdx++) {
31629
- var resultItem = result[resultDimIdx] = result[resultDimIdx] || {};
32019
+ var resultItem = result[resultDimIdx] = result[resultDimIdx] || new DataDimensionInfo();
31630
32020
  var coordDim = resultItem.coordDim;
31631
32021
 
31632
32022
  if (coordDim == null) {
@@ -31645,7 +32035,28 @@ function completeDimensions(sysDims, source, opt) {
31645
32035
  dataDimNameMap
31646
32036
  ));
31647
32037
 
31648
- if (resultItem.type == null && guessOrdinal(source, resultDimIdx, resultItem.name)) {
32038
+ if (resultItem.type == null
32039
+ && (
32040
+ guessOrdinal(source, resultDimIdx, resultItem.name) === BE_ORDINAL.Must
32041
+ // Consider the case:
32042
+ // {
32043
+ // dataset: {source: [
32044
+ // ['2001', 123],
32045
+ // ['2002', 456],
32046
+ // ...
32047
+ // ['The others', 987],
32048
+ // ]},
32049
+ // series: {type: 'pie'}
32050
+ // }
32051
+ // The first colum should better be treated as a "ordinal" although it
32052
+ // might not able to be detected as an "ordinal" by `guessOrdinal`.
32053
+ || (resultItem.isExtraCoord
32054
+ && (resultItem.otherDims.itemName != null
32055
+ || resultItem.otherDims.seriesName != null
32056
+ )
32057
+ )
32058
+ )
32059
+ ) {
31649
32060
  resultItem.type = 'ordinal';
31650
32061
  }
31651
32062
  }
@@ -31723,6 +32134,7 @@ function genName(name, map$$1, fromZero) {
31723
32134
  * @param {string} [opt.generateCoordCount]
31724
32135
  * @param {Array.<string|Object>} [opt.dimensionsDefine=source.dimensionsDefine] Overwrite source define.
31725
32136
  * @param {Object|HashMap} [opt.encodeDefine=source.encodeDefine] Overwrite source define.
32137
+ * @param {Function} [opt.encodeDefaulter] Make default encode if user not specified.
31726
32138
  * @return {Array.<Object>} dimensionsInfo
31727
32139
  */
31728
32140
  var createDimensions = function (source, opt) {
@@ -31731,6 +32143,7 @@ var createDimensions = function (source, opt) {
31731
32143
  dimsDef: opt.dimensionsDefine || source.dimensionsDefine,
31732
32144
  encodeDef: opt.encodeDefine || source.encodeDefine,
31733
32145
  dimCount: opt.dimensionsCount,
32146
+ encodeDefaulter: opt.encodeDefaulter,
31734
32147
  generateCoord: opt.generateCoord,
31735
32148
  generateCoordCount: opt.generateCoordCount
31736
32149
  });
@@ -31755,6 +32168,201 @@ var createDimensions = function (source, opt) {
31755
32168
  * under the License.
31756
32169
  */
31757
32170
 
32171
+ /**
32172
+ * Helper for model references.
32173
+ * There are many manners to refer axis/coordSys.
32174
+ */
32175
+
32176
+ // TODO
32177
+ // merge relevant logic to this file?
32178
+ // check: "modelHelper" of tooltip and "BrushTargetManager".
32179
+
32180
+ /**
32181
+ * @class
32182
+ * For example:
32183
+ * {
32184
+ * coordSysName: 'cartesian2d',
32185
+ * coordSysDims: ['x', 'y', ...],
32186
+ * axisMap: HashMap({
32187
+ * x: xAxisModel,
32188
+ * y: yAxisModel
32189
+ * }),
32190
+ * categoryAxisMap: HashMap({
32191
+ * x: xAxisModel,
32192
+ * y: undefined
32193
+ * }),
32194
+ * // The index of the first category axis in `coordSysDims`.
32195
+ * // `null/undefined` means no category axis exists.
32196
+ * firstCategoryDimIndex: 1,
32197
+ * // To replace user specified encode.
32198
+ * }
32199
+ */
32200
+ function CoordSysInfo(coordSysName) {
32201
+ /**
32202
+ * @type {string}
32203
+ */
32204
+ this.coordSysName = coordSysName;
32205
+ /**
32206
+ * @type {Array.<string>}
32207
+ */
32208
+ this.coordSysDims = [];
32209
+ /**
32210
+ * @type {module:zrender/core/util#HashMap}
32211
+ */
32212
+ this.axisMap = createHashMap();
32213
+ /**
32214
+ * @type {module:zrender/core/util#HashMap}
32215
+ */
32216
+ this.categoryAxisMap = createHashMap();
32217
+ /**
32218
+ * @type {number}
32219
+ */
32220
+ this.firstCategoryDimIndex = null;
32221
+ }
32222
+
32223
+ /**
32224
+ * @return {module:model/referHelper#CoordSysInfo}
32225
+ */
32226
+ function getCoordSysInfoBySeries(seriesModel) {
32227
+ var coordSysName = seriesModel.get('coordinateSystem');
32228
+ var result = new CoordSysInfo(coordSysName);
32229
+ var fetch = fetchers[coordSysName];
32230
+ if (fetch) {
32231
+ fetch(seriesModel, result, result.axisMap, result.categoryAxisMap);
32232
+ return result;
32233
+ }
32234
+ }
32235
+
32236
+ var fetchers = {
32237
+
32238
+ cartesian2d: function (seriesModel, result, axisMap, categoryAxisMap) {
32239
+ var xAxisModel = seriesModel.getReferringComponents('xAxis')[0];
32240
+ var yAxisModel = seriesModel.getReferringComponents('yAxis')[0];
32241
+
32242
+ if (__DEV__) {
32243
+ if (!xAxisModel) {
32244
+ throw new Error('xAxis "' + retrieve(
32245
+ seriesModel.get('xAxisIndex'),
32246
+ seriesModel.get('xAxisId'),
32247
+ 0
32248
+ ) + '" not found');
32249
+ }
32250
+ if (!yAxisModel) {
32251
+ throw new Error('yAxis "' + retrieve(
32252
+ seriesModel.get('xAxisIndex'),
32253
+ seriesModel.get('yAxisId'),
32254
+ 0
32255
+ ) + '" not found');
32256
+ }
32257
+ }
32258
+
32259
+ result.coordSysDims = ['x', 'y'];
32260
+ axisMap.set('x', xAxisModel);
32261
+ axisMap.set('y', yAxisModel);
32262
+
32263
+ if (isCategory(xAxisModel)) {
32264
+ categoryAxisMap.set('x', xAxisModel);
32265
+ result.firstCategoryDimIndex = 0;
32266
+ }
32267
+ if (isCategory(yAxisModel)) {
32268
+ categoryAxisMap.set('y', yAxisModel);
32269
+ result.firstCategoryDimIndex == null & (result.firstCategoryDimIndex = 1);
32270
+ }
32271
+ },
32272
+
32273
+ singleAxis: function (seriesModel, result, axisMap, categoryAxisMap) {
32274
+ var singleAxisModel = seriesModel.getReferringComponents('singleAxis')[0];
32275
+
32276
+ if (__DEV__) {
32277
+ if (!singleAxisModel) {
32278
+ throw new Error('singleAxis should be specified.');
32279
+ }
32280
+ }
32281
+
32282
+ result.coordSysDims = ['single'];
32283
+ axisMap.set('single', singleAxisModel);
32284
+
32285
+ if (isCategory(singleAxisModel)) {
32286
+ categoryAxisMap.set('single', singleAxisModel);
32287
+ result.firstCategoryDimIndex = 0;
32288
+ }
32289
+ },
32290
+
32291
+ polar: function (seriesModel, result, axisMap, categoryAxisMap) {
32292
+ var polarModel = seriesModel.getReferringComponents('polar')[0];
32293
+ var radiusAxisModel = polarModel.findAxisModel('radiusAxis');
32294
+ var angleAxisModel = polarModel.findAxisModel('angleAxis');
32295
+
32296
+ if (__DEV__) {
32297
+ if (!angleAxisModel) {
32298
+ throw new Error('angleAxis option not found');
32299
+ }
32300
+ if (!radiusAxisModel) {
32301
+ throw new Error('radiusAxis option not found');
32302
+ }
32303
+ }
32304
+
32305
+ result.coordSysDims = ['radius', 'angle'];
32306
+ axisMap.set('radius', radiusAxisModel);
32307
+ axisMap.set('angle', angleAxisModel);
32308
+
32309
+ if (isCategory(radiusAxisModel)) {
32310
+ categoryAxisMap.set('radius', radiusAxisModel);
32311
+ result.firstCategoryDimIndex = 0;
32312
+ }
32313
+ if (isCategory(angleAxisModel)) {
32314
+ categoryAxisMap.set('angle', angleAxisModel);
32315
+ result.firstCategoryDimIndex == null && (result.firstCategoryDimIndex = 1);
32316
+ }
32317
+ },
32318
+
32319
+ geo: function (seriesModel, result, axisMap, categoryAxisMap) {
32320
+ result.coordSysDims = ['lng', 'lat'];
32321
+ },
32322
+
32323
+ parallel: function (seriesModel, result, axisMap, categoryAxisMap) {
32324
+ var ecModel = seriesModel.ecModel;
32325
+ var parallelModel = ecModel.getComponent(
32326
+ 'parallel', seriesModel.get('parallelIndex')
32327
+ );
32328
+ var coordSysDims = result.coordSysDims = parallelModel.dimensions.slice();
32329
+
32330
+ each$1(parallelModel.parallelAxisIndex, function (axisIndex, index) {
32331
+ var axisModel = ecModel.getComponent('parallelAxis', axisIndex);
32332
+ var axisDim = coordSysDims[index];
32333
+ axisMap.set(axisDim, axisModel);
32334
+
32335
+ if (isCategory(axisModel) && result.firstCategoryDimIndex == null) {
32336
+ categoryAxisMap.set(axisDim, axisModel);
32337
+ result.firstCategoryDimIndex = index;
32338
+ }
32339
+ });
32340
+ }
32341
+ };
32342
+
32343
+ function isCategory(axisModel) {
32344
+ return axisModel.get('type') === 'category';
32345
+ }
32346
+
32347
+ /*
32348
+ * Licensed to the Apache Software Foundation (ASF) under one
32349
+ * or more contributor license agreements. See the NOTICE file
32350
+ * distributed with this work for additional information
32351
+ * regarding copyright ownership. The ASF licenses this file
32352
+ * to you under the Apache License, Version 2.0 (the
32353
+ * "License"); you may not use this file except in compliance
32354
+ * with the License. You may obtain a copy of the License at
32355
+ *
32356
+ * http://www.apache.org/licenses/LICENSE-2.0
32357
+ *
32358
+ * Unless required by applicable law or agreed to in writing,
32359
+ * software distributed under the License is distributed on an
32360
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
32361
+ * KIND, either express or implied. See the License for the
32362
+ * specific language governing permissions and limitations
32363
+ * under the License.
32364
+ */
32365
+
31758
32366
  /**
31759
32367
  * Note that it is too complicated to support 3d stack by value
31760
32368
  * (have to create two-dimension inverted index), so in 3d case
@@ -31921,6 +32529,7 @@ function getStackedDimension(data, targetDim) {
31921
32529
  * @param {module:echarts/model/Series} seriesModel
31922
32530
  * @param {Object} [opt]
31923
32531
  * @param {string} [opt.generateCoord]
32532
+ * @param {boolean} [opt.useEncodeDefaulter]
31924
32533
  */
31925
32534
  function createListFromArray(source, seriesModel, opt) {
31926
32535
  opt = opt || {};
@@ -31932,14 +32541,14 @@ function createListFromArray(source, seriesModel, opt) {
31932
32541
  var coordSysName = seriesModel.get('coordinateSystem');
31933
32542
  var registeredCoordSys = CoordinateSystemManager.get(coordSysName);
31934
32543
 
31935
- var coordSysDefine = getCoordSysDefineBySeries(seriesModel);
32544
+ var coordSysInfo = getCoordSysInfoBySeries(seriesModel);
31936
32545
 
31937
32546
  var coordSysDimDefs;
31938
32547
 
31939
- if (coordSysDefine) {
31940
- coordSysDimDefs = map(coordSysDefine.coordSysDims, function (dim) {
32548
+ if (coordSysInfo) {
32549
+ coordSysDimDefs = map(coordSysInfo.coordSysDims, function (dim) {
31941
32550
  var dimInfo = {name: dim};
31942
- var axisModel = coordSysDefine.axisMap.get(dim);
32551
+ var axisModel = coordSysInfo.axisMap.get(dim);
31943
32552
  if (axisModel) {
31944
32553
  var axisType = axisModel.get('type');
31945
32554
  dimInfo.type = getDimensionTypeByAxis(axisType);
@@ -31960,14 +32569,17 @@ function createListFromArray(source, seriesModel, opt) {
31960
32569
 
31961
32570
  var dimInfoList = createDimensions(source, {
31962
32571
  coordDimensions: coordSysDimDefs,
31963
- generateCoord: opt.generateCoord
32572
+ generateCoord: opt.generateCoord,
32573
+ encodeDefaulter: opt.useEncodeDefaulter
32574
+ ? curry(makeSeriesEncodeForAxisCoordSys, coordSysDimDefs, seriesModel)
32575
+ : null
31964
32576
  });
31965
32577
 
31966
32578
  var firstCategoryDimIndex;
31967
32579
  var hasNameEncode;
31968
- coordSysDefine && each$1(dimInfoList, function (dimInfo, dimIndex) {
32580
+ coordSysInfo && each$1(dimInfoList, function (dimInfo, dimIndex) {
31969
32581
  var coordDim = dimInfo.coordDim;
31970
- var categoryAxisModel = coordSysDefine.categoryAxisMap.get(coordDim);
32582
+ var categoryAxisModel = coordSysInfo.categoryAxisMap.get(coordDim);
31971
32583
  if (categoryAxisModel) {
31972
32584
  if (firstCategoryDimIndex == null) {
31973
32585
  firstCategoryDimIndex = dimIndex;
@@ -32051,7 +32663,7 @@ SeriesModel.extend({
32051
32663
  throw new Error('Line not support coordinateSystem besides cartesian and polar');
32052
32664
  }
32053
32665
  }
32054
- return createListFromArray(this.getSource(), this);
32666
+ return createListFromArray(this.getSource(), this, {useEncodeDefaulter: true});
32055
32667
  },
32056
32668
 
32057
32669
  defaultOption: {
@@ -34265,7 +34877,7 @@ Chart.extend({
34265
34877
  // FIXME step not support polar
34266
34878
  var step = !isCoordSysPolar && seriesModel.get('step');
34267
34879
  var clipShapeForSymbol;
34268
- if (coordSys && coordSys.getArea) {
34880
+ if (coordSys && coordSys.getArea && seriesModel.get('clip', true)) {
34269
34881
  clipShapeForSymbol = coordSys.getArea();
34270
34882
  // Avoid float number rounding error for symbol on the edge of axis extent.
34271
34883
  // See #7913 and `test/dataZoom-clip.html`.
@@ -34280,6 +34892,7 @@ Chart.extend({
34280
34892
  clipShapeForSymbol.r1 += 0.5;
34281
34893
  }
34282
34894
  }
34895
+ this._clipShapeForSymbol = clipShapeForSymbol;
34283
34896
  // Initialization animation or coordinate system changed
34284
34897
  if (
34285
34898
  !(polyline && prevCoordSys.type === coordSys.type && step === this._step)
@@ -34432,6 +35045,10 @@ Chart.extend({
34432
35045
  // Null data
34433
35046
  return;
34434
35047
  }
35048
+ // fix #11360: should't draw symbol outside clipShapeForSymbol
35049
+ if (this._clipShapeForSymbol && !this._clipShapeForSymbol.contain(pt[0], pt[1])) {
35050
+ return;
35051
+ }
34435
35052
  symbol = new SymbolClz(data, dataIndex);
34436
35053
  symbol.position = pt;
34437
35054
  symbol.setZ(
@@ -35437,44 +36054,6 @@ function fixExtent(niceTickExtent, extent) {
35437
36054
  }
35438
36055
  }
35439
36056
 
35440
- function intervalScaleGetTicks(interval, extent, niceTickExtent, intervalPrecision) {
35441
- var ticks = [];
35442
-
35443
- // If interval is 0, return [];
35444
- if (!interval) {
35445
- return ticks;
35446
- }
35447
-
35448
- // Consider this case: using dataZoom toolbox, zoom and zoom.
35449
- var safeLimit = 10000;
35450
-
35451
- if (extent[0] < niceTickExtent[0]) {
35452
- ticks.push(extent[0]);
35453
- }
35454
- var tick = niceTickExtent[0];
35455
-
35456
- while (tick <= niceTickExtent[1]) {
35457
- ticks.push(tick);
35458
- // Avoid rounding error
35459
- tick = roundNumber$1(tick + interval, intervalPrecision);
35460
- if (tick === ticks[ticks.length - 1]) {
35461
- // Consider out of safe float point, e.g.,
35462
- // -3711126.9907707 + 2e-10 === -3711126.9907707
35463
- break;
35464
- }
35465
- if (ticks.length > safeLimit) {
35466
- return [];
35467
- }
35468
- }
35469
- // Consider this case: the last item of ticks is smaller
35470
- // than niceTickExtent[1] and niceTickExtent[1] === extent[1].
35471
- if (extent[1] > (ticks.length ? ticks[ticks.length - 1] : niceTickExtent[1])) {
35472
- ticks.push(extent[1]);
35473
- }
35474
-
35475
- return ticks;
35476
- }
35477
-
35478
36057
  /*
35479
36058
  * Licensed to the Apache Software Foundation (ASF) under one
35480
36059
  * or more contributor license agreements. See the NOTICE file
@@ -35553,12 +36132,92 @@ var IntervalScale = Scale.extend({
35553
36132
  },
35554
36133
 
35555
36134
  /**
36135
+ * @param {boolean} [expandToNicedExtent=false] If expand the ticks to niced extent.
35556
36136
  * @return {Array.<number>}
35557
36137
  */
35558
- getTicks: function () {
35559
- return intervalScaleGetTicks(
35560
- this._interval, this._extent, this._niceExtent, this._intervalPrecision
35561
- );
36138
+ getTicks: function (expandToNicedExtent) {
36139
+ var interval = this._interval;
36140
+ var extent = this._extent;
36141
+ var niceTickExtent = this._niceExtent;
36142
+ var intervalPrecision = this._intervalPrecision;
36143
+
36144
+ var ticks = [];
36145
+ // If interval is 0, return [];
36146
+ if (!interval) {
36147
+ return ticks;
36148
+ }
36149
+
36150
+ // Consider this case: using dataZoom toolbox, zoom and zoom.
36151
+ var safeLimit = 10000;
36152
+
36153
+ if (extent[0] < niceTickExtent[0]) {
36154
+ if (expandToNicedExtent) {
36155
+ ticks.push(roundNumber(niceTickExtent[0] - interval));
36156
+ }
36157
+ else {
36158
+ ticks.push(extent[0]);
36159
+ }
36160
+ }
36161
+ var tick = niceTickExtent[0];
36162
+
36163
+ while (tick <= niceTickExtent[1]) {
36164
+ ticks.push(tick);
36165
+ // Avoid rounding error
36166
+ tick = roundNumber(tick + interval, intervalPrecision);
36167
+ if (tick === ticks[ticks.length - 1]) {
36168
+ // Consider out of safe float point, e.g.,
36169
+ // -3711126.9907707 + 2e-10 === -3711126.9907707
36170
+ break;
36171
+ }
36172
+ if (ticks.length > safeLimit) {
36173
+ return [];
36174
+ }
36175
+ }
36176
+ // Consider this case: the last item of ticks is smaller
36177
+ // than niceTickExtent[1] and niceTickExtent[1] === extent[1].
36178
+ var lastNiceTick = ticks.length ? ticks[ticks.length - 1] : niceTickExtent[1];
36179
+ if (extent[1] > lastNiceTick) {
36180
+ if (expandToNicedExtent) {
36181
+ ticks.push(lastNiceTick + interval);
36182
+ }
36183
+ else {
36184
+ ticks.push(extent[1]);
36185
+ }
36186
+ }
36187
+
36188
+ return ticks;
36189
+ },
36190
+
36191
+ /**
36192
+ * @param {number} [splitNumber=5]
36193
+ * @return {Array.<Array.<number>>}
36194
+ */
36195
+ getMinorTicks: function (splitNumber) {
36196
+ var ticks = this.getTicks(true);
36197
+ var minorTicks = [];
36198
+ var extent = this.getExtent();
36199
+
36200
+ for (var i = 1; i < ticks.length; i++) {
36201
+ var nextTick = ticks[i];
36202
+ var prevTick = ticks[i - 1];
36203
+ var count = 0;
36204
+ var minorTicksGroup = [];
36205
+ var interval = nextTick - prevTick;
36206
+ var minorInterval = interval / splitNumber;
36207
+
36208
+ while (count < splitNumber - 1) {
36209
+ var minorTick = round$1(prevTick + (count + 1) * minorInterval);
36210
+
36211
+ // For the first and last interval. The count may be less than splitNumber.
36212
+ if (minorTick > extent[0] && minorTick < extent[1]) {
36213
+ minorTicksGroup.push(minorTick);
36214
+ }
36215
+ count++;
36216
+ }
36217
+ minorTicks.push(minorTicksGroup);
36218
+ }
36219
+
36220
+ return minorTicks;
35562
36221
  },
35563
36222
 
35564
36223
  /**
@@ -35897,7 +36556,6 @@ function doCalBarWidthAndOffset(seriesInfoList) {
35897
36556
  // only the attributes set on the last series will work.
35898
36557
  // Do not change this fact unless there will be a break change.
35899
36558
 
35900
- // TODO
35901
36559
  var barWidth = seriesInfo.barWidth;
35902
36560
  if (barWidth && !stacks[stackId].width) {
35903
36561
  // See #6312, do not restrict width.
@@ -35937,6 +36595,7 @@ function doCalBarWidthAndOffset(seriesInfoList) {
35937
36595
  each$1(stacks, function (column) {
35938
36596
  var maxWidth = column.maxWidth;
35939
36597
  var minWidth = column.minWidth;
36598
+
35940
36599
  if (!column.width) {
35941
36600
  var finalWidth = autoWidth;
35942
36601
  if (maxWidth && maxWidth < finalWidth) {
@@ -35952,7 +36611,7 @@ function doCalBarWidthAndOffset(seriesInfoList) {
35952
36611
  }
35953
36612
  if (finalWidth !== autoWidth) {
35954
36613
  column.width = finalWidth;
35955
- remainedWidth -= finalWidth;
36614
+ remainedWidth -= finalWidth + barGapPercent * finalWidth;
35956
36615
  autoWidthCount--;
35957
36616
  }
35958
36617
  }
@@ -35969,7 +36628,7 @@ function doCalBarWidthAndOffset(seriesInfoList) {
35969
36628
  finalWidth = Math.max(finalWidth, minWidth);
35970
36629
  }
35971
36630
  column.width = finalWidth;
35972
- remainedWidth -= finalWidth;
36631
+ remainedWidth -= finalWidth + barGapPercent * finalWidth;
35973
36632
  autoWidthCount--;
35974
36633
  }
35975
36634
  });
@@ -35977,8 +36636,10 @@ function doCalBarWidthAndOffset(seriesInfoList) {
35977
36636
  // Recalculate width again
35978
36637
  autoWidth = (remainedWidth - categoryGap)
35979
36638
  / (autoWidthCount + (autoWidthCount - 1) * barGapPercent);
36639
+
35980
36640
  autoWidth = Math.max(autoWidth, 0);
35981
36641
 
36642
+
35982
36643
  var widthSum = 0;
35983
36644
  var lastColumn;
35984
36645
  each$1(stacks, function (column, idx) {
@@ -36117,6 +36778,7 @@ function layout(seriesType, ecModel) {
36117
36778
  }
36118
36779
  stacked && (lastStackCoords[stackId][baseValue][sign] += height);
36119
36780
  }
36781
+
36120
36782
  data.setItemLayout(idx, {
36121
36783
  x: x,
36122
36784
  y: y,
@@ -36477,14 +37139,15 @@ var LogScale = Scale.extend({
36477
37139
  },
36478
37140
 
36479
37141
  /**
37142
+ * @param {boolean} [expandToNicedExtent=false] If expand the ticks to niced extent.
36480
37143
  * @return {Array.<number>}
36481
37144
  */
36482
- getTicks: function () {
37145
+ getTicks: function (expandToNicedExtent) {
36483
37146
  var originalScale = this._originalScale;
36484
37147
  var extent = this._extent;
36485
37148
  var originalExtent = originalScale.getExtent();
36486
37149
 
36487
- return map(intervalScaleProto$1.getTicks.call(this), function (val) {
37150
+ return map(intervalScaleProto$1.getTicks.call(this, expandToNicedExtent), function (val) {
36488
37151
  var powVal = round$1(mathPow$1(this.base, val));
36489
37152
 
36490
37153
  // Fix #4158
@@ -36499,6 +37162,12 @@ var LogScale = Scale.extend({
36499
37162
  }, this);
36500
37163
  },
36501
37164
 
37165
+ /**
37166
+ * @param {number} splitNumber
37167
+ * @return {Array.<Array.<number>>}
37168
+ */
37169
+ getMinorTicks: intervalScaleProto$1.getMinorTicks,
37170
+
36502
37171
  /**
36503
37172
  * @param {number} val
36504
37173
  * @return {string}
@@ -37744,7 +38413,7 @@ Axis.prototype = {
37744
38413
  * @return {boolean}
37745
38414
  */
37746
38415
  containData: function (data) {
37747
- return this.contain(this.dataToCoord(data));
38416
+ return this.scale.contain(data);
37748
38417
  },
37749
38418
 
37750
38419
  /**
@@ -37832,7 +38501,7 @@ Axis.prototype = {
37832
38501
  * `axis.getTicksCoords` considers `onBand`, which is used by
37833
38502
  * `boundaryGap:true` of category axis and splitLine and splitArea.
37834
38503
  * @param {Object} [opt]
37835
- * @param {number} [opt.tickModel=axis.model.getModel('axisTick')]
38504
+ * @param {Model} [opt.tickModel=axis.model.getModel('axisTick')]
37836
38505
  * @param {boolean} [opt.clamp] If `true`, the first and the last
37837
38506
  * tick must be at the axis end points. Otherwise, clip ticks
37838
38507
  * that outside the axis extent.
@@ -37864,6 +38533,33 @@ Axis.prototype = {
37864
38533
  return ticksCoords;
37865
38534
  },
37866
38535
 
38536
+ /**
38537
+ * @return {Array.<Array.<Object>>} [{ coord: ..., tickValue: ...}]
38538
+ */
38539
+ getMinorTicksCoords: function () {
38540
+ if (this.scale.type === 'ordinal') {
38541
+ // Category axis doesn't support minor ticks
38542
+ return [];
38543
+ }
38544
+
38545
+ var minorTickModel = this.model.getModel('minorTick');
38546
+ var splitNumber = minorTickModel.get('splitNumber');
38547
+ // Protection.
38548
+ if (!(splitNumber > 0 && splitNumber < 100)) {
38549
+ splitNumber = 5;
38550
+ }
38551
+ var minorTicks = this.scale.getMinorTicks(splitNumber);
38552
+ var minorTicksCoords = map(minorTicks, function (minorTicksGroup) {
38553
+ return map(minorTicksGroup, function (minorTick) {
38554
+ return {
38555
+ coord: this.dataToCoord(minorTick),
38556
+ tickValue: minorTick
38557
+ };
38558
+ }, this);
38559
+ }, this);
38560
+ return minorTicksCoords;
38561
+ },
38562
+
37867
38563
  /**
37868
38564
  * @return {Array.<Object>} [{
37869
38565
  * formattedLabel: string,
@@ -38298,7 +38994,7 @@ axisDefault.valueAxis = merge({
38298
38994
  // scale: false,
38299
38995
 
38300
38996
  // AxisTick and axisLabel and splitLine are caculated based on splitNumber.
38301
- splitNumber: 5
38997
+ splitNumber: 5,
38302
38998
 
38303
38999
  // Interval specifies the span of the ticks is mandatorily.
38304
39000
  // interval: null
@@ -38309,6 +39005,30 @@ axisDefault.valueAxis = merge({
38309
39005
  // Specify max interval when auto calculate tick interval.
38310
39006
  // maxInterval: null
38311
39007
 
39008
+ minorTick: {
39009
+ // Minor tick, not available for cateogry axis.
39010
+ show: false,
39011
+ // Split number of minor ticks. The value should be in range of (0, 100)
39012
+ splitNumber: 5,
39013
+ // Lenght of minor tick
39014
+ length: 3,
39015
+
39016
+ // Same inside with axisTick
39017
+
39018
+ // Line style
39019
+ lineStyle: {
39020
+ // Default to be same with axisTick
39021
+ }
39022
+ },
39023
+
39024
+ minorSplitLine: {
39025
+ show: false,
39026
+
39027
+ lineStyle: {
39028
+ color: '#eee',
39029
+ width: 1
39030
+ }
39031
+ }
38312
39032
  }, defaultOption);
38313
39033
 
38314
39034
  axisDefault.timeAxis = defaults({
@@ -39521,10 +40241,12 @@ var builders = {
39521
40241
  var axisModel = this.axisModel;
39522
40242
  var opt = this.opt;
39523
40243
 
39524
- var tickEls = buildAxisTick(this, axisModel, opt);
40244
+ var ticksEls = buildAxisMajorTicks(this, axisModel, opt);
39525
40245
  var labelEls = buildAxisLabel(this, axisModel, opt);
39526
40246
 
39527
- fixMinMaxLabelShow(axisModel, labelEls, tickEls);
40247
+ fixMinMaxLabelShow(axisModel, labelEls, ticksEls);
40248
+
40249
+ buildAxisMinorTicks(this, axisModel, opt);
39528
40250
  },
39529
40251
 
39530
40252
  /**
@@ -39843,42 +40565,27 @@ function isNameLocationCenter(nameLocation) {
39843
40565
  return nameLocation === 'middle' || nameLocation === 'center';
39844
40566
  }
39845
40567
 
39846
- function buildAxisTick(axisBuilder, axisModel, opt) {
39847
- var axis = axisModel.axis;
39848
-
39849
- if (!axisModel.get('axisTick.show') || axis.scale.isBlank()) {
39850
- return;
39851
- }
39852
-
39853
- var tickModel = axisModel.getModel('axisTick');
39854
-
39855
- var lineStyleModel = tickModel.getModel('lineStyle');
39856
- var tickLen = tickModel.get('length');
39857
-
39858
- var ticksCoords = axis.getTicksCoords();
39859
40568
 
40569
+ function createTicks(ticksCoords, tickTransform, tickEndCoord, tickLineStyle, aniid) {
40570
+ var tickEls = [];
39860
40571
  var pt1 = [];
39861
40572
  var pt2 = [];
39862
- var matrix = axisBuilder._transform;
39863
-
39864
- var tickEls = [];
39865
-
39866
40573
  for (var i = 0; i < ticksCoords.length; i++) {
39867
40574
  var tickCoord = ticksCoords[i].coord;
39868
40575
 
39869
40576
  pt1[0] = tickCoord;
39870
40577
  pt1[1] = 0;
39871
40578
  pt2[0] = tickCoord;
39872
- pt2[1] = opt.tickDirection * tickLen;
40579
+ pt2[1] = tickEndCoord;
39873
40580
 
39874
- if (matrix) {
39875
- applyTransform(pt1, pt1, matrix);
39876
- applyTransform(pt2, pt2, matrix);
40581
+ if (tickTransform) {
40582
+ applyTransform(pt1, pt1, tickTransform);
40583
+ applyTransform(pt2, pt2, tickTransform);
39877
40584
  }
39878
40585
  // Tick line, Not use group transform to have better line draw
39879
40586
  var tickEl = new Line({
39880
40587
  // Id for animation
39881
- anid: 'tick_' + ticksCoords[i].tickValue,
40588
+ anid: aniid + '_' + ticksCoords[i].tickValue,
39882
40589
  subPixelOptimize: true,
39883
40590
  shape: {
39884
40591
  x1: pt1[0],
@@ -39886,22 +40593,80 @@ function buildAxisTick(axisBuilder, axisModel, opt) {
39886
40593
  x2: pt2[0],
39887
40594
  y2: pt2[1]
39888
40595
  },
39889
- style: defaults(
39890
- lineStyleModel.getLineStyle(),
39891
- {
39892
- stroke: axisModel.get('axisLine.lineStyle.color')
39893
- }
39894
- ),
40596
+ style: tickLineStyle,
39895
40597
  z2: 2,
39896
40598
  silent: true
39897
40599
  });
39898
- axisBuilder.group.add(tickEl);
39899
40600
  tickEls.push(tickEl);
39900
40601
  }
39901
-
39902
40602
  return tickEls;
39903
40603
  }
39904
40604
 
40605
+ function buildAxisMajorTicks(axisBuilder, axisModel, opt) {
40606
+ var axis = axisModel.axis;
40607
+
40608
+ var tickModel = axisModel.getModel('axisTick');
40609
+
40610
+ if (!tickModel.get('show') || axis.scale.isBlank()) {
40611
+ return;
40612
+ }
40613
+
40614
+ var lineStyleModel = tickModel.getModel('lineStyle');
40615
+ var tickEndCoord = opt.tickDirection * tickModel.get('length');
40616
+
40617
+ var ticksCoords = axis.getTicksCoords();
40618
+
40619
+ var ticksEls = createTicks(ticksCoords, axisBuilder._transform, tickEndCoord, defaults(
40620
+ lineStyleModel.getLineStyle(),
40621
+ {
40622
+ stroke: axisModel.get('axisLine.lineStyle.color')
40623
+ }
40624
+ ), 'ticks');
40625
+
40626
+ for (var i = 0; i < ticksEls.length; i++) {
40627
+ axisBuilder.group.add(ticksEls[i]);
40628
+ }
40629
+
40630
+ return ticksEls;
40631
+ }
40632
+
40633
+ function buildAxisMinorTicks(axisBuilder, axisModel, opt) {
40634
+ var axis = axisModel.axis;
40635
+
40636
+ var minorTickModel = axisModel.getModel('minorTick');
40637
+
40638
+ if (!minorTickModel.get('show') || axis.scale.isBlank()) {
40639
+ return;
40640
+ }
40641
+
40642
+ var minorTicksCoords = axis.getMinorTicksCoords();
40643
+ if (!minorTicksCoords.length) {
40644
+ return;
40645
+ }
40646
+
40647
+ var lineStyleModel = minorTickModel.getModel('lineStyle');
40648
+ var tickEndCoord = opt.tickDirection * minorTickModel.get('length');
40649
+
40650
+ var minorTickLineStyle = defaults(
40651
+ lineStyleModel.getLineStyle(),
40652
+ defaults(
40653
+ axisModel.getModel('axisTick').getLineStyle(),
40654
+ {
40655
+ stroke: axisModel.get('axisLine.lineStyle.color')
40656
+ }
40657
+ )
40658
+ );
40659
+
40660
+ for (var i = 0; i < minorTicksCoords.length; i++) {
40661
+ var minorTicksEls = createTicks(
40662
+ minorTicksCoords[i], axisBuilder._transform, tickEndCoord, minorTickLineStyle, 'minorticks_' + i
40663
+ );
40664
+ for (var k = 0; k < minorTicksEls.length; k++) {
40665
+ axisBuilder.group.add(minorTicksEls[k]);
40666
+ }
40667
+ }
40668
+ }
40669
+
39905
40670
  function buildAxisLabel(axisBuilder, axisModel, opt) {
39906
40671
  var axis = axisModel.axis;
39907
40672
  var show = retrieve(opt.axisLabelShow, axisModel.get('axisLabel.show'));
@@ -40321,17 +41086,9 @@ var axisBuilderAttrs = [
40321
41086
  'axisLine', 'axisTickLabel', 'axisName'
40322
41087
  ];
40323
41088
  var selfBuilderAttrs = [
40324
- 'splitArea', 'splitLine'
41089
+ 'splitArea', 'splitLine', 'minorSplitLine'
40325
41090
  ];
40326
41091
 
40327
- // function getAlignWithLabel(model, axisModel) {
40328
- // var alignWithLabel = model.get('alignWithLabel');
40329
- // if (alignWithLabel === 'auto') {
40330
- // alignWithLabel = axisModel.get('axisTick.alignWithLabel');
40331
- // }
40332
- // return alignWithLabel;
40333
- // }
40334
-
40335
41092
  var CartesianAxisView = AxisView.extend({
40336
41093
 
40337
41094
  type: 'cartesianAxis',
@@ -40409,8 +41166,6 @@ var CartesianAxisView = AxisView.extend({
40409
41166
  var p1 = [];
40410
41167
  var p2 = [];
40411
41168
 
40412
- // Simple optimization
40413
- // Batching the lines if color are the same
40414
41169
  var lineStyle = lineStyleModel.getLineStyle();
40415
41170
  for (var i = 0; i < ticksCoords.length; i++) {
40416
41171
  var tickCoord = axis.toGlobalCoord(ticksCoords[i].coord);
@@ -40447,6 +41202,63 @@ var CartesianAxisView = AxisView.extend({
40447
41202
  }
40448
41203
  },
40449
41204
 
41205
+ /**
41206
+ * @param {module:echarts/coord/cartesian/AxisModel} axisModel
41207
+ * @param {module:echarts/coord/cartesian/GridModel} gridModel
41208
+ * @private
41209
+ */
41210
+ _minorSplitLine: function (axisModel, gridModel) {
41211
+ var axis = axisModel.axis;
41212
+
41213
+ var minorSplitLineModel = axisModel.getModel('minorSplitLine');
41214
+ var lineStyleModel = minorSplitLineModel.getModel('lineStyle');
41215
+
41216
+ var gridRect = gridModel.coordinateSystem.getRect();
41217
+ var isHorizontal = axis.isHorizontal();
41218
+
41219
+ var minorTicksCoords = axis.getMinorTicksCoords();
41220
+ if (!minorTicksCoords.length) {
41221
+ return;
41222
+ }
41223
+ var p1 = [];
41224
+ var p2 = [];
41225
+
41226
+ var lineStyle = lineStyleModel.getLineStyle();
41227
+
41228
+
41229
+ for (var i = 0; i < minorTicksCoords.length; i++) {
41230
+ for (var k = 0; k < minorTicksCoords[i].length; k++) {
41231
+ var tickCoord = axis.toGlobalCoord(minorTicksCoords[i][k].coord);
41232
+
41233
+ if (isHorizontal) {
41234
+ p1[0] = tickCoord;
41235
+ p1[1] = gridRect.y;
41236
+ p2[0] = tickCoord;
41237
+ p2[1] = gridRect.y + gridRect.height;
41238
+ }
41239
+ else {
41240
+ p1[0] = gridRect.x;
41241
+ p1[1] = tickCoord;
41242
+ p2[0] = gridRect.x + gridRect.width;
41243
+ p2[1] = tickCoord;
41244
+ }
41245
+
41246
+ this._axisGroup.add(new Line({
41247
+ anid: 'minor_line_' + minorTicksCoords[i][k].tickValue,
41248
+ subPixelOptimize: true,
41249
+ shape: {
41250
+ x1: p1[0],
41251
+ y1: p1[1],
41252
+ x2: p2[0],
41253
+ y2: p2[1]
41254
+ },
41255
+ style: lineStyle,
41256
+ silent: true
41257
+ }));
41258
+ }
41259
+ }
41260
+ },
41261
+
40450
41262
  /**
40451
41263
  * @param {module:echarts/coord/cartesian/AxisModel} axisModel
40452
41264
  * @param {module:echarts/coord/cartesian/GridModel} gridModel
@@ -40667,7 +41479,7 @@ var BaseBarSeries = SeriesModel.extend({
40667
41479
  type: 'series.__base_bar__',
40668
41480
 
40669
41481
  getInitialData: function (option, ecModel) {
40670
- return createListFromArray(this.getSource(), this);
41482
+ return createListFromArray(this.getSource(), this, {useEncodeDefaulter: true});
40671
41483
  },
40672
41484
 
40673
41485
  getMarkerPosition: function (value) {
@@ -41371,11 +42183,18 @@ var getLayout = {
41371
42183
  }
41372
42184
  };
41373
42185
 
42186
+ function isZeroOnPolar(layout) {
42187
+ return layout.startAngle != null
42188
+ && layout.endAngle != null
42189
+ && layout.startAngle === layout.endAngle;
42190
+ }
42191
+
41374
42192
  function updateStyle(
41375
42193
  el, data, dataIndex, itemModel, layout, seriesModel, isHorizontal, isPolar
41376
42194
  ) {
41377
42195
  var color = data.getItemVisual(dataIndex, 'color');
41378
42196
  var opacity = data.getItemVisual(dataIndex, 'opacity');
42197
+ var stroke = data.getVisual('borderColor');
41379
42198
  var itemStyleModel = itemModel.getModel('itemStyle');
41380
42199
  var hoverStyle = itemModel.getModel('emphasis.itemStyle').getBarItemStyle();
41381
42200
 
@@ -41385,7 +42204,8 @@ function updateStyle(
41385
42204
 
41386
42205
  el.useStyle(defaults(
41387
42206
  {
41388
- fill: color,
42207
+ stroke: isZeroOnPolar(layout) ? 'none' : stroke,
42208
+ fill: isZeroOnPolar(layout) ? 'none' : color,
41389
42209
  opacity: opacity
41390
42210
  },
41391
42211
  itemStyleModel.getBarItemStyle()
@@ -41404,7 +42224,9 @@ function updateStyle(
41404
42224
  seriesModel, dataIndex, labelPositionOutside
41405
42225
  );
41406
42226
  }
41407
-
42227
+ if (isZeroOnPolar(layout)) {
42228
+ hoverStyle.fill = hoverStyle.stroke = 'none';
42229
+ }
41408
42230
  setHoverStyle(el, hoverStyle);
41409
42231
  }
41410
42232
 
@@ -41725,6 +42547,60 @@ var dataSelectableMixin = {
41725
42547
  * under the License.
41726
42548
  */
41727
42549
 
42550
+
42551
+ /**
42552
+ * LegendVisualProvider is an bridge that pick encoded color from data and
42553
+ * provide to the legend component.
42554
+ * @param {Function} getDataWithEncodedVisual Function to get data after filtered. It stores all the encoding info
42555
+ * @param {Function} getRawData Function to get raw data before filtered.
42556
+ */
42557
+ function LegendVisualProvider(getDataWithEncodedVisual, getRawData) {
42558
+ this.getAllNames = function () {
42559
+ var rawData = getRawData();
42560
+ // We find the name from the raw data. In case it's filtered by the legend component.
42561
+ // Normally, the name can be found in rawData, but can't be found in filtered data will display as gray.
42562
+ return rawData.mapArray(rawData.getName);
42563
+ };
42564
+
42565
+ this.containName = function (name) {
42566
+ var rawData = getRawData();
42567
+ return rawData.indexOfName(name) >= 0;
42568
+ };
42569
+
42570
+ this.indexOfName = function (name) {
42571
+ // Only get data when necessary.
42572
+ // Because LegendVisualProvider constructor may be new in the stage that data is not prepared yet.
42573
+ // Invoking Series#getData immediately will throw an error.
42574
+ var dataWithEncodedVisual = getDataWithEncodedVisual();
42575
+ return dataWithEncodedVisual.indexOfName(name);
42576
+ };
42577
+
42578
+ this.getItemVisual = function (dataIndex, key) {
42579
+ // Get encoded visual properties from final filtered data.
42580
+ var dataWithEncodedVisual = getDataWithEncodedVisual();
42581
+ return dataWithEncodedVisual.getItemVisual(dataIndex, key);
42582
+ };
42583
+ }
42584
+
42585
+ /*
42586
+ * Licensed to the Apache Software Foundation (ASF) under one
42587
+ * or more contributor license agreements. See the NOTICE file
42588
+ * distributed with this work for additional information
42589
+ * regarding copyright ownership. The ASF licenses this file
42590
+ * to you under the Apache License, Version 2.0 (the
42591
+ * "License"); you may not use this file except in compliance
42592
+ * with the License. You may obtain a copy of the License at
42593
+ *
42594
+ * http://www.apache.org/licenses/LICENSE-2.0
42595
+ *
42596
+ * Unless required by applicable law or agreed to in writing,
42597
+ * software distributed under the License is distributed on an
42598
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
42599
+ * KIND, either express or implied. See the License for the
42600
+ * specific language governing permissions and limitations
42601
+ * under the License.
42602
+ */
42603
+
41728
42604
  var PieSeries = extendSeriesModel({
41729
42605
 
41730
42606
  type: 'series.pie',
@@ -41735,9 +42611,9 @@ var PieSeries = extendSeriesModel({
41735
42611
 
41736
42612
  // Enable legend selection for each data item
41737
42613
  // Use a function instead of direct access because data reference may changed
41738
- this.legendDataProvider = function () {
41739
- return this.getRawData();
41740
- };
42614
+ this.legendVisualProvider = new LegendVisualProvider(
42615
+ bind(this.getData, this), bind(this.getRawData, this)
42616
+ );
41741
42617
 
41742
42618
  this.updateSelectedMap(this._createSelectableList());
41743
42619
 
@@ -41752,7 +42628,10 @@ var PieSeries = extendSeriesModel({
41752
42628
  },
41753
42629
 
41754
42630
  getInitialData: function (option, ecModel) {
41755
- return createListSimply(this, ['value']);
42631
+ return createListSimply(this, {
42632
+ coordDimensions: ['value'],
42633
+ encodeDefaulter: curry(makeSeriesEncodeForNameBased, this)
42634
+ });
41756
42635
  },
41757
42636
 
41758
42637
  _createSelectableList: function () {
@@ -41841,12 +42720,28 @@ var PieSeries = extendSeriesModel({
41841
42720
 
41842
42721
  // cursor: null,
41843
42722
 
42723
+ left: 0,
42724
+ top: 0,
42725
+ right: 0,
42726
+ bottom: 0,
42727
+ width: null,
42728
+ height: null,
42729
+
41844
42730
  label: {
41845
42731
  // If rotate around circle
41846
42732
  rotate: false,
41847
42733
  show: true,
41848
42734
  // 'outer', 'inside', 'center'
41849
- position: 'outer'
42735
+ position: 'outer',
42736
+ // 'none', 'labelLine', 'edge'. Works only when position is 'outer'
42737
+ alignTo: 'none',
42738
+ // Closest distance between label and chart edge.
42739
+ // Works only position is 'outer' and alignTo is 'edge'.
42740
+ margin: '25%',
42741
+ // Works only position is 'outer' and alignTo is not 'edge'.
42742
+ bleedMargin: 10,
42743
+ // Distance between text and label line.
42744
+ distanceToLabelLine: 5
41850
42745
  // formatter: 标签文本格式器,同Tooltip.formatter,不支持异步回调
41851
42746
  // 默认使用全局文本样式,详见TEXTSTYLE
41852
42747
  // distance: 当position为inner时有效,为label位置到圆心的距离与圆半径(环状图为内外半径和)的比例系数
@@ -42152,7 +43047,7 @@ piePieceProto._updateLabel = function (data, idx, withAnimation) {
42152
43047
  {
42153
43048
  labelFetcher: data.hostModel,
42154
43049
  labelDataIndex: idx,
42155
- defaultText: data.getName(idx),
43050
+ defaultText: labelLayout.text,
42156
43051
  autoColor: visualColor,
42157
43052
  useInsideStyle: !!labelLayout.inside
42158
43053
  },
@@ -42448,33 +43343,20 @@ var dataColor = function (seriesType) {
42448
43343
  dataAll.getName(rawIdx) || (rawIdx + ''), seriesModel.__paletteScope,
42449
43344
  dataAll.count()
42450
43345
  );
42451
- // Legend may use the visual info in data before processed
42452
- dataAll.setItemVisual(rawIdx, 'color', color);
42453
-
42454
43346
  // Data is not filtered
42455
43347
  if (filteredIdx != null) {
42456
43348
  data.setItemVisual(filteredIdx, 'color', color);
42457
43349
  }
42458
43350
  }
42459
- else {
42460
- // Set data all color for legend
42461
- dataAll.setItemVisual(rawIdx, 'color', singleDataColor);
42462
- }
42463
43351
 
42464
43352
  if (!singleDataBorderColor) {
42465
43353
  var borderColor = itemModel.get('itemStyle.borderColor');
42466
- // Legend may use the visual info in data before processed
42467
- dataAll.setItemVisual(rawIdx, 'borderColor', borderColor);
42468
43354
 
42469
43355
  // Data is not filtered
42470
43356
  if (filteredIdx != null) {
42471
43357
  data.setItemVisual(filteredIdx, 'borderColor', borderColor);
42472
43358
  }
42473
43359
  }
42474
- else {
42475
- // Set data all borderColor for legend
42476
- dataAll.setItemVisual(rawIdx, 'borderColor', singleDataBorderColor);
42477
- }
42478
43360
  });
42479
43361
  }
42480
43362
  };
@@ -42503,13 +43385,17 @@ var dataColor = function (seriesType) {
42503
43385
 
42504
43386
  var RADIAN$1 = Math.PI / 180;
42505
43387
 
42506
- function adjustSingleSide(list, cx, cy, r, dir, viewWidth, viewHeight) {
43388
+ function adjustSingleSide(list, cx, cy, r, dir, viewWidth, viewHeight, viewLeft, viewTop, farthestX) {
42507
43389
  list.sort(function (a, b) {
42508
43390
  return a.y - b.y;
42509
43391
  });
42510
43392
 
42511
43393
  function shiftDown(start, end, delta, dir) {
42512
43394
  for (var j = start; j < end; j++) {
43395
+ if (list[j].y + delta > viewTop + viewHeight) {
43396
+ break;
43397
+ }
43398
+
42513
43399
  list[j].y += delta;
42514
43400
  if (j > start
42515
43401
  && j + 1 < end
@@ -42525,6 +43411,10 @@ function adjustSingleSide(list, cx, cy, r, dir, viewWidth, viewHeight) {
42525
43411
 
42526
43412
  function shiftUp(end, delta) {
42527
43413
  for (var j = end; j >= 0; j--) {
43414
+ if (list[j].y - delta < viewTop) {
43415
+ break;
43416
+ }
43417
+
42528
43418
  list[j].y -= delta;
42529
43419
  if (j > 0
42530
43420
  && list[j].y > list[j - 1].y + list[j - 1].height
@@ -42544,6 +43434,10 @@ function adjustSingleSide(list, cx, cy, r, dir, viewWidth, viewHeight) {
42544
43434
  : 0; // up
42545
43435
 
42546
43436
  for (var i = 0, l = list.length; i < l; i++) {
43437
+ if (list[i].labelAlignTo !== 'none') {
43438
+ continue;
43439
+ }
43440
+
42547
43441
  var deltaY = Math.abs(list[i].y - cy);
42548
43442
  var length = list[i].len;
42549
43443
  var length2 = list[i].len2;
@@ -42573,6 +43467,12 @@ function adjustSingleSide(list, cx, cy, r, dir, viewWidth, viewHeight) {
42573
43467
  var upList = [];
42574
43468
  var downList = [];
42575
43469
  for (var i = 0; i < len; i++) {
43470
+ if (list[i].position === 'outer' && list[i].labelAlignTo === 'labelLine') {
43471
+ var dx = list[i].x - farthestX;
43472
+ list[i].linePoints[1][0] += dx;
43473
+ list[i].x = farthestX;
43474
+ }
43475
+
42576
43476
  delta = list[i].y - lastY;
42577
43477
  if (delta < 0) {
42578
43478
  shiftDown(i, len, -delta, dir);
@@ -42594,39 +43494,85 @@ function adjustSingleSide(list, cx, cy, r, dir, viewWidth, viewHeight) {
42594
43494
  changeX(downList, true, cx, cy, r, dir);
42595
43495
  }
42596
43496
 
42597
- function avoidOverlap(labelLayoutList, cx, cy, r, viewWidth, viewHeight) {
43497
+ function avoidOverlap(labelLayoutList, cx, cy, r, viewWidth, viewHeight, viewLeft, viewTop) {
42598
43498
  var leftList = [];
42599
43499
  var rightList = [];
43500
+ var leftmostX = Number.MAX_VALUE;
43501
+ var rightmostX = -Number.MAX_VALUE;
42600
43502
  for (var i = 0; i < labelLayoutList.length; i++) {
42601
43503
  if (isPositionCenter(labelLayoutList[i])) {
42602
43504
  continue;
42603
43505
  }
42604
43506
  if (labelLayoutList[i].x < cx) {
43507
+ leftmostX = Math.min(leftmostX, labelLayoutList[i].x);
42605
43508
  leftList.push(labelLayoutList[i]);
42606
43509
  }
42607
43510
  else {
43511
+ rightmostX = Math.max(rightmostX, labelLayoutList[i].x);
42608
43512
  rightList.push(labelLayoutList[i]);
42609
43513
  }
42610
43514
  }
42611
43515
 
42612
- adjustSingleSide(rightList, cx, cy, r, 1, viewWidth, viewHeight);
42613
- adjustSingleSide(leftList, cx, cy, r, -1, viewWidth, viewHeight);
43516
+ adjustSingleSide(rightList, cx, cy, r, 1, viewWidth, viewHeight, viewLeft, viewTop, rightmostX);
43517
+ adjustSingleSide(leftList, cx, cy, r, -1, viewWidth, viewHeight, viewLeft, viewTop, leftmostX);
42614
43518
 
42615
43519
  for (var i = 0; i < labelLayoutList.length; i++) {
42616
- if (isPositionCenter(labelLayoutList[i])) {
43520
+ var layout = labelLayoutList[i];
43521
+ if (isPositionCenter(layout)) {
42617
43522
  continue;
42618
43523
  }
42619
- var linePoints = labelLayoutList[i].linePoints;
43524
+
43525
+ var linePoints = layout.linePoints;
42620
43526
  if (linePoints) {
43527
+ var isAlignToEdge = layout.labelAlignTo === 'edge';
43528
+
43529
+ var realTextWidth = layout.textRect.width;
43530
+ var targetTextWidth;
43531
+ if (isAlignToEdge) {
43532
+ if (layout.x < cx) {
43533
+ targetTextWidth = linePoints[2][0] - layout.labelDistance
43534
+ - viewLeft - layout.labelMargin;
43535
+ }
43536
+ else {
43537
+ targetTextWidth = viewLeft + viewWidth - layout.labelMargin
43538
+ - linePoints[2][0] - layout.labelDistance;
43539
+ }
43540
+ }
43541
+ else {
43542
+ if (layout.x < cx) {
43543
+ targetTextWidth = layout.x - viewLeft - layout.bleedMargin;
43544
+ }
43545
+ else {
43546
+ targetTextWidth = viewLeft + viewWidth - layout.x - layout.bleedMargin;
43547
+ }
43548
+ }
43549
+ if (targetTextWidth < layout.textRect.width) {
43550
+ layout.text = truncateText(layout.text, targetTextWidth, layout.font);
43551
+ if (layout.labelAlignTo === 'edge') {
43552
+ realTextWidth = getWidth(layout.text, layout.font);
43553
+ }
43554
+ }
43555
+
42621
43556
  var dist = linePoints[1][0] - linePoints[2][0];
42622
- if (labelLayoutList[i].x < cx) {
42623
- linePoints[2][0] = labelLayoutList[i].x + 3;
43557
+ if (isAlignToEdge) {
43558
+ if (layout.x < cx) {
43559
+ linePoints[2][0] = viewLeft + layout.labelMargin + realTextWidth + layout.labelDistance;
43560
+ }
43561
+ else {
43562
+ linePoints[2][0] = viewLeft + viewWidth - layout.labelMargin
43563
+ - realTextWidth - layout.labelDistance;
43564
+ }
42624
43565
  }
42625
43566
  else {
42626
- linePoints[2][0] = labelLayoutList[i].x - 3;
43567
+ if (layout.x < cx) {
43568
+ linePoints[2][0] = layout.x + layout.labelDistance;
43569
+ }
43570
+ else {
43571
+ linePoints[2][0] = layout.x - layout.labelDistance;
43572
+ }
43573
+ linePoints[1][0] = linePoints[2][0] + dist;
42627
43574
  }
42628
- linePoints[1][1] = linePoints[2][1] = labelLayoutList[i].y;
42629
- linePoints[1][0] = linePoints[2][0] + dist;
43575
+ linePoints[1][1] = linePoints[2][1] = layout.y;
42630
43576
  }
42631
43577
  }
42632
43578
  }
@@ -42636,7 +43582,7 @@ function isPositionCenter(layout) {
42636
43582
  return layout.position === 'center';
42637
43583
  }
42638
43584
 
42639
- var labelLayout = function (seriesModel, r, viewWidth, viewHeight, sum) {
43585
+ var labelLayout = function (seriesModel, r, viewWidth, viewHeight, viewLeft, viewTop) {
42640
43586
  var data = seriesModel.getData();
42641
43587
  var labelLayoutList = [];
42642
43588
  var cx;
@@ -42651,10 +43597,17 @@ var labelLayout = function (seriesModel, r, viewWidth, viewHeight, sum) {
42651
43597
  var labelModel = itemModel.getModel('label');
42652
43598
  // Use position in normal or emphasis
42653
43599
  var labelPosition = labelModel.get('position') || itemModel.get('emphasis.label.position');
43600
+ var labelDistance = labelModel.get('distanceToLabelLine');
43601
+ var labelAlignTo = labelModel.get('alignTo');
43602
+ var labelMargin = parsePercent$1(labelModel.get('margin'), viewWidth);
43603
+ var bleedMargin = labelModel.get('bleedMargin');
43604
+ var font = labelModel.getFont();
42654
43605
 
42655
43606
  var labelLineModel = itemModel.getModel('labelLine');
42656
43607
  var labelLineLen = labelLineModel.get('length');
43608
+ labelLineLen = parsePercent$1(labelLineLen, viewWidth);
42657
43609
  var labelLineLen2 = labelLineModel.get('length2');
43610
+ labelLineLen2 = parsePercent$1(labelLineLen2, viewWidth);
42658
43611
 
42659
43612
  if (layout.angle < minShowLabelRadian) {
42660
43613
  return;
@@ -42672,6 +43625,12 @@ var labelLayout = function (seriesModel, r, viewWidth, viewHeight, sum) {
42672
43625
  cx = layout.cx;
42673
43626
  cy = layout.cy;
42674
43627
 
43628
+ var text = seriesModel.getFormattedLabel(idx, 'normal')
43629
+ || data.getName(idx);
43630
+ var textRect = getBoundingRect(
43631
+ text, font, textAlign, 'top'
43632
+ );
43633
+
42675
43634
  var isLabelInside = labelPosition === 'inside' || labelPosition === 'inner';
42676
43635
  if (labelPosition === 'center') {
42677
43636
  textX = layout.cx;
@@ -42692,14 +43651,25 @@ var labelLayout = function (seriesModel, r, viewWidth, viewHeight, sum) {
42692
43651
  var x3 = x2 + ((dx < 0 ? -1 : 1) * labelLineLen2);
42693
43652
  var y3 = y2;
42694
43653
 
42695
- textX = x3 + (dx < 0 ? -5 : 5);
43654
+ if (labelAlignTo === 'edge') {
43655
+ // Adjust textX because text align of edge is opposite
43656
+ textX = dx < 0
43657
+ ? viewLeft + labelMargin
43658
+ : viewLeft + viewWidth - labelMargin;
43659
+ }
43660
+ else {
43661
+ textX = x3 + (dx < 0 ? -labelDistance : labelDistance);
43662
+ }
42696
43663
  textY = y3;
42697
43664
  linePoints = [[x1, y1], [x2, y2], [x3, y3]];
42698
43665
  }
42699
43666
 
42700
- textAlign = isLabelInside ? 'center' : (dx > 0 ? 'left' : 'right');
43667
+ textAlign = isLabelInside
43668
+ ? 'center'
43669
+ : (labelAlignTo === 'edge'
43670
+ ? (dx > 0 ? 'right' : 'left')
43671
+ : (dx > 0 ? 'left' : 'right'));
42701
43672
  }
42702
- var font = labelModel.getFont();
42703
43673
 
42704
43674
  var labelRotate;
42705
43675
  var rotate = labelModel.get('rotate');
@@ -42711,11 +43681,7 @@ var labelLayout = function (seriesModel, r, viewWidth, viewHeight, sum) {
42711
43681
  ? (dx < 0 ? -midAngle + Math.PI : -midAngle)
42712
43682
  : 0;
42713
43683
  }
42714
- var text = seriesModel.getFormattedLabel(idx, 'normal')
42715
- || data.getName(idx);
42716
- var textRect = getBoundingRect(
42717
- text, font, textAlign, 'top'
42718
- );
43684
+
42719
43685
  hasLabelRotate = !!labelRotate;
42720
43686
  layout.label = {
42721
43687
  x: textX,
@@ -42728,7 +43694,14 @@ var labelLayout = function (seriesModel, r, viewWidth, viewHeight, sum) {
42728
43694
  textAlign: textAlign,
42729
43695
  verticalAlign: 'middle',
42730
43696
  rotation: labelRotate,
42731
- inside: isLabelInside
43697
+ inside: isLabelInside,
43698
+ labelDistance: labelDistance,
43699
+ labelAlignTo: labelAlignTo,
43700
+ labelMargin:labelMargin,
43701
+ bleedMargin: bleedMargin,
43702
+ textRect: textRect,
43703
+ text: text,
43704
+ font: font
42732
43705
  };
42733
43706
 
42734
43707
  // Not layout the inside label
@@ -42737,7 +43710,7 @@ var labelLayout = function (seriesModel, r, viewWidth, viewHeight, sum) {
42737
43710
  }
42738
43711
  });
42739
43712
  if (!hasLabelRotate && seriesModel.get('avoidLabelOverlap')) {
42740
- avoidOverlap(labelLayoutList, cx, cy, r, viewWidth, viewHeight);
43713
+ avoidOverlap(labelLayoutList, cx, cy, r, viewWidth, viewHeight, viewLeft, viewTop);
42741
43714
  }
42742
43715
  };
42743
43716
 
@@ -42764,10 +43737,20 @@ var labelLayout = function (seriesModel, r, viewWidth, viewHeight, sum) {
42764
43737
  var PI2$4 = Math.PI * 2;
42765
43738
  var RADIAN = Math.PI / 180;
42766
43739
 
43740
+ function getViewRect(seriesModel, api) {
43741
+ return getLayoutRect(
43742
+ seriesModel.getBoxLayoutParams(), {
43743
+ width: api.getWidth(),
43744
+ height: api.getHeight()
43745
+ }
43746
+ );
43747
+ }
43748
+
42767
43749
  var pieLayout = function (seriesType, ecModel, api, payload) {
42768
43750
  ecModel.eachSeriesByType(seriesType, function (seriesModel) {
42769
43751
  var data = seriesModel.getData();
42770
43752
  var valueDim = data.mapDimension('value');
43753
+ var viewRect = getViewRect(seriesModel, api);
42771
43754
 
42772
43755
  var center = seriesModel.get('center');
42773
43756
  var radius = seriesModel.get('radius');
@@ -42779,11 +43762,11 @@ var pieLayout = function (seriesType, ecModel, api, payload) {
42779
43762
  center = [center, center];
42780
43763
  }
42781
43764
 
42782
- var width = api.getWidth();
42783
- var height = api.getHeight();
43765
+ var width = parsePercent$1(viewRect.width, api.getWidth());
43766
+ var height = parsePercent$1(viewRect.height, api.getHeight());
42784
43767
  var size = Math.min(width, height);
42785
- var cx = parsePercent$1(center[0], width);
42786
- var cy = parsePercent$1(center[1], height);
43768
+ var cx = parsePercent$1(center[0], width) + viewRect.x;
43769
+ var cy = parsePercent$1(center[1], height) + viewRect.y;
42787
43770
  var r0 = parsePercent$1(radius[0], size / 2);
42788
43771
  var r = parsePercent$1(radius[1], size / 2);
42789
43772
 
@@ -42829,7 +43812,8 @@ var pieLayout = function (seriesType, ecModel, api, payload) {
42829
43812
  r0: r0,
42830
43813
  r: roseType
42831
43814
  ? NaN
42832
- : r
43815
+ : r,
43816
+ viewRect: viewRect
42833
43817
  });
42834
43818
  return;
42835
43819
  }
@@ -42862,7 +43846,8 @@ var pieLayout = function (seriesType, ecModel, api, payload) {
42862
43846
  r0: r0,
42863
43847
  r: roseType
42864
43848
  ? linearMap(value, extent, [r0, r])
42865
- : r
43849
+ : r,
43850
+ viewRect: viewRect
42866
43851
  });
42867
43852
 
42868
43853
  currentAngle = endAngle;
@@ -42900,7 +43885,7 @@ var pieLayout = function (seriesType, ecModel, api, payload) {
42900
43885
  }
42901
43886
  }
42902
43887
 
42903
- labelLayout(seriesModel, r, width, height);
43888
+ labelLayout(seriesModel, r, viewRect.width, viewRect.height, viewRect.x, viewRect.y);
42904
43889
  });
42905
43890
  };
42906
43891