@visactor/vrender-components 0.13.9-alpha.5 → 0.14.0-alpha.2

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 (89) hide show
  1. package/cjs/axis/base.d.ts +3 -1
  2. package/cjs/axis/base.js +4 -2
  3. package/cjs/axis/base.js.map +1 -1
  4. package/cjs/axis/circle.d.ts +3 -1
  5. package/cjs/axis/circle.js +3 -1
  6. package/cjs/axis/circle.js.map +1 -1
  7. package/cjs/axis/constant.d.ts +2 -1
  8. package/cjs/axis/constant.js +1 -1
  9. package/cjs/axis/constant.js.map +1 -1
  10. package/cjs/axis/line.d.ts +5 -2
  11. package/cjs/axis/line.js +41 -9
  12. package/cjs/axis/line.js.map +1 -1
  13. package/cjs/axis/type.d.ts +6 -2
  14. package/cjs/axis/type.js.map +1 -1
  15. package/cjs/index.d.ts +1 -1
  16. package/cjs/index.js +1 -1
  17. package/cjs/index.js.map +1 -1
  18. package/cjs/label/base.d.ts +1 -3
  19. package/cjs/label/base.js +30 -69
  20. package/cjs/label/base.js.map +1 -1
  21. package/cjs/label/dataLabel.js +2 -3
  22. package/cjs/label/dataLabel.js.map +1 -1
  23. package/cjs/label/index.d.ts +0 -1
  24. package/cjs/label/index.js +1 -2
  25. package/cjs/label/index.js.map +1 -1
  26. package/cjs/label/type.d.ts +2 -41
  27. package/cjs/label/type.js.map +1 -1
  28. package/cjs/link-path/type.js +2 -1
  29. package/cjs/marker/base.js +1 -2
  30. package/cjs/pager/index.js +1 -1
  31. package/cjs/pager/pager.js +1 -1
  32. package/cjs/util/align.d.ts +2 -0
  33. package/cjs/util/align.js +60 -0
  34. package/cjs/util/align.js.map +1 -0
  35. package/cjs/util/common.d.ts +3 -1
  36. package/cjs/util/common.js +14 -2
  37. package/cjs/util/common.js.map +1 -1
  38. package/dist/index.js +211 -870
  39. package/dist/index.min.js +1 -1
  40. package/es/axis/base.d.ts +3 -1
  41. package/es/axis/base.js +4 -2
  42. package/es/axis/base.js.map +1 -1
  43. package/es/axis/circle.d.ts +3 -1
  44. package/es/axis/circle.js +3 -1
  45. package/es/axis/circle.js.map +1 -1
  46. package/es/axis/constant.d.ts +2 -1
  47. package/es/axis/constant.js +1 -1
  48. package/es/axis/constant.js.map +1 -1
  49. package/es/axis/line.d.ts +5 -2
  50. package/es/axis/line.js +45 -9
  51. package/es/axis/line.js.map +1 -1
  52. package/es/axis/type.d.ts +6 -2
  53. package/es/axis/type.js.map +1 -1
  54. package/es/index.d.ts +1 -1
  55. package/es/index.js +1 -1
  56. package/es/index.js.map +1 -1
  57. package/es/label/base.d.ts +1 -3
  58. package/es/label/base.js +32 -71
  59. package/es/label/base.js.map +1 -1
  60. package/es/label/dataLabel.js +1 -4
  61. package/es/label/dataLabel.js.map +1 -1
  62. package/es/label/index.d.ts +0 -1
  63. package/es/label/index.js +0 -2
  64. package/es/label/index.js.map +1 -1
  65. package/es/label/type.d.ts +2 -41
  66. package/es/label/type.js.map +1 -1
  67. package/es/link-path/type.js +2 -1
  68. package/es/marker/base.js +1 -2
  69. package/es/pager/index.js +1 -1
  70. package/es/pager/pager.js +1 -1
  71. package/es/util/align.d.ts +2 -0
  72. package/es/util/align.js +54 -0
  73. package/es/util/align.js.map +1 -0
  74. package/es/util/common.d.ts +3 -1
  75. package/es/util/common.js +12 -0
  76. package/es/util/common.js.map +1 -1
  77. package/package.json +2 -2
  78. package/cjs/label/arc.d.ts +0 -69
  79. package/cjs/label/arc.js +0 -397
  80. package/cjs/label/arc.js.map +0 -1
  81. package/cjs/label/util.d.ts +0 -12
  82. package/cjs/label/util.js +0 -113
  83. package/cjs/label/util.js.map +0 -1
  84. package/es/label/arc.d.ts +0 -69
  85. package/es/label/arc.js +0 -387
  86. package/es/label/arc.js.map +0 -1
  87. package/es/label/util.d.ts +0 -12
  88. package/es/label/util.js +0 -99
  89. package/es/label/util.js.map +0 -1
package/dist/index.js CHANGED
@@ -341,6 +341,26 @@
341
341
  }
342
342
  return obj.visible !== false;
343
343
  };
344
+ function getMarksByName(root, name) {
345
+ if (!name) {
346
+ return [];
347
+ }
348
+ const group = root.find(node => node.name === name, true);
349
+ if (!group) {
350
+ return [];
351
+ }
352
+ return group.getChildren();
353
+ }
354
+ function getNoneGroupMarksByName(root, name) {
355
+ if (!name) {
356
+ return [];
357
+ }
358
+ const group = root.find(node => node.name === name, true);
359
+ if (!group) {
360
+ return [];
361
+ }
362
+ return group.findAll(node => node.type !== 'group', true);
363
+ }
344
364
 
345
365
  const defaultAlternativeColors = ['#ffffff', '#000000'];
346
366
  function labelSmartInvert(foregroundColorOrigin, backgroundColorOrogin, textType, contrastRatiosThreshold, alternativeColors) {
@@ -1592,10 +1612,6 @@
1592
1612
  _lastHover;
1593
1613
  _lastSelect;
1594
1614
  _enableAnimation;
1595
- layoutArcLabels(position, attribute, currentMarks) {
1596
- const arcs = [];
1597
- return arcs;
1598
- }
1599
1615
  render() {
1600
1616
  this._prepare();
1601
1617
  const { overlap, smartInvert, dataFilter, customLayoutFunc, customOverlapFunc } = this.attribute;
@@ -1609,14 +1625,12 @@
1609
1625
  }
1610
1626
  else {
1611
1627
  labels = this.layout(data);
1612
- if (this.attribute.type !== 'arc') {
1613
- if (vutils.isFunction(customOverlapFunc)) {
1614
- labels = customOverlapFunc(labels, (d) => this._idToGraphic.get(d.id));
1615
- }
1616
- else {
1617
- if (overlap !== false) {
1618
- labels = this._overlapping(labels);
1619
- }
1628
+ if (vutils.isFunction(customOverlapFunc)) {
1629
+ labels = customOverlapFunc(labels, (d) => this._idToGraphic.get(d.id));
1630
+ }
1631
+ else {
1632
+ if (overlap !== false) {
1633
+ labels = this._overlapping(labels);
1620
1634
  }
1621
1635
  }
1622
1636
  }
@@ -1700,7 +1714,7 @@
1700
1714
  return text;
1701
1715
  }
1702
1716
  _prepare() {
1703
- const baseMarks = this.getBaseMarks();
1717
+ const baseMarks = getMarksByName(this.getRootNode(), this.attribute.baseMarkGroupName);
1704
1718
  const currentBaseMarks = [];
1705
1719
  baseMarks.forEach(mark => {
1706
1720
  if (mark.releaseStatus !== 'willRelease') {
@@ -1737,47 +1751,20 @@
1737
1751
  const textData = data[i];
1738
1752
  const baseMark = this._idToGraphic.get(textData.id);
1739
1753
  const labelAttribute = {
1740
- fill: baseMark.attribute.fill,
1741
1754
  ...textStyle,
1742
1755
  ...textData
1743
1756
  };
1744
1757
  const text = this._createLabelText(labelAttribute);
1745
1758
  const textBounds = this.getGraphicBounds(text);
1746
1759
  const graphicBounds = this.getGraphicBounds(baseMark, { x: textData.x, y: textData.y });
1747
- if (this.attribute.type === 'arc') {
1748
- const graphicAttributes = baseMark.attribute;
1749
- const { width, height } = this.attribute;
1750
- this.labeling(textBounds, graphicBounds, vutils.isFunction(position) ? position(textData) : position, offset, graphicAttributes, textData, width, height, this.attribute);
1751
- labels.push(text);
1752
- }
1753
- else {
1754
- const textLocation = this.labeling(textBounds, graphicBounds, vutils.isFunction(position) ? position(textData) : position, offset);
1755
- if (!textLocation) {
1756
- continue;
1757
- }
1758
- labelAttribute.x = textLocation.x;
1759
- labelAttribute.y = textLocation.y;
1760
- text.setAttributes(textLocation);
1761
- labels.push(text);
1762
- }
1763
- }
1764
- if (this.attribute.type === 'arc') {
1765
- const arcs = this.layoutArcLabels(position, this.attribute, Array.from(this._idToGraphic.values()));
1766
- for (let i = 0; i < data.length; i++) {
1767
- const textData = data[i];
1768
- const basedArc = arcs.find(arc => arc.labelText === textData.text);
1769
- const labelAttribute = {
1770
- x: basedArc.labelPosition.x,
1771
- y: basedArc.labelPosition.y,
1772
- textAlign: this.attribute.textAlign ?? basedArc.textAlign,
1773
- textBaseline: this.attribute.textBaseline ?? basedArc.textBaseline,
1774
- angle: this.attribute.angle ?? basedArc.angle
1775
- };
1776
- labels[i].setAttributes(labelAttribute);
1777
- labels[i].pointA = basedArc.pointA;
1778
- labels[i].pointB = basedArc.pointB;
1779
- labels[i].pointC = basedArc.pointC;
1760
+ const textLocation = this.labeling(textBounds, graphicBounds, vutils.isFunction(position) ? position(textData) : position, offset);
1761
+ if (!textLocation) {
1762
+ continue;
1780
1763
  }
1764
+ labelAttribute.x = textLocation.x;
1765
+ labelAttribute.y = textLocation.y;
1766
+ text.setAttributes(textLocation);
1767
+ labels.push(text);
1781
1768
  }
1782
1769
  return labels;
1783
1770
  }
@@ -1795,7 +1782,7 @@
1795
1782
  if (size.width === 0 || size.height === 0) {
1796
1783
  return labels;
1797
1784
  }
1798
- const { avoidBaseMark, strategy = [], hideOnHit = true, clampForce = true } = option;
1785
+ const { avoidBaseMark, strategy = [], hideOnHit = true, clampForce = true, avoidMarks = [] } = option;
1799
1786
  const bmpTool = this._bmpTool || bitmapTool(size.width, size.height);
1800
1787
  const bitmap = this._bitmap || bmpTool.bitmap();
1801
1788
  const checkBounds = strategy.some(s => s.type === 'bound');
@@ -1804,6 +1791,18 @@
1804
1791
  mark.AABBBounds && bitmap.setRange(boundToRange(bmpTool, mark.AABBBounds, true));
1805
1792
  });
1806
1793
  }
1794
+ if (avoidMarks.length > 0) {
1795
+ avoidMarks.forEach(avoid => {
1796
+ if (vutils.isString(avoid)) {
1797
+ getNoneGroupMarksByName(this.getRootNode(), avoid).forEach(avoidMark => {
1798
+ avoidMark.AABBBounds && bitmap.setRange(boundToRange(bmpTool, avoidMark.AABBBounds, true));
1799
+ });
1800
+ }
1801
+ else if (avoid.AABBBounds) {
1802
+ bitmap.setRange(boundToRange(bmpTool, avoid.AABBBounds, true));
1803
+ }
1804
+ });
1805
+ }
1807
1806
  for (let i = 0; i < labels.length; i++) {
1808
1807
  if (labels[i].visible === false) {
1809
1808
  continue;
@@ -1823,7 +1822,16 @@
1823
1822
  continue;
1824
1823
  }
1825
1824
  }
1826
- if (clampForce) {
1825
+ let hasPlace = false;
1826
+ for (let j = 0; j < strategy.length; j++) {
1827
+ hasPlace = place(bmpTool, bitmap, strategy[j], this.attribute, text, this.getGraphicBounds(baseMark, labels[i]), this.labeling);
1828
+ if (hasPlace !== false) {
1829
+ text.setAttributes({ x: hasPlace.x, y: hasPlace.y });
1830
+ result.push(text);
1831
+ break;
1832
+ }
1833
+ }
1834
+ if (!hasPlace && clampForce) {
1827
1835
  const { dx = 0, dy = 0 } = clampText(text, bmpTool.width, bmpTool.height);
1828
1836
  if (!(dx === 0 && dy === 0) &&
1829
1837
  canPlace(bmpTool, bitmap, {
@@ -1833,19 +1841,11 @@
1833
1841
  y2: text.AABBBounds.y2 + dy
1834
1842
  })) {
1835
1843
  text.setAttributes({ x: text.attribute.x + dx, y: text.attribute.y + dy });
1844
+ bitmap.setRange(boundToRange(bmpTool, text.AABBBounds, true));
1836
1845
  result.push(text);
1837
1846
  continue;
1838
1847
  }
1839
1848
  }
1840
- let hasPlace = false;
1841
- for (let j = 0; j < strategy.length; j++) {
1842
- hasPlace = place(bmpTool, bitmap, strategy[j], this.attribute, text, this.getGraphicBounds(baseMark, labels[i]), this.labeling);
1843
- if (hasPlace !== false) {
1844
- text.setAttributes({ x: hasPlace.x, y: hasPlace.y });
1845
- result.push(text);
1846
- break;
1847
- }
1848
- }
1849
1849
  !hasPlace && !hideOnHit && result.push(text);
1850
1850
  }
1851
1851
  if (vutils.isFunction(this.onAfterLabelOverlap)) {
@@ -1853,13 +1853,6 @@
1853
1853
  }
1854
1854
  return result;
1855
1855
  }
1856
- getBaseMarks() {
1857
- const baseMarkGroup = this.getBaseMarkGroup();
1858
- if (!baseMarkGroup) {
1859
- return;
1860
- }
1861
- return baseMarkGroup.getChildren();
1862
- }
1863
1856
  getBaseMarkGroup() {
1864
1857
  const { baseMarkGroupName } = this.attribute;
1865
1858
  if (!baseMarkGroupName) {
@@ -1887,29 +1880,14 @@
1887
1880
  const prevTextMap = this._graphicToText || new Map();
1888
1881
  const texts = [];
1889
1882
  labels.forEach((text, index) => {
1890
- let labelLine;
1891
- if (this.attribute.type === 'arc' && this.attribute.position === 'outside') {
1892
- labelLine = vrender.createPath({
1893
- visible: text.attribute?.visible ?? true,
1894
- stroke: text.attribute?.line?.stroke ?? text.attribute?.fill,
1895
- lineWidth: 1,
1896
- path: `M${Math.round(text.pointA.x)},${Math.round(text.pointA.y)}` +
1897
- ` L${Math.round(text.pointB.x)},${Math.round(text.pointB.y)}` +
1898
- ` L${Math.round(text.pointC.x)},${Math.round(text.pointC.y)}`
1899
- });
1900
- }
1901
1883
  const relatedGraphic = this._idToGraphic.get(text.attribute.id);
1902
1884
  const state = prevTextMap?.get(relatedGraphic) ? 'update' : 'enter';
1903
1885
  if (state === 'enter') {
1904
1886
  texts.push(text);
1905
- if (this.attribute.type === 'arc' && this.attribute.position === 'outside') ;
1906
1887
  currentTextMap.set(relatedGraphic, text);
1907
1888
  if (!disableAnimation && relatedGraphic) {
1908
1889
  const { from, to } = getAnimationAttributes(text.attribute, 'fadeIn');
1909
1890
  this.add(text);
1910
- if (this.attribute.type === 'arc' && this.attribute.position === 'outside') {
1911
- this.add(labelLine);
1912
- }
1913
1891
  relatedGraphic.onAnimateBind = () => {
1914
1892
  text.setAttributes(from);
1915
1893
  const listener = this._afterRelatedGraphicAttributeUpdate(text, texts, index, relatedGraphic, {
@@ -2017,15 +1995,7 @@
2017
1995
  continue;
2018
1996
  }
2019
1997
  const baseMark = this._idToGraphic.get(label.attribute.id);
2020
- let isInside = canPlaceInside(label.AABBBounds, baseMark?.AABBBounds);
2021
- if (this.attribute.type === 'arc') {
2022
- if (this.attribute.position === 'inside') {
2023
- isInside = true;
2024
- }
2025
- else {
2026
- isInside = false;
2027
- }
2028
- }
1998
+ const isInside = canPlaceInside(label.AABBBounds, baseMark?.AABBBounds);
2029
1999
  if (label.attribute.stroke && label.attribute.lineWidth > 0) {
2030
2000
  label.setAttributes({
2031
2001
  fill: labelSmartInvert(label.attribute.fill, label.attribute.stroke, textType, contrastRatiosThreshold, alternativeColors)
@@ -2252,769 +2222,9 @@
2252
2222
  }
2253
2223
  }
2254
2224
 
2255
- function polarToCartesian(point) {
2256
- if (!point.radius) {
2257
- return { x: 0, y: 0 };
2258
- }
2259
- return {
2260
- x: Math.cos(point.angle) * point.radius,
2261
- y: Math.sin(point.angle) * point.radius
2262
- };
2263
- }
2264
- function circlePoint(x0, y0, radius, radian) {
2265
- const offset = polarToCartesian({
2266
- radius,
2267
- angle: radian
2268
- });
2269
- return {
2270
- x: x0 + offset.x,
2271
- y: y0 + offset.y
2272
- };
2273
- }
2274
- function computeQuadrant(angle) {
2275
- angle = normalizeAngle(angle);
2276
- if (angle > 0 && angle <= Math.PI / 2) {
2277
- return 2;
2278
- }
2279
- else if (angle > Math.PI / 2 && angle <= Math.PI) {
2280
- return 3;
2281
- }
2282
- else if (angle > Math.PI && angle <= (3 * Math.PI) / 2) {
2283
- return 4;
2284
- }
2285
- return 1;
2286
- }
2287
- function normalizeAngle(angle) {
2288
- while (angle < 0) {
2289
- angle += Math.PI * 2;
2290
- }
2291
- while (angle >= Math.PI * 2) {
2292
- angle -= Math.PI * 2;
2293
- }
2294
- return angle;
2295
- }
2296
- function isQuadrantLeft(quadrant) {
2297
- return quadrant === 3 || quadrant === 4;
2298
- }
2299
- function isQuadrantRight(quadrant) {
2300
- return quadrant === 1 || quadrant === 2;
2301
- }
2302
- function lineCirclePoints(a, b, c, x0, y0, r) {
2303
- if ((a === 0 && b === 0) || r <= 0) {
2304
- return [];
2305
- }
2306
- if (a === 0) {
2307
- const y1 = -c / b;
2308
- const fy = (y1 - y0) ** 2;
2309
- const fd = r ** 2 - fy;
2310
- if (fd < 0) {
2311
- return [];
2312
- }
2313
- else if (fd === 0) {
2314
- return [{ x: x0, y: y1 }];
2315
- }
2316
- const x1 = Math.sqrt(fd) + x0;
2317
- const x2 = -Math.sqrt(fd) + x0;
2318
- return [
2319
- { x: x1, y: y1 },
2320
- { x: x2, y: y1 }
2321
- ];
2322
- }
2323
- else if (b === 0) {
2324
- const x1 = -c / a;
2325
- const fx = (x1 - x0) ** 2;
2326
- const fd = r ** 2 - fx;
2327
- if (fd < 0) {
2328
- return [];
2329
- }
2330
- else if (fd === 0) {
2331
- return [{ x: x1, y: y0 }];
2332
- }
2333
- const y1 = Math.sqrt(fd) + y0;
2334
- const y2 = -Math.sqrt(fd) + y0;
2335
- return [
2336
- { x: x1, y: y1 },
2337
- { x: x1, y: y2 }
2338
- ];
2339
- }
2340
- const fa = (b / a) ** 2 + 1;
2341
- const fb = 2 * ((c / a + x0) * (b / a) - y0);
2342
- const fc = (c / a + x0) ** 2 + y0 ** 2 - r ** 2;
2343
- const fd = fb ** 2 - 4 * fa * fc;
2344
- if (fd < 0) {
2345
- return [];
2346
- }
2347
- const y1 = (-fb + Math.sqrt(fd)) / (2 * fa);
2348
- const y2 = (-fb - Math.sqrt(fd)) / (2 * fa);
2349
- const x1 = -(b * y1 + c) / a;
2350
- const x2 = -(b * y2 + c) / a;
2351
- if (fd === 0) {
2352
- return [{ x: x1, y: y1 }];
2353
- }
2354
- return [
2355
- { x: x1, y: y1 },
2356
- { x: x2, y: y2 }
2357
- ];
2358
- }
2359
- function connectLineRadian(radius, length) {
2360
- if (length > radius * 2) {
2361
- return NaN;
2362
- }
2363
- return Math.asin(length / 2 / radius) * 2;
2364
- }
2365
- function checkBoundsOverlap(boundsA, boundsB) {
2366
- const { x1: ax1, y1: ay1, x2: ax2, y2: ay2 } = boundsA;
2367
- const { x1: bx1, y1: by1, x2: bx2, y2: by2 } = boundsB;
2368
- return !((ax1 <= bx1 && ax2 <= bx1) ||
2369
- (ax1 >= bx2 && ax2 >= bx2) ||
2370
- (ay1 <= by1 && ay2 <= by1) ||
2371
- (ay1 >= by2 && ay2 >= by2));
2372
- }
2373
-
2374
- class ArcInfo {
2375
- key;
2376
- refDatum;
2377
- center;
2378
- outerCenter;
2379
- labelSize;
2380
- labelPosition;
2381
- labelLimit;
2382
- labelVisible;
2383
- lastLabelY;
2384
- labelYRange;
2385
- labelText;
2386
- pointA;
2387
- pointB;
2388
- pointC;
2389
- quadrant;
2390
- radian;
2391
- middleAngle;
2392
- k;
2393
- textAlign;
2394
- textBaseline;
2395
- angle;
2396
- constructor(refDatum, center, outerCenter, quadrant, radian, middleAngle) {
2397
- this.refDatum = refDatum;
2398
- this.center = center;
2399
- this.outerCenter = outerCenter;
2400
- this.quadrant = quadrant;
2401
- this.radian = radian;
2402
- this.middleAngle = middleAngle;
2403
- this.labelVisible = true;
2404
- this.labelLimit = 0;
2405
- }
2406
- getLabelBounds() {
2407
- if (!this.labelPosition || !this.labelSize) {
2408
- return { x1: 0, x2: 0, y1: 0, y2: 0 };
2409
- }
2410
- return {
2411
- x1: this.labelPosition.x - this.labelSize.width / 2,
2412
- y1: this.labelPosition.y - this.labelSize.height / 2,
2413
- x2: this.labelPosition.x + this.labelSize.width / 2,
2414
- y2: this.labelPosition.y + this.labelSize.height / 2
2415
- };
2416
- }
2417
- }
2418
- class ArcLabel extends LabelBase {
2419
- name = 'arc-label';
2420
- static defaultAttributes = {
2421
- coverEnable: false,
2422
- spaceWidth: 5,
2423
- layoutArcGap: 6,
2424
- textStyle: {
2425
- visible: true,
2426
- fontSize: 14,
2427
- fontWeight: 'normal',
2428
- fillOpacity: 1
2429
- },
2430
- position: 'outside',
2431
- offset: 0,
2432
- line: {
2433
- visible: true,
2434
- line1MinLength: 20,
2435
- line2MinLength: 10
2436
- },
2437
- layout: {
2438
- align: 'arc',
2439
- strategy: 'priority',
2440
- tangentConstraint: true
2441
- }
2442
- };
2443
- _ellipsisWidth = 0;
2444
- _arcLeft = new Map();
2445
- _arcRight = new Map();
2446
- constructor(attributes) {
2447
- super(vutils.merge({}, ArcLabel.defaultAttributes, attributes));
2448
- }
2449
- labeling(textBounds, graphicBounds, position = 'outside', offset = 0, graphicAttributes, textData, width, height, attribute) {
2450
- if (!textBounds || !graphicBounds) {
2451
- return;
2452
- }
2453
- const radiusRatio = this.computeLayoutOuterRadius(graphicAttributes.outerRadius, width, height);
2454
- const radius = this.computeRadius(radiusRatio, width, height);
2455
- const center = { x: graphicAttributes?.x ?? 0, y: graphicAttributes?.y ?? 0 };
2456
- const item = textData;
2457
- const arcMiddleAngle = (graphicAttributes.startAngle + graphicAttributes.endAngle) / 2;
2458
- const intervalAngle = graphicAttributes.endAngle - graphicAttributes.startAngle;
2459
- const arcQuadrant = computeQuadrant(graphicAttributes.endAngle - intervalAngle / 2);
2460
- const arcMiddle = circlePoint(center.x, center.y, graphicAttributes.outerRadius, arcMiddleAngle);
2461
- const outerArcMiddle = circlePoint(center.x, center.y, radius + attribute.line.line1MinLength, arcMiddleAngle);
2462
- const arc = new ArcInfo(item, arcMiddle, outerArcMiddle, arcQuadrant, intervalAngle, arcMiddleAngle);
2463
- arc.pointA = circlePoint(center.x, center.y, this.computeDatumRadius(center.x * 2, center.y * 2, graphicAttributes.outerRadius), arc.middleAngle);
2464
- arc.labelSize = {
2465
- width: textBounds.x2 - textBounds.x1,
2466
- height: textBounds.y2 - textBounds.y1
2467
- };
2468
- if (isQuadrantRight(arc.quadrant)) {
2469
- arc.textAlign = 'left';
2470
- arc.textBaseline = 'middle';
2471
- this._arcRight.set(arc.refDatum, arc);
2472
- }
2473
- else if (isQuadrantLeft(arc.quadrant)) {
2474
- arc.textAlign = 'right';
2475
- arc.textBaseline = 'middle';
2476
- this._arcLeft.set(arc.refDatum, arc);
2477
- }
2478
- }
2479
- layoutArcLabels(position, attribute, currentMarks) {
2480
- const leftArcs = Array.from(this._arcLeft.values());
2481
- const rightArcs = Array.from(this._arcRight.values());
2482
- const arcs = [];
2483
- if (position === 'inside') {
2484
- arcs.push(...this._layoutInsideLabels(rightArcs, attribute, currentMarks));
2485
- arcs.push(...this._layoutInsideLabels(leftArcs, attribute, currentMarks));
2486
- }
2487
- else {
2488
- arcs.push(...this._layoutOutsideLabels(rightArcs, attribute, currentMarks));
2489
- arcs.push(...this._layoutOutsideLabels(leftArcs, attribute, currentMarks));
2490
- }
2491
- return arcs;
2492
- }
2493
- _layoutInsideLabels(arcs, attribute, currentMarks) {
2494
- const center = { x: currentMarks[0].attribute?.x ?? 0, y: currentMarks[0].attribute?.y ?? 0 };
2495
- const innerRadiusRatio = this.computeLayoutOuterRadius(currentMarks[0].attribute.innerRadius, attribute.width, attribute.height);
2496
- const outerRadiusRatio = this.computeLayoutOuterRadius(currentMarks[0].attribute.outerRadius, attribute.width, attribute.height);
2497
- const labelConfig = attribute;
2498
- const spaceWidth = labelConfig.spaceWidth;
2499
- arcs.forEach((arc) => {
2500
- const { labelSize, radian } = arc;
2501
- const innerRadius = this.computeRadius(innerRadiusRatio, attribute.width, attribute.height, 1);
2502
- const outerRadius = this.computeRadius(outerRadiusRatio, attribute.width, attribute.height, 1);
2503
- const minRadian = connectLineRadian(outerRadius, labelSize.height);
2504
- let limit;
2505
- if (radian < minRadian) {
2506
- limit = 0;
2507
- }
2508
- else {
2509
- let minRadius;
2510
- if (radian >= Math.PI) {
2511
- minRadius = innerRadius;
2512
- }
2513
- else {
2514
- minRadius = Math.max(innerRadius, labelSize.height / 2 / Math.tan(radian / 2));
2515
- }
2516
- limit = outerRadius - minRadius - spaceWidth;
2517
- }
2518
- if (labelConfig?.rotate !== true) {
2519
- limit = outerRadius - spaceWidth;
2520
- }
2521
- const text = this._getFormatLabelText(arc.refDatum, limit);
2522
- arc.labelText = text;
2523
- const labelWidth = Math.min(limit, arc.labelSize.width);
2524
- const align = this._computeAlign(arc, attribute);
2525
- const alignOffset = align === 'left' ? labelWidth : align === 'right' ? 0 : labelWidth / 2;
2526
- const labelRadius = outerRadius - spaceWidth - alignOffset;
2527
- arc.labelPosition = circlePoint(center.x, center.y, labelRadius, arc.middleAngle);
2528
- arc.labelLimit = labelWidth;
2529
- if (!vutils.isGreater(labelWidth, 0)) {
2530
- arc.labelVisible = false;
2531
- }
2532
- (arc.textAlign = 'center'), (arc.textBaseline = 'middle');
2533
- arc.angle = arc.middleAngle;
2534
- });
2535
- return arcs;
2536
- }
2537
- _layoutOutsideLabels(arcs, attribute, currentMarks) {
2538
- const center = { x: currentMarks[0].attribute?.x ?? 0, y: currentMarks[0].attribute?.y ?? 0 };
2539
- const height = center.y * 2;
2540
- const line2MinLength = attribute.line.line2MinLength;
2541
- const labelLayout = attribute.layout;
2542
- const spaceWidth = attribute.spaceWidth;
2543
- arcs.forEach(arc => {
2544
- const direction = isQuadrantLeft(arc.quadrant) ? -1 : 1;
2545
- arc.labelPosition = {
2546
- x: arc.outerCenter.x + direction * (arc.labelSize.width / 2 + line2MinLength + spaceWidth),
2547
- y: arc.outerCenter.y
2548
- };
2549
- });
2550
- arcs.sort((a, b) => {
2551
- return a.labelPosition.y - b.labelPosition.y;
2552
- });
2553
- if (attribute.coverEnable !== false || labelLayout.strategy === 'none') {
2554
- for (const arc of arcs) {
2555
- const { labelPosition, labelSize } = arc;
2556
- arc.labelLimit = labelSize.width;
2557
- arc.pointB = isQuadrantLeft(arc.quadrant)
2558
- ? {
2559
- x: labelPosition.x + labelSize.width / 2 + line2MinLength + spaceWidth,
2560
- y: labelPosition.y
2561
- }
2562
- : {
2563
- x: labelPosition.x - labelSize.width / 2 - line2MinLength - spaceWidth,
2564
- y: labelPosition.y
2565
- };
2566
- this._computeX(arc, attribute, currentMarks);
2567
- }
2568
- if (attribute.coverEnable === false && labelLayout.strategy === 'none') {
2569
- this._coverLabels(arcs);
2570
- }
2571
- }
2572
- else {
2573
- const maxLabels = height / (attribute.textStyle?.fontSize || 16);
2574
- this._adjustY(arcs, maxLabels, attribute, currentMarks);
2575
- const { minY, maxY } = arcs.reduce((yInfo, arc) => {
2576
- const { y1, y2 } = arc.getLabelBounds();
2577
- yInfo.minY = Math.max(0, Math.min(y1, yInfo.minY));
2578
- yInfo.maxY = Math.min(height, Math.max(y2, yInfo.maxY));
2579
- return yInfo;
2580
- }, { minY: Infinity, maxY: -Infinity });
2581
- const halfY = Math.max(Math.abs(height / 2 - minY), Math.abs(maxY - height / 2));
2582
- const r = this._computeLayoutRadius(halfY, attribute, currentMarks);
2583
- for (const arc of arcs) {
2584
- this._computePointB(arc, r, attribute, currentMarks);
2585
- this._computeX(arc, attribute, currentMarks);
2586
- }
2587
- }
2588
- const width = center.x * 2;
2589
- arcs.forEach(arc => {
2590
- if (arc.labelVisible &&
2591
- (vutils.isLess(arc.pointB.x, line2MinLength + spaceWidth) ||
2592
- vutils.isGreater(arc.pointB.x, width - line2MinLength - spaceWidth))) {
2593
- arc.labelVisible = false;
2594
- }
2595
- arc.angle = 0;
2596
- });
2597
- return arcs;
2598
- }
2599
- _computeX(arc, attribute, currentMarks) {
2600
- const center = { x: currentMarks[0].attribute?.x ?? 0, y: currentMarks[0].attribute?.y ?? 0 };
2601
- const plotLayout = { width: center.x * 2, height: center.y * 2 };
2602
- const radiusRatio = this.computeLayoutOuterRadius(currentMarks[0].attribute.outerRadius, attribute.width, attribute.height);
2603
- const line1MinLength = attribute.line.line1MinLength;
2604
- const line2MinLength = attribute.line.line2MinLength;
2605
- const labelLayoutAlign = attribute.layout?.align;
2606
- const spaceWidth = attribute.spaceWidth;
2607
- const align = this._computeAlign(arc, attribute);
2608
- const { labelPosition, quadrant, pointB } = arc;
2609
- if (!vutils.isValidNumber(pointB.x * pointB.y)) {
2610
- arc.pointC = { x: NaN, y: NaN };
2611
- labelPosition.x = NaN;
2612
- arc.labelLimit = 0;
2613
- }
2614
- const radius = this.computeRadius(radiusRatio, attribute.width, attribute.height);
2615
- const flag = isQuadrantLeft(quadrant) ? -1 : 1;
2616
- let cx = 0;
2617
- const restWidth = flag > 0 ? plotLayout.width - pointB.x : pointB.x;
2618
- let limit = restWidth - line2MinLength - spaceWidth;
2619
- if (labelLayoutAlign === 'labelLine') {
2620
- cx = (radius + line1MinLength + line2MinLength) * flag + center.x;
2621
- limit = (flag > 0 ? plotLayout.width - cx : cx) - spaceWidth;
2622
- }
2623
- const text = this._getFormatLabelText(arc.refDatum, limit);
2624
- arc.labelText = text;
2625
- let labelWidth = Math.min(limit, arc.labelSize.width);
2626
- switch (labelLayoutAlign) {
2627
- case 'labelLine':
2628
- break;
2629
- case 'edge':
2630
- cx = flag > 0 ? plotLayout.width - labelWidth - spaceWidth : labelWidth + spaceWidth;
2631
- break;
2632
- case 'arc':
2633
- default:
2634
- cx = pointB.x + flag * line2MinLength;
2635
- break;
2636
- }
2637
- labelWidth = Math.max(this._ellipsisWidth, labelWidth);
2638
- arc.pointC = { x: cx, y: labelPosition.y };
2639
- if (labelLayoutAlign === 'edge') {
2640
- const alignOffset = this._computeAlignOffset(align, labelWidth, -flag);
2641
- labelPosition.x = flag > 0 ? plotLayout.width + alignOffset : alignOffset;
2642
- }
2643
- else {
2644
- const alignOffset = this._computeAlignOffset(align, labelWidth, flag);
2645
- labelPosition.x = cx + alignOffset + flag * spaceWidth;
2646
- }
2647
- arc.labelLimit = labelWidth;
2648
- }
2649
- _computeAlignOffset(align, labelWidth, alignFlag) {
2650
- switch (align) {
2651
- case 'left':
2652
- return alignFlag < 0 ? -labelWidth : 0;
2653
- case 'right':
2654
- return alignFlag < 0 ? 0 : labelWidth;
2655
- case 'center':
2656
- default:
2657
- return (labelWidth / 2) * alignFlag;
2658
- }
2659
- }
2660
- _computeAlign(arc, attribute) {
2661
- const labelConfig = attribute;
2662
- const textAlign = labelConfig.textStyle?.textAlign ?? labelConfig.textStyle?.align;
2663
- const layoutAlign = labelConfig.layout?.textAlign ?? labelConfig.layout?.align;
2664
- if (labelConfig.position !== 'inside') {
2665
- if (vutils.isNil(textAlign) || textAlign === 'auto') {
2666
- if (layoutAlign === 'edge') {
2667
- return isQuadrantLeft(arc.quadrant) ? 'left' : 'right';
2668
- }
2669
- return isQuadrantLeft(arc.quadrant) ? 'right' : 'left';
2670
- }
2671
- return textAlign;
2672
- }
2673
- return vutils.isNil(textAlign) || textAlign === 'auto' ? 'center' : textAlign;
2674
- }
2675
- _getFormatLabelText(value, limit) {
2676
- return value.text;
2677
- }
2678
- _adjustY(arcs, maxLabels, attribute, currentMarks) {
2679
- const center = { x: currentMarks[0].attribute?.x ?? 0, y: currentMarks[0].attribute?.y ?? 0 };
2680
- const plotRect = { width: center.x * 2, height: center.y * 2 };
2681
- const labelLayout = attribute.layout;
2682
- if (labelLayout.strategy === 'vertical') {
2683
- let lastY = 0;
2684
- let delta;
2685
- const len = arcs.length;
2686
- if (len <= 0) {
2687
- return;
2688
- }
2689
- for (let i = 0; i < len; i++) {
2690
- const { y1 } = arcs[i].getLabelBounds();
2691
- delta = y1 - lastY;
2692
- if (vutils.isLess(delta, 0)) {
2693
- const index = this._shiftY(arcs, i, len - 1, -delta);
2694
- this._shiftY(arcs, index, 0, delta / 2);
2695
- }
2696
- const { y2 } = arcs[i].getLabelBounds();
2697
- lastY = y2;
2698
- }
2699
- const { y1: firstY1 } = arcs[0].getLabelBounds();
2700
- delta = firstY1 - 0;
2701
- if (vutils.isLess(delta, 0)) {
2702
- this._shiftY(arcs, 0, len - 1, -delta);
2703
- }
2704
- for (let i = arcs.length - 1; i >= 0; i--) {
2705
- if (arcs[i].getLabelBounds().y2 > plotRect.height) {
2706
- arcs[i].labelVisible = false;
2707
- }
2708
- else {
2709
- break;
2710
- }
2711
- }
2712
- }
2713
- else if (labelLayout.strategy !== 'none') {
2714
- const priorityArcs = arcs.map((arc, i) => {
2715
- return {
2716
- arc,
2717
- originIndex: i,
2718
- priorityIndex: 0
2719
- };
2720
- });
2721
- priorityArcs.sort((a, b) => {
2722
- return b.arc.radian - a.arc.radian;
2723
- });
2724
- priorityArcs.forEach((priorityArc, i) => {
2725
- priorityArc.priorityIndex = i;
2726
- priorityArc.arc.labelVisible = false;
2727
- });
2728
- let topLabelIndex = Infinity;
2729
- let bottomLabelIndex = -Infinity;
2730
- for (let i = 0; i < maxLabels && i < arcs.length; i++) {
2731
- this._storeY(arcs);
2732
- const arc = priorityArcs[i].arc;
2733
- this._computeYRange(arc, attribute, currentMarks);
2734
- arc.labelVisible = true;
2735
- const curY = arc.labelPosition.y;
2736
- const { lastIndex, nextIndex } = this._findNeighborIndex(arcs, priorityArcs[i]);
2737
- const lastArc = arcs[lastIndex];
2738
- const nextArc = arcs[nextIndex];
2739
- if (lastIndex === -1 && nextIndex !== -1) {
2740
- const nextY = nextArc.labelPosition.y;
2741
- if (curY > nextY) {
2742
- arc.labelPosition.y = nextY - nextArc.labelSize.height / 2 - arc.labelSize.height / 2;
2743
- }
2744
- else {
2745
- this._twoWayShift(arcs, arc, nextArc, nextIndex);
2746
- }
2747
- }
2748
- else if (lastIndex !== -1 && nextIndex === -1) {
2749
- const lastY = lastArc.labelPosition.y;
2750
- if (curY < lastY) {
2751
- arc.labelPosition.y = lastY + lastArc.labelSize.height / 2 + arc.labelSize.height / 2;
2752
- }
2753
- else {
2754
- this._twoWayShift(arcs, lastArc, arc, priorityArcs[i].originIndex);
2755
- }
2756
- }
2757
- else if (lastIndex !== -1 && nextIndex !== -1) {
2758
- const lastY = lastArc.labelPosition.y;
2759
- const nextY = nextArc.labelPosition.y;
2760
- if (curY > nextY) {
2761
- arc.labelPosition.y = nextY - nextArc.labelSize.height / 2 - arc.labelSize.height / 2;
2762
- this._twoWayShift(arcs, lastArc, arc, priorityArcs[i].originIndex);
2763
- }
2764
- else if (curY < lastY) {
2765
- arc.labelPosition.y = lastY + lastArc.labelSize.height / 2 + arc.labelSize.height / 2;
2766
- this._twoWayShift(arcs, arc, nextArc, nextIndex);
2767
- }
2768
- else {
2769
- this._twoWayShift(arcs, lastArc, arc, priorityArcs[i].originIndex);
2770
- this._twoWayShift(arcs, arc, nextArc, nextIndex);
2771
- }
2772
- }
2773
- const nextTopIndex = Math.min(topLabelIndex, priorityArcs[i].originIndex);
2774
- const nextBottomIndex = Math.max(bottomLabelIndex, priorityArcs[i].originIndex);
2775
- let delta;
2776
- delta = arcs[nextBottomIndex].getLabelBounds().y2 - plotRect.height;
2777
- if (vutils.isGreater(delta, 0)) {
2778
- this._shiftY(arcs, nextBottomIndex, 0, -delta);
2779
- }
2780
- delta = arcs[nextTopIndex].getLabelBounds().y1 - 0;
2781
- if (vutils.isLess(delta, 0)) {
2782
- this._shiftY(arcs, nextTopIndex, arcs.length - 1, -delta);
2783
- }
2784
- delta = arcs[nextBottomIndex].getLabelBounds().y2 - plotRect.height;
2785
- if (vutils.isGreater(delta, 0)) {
2786
- arc.labelVisible = false;
2787
- this._restoreY(arcs);
2788
- break;
2789
- }
2790
- else if (labelLayout.tangentConstraint && !this._checkYRange(arcs)) {
2791
- arc.labelVisible = false;
2792
- this._restoreY(arcs);
2793
- }
2794
- else {
2795
- topLabelIndex = nextTopIndex;
2796
- bottomLabelIndex = nextBottomIndex;
2797
- }
2798
- }
2799
- }
2800
- }
2801
- _shiftY(arcs, start, end, delta) {
2802
- const direction = start < end ? 1 : -1;
2803
- let index = start;
2804
- while (index !== -1) {
2805
- arcs[index].labelPosition.y += delta;
2806
- const nextIndex = this._findNextVisibleIndex(arcs, index, end, direction);
2807
- if (nextIndex >= 0 && nextIndex < arcs.length) {
2808
- const { y1: curY1, y2: curY2 } = arcs[index].getLabelBounds();
2809
- const { y1: nextY1, y2: nextY2 } = arcs[nextIndex].getLabelBounds();
2810
- if ((direction > 0 && curY2 < nextY1) || (direction < 0 && curY1 > nextY2)) {
2811
- return index;
2812
- }
2813
- }
2814
- index = nextIndex;
2815
- }
2816
- return end;
2817
- }
2818
- _findNextVisibleIndex(arcs, start, end, direction) {
2819
- const diff = (end - start) * direction;
2820
- for (let i = 1; i <= diff; i++) {
2821
- const index = start + i * direction;
2822
- if (arcs[index].labelVisible) {
2823
- return index;
2824
- }
2825
- }
2826
- return -1;
2827
- }
2828
- _computePointB(arc, r, attribute, currentMarks) {
2829
- const labelConfig = attribute;
2830
- const radiusRatio = this.computeLayoutOuterRadius(currentMarks[0].attribute.outerRadius, attribute.width, attribute.height);
2831
- const line1MinLength = labelConfig.line.line1MinLength;
2832
- const labelLayout = labelConfig.layout;
2833
- if (labelLayout.strategy === 'none') {
2834
- arc.pointB = {
2835
- x: arc.outerCenter.x,
2836
- y: arc.outerCenter.y
2837
- };
2838
- }
2839
- else {
2840
- const center = { x: currentMarks[0].attribute?.x ?? 0, y: currentMarks[0].attribute?.y ?? 0 };
2841
- const radius = this.computeRadius(radiusRatio, attribute.width, attribute.height);
2842
- const { labelPosition, quadrant } = arc;
2843
- const outerR = Math.max(radius + line1MinLength, currentMarks[0].attribute.outerRadius);
2844
- const rd = r - outerR;
2845
- const x = Math.sqrt(r ** 2 - Math.abs(center.y - labelPosition.y) ** 2) - rd;
2846
- if (vutils.isValidNumber(x)) {
2847
- arc.pointB = {
2848
- x: center.x + x * (isQuadrantLeft(quadrant) ? -1 : 1),
2849
- y: labelPosition.y
2850
- };
2851
- }
2852
- else {
2853
- arc.pointB = { x: NaN, y: NaN };
2854
- }
2855
- }
2856
- }
2857
- _storeY(arcs) {
2858
- for (const arc of arcs) {
2859
- if (arc.labelVisible) {
2860
- arc.lastLabelY = arc.labelPosition.y;
2861
- }
2862
- }
2863
- }
2864
- _computeYRange(arc, attribute, currentMarks) {
2865
- const center = { x: currentMarks[0].attribute?.x ?? 0, y: currentMarks[0].attribute?.y ?? 0 };
2866
- const plotRect = { width: center.x * 2, height: center.y * 2 };
2867
- const radiusRatio = this.computeLayoutOuterRadius(currentMarks[0].attribute.outerRadius, attribute.width, attribute.height);
2868
- const line1MinLength = attribute.line.line1MinLength;
2869
- const { width, height } = plotRect;
2870
- const radius = this.computeRadius(radiusRatio, attribute.width, attribute.height);
2871
- const r = this._computeLayoutRadius(height / 2, attribute, currentMarks);
2872
- const cx = Math.abs(arc.center.x - width / 2);
2873
- const cy = arc.center.y - height / 2;
2874
- let a;
2875
- let b;
2876
- let c;
2877
- if (vutils.isNumberClose(width / 2, cx)) {
2878
- a = 0;
2879
- b = 1;
2880
- c = -cy;
2881
- }
2882
- else if (vutils.isNumberClose(height / 2, cy)) {
2883
- a = 1;
2884
- b = 0;
2885
- c = -cx;
2886
- }
2887
- else {
2888
- const k = -1 / (cy / cx);
2889
- a = k;
2890
- b = -1;
2891
- c = cy - k * cx;
2892
- }
2893
- const points = lineCirclePoints(a, b, c, line1MinLength + radius - r, 0, r);
2894
- if (points.length < 2) {
2895
- return;
2896
- }
2897
- let min;
2898
- let max;
2899
- if (points[0].x > points[1].x) {
2900
- points.reverse();
2901
- }
2902
- if (points[0].x < 0) {
2903
- if (vutils.isNumberClose(points[0].y, points[1].y)) {
2904
- if (Math.abs(arc.middleAngle) < Math.PI / 2) {
2905
- min = 0;
2906
- max = points[1].y + height / 2;
2907
- }
2908
- else {
2909
- min = points[1].y + height / 2;
2910
- max = height;
2911
- }
2912
- }
2913
- else if (points[0].y < points[1].y) {
2914
- min = 0;
2915
- max = points[1].y + height / 2;
2916
- }
2917
- else {
2918
- min = points[1].y + height / 2;
2919
- max = plotRect.height;
2920
- }
2921
- }
2922
- else {
2923
- min = Math.min(points[0].y, points[1].y) + height / 2;
2924
- max = Math.max(points[0].y, points[1].y) + height / 2;
2925
- }
2926
- arc.labelYRange = [min, max];
2927
- }
2928
- _computeLayoutRadius(halfYLength, attribute, currentMarks) {
2929
- const labelConfig = attribute;
2930
- const layoutArcGap = labelConfig.layoutArcGap;
2931
- const line1MinLength = labelConfig.line.line1MinLength;
2932
- const radiusRatio = this.computeLayoutOuterRadius(currentMarks[0].attribute.outerRadius, attribute.width, attribute.height);
2933
- const radius = this.computeRadius(radiusRatio, attribute.width, attribute.height);
2934
- const outerR = radius + line1MinLength;
2935
- const a = outerR - layoutArcGap;
2936
- return Math.max((a ** 2 + halfYLength ** 2) / (2 * a), outerR);
2937
- }
2938
- _findNeighborIndex(arcs, priorityArc) {
2939
- const index = priorityArc.originIndex;
2940
- let lastIndex = -1;
2941
- let nextIndex = -1;
2942
- for (let i = index - 1; i >= 0; i--) {
2943
- if (arcs[i].labelVisible) {
2944
- lastIndex = i;
2945
- break;
2946
- }
2947
- }
2948
- for (let i = index + 1; i < arcs.length; i++) {
2949
- if (arcs[i].labelVisible) {
2950
- nextIndex = i;
2951
- break;
2952
- }
2953
- }
2954
- return {
2955
- lastIndex,
2956
- nextIndex
2957
- };
2958
- }
2959
- _twoWayShift(arcs, lastArc, nextArc, nextIndex) {
2960
- const delta = nextArc.getLabelBounds().y1 - lastArc.getLabelBounds().y2;
2961
- if (vutils.isLess(delta, 0)) {
2962
- const i = this._shiftY(arcs, nextIndex, arcs.length - 1, -delta);
2963
- this._shiftY(arcs, i, 0, delta / 2);
2964
- }
2965
- }
2966
- _restoreY(arcs) {
2967
- for (const arc of arcs) {
2968
- if (arc.labelVisible) {
2969
- arc.labelPosition.y = arc.lastLabelY;
2970
- }
2971
- }
2972
- }
2973
- _checkYRange(arcs) {
2974
- for (const arc of arcs) {
2975
- const { labelYRange, labelPosition } = arc;
2976
- if (arc.labelVisible &&
2977
- labelYRange &&
2978
- (vutils.isLess(labelPosition.y, labelYRange[0]) || vutils.isGreater(labelPosition.y, labelYRange[1]))) {
2979
- return false;
2980
- }
2981
- }
2982
- return true;
2983
- }
2984
- _coverLabels(arcs) {
2985
- if (arcs.length <= 1) {
2986
- return;
2987
- }
2988
- let lastBounds = arcs[0].getLabelBounds();
2989
- for (let i = 1; i < arcs.length; i++) {
2990
- const bounds = arcs[i].getLabelBounds();
2991
- if (!checkBoundsOverlap(lastBounds, bounds)) {
2992
- lastBounds = bounds;
2993
- }
2994
- else {
2995
- arcs[i].labelVisible = false;
2996
- }
2997
- }
2998
- }
2999
- computeRadius(r, width, height, k) {
3000
- return this.computeLayoutRadius(width ? width : 0, height ? height : 0) * r * (vutils.isNil(k) ? 1 : k);
3001
- }
3002
- computeLayoutRadius(width, height) {
3003
- return Math.min(width / 2, height / 2);
3004
- }
3005
- computeLayoutOuterRadius(r, width, height) {
3006
- return r / (Math.min(width, height) / 2);
3007
- }
3008
- computeDatumRadius(width, height, outerRadius) {
3009
- const outerRadiusRatio = this.computeLayoutOuterRadius(outerRadius, width, height);
3010
- return this.computeLayoutRadius(width ? width : 0, height ? height : 0) * outerRadiusRatio;
3011
- }
3012
- }
3013
-
3014
2225
  const labelComponentMap = {
3015
2226
  rect: RectLabel,
3016
- symbol: SymbolLabel,
3017
- arc: ArcLabel
2227
+ symbol: SymbolLabel
3018
2228
  };
3019
2229
  class DataLabel extends AbstractComponent {
3020
2230
  name = 'data-label';
@@ -3409,6 +2619,7 @@
3409
2619
  AXIS_ELEMENT_NAME["gridRegion"] = "axis-grid-region";
3410
2620
  AXIS_ELEMENT_NAME["line"] = "axis-line";
3411
2621
  AXIS_ELEMENT_NAME["background"] = "axis-background";
2622
+ AXIS_ELEMENT_NAME["axisLabelBackground"] = "axis-label-background";
3412
2623
  })(exports.AXIS_ELEMENT_NAME || (exports.AXIS_ELEMENT_NAME = {}));
3413
2624
  exports.AxisStateValue = void 0;
3414
2625
  (function (AxisStateValue) {
@@ -3615,7 +2826,9 @@
3615
2826
  items.forEach((axisItems, layer) => {
3616
2827
  const layerLabelGroup = this.renderLabels(labelGroup, axisItems, layer);
3617
2828
  const labels = layerLabelGroup.getChildren();
3618
- this.handleLabelsOverlap(labels, axisItems, layer, items.length);
2829
+ this.beforeLabelsOverlap(labels, axisItems, layerLabelGroup, layer, items.length);
2830
+ this.handleLabelsOverlap(labels, axisItems, layerLabelGroup, layer, items.length);
2831
+ this.afterLabelsOverlap(labels, axisItems, layerLabelGroup, layer, items.length);
3619
2832
  });
3620
2833
  }
3621
2834
  if (grid?.visible) {
@@ -4175,6 +3388,67 @@
4175
3388
  });
4176
3389
  }
4177
3390
 
3391
+ function alignAxisLabels(labels, start, containerSize, orient, align) {
3392
+ if (orient === 'right' || orient === 'left') {
3393
+ if (align === 'left') {
3394
+ const flag = orient === 'right' ? 0 : -1;
3395
+ labels.forEach(label => {
3396
+ label.setAttributes({
3397
+ x: start + containerSize * flag,
3398
+ textAlign: 'left'
3399
+ });
3400
+ });
3401
+ }
3402
+ else if (align === 'right') {
3403
+ const flag = orient === 'right' ? 1 : 0;
3404
+ labels.forEach(label => {
3405
+ label.setAttributes({
3406
+ x: start + containerSize * flag,
3407
+ textAlign: 'right'
3408
+ });
3409
+ });
3410
+ }
3411
+ else if (align === 'center') {
3412
+ const flag = orient === 'right' ? 1 : -1;
3413
+ labels.forEach(label => {
3414
+ label.setAttributes({
3415
+ x: start + containerSize * 0.5 * flag,
3416
+ textAlign: 'center'
3417
+ });
3418
+ });
3419
+ }
3420
+ }
3421
+ else if (orient === 'bottom' || orient === 'top') {
3422
+ if (align === 'top') {
3423
+ const flag = orient === 'bottom' ? 0 : -1;
3424
+ labels.forEach(label => {
3425
+ label.setAttributes({
3426
+ y: start + containerSize * flag,
3427
+ textBaseline: 'top'
3428
+ });
3429
+ });
3430
+ }
3431
+ else if (align === 'bottom') {
3432
+ const flag = orient === 'bottom' ? 1 : 0;
3433
+ labels.forEach(label => {
3434
+ label.setAttributes({
3435
+ y: start + containerSize * flag,
3436
+ textBaseline: 'bottom'
3437
+ });
3438
+ });
3439
+ }
3440
+ else if (align === 'middle') {
3441
+ const flag = orient === 'bottom' ? 1 : -1;
3442
+ labels.forEach(label => {
3443
+ label.setAttributes({
3444
+ y: start + containerSize * 0.5 * flag,
3445
+ textBaseline: 'middle'
3446
+ });
3447
+ });
3448
+ }
3449
+ }
3450
+ }
3451
+
4178
3452
  function getCirclePoints(center, count, radius, startAngle, endAngle) {
4179
3453
  const points = [];
4180
3454
  const range = endAngle - startAngle;
@@ -4499,24 +3773,15 @@
4499
3773
  }
4500
3774
  return base;
4501
3775
  }
4502
- handleLabelsOverlap(labelShapes, labelData, layer, layerCount) {
3776
+ beforeLabelsOverlap(labelShapes, labelData, labelContainer, layer, layerCount) {
3777
+ return;
3778
+ }
3779
+ handleLabelsOverlap(labelShapes, labelData, labelContainer, layer, layerCount) {
4503
3780
  if (vutils.isEmpty(labelShapes)) {
4504
3781
  return;
4505
3782
  }
4506
- const { verticalLimitSize, label, title, line, tick, orient } = this.attribute;
4507
- const labelSpace = label.space ?? 4;
4508
- let limitLength = verticalLimitSize;
4509
- let titleHeight = 0;
4510
- let titleSpacing = 0;
4511
- const axisLineWidth = line?.visible ? line.style.lineWidth ?? 1 : 0;
4512
- const tickLength = tick?.visible ? tick.length ?? 4 : 0;
4513
- if (title?.visible) {
4514
- titleHeight = measureTextSize(title.text, title.textStyle).height;
4515
- titleSpacing = title.space;
4516
- }
4517
- if (limitLength) {
4518
- limitLength = (limitLength - labelSpace - titleSpacing - titleHeight - axisLineWidth - tickLength) / layerCount;
4519
- }
3783
+ const { verticalLimitSize, label, orient } = this.attribute;
3784
+ const limitLength = this._getAxisLabelLimitLength(verticalLimitSize, layerCount);
4520
3785
  const { layoutFunc, autoRotate: autoRotate$1, autoRotateAngle, autoLimit: autoLimit$1, limitEllipsis, autoHide: autoHide$1, autoHideMethod, autoHideSeparation } = label;
4521
3786
  if (vutils.isFunction(layoutFunc)) {
4522
3787
  layoutFunc(labelShapes, labelData, layer, this);
@@ -4544,6 +3809,78 @@
4544
3809
  }
4545
3810
  }
4546
3811
  }
3812
+ afterLabelsOverlap(labelShapes, labelData, labelContainer, layer, layerCount) {
3813
+ const { verticalLimitSize, orient } = this.attribute;
3814
+ const isHorizontal = orient === 'bottom' || orient === 'top';
3815
+ const axisLabelContainerBounds = labelContainer.AABBBounds;
3816
+ let axisLabelContainerSize = isHorizontal ? axisLabelContainerBounds.height() : axisLabelContainerBounds.width();
3817
+ const { verticalMinSize } = this.attribute;
3818
+ if (vutils.isValidNumber(verticalMinSize) && (!vutils.isValidNumber(verticalLimitSize) || verticalMinSize <= verticalLimitSize)) {
3819
+ const minSize = this._getAxisLabelLimitLength(verticalMinSize, layerCount);
3820
+ axisLabelContainerSize = Math.max(axisLabelContainerSize, minSize);
3821
+ let x;
3822
+ let y;
3823
+ if (orient === 'left') {
3824
+ x = axisLabelContainerBounds.x2 - axisLabelContainerSize;
3825
+ y = axisLabelContainerBounds.y1;
3826
+ }
3827
+ else if (orient === 'right') {
3828
+ x = axisLabelContainerBounds.x1;
3829
+ y = axisLabelContainerBounds.y1;
3830
+ }
3831
+ else if (orient === 'top') {
3832
+ x = axisLabelContainerBounds.x1;
3833
+ y = axisLabelContainerBounds.y2 - axisLabelContainerSize;
3834
+ }
3835
+ else if (orient === 'bottom') {
3836
+ x = axisLabelContainerBounds.x1;
3837
+ y = axisLabelContainerBounds.y1;
3838
+ }
3839
+ const bgRect = vrender.createRect({
3840
+ x,
3841
+ y,
3842
+ width: isHorizontal ? axisLabelContainerBounds.width() : axisLabelContainerSize,
3843
+ height: isHorizontal ? axisLabelContainerSize : axisLabelContainerBounds.height(),
3844
+ pickable: false
3845
+ });
3846
+ bgRect.name = exports.AXIS_ELEMENT_NAME.axisLabelBackground;
3847
+ bgRect.id = this._getNodeId('axis-label-background');
3848
+ labelContainer.insertBefore(bgRect, labelContainer.firstChild);
3849
+ }
3850
+ if (vutils.isValid(this.attribute.label.containerAlign)) {
3851
+ let start;
3852
+ if (orient === 'left') {
3853
+ start = axisLabelContainerBounds.x2;
3854
+ }
3855
+ else if (orient === 'right') {
3856
+ start = axisLabelContainerBounds.x1;
3857
+ }
3858
+ else if (orient === 'top') {
3859
+ start = axisLabelContainerBounds.y2;
3860
+ }
3861
+ else if (orient === 'bottom') {
3862
+ start = axisLabelContainerBounds.y1;
3863
+ }
3864
+ alignAxisLabels(labelShapes, start, axisLabelContainerSize, orient, this.attribute.label.containerAlign);
3865
+ }
3866
+ }
3867
+ _getAxisLabelLimitLength(limitSize, layerCount) {
3868
+ const { label, title, line, tick } = this.attribute;
3869
+ const labelSpace = label.space ?? 4;
3870
+ let limitLength = limitSize;
3871
+ let titleHeight = 0;
3872
+ let titleSpacing = 0;
3873
+ const axisLineWidth = line?.visible ? line.style.lineWidth ?? 1 : 0;
3874
+ const tickLength = tick?.visible ? tick.length ?? 4 : 0;
3875
+ if (title?.visible) {
3876
+ titleHeight = measureTextSize(title.text, title.textStyle).height;
3877
+ titleSpacing = title.space;
3878
+ }
3879
+ if (limitLength) {
3880
+ limitLength = (limitLength - labelSpace - titleSpacing - titleHeight - axisLineWidth - tickLength) / layerCount;
3881
+ }
3882
+ return limitLength;
3883
+ }
4547
3884
  }
4548
3885
 
4549
3886
  class CircleAxis extends AxisBase {
@@ -4798,7 +4135,13 @@
4798
4135
  }
4799
4136
  return base;
4800
4137
  }
4801
- handleLabelsOverlap(labelShapes, labelData, layer, layerCount) {
4138
+ beforeLabelsOverlap(labelShapes, labelData, labelContainer, layer, layerCount) {
4139
+ return;
4140
+ }
4141
+ handleLabelsOverlap(labelShapes, labelData, labelContainer, layer, layerCount) {
4142
+ return;
4143
+ }
4144
+ afterLabelsOverlap(labelShapes, labelData, labelContainer, layer, layerCount) {
4802
4145
  return;
4803
4146
  }
4804
4147
  }
@@ -10411,11 +9754,9 @@
10411
9754
  }
10412
9755
  }
10413
9756
 
10414
- const version = "0.13.9-alpha.5";
9757
+ const version = "0.14.0-alpha.2";
10415
9758
 
10416
9759
  exports.AbstractComponent = AbstractComponent;
10417
- exports.ArcInfo = ArcInfo;
10418
- exports.ArcLabel = ArcLabel;
10419
9760
  exports.BasePlayer = BasePlayer;
10420
9761
  exports.Brush = Brush;
10421
9762
  exports.CircleAxis = CircleAxis;