echarts 4.2.0-rc.2 → 4.2.1

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 (82) hide show
  1. package/KEYS +60 -0
  2. package/LICENSE +7 -8
  3. package/dist/echarts-en.common.js +1250 -717
  4. package/dist/echarts-en.common.min.js +1 -1
  5. package/dist/echarts-en.js +2284 -1763
  6. package/dist/echarts-en.js.map +1 -1
  7. package/dist/echarts-en.min.js +1 -1
  8. package/dist/echarts-en.simple.js +1001 -560
  9. package/dist/echarts-en.simple.min.js +1 -1
  10. package/dist/echarts.common.js +1250 -717
  11. package/dist/echarts.common.min.js +1 -1
  12. package/dist/echarts.js +2284 -1763
  13. package/dist/echarts.js.map +1 -1
  14. package/dist/echarts.min.js +1 -1
  15. package/dist/echarts.simple.js +1001 -560
  16. package/dist/echarts.simple.min.js +1 -1
  17. package/dist/extension/dataTool.js +32 -33
  18. package/dist/extension/dataTool.js.map +1 -1
  19. package/lib/chart/graph/GraphView.js +17 -9
  20. package/lib/chart/graph/forceHelper.js +15 -20
  21. package/lib/chart/helper/Line.js +5 -1
  22. package/lib/chart/map/MapSeries.js +32 -26
  23. package/lib/chart/map/MapView.js +93 -40
  24. package/lib/chart/pie/labelLayout.js +23 -16
  25. package/lib/chart/sankey/sankeyLayout.js +18 -17
  26. package/lib/chart/sunburst/SunburstPiece.js +10 -5
  27. package/lib/chart/themeRiver/ThemeRiverSeries.js +26 -29
  28. package/lib/chart/tree/layoutHelper.js +57 -10
  29. package/lib/chart/treemap/treemapLayout.js +13 -7
  30. package/lib/component/axis/AxisBuilder.js +11 -2
  31. package/lib/component/helper/MapDraw.js +4 -0
  32. package/lib/component/helper/RoamController.js +3 -3
  33. package/lib/component/legend/LegendView.js +19 -1
  34. package/lib/component/legend/ScrollableLegendView.js +105 -70
  35. package/lib/coord/axisHelper.js +24 -1
  36. package/lib/coord/axisTickLabelBuilder.js +7 -12
  37. package/lib/coord/geo/Geo.js +1 -1
  38. package/lib/data/List.js +111 -36
  39. package/lib/echarts.js +13 -4
  40. package/lib/model/Model.js +1 -1
  41. package/lib/model/mixin/textStyle.js +1 -1
  42. package/lib/scale/Time.js +14 -4
  43. package/lib/util/format.js +30 -1
  44. package/lib/util/graphic.js +114 -27
  45. package/lib/util/model.js +27 -1
  46. package/lib/util/number.js +12 -33
  47. package/lib/visual/visualSolution.js +1 -1
  48. package/package.json +3 -4
  49. package/src/chart/graph/GraphView.js +15 -10
  50. package/src/chart/graph/forceHelper.js +17 -24
  51. package/src/chart/helper/Line.js +5 -1
  52. package/src/chart/map/MapSeries.js +28 -31
  53. package/src/chart/map/MapView.js +96 -38
  54. package/src/chart/pie/labelLayout.js +19 -14
  55. package/src/chart/sankey/sankeyLayout.js +17 -19
  56. package/src/chart/sunburst/SunburstPiece.js +11 -3
  57. package/src/chart/themeRiver/ThemeRiverSeries.js +18 -33
  58. package/src/chart/tree/layoutHelper.js +56 -10
  59. package/src/chart/treemap/treemapLayout.js +13 -7
  60. package/src/component/axis/AxisBuilder.js +7 -1
  61. package/src/component/helper/MapDraw.js +5 -1
  62. package/src/component/helper/RoamController.js +3 -4
  63. package/src/component/legend/LegendView.js +20 -1
  64. package/src/component/legend/ScrollableLegendView.js +119 -85
  65. package/src/coord/axisHelper.js +19 -0
  66. package/src/coord/axisTickLabelBuilder.js +10 -13
  67. package/src/coord/geo/Geo.js +1 -1
  68. package/src/data/List.js +107 -28
  69. package/src/echarts.js +11 -5
  70. package/src/model/Model.js +1 -1
  71. package/src/model/mixin/textStyle.js +1 -0
  72. package/src/scale/Time.js +14 -4
  73. package/src/util/format.js +39 -1
  74. package/src/util/graphic.js +110 -28
  75. package/src/util/model.js +25 -0
  76. package/src/util/number.js +12 -33
  77. package/src/visual/visualSolution.js +1 -1
  78. package/extension/dataTool/quantile.js +0 -82
  79. package/lib/component/tooltip/TooltipContentManager.js +0 -126
  80. package/lib/util/nest.js +0 -148
  81. package/src/component/tooltip/TooltipContentManager.js +0 -120
  82. package/src/util/nest.js +0 -127
package/src/data/List.js CHANGED
@@ -35,6 +35,7 @@ import {summarizeDimensions} from './helper/dimensionHelper';
35
35
  var isObject = zrUtil.isObject;
36
36
 
37
37
  var UNDEFINED = 'undefined';
38
+ var INDEX_NOT_FOUND = -1;
38
39
 
39
40
  // Use prefix to avoid index to be the same as otherIdList[idx],
40
41
  // which will cause weird udpate animation.
@@ -54,6 +55,7 @@ var dataCtors = {
54
55
  // Caution: MUST not use `new CtorUint32Array(arr, 0, len)`, because the Ctor of array is
55
56
  // different from the Ctor of typed array.
56
57
  var CtorUint32Array = typeof Uint32Array === UNDEFINED ? Array : Uint32Array;
58
+ var CtorInt32Array = typeof Int32Array === UNDEFINED ? Array : Int32Array;
57
59
  var CtorUint16Array = typeof Uint16Array === UNDEFINED ? Array : Uint16Array;
58
60
 
59
61
  function getIndicesCtor(list) {
@@ -414,10 +416,10 @@ listProto.initData = function (data, nameList, dimValueGetter) {
414
416
  this.defaultDimValueGetter = defaultDimValueGetters[
415
417
  this._rawData.getSource().sourceFormat
416
418
  ];
417
-
418
419
  // Default dim value getter
419
420
  this._dimValueGetter = dimValueGetter = dimValueGetter
420
421
  || this.defaultDimValueGetter;
422
+ this._dimValueGetterArrayRows = defaultDimValueGetters.arrayRows;
421
423
 
422
424
  // Reset raw extent.
423
425
  this._rawExtent = {};
@@ -434,6 +436,9 @@ listProto.getProvider = function () {
434
436
  return this._rawData;
435
437
  };
436
438
 
439
+ /**
440
+ * Caution: Can be only called on raw data (before `this._indices` created).
441
+ */
437
442
  listProto.appendData = function (data) {
438
443
  if (__DEV__) {
439
444
  zrUtil.assert(!this._indices, 'appendData can only be called on raw data.');
@@ -449,6 +454,77 @@ listProto.appendData = function (data) {
449
454
  this._initDataFromProvider(start, end);
450
455
  };
451
456
 
457
+ /**
458
+ * Caution: Can be only called on raw data (before `this._indices` created).
459
+ * This method does not modify `rawData` (`dataProvider`), but only
460
+ * add values to storage.
461
+ *
462
+ * The final count will be increased by `Math.max(values.length, names.length)`.
463
+ *
464
+ * @param {Array.<Array.<*>>} values That is the SourceType: 'arrayRows', like
465
+ * [
466
+ * [12, 33, 44],
467
+ * [NaN, 43, 1],
468
+ * ['-', 'asdf', 0]
469
+ * ]
470
+ * Each item is exaclty cooresponding to a dimension.
471
+ * @param {Array.<string>} [names]
472
+ */
473
+ listProto.appendValues = function (values, names) {
474
+ var chunkSize = this._chunkSize;
475
+ var storage = this._storage;
476
+ var dimensions = this.dimensions;
477
+ var dimLen = dimensions.length;
478
+ var rawExtent = this._rawExtent;
479
+
480
+ var start = this.count();
481
+ var end = start + Math.max(values.length, names ? names.length : 0);
482
+ var originalChunkCount = this._chunkCount;
483
+
484
+ for (var i = 0; i < dimLen; i++) {
485
+ var dim = dimensions[i];
486
+ if (!rawExtent[dim]) {
487
+ rawExtent[dim] = getInitialExtent();
488
+ }
489
+ if (!storage[dim]) {
490
+ storage[dim] = [];
491
+ }
492
+ prepareChunks(storage, this._dimensionInfos[dim], chunkSize, originalChunkCount, end);
493
+ this._chunkCount = storage[dim].length;
494
+ }
495
+
496
+ var emptyDataItem = new Array(dimLen);
497
+ for (var idx = start; idx < end; idx++) {
498
+ var sourceIdx = idx - start;
499
+ var chunkIndex = Math.floor(idx / chunkSize);
500
+ var chunkOffset = idx % chunkSize;
501
+
502
+ // Store the data by dimensions
503
+ for (var k = 0; k < dimLen; k++) {
504
+ var dim = dimensions[k];
505
+ var val = this._dimValueGetterArrayRows(
506
+ values[sourceIdx] || emptyDataItem, dim, sourceIdx, k
507
+ );
508
+ storage[dim][chunkIndex][chunkOffset] = val;
509
+
510
+ var dimRawExtent = rawExtent[dim];
511
+ val < dimRawExtent[0] && (dimRawExtent[0] = val);
512
+ val > dimRawExtent[1] && (dimRawExtent[1] = val);
513
+ }
514
+
515
+ if (names) {
516
+ this._nameList[idx] = names[sourceIdx];
517
+ }
518
+ }
519
+
520
+ this._rawCount = this._count = end;
521
+
522
+ // Reset data extent
523
+ this._extent = {};
524
+
525
+ prepareInvertedIndex(this);
526
+ };
527
+
452
528
  listProto._initDataFromProvider = function (start, end) {
453
529
  // Optimize.
454
530
  if (start >= end) {
@@ -467,8 +543,7 @@ listProto._initDataFromProvider = function (start, end) {
467
543
  var nameRepeatCount = this._nameRepeatCount = {};
468
544
  var nameDimIdx;
469
545
 
470
- var chunkCount = this._chunkCount;
471
- var lastChunkIndex = chunkCount - 1;
546
+ var originalChunkCount = this._chunkCount;
472
547
  for (var i = 0; i < dimLen; i++) {
473
548
  var dim = dimensions[i];
474
549
  if (!rawExtent[dim]) {
@@ -482,26 +557,13 @@ listProto._initDataFromProvider = function (start, end) {
482
557
  if (dimInfo.otherDims.itemId === 0) {
483
558
  this._idDimIdx = i;
484
559
  }
485
- var DataCtor = dataCtors[dimInfo.type];
486
560
 
487
561
  if (!storage[dim]) {
488
562
  storage[dim] = [];
489
563
  }
490
- var resizeChunkArray = storage[dim][lastChunkIndex];
491
- if (resizeChunkArray && resizeChunkArray.length < chunkSize) {
492
- var newStore = new DataCtor(Math.min(end - lastChunkIndex * chunkSize, chunkSize));
493
- // The cost of the copy is probably inconsiderable
494
- // within the initial chunkSize.
495
- for (var j = 0; j < resizeChunkArray.length; j++) {
496
- newStore[j] = resizeChunkArray[j];
497
- }
498
- storage[dim][lastChunkIndex] = newStore;
499
- }
500
564
 
501
- // Create new chunks.
502
- for (var k = chunkCount * chunkSize; k < end; k += chunkSize) {
503
- storage[dim].push(new DataCtor(Math.min(end - k, chunkSize)));
504
- }
565
+ prepareChunks(storage, dimInfo, chunkSize, originalChunkCount, end);
566
+
505
567
  this._chunkCount = storage[dim].length;
506
568
  }
507
569
 
@@ -527,12 +589,8 @@ listProto._initDataFromProvider = function (start, end) {
527
589
  dimStorage[chunkOffset] = val;
528
590
 
529
591
  var dimRawExtent = rawExtent[dim];
530
- if (val < dimRawExtent[0]) {
531
- dimRawExtent[0] = val;
532
- }
533
- if (val > dimRawExtent[1]) {
534
- dimRawExtent[1] = val;
535
- }
592
+ val < dimRawExtent[0] && (dimRawExtent[0] = val);
593
+ val > dimRawExtent[1] && (dimRawExtent[1] = val);
536
594
  }
537
595
 
538
596
  // ??? FIXME not check by pure but sourceFormat?
@@ -591,6 +649,27 @@ listProto._initDataFromProvider = function (start, end) {
591
649
  prepareInvertedIndex(this);
592
650
  };
593
651
 
652
+ function prepareChunks(storage, dimInfo, chunkSize, chunkCount, end) {
653
+ var DataCtor = dataCtors[dimInfo.type];
654
+ var lastChunkIndex = chunkCount - 1;
655
+ var dim = dimInfo.name;
656
+ var resizeChunkArray = storage[dim][lastChunkIndex];
657
+ if (resizeChunkArray && resizeChunkArray.length < chunkSize) {
658
+ var newStore = new DataCtor(Math.min(end - lastChunkIndex * chunkSize, chunkSize));
659
+ // The cost of the copy is probably inconsiderable
660
+ // within the initial chunkSize.
661
+ for (var j = 0; j < resizeChunkArray.length; j++) {
662
+ newStore[j] = resizeChunkArray[j];
663
+ }
664
+ storage[dim][lastChunkIndex] = newStore;
665
+ }
666
+
667
+ // Create new chunks.
668
+ for (var k = chunkCount * chunkSize; k < end; k += chunkSize) {
669
+ storage[dim].push(new DataCtor(Math.min(end - k, chunkSize)));
670
+ }
671
+ }
672
+
594
673
  function prepareInvertedIndex(list) {
595
674
  var invertedIndicesMap = list._invertedIndicesMap;
596
675
  zrUtil.each(invertedIndicesMap, function (invertedIndices, dim) {
@@ -599,13 +678,13 @@ function prepareInvertedIndex(list) {
599
678
  // Currently, only dimensions that has ordinalMeta can create inverted indices.
600
679
  var ordinalMeta = dimInfo.ordinalMeta;
601
680
  if (ordinalMeta) {
602
- invertedIndices = invertedIndicesMap[dim] = new CtorUint32Array(
681
+ invertedIndices = invertedIndicesMap[dim] = new CtorInt32Array(
603
682
  ordinalMeta.categories.length
604
683
  );
605
684
  // The default value of TypedArray is 0. To avoid miss
606
- // mapping to 0, we should set it as NaN.
685
+ // mapping to 0, we should set it as INDEX_NOT_FOUND.
607
686
  for (var i = 0; i < invertedIndices.length; i++) {
608
- invertedIndices[i] = NaN;
687
+ invertedIndices[i] = INDEX_NOT_FOUND;
609
688
  }
610
689
  for (var i = 0; i < list._count; i++) {
611
690
  // Only support the case that all values are distinct.
@@ -970,7 +1049,7 @@ listProto.rawIndexOf = function (dim, value) {
970
1049
  }
971
1050
  var rawIndex = invertedIndices[value];
972
1051
  if (rawIndex == null || isNaN(rawIndex)) {
973
- return -1;
1052
+ return INDEX_NOT_FOUND;
974
1053
  }
975
1054
  return rawIndex;
976
1055
  };
package/src/echarts.js CHANGED
@@ -51,10 +51,10 @@ var isFunction = zrUtil.isFunction;
51
51
  var isObject = zrUtil.isObject;
52
52
  var parseClassType = ComponentModel.parseClassType;
53
53
 
54
- export var version = '4.2.0';
54
+ export var version = '4.2.1';
55
55
 
56
56
  export var dependencies = {
57
- zrender: '4.0.5'
57
+ zrender: '4.0.6'
58
58
  };
59
59
 
60
60
  var TEST_FRAME_REMAIN_TIME = 1;
@@ -1506,7 +1506,7 @@ var MOUSE_EVENT_NAMES = [
1506
1506
  */
1507
1507
  echartsProto._initEvents = function () {
1508
1508
  each(MOUSE_EVENT_NAMES, function (eveName) {
1509
- this._zr.on(eveName, function (e) {
1509
+ var handler = function (e) {
1510
1510
  var ecModel = this.getModel();
1511
1511
  var el = e.target;
1512
1512
  var params;
@@ -1575,8 +1575,14 @@ echartsProto._initEvents = function () {
1575
1575
 
1576
1576
  this.trigger(eveName, params);
1577
1577
  }
1578
-
1579
- }, this);
1578
+ };
1579
+ // Consider that some component (like tooltip, brush, ...)
1580
+ // register zr event handler, but user event handler might
1581
+ // do anything, such as call `setOption` or `dispatchAction`,
1582
+ // which probably update any of the content and probably
1583
+ // cause problem if it is called previous other inner handlers.
1584
+ handler.zrEventfulCallAtLast = true;
1585
+ this._zr.on(eveName, handler, this);
1580
1586
  }, this);
1581
1587
 
1582
1588
  each(eventActionMap, function (actionType, eventType) {
@@ -37,7 +37,7 @@ var inner = makeInner();
37
37
  /**
38
38
  * @alias module:echarts/model/Model
39
39
  * @constructor
40
- * @param {Object} option
40
+ * @param {Object} [option]
41
41
  * @param {module:echarts/model/Model} [parentModel]
42
42
  * @param {module:echarts/model/Global} [ecModel]
43
43
  */
@@ -56,6 +56,7 @@ export default {
56
56
  this.getShallow('align'),
57
57
  this.getShallow('verticalAlign') || this.getShallow('baseline'),
58
58
  this.getShallow('padding'),
59
+ this.getShallow('lineHeight'),
59
60
  this.getShallow('rich'),
60
61
  this.getShallow('truncateText')
61
62
  );
package/src/scale/Time.js CHANGED
@@ -18,11 +18,16 @@
18
18
  */
19
19
 
20
20
  /*
21
- * The `scaleLevels` references to d3.js. The use of the source
22
- * code of this file is also subject to the terms and consitions
23
- * of its license (BSD-3Clause, see <echarts/src/licenses/LICENSE-d3>).
21
+ * A third-party license is embeded for some of the code in this file:
22
+ * The "scaleLevels" was originally copied from "d3.js" with some
23
+ * modifications made for this project.
24
+ * (See more details in the comment on the definition of "scaleLevels" below.)
25
+ * The use of the source code of this file is also subject to the terms
26
+ * and consitions of the license of "d3.js" (BSD-3Clause, see
27
+ * </licenses/LICENSE-d3>).
24
28
  */
25
29
 
30
+
26
31
  // [About UTC and local time zone]:
27
32
  // In most cases, `number.parseDate` will treat input data string as local time
28
33
  // (except time zone is specified in time string). And `format.formateTime` returns
@@ -171,7 +176,12 @@ zrUtil.each(['contain', 'normalize'], function (methodName) {
171
176
  };
172
177
  });
173
178
 
174
- // Steps from d3, see the license statement at the top of this file.
179
+ /**
180
+ * This implementation was originally copied from "d3.js"
181
+ * <https://github.com/d3/d3/blob/b516d77fb8566b576088e73410437494717ada26/src/time/scale.js>
182
+ * with some modifications made for this program.
183
+ * See the license statement at the head of this file.
184
+ */
175
185
  var scaleLevels = [
176
186
  // Format interval
177
187
  ['hh:mm:ss', ONE_SECOND], // 1s
@@ -236,4 +236,42 @@ export function capitalFirst(str) {
236
236
 
237
237
  export var truncateText = textContain.truncateText;
238
238
 
239
- export var getTextRect = textContain.getBoundingRect;
239
+ /**
240
+ * @public
241
+ * @param {Object} opt
242
+ * @param {string} opt.text
243
+ * @param {string} opt.font
244
+ * @param {string} [opt.textAlign='left']
245
+ * @param {string} [opt.textVerticalAlign='top']
246
+ * @param {Array.<number>} [opt.textPadding]
247
+ * @param {number} [opt.textLineHeight]
248
+ * @param {Object} [opt.rich]
249
+ * @param {Object} [opt.truncate]
250
+ * @return {Object} {x, y, width, height, lineHeight}
251
+ */
252
+ export function getTextBoundingRect(opt) {
253
+ return textContain.getBoundingRect(
254
+ opt.text,
255
+ opt.font,
256
+ opt.textAlign,
257
+ opt.textVerticalAlign,
258
+ opt.textPadding,
259
+ opt.textLineHeight,
260
+ opt.rich,
261
+ opt.truncate
262
+ );
263
+ }
264
+
265
+ /**
266
+ * @deprecated
267
+ * the `textLineHeight` was added later.
268
+ * For backward compatiblility, put it as the last parameter.
269
+ * But deprecated this interface. Please use `getTextBoundingRect` instead.
270
+ */
271
+ export function getTextRect(
272
+ text, font, textAlign, textVerticalAlign, textPadding, rich, truncate, textLineHeight
273
+ ) {
274
+ return textContain.getBoundingRect(
275
+ text, font, textAlign, textVerticalAlign, textPadding, textLineHeight, rich, truncate
276
+ );
277
+ }
@@ -49,6 +49,8 @@ var mathMin = Math.min;
49
49
 
50
50
  var EMPTY_OBJ = {};
51
51
 
52
+ export var Z2_EMPHASIS_LIFT = 1;
53
+
52
54
  /**
53
55
  * Extend shape with parameters
54
56
  */
@@ -266,11 +268,12 @@ function cacheElementStl(el) {
266
268
 
267
269
  var hoverStyle = el.__hoverStl;
268
270
  if (!hoverStyle) {
269
- el.__normalStl = null;
271
+ el.__cachedNormalStl = el.__cachedNormalZ2 = null;
270
272
  return;
271
273
  }
272
274
 
273
- var normalStyle = el.__normalStl = {};
275
+ var normalStyle = el.__cachedNormalStl = {};
276
+ el.__cachedNormalZ2 = el.z2;
274
277
  var elStyle = el.style;
275
278
 
276
279
  for (var name in hoverStyle) {
@@ -308,9 +311,6 @@ function doSingleEnterHover(el) {
308
311
  targetStyle = elTarget.style;
309
312
  }
310
313
 
311
- // Consider case: only `position: 'top'` is set on emphasis, then text
312
- // color should be returned to `autoColor`, rather than remain '#fff'.
313
- // So we should rollback then apply again after style merging.
314
314
  rollbackDefaultTextStyle(targetStyle);
315
315
 
316
316
  if (!useHoverLayer) {
@@ -345,7 +345,7 @@ function doSingleEnterHover(el) {
345
345
 
346
346
  if (!useHoverLayer) {
347
347
  el.dirty(false);
348
- el.z2 += 1;
348
+ el.z2 += Z2_EMPHASIS_LIFT;
349
349
  }
350
350
  }
351
351
 
@@ -356,32 +356,34 @@ function setDefaultHoverFillStroke(targetStyle, hoverStyle, prop) {
356
356
  }
357
357
 
358
358
  function doSingleLeaveHover(el) {
359
- if (el.__highlighted) {
360
- doSingleRestoreHoverStyle(el);
361
- el.__highlighted = false;
359
+ var highlighted = el.__highlighted;
360
+
361
+ if (!highlighted) {
362
+ return;
362
363
  }
363
- }
364
364
 
365
- function doSingleRestoreHoverStyle(el) {
366
- var highlighted = el.__highlighted;
365
+ el.__highlighted = false;
367
366
 
368
367
  if (highlighted === 'layer') {
369
368
  el.__zr && el.__zr.removeHover(el);
370
369
  }
371
370
  else if (highlighted) {
372
371
  var style = el.style;
373
- var normalStl = el.__normalStl;
374
372
 
373
+ var normalStl = el.__cachedNormalStl;
375
374
  if (normalStl) {
376
375
  rollbackDefaultTextStyle(style);
377
-
378
376
  // Consider null/undefined value, should use
379
377
  // `setStyle` but not `extendFrom(stl, true)`.
380
378
  el.setStyle(normalStl);
381
-
382
379
  applyDefaultTextStyle(style);
383
-
384
- el.z2 -= 1;
380
+ }
381
+ // `__cachedNormalZ2` will not be reset if calling `setElementHoverStyle`
382
+ // when `el` is on emphasis state. So here by comparing with 1, we try
383
+ // hard to make the bug case rare.
384
+ var normalZ2 = el.__cachedNormalZ2;
385
+ if (normalZ2 != null && el.z2 - normalZ2 === Z2_EMPHASIS_LIFT) {
386
+ el.z2 = normalZ2;
385
387
  }
386
388
  }
387
389
  }
@@ -395,7 +397,10 @@ function traverseCall(el, method) {
395
397
  }
396
398
 
397
399
  /**
398
- * Set hover style of element.
400
+ * Set hover style (namely "emphasis style") of element, based on the current
401
+ * style of the given `el`.
402
+ * This method should be called after all of the normal styles have been adopted
403
+ * to the `el`. See the reason on `setHoverStyle`.
399
404
  *
400
405
  * @param {module:zrender/Element} el Should not be `zrender/container/Group`.
401
406
  * @param {Object|boolean} [hoverStl] The specified hover style.
@@ -407,11 +412,29 @@ function traverseCall(el, method) {
407
412
  * @param {boolean} [opt.hoverSilentOnTouch=false] See `graphic.setAsHoverStyleTrigger`
408
413
  */
409
414
  export function setElementHoverStyle(el, hoverStl) {
415
+ // For performance consideration, it might be better to make the "hover style" only the
416
+ // difference properties from the "normal style", but not a entire copy of all styles.
410
417
  hoverStl = el.__hoverStl = hoverStl !== false && (hoverStl || {});
411
418
  el.__hoverStlDirty = true;
412
419
 
420
+ // FIXME
421
+ // It is not completely right to save "normal"/"emphasis" flag on elements.
422
+ // It probably should be saved on `data` of series. Consider the cases:
423
+ // (1) A highlighted elements are moved out of the view port and re-enter
424
+ // again by dataZoom.
425
+ // (2) call `setOption` and replace elements totally when they are highlighted.
413
426
  if (el.__highlighted) {
427
+ // Consider the case:
428
+ // The styles of a highlighted `el` is being updated. The new "emphasis style"
429
+ // should be adapted to the `el`. Notice here new "normal styles" should have
430
+ // been set outside and the cached "normal style" is out of date.
431
+ el.__cachedNormalStl = null;
432
+ // Do not clear `__cachedNormalZ2` here, because setting `z2` is not a constraint
433
+ // of this method. In most cases, `z2` is not set and hover style should be able
434
+ // to rollback. Of course, that would bring bug, but only in a rare case, see
435
+ // `doSingleLeaveHover` for details.
414
436
  doSingleLeaveHover(el);
437
+
415
438
  doSingleEnterHover(el);
416
439
  }
417
440
  }
@@ -460,12 +483,29 @@ function leaveEmphasis() {
460
483
  }
461
484
 
462
485
  /**
463
- * Set hover style of element.
486
+ * Set hover style (namely "emphasis style") of element,
487
+ * based on the current style of the given `el`.
488
+ *
489
+ * (1)
490
+ * **CONSTRAINTS** for this method:
491
+ * <A> This method MUST be called after all of the normal styles having been adopted
492
+ * to the `el`.
493
+ * <B> The input `hoverStyle` (that is, "emphasis style") MUST be the subset of the
494
+ * "normal style" having been set to the el.
495
+ * <C> `color` MUST be one of the "normal styles" (because color might be lifted as
496
+ * a default hover style).
464
497
  *
465
- * [Caveat]:
466
- * This method can be called repeatly and achieve the same result.
498
+ * The reason: this method treat the current style of the `el` as the "normal style"
499
+ * and cache them when enter/update the "emphasis style". Consider the case: the `el`
500
+ * is in "emphasis" state and `setOption`/`dispatchAction` trigger the style updating
501
+ * logic, where the el should shift from the original emphasis style to the new
502
+ * "emphasis style" and should be able to "downplay" back to the new "normal style".
467
503
  *
468
- * [Usage]:
504
+ * Indeed, it is error-prone to make a interface has so many constraints, but I have
505
+ * not found a better solution yet to fit the backward compatibility, performance and
506
+ * the current programming style.
507
+ *
508
+ * (2)
469
509
  * Call the method for a "root" element once. Do not call it for each descendants.
470
510
  * If the descendants elemenets of a group has itself hover style different from the
471
511
  * root group, we can simply mount the style on `el.hoverStyle` for them, but should
@@ -520,6 +560,7 @@ export function setAsHoverStyleTrigger(el, opt) {
520
560
  }
521
561
 
522
562
  /**
563
+ * See more info in `setTextStyleCommon`.
523
564
  * @param {Object|module:zrender/graphic/Style} normalStyle
524
565
  * @param {Object} emphasisStyle
525
566
  * @param {module:echarts/model/Model} normalModel
@@ -592,6 +633,7 @@ export function setLabelStyle(
592
633
 
593
634
  /**
594
635
  * Set basic textStyle properties.
636
+ * See more info in `setTextStyleCommon`.
595
637
  * @param {Object|module:zrender/graphic/Style} textStyle
596
638
  * @param {module:echarts/model/Model} model
597
639
  * @param {Object} [specifiedTextStyle] Can be overrided by settings in model.
@@ -610,6 +652,7 @@ export function setTextStyle(
610
652
 
611
653
  /**
612
654
  * Set text option in the style.
655
+ * See more info in `setTextStyleCommon`.
613
656
  * @deprecated
614
657
  * @param {Object} textStyle
615
658
  * @param {module:echarts/model/Model} labelModel
@@ -632,7 +675,23 @@ export function setText(textStyle, labelModel, defaultColor) {
632
675
  }
633
676
 
634
677
  /**
635
- * {
678
+ * The uniform entry of set text style, that is, retrieve style definitions
679
+ * from `model` and set to `textStyle` object.
680
+ *
681
+ * Never in merge mode, but in overwrite mode, that is, all of the text style
682
+ * properties will be set. (Consider the states of normal and emphasis and
683
+ * default value can be adopted, merge would make the logic too complicated
684
+ * to manage.)
685
+ *
686
+ * The `textStyle` object can either be a plain object or an instance of
687
+ * `zrender/src/graphic/Style`, and either be the style of normal or emphasis.
688
+ * After this mothod called, the `textStyle` object can then be used in
689
+ * `el.setStyle(textStyle)` or `el.hoverStyle = textStyle`.
690
+ *
691
+ * Default value will be adopted and `insideRollbackOpt` will be created.
692
+ * See `applyDefaultTextStyle` `rollbackDefaultTextStyle` for more details.
693
+ *
694
+ * opt: {
636
695
  * disableBox: boolean, Whether diable drawing box of block (outer most).
637
696
  * isRectText: boolean,
638
697
  * autoColor: string, specify a color when color is 'auto',
@@ -813,14 +872,27 @@ function getAutoColor(color, opt) {
813
872
  return color !== 'auto' ? color : (opt && opt.autoColor) ? opt.autoColor : null;
814
873
  }
815
874
 
816
- // When text position is `inside` and `textFill` not specified, we
817
- // provide a mechanism to auto make text border for better view. But
818
- // text position changing when hovering or being emphasis should be
819
- // considered, where the `insideRollback` enables to restore the style.
875
+ /**
876
+ * Give some default value to the input `textStyle` object, based on the current settings
877
+ * in this `textStyle` object.
878
+ *
879
+ * The Scenario:
880
+ * when text position is `inside` and `textFill` is not specified, we show
881
+ * text border by default for better view. But it should be considered that text position
882
+ * might be changed when hovering or being emphasis, where the `insideRollback` is used to
883
+ * restore the style.
884
+ *
885
+ * Usage (& NOTICE):
886
+ * When a style object (eithor plain object or instance of `zrender/src/graphic/Style`) is
887
+ * about to be modified on its text related properties, `rollbackDefaultTextStyle` should
888
+ * be called before the modification and `applyDefaultTextStyle` should be called after that.
889
+ * (For the case that all of the text related properties is reset, like `setTextStyleCommon`
890
+ * does, `rollbackDefaultTextStyle` is not needed to be called).
891
+ */
820
892
  function applyDefaultTextStyle(textStyle) {
821
893
  var opt = textStyle.insideRollbackOpt;
822
894
 
823
- // Only insideRollbackOpt create (setTextStyleCommon used),
895
+ // Only `insideRollbackOpt` created (in `setTextStyleCommon`),
824
896
  // applyDefaultTextStyle works.
825
897
  if (!opt || textStyle.textFill != null) {
826
898
  return;
@@ -864,6 +936,16 @@ function applyDefaultTextStyle(textStyle) {
864
936
  }
865
937
  }
866
938
 
939
+ /**
940
+ * Consider the case: in a scatter,
941
+ * label: {
942
+ * normal: {position: 'inside'},
943
+ * emphasis: {position: 'top'}
944
+ * }
945
+ * In the normal state, the `textFill` will be set as '#fff' for pretty view (see
946
+ * `applyDefaultTextStyle`), but when switching to emphasis state, the `textFill`
947
+ * should be retured to 'autoColor', but not keep '#fff'.
948
+ */
867
949
  function rollbackDefaultTextStyle(style) {
868
950
  var insideRollback = style.insideRollback;
869
951
  if (insideRollback) {
package/src/util/model.js CHANGED
@@ -534,3 +534,28 @@ export function getTooltipRenderMode(renderModeOption) {
534
534
  return renderModeOption || 'html';
535
535
  }
536
536
  }
537
+
538
+ /**
539
+ * Group a list by key.
540
+ *
541
+ * @param {Array} array
542
+ * @param {Function} getKey
543
+ * param {*} Array item
544
+ * return {string} key
545
+ * @return {Object} Result
546
+ * {Array}: keys,
547
+ * {module:zrender/core/util/HashMap} buckets: {key -> Array}
548
+ */
549
+ export function groupData(array, getKey) {
550
+ var buckets = zrUtil.createHashMap();
551
+ var keys = [];
552
+
553
+ zrUtil.each(array, function (item) {
554
+ var key = getKey(item);
555
+ (buckets.get(key)
556
+ || (keys.push(key), buckets.set(key, []))
557
+ ).push(item);
558
+ });
559
+
560
+ return {keys: keys, buckets: buckets};
561
+ }