echarts 4.4.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 (211) hide show
  1. package/.github/ISSUE_TEMPLATE.md +1 -1
  2. package/.github/workflows/nodejs.yml +31 -0
  3. package/CONTRIBUTING.md +2 -2
  4. package/README.md +6 -12
  5. package/dist/echarts-en.common.js +2354 -1029
  6. package/dist/echarts-en.common.min.js +1 -1
  7. package/dist/echarts-en.js +2727 -1138
  8. package/dist/echarts-en.js.map +1 -1
  9. package/dist/echarts-en.min.js +1 -1
  10. package/dist/echarts-en.simple.js +2028 -759
  11. package/dist/echarts-en.simple.min.js +1 -1
  12. package/dist/echarts.common.js +2354 -1029
  13. package/dist/echarts.common.min.js +1 -1
  14. package/dist/echarts.js +2727 -1138
  15. package/dist/echarts.js.map +1 -1
  16. package/dist/echarts.min.js +1 -1
  17. package/dist/echarts.simple.js +2028 -759
  18. package/dist/echarts.simple.min.js +1 -1
  19. package/dist/extension/dataTool.js +9 -0
  20. package/dist/extension/dataTool.js.map +1 -1
  21. package/echarts.all.js +1 -1
  22. package/lib/chart/bar/BarSeries.js +4 -1
  23. package/lib/chart/bar/BarView.js +20 -6
  24. package/lib/chart/bar/BaseBarSeries.js +5 -1
  25. package/lib/chart/candlestick/CandlestickSeries.js +1 -0
  26. package/lib/chart/candlestick/CandlestickView.js +42 -1
  27. package/lib/chart/custom.js +1 -0
  28. package/lib/chart/effectScatter/EffectScatterSeries.js +3 -1
  29. package/lib/chart/funnel/FunnelSeries.js +15 -5
  30. package/lib/chart/gauge/GaugeSeries.js +0 -9
  31. package/lib/chart/graph/GraphSeries.js +11 -4
  32. package/lib/chart/graph/GraphView.js +28 -8
  33. package/lib/chart/graph/forceHelper.js +8 -2
  34. package/lib/chart/graph/forceLayout.js +5 -2
  35. package/lib/chart/heatmap/HeatmapView.js +4 -4
  36. package/lib/chart/helper/Symbol.js +8 -0
  37. package/lib/chart/helper/createListFromArray.js +14 -8
  38. package/lib/chart/helper/whiskerBoxCommon.js +22 -16
  39. package/lib/chart/line/LineSeries.js +3 -1
  40. package/lib/chart/line/LineView.js +8 -2
  41. package/lib/chart/map/MapSeries.js +8 -1
  42. package/lib/chart/pie/PieSeries.js +27 -6
  43. package/lib/chart/pie/PieView.js +1 -1
  44. package/lib/chart/pie/labelLayout.js +102 -19
  45. package/lib/chart/pie/pieLayout.js +19 -7
  46. package/lib/chart/radar/RadarSeries.js +3 -3
  47. package/lib/chart/sankey/SankeyView.js +28 -9
  48. package/lib/chart/scatter/ScatterSeries.js +3 -1
  49. package/lib/chart/themeRiver/ThemeRiverSeries.js +3 -3
  50. package/lib/chart/tree/TreeSeries.js +15 -1
  51. package/lib/chart/tree/TreeView.js +4 -2
  52. package/lib/component/axis/AngleAxisView.js +97 -20
  53. package/lib/component/axis/AxisBuilder.js +63 -24
  54. package/lib/component/axis/CartesianAxisView.js +55 -11
  55. package/lib/component/axis/RadiusAxisView.js +36 -4
  56. package/lib/component/brush/BrushView.js +6 -0
  57. package/lib/component/brush/brushAction.js +5 -0
  58. package/lib/component/dataZoom/DataZoomModel.js +15 -1
  59. package/lib/component/dataZoom/SliderZoomView.js +4 -10
  60. package/lib/component/helper/BrushController.js +43 -25
  61. package/lib/component/legend/LegendModel.js +3 -3
  62. package/lib/component/legend/LegendView.js +17 -13
  63. package/lib/component/toolbox/ToolboxView.js +16 -7
  64. package/lib/component/toolbox/feature/MagicType.js +19 -14
  65. package/lib/coord/Axis.js +44 -12
  66. package/lib/coord/axisDefault.js +21 -2
  67. package/lib/coord/axisTickLabelBuilder.js +9 -1
  68. package/lib/coord/cartesian/Cartesian2D.js +0 -15
  69. package/lib/coord/geo/geoJSONLoader.js +1 -1
  70. package/lib/coord/polar/polarCreator.js +11 -2
  71. package/lib/coord/radar/Radar.js +3 -1
  72. package/lib/coord/radar/RadarModel.js +4 -1
  73. package/lib/data/DataDiffer.js +2 -4
  74. package/lib/data/DataDimensionInfo.js +157 -0
  75. package/lib/data/List.js +29 -23
  76. package/lib/data/Tree.js +2 -1
  77. package/lib/data/helper/completeDimensions.js +43 -32
  78. package/lib/data/helper/createDimensions.js +2 -0
  79. package/lib/data/helper/sourceHelper.js +214 -114
  80. package/lib/echarts.js +2 -2
  81. package/lib/layout/barGrid.js +136 -11
  82. package/lib/layout/barPolar.js +2 -2
  83. package/lib/model/Global.js +1 -1
  84. package/lib/model/Series.js +3 -3
  85. package/lib/model/referHelper.js +40 -12
  86. package/lib/scale/Interval.js +87 -2
  87. package/lib/scale/Log.js +9 -2
  88. package/lib/scale/helper.js +1 -43
  89. package/lib/theme/dark.js +3 -0
  90. package/lib/util/graphic.js +1 -2
  91. package/lib/util/number.js +25 -1
  92. package/lib/util/shape/sausage.js +93 -0
  93. package/lib/visual/LegendVisualProvider.js +75 -0
  94. package/lib/visual/dataColor.js +2 -12
  95. package/lib/visual/seriesColor.js +15 -7
  96. package/map/js/china.js +2 -2
  97. package/map/json/china.json +1 -1
  98. package/map/json/province/tianjin.json +1 -1
  99. package/package.json +3 -2
  100. package/src/chart/bar/BarSeries.js +5 -1
  101. package/src/chart/bar/BarView.js +24 -8
  102. package/src/chart/bar/BaseBarSeries.js +5 -1
  103. package/src/chart/candlestick/CandlestickSeries.js +2 -0
  104. package/src/chart/candlestick/CandlestickView.js +44 -1
  105. package/src/chart/custom.js +1 -0
  106. package/src/chart/effectScatter/EffectScatterSeries.js +1 -1
  107. package/src/chart/funnel/FunnelSeries.js +11 -4
  108. package/src/chart/gauge/GaugeSeries.js +0 -6
  109. package/src/chart/graph/GraphSeries.js +10 -3
  110. package/src/chart/graph/GraphView.js +26 -8
  111. package/src/chart/graph/forceHelper.js +7 -3
  112. package/src/chart/graph/forceLayout.js +6 -3
  113. package/src/chart/heatmap/HeatmapView.js +4 -4
  114. package/src/chart/helper/Symbol.js +9 -0
  115. package/src/chart/helper/createClipPathFromCoordSys.js +5 -1
  116. package/src/chart/helper/createGraphFromNodeEdge.js +1 -1
  117. package/src/chart/helper/createListFromArray.js +13 -8
  118. package/src/chart/helper/whiskerBoxCommon.js +21 -16
  119. package/src/chart/line/LineSeries.js +1 -1
  120. package/src/chart/line/LineView.js +6 -1
  121. package/src/chart/map/MapSeries.js +5 -1
  122. package/src/chart/pie/PieSeries.js +26 -5
  123. package/src/chart/pie/PieView.js +1 -1
  124. package/src/chart/pie/labelLayout.js +114 -22
  125. package/src/chart/pie/pieLayout.js +20 -7
  126. package/src/chart/radar/RadarSeries.js +5 -3
  127. package/src/chart/sankey/SankeyView.js +26 -9
  128. package/src/chart/scatter/ScatterSeries.js +1 -1
  129. package/src/chart/themeRiver/ThemeRiverSeries.js +4 -3
  130. package/src/chart/tree/TreeSeries.js +12 -1
  131. package/src/chart/tree/TreeView.js +5 -2
  132. package/src/component/axis/AngleAxisView.js +106 -19
  133. package/src/component/axis/AxisBuilder.js +78 -33
  134. package/src/component/axis/CartesianAxisView.js +58 -11
  135. package/src/component/axis/RadiusAxisView.js +37 -4
  136. package/src/component/brush/BrushView.js +6 -0
  137. package/src/component/brush/brushAction.js +6 -1
  138. package/src/component/dataZoom/DataZoomModel.js +15 -1
  139. package/src/component/dataZoom/SliderZoomView.js +4 -9
  140. package/src/component/helper/BrushController.js +50 -28
  141. package/src/component/legend/LegendModel.js +3 -3
  142. package/src/component/legend/LegendView.js +18 -12
  143. package/src/component/toolbox/ToolboxView.js +18 -5
  144. package/src/component/toolbox/feature/MagicType.js +18 -13
  145. package/src/coord/Axis.js +48 -13
  146. package/src/coord/axisDefault.js +25 -1
  147. package/src/coord/axisTickLabelBuilder.js +10 -0
  148. package/src/coord/cartesian/Cartesian2D.js +0 -13
  149. package/src/coord/geo/geoJSONLoader.js +2 -2
  150. package/src/coord/polar/polarCreator.js +16 -3
  151. package/src/coord/radar/Radar.js +3 -1
  152. package/src/coord/radar/RadarModel.js +5 -2
  153. package/src/data/DataDiffer.js +1 -4
  154. package/src/data/DataDimensionInfo.js +135 -0
  155. package/src/data/Graph.js +1 -1
  156. package/src/data/List.js +33 -20
  157. package/src/data/Tree.js +3 -1
  158. package/src/data/helper/completeDimensions.js +49 -30
  159. package/src/data/helper/createDimensions.js +2 -0
  160. package/src/data/helper/sourceHelper.js +216 -124
  161. package/src/echarts.js +2 -2
  162. package/src/layout/barGrid.js +136 -13
  163. package/src/layout/barPolar.js +3 -2
  164. package/src/model/Global.js +1 -1
  165. package/src/model/Series.js +3 -3
  166. package/src/model/referHelper.js +34 -11
  167. package/src/scale/Interval.js +84 -4
  168. package/src/scale/Log.js +9 -2
  169. package/src/scale/helper.js +1 -39
  170. package/src/theme/dark.js +3 -0
  171. package/src/util/graphic.js +1 -2
  172. package/src/util/number.js +22 -2
  173. package/src/util/shape/sausage.js +93 -0
  174. package/src/visual/LegendVisualProvider.js +55 -0
  175. package/src/visual/dataColor.js +0 -13
  176. package/src/visual/seriesColor.js +13 -7
  177. package/theme/azul.js +163 -0
  178. package/theme/bee-inspired.js +178 -0
  179. package/theme/blue.js +178 -0
  180. package/theme/caravan.js +178 -0
  181. package/theme/carp.js +163 -0
  182. package/theme/cool.js +180 -0
  183. package/theme/dark-blue.js +168 -0
  184. package/theme/dark-bold.js +168 -0
  185. package/theme/dark-digerati.js +168 -0
  186. package/theme/dark-fresh-cut.js +168 -0
  187. package/theme/dark-mushroom.js +168 -0
  188. package/theme/dark.js +69 -62
  189. package/theme/eduardo.js +178 -0
  190. package/theme/forest.js +163 -0
  191. package/theme/fresh-cut.js +163 -0
  192. package/theme/fruit.js +178 -0
  193. package/theme/gray.js +220 -0
  194. package/theme/green.js +222 -0
  195. package/theme/helianthus.js +263 -0
  196. package/theme/infographic.js +72 -57
  197. package/theme/inspired.js +163 -0
  198. package/theme/jazz.js +163 -0
  199. package/theme/london.js +163 -0
  200. package/theme/macarons.js +80 -57
  201. package/theme/macarons2.js +251 -0
  202. package/theme/mint.js +155 -0
  203. package/theme/red-velvet.js +163 -0
  204. package/theme/red.js +225 -0
  205. package/theme/roma.js +55 -22
  206. package/theme/royal.js +163 -0
  207. package/theme/sakura.js +140 -0
  208. package/theme/shine.js +52 -45
  209. package/theme/tech-blue.js +180 -0
  210. package/theme/vintage.js +37 -23
  211. package/.travis.yml +0 -16
@@ -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
 
@@ -6839,23 +6948,31 @@ Style.prototype = {
6839
6948
 
6840
6949
  /**
6841
6950
  * Whether transform text.
6842
- * Only useful in Path and Image element
6951
+ * Only available in Path and Image element,
6952
+ * where the text is called as `RectText`.
6843
6953
  * @type {boolean}
6844
6954
  */
6845
6955
  transformText: false,
6846
6956
 
6847
6957
  /**
6848
- * Text rotate around position of Path or Image
6849
- * Only useful in Path and Image element and transformText is false.
6958
+ * Text rotate around position of Path or Image.
6959
+ * The origin of the rotation can be specified by `textOrigin`.
6960
+ * Only available in Path and Image element,
6961
+ * where the text is called as `RectText`.
6850
6962
  */
6851
6963
  textRotation: 0,
6852
6964
 
6853
6965
  /**
6854
- * Text origin of text rotation, like [10, 40].
6855
- * Based on x, y of rect.
6856
- * Useful in label rotation of circular symbol.
6857
- * By default, this origin is textPosition.
6858
- * Can be 'center'.
6966
+ * Text origin of text rotation.
6967
+ * Useful in the case like label rotation of circular symbol.
6968
+ * Only available in Path and Image element, where the text is called
6969
+ * as `RectText` and the element is called as "host element".
6970
+ * The value can be:
6971
+ * + If specified as a coordinate like `[10, 40]`, it is the `[x, y]`
6972
+ * base on the left-top corner of the rect of its host element.
6973
+ * + If specified as a string `center`, it is the center of the rect of
6974
+ * its host element.
6975
+ * + By default, this origin is the `textPosition`.
6859
6976
  * @type {string|Array.<number>}
6860
6977
  */
6861
6978
  textOrigin: null,
@@ -7528,6 +7645,7 @@ function calculateTextPosition(out, style, rect) {
7528
7645
 
7529
7646
  var x = rect.x;
7530
7647
  var y = rect.y;
7648
+ distance = distance || 0;
7531
7649
 
7532
7650
  var height = rect.height;
7533
7651
  var width = rect.width;
@@ -7780,8 +7898,11 @@ methods$1.measureText = function (text, font) {
7780
7898
  * @param {string} text
7781
7899
  * @param {string} font
7782
7900
  * @param {Object} [truncate]
7783
- * @return {Object} block: {lineHeight, lines, height, outerHeight}
7901
+ * @return {Object} block: {lineHeight, lines, height, outerHeight, canCacheByTextString}
7784
7902
  * Notice: for performance, do not calculate outerWidth util needed.
7903
+ * `canCacheByTextString` means the result `lines` is only determined by the input `text`.
7904
+ * Thus we can simply comparing the `input` text to determin whether the result changed,
7905
+ * without travel the result `lines`.
7785
7906
  */
7786
7907
  function parsePlainText(text, font, padding, textLineHeight, truncate) {
7787
7908
  text != null && (text += '');
@@ -7790,12 +7911,14 @@ function parsePlainText(text, font, padding, textLineHeight, truncate) {
7790
7911
  var lines = text ? text.split('\n') : [];
7791
7912
  var height = lines.length * lineHeight;
7792
7913
  var outerHeight = height;
7914
+ var canCacheByTextString = true;
7793
7915
 
7794
7916
  if (padding) {
7795
7917
  outerHeight += padding[0] + padding[2];
7796
7918
  }
7797
7919
 
7798
7920
  if (text && truncate) {
7921
+ canCacheByTextString = false;
7799
7922
  var truncOuterHeight = truncate.outerHeight;
7800
7923
  var truncOuterWidth = truncate.outerWidth;
7801
7924
  if (truncOuterHeight != null && outerHeight > truncOuterHeight) {
@@ -7822,7 +7945,8 @@ function parsePlainText(text, font, padding, textLineHeight, truncate) {
7822
7945
  lines: lines,
7823
7946
  height: height,
7824
7947
  outerHeight: outerHeight,
7825
- lineHeight: lineHeight
7948
+ lineHeight: lineHeight,
7949
+ canCacheByTextString: canCacheByTextString
7826
7950
  };
7827
7951
  }
7828
7952
 
@@ -8802,7 +8926,6 @@ RectText.prototype = {
8802
8926
  };
8803
8927
 
8804
8928
  /**
8805
- * 可绘制的图形基类
8806
8929
  * Base class of all displayable graphic objects
8807
8930
  * @module zrender/graphic/Displayable
8808
8931
  */
@@ -8851,16 +8974,15 @@ Displayable.prototype = {
8851
8974
  type: 'displayable',
8852
8975
 
8853
8976
  /**
8854
- * Displayable 是否为脏,Painter 中会根据该标记判断是否需要是否需要重新绘制
8855
- * Dirty flag. From which painter will determine if this displayable object needs brush
8977
+ * Dirty flag. From which painter will determine if this displayable object needs brush.
8856
8978
  * @name module:zrender/graphic/Displayable#__dirty
8857
8979
  * @type {boolean}
8858
8980
  */
8859
8981
  __dirty: true,
8860
8982
 
8861
8983
  /**
8862
- * 图形是否可见,为true时不绘制图形,但是仍能触发鼠标事件
8863
- * If ignore drawing of the displayable object. Mouse event will still be triggered
8984
+ * Whether the displayable object is visible. when it is true, the displayable object
8985
+ * is not drawn, but the mouse event can still trigger the object.
8864
8986
  * @name module:/zrender/graphic/Displayable#invisible
8865
8987
  * @type {boolean}
8866
8988
  * @default false
@@ -8882,7 +9004,7 @@ Displayable.prototype = {
8882
9004
  z2: 0,
8883
9005
 
8884
9006
  /**
8885
- * zlevel,决定绘画在哪层canvas
9007
+ * The z level determines the displayable object can be drawn in which layer canvas.
8886
9008
  * @name module:/zrender/graphic/Displayable#zlevel
8887
9009
  * @type {number}
8888
9010
  * @default 0
@@ -8890,7 +9012,7 @@ Displayable.prototype = {
8890
9012
  zlevel: 0,
8891
9013
 
8892
9014
  /**
8893
- * 是否可拖拽
9015
+ * Whether it can be dragged.
8894
9016
  * @name module:/zrender/graphic/Displayable#draggable
8895
9017
  * @type {boolean}
8896
9018
  * @default false
@@ -8898,7 +9020,7 @@ Displayable.prototype = {
8898
9020
  draggable: false,
8899
9021
 
8900
9022
  /**
8901
- * 是否正在拖拽
9023
+ * Whether is it dragging.
8902
9024
  * @name module:/zrender/graphic/Displayable#draggable
8903
9025
  * @type {boolean}
8904
9026
  * @default false
@@ -8906,7 +9028,7 @@ Displayable.prototype = {
8906
9028
  dragging: false,
8907
9029
 
8908
9030
  /**
8909
- * 是否相应鼠标事件
9031
+ * Whether to respond to mouse events.
8910
9032
  * @name module:/zrender/graphic/Displayable#silent
8911
9033
  * @type {boolean}
8912
9034
  * @default false
@@ -8956,21 +9078,20 @@ Displayable.prototype = {
8956
9078
  afterBrush: function (ctx) {},
8957
9079
 
8958
9080
  /**
8959
- * 图形绘制方法
9081
+ * Graphic drawing method.
8960
9082
  * @param {CanvasRenderingContext2D} ctx
8961
9083
  */
8962
9084
  // Interface
8963
9085
  brush: function (ctx, prevEl) {},
8964
9086
 
8965
9087
  /**
8966
- * 获取最小包围盒
9088
+ * Get the minimum bounding box.
8967
9089
  * @return {module:zrender/core/BoundingRect}
8968
9090
  */
8969
9091
  // Interface
8970
9092
  getBoundingRect: function () {},
8971
9093
 
8972
9094
  /**
8973
- * 判断坐标 x, y 是否在图形上
8974
9095
  * If displayable element contain coord x, y
8975
9096
  * @param {number} x
8976
9097
  * @param {number} y
@@ -8989,7 +9110,6 @@ Displayable.prototype = {
8989
9110
  },
8990
9111
 
8991
9112
  /**
8992
- * 判断坐标 x, y 是否在图形的包围盒上
8993
9113
  * If bounding rect of element contain coord x, y
8994
9114
  * @param {number} x
8995
9115
  * @param {number} y
@@ -9002,7 +9122,6 @@ Displayable.prototype = {
9002
9122
  },
9003
9123
 
9004
9124
  /**
9005
- * 标记图形元素为脏,并且在下一帧重绘
9006
9125
  * Mark displayable element dirty and refresh next frame
9007
9126
  */
9008
9127
  dirty: function () {
@@ -9014,11 +9133,10 @@ Displayable.prototype = {
9014
9133
  },
9015
9134
 
9016
9135
  /**
9017
- * 图形是否会触发事件
9018
9136
  * If displayable object binded any event
9019
9137
  * @return {boolean}
9020
9138
  */
9021
- // TODO, 通过 bind 绑定的事件
9139
+ // TODO, events bound by bind
9022
9140
  // isSilent: function () {
9023
9141
  // return !(
9024
9142
  // this.hoverable || this.draggable
@@ -9270,10 +9388,16 @@ function doClip(clipPaths, ctx) {
9270
9388
  function createRoot(width, height) {
9271
9389
  var domRoot = document.createElement('div');
9272
9390
 
9273
- // domRoot.onselectstart = returnFalse; // 避免页面选中的尴尬
9391
+ // domRoot.onselectstart = returnFalse; // Avoid page selected
9274
9392
  domRoot.style.cssText = [
9275
9393
  'position:relative',
9276
- 'overflow:hidden',
9394
+ // IOS13 safari probably has a compositing bug (z order of the canvas and the consequent
9395
+ // dom does not act as expected) when some of the parent dom has
9396
+ // `-webkit-overflow-scrolling: touch;` and the webpage is longer than one screen and
9397
+ // the canvas is not at the top part of the page.
9398
+ // Check `https://bugs.webkit.org/show_bug.cgi?id=203681` for more details. We remove
9399
+ // this `overflow:hidden` to avoid the bug.
9400
+ // 'overflow:hidden',
9277
9401
  'width:' + width + 'px',
9278
9402
  'height:' + height + 'px',
9279
9403
  'padding:0',
@@ -10496,30 +10620,55 @@ Animation.prototype = {
10496
10620
 
10497
10621
  mixin(Animation, Eventful);
10498
10622
 
10623
+ /* global document */
10624
+
10499
10625
  var TOUCH_CLICK_DELAY = 300;
10500
10626
 
10501
- var mouseHandlerNames = [
10502
- 'click', 'dblclick', 'mousewheel', 'mouseout',
10503
- 'mouseup', 'mousedown', 'mousemove', 'contextmenu'
10504
- ];
10627
+ var globalEventSupported = env$1.domSupported;
10505
10628
 
10506
- var touchHandlerNames = [
10507
- 'touchstart', 'touchend', 'touchmove'
10508
- ];
10509
10629
 
10510
- var pointerEventNames = {
10511
- 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']
10512
10656
  };
10513
10657
 
10514
- var pointerHandlerNames = map(mouseHandlerNames, function (name) {
10515
- var nm = name.replace('mouse', 'pointer');
10516
- return pointerEventNames[nm] ? nm : name;
10517
- });
10518
10658
 
10519
10659
  function eventNameFix(name) {
10520
10660
  return (name === 'mousewheel' && env$1.browser.firefox) ? 'DOMMouseScroll' : name;
10521
10661
  }
10522
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
+
10523
10672
  // function onMSGestureChange(proxy, event) {
10524
10673
  // if (event.translationX || event.translationY) {
10525
10674
  // // mousemove is carried by MSGesture to reduce the sensitivity.
@@ -10539,117 +10688,174 @@ function eventNameFix(name) {
10539
10688
  * 1. Mobile browsers dispatch mouse events 300ms after touchend.
10540
10689
  * 2. Chrome for Android dispatch mousedown for long-touch about 650ms
10541
10690
  * Result: Blocking Mouse Events for 700ms.
10691
+ *
10692
+ * @param {DOMHandlerScope} scope
10542
10693
  */
10543
- function setTouchTimer(instance) {
10544
- instance._touching = true;
10545
- clearTimeout(instance._touchTimer);
10546
- instance._touchTimer = setTimeout(function () {
10547
- 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;
10548
10703
  }, 700);
10549
10704
  }
10550
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
+ },
10551
10779
 
10552
- var domHandlers = {
10553
- /**
10554
- * Mouse move handler
10555
- * @inner
10556
- * @param {Event} event
10557
- */
10558
10780
  mousemove: function (event) {
10559
10781
  event = normalizeEvent(this.dom, event);
10560
10782
 
10783
+ var downPoint = this._mayPointerCapture;
10784
+ if (downPoint && (event.zrX !== downPoint[0] || event.zrY !== downPoint[1])) {
10785
+ togglePointerCapture(this, true);
10786
+ }
10787
+
10561
10788
  this.trigger('mousemove', event);
10562
10789
  },
10563
10790
 
10564
- /**
10565
- * Mouse out handler
10566
- * @inner
10567
- * @param {Event} event
10568
- */
10569
- mouseout: function (event) {
10791
+ mouseup: function (event) {
10570
10792
  event = normalizeEvent(this.dom, event);
10571
10793
 
10572
- var element = event.toElement || event.relatedTarget;
10573
- if (element !== this.dom) {
10574
- while (element && element.nodeType !== 9) {
10575
- // 忽略包含在root中的dom引起的mouseOut
10576
- if (element === this.dom) {
10577
- return;
10578
- }
10794
+ togglePointerCapture(this, false);
10579
10795
 
10580
- element = element.parentNode;
10581
- }
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';
10582
10806
  }
10583
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
+
10584
10816
  this.trigger('mouseout', event);
10585
10817
  },
10586
10818
 
10587
- /**
10588
- * Touch开始响应函数
10589
- * @inner
10590
- * @param {Event} event
10591
- */
10592
10819
  touchstart: function (event) {
10593
10820
  // Default mouse behaviour should not be disabled here.
10594
10821
  // For example, page may needs to be slided.
10595
10822
  event = normalizeEvent(this.dom, event);
10596
10823
 
10597
- // Mark touch, which is useful in distinguish touch and
10598
- // mouse event in upper applicatoin.
10599
- event.zrByTouch = true;
10824
+ markTouch(event);
10600
10825
 
10601
10826
  this._lastTouchMoment = new Date();
10602
10827
 
10603
- this.handler.processGesture(this, event, 'start');
10828
+ this.handler.processGesture(event, 'start');
10604
10829
 
10605
- // In touch device, trigger `mousemove`(`mouseover`) should
10606
- // be triggered, and must before `mousedown` triggered.
10607
- domHandlers.mousemove.call(this, event);
10608
-
10609
- domHandlers.mousedown.call(this, event);
10610
-
10611
- 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);
10612
10836
  },
10613
10837
 
10614
- /**
10615
- * Touch移动响应函数
10616
- * @inner
10617
- * @param {Event} event
10618
- */
10619
10838
  touchmove: function (event) {
10620
-
10621
10839
  event = normalizeEvent(this.dom, event);
10622
10840
 
10623
- // Mark touch, which is useful in distinguish touch and
10624
- // mouse event in upper applicatoin.
10625
- event.zrByTouch = true;
10841
+ markTouch(event);
10626
10842
 
10627
- this.handler.processGesture(this, event, 'change');
10843
+ this.handler.processGesture(event, 'change');
10628
10844
 
10629
10845
  // Mouse move should always be triggered no matter whether
10630
10846
  // there is gestrue event, because mouse move and pinch may
10631
10847
  // be used at the same time.
10632
- domHandlers.mousemove.call(this, event);
10633
-
10634
- setTouchTimer(this);
10848
+ localDOMHandlers.mousemove.call(this, event);
10635
10849
  },
10636
10850
 
10637
- /**
10638
- * Touch结束响应函数
10639
- * @inner
10640
- * @param {Event} event
10641
- */
10642
10851
  touchend: function (event) {
10643
-
10644
10852
  event = normalizeEvent(this.dom, event);
10645
10853
 
10646
- // Mark touch, which is useful in distinguish touch and
10647
- // mouse event in upper applicatoin.
10648
- event.zrByTouch = true;
10854
+ markTouch(event);
10649
10855
 
10650
- this.handler.processGesture(this, event, 'end');
10856
+ this.handler.processGesture(event, 'end');
10651
10857
 
10652
- domHandlers.mouseup.call(this, event);
10858
+ localDOMHandlers.mouseup.call(this, event);
10653
10859
 
10654
10860
  // Do not trigger `mouseout` here, in spite of `mousemove`(`mouseover`) is
10655
10861
  // triggered in `touchstart`. This seems to be illogical, but by this mechanism,
@@ -10662,14 +10868,12 @@ var domHandlers = {
10662
10868
  // click event should always be triggered no matter whether
10663
10869
  // there is gestrue event. System click can not be prevented.
10664
10870
  if (+new Date() - this._lastTouchMoment < TOUCH_CLICK_DELAY) {
10665
- domHandlers.click.call(this, event);
10871
+ localDOMHandlers.click.call(this, event);
10666
10872
  }
10667
-
10668
- setTouchTimer(this);
10669
10873
  },
10670
10874
 
10671
10875
  pointerdown: function (event) {
10672
- domHandlers.mousedown.call(this, event);
10876
+ localDOMHandlers.mousedown.call(this, event);
10673
10877
 
10674
10878
  // if (useMSGuesture(this, event)) {
10675
10879
  // this._msGesture.addPointer(event.pointerId);
@@ -10683,12 +10887,12 @@ var domHandlers = {
10683
10887
  // upper application. So, we dont support mousemove on MS touch
10684
10888
  // device yet.
10685
10889
  if (!isPointerFromTouch(event)) {
10686
- domHandlers.mousemove.call(this, event);
10890
+ localDOMHandlers.mousemove.call(this, event);
10687
10891
  }
10688
10892
  },
10689
10893
 
10690
10894
  pointerup: function (event) {
10691
- domHandlers.mouseup.call(this, event);
10895
+ localDOMHandlers.mouseup.call(this, event);
10692
10896
  },
10693
10897
 
10694
10898
  pointerout: function (event) {
@@ -10696,80 +10900,77 @@ var domHandlers = {
10696
10900
  // (IE11+/Edge on MS Surface) after click event triggered,
10697
10901
  // which is inconsistent with the mousout behavior we defined
10698
10902
  // in touchend. So we unify them.
10699
- // (check domHandlers.touchend for detailed explanation)
10903
+ // (check localDOMHandlers.touchend for detailed explanation)
10700
10904
  if (!isPointerFromTouch(event)) {
10701
- domHandlers.mouseout.call(this, event);
10905
+ localDOMHandlers.mouseout.call(this, event);
10702
10906
  }
10703
10907
  }
10704
- };
10705
10908
 
10706
- function isPointerFromTouch(event) {
10707
- var pointerType = event.pointerType;
10708
- return pointerType === 'pen' || pointerType === 'touch';
10709
- }
10710
-
10711
- // function useMSGuesture(handlerProxy, event) {
10712
- // return isPointerFromTouch(event) && !!handlerProxy._msGesture;
10713
- // }
10909
+ };
10714
10910
 
10715
- // Common handlers
10716
- each$1(['click', 'mousedown', 'mouseup', 'mousewheel', 'dblclick', 'contextmenu'], function (name) {
10717
- 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) {
10718
10917
  event = normalizeEvent(this.dom, event);
10719
10918
  this.trigger(name, event);
10720
10919
  };
10721
10920
  });
10722
10921
 
10922
+
10723
10923
  /**
10724
- * 为控制类实例初始化dom 事件处理函数
10924
+ * DOM UI Event handlers for global page.
10725
10925
  *
10726
- * @inner
10727
- * @param {module:zrender/Handler} instance 控制类实例
10926
+ * [Caution]:
10927
+ * those handlers should both support in capture phase and bubble phase!
10928
+ *
10929
+ * @this {HandlerProxy}
10728
10930
  */
10729
- function initDomHandler(instance) {
10730
- each$1(touchHandlerNames, function (name) {
10731
- instance._handlers[name] = bind(domHandlers[name], instance);
10732
- });
10931
+ var globalDOMHandlers = {
10733
10932
 
10734
- each$1(pointerHandlerNames, function (name) {
10735
- instance._handlers[name] = bind(domHandlers[name], instance);
10736
- });
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
+ },
10737
10943
 
10738
- each$1(mouseHandlerNames, function (name) {
10739
- instance._handlers[name] = makeMouseHandler(domHandlers[name], instance);
10740
- });
10944
+ pointerup: function (event) {
10945
+ globalDOMHandlers.mouseup.call(this, event);
10946
+ },
10741
10947
 
10742
- function makeMouseHandler(fn, instance) {
10743
- return function () {
10744
- if (instance._touching) {
10745
- return;
10746
- }
10747
- return fn.apply(instance, arguments);
10748
- };
10749
- }
10750
- }
10948
+ mousemove: function (event) {
10949
+ this.trigger('mousemove', event);
10950
+ },
10751
10951
 
10952
+ mouseup: function (event) {
10953
+ var pointerCaptureReleasing = this._pointerCapturing;
10752
10954
 
10753
- function HandlerDomProxy(dom) {
10754
- Eventful.call(this);
10955
+ togglePointerCapture(this, false);
10755
10956
 
10756
- this.dom = dom;
10957
+ this.trigger('mouseup', event);
10757
10958
 
10758
- /**
10759
- * @private
10760
- * @type {boolean}
10761
- */
10762
- this._touching = false;
10959
+ if (pointerCaptureReleasing) {
10960
+ event.zrEventControl = 'only_globalout';
10961
+ this.trigger('mouseout', event);
10962
+ }
10963
+ }
10763
10964
 
10764
- /**
10765
- * @private
10766
- * @type {number}
10767
- */
10768
- this._touchTimer;
10965
+ };
10769
10966
 
10770
- this._handlers = {};
10771
10967
 
10772
- initDomHandler(this);
10968
+ /**
10969
+ * @param {HandlerProxy} instance
10970
+ * @param {DOMHandlerScope} scope
10971
+ */
10972
+ function mountLocalDOMEventListeners(instance, scope) {
10973
+ var domHandlers = scope.domHandlers;
10773
10974
 
10774
10975
  if (env$1.pointerEventsSupported) { // Only IE11+/Edge
10775
10976
  // 1. On devices that both enable touch and mouse (e.g., MS Surface and lenovo X240),
@@ -10778,7 +10979,12 @@ function HandlerDomProxy(dom) {
10778
10979
  // 2. On MS Surface, it probablely only trigger mousedown but no mouseup when tap on
10779
10980
  // screen, which do not occurs in pointer event.
10780
10981
  // So we use pointer event to both detect touch gesture and mouse behavior.
10781
- 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
+ });
10782
10988
 
10783
10989
  // FIXME
10784
10990
  // Note: MS Gesture require CSS touch-action set. But touch-action is not reliable,
@@ -10797,7 +11003,13 @@ function HandlerDomProxy(dom) {
10797
11003
  }
10798
11004
  else {
10799
11005
  if (env$1.touchEventsSupported) {
10800
- 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
+ });
10801
11013
  // Handler of 'mouseout' event is needed in touch mode, which will be mounted below.
10802
11014
  // addEventListener(root, 'mouseout', this._mouseoutHandler);
10803
11015
  }
@@ -10807,23 +11019,145 @@ function HandlerDomProxy(dom) {
10807
11019
  // mouse event can not be handle in those devices.
10808
11020
  // 2. On MS Surface, Chrome will trigger both touch event and mouse event. How to prevent
10809
11021
  // mouseevent after touch event triggered, see `setTouchTimer`.
10810
- 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
+ });
10811
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);
11107
+ }
11108
+ }
11109
+
11110
+ /**
11111
+ * @inner
11112
+ * @class
11113
+ */
11114
+ function DOMHandlerScope(domTarget, domHandlers) {
11115
+ this.domTarget = domTarget;
11116
+ this.domHandlers = domHandlers;
10812
11117
 
10813
- function mountHandlers(handlerNames, instance) {
10814
- each$1(handlerNames, function (name) {
10815
- addEventListener(dom, eventNameFix(name), instance._handlers[name]);
10816
- }, instance);
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;
11136
+
11137
+ this._localHandlerScope = new DOMHandlerScope(dom, localDOMHandlers);
11138
+
11139
+ if (globalEventSupported) {
11140
+ this._globalHandlerScope = new DOMHandlerScope(document, globalDOMHandlers);
10817
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);
10818
11153
  }
10819
11154
 
10820
11155
  var handlerDomProxyProto = HandlerDomProxy.prototype;
10821
- handlerDomProxyProto.dispose = function () {
10822
- var handlerNames = mouseHandlerNames.concat(touchHandlerNames);
10823
11156
 
10824
- for (var i = 0; i < handlerNames.length; i++) {
10825
- var name = handlerNames[i];
10826
- removeEventListener(this.dom, eventNameFix(name), this._handlers[name]);
11157
+ handlerDomProxyProto.dispose = function () {
11158
+ unmountDOMEventListeners(this._localHandlerScope);
11159
+ if (globalEventSupported) {
11160
+ unmountDOMEventListeners(this._globalHandlerScope);
10827
11161
  }
10828
11162
  };
10829
11163
 
@@ -10831,6 +11165,7 @@ handlerDomProxyProto.setCursor = function (cursorStyle) {
10831
11165
  this.dom.style && (this.dom.style.cursor = cursorStyle || 'default');
10832
11166
  };
10833
11167
 
11168
+
10834
11169
  mixin(HandlerDomProxy, Eventful);
10835
11170
 
10836
11171
  /*!
@@ -10852,7 +11187,7 @@ var painterCtors = {
10852
11187
  /**
10853
11188
  * @type {string}
10854
11189
  */
10855
- var version$1 = '4.1.1';
11190
+ var version$1 = '4.2.0';
10856
11191
 
10857
11192
  /**
10858
11193
  * Initializing a zrender instance
@@ -10931,7 +11266,7 @@ var ZRender = function (id, dom, opts) {
10931
11266
  this.storage = storage;
10932
11267
  this.painter = painter;
10933
11268
 
10934
- 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;
10935
11270
  this.handler = new Handler(storage, painter, handerProxy, painter.root);
10936
11271
 
10937
11272
  /**
@@ -17410,8 +17745,7 @@ function rollbackDefaultTextStyle(style) {
17410
17745
  }
17411
17746
 
17412
17747
  function getFont(opt, ecModel) {
17413
- // ecModel or default text style model.
17414
- var gTextStyleModel = ecModel || ecModel.getModel('textStyle');
17748
+ var gTextStyleModel = ecModel && ecModel.getModel('textStyle');
17415
17749
  return trim([
17416
17750
  // FIXME in node-canvas fontWeight is before fontStyle
17417
17751
  opt.fontStyle || gTextStyleModel && gTextStyleModel.getShallow('fontStyle') || '',
@@ -18708,8 +19042,28 @@ function quantity(val) {
18708
19042
  return Math.pow(10, quantityExponent(val));
18709
19043
  }
18710
19044
 
19045
+ /**
19046
+ * Exponent of the quantity of a number
19047
+ * e.g., 1234 equals to 1.234*10^3, so quantityExponent(1234) is 3
19048
+ *
19049
+ * @param {number} val non-negative value
19050
+ * @return {number}
19051
+ */
18711
19052
  function quantityExponent(val) {
18712
- return Math.floor(Math.log(val) / Math.LN10);
19053
+ if (val === 0) {
19054
+ return 0;
19055
+ }
19056
+
19057
+ var exp = Math.floor(Math.log(val) / Math.LN10);
19058
+ /**
19059
+ * exp is expected to be the rounded-down result of the base-10 log of val.
19060
+ * But due to the precision loss with Math.log(val), we need to restore it
19061
+ * using 10^exp to make sure we can get val back from exp. #11249
19062
+ */
19063
+ if (val / Math.pow(10, exp) >= 10) {
19064
+ exp++;
19065
+ }
19066
+ return exp;
18713
19067
  }
18714
19068
 
18715
19069
  /**
@@ -19911,178 +20265,6 @@ var colorPaletteMixin = {
19911
20265
  * under the License.
19912
20266
  */
19913
20267
 
19914
- /**
19915
- * Helper for model references.
19916
- * There are many manners to refer axis/coordSys.
19917
- */
19918
-
19919
- // TODO
19920
- // merge relevant logic to this file?
19921
- // check: "modelHelper" of tooltip and "BrushTargetManager".
19922
-
19923
- /**
19924
- * @return {Object} For example:
19925
- * {
19926
- * coordSysName: 'cartesian2d',
19927
- * coordSysDims: ['x', 'y', ...],
19928
- * axisMap: HashMap({
19929
- * x: xAxisModel,
19930
- * y: yAxisModel
19931
- * }),
19932
- * categoryAxisMap: HashMap({
19933
- * x: xAxisModel,
19934
- * y: undefined
19935
- * }),
19936
- * // It also indicate that whether there is category axis.
19937
- * firstCategoryDimIndex: 1,
19938
- * // To replace user specified encode.
19939
- * }
19940
- */
19941
- function getCoordSysDefineBySeries(seriesModel) {
19942
- var coordSysName = seriesModel.get('coordinateSystem');
19943
- var result = {
19944
- coordSysName: coordSysName,
19945
- coordSysDims: [],
19946
- axisMap: createHashMap(),
19947
- categoryAxisMap: createHashMap()
19948
- };
19949
- var fetch = fetchers[coordSysName];
19950
- if (fetch) {
19951
- fetch(seriesModel, result, result.axisMap, result.categoryAxisMap);
19952
- return result;
19953
- }
19954
- }
19955
-
19956
- var fetchers = {
19957
-
19958
- cartesian2d: function (seriesModel, result, axisMap, categoryAxisMap) {
19959
- var xAxisModel = seriesModel.getReferringComponents('xAxis')[0];
19960
- var yAxisModel = seriesModel.getReferringComponents('yAxis')[0];
19961
-
19962
- if (__DEV__) {
19963
- if (!xAxisModel) {
19964
- throw new Error('xAxis "' + retrieve(
19965
- seriesModel.get('xAxisIndex'),
19966
- seriesModel.get('xAxisId'),
19967
- 0
19968
- ) + '" not found');
19969
- }
19970
- if (!yAxisModel) {
19971
- throw new Error('yAxis "' + retrieve(
19972
- seriesModel.get('xAxisIndex'),
19973
- seriesModel.get('yAxisId'),
19974
- 0
19975
- ) + '" not found');
19976
- }
19977
- }
19978
-
19979
- result.coordSysDims = ['x', 'y'];
19980
- axisMap.set('x', xAxisModel);
19981
- axisMap.set('y', yAxisModel);
19982
-
19983
- if (isCategory(xAxisModel)) {
19984
- categoryAxisMap.set('x', xAxisModel);
19985
- result.firstCategoryDimIndex = 0;
19986
- }
19987
- if (isCategory(yAxisModel)) {
19988
- categoryAxisMap.set('y', yAxisModel);
19989
- result.firstCategoryDimIndex = 1;
19990
- }
19991
- },
19992
-
19993
- singleAxis: function (seriesModel, result, axisMap, categoryAxisMap) {
19994
- var singleAxisModel = seriesModel.getReferringComponents('singleAxis')[0];
19995
-
19996
- if (__DEV__) {
19997
- if (!singleAxisModel) {
19998
- throw new Error('singleAxis should be specified.');
19999
- }
20000
- }
20001
-
20002
- result.coordSysDims = ['single'];
20003
- axisMap.set('single', singleAxisModel);
20004
-
20005
- if (isCategory(singleAxisModel)) {
20006
- categoryAxisMap.set('single', singleAxisModel);
20007
- result.firstCategoryDimIndex = 0;
20008
- }
20009
- },
20010
-
20011
- polar: function (seriesModel, result, axisMap, categoryAxisMap) {
20012
- var polarModel = seriesModel.getReferringComponents('polar')[0];
20013
- var radiusAxisModel = polarModel.findAxisModel('radiusAxis');
20014
- var angleAxisModel = polarModel.findAxisModel('angleAxis');
20015
-
20016
- if (__DEV__) {
20017
- if (!angleAxisModel) {
20018
- throw new Error('angleAxis option not found');
20019
- }
20020
- if (!radiusAxisModel) {
20021
- throw new Error('radiusAxis option not found');
20022
- }
20023
- }
20024
-
20025
- result.coordSysDims = ['radius', 'angle'];
20026
- axisMap.set('radius', radiusAxisModel);
20027
- axisMap.set('angle', angleAxisModel);
20028
-
20029
- if (isCategory(radiusAxisModel)) {
20030
- categoryAxisMap.set('radius', radiusAxisModel);
20031
- result.firstCategoryDimIndex = 0;
20032
- }
20033
- if (isCategory(angleAxisModel)) {
20034
- categoryAxisMap.set('angle', angleAxisModel);
20035
- result.firstCategoryDimIndex = 1;
20036
- }
20037
- },
20038
-
20039
- geo: function (seriesModel, result, axisMap, categoryAxisMap) {
20040
- result.coordSysDims = ['lng', 'lat'];
20041
- },
20042
-
20043
- parallel: function (seriesModel, result, axisMap, categoryAxisMap) {
20044
- var ecModel = seriesModel.ecModel;
20045
- var parallelModel = ecModel.getComponent(
20046
- 'parallel', seriesModel.get('parallelIndex')
20047
- );
20048
- var coordSysDims = result.coordSysDims = parallelModel.dimensions.slice();
20049
-
20050
- each$1(parallelModel.parallelAxisIndex, function (axisIndex, index) {
20051
- var axisModel = ecModel.getComponent('parallelAxis', axisIndex);
20052
- var axisDim = coordSysDims[index];
20053
- axisMap.set(axisDim, axisModel);
20054
-
20055
- if (isCategory(axisModel) && result.firstCategoryDimIndex == null) {
20056
- categoryAxisMap.set(axisDim, axisModel);
20057
- result.firstCategoryDimIndex = index;
20058
- }
20059
- });
20060
- }
20061
- };
20062
-
20063
- function isCategory(axisModel) {
20064
- return axisModel.get('type') === 'category';
20065
- }
20066
-
20067
- /*
20068
- * Licensed to the Apache Software Foundation (ASF) under one
20069
- * or more contributor license agreements. See the NOTICE file
20070
- * distributed with this work for additional information
20071
- * regarding copyright ownership. The ASF licenses this file
20072
- * to you under the Apache License, Version 2.0 (the
20073
- * "License"); you may not use this file except in compliance
20074
- * with the License. You may obtain a copy of the License at
20075
- *
20076
- * http://www.apache.org/licenses/LICENSE-2.0
20077
- *
20078
- * Unless required by applicable law or agreed to in writing,
20079
- * software distributed under the License is distributed on an
20080
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
20081
- * KIND, either express or implied. See the License for the
20082
- * specific language governing permissions and limitations
20083
- * under the License.
20084
- */
20085
-
20086
20268
  // Avoid typo.
20087
20269
  var SOURCE_FORMAT_ORIGINAL = 'original';
20088
20270
  var SOURCE_FORMAT_ARRAY_ROWS = 'arrayRows';
@@ -20252,6 +20434,13 @@ enableClassCheck(Source);
20252
20434
  * under the License.
20253
20435
  */
20254
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
+
20255
20444
  var inner$3 = makeInner();
20256
20445
 
20257
20446
  /**
@@ -20385,14 +20574,6 @@ function prepareSource(seriesModel) {
20385
20574
  data, sourceFormat, seriesLayoutBy, sourceHeader, dimensionsDefine
20386
20575
  );
20387
20576
 
20388
- // Note: dataset option does not have `encode`.
20389
- var encodeDefine = seriesOption.encode;
20390
- if (!encodeDefine && datasetModel) {
20391
- encodeDefine = makeDefaultEncode(
20392
- seriesModel, datasetModel, data, sourceFormat, seriesLayoutBy, completeResult
20393
- );
20394
- }
20395
-
20396
20577
  inner$3(seriesModel).source = new Source({
20397
20578
  data: data,
20398
20579
  fromDataset: fromDataset,
@@ -20401,7 +20582,8 @@ function prepareSource(seriesModel) {
20401
20582
  dimensionsDefine: completeResult.dimensionsDefine,
20402
20583
  startIndex: completeResult.startIndex,
20403
20584
  dimensionsDetectCount: completeResult.dimensionsDetectCount,
20404
- encodeDefine: encodeDefine
20585
+ // Note: dataset option does not have `encode`.
20586
+ encodeDefine: seriesOption.encode
20405
20587
  });
20406
20588
  }
20407
20589
 
@@ -20413,7 +20595,6 @@ function completeBySourceData(data, sourceFormat, seriesLayoutBy, sourceHeader,
20413
20595
 
20414
20596
  var dimensionsDetectCount;
20415
20597
  var startIndex;
20416
- var findPotentialName;
20417
20598
 
20418
20599
  if (sourceFormat === SOURCE_FORMAT_ARRAY_ROWS) {
20419
20600
  // Rule: Most of the first line are string: it is header.
@@ -20456,13 +20637,11 @@ function completeBySourceData(data, sourceFormat, seriesLayoutBy, sourceHeader,
20456
20637
  else if (sourceFormat === SOURCE_FORMAT_OBJECT_ROWS) {
20457
20638
  if (!dimensionsDefine) {
20458
20639
  dimensionsDefine = objectRowsCollectDimensions(data);
20459
- findPotentialName = true;
20460
20640
  }
20461
20641
  }
20462
20642
  else if (sourceFormat === SOURCE_FORMAT_KEYED_COLUMNS) {
20463
20643
  if (!dimensionsDefine) {
20464
20644
  dimensionsDefine = [];
20465
- findPotentialName = true;
20466
20645
  each$1(data, function (colArr, key) {
20467
20646
  dimensionsDefine.push(key);
20468
20647
  });
@@ -20478,21 +20657,10 @@ function completeBySourceData(data, sourceFormat, seriesLayoutBy, sourceHeader,
20478
20657
  }
20479
20658
  }
20480
20659
 
20481
- var potentialNameDimIndex;
20482
- if (findPotentialName) {
20483
- each$1(dimensionsDefine, function (dim, idx) {
20484
- if ((isObject$1(dim) ? dim.name : dim) === 'name') {
20485
- potentialNameDimIndex = idx;
20486
- }
20487
- });
20488
- }
20489
-
20490
20660
  return {
20491
20661
  startIndex: startIndex,
20492
20662
  dimensionsDefine: normalizeDimensionsDefine(dimensionsDefine),
20493
- dimensionsDetectCount: dimensionsDetectCount,
20494
- potentialNameDimIndex: potentialNameDimIndex
20495
- // TODO: potentialIdDimIdx
20663
+ dimensionsDetectCount: dimensionsDetectCount
20496
20664
  };
20497
20665
  }
20498
20666
 
@@ -20566,107 +20734,202 @@ function objectRowsCollectDimensions(data) {
20566
20734
  }
20567
20735
  }
20568
20736
 
20569
- // ??? TODO merge to completedimensions, where also has
20570
- // default encode making logic. And the default rule
20571
- // should depends on series? consider 'map'.
20572
- function makeDefaultEncode(
20573
- seriesModel, datasetModel, data, sourceFormat, seriesLayoutBy, completeResult
20574
- ) {
20575
- 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) {
20576
20756
  var encode = {};
20577
- // var encodeTooltip = [];
20578
- // 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
+
20579
20764
  var encodeItemName = [];
20580
20765
  var encodeSeriesName = [];
20581
- var seriesType = seriesModel.subType;
20582
-
20583
- // ??? TODO refactor: provide by series itself.
20584
- // Consider the case: 'map' series is based on geo coordSys,
20585
- // 'graph', 'heatmap' can be based on cartesian. But can not
20586
- // give default rule simply here.
20587
- var nSeriesMap = createHashMap(['pie', 'map', 'funnel']);
20588
- var cSeriesMap = createHashMap([
20589
- 'line', 'bar', 'pictorialBar', 'scatter', 'effectScatter', 'candlestick', 'boxplot'
20590
- ]);
20591
-
20592
- // Usually in this case series will use the first data
20593
- // dimension as the "value" dimension, or other default
20594
- // processes respectively.
20595
- if (coordSysDefine && cSeriesMap.get(seriesType) != null) {
20596
- var ecModel = seriesModel.ecModel;
20597
- var datasetMap = inner$3(ecModel).datasetMap;
20598
- var key = datasetModel.uid + '_' + seriesLayoutBy;
20599
- var datasetRecord = datasetMap.get(key)
20600
- || datasetMap.set(key, {categoryWayDim: 1, valueWayDim: 0});
20601
20766
 
20602
- // TODO
20603
- // Auto detect first time axis and do arrangement.
20604
- each$1(coordSysDefine.coordSysDims, function (coordDim) {
20605
- // In value way.
20606
- if (coordSysDefine.firstCategoryDimIndex == null) {
20607
- var dataDim = datasetRecord.valueWayDim++;
20608
- encode[coordDim] = dataDim;
20609
-
20610
- // ??? TODO give a better default series name rule?
20611
- // especially when encode x y specified.
20612
- // consider: when mutiple series share one dimension
20613
- // category axis, series name should better use
20614
- // the other dimsion name. On the other hand, use
20615
- // both dimensions name.
20616
-
20617
- encodeSeriesName.push(dataDim);
20618
- // encodeTooltip.push(dataDim);
20619
- // encodeLabel.push(dataDim);
20620
- }
20621
- // In category way, category axis.
20622
- else if (coordSysDefine.categoryAxisMap.get(coordDim)) {
20623
- encode[coordDim] = 0;
20624
- encodeItemName.push(0);
20625
- }
20626
- // In category way, non-category axis.
20627
- else {
20628
- var dataDim = datasetRecord.categoryWayDim++;
20629
- encode[coordDim] = dataDim;
20630
- // encodeTooltip.push(dataDim);
20631
- // encodeLabel.push(dataDim);
20632
- encodeSeriesName.push(dataDim);
20633
- }
20634
- });
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
+ }
20824
+ }
20825
+
20826
+ function getDataDimCountOnCoordDim(coordDimInfo) {
20827
+ var dimsDef = coordDimInfo.dimsDef;
20828
+ return dimsDef ? dimsDef.length : 1;
20635
20829
  }
20636
- // Do not make a complex rule! Hard to code maintain and not necessary.
20637
- // ??? TODO refactor: provide by series itself.
20638
- // [{name: ..., value: ...}, ...] like:
20639
- else if (nSeriesMap.get(seriesType) != null) {
20640
- // Find the first not ordinal. (5 is an experience value)
20641
- var firstNotOrdinal;
20642
- for (var i = 0; i < 5 && firstNotOrdinal == null; i++) {
20643
- if (!doGuessOrdinal(
20644
- data, sourceFormat, seriesLayoutBy,
20645
- completeResult.dimensionsDefine, completeResult.startIndex, i
20646
- )) {
20647
- firstNotOrdinal = i;
20648
- }
20649
- }
20650
- if (firstNotOrdinal != null) {
20651
- encode.value = firstNotOrdinal;
20652
- var nameDimIndex = completeResult.potentialNameDimIndex
20653
- || Math.max(firstNotOrdinal - 1, 0);
20654
- // By default, label use itemName in charts.
20655
- // So we dont set encodeLabel here.
20656
- encodeSeriesName.push(nameDimIndex);
20657
- encodeItemName.push(nameDimIndex);
20658
- // encodeTooltip.push(firstNotOrdinal);
20659
- }
20660
- }
20661
-
20662
- // encodeTooltip.length && (encode.tooltip = encodeTooltip);
20663
- // encodeLabel.length && (encode.label = encodeLabel);
20830
+
20664
20831
  encodeItemName.length && (encode.itemName = encodeItemName);
20665
20832
  encodeSeriesName.length && (encode.seriesName = encodeSeriesName);
20666
20833
 
20667
20834
  return encode;
20668
20835
  }
20669
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
+
20670
20933
  /**
20671
20934
  * If return null/undefined, indicate that should not use datasetModel.
20672
20935
  */
@@ -20690,7 +20953,7 @@ function getDatasetModel(seriesModel) {
20690
20953
  *
20691
20954
  * @param {module:echars/data/Source} source
20692
20955
  * @param {number} dimIndex
20693
- * @return {boolean} Whether ordinal.
20956
+ * @return {BE_ORDINAL} guess result.
20694
20957
  */
20695
20958
  function guessOrdinal(source, dimIndex) {
20696
20959
  return doGuessOrdinal(
@@ -20704,6 +20967,7 @@ function guessOrdinal(source, dimIndex) {
20704
20967
  }
20705
20968
 
20706
20969
  // dimIndex may be overflow source data.
20970
+ // return {BE_ORDINAL}
20707
20971
  function doGuessOrdinal(
20708
20972
  data, sourceFormat, seriesLayoutBy, dimensionsDefine, startIndex, dimIndex
20709
20973
  ) {
@@ -20712,15 +20976,26 @@ function doGuessOrdinal(
20712
20976
  var maxLoop = 5;
20713
20977
 
20714
20978
  if (isTypedArray(data)) {
20715
- return false;
20979
+ return BE_ORDINAL.Not;
20716
20980
  }
20717
20981
 
20718
20982
  // When sourceType is 'objectRows' or 'keyedColumns', dimensionsDefine
20719
20983
  // always exists in source.
20720
20984
  var dimName;
20985
+ var dimType;
20721
20986
  if (dimensionsDefine) {
20722
- dimName = dimensionsDefine[dimIndex];
20723
- 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;
20724
20999
  }
20725
21000
 
20726
21001
  if (sourceFormat === SOURCE_FORMAT_ARRAY_ROWS) {
@@ -20743,7 +21018,7 @@ function doGuessOrdinal(
20743
21018
  }
20744
21019
  else if (sourceFormat === SOURCE_FORMAT_OBJECT_ROWS) {
20745
21020
  if (!dimName) {
20746
- return;
21021
+ return BE_ORDINAL.Not;
20747
21022
  }
20748
21023
  for (var i = 0; i < data.length && i < maxLoop; i++) {
20749
21024
  var item = data[i];
@@ -20754,11 +21029,11 @@ function doGuessOrdinal(
20754
21029
  }
20755
21030
  else if (sourceFormat === SOURCE_FORMAT_KEYED_COLUMNS) {
20756
21031
  if (!dimName) {
20757
- return;
21032
+ return BE_ORDINAL.Not;
20758
21033
  }
20759
21034
  var sample = data[dimName];
20760
21035
  if (!sample || isTypedArray(sample)) {
20761
- return false;
21036
+ return BE_ORDINAL.Not;
20762
21037
  }
20763
21038
  for (var i = 0; i < sample.length && i < maxLoop; i++) {
20764
21039
  if ((result = detectValue(sample[i])) != null) {
@@ -20771,7 +21046,7 @@ function doGuessOrdinal(
20771
21046
  var item = data[i];
20772
21047
  var val = getDataItemValue(item);
20773
21048
  if (!isArray(val)) {
20774
- return false;
21049
+ return BE_ORDINAL.Not;
20775
21050
  }
20776
21051
  if ((result = detectValue(val[dimIndex])) != null) {
20777
21052
  return result;
@@ -20780,17 +21055,18 @@ function doGuessOrdinal(
20780
21055
  }
20781
21056
 
20782
21057
  function detectValue(val) {
21058
+ var beStr = isString(val);
20783
21059
  // Consider usage convenience, '1', '2' will be treated as "number".
20784
21060
  // `isFinit('')` get `true`.
20785
21061
  if (val != null && isFinite(val) && val !== '') {
20786
- return false;
21062
+ return beStr ? BE_ORDINAL.Might : BE_ORDINAL.Not;
20787
21063
  }
20788
- else if (isString(val) && val !== '-') {
20789
- return true;
21064
+ else if (beStr && val !== '-') {
21065
+ return BE_ORDINAL.Must;
20790
21066
  }
20791
21067
  }
20792
21068
 
20793
- return false;
21069
+ return BE_ORDINAL.Not;
20794
21070
  }
20795
21071
 
20796
21072
  /*
@@ -20995,7 +21271,7 @@ var GlobalModel = Model.extend({
20995
21271
  mainType, resultItem.keyInfo.subType, true
20996
21272
  );
20997
21273
 
20998
- if (componentModel && componentModel instanceof ComponentModelClass) {
21274
+ if (componentModel && componentModel.constructor === ComponentModelClass) {
20999
21275
  componentModel.name = resultItem.keyInfo.name;
21000
21276
  // componentModel.settingTask && componentModel.settingTask.dirty();
21001
21277
  componentModel.mergeOption(newCptOption, this);
@@ -23537,11 +23813,11 @@ var SeriesModel = ComponentModel.extend({
23537
23813
  defaultOption: null,
23538
23814
 
23539
23815
  /**
23540
- * Data provided for legend
23541
- * @type {Function}
23816
+ * legend visual provider to the legend component
23817
+ * @type {Object}
23542
23818
  */
23543
23819
  // PENDING
23544
- legendDataProvider: null,
23820
+ legendVisualProvider: null,
23545
23821
 
23546
23822
  /**
23547
23823
  * Access path of color for visual
@@ -24630,25 +24906,30 @@ var seriesColor = {
24630
24906
  reset: function (seriesModel, ecModel) {
24631
24907
  var data = seriesModel.getData();
24632
24908
  var colorAccessPath = (seriesModel.visualColorAccessPath || 'itemStyle.color').split('.');
24633
- var color = seriesModel.get(colorAccessPath) // Set in itemStyle
24634
- || 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(
24635
24916
  // TODO series count changed.
24636
24917
  seriesModel.name, null, ecModel.getSeriesCount()
24637
- ); // Default color
24918
+ );
24919
+ }
24638
24920
 
24639
- // FIXME Set color function or use the platte color
24640
24921
  data.setVisual('color', color);
24641
-
24922
+
24642
24923
  var borderColorAccessPath = (seriesModel.visualBorderColorAccessPath || 'itemStyle.borderColor').split('.');
24643
24924
  var borderColor = seriesModel.get(borderColorAccessPath);
24644
24925
  data.setVisual('borderColor', borderColor);
24645
24926
 
24646
24927
  // Only visible series has each data be visual encoded
24647
24928
  if (!ecModel.isSeriesFiltered(seriesModel)) {
24648
- if (typeof color === 'function' && !(color instanceof Gradient)) {
24929
+ if (colorCallback) {
24649
24930
  data.each(function (idx) {
24650
24931
  data.setItemVisual(
24651
- idx, 'color', color(seriesModel.getDataParams(idx))
24932
+ idx, 'color', colorCallback(seriesModel.getDataParams(idx))
24652
24933
  );
24653
24934
  });
24654
24935
  }
@@ -25707,6 +25988,9 @@ var theme = {
25707
25988
  },
25708
25989
  crossStyle: {
25709
25990
  color: contrastColor
25991
+ },
25992
+ label: {
25993
+ color: '#000'
25710
25994
  }
25711
25995
  }
25712
25996
  },
@@ -26677,10 +26961,10 @@ var isFunction = isFunction$1;
26677
26961
  var isObject = isObject$1;
26678
26962
  var parseClassType = ComponentModel.parseClassType;
26679
26963
 
26680
- var version = '4.4.0';
26964
+ var version = '4.6.0';
26681
26965
 
26682
26966
  var dependencies = {
26683
- zrender: '4.1.1'
26967
+ zrender: '4.2.0'
26684
26968
  };
26685
26969
 
26686
26970
  var TEST_FRAME_REMAIN_TIME = 1;
@@ -29156,9 +29440,6 @@ DataDiffer.prototype = {
29156
29440
  initIndexMap(oldArr, oldDataIndexMap, oldDataKeyArr, '_oldKeyGetter', this);
29157
29441
  initIndexMap(newArr, newDataIndexMap, newDataKeyArr, '_newKeyGetter', this);
29158
29442
 
29159
- // Travel by inverted order to make sure order consistency
29160
- // when duplicate keys exists (consider newDataIndex.pop() below).
29161
- // For performance consideration, these code below do not look neat.
29162
29443
  for (i = 0; i < oldArr.length; i++) {
29163
29444
  var key = oldDataKeyArr[i];
29164
29445
  var idx = newDataIndexMap[key];
@@ -29170,7 +29451,7 @@ DataDiffer.prototype = {
29170
29451
  var len = idx.length;
29171
29452
  if (len) {
29172
29453
  len === 1 && (newDataIndexMap[key] = null);
29173
- idx = idx.unshift();
29454
+ idx = idx.shift();
29174
29455
  }
29175
29456
  else {
29176
29457
  newDataIndexMap[key] = null;
@@ -29390,6 +29671,138 @@ function mayLabelDimType(dimType) {
29390
29671
  * under the License.
29391
29672
  */
29392
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
+
29393
29806
  /* global Float64Array, Int32Array, Uint32Array, Uint16Array */
29394
29807
 
29395
29808
  /**
@@ -29467,13 +29880,9 @@ function transferProperties(target, source) {
29467
29880
  * @constructor
29468
29881
  * @alias module:echarts/data/List
29469
29882
  *
29470
- * @param {Array.<string|Object>} dimensions
29883
+ * @param {Array.<string|Object|module:data/DataDimensionInfo>} dimensions
29471
29884
  * For example, ['someDimName', {name: 'someDimName', type: 'someDimType'}, ...].
29472
29885
  * Dimensions should be concrete names like x, y, z, lng, lat, angle, radius
29473
- * Spetial fields: {
29474
- * ordinalMeta: <module:echarts/data/OrdinalMeta>
29475
- * createInvertedIndices: <boolean>
29476
- * }
29477
29886
  * @param {module:echarts/model/Model} hostModel
29478
29887
  */
29479
29888
  var List = function (dimensions, hostModel) {
@@ -29489,7 +29898,10 @@ var List = function (dimensions, hostModel) {
29489
29898
  var dimensionInfo = dimensions[i];
29490
29899
 
29491
29900
  if (isString(dimensionInfo)) {
29492
- dimensionInfo = {name: dimensionInfo};
29901
+ dimensionInfo = new DataDimensionInfo({name: dimensionInfo});
29902
+ }
29903
+ else if (!(dimensionInfo instanceof DataDimensionInfo)) {
29904
+ dimensionInfo = new DataDimensionInfo(dimensionInfo);
29493
29905
  }
29494
29906
 
29495
29907
  var dimensionName = dimensionInfo.name;
@@ -30470,14 +30882,14 @@ listProto.indexOfName = function (name) {
30470
30882
  * @return {number}
30471
30883
  */
30472
30884
  listProto.indexOfRawIndex = function (rawIndex) {
30473
- if (!this._indices) {
30474
- return rawIndex;
30475
- }
30476
-
30477
30885
  if (rawIndex >= this._rawCount || rawIndex < 0) {
30478
30886
  return -1;
30479
30887
  }
30480
30888
 
30889
+ if (!this._indices) {
30890
+ return rawIndex;
30891
+ }
30892
+
30481
30893
  // Indices are ascending
30482
30894
  var indices = this._indices;
30483
30895
 
@@ -30509,7 +30921,8 @@ listProto.indexOfRawIndex = function (rawIndex) {
30509
30921
  * @param {string} dim
30510
30922
  * @param {number} value
30511
30923
  * @param {number} [maxDistance=Infinity]
30512
- * @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.
30513
30926
  */
30514
30927
  listProto.indicesOfNearest = function (dim, value, maxDistance) {
30515
30928
  var storage = this._storage;
@@ -30524,23 +30937,35 @@ listProto.indicesOfNearest = function (dim, value, maxDistance) {
30524
30937
  maxDistance = Infinity;
30525
30938
  }
30526
30939
 
30527
- var minDist = Number.MAX_VALUE;
30940
+ var minDist = Infinity;
30528
30941
  var minDiff = -1;
30942
+ var nearestIndicesLen = 0;
30943
+
30944
+ // Check the test case of `test/ut/spec/data/List.js`.
30529
30945
  for (var i = 0, len = this.count(); i < len; i++) {
30530
- var diff = value - this.get(dim, i /*, stack */);
30946
+ var diff = value - this.get(dim, i);
30531
30947
  var dist = Math.abs(diff);
30532
- if (diff <= maxDistance && dist <= minDist) {
30533
- // For the case of two data are same on xAxis, which has sequence data.
30534
- // Show the nearest index
30535
- // https://github.com/ecomfe/echarts/issues/2869
30536
- 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
+ ) {
30537
30958
  minDist = dist;
30538
30959
  minDiff = diff;
30539
- nearestIndices.length = 0;
30960
+ nearestIndicesLen = 0;
30961
+ }
30962
+ if (diff === minDiff) {
30963
+ nearestIndices[nearestIndicesLen++] = i;
30540
30964
  }
30541
- nearestIndices.push(i);
30542
30965
  }
30543
30966
  }
30967
+ nearestIndices.length = nearestIndicesLen;
30968
+
30544
30969
  return nearestIndices;
30545
30970
  };
30546
30971
 
@@ -31414,8 +31839,12 @@ listProto.CHANGABLE_METHODS = ['filterSelf', 'selectRange'];
31414
31839
  /**
31415
31840
  * @see {module:echarts/test/ut/spec/data/completeDimensions}
31416
31841
  *
31417
- * Complete the dimensions array, by user defined `dimension` and `encode`,
31418
- * 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.
31419
31848
  * If no 'value' dimension specified, the first no-named dimension will be
31420
31849
  * named as 'value'.
31421
31850
  *
@@ -31431,32 +31860,20 @@ listProto.CHANGABLE_METHODS = ['filterSelf', 'selectRange'];
31431
31860
  * @param {Array.<Object|string>} [opt.dimsDef] option.series.dimensions User defined dimensions
31432
31861
  * For example: ['asdf', {name, type}, ...].
31433
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`.
31434
31868
  * @param {string} [opt.generateCoord] Generate coord dim with the given name.
31435
- * If not specified, extra dim names will be:
31436
- * 'value', 'value0', 'value1', ...
31869
+ * If not specified, extra dim names will be:
31870
+ * 'value', 'value0', 'value1', ...
31437
31871
  * @param {number} [opt.generateCoordCount] By default, the generated dim name is `generateCoord`.
31438
- * If `generateCoordCount` specified, the generated dim names will be:
31439
- * `generateCoord` + 0, `generateCoord` + 1, ...
31440
- * 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.
31441
31875
  * @param {number} [opt.dimCount] If not specified, guess by the first data item.
31442
- * @param {number} [opt.encodeDefaulter] If not specified, auto find the next available data dim.
31443
- * @return {Array.<Object>} [{
31444
- * name: string mandatory,
31445
- * displayName: string, the origin name in dimsDef, see source helper.
31446
- * If displayName given, the tooltip will displayed vertically.
31447
- * coordDim: string mandatory,
31448
- * coordDimIndex: number mandatory,
31449
- * type: string optional,
31450
- * otherDims: { never null/undefined
31451
- * tooltip: number optional,
31452
- * label: number optional,
31453
- * itemName: number optional,
31454
- * seriesName: number optional,
31455
- * },
31456
- * isExtraCoord: boolean true if coord is generated
31457
- * (not specified in encode and not series specified)
31458
- * other props ...
31459
- * }]
31876
+ * @return {Array.<module:data/DataDimensionInfo>}
31460
31877
  */
31461
31878
  function completeDimensions(sysDims, source, opt) {
31462
31879
  if (!Source.isInstance(source)) {
@@ -31466,7 +31883,6 @@ function completeDimensions(sysDims, source, opt) {
31466
31883
  opt = opt || {};
31467
31884
  sysDims = (sysDims || []).slice();
31468
31885
  var dimsDef = (opt.dimsDef || []).slice();
31469
- var encodeDef = createHashMap(opt.encodeDef);
31470
31886
  var dataDimNameMap = createHashMap();
31471
31887
  var coordDimNameMap = createHashMap();
31472
31888
  // var valueCandidate;
@@ -31480,7 +31896,7 @@ function completeDimensions(sysDims, source, opt) {
31480
31896
  {}, isObject$1(dimsDef[i]) ? dimsDef[i] : {name: dimsDef[i]}
31481
31897
  );
31482
31898
  var userDimName = dimDefItem.name;
31483
- var resultItem = result[i] = {otherDims: {}};
31899
+ var resultItem = result[i] = new DataDimensionInfo();
31484
31900
  // Name will be applied later for avoiding duplication.
31485
31901
  if (userDimName != null && dataDimNameMap.get(userDimName) == null) {
31486
31902
  // Only if `series.dimensions` is defined in option
@@ -31493,6 +31909,12 @@ function completeDimensions(sysDims, source, opt) {
31493
31909
  dimDefItem.displayName != null && (resultItem.displayName = dimDefItem.displayName);
31494
31910
  }
31495
31911
 
31912
+ var encodeDef = opt.encodeDef;
31913
+ if (!encodeDef && opt.encodeDefaulter) {
31914
+ encodeDef = opt.encodeDefaulter(source, dimCount);
31915
+ }
31916
+ encodeDef = createHashMap(encodeDef);
31917
+
31496
31918
  // Set `coordDim` and `coordDimIndex` by `encodeDef` and normalize `encodeDef`.
31497
31919
  encodeDef.each(function (dataDims, coordDim) {
31498
31920
  dataDims = normalizeToArray(dataDims).slice();
@@ -31594,7 +32016,7 @@ function completeDimensions(sysDims, source, opt) {
31594
32016
 
31595
32017
  // Set dim `name` and other `coordDim` and other props.
31596
32018
  for (var resultDimIdx = 0; resultDimIdx < dimCount; resultDimIdx++) {
31597
- var resultItem = result[resultDimIdx] = result[resultDimIdx] || {};
32019
+ var resultItem = result[resultDimIdx] = result[resultDimIdx] || new DataDimensionInfo();
31598
32020
  var coordDim = resultItem.coordDim;
31599
32021
 
31600
32022
  if (coordDim == null) {
@@ -31613,7 +32035,28 @@ function completeDimensions(sysDims, source, opt) {
31613
32035
  dataDimNameMap
31614
32036
  ));
31615
32037
 
31616
- 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
+ ) {
31617
32060
  resultItem.type = 'ordinal';
31618
32061
  }
31619
32062
  }
@@ -31691,6 +32134,7 @@ function genName(name, map$$1, fromZero) {
31691
32134
  * @param {string} [opt.generateCoordCount]
31692
32135
  * @param {Array.<string|Object>} [opt.dimensionsDefine=source.dimensionsDefine] Overwrite source define.
31693
32136
  * @param {Object|HashMap} [opt.encodeDefine=source.encodeDefine] Overwrite source define.
32137
+ * @param {Function} [opt.encodeDefaulter] Make default encode if user not specified.
31694
32138
  * @return {Array.<Object>} dimensionsInfo
31695
32139
  */
31696
32140
  var createDimensions = function (source, opt) {
@@ -31699,6 +32143,7 @@ var createDimensions = function (source, opt) {
31699
32143
  dimsDef: opt.dimensionsDefine || source.dimensionsDefine,
31700
32144
  encodeDef: opt.encodeDefine || source.encodeDefine,
31701
32145
  dimCount: opt.dimensionsCount,
32146
+ encodeDefaulter: opt.encodeDefaulter,
31702
32147
  generateCoord: opt.generateCoord,
31703
32148
  generateCoordCount: opt.generateCoordCount
31704
32149
  });
@@ -31723,6 +32168,201 @@ var createDimensions = function (source, opt) {
31723
32168
  * under the License.
31724
32169
  */
31725
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
+
31726
32366
  /**
31727
32367
  * Note that it is too complicated to support 3d stack by value
31728
32368
  * (have to create two-dimension inverted index), so in 3d case
@@ -31889,6 +32529,7 @@ function getStackedDimension(data, targetDim) {
31889
32529
  * @param {module:echarts/model/Series} seriesModel
31890
32530
  * @param {Object} [opt]
31891
32531
  * @param {string} [opt.generateCoord]
32532
+ * @param {boolean} [opt.useEncodeDefaulter]
31892
32533
  */
31893
32534
  function createListFromArray(source, seriesModel, opt) {
31894
32535
  opt = opt || {};
@@ -31900,14 +32541,14 @@ function createListFromArray(source, seriesModel, opt) {
31900
32541
  var coordSysName = seriesModel.get('coordinateSystem');
31901
32542
  var registeredCoordSys = CoordinateSystemManager.get(coordSysName);
31902
32543
 
31903
- var coordSysDefine = getCoordSysDefineBySeries(seriesModel);
32544
+ var coordSysInfo = getCoordSysInfoBySeries(seriesModel);
31904
32545
 
31905
32546
  var coordSysDimDefs;
31906
32547
 
31907
- if (coordSysDefine) {
31908
- coordSysDimDefs = map(coordSysDefine.coordSysDims, function (dim) {
32548
+ if (coordSysInfo) {
32549
+ coordSysDimDefs = map(coordSysInfo.coordSysDims, function (dim) {
31909
32550
  var dimInfo = {name: dim};
31910
- var axisModel = coordSysDefine.axisMap.get(dim);
32551
+ var axisModel = coordSysInfo.axisMap.get(dim);
31911
32552
  if (axisModel) {
31912
32553
  var axisType = axisModel.get('type');
31913
32554
  dimInfo.type = getDimensionTypeByAxis(axisType);
@@ -31928,14 +32569,17 @@ function createListFromArray(source, seriesModel, opt) {
31928
32569
 
31929
32570
  var dimInfoList = createDimensions(source, {
31930
32571
  coordDimensions: coordSysDimDefs,
31931
- generateCoord: opt.generateCoord
32572
+ generateCoord: opt.generateCoord,
32573
+ encodeDefaulter: opt.useEncodeDefaulter
32574
+ ? curry(makeSeriesEncodeForAxisCoordSys, coordSysDimDefs, seriesModel)
32575
+ : null
31932
32576
  });
31933
32577
 
31934
32578
  var firstCategoryDimIndex;
31935
32579
  var hasNameEncode;
31936
- coordSysDefine && each$1(dimInfoList, function (dimInfo, dimIndex) {
32580
+ coordSysInfo && each$1(dimInfoList, function (dimInfo, dimIndex) {
31937
32581
  var coordDim = dimInfo.coordDim;
31938
- var categoryAxisModel = coordSysDefine.categoryAxisMap.get(coordDim);
32582
+ var categoryAxisModel = coordSysInfo.categoryAxisMap.get(coordDim);
31939
32583
  if (categoryAxisModel) {
31940
32584
  if (firstCategoryDimIndex == null) {
31941
32585
  firstCategoryDimIndex = dimIndex;
@@ -32019,7 +32663,7 @@ SeriesModel.extend({
32019
32663
  throw new Error('Line not support coordinateSystem besides cartesian and polar');
32020
32664
  }
32021
32665
  }
32022
- return createListFromArray(this.getSource(), this);
32666
+ return createListFromArray(this.getSource(), this, {useEncodeDefaulter: true});
32023
32667
  },
32024
32668
 
32025
32669
  defaultOption: {
@@ -32730,6 +33374,15 @@ symbolProto._updateCommon = function (data, idx, symbolSize, seriesScope) {
32730
33374
  strokeNoScale: true
32731
33375
  });
32732
33376
  }
33377
+ else {
33378
+ symbolPath.setStyle({
33379
+ opacity: null,
33380
+ shadowBlur: null,
33381
+ shadowOffsetX: null,
33382
+ shadowOffsetY: null,
33383
+ shadowColor: null
33384
+ });
33385
+ }
32733
33386
 
32734
33387
  var itemStyle = seriesScope && seriesScope.itemStyle;
32735
33388
  var hoverItemStyle = seriesScope && seriesScope.hoverItemStyle;
@@ -34224,7 +34877,7 @@ Chart.extend({
34224
34877
  // FIXME step not support polar
34225
34878
  var step = !isCoordSysPolar && seriesModel.get('step');
34226
34879
  var clipShapeForSymbol;
34227
- if (coordSys && coordSys.getArea) {
34880
+ if (coordSys && coordSys.getArea && seriesModel.get('clip', true)) {
34228
34881
  clipShapeForSymbol = coordSys.getArea();
34229
34882
  // Avoid float number rounding error for symbol on the edge of axis extent.
34230
34883
  // See #7913 and `test/dataZoom-clip.html`.
@@ -34239,6 +34892,7 @@ Chart.extend({
34239
34892
  clipShapeForSymbol.r1 += 0.5;
34240
34893
  }
34241
34894
  }
34895
+ this._clipShapeForSymbol = clipShapeForSymbol;
34242
34896
  // Initialization animation or coordinate system changed
34243
34897
  if (
34244
34898
  !(polyline && prevCoordSys.type === coordSys.type && step === this._step)
@@ -34391,6 +35045,10 @@ Chart.extend({
34391
35045
  // Null data
34392
35046
  return;
34393
35047
  }
35048
+ // fix #11360: should't draw symbol outside clipShapeForSymbol
35049
+ if (this._clipShapeForSymbol && !this._clipShapeForSymbol.contain(pt[0], pt[1])) {
35050
+ return;
35051
+ }
34394
35052
  symbol = new SymbolClz(data, dataIndex);
34395
35053
  symbol.position = pt;
34396
35054
  symbol.setZ(
@@ -35396,44 +36054,6 @@ function fixExtent(niceTickExtent, extent) {
35396
36054
  }
35397
36055
  }
35398
36056
 
35399
- function intervalScaleGetTicks(interval, extent, niceTickExtent, intervalPrecision) {
35400
- var ticks = [];
35401
-
35402
- // If interval is 0, return [];
35403
- if (!interval) {
35404
- return ticks;
35405
- }
35406
-
35407
- // Consider this case: using dataZoom toolbox, zoom and zoom.
35408
- var safeLimit = 10000;
35409
-
35410
- if (extent[0] < niceTickExtent[0]) {
35411
- ticks.push(extent[0]);
35412
- }
35413
- var tick = niceTickExtent[0];
35414
-
35415
- while (tick <= niceTickExtent[1]) {
35416
- ticks.push(tick);
35417
- // Avoid rounding error
35418
- tick = roundNumber$1(tick + interval, intervalPrecision);
35419
- if (tick === ticks[ticks.length - 1]) {
35420
- // Consider out of safe float point, e.g.,
35421
- // -3711126.9907707 + 2e-10 === -3711126.9907707
35422
- break;
35423
- }
35424
- if (ticks.length > safeLimit) {
35425
- return [];
35426
- }
35427
- }
35428
- // Consider this case: the last item of ticks is smaller
35429
- // than niceTickExtent[1] and niceTickExtent[1] === extent[1].
35430
- if (extent[1] > (ticks.length ? ticks[ticks.length - 1] : niceTickExtent[1])) {
35431
- ticks.push(extent[1]);
35432
- }
35433
-
35434
- return ticks;
35435
- }
35436
-
35437
36057
  /*
35438
36058
  * Licensed to the Apache Software Foundation (ASF) under one
35439
36059
  * or more contributor license agreements. See the NOTICE file
@@ -35512,12 +36132,92 @@ var IntervalScale = Scale.extend({
35512
36132
  },
35513
36133
 
35514
36134
  /**
36135
+ * @param {boolean} [expandToNicedExtent=false] If expand the ticks to niced extent.
35515
36136
  * @return {Array.<number>}
35516
36137
  */
35517
- getTicks: function () {
35518
- return intervalScaleGetTicks(
35519
- this._interval, this._extent, this._niceExtent, this._intervalPrecision
35520
- );
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;
35521
36221
  },
35522
36222
 
35523
36223
  /**
@@ -35680,6 +36380,7 @@ function getAxisKey(axis) {
35680
36380
  * @param {number} opt.count Positive interger.
35681
36381
  * @param {number} [opt.barWidth]
35682
36382
  * @param {number} [opt.barMaxWidth]
36383
+ * @param {number} [opt.barMinWidth]
35683
36384
  * @param {number} [opt.barGap]
35684
36385
  * @param {number} [opt.barCategoryGap]
35685
36386
  * @return {Object} {width, offset, offsetCenter} If axis.type is not 'category', return undefined.
@@ -35697,16 +36398,101 @@ function prepareLayoutBarSeries(seriesType, ecModel) {
35697
36398
  return seriesModels;
35698
36399
  }
35699
36400
 
36401
+
36402
+ /**
36403
+ * Map from (baseAxis.dim + '_' + baseAxis.index) to min gap of two adjacent
36404
+ * values.
36405
+ * This works for time axes, value axes, and log axes.
36406
+ * For a single time axis, return value is in the form like
36407
+ * {'x_0': [1000000]}.
36408
+ * The value of 1000000 is in milliseconds.
36409
+ */
36410
+ function getValueAxesMinGaps(barSeries) {
36411
+ /**
36412
+ * Map from axis.index to values.
36413
+ * For a single time axis, axisValues is in the form like
36414
+ * {'x_0': [1495555200000, 1495641600000, 1495728000000]}.
36415
+ * Items in axisValues[x], e.g. 1495555200000, are time values of all
36416
+ * series.
36417
+ */
36418
+ var axisValues = {};
36419
+ each$1(barSeries, function (seriesModel) {
36420
+ var cartesian = seriesModel.coordinateSystem;
36421
+ var baseAxis = cartesian.getBaseAxis();
36422
+ if (baseAxis.type !== 'time' && baseAxis.type !== 'value') {
36423
+ return;
36424
+ }
36425
+
36426
+ var data = seriesModel.getData();
36427
+ var key = baseAxis.dim + '_' + baseAxis.index;
36428
+ var dim = data.mapDimension(baseAxis.dim);
36429
+ for (var i = 0, cnt = data.count(); i < cnt; ++i) {
36430
+ var value = data.get(dim, i);
36431
+ if (!axisValues[key]) {
36432
+ // No previous data for the axis
36433
+ axisValues[key] = [value];
36434
+ }
36435
+ else {
36436
+ // No value in previous series
36437
+ axisValues[key].push(value);
36438
+ }
36439
+ // Ignore duplicated time values in the same axis
36440
+ }
36441
+ });
36442
+
36443
+ var axisMinGaps = [];
36444
+ for (var key in axisValues) {
36445
+ if (axisValues.hasOwnProperty(key)) {
36446
+ var valuesInAxis = axisValues[key];
36447
+ if (valuesInAxis) {
36448
+ // Sort axis values into ascending order to calculate gaps
36449
+ valuesInAxis.sort(function (a, b) {
36450
+ return a - b;
36451
+ });
36452
+
36453
+ var min = null;
36454
+ for (var j = 1; j < valuesInAxis.length; ++j) {
36455
+ var delta = valuesInAxis[j] - valuesInAxis[j - 1];
36456
+ if (delta > 0) {
36457
+ // Ignore 0 delta because they are of the same axis value
36458
+ min = min === null ? delta : Math.min(min, delta);
36459
+ }
36460
+ }
36461
+ // Set to null if only have one data
36462
+ axisMinGaps[key] = min;
36463
+ }
36464
+ }
36465
+ }
36466
+ return axisMinGaps;
36467
+ }
36468
+
35700
36469
  function makeColumnLayout(barSeries) {
36470
+ var axisMinGaps = getValueAxesMinGaps(barSeries);
36471
+
35701
36472
  var seriesInfoList = [];
35702
36473
  each$1(barSeries, function (seriesModel) {
35703
- var data = seriesModel.getData();
35704
36474
  var cartesian = seriesModel.coordinateSystem;
35705
36475
  var baseAxis = cartesian.getBaseAxis();
35706
36476
  var axisExtent = baseAxis.getExtent();
35707
- var bandWidth = baseAxis.type === 'category'
35708
- ? baseAxis.getBandWidth()
35709
- : (Math.abs(axisExtent[1] - axisExtent[0]) / data.count());
36477
+
36478
+ var bandWidth;
36479
+ if (baseAxis.type === 'category') {
36480
+ bandWidth = baseAxis.getBandWidth();
36481
+ }
36482
+ else if (baseAxis.type === 'value' || baseAxis.type === 'time') {
36483
+ var key = baseAxis.dim + '_' + baseAxis.index;
36484
+ var minGap = axisMinGaps[key];
36485
+ var extentSpan = Math.abs(axisExtent[1] - axisExtent[0]);
36486
+ var scale = baseAxis.scale.getExtent();
36487
+ var scaleSpan = Math.abs(scale[1] - scale[0]);
36488
+ bandWidth = minGap
36489
+ ? extentSpan / scaleSpan * minGap
36490
+ : extentSpan; // When there is only one data value
36491
+ }
36492
+ else {
36493
+ var data = seriesModel.getData();
36494
+ bandWidth = Math.abs(axisExtent[1] - axisExtent[0]) / data.count();
36495
+ }
35710
36496
 
35711
36497
  var barWidth = parsePercent$1(
35712
36498
  seriesModel.get('barWidth'), bandWidth
@@ -35714,6 +36500,11 @@ function makeColumnLayout(barSeries) {
35714
36500
  var barMaxWidth = parsePercent$1(
35715
36501
  seriesModel.get('barMaxWidth'), bandWidth
35716
36502
  );
36503
+ var barMinWidth = parsePercent$1(
36504
+ // barMinWidth by default is 1 in cartesian. Because in value axis,
36505
+ // the auto-calculated bar width might be less than 1.
36506
+ seriesModel.get('barMinWidth') || 1, bandWidth
36507
+ );
35717
36508
  var barGap = seriesModel.get('barGap');
35718
36509
  var barCategoryGap = seriesModel.get('barCategoryGap');
35719
36510
 
@@ -35721,6 +36512,7 @@ function makeColumnLayout(barSeries) {
35721
36512
  bandWidth: bandWidth,
35722
36513
  barWidth: barWidth,
35723
36514
  barMaxWidth: barMaxWidth,
36515
+ barMinWidth: barMinWidth,
35724
36516
  barGap: barGap,
35725
36517
  barCategoryGap: barCategoryGap,
35726
36518
  axisKey: getAxisKey(baseAxis),
@@ -35764,7 +36556,6 @@ function doCalBarWidthAndOffset(seriesInfoList) {
35764
36556
  // only the attributes set on the last series will work.
35765
36557
  // Do not change this fact unless there will be a break change.
35766
36558
 
35767
- // TODO
35768
36559
  var barWidth = seriesInfo.barWidth;
35769
36560
  if (barWidth && !stacks[stackId].width) {
35770
36561
  // See #6312, do not restrict width.
@@ -35775,6 +36566,8 @@ function doCalBarWidthAndOffset(seriesInfoList) {
35775
36566
 
35776
36567
  var barMaxWidth = seriesInfo.barMaxWidth;
35777
36568
  barMaxWidth && (stacks[stackId].maxWidth = barMaxWidth);
36569
+ var barMinWidth = seriesInfo.barMinWidth;
36570
+ barMinWidth && (stacks[stackId].minWidth = barMinWidth);
35778
36571
  var barGap = seriesInfo.barGap;
35779
36572
  (barGap != null) && (columnsOnAxis.gap = barGap);
35780
36573
  var barCategoryGap = seriesInfo.barCategoryGap;
@@ -35799,15 +36592,43 @@ function doCalBarWidthAndOffset(seriesInfoList) {
35799
36592
  autoWidth = Math.max(autoWidth, 0);
35800
36593
 
35801
36594
  // Find if any auto calculated bar exceeded maxBarWidth
35802
- each$1(stacks, function (column, stack) {
36595
+ each$1(stacks, function (column) {
35803
36596
  var maxWidth = column.maxWidth;
35804
- if (maxWidth && maxWidth < autoWidth) {
35805
- maxWidth = Math.min(maxWidth, remainedWidth);
35806
- if (column.width) {
35807
- maxWidth = Math.min(maxWidth, column.width);
36597
+ var minWidth = column.minWidth;
36598
+
36599
+ if (!column.width) {
36600
+ var finalWidth = autoWidth;
36601
+ if (maxWidth && maxWidth < finalWidth) {
36602
+ finalWidth = Math.min(maxWidth, remainedWidth);
36603
+ }
36604
+ // `minWidth` has higher priority. `minWidth` decide that wheter the
36605
+ // bar is able to be visible. So `minWidth` should not be restricted
36606
+ // by `maxWidth` or `remainedWidth` (which is from `bandWidth`). In
36607
+ // the extreme cases for `value` axis, bars are allowed to overlap
36608
+ // with each other if `minWidth` specified.
36609
+ if (minWidth && minWidth > finalWidth) {
36610
+ finalWidth = minWidth;
35808
36611
  }
35809
- remainedWidth -= maxWidth;
35810
- column.width = maxWidth;
36612
+ if (finalWidth !== autoWidth) {
36613
+ column.width = finalWidth;
36614
+ remainedWidth -= finalWidth + barGapPercent * finalWidth;
36615
+ autoWidthCount--;
36616
+ }
36617
+ }
36618
+ else {
36619
+ // `barMinWidth/barMaxWidth` has higher priority than `barWidth`, as
36620
+ // CSS does. Becuase barWidth can be a percent value, where
36621
+ // `barMaxWidth` can be used to restrict the final width.
36622
+ var finalWidth = column.width;
36623
+ if (maxWidth) {
36624
+ finalWidth = Math.min(finalWidth, maxWidth);
36625
+ }
36626
+ // `minWidth` has higher priority, as described above
36627
+ if (minWidth) {
36628
+ finalWidth = Math.max(finalWidth, minWidth);
36629
+ }
36630
+ column.width = finalWidth;
36631
+ remainedWidth -= finalWidth + barGapPercent * finalWidth;
35811
36632
  autoWidthCount--;
35812
36633
  }
35813
36634
  });
@@ -35815,8 +36636,10 @@ function doCalBarWidthAndOffset(seriesInfoList) {
35815
36636
  // Recalculate width again
35816
36637
  autoWidth = (remainedWidth - categoryGap)
35817
36638
  / (autoWidthCount + (autoWidthCount - 1) * barGapPercent);
36639
+
35818
36640
  autoWidth = Math.max(autoWidth, 0);
35819
36641
 
36642
+
35820
36643
  var widthSum = 0;
35821
36644
  var lastColumn;
35822
36645
  each$1(stacks, function (column, idx) {
@@ -36039,7 +36862,7 @@ function isInLargeMode(seriesModel) {
36039
36862
 
36040
36863
  // See cases in `test/bar-start.html` and `#7412`, `#8747`.
36041
36864
  function getValueAxisStart(baseAxis, valueAxis, stacked) {
36042
- return valueAxis.toGlobalCoord(valueAxis.dataToCoord(0));
36865
+ return valueAxis.toGlobalCoord(valueAxis.dataToCoord(valueAxis.type === 'log' ? 1 : 0));
36043
36866
  }
36044
36867
 
36045
36868
  /*
@@ -36316,14 +37139,15 @@ var LogScale = Scale.extend({
36316
37139
  },
36317
37140
 
36318
37141
  /**
37142
+ * @param {boolean} [expandToNicedExtent=false] If expand the ticks to niced extent.
36319
37143
  * @return {Array.<number>}
36320
37144
  */
36321
- getTicks: function () {
37145
+ getTicks: function (expandToNicedExtent) {
36322
37146
  var originalScale = this._originalScale;
36323
37147
  var extent = this._extent;
36324
37148
  var originalExtent = originalScale.getExtent();
36325
37149
 
36326
- return map(intervalScaleProto$1.getTicks.call(this), function (val) {
37150
+ return map(intervalScaleProto$1.getTicks.call(this, expandToNicedExtent), function (val) {
36327
37151
  var powVal = round$1(mathPow$1(this.base, val));
36328
37152
 
36329
37153
  // Fix #4158
@@ -36338,6 +37162,12 @@ var LogScale = Scale.extend({
36338
37162
  }, this);
36339
37163
  },
36340
37164
 
37165
+ /**
37166
+ * @param {number} splitNumber
37167
+ * @return {Array.<Array.<number>>}
37168
+ */
37169
+ getMinorTicks: intervalScaleProto$1.getMinorTicks,
37170
+
36341
37171
  /**
36342
37172
  * @param {number} val
36343
37173
  * @return {string}
@@ -37373,12 +38203,16 @@ function calculateCategoryInterval(axis) {
37373
38203
  var interval = Math.max(0, Math.floor(Math.min(dw, dh)));
37374
38204
 
37375
38205
  var cache = inner$6(axis.model);
38206
+ var axisExtent = axis.getExtent();
37376
38207
  var lastAutoInterval = cache.lastAutoInterval;
37377
38208
  var lastTickCount = cache.lastTickCount;
37378
38209
 
37379
38210
  // Use cache to keep interval stable while moving zoom window,
37380
38211
  // otherwise the calculated interval might jitter when the zoom
37381
38212
  // window size is close to the interval-changing size.
38213
+ // For example, if all of the axis labels are `a, b, c, d, e, f, g`.
38214
+ // The jitter will cause that sometimes the displayed labels are
38215
+ // `a, d, g` (interval: 2) sometimes `a, c, e`(interval: 1).
37382
38216
  if (lastAutoInterval != null
37383
38217
  && lastTickCount != null
37384
38218
  && Math.abs(lastAutoInterval - interval) <= 1
@@ -37386,6 +38220,10 @@ function calculateCategoryInterval(axis) {
37386
38220
  // Always choose the bigger one, otherwise the critical
37387
38221
  // point is not the same when zooming in or zooming out.
37388
38222
  && lastAutoInterval > interval
38223
+ // If the axis change is caused by chart resize, the cache should not
38224
+ // be used. Otherwise some hiden labels might not be shown again.
38225
+ && cache.axisExtend0 === axisExtent[0]
38226
+ && cache.axisExtend1 === axisExtent[1]
37389
38227
  ) {
37390
38228
  interval = lastAutoInterval;
37391
38229
  }
@@ -37394,6 +38232,8 @@ function calculateCategoryInterval(axis) {
37394
38232
  else {
37395
38233
  cache.lastTickCount = tickCount;
37396
38234
  cache.lastAutoInterval = interval;
38235
+ cache.axisExtend0 = axisExtent[0];
38236
+ cache.axisExtend1 = axisExtent[1];
37397
38237
  }
37398
38238
 
37399
38239
  return interval;
@@ -37573,7 +38413,7 @@ Axis.prototype = {
37573
38413
  * @return {boolean}
37574
38414
  */
37575
38415
  containData: function (data) {
37576
- return this.contain(this.dataToCoord(data));
38416
+ return this.scale.contain(data);
37577
38417
  },
37578
38418
 
37579
38419
  /**
@@ -37661,7 +38501,7 @@ Axis.prototype = {
37661
38501
  * `axis.getTicksCoords` considers `onBand`, which is used by
37662
38502
  * `boundaryGap:true` of category axis and splitLine and splitArea.
37663
38503
  * @param {Object} [opt]
37664
- * @param {number} [opt.tickModel=axis.model.getModel('axisTick')]
38504
+ * @param {Model} [opt.tickModel=axis.model.getModel('axisTick')]
37665
38505
  * @param {boolean} [opt.clamp] If `true`, the first and the last
37666
38506
  * tick must be at the axis end points. Otherwise, clip ticks
37667
38507
  * that outside the axis extent.
@@ -37674,7 +38514,6 @@ Axis.prototype = {
37674
38514
  opt = opt || {};
37675
38515
 
37676
38516
  var tickModel = opt.tickModel || this.getTickModel();
37677
-
37678
38517
  var result = createAxisTicks(this, tickModel);
37679
38518
  var ticks = result.ticks;
37680
38519
 
@@ -37686,13 +38525,41 @@ Axis.prototype = {
37686
38525
  }, this);
37687
38526
 
37688
38527
  var alignWithLabel = tickModel.get('alignWithLabel');
38528
+
37689
38529
  fixOnBandTicksCoords(
37690
- this, ticksCoords, result.tickCategoryInterval, alignWithLabel, opt.clamp
38530
+ this, ticksCoords, alignWithLabel, opt.clamp
37691
38531
  );
37692
38532
 
37693
38533
  return ticksCoords;
37694
38534
  },
37695
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
+
37696
38563
  /**
37697
38564
  * @return {Array.<Object>} [{
37698
38565
  * formattedLabel: string,
@@ -37780,7 +38647,7 @@ function fixExtentWithBands(extent, nTick) {
37780
38647
  // splitLine/spliteArea should layout appropriately corresponding
37781
38648
  // to displayed labels. (So we should not use `getBandWidth` in this
37782
38649
  // case).
37783
- function fixOnBandTicksCoords(axis, ticksCoords, tickCategoryInterval, alignWithLabel, clamp) {
38650
+ function fixOnBandTicksCoords(axis, ticksCoords, alignWithLabel, clamp) {
37784
38651
  var ticksLen = ticksCoords.length;
37785
38652
 
37786
38653
  if (!axis.onBand || alignWithLabel || !ticksLen) {
@@ -37789,26 +38656,30 @@ function fixOnBandTicksCoords(axis, ticksCoords, tickCategoryInterval, alignWith
37789
38656
 
37790
38657
  var axisExtent = axis.getExtent();
37791
38658
  var last;
38659
+ var diffSize;
37792
38660
  if (ticksLen === 1) {
37793
38661
  ticksCoords[0].coord = axisExtent[0];
37794
38662
  last = ticksCoords[1] = {coord: axisExtent[0]};
37795
38663
  }
37796
38664
  else {
37797
- var shift = (ticksCoords[1].coord - ticksCoords[0].coord);
38665
+ var crossLen = ticksCoords[ticksLen - 1].tickValue - ticksCoords[0].tickValue;
38666
+ var shift = (ticksCoords[ticksLen - 1].coord - ticksCoords[0].coord) / crossLen;
38667
+
37798
38668
  each$1(ticksCoords, function (ticksItem) {
37799
38669
  ticksItem.coord -= shift / 2;
37800
- var tickCategoryInterval = tickCategoryInterval || 0;
37801
- // Avoid split a single data item when odd interval.
37802
- if (tickCategoryInterval % 2 > 0) {
37803
- ticksItem.coord -= shift / ((tickCategoryInterval + 1) * 2);
37804
- }
37805
38670
  });
37806
- last = {coord: ticksCoords[ticksLen - 1].coord + shift};
38671
+
38672
+ var dataExtent = axis.scale.getExtent();
38673
+ diffSize = 1 + dataExtent[1] - ticksCoords[ticksLen - 1].tickValue;
38674
+
38675
+ last = {coord: ticksCoords[ticksLen - 1].coord + shift * diffSize};
38676
+
37807
38677
  ticksCoords.push(last);
37808
38678
  }
37809
38679
 
37810
38680
  var inverse = axisExtent[0] > axisExtent[1];
37811
38681
 
38682
+ // Handling clamp.
37812
38683
  if (littleThan(ticksCoords[0].coord, axisExtent[0])) {
37813
38684
  clamp ? (ticksCoords[0].coord = axisExtent[0]) : ticksCoords.shift();
37814
38685
  }
@@ -37823,6 +38694,10 @@ function fixOnBandTicksCoords(axis, ticksCoords, tickCategoryInterval, alignWith
37823
38694
  }
37824
38695
 
37825
38696
  function littleThan(a, b) {
38697
+ // Avoid rounding error cause calculated tick coord different with extent.
38698
+ // It may cause an extra unecessary tick added.
38699
+ a = round$1(a);
38700
+ b = round$1(b);
37826
38701
  return inverse ? a > b : a < b;
37827
38702
  }
37828
38703
  }
@@ -38119,7 +38994,7 @@ axisDefault.valueAxis = merge({
38119
38994
  // scale: false,
38120
38995
 
38121
38996
  // AxisTick and axisLabel and splitLine are caculated based on splitNumber.
38122
- splitNumber: 5
38997
+ splitNumber: 5,
38123
38998
 
38124
38999
  // Interval specifies the span of the ticks is mandatorily.
38125
39000
  // interval: null
@@ -38130,6 +39005,30 @@ axisDefault.valueAxis = merge({
38130
39005
  // Specify max interval when auto calculate tick interval.
38131
39006
  // maxInterval: null
38132
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
+ }
38133
39032
  }, defaultOption);
38134
39033
 
38135
39034
  axisDefault.timeAxis = defaults({
@@ -39342,10 +40241,12 @@ var builders = {
39342
40241
  var axisModel = this.axisModel;
39343
40242
  var opt = this.opt;
39344
40243
 
39345
- var tickEls = buildAxisTick(this, axisModel, opt);
40244
+ var ticksEls = buildAxisMajorTicks(this, axisModel, opt);
39346
40245
  var labelEls = buildAxisLabel(this, axisModel, opt);
39347
40246
 
39348
- fixMinMaxLabelShow(axisModel, labelEls, tickEls);
40247
+ fixMinMaxLabelShow(axisModel, labelEls, ticksEls);
40248
+
40249
+ buildAxisMinorTicks(this, axisModel, opt);
39349
40250
  },
39350
40251
 
39351
40252
  /**
@@ -39664,42 +40565,27 @@ function isNameLocationCenter(nameLocation) {
39664
40565
  return nameLocation === 'middle' || nameLocation === 'center';
39665
40566
  }
39666
40567
 
39667
- function buildAxisTick(axisBuilder, axisModel, opt) {
39668
- var axis = axisModel.axis;
39669
-
39670
- if (!axisModel.get('axisTick.show') || axis.scale.isBlank()) {
39671
- return;
39672
- }
39673
-
39674
- var tickModel = axisModel.getModel('axisTick');
39675
-
39676
- var lineStyleModel = tickModel.getModel('lineStyle');
39677
- var tickLen = tickModel.get('length');
39678
-
39679
- var ticksCoords = axis.getTicksCoords();
39680
40568
 
40569
+ function createTicks(ticksCoords, tickTransform, tickEndCoord, tickLineStyle, aniid) {
40570
+ var tickEls = [];
39681
40571
  var pt1 = [];
39682
40572
  var pt2 = [];
39683
- var matrix = axisBuilder._transform;
39684
-
39685
- var tickEls = [];
39686
-
39687
40573
  for (var i = 0; i < ticksCoords.length; i++) {
39688
40574
  var tickCoord = ticksCoords[i].coord;
39689
40575
 
39690
40576
  pt1[0] = tickCoord;
39691
40577
  pt1[1] = 0;
39692
40578
  pt2[0] = tickCoord;
39693
- pt2[1] = opt.tickDirection * tickLen;
40579
+ pt2[1] = tickEndCoord;
39694
40580
 
39695
- if (matrix) {
39696
- applyTransform(pt1, pt1, matrix);
39697
- applyTransform(pt2, pt2, matrix);
40581
+ if (tickTransform) {
40582
+ applyTransform(pt1, pt1, tickTransform);
40583
+ applyTransform(pt2, pt2, tickTransform);
39698
40584
  }
39699
40585
  // Tick line, Not use group transform to have better line draw
39700
40586
  var tickEl = new Line({
39701
40587
  // Id for animation
39702
- anid: 'tick_' + ticksCoords[i].tickValue,
40588
+ anid: aniid + '_' + ticksCoords[i].tickValue,
39703
40589
  subPixelOptimize: true,
39704
40590
  shape: {
39705
40591
  x1: pt1[0],
@@ -39707,22 +40593,80 @@ function buildAxisTick(axisBuilder, axisModel, opt) {
39707
40593
  x2: pt2[0],
39708
40594
  y2: pt2[1]
39709
40595
  },
39710
- style: defaults(
39711
- lineStyleModel.getLineStyle(),
39712
- {
39713
- stroke: axisModel.get('axisLine.lineStyle.color')
39714
- }
39715
- ),
40596
+ style: tickLineStyle,
39716
40597
  z2: 2,
39717
40598
  silent: true
39718
40599
  });
39719
- axisBuilder.group.add(tickEl);
39720
40600
  tickEls.push(tickEl);
39721
40601
  }
39722
-
39723
40602
  return tickEls;
39724
40603
  }
39725
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
+
39726
40670
  function buildAxisLabel(axisBuilder, axisModel, opt) {
39727
40671
  var axis = axisModel.axis;
39728
40672
  var show = retrieve(opt.axisLabelShow, axisModel.get('axisLabel.show'));
@@ -40142,17 +41086,9 @@ var axisBuilderAttrs = [
40142
41086
  'axisLine', 'axisTickLabel', 'axisName'
40143
41087
  ];
40144
41088
  var selfBuilderAttrs = [
40145
- 'splitArea', 'splitLine'
41089
+ 'splitArea', 'splitLine', 'minorSplitLine'
40146
41090
  ];
40147
41091
 
40148
- // function getAlignWithLabel(model, axisModel) {
40149
- // var alignWithLabel = model.get('alignWithLabel');
40150
- // if (alignWithLabel === 'auto') {
40151
- // alignWithLabel = axisModel.get('axisTick.alignWithLabel');
40152
- // }
40153
- // return alignWithLabel;
40154
- // }
40155
-
40156
41092
  var CartesianAxisView = AxisView.extend({
40157
41093
 
40158
41094
  type: 'cartesianAxis',
@@ -40230,8 +41166,6 @@ var CartesianAxisView = AxisView.extend({
40230
41166
  var p1 = [];
40231
41167
  var p2 = [];
40232
41168
 
40233
- // Simple optimization
40234
- // Batching the lines if color are the same
40235
41169
  var lineStyle = lineStyleModel.getLineStyle();
40236
41170
  for (var i = 0; i < ticksCoords.length; i++) {
40237
41171
  var tickCoord = axis.toGlobalCoord(ticksCoords[i].coord);
@@ -40268,6 +41202,63 @@ var CartesianAxisView = AxisView.extend({
40268
41202
  }
40269
41203
  },
40270
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
+
40271
41262
  /**
40272
41263
  * @param {module:echarts/coord/cartesian/AxisModel} axisModel
40273
41264
  * @param {module:echarts/coord/cartesian/GridModel} gridModel
@@ -40488,7 +41479,7 @@ var BaseBarSeries = SeriesModel.extend({
40488
41479
  type: 'series.__base_bar__',
40489
41480
 
40490
41481
  getInitialData: function (option, ecModel) {
40491
- return createListFromArray(this.getSource(), this);
41482
+ return createListFromArray(this.getSource(), this, {useEncodeDefaulter: true});
40492
41483
  },
40493
41484
 
40494
41485
  getMarkerPosition: function (value) {
@@ -40529,6 +41520,10 @@ var BaseBarSeries = SeriesModel.extend({
40529
41520
  progressiveChunkMode: 'mod',
40530
41521
 
40531
41522
  // barMaxWidth: null,
41523
+
41524
+ // In cartesian, the default value is 1. Otherwise null.
41525
+ // barMinWidth: null,
41526
+
40532
41527
  // 默认自适应
40533
41528
  // barWidth: null,
40534
41529
  // 柱间距离,默认为柱形宽度的30%,可设固定值
@@ -40596,7 +41591,11 @@ BaseBarSeries.extend({
40596
41591
  defaultOption: {
40597
41592
  // If clipped
40598
41593
  // Only available on cartesian2d
40599
- clip: true
41594
+ clip: true,
41595
+
41596
+ // If use caps on two sides of bars
41597
+ // Only available on tangential polar bar
41598
+ roundCap: false
40600
41599
  }
40601
41600
  });
40602
41601
 
@@ -40711,6 +41710,98 @@ var barItemStyle = {
40711
41710
  * under the License.
40712
41711
  */
40713
41712
 
41713
+ /**
41714
+ * Sausage: similar to sector, but have half circle on both sides
41715
+ * @public
41716
+ */
41717
+ var Sausage = extendShape({
41718
+
41719
+ type: 'sausage',
41720
+
41721
+ shape: {
41722
+
41723
+ cx: 0,
41724
+
41725
+ cy: 0,
41726
+
41727
+ r0: 0,
41728
+
41729
+ r: 0,
41730
+
41731
+ startAngle: 0,
41732
+
41733
+ endAngle: Math.PI * 2,
41734
+
41735
+ clockwise: true
41736
+ },
41737
+
41738
+ buildPath: function (ctx, shape) {
41739
+ var x = shape.cx;
41740
+ var y = shape.cy;
41741
+ var r0 = Math.max(shape.r0 || 0, 0);
41742
+ var r = Math.max(shape.r, 0);
41743
+ var dr = (r - r0) * 0.5;
41744
+ var rCenter = r0 + dr;
41745
+ var startAngle = shape.startAngle;
41746
+ var endAngle = shape.endAngle;
41747
+ var clockwise = shape.clockwise;
41748
+
41749
+ var unitStartX = Math.cos(startAngle);
41750
+ var unitStartY = Math.sin(startAngle);
41751
+ var unitEndX = Math.cos(endAngle);
41752
+ var unitEndY = Math.sin(endAngle);
41753
+
41754
+ var lessThanCircle = clockwise
41755
+ ? endAngle - startAngle < Math.PI * 2
41756
+ : startAngle - endAngle < Math.PI * 2;
41757
+
41758
+ if (lessThanCircle) {
41759
+ ctx.moveTo(unitStartX * r0 + x, unitStartY * r0 + y);
41760
+
41761
+ ctx.arc(
41762
+ unitStartX * rCenter + x, unitStartY * rCenter + y, dr,
41763
+ -Math.PI + startAngle, startAngle, !clockwise
41764
+ );
41765
+ }
41766
+
41767
+ ctx.arc(x, y, r, startAngle, endAngle, !clockwise);
41768
+
41769
+ ctx.moveTo(unitEndX * r + x, unitEndY * r + y);
41770
+
41771
+ ctx.arc(
41772
+ unitEndX * rCenter + x, unitEndY * rCenter + y, dr,
41773
+ endAngle - Math.PI * 2, endAngle - Math.PI, !clockwise
41774
+ );
41775
+
41776
+ if (r0 !== 0) {
41777
+ ctx.arc(x, y, r0, endAngle, startAngle, clockwise);
41778
+
41779
+ ctx.moveTo(unitStartX * r0 + x, unitEndY * r0 + y);
41780
+ }
41781
+
41782
+ ctx.closePath();
41783
+ }
41784
+ });
41785
+
41786
+ /*
41787
+ * Licensed to the Apache Software Foundation (ASF) under one
41788
+ * or more contributor license agreements. See the NOTICE file
41789
+ * distributed with this work for additional information
41790
+ * regarding copyright ownership. The ASF licenses this file
41791
+ * to you under the Apache License, Version 2.0 (the
41792
+ * "License"); you may not use this file except in compliance
41793
+ * with the License. You may obtain a copy of the License at
41794
+ *
41795
+ * http://www.apache.org/licenses/LICENSE-2.0
41796
+ *
41797
+ * Unless required by applicable law or agreed to in writing,
41798
+ * software distributed under the License is distributed on an
41799
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
41800
+ * KIND, either express or implied. See the License for the
41801
+ * specific language governing permissions and limitations
41802
+ * under the License.
41803
+ */
41804
+
40714
41805
  var BAR_BORDER_WIDTH_QUERY = ['itemStyle', 'barBorderWidth'];
40715
41806
  var _eventPos = [0, 0];
40716
41807
 
@@ -40807,6 +41898,8 @@ extendChartView({
40807
41898
  // We don't use clipPath in normal mode because we needs a perfect animation
40808
41899
  // And don't want the label are clipped.
40809
41900
 
41901
+ var roundCap = seriesModel.get('roundCap', true);
41902
+
40810
41903
  data.diff(oldData)
40811
41904
  .add(function (dataIndex) {
40812
41905
  if (!data.hasValue(dataIndex)) {
@@ -40827,7 +41920,7 @@ extendChartView({
40827
41920
  }
40828
41921
 
40829
41922
  var el = elementCreator[coord.type](
40830
- data, dataIndex, itemModel, layout, isHorizontalOrRadial, animationModel
41923
+ dataIndex, layout, isHorizontalOrRadial, animationModel, false, roundCap
40831
41924
  );
40832
41925
  data.setItemGraphicEl(dataIndex, el);
40833
41926
  group.add(el);
@@ -40861,7 +41954,7 @@ extendChartView({
40861
41954
  }
40862
41955
  else {
40863
41956
  el = elementCreator[coord.type](
40864
- data, newIndex, itemModel, layout, isHorizontalOrRadial, animationModel, true
41957
+ newIndex, layout, isHorizontalOrRadial, animationModel, true, roundCap
40865
41958
  );
40866
41959
  }
40867
41960
 
@@ -40985,7 +42078,7 @@ var clip = {
40985
42078
  var elementCreator = {
40986
42079
 
40987
42080
  cartesian2d: function (
40988
- data, dataIndex, itemModel, layout, isHorizontal,
42081
+ dataIndex, layout, isHorizontal,
40989
42082
  animationModel, isUpdate
40990
42083
  ) {
40991
42084
  var rect = new Rect({shape: extend({}, layout)});
@@ -41006,15 +42099,18 @@ var elementCreator = {
41006
42099
  },
41007
42100
 
41008
42101
  polar: function (
41009
- data, dataIndex, itemModel, layout, isRadial,
41010
- animationModel, isUpdate
42102
+ dataIndex, layout, isRadial,
42103
+ animationModel, isUpdate, roundCap
41011
42104
  ) {
41012
42105
  // Keep the same logic with bar in catesion: use end value to control
41013
42106
  // direction. Notice that if clockwise is true (by default), the sector
41014
42107
  // will always draw clockwisely, no matter whether endAngle is greater
41015
42108
  // or less than startAngle.
41016
42109
  var clockwise = layout.startAngle < layout.endAngle;
41017
- var sector = new Sector({
42110
+
42111
+ var ShapeClass = (!isRadial && roundCap) ? Sausage : Sector;
42112
+
42113
+ var sector = new ShapeClass({
41018
42114
  shape: defaults({clockwise: clockwise}, layout)
41019
42115
  });
41020
42116
 
@@ -41087,11 +42183,18 @@ var getLayout = {
41087
42183
  }
41088
42184
  };
41089
42185
 
42186
+ function isZeroOnPolar(layout) {
42187
+ return layout.startAngle != null
42188
+ && layout.endAngle != null
42189
+ && layout.startAngle === layout.endAngle;
42190
+ }
42191
+
41090
42192
  function updateStyle(
41091
42193
  el, data, dataIndex, itemModel, layout, seriesModel, isHorizontal, isPolar
41092
42194
  ) {
41093
42195
  var color = data.getItemVisual(dataIndex, 'color');
41094
42196
  var opacity = data.getItemVisual(dataIndex, 'opacity');
42197
+ var stroke = data.getVisual('borderColor');
41095
42198
  var itemStyleModel = itemModel.getModel('itemStyle');
41096
42199
  var hoverStyle = itemModel.getModel('emphasis.itemStyle').getBarItemStyle();
41097
42200
 
@@ -41101,7 +42204,8 @@ function updateStyle(
41101
42204
 
41102
42205
  el.useStyle(defaults(
41103
42206
  {
41104
- fill: color,
42207
+ stroke: isZeroOnPolar(layout) ? 'none' : stroke,
42208
+ fill: isZeroOnPolar(layout) ? 'none' : color,
41105
42209
  opacity: opacity
41106
42210
  },
41107
42211
  itemStyleModel.getBarItemStyle()
@@ -41120,7 +42224,9 @@ function updateStyle(
41120
42224
  seriesModel, dataIndex, labelPositionOutside
41121
42225
  );
41122
42226
  }
41123
-
42227
+ if (isZeroOnPolar(layout)) {
42228
+ hoverStyle.fill = hoverStyle.stroke = 'none';
42229
+ }
41124
42230
  setHoverStyle(el, hoverStyle);
41125
42231
  }
41126
42232
 
@@ -41441,6 +42547,60 @@ var dataSelectableMixin = {
41441
42547
  * under the License.
41442
42548
  */
41443
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
+
41444
42604
  var PieSeries = extendSeriesModel({
41445
42605
 
41446
42606
  type: 'series.pie',
@@ -41451,9 +42611,9 @@ var PieSeries = extendSeriesModel({
41451
42611
 
41452
42612
  // Enable legend selection for each data item
41453
42613
  // Use a function instead of direct access because data reference may changed
41454
- this.legendDataProvider = function () {
41455
- return this.getRawData();
41456
- };
42614
+ this.legendVisualProvider = new LegendVisualProvider(
42615
+ bind(this.getData, this), bind(this.getRawData, this)
42616
+ );
41457
42617
 
41458
42618
  this.updateSelectedMap(this._createSelectableList());
41459
42619
 
@@ -41468,7 +42628,10 @@ var PieSeries = extendSeriesModel({
41468
42628
  },
41469
42629
 
41470
42630
  getInitialData: function (option, ecModel) {
41471
- return createListSimply(this, ['value']);
42631
+ return createListSimply(this, {
42632
+ coordDimensions: ['value'],
42633
+ encodeDefaulter: curry(makeSeriesEncodeForNameBased, this)
42634
+ });
41472
42635
  },
41473
42636
 
41474
42637
  _createSelectableList: function () {
@@ -41557,12 +42720,28 @@ var PieSeries = extendSeriesModel({
41557
42720
 
41558
42721
  // cursor: null,
41559
42722
 
42723
+ left: 0,
42724
+ top: 0,
42725
+ right: 0,
42726
+ bottom: 0,
42727
+ width: null,
42728
+ height: null,
42729
+
41560
42730
  label: {
41561
42731
  // If rotate around circle
41562
42732
  rotate: false,
41563
42733
  show: true,
41564
42734
  // 'outer', 'inside', 'center'
41565
- 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
41566
42745
  // formatter: 标签文本格式器,同Tooltip.formatter,不支持异步回调
41567
42746
  // 默认使用全局文本样式,详见TEXTSTYLE
41568
42747
  // distance: 当position为inner时有效,为label位置到圆心的距离与圆半径(环状图为内外半径和)的比例系数
@@ -41868,7 +43047,7 @@ piePieceProto._updateLabel = function (data, idx, withAnimation) {
41868
43047
  {
41869
43048
  labelFetcher: data.hostModel,
41870
43049
  labelDataIndex: idx,
41871
- defaultText: data.getName(idx),
43050
+ defaultText: labelLayout.text,
41872
43051
  autoColor: visualColor,
41873
43052
  useInsideStyle: !!labelLayout.inside
41874
43053
  },
@@ -42164,33 +43343,20 @@ var dataColor = function (seriesType) {
42164
43343
  dataAll.getName(rawIdx) || (rawIdx + ''), seriesModel.__paletteScope,
42165
43344
  dataAll.count()
42166
43345
  );
42167
- // Legend may use the visual info in data before processed
42168
- dataAll.setItemVisual(rawIdx, 'color', color);
42169
-
42170
43346
  // Data is not filtered
42171
43347
  if (filteredIdx != null) {
42172
43348
  data.setItemVisual(filteredIdx, 'color', color);
42173
43349
  }
42174
43350
  }
42175
- else {
42176
- // Set data all color for legend
42177
- dataAll.setItemVisual(rawIdx, 'color', singleDataColor);
42178
- }
42179
43351
 
42180
43352
  if (!singleDataBorderColor) {
42181
43353
  var borderColor = itemModel.get('itemStyle.borderColor');
42182
- // Legend may use the visual info in data before processed
42183
- dataAll.setItemVisual(rawIdx, 'borderColor', borderColor);
42184
43354
 
42185
43355
  // Data is not filtered
42186
43356
  if (filteredIdx != null) {
42187
43357
  data.setItemVisual(filteredIdx, 'borderColor', borderColor);
42188
43358
  }
42189
43359
  }
42190
- else {
42191
- // Set data all borderColor for legend
42192
- dataAll.setItemVisual(rawIdx, 'borderColor', singleDataBorderColor);
42193
- }
42194
43360
  });
42195
43361
  }
42196
43362
  };
@@ -42219,13 +43385,17 @@ var dataColor = function (seriesType) {
42219
43385
 
42220
43386
  var RADIAN$1 = Math.PI / 180;
42221
43387
 
42222
- function adjustSingleSide(list, cx, cy, r, dir, viewWidth, viewHeight) {
43388
+ function adjustSingleSide(list, cx, cy, r, dir, viewWidth, viewHeight, viewLeft, viewTop, farthestX) {
42223
43389
  list.sort(function (a, b) {
42224
43390
  return a.y - b.y;
42225
43391
  });
42226
43392
 
42227
43393
  function shiftDown(start, end, delta, dir) {
42228
43394
  for (var j = start; j < end; j++) {
43395
+ if (list[j].y + delta > viewTop + viewHeight) {
43396
+ break;
43397
+ }
43398
+
42229
43399
  list[j].y += delta;
42230
43400
  if (j > start
42231
43401
  && j + 1 < end
@@ -42241,6 +43411,10 @@ function adjustSingleSide(list, cx, cy, r, dir, viewWidth, viewHeight) {
42241
43411
 
42242
43412
  function shiftUp(end, delta) {
42243
43413
  for (var j = end; j >= 0; j--) {
43414
+ if (list[j].y - delta < viewTop) {
43415
+ break;
43416
+ }
43417
+
42244
43418
  list[j].y -= delta;
42245
43419
  if (j > 0
42246
43420
  && list[j].y > list[j - 1].y + list[j - 1].height
@@ -42260,6 +43434,10 @@ function adjustSingleSide(list, cx, cy, r, dir, viewWidth, viewHeight) {
42260
43434
  : 0; // up
42261
43435
 
42262
43436
  for (var i = 0, l = list.length; i < l; i++) {
43437
+ if (list[i].labelAlignTo !== 'none') {
43438
+ continue;
43439
+ }
43440
+
42263
43441
  var deltaY = Math.abs(list[i].y - cy);
42264
43442
  var length = list[i].len;
42265
43443
  var length2 = list[i].len2;
@@ -42289,6 +43467,12 @@ function adjustSingleSide(list, cx, cy, r, dir, viewWidth, viewHeight) {
42289
43467
  var upList = [];
42290
43468
  var downList = [];
42291
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
+
42292
43476
  delta = list[i].y - lastY;
42293
43477
  if (delta < 0) {
42294
43478
  shiftDown(i, len, -delta, dir);
@@ -42310,39 +43494,85 @@ function adjustSingleSide(list, cx, cy, r, dir, viewWidth, viewHeight) {
42310
43494
  changeX(downList, true, cx, cy, r, dir);
42311
43495
  }
42312
43496
 
42313
- function avoidOverlap(labelLayoutList, cx, cy, r, viewWidth, viewHeight) {
43497
+ function avoidOverlap(labelLayoutList, cx, cy, r, viewWidth, viewHeight, viewLeft, viewTop) {
42314
43498
  var leftList = [];
42315
43499
  var rightList = [];
43500
+ var leftmostX = Number.MAX_VALUE;
43501
+ var rightmostX = -Number.MAX_VALUE;
42316
43502
  for (var i = 0; i < labelLayoutList.length; i++) {
42317
43503
  if (isPositionCenter(labelLayoutList[i])) {
42318
43504
  continue;
42319
43505
  }
42320
43506
  if (labelLayoutList[i].x < cx) {
43507
+ leftmostX = Math.min(leftmostX, labelLayoutList[i].x);
42321
43508
  leftList.push(labelLayoutList[i]);
42322
43509
  }
42323
43510
  else {
43511
+ rightmostX = Math.max(rightmostX, labelLayoutList[i].x);
42324
43512
  rightList.push(labelLayoutList[i]);
42325
43513
  }
42326
43514
  }
42327
43515
 
42328
- adjustSingleSide(rightList, cx, cy, r, 1, viewWidth, viewHeight);
42329
- 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);
42330
43518
 
42331
43519
  for (var i = 0; i < labelLayoutList.length; i++) {
42332
- if (isPositionCenter(labelLayoutList[i])) {
43520
+ var layout = labelLayoutList[i];
43521
+ if (isPositionCenter(layout)) {
42333
43522
  continue;
42334
43523
  }
42335
- var linePoints = labelLayoutList[i].linePoints;
43524
+
43525
+ var linePoints = layout.linePoints;
42336
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
+
42337
43556
  var dist = linePoints[1][0] - linePoints[2][0];
42338
- if (labelLayoutList[i].x < cx) {
42339
- 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
+ }
42340
43565
  }
42341
43566
  else {
42342
- 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;
42343
43574
  }
42344
- linePoints[1][1] = linePoints[2][1] = labelLayoutList[i].y;
42345
- linePoints[1][0] = linePoints[2][0] + dist;
43575
+ linePoints[1][1] = linePoints[2][1] = layout.y;
42346
43576
  }
42347
43577
  }
42348
43578
  }
@@ -42352,7 +43582,7 @@ function isPositionCenter(layout) {
42352
43582
  return layout.position === 'center';
42353
43583
  }
42354
43584
 
42355
- var labelLayout = function (seriesModel, r, viewWidth, viewHeight, sum) {
43585
+ var labelLayout = function (seriesModel, r, viewWidth, viewHeight, viewLeft, viewTop) {
42356
43586
  var data = seriesModel.getData();
42357
43587
  var labelLayoutList = [];
42358
43588
  var cx;
@@ -42367,10 +43597,17 @@ var labelLayout = function (seriesModel, r, viewWidth, viewHeight, sum) {
42367
43597
  var labelModel = itemModel.getModel('label');
42368
43598
  // Use position in normal or emphasis
42369
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();
42370
43605
 
42371
43606
  var labelLineModel = itemModel.getModel('labelLine');
42372
43607
  var labelLineLen = labelLineModel.get('length');
43608
+ labelLineLen = parsePercent$1(labelLineLen, viewWidth);
42373
43609
  var labelLineLen2 = labelLineModel.get('length2');
43610
+ labelLineLen2 = parsePercent$1(labelLineLen2, viewWidth);
42374
43611
 
42375
43612
  if (layout.angle < minShowLabelRadian) {
42376
43613
  return;
@@ -42388,6 +43625,12 @@ var labelLayout = function (seriesModel, r, viewWidth, viewHeight, sum) {
42388
43625
  cx = layout.cx;
42389
43626
  cy = layout.cy;
42390
43627
 
43628
+ var text = seriesModel.getFormattedLabel(idx, 'normal')
43629
+ || data.getName(idx);
43630
+ var textRect = getBoundingRect(
43631
+ text, font, textAlign, 'top'
43632
+ );
43633
+
42391
43634
  var isLabelInside = labelPosition === 'inside' || labelPosition === 'inner';
42392
43635
  if (labelPosition === 'center') {
42393
43636
  textX = layout.cx;
@@ -42408,14 +43651,25 @@ var labelLayout = function (seriesModel, r, viewWidth, viewHeight, sum) {
42408
43651
  var x3 = x2 + ((dx < 0 ? -1 : 1) * labelLineLen2);
42409
43652
  var y3 = y2;
42410
43653
 
42411
- 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
+ }
42412
43663
  textY = y3;
42413
43664
  linePoints = [[x1, y1], [x2, y2], [x3, y3]];
42414
43665
  }
42415
43666
 
42416
- 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'));
42417
43672
  }
42418
- var font = labelModel.getFont();
42419
43673
 
42420
43674
  var labelRotate;
42421
43675
  var rotate = labelModel.get('rotate');
@@ -42427,11 +43681,7 @@ var labelLayout = function (seriesModel, r, viewWidth, viewHeight, sum) {
42427
43681
  ? (dx < 0 ? -midAngle + Math.PI : -midAngle)
42428
43682
  : 0;
42429
43683
  }
42430
- var text = seriesModel.getFormattedLabel(idx, 'normal')
42431
- || data.getName(idx);
42432
- var textRect = getBoundingRect(
42433
- text, font, textAlign, 'top'
42434
- );
43684
+
42435
43685
  hasLabelRotate = !!labelRotate;
42436
43686
  layout.label = {
42437
43687
  x: textX,
@@ -42444,7 +43694,14 @@ var labelLayout = function (seriesModel, r, viewWidth, viewHeight, sum) {
42444
43694
  textAlign: textAlign,
42445
43695
  verticalAlign: 'middle',
42446
43696
  rotation: labelRotate,
42447
- 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
42448
43705
  };
42449
43706
 
42450
43707
  // Not layout the inside label
@@ -42453,7 +43710,7 @@ var labelLayout = function (seriesModel, r, viewWidth, viewHeight, sum) {
42453
43710
  }
42454
43711
  });
42455
43712
  if (!hasLabelRotate && seriesModel.get('avoidLabelOverlap')) {
42456
- avoidOverlap(labelLayoutList, cx, cy, r, viewWidth, viewHeight);
43713
+ avoidOverlap(labelLayoutList, cx, cy, r, viewWidth, viewHeight, viewLeft, viewTop);
42457
43714
  }
42458
43715
  };
42459
43716
 
@@ -42480,10 +43737,20 @@ var labelLayout = function (seriesModel, r, viewWidth, viewHeight, sum) {
42480
43737
  var PI2$4 = Math.PI * 2;
42481
43738
  var RADIAN = Math.PI / 180;
42482
43739
 
43740
+ function getViewRect(seriesModel, api) {
43741
+ return getLayoutRect(
43742
+ seriesModel.getBoxLayoutParams(), {
43743
+ width: api.getWidth(),
43744
+ height: api.getHeight()
43745
+ }
43746
+ );
43747
+ }
43748
+
42483
43749
  var pieLayout = function (seriesType, ecModel, api, payload) {
42484
43750
  ecModel.eachSeriesByType(seriesType, function (seriesModel) {
42485
43751
  var data = seriesModel.getData();
42486
43752
  var valueDim = data.mapDimension('value');
43753
+ var viewRect = getViewRect(seriesModel, api);
42487
43754
 
42488
43755
  var center = seriesModel.get('center');
42489
43756
  var radius = seriesModel.get('radius');
@@ -42495,11 +43762,11 @@ var pieLayout = function (seriesType, ecModel, api, payload) {
42495
43762
  center = [center, center];
42496
43763
  }
42497
43764
 
42498
- var width = api.getWidth();
42499
- var height = api.getHeight();
43765
+ var width = parsePercent$1(viewRect.width, api.getWidth());
43766
+ var height = parsePercent$1(viewRect.height, api.getHeight());
42500
43767
  var size = Math.min(width, height);
42501
- var cx = parsePercent$1(center[0], width);
42502
- 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;
42503
43770
  var r0 = parsePercent$1(radius[0], size / 2);
42504
43771
  var r = parsePercent$1(radius[1], size / 2);
42505
43772
 
@@ -42545,7 +43812,8 @@ var pieLayout = function (seriesType, ecModel, api, payload) {
42545
43812
  r0: r0,
42546
43813
  r: roseType
42547
43814
  ? NaN
42548
- : r
43815
+ : r,
43816
+ viewRect: viewRect
42549
43817
  });
42550
43818
  return;
42551
43819
  }
@@ -42578,7 +43846,8 @@ var pieLayout = function (seriesType, ecModel, api, payload) {
42578
43846
  r0: r0,
42579
43847
  r: roseType
42580
43848
  ? linearMap(value, extent, [r0, r])
42581
- : r
43849
+ : r,
43850
+ viewRect: viewRect
42582
43851
  });
42583
43852
 
42584
43853
  currentAngle = endAngle;
@@ -42616,7 +43885,7 @@ var pieLayout = function (seriesType, ecModel, api, payload) {
42616
43885
  }
42617
43886
  }
42618
43887
 
42619
- labelLayout(seriesModel, r, width, height);
43888
+ labelLayout(seriesModel, r, viewRect.width, viewRect.height, viewRect.x, viewRect.y);
42620
43889
  });
42621
43890
  };
42622
43891