@visactor/vrender-components 0.13.5-alpha.0 → 0.13.5-alpha.6

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 (87) hide show
  1. package/cjs/index.d.ts +1 -1
  2. package/cjs/index.js +1 -1
  3. package/cjs/index.js.map +1 -1
  4. package/cjs/label/arc.d.ts +69 -0
  5. package/cjs/label/arc.js +396 -0
  6. package/cjs/label/arc.js.map +1 -0
  7. package/cjs/label/base.d.ts +13 -10
  8. package/cjs/label/base.js +113 -56
  9. package/cjs/label/base.js.map +1 -1
  10. package/cjs/label/constant.d.ts +18 -0
  11. package/cjs/label/constant.js +15 -0
  12. package/cjs/label/constant.js.map +1 -0
  13. package/cjs/label/dataLabel.js +3 -2
  14. package/cjs/label/dataLabel.js.map +1 -1
  15. package/cjs/label/index.d.ts +1 -0
  16. package/cjs/label/index.js +2 -1
  17. package/cjs/label/index.js.map +1 -1
  18. package/cjs/label/overlap/place.d.ts +8 -4
  19. package/cjs/label/overlap/place.js +14 -2
  20. package/cjs/label/overlap/place.js.map +1 -1
  21. package/cjs/label/rect.d.ts +5 -3
  22. package/cjs/label/rect.js.map +1 -1
  23. package/cjs/label/symbol.d.ts +5 -3
  24. package/cjs/label/symbol.js.map +1 -1
  25. package/cjs/label/type.d.ts +48 -7
  26. package/cjs/label/type.js.map +1 -1
  27. package/cjs/label/util.d.ts +10 -0
  28. package/cjs/label/util.js +102 -0
  29. package/cjs/label/util.js.map +1 -0
  30. package/cjs/link-path/link-path.js +1 -2
  31. package/cjs/marker/base.js +2 -1
  32. package/cjs/marker/type.d.ts +5 -5
  33. package/cjs/marker/type.js +1 -1
  34. package/cjs/marker/type.js.map +1 -1
  35. package/cjs/pager/index.js +1 -1
  36. package/cjs/pager/pager.js +1 -1
  37. package/cjs/poptip/contribution.js +1 -1
  38. package/cjs/poptip/contribution.js.map +1 -1
  39. package/cjs/tag/tag.js +2 -2
  40. package/cjs/tag/tag.js.map +1 -1
  41. package/cjs/tag/type.d.ts +3 -4
  42. package/cjs/tag/type.js.map +1 -1
  43. package/dist/index.js +929 -77
  44. package/dist/index.min.js +1 -1
  45. package/es/index.d.ts +1 -1
  46. package/es/index.js +1 -1
  47. package/es/index.js.map +1 -1
  48. package/es/label/arc.d.ts +69 -0
  49. package/es/label/arc.js +390 -0
  50. package/es/label/arc.js.map +1 -0
  51. package/es/label/base.d.ts +13 -10
  52. package/es/label/base.js +115 -59
  53. package/es/label/base.js.map +1 -1
  54. package/es/label/constant.d.ts +18 -0
  55. package/es/label/constant.js +36 -0
  56. package/es/label/constant.js.map +1 -0
  57. package/es/label/dataLabel.js +4 -1
  58. package/es/label/dataLabel.js.map +1 -1
  59. package/es/label/index.d.ts +1 -0
  60. package/es/label/index.js +2 -0
  61. package/es/label/index.js.map +1 -1
  62. package/es/label/overlap/place.d.ts +8 -4
  63. package/es/label/overlap/place.js +11 -0
  64. package/es/label/overlap/place.js.map +1 -1
  65. package/es/label/rect.d.ts +5 -3
  66. package/es/label/rect.js.map +1 -1
  67. package/es/label/symbol.d.ts +5 -3
  68. package/es/label/symbol.js.map +1 -1
  69. package/es/label/type.d.ts +48 -7
  70. package/es/label/type.js.map +1 -1
  71. package/es/label/util.d.ts +10 -0
  72. package/es/label/util.js +89 -0
  73. package/es/label/util.js.map +1 -0
  74. package/es/link-path/link-path.js +1 -2
  75. package/es/marker/base.js +2 -1
  76. package/es/marker/type.d.ts +5 -5
  77. package/es/marker/type.js +1 -1
  78. package/es/marker/type.js.map +1 -1
  79. package/es/pager/index.js +1 -1
  80. package/es/pager/pager.js +1 -1
  81. package/es/poptip/contribution.js +1 -1
  82. package/es/poptip/contribution.js.map +1 -1
  83. package/es/tag/tag.js +2 -2
  84. package/es/tag/tag.js.map +1 -1
  85. package/es/tag/type.d.ts +3 -4
  86. package/es/tag/type.js.map +1 -1
  87. package/package.json +2 -2
package/dist/index.js CHANGED
@@ -543,7 +543,7 @@
543
543
  super(vutils.merge({}, Tag.defaultAttributes, attributes));
544
544
  }
545
545
  render() {
546
- const { text = '', textStyle = {}, shape = {}, panel = {}, space = 4, minWidth, maxWidth, padding = 4, visible, state, formatMethod } = this.attribute;
546
+ const { text = '', textStyle = {}, shape = {}, panel = {}, space = 4, minWidth, maxWidth, padding = 4, visible, state } = this.attribute;
547
547
  const parsedPadding = vutils.normalizePadding(padding);
548
548
  const group = this.createOrUpdateChild('tag-content', { x: 0, y: 0, zIndex: 1 }, 'group');
549
549
  let symbol;
@@ -574,7 +574,7 @@
574
574
  tagWidth += symbolPlaceWidth;
575
575
  textX += symbolPlaceWidth;
576
576
  const textAttrs = {
577
- text: formatMethod ? formatMethod(text) : text,
577
+ text,
578
578
  visible: vutils.isValid(text) && visible !== false,
579
579
  lineHeight: textStyle?.fontSize,
580
580
  ...textStyle,
@@ -963,6 +963,7 @@
963
963
  x: matrix.e,
964
964
  y: matrix.f
965
965
  });
966
+ drawContext.stage.tryInitInteractiveLayer();
966
967
  const interactiveLayer = drawContext.stage.getLayer('_builtin_interactive');
967
968
  if (interactiveLayer) {
968
969
  interactiveLayer.add(this.poptipComponent);
@@ -1513,6 +1514,28 @@
1513
1514
  return DefaultPositions;
1514
1515
  }
1515
1516
  }
1517
+ function clampText(text, width, height) {
1518
+ const { x1, x2, y1, y2 } = text.AABBBounds;
1519
+ const minX = Math.min(x1, x2);
1520
+ const maxX = Math.max(x1, x2);
1521
+ const minY = Math.min(y1, y2);
1522
+ const maxY = Math.max(y1, y2);
1523
+ let dx = 0;
1524
+ let dy = 0;
1525
+ if (minX < 0 && maxX - minX <= width) {
1526
+ dx = -minX;
1527
+ }
1528
+ else if (maxX > width && minX - (maxX - width) >= 0) {
1529
+ dx = width - maxX;
1530
+ }
1531
+ if (minY < 0 && maxY - minY <= height) {
1532
+ dy = -minY;
1533
+ }
1534
+ else if (maxY > height && minY - (maxY - height) >= 0) {
1535
+ dy = height - maxY;
1536
+ }
1537
+ return { dx, dy };
1538
+ }
1516
1539
 
1517
1540
  const fadeIn = (textAttribute = {}) => {
1518
1541
  return {
@@ -1563,17 +1586,43 @@
1563
1586
  setBitmapTool(bmpTool) {
1564
1587
  this._bmpTool = bmpTool;
1565
1588
  }
1566
- _relationMap;
1567
- _prevRelationMap;
1568
- _textMap;
1589
+ _graphicToText;
1590
+ _idToGraphic;
1569
1591
  onAfterLabelOverlap;
1570
1592
  _lastHover;
1571
1593
  _lastSelect;
1572
1594
  _enableAnimation;
1595
+ layoutArcLabels(position, attribute, currentMarks) {
1596
+ const arcs = [];
1597
+ return arcs;
1598
+ }
1573
1599
  render() {
1574
- const currentBaseMarks = this._checkMarks();
1575
- const labels = this.layout(currentBaseMarks);
1576
- this._smartInvert(labels);
1600
+ this._prepare();
1601
+ const { overlap, smartInvert, dataFilter, customLayoutFunc, customOverlapFunc } = this.attribute;
1602
+ let data = this.attribute.data;
1603
+ if (vutils.isFunction(dataFilter)) {
1604
+ data = dataFilter(data);
1605
+ }
1606
+ let labels;
1607
+ if (vutils.isFunction(customLayoutFunc)) {
1608
+ labels = customLayoutFunc(data, (d) => this._idToGraphic.get(d.id));
1609
+ }
1610
+ else {
1611
+ 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
+ }
1620
+ }
1621
+ }
1622
+ }
1623
+ if (smartInvert !== false) {
1624
+ this._smartInvert(labels);
1625
+ }
1577
1626
  this._renderLabels(labels);
1578
1627
  }
1579
1628
  _bindEvent(target) {
@@ -1650,7 +1699,7 @@
1650
1699
  this._setStates(text);
1651
1700
  return text;
1652
1701
  }
1653
- _checkMarks() {
1702
+ _prepare() {
1654
1703
  const baseMarks = this.getBaseMarks();
1655
1704
  const currentBaseMarks = [];
1656
1705
  baseMarks.forEach(mark => {
@@ -1658,59 +1707,84 @@
1658
1707
  currentBaseMarks.push(mark);
1659
1708
  }
1660
1709
  });
1661
- this._prevRelationMap = new Map(this._relationMap);
1662
- this._relationMap?.clear();
1663
- return currentBaseMarks;
1664
- }
1665
- layout(currentMarks) {
1666
- const { textStyle, position, offset } = this.attribute;
1667
- let { data } = this.attribute;
1668
- if (vutils.isFunction(data)) {
1669
- data = data({});
1710
+ this._idToGraphic?.clear();
1711
+ this._baseMarks = currentBaseMarks;
1712
+ if (!currentBaseMarks || currentBaseMarks.length === 0) {
1713
+ return;
1670
1714
  }
1715
+ const { data } = this.attribute;
1671
1716
  if (!data || data.length === 0) {
1672
- return [];
1717
+ return;
1673
1718
  }
1674
- let labels = [];
1675
- if (vutils.isFunction(this.attribute.sort) && currentMarks && currentMarks.length) {
1676
- currentMarks = currentMarks.sort(this.attribute.sort);
1719
+ if (!this._idToGraphic) {
1720
+ this._idToGraphic = new Map();
1677
1721
  }
1678
- if (!this._relationMap) {
1679
- this._relationMap = new Map();
1722
+ for (let i = 0; i < currentBaseMarks.length; i++) {
1723
+ const textData = data[i];
1724
+ const baseMark = currentBaseMarks[i];
1725
+ if (textData && baseMark) {
1726
+ if (!vutils.isValid(textData.id)) {
1727
+ textData.id = `vrender-component-${this.name}-${i}`;
1728
+ }
1729
+ this._idToGraphic.set(textData.id, baseMark);
1730
+ }
1680
1731
  }
1732
+ }
1733
+ layout(data = []) {
1734
+ const { textStyle = {}, position, offset } = this.attribute;
1735
+ const labels = [];
1681
1736
  for (let i = 0; i < data.length; i++) {
1682
1737
  const textData = data[i];
1683
- const baseMark = currentMarks?.[i];
1738
+ const baseMark = this._idToGraphic.get(textData.id);
1684
1739
  const labelAttribute = {
1685
1740
  ...textStyle,
1686
- ...textData,
1687
- _relatedIndex: i
1741
+ ...textData
1688
1742
  };
1689
- this._relationMap.set(i, baseMark);
1690
- if (textData) {
1691
- const text = vrender.createText(labelAttribute);
1692
- text.update();
1693
- const textBounds = this.getGraphicBounds(text);
1694
- const graphicBounds = this.getGraphicBounds(baseMark, { x: textData.x, y: textData.y });
1695
- const textAttributes = this.labeling(textBounds, graphicBounds, vutils.isFunction(position) ? position(textData) : position, offset);
1696
- if (!textAttributes) {
1743
+ const text = this._createLabelText(labelAttribute);
1744
+ const textBounds = this.getGraphicBounds(text);
1745
+ const graphicBounds = this.getGraphicBounds(baseMark, { x: textData.x, y: textData.y });
1746
+ if (this.attribute.type === 'arc') {
1747
+ const graphicAttributes = baseMark.attribute;
1748
+ const { width, height } = this.attribute;
1749
+ this.labeling(textBounds, graphicBounds, vutils.isFunction(position) ? position(textData) : position, offset, graphicAttributes, textData, width, height, this.attribute);
1750
+ labels.push(text);
1751
+ }
1752
+ else {
1753
+ const textLocation = this.labeling(textBounds, graphicBounds, vutils.isFunction(position) ? position(textData) : position, offset);
1754
+ if (!textLocation) {
1697
1755
  continue;
1698
1756
  }
1699
- labelAttribute.x = textAttributes.x;
1700
- labelAttribute.y = textAttributes.y;
1701
- labels.push(labelAttribute);
1757
+ labelAttribute.x = textLocation.x;
1758
+ labelAttribute.y = textLocation.y;
1759
+ text.setAttributes(textLocation);
1760
+ labels.push(text);
1761
+ }
1762
+ }
1763
+ if (this.attribute.type === 'arc') {
1764
+ const arcs = this.layoutArcLabels(position, this.attribute, Array.from(this._idToGraphic.values()));
1765
+ for (let i = 0; i < data.length; i++) {
1766
+ const textData = data[i];
1767
+ const basedArc = arcs.find(arc => arc.labelText === textData.text);
1768
+ const labelAttribute = {
1769
+ x: basedArc.labelPosition.x,
1770
+ y: basedArc.labelPosition.y,
1771
+ textAlign: basedArc.textAlign,
1772
+ textBaseline: basedArc.textBaseline,
1773
+ angle: basedArc.angle
1774
+ };
1775
+ labels[i].setAttributes(labelAttribute);
1776
+ labels[i].pointA = basedArc.pointA;
1777
+ labels[i].pointB = basedArc.pointB;
1778
+ labels[i].pointC = basedArc.pointC;
1702
1779
  }
1703
1780
  }
1704
- this._baseMarks = currentMarks;
1705
- if (this.attribute.overlap !== false) {
1706
- labels = this.overlapping(labels, this.attribute.overlap);
1707
- }
1708
1781
  return labels;
1709
1782
  }
1710
- overlapping(labels, option = {}) {
1783
+ _overlapping(labels) {
1711
1784
  if (labels.length === 0) {
1712
1785
  return [];
1713
1786
  }
1787
+ const option = this.attribute.overlap;
1714
1788
  const result = [];
1715
1789
  const baseMarkGroup = this.getBaseMarkGroup();
1716
1790
  const size = option.size ?? {
@@ -1733,18 +1807,32 @@
1733
1807
  if (labels[i].visible === false) {
1734
1808
  continue;
1735
1809
  }
1736
- const text = vrender.createText(labels[i]);
1737
- const baseMark = this._baseMarks?.[i];
1810
+ const text = labels[i];
1811
+ const baseMark = this._idToGraphic.get(text.attribute.id);
1738
1812
  text.update();
1739
1813
  if (canPlace(bmpTool, bitmap, text.AABBBounds, clampForce)) {
1740
1814
  if (!checkBounds) {
1741
1815
  bitmap.setRange(boundToRange(bmpTool, text.AABBBounds, true));
1742
- result.push({ ...text.attribute });
1816
+ result.push(text);
1743
1817
  continue;
1744
1818
  }
1745
1819
  if (checkBounds && baseMark?.AABBBounds && canPlaceInside(text.AABBBounds, baseMark?.AABBBounds)) {
1746
1820
  bitmap.setRange(boundToRange(bmpTool, text.AABBBounds, true));
1747
- result.push({ ...text.attribute });
1821
+ result.push(text);
1822
+ continue;
1823
+ }
1824
+ }
1825
+ if (clampForce) {
1826
+ const { dx = 0, dy = 0 } = clampText(text, bmpTool.width, bmpTool.height);
1827
+ if (!(dx === 0 && dy === 0) &&
1828
+ canPlace(bmpTool, bitmap, {
1829
+ x1: text.AABBBounds.x1 + dx,
1830
+ x2: text.AABBBounds.x2 + dx,
1831
+ y1: text.AABBBounds.y1 + dy,
1832
+ y2: text.AABBBounds.y2 + dy
1833
+ })) {
1834
+ text.setAttributes({ x: text.attribute.x + dx, y: text.attribute.y + dy });
1835
+ result.push(text);
1748
1836
  continue;
1749
1837
  }
1750
1838
  }
@@ -1752,15 +1840,12 @@
1752
1840
  for (let j = 0; j < strategy.length; j++) {
1753
1841
  hasPlace = place(bmpTool, bitmap, strategy[j], this.attribute, text, this.getGraphicBounds(baseMark, labels[i]), this.labeling);
1754
1842
  if (hasPlace !== false) {
1755
- result.push({
1756
- ...text.attribute,
1757
- x: hasPlace.x,
1758
- y: hasPlace.y
1759
- });
1843
+ text.setAttributes({ x: hasPlace.x, y: hasPlace.y });
1844
+ result.push(text);
1760
1845
  break;
1761
1846
  }
1762
1847
  }
1763
- !hasPlace && !hideOnHit && result.push({ ...text.attribute });
1848
+ !hasPlace && !hideOnHit && result.push(text);
1764
1849
  }
1765
1850
  if (vutils.isFunction(this.onAfterLabelOverlap)) {
1766
1851
  this.onAfterLabelOverlap(bitmap);
@@ -1798,18 +1883,32 @@
1798
1883
  const easing = animationConfig.easing ?? DefaultLabelAnimation.easing;
1799
1884
  const delay = animationConfig.delay ?? 0;
1800
1885
  const currentTextMap = new Map();
1801
- const prevTextMap = this._textMap || new Map();
1886
+ const prevTextMap = this._graphicToText || new Map();
1802
1887
  const texts = [];
1803
- labels.forEach((label, index) => {
1804
- const text = this._createLabelText(label);
1805
- const relatedGraphic = this._relationMap.get(label._relatedIndex);
1888
+ labels.forEach((text, index) => {
1889
+ let labelLine;
1890
+ if (this.attribute.type === 'arc' && this.attribute.position === 'outside') {
1891
+ labelLine = vrender.createPath({
1892
+ visible: text.attribute?.visible ?? true,
1893
+ stroke: text.attribute?.line?.stroke ?? text.attribute?.fill,
1894
+ lineWidth: 1,
1895
+ path: `M${Math.round(text.pointA.x)},${Math.round(text.pointA.y)}` +
1896
+ ` L${Math.round(text.pointB.x)},${Math.round(text.pointB.y)}` +
1897
+ ` L${Math.round(text.pointC.x)},${Math.round(text.pointC.y)}`
1898
+ });
1899
+ }
1900
+ const relatedGraphic = this._idToGraphic.get(text.attribute.id);
1806
1901
  const state = prevTextMap?.get(relatedGraphic) ? 'update' : 'enter';
1807
1902
  if (state === 'enter') {
1808
1903
  texts.push(text);
1904
+ if (this.attribute.type === 'arc' && this.attribute.position === 'outside') ;
1809
1905
  currentTextMap.set(relatedGraphic, text);
1810
1906
  if (!disableAnimation && relatedGraphic) {
1811
- const { from, to } = getAnimationAttributes(label, 'fadeIn');
1907
+ const { from, to } = getAnimationAttributes(text.attribute, 'fadeIn');
1812
1908
  this.add(text);
1909
+ if (this.attribute.type === 'arc' && this.attribute.position === 'outside') {
1910
+ this.add(labelLine);
1911
+ }
1813
1912
  relatedGraphic.onAnimateBind = () => {
1814
1913
  text.setAttributes(from);
1815
1914
  const listener = this._afterRelatedGraphicAttributeUpdate(text, texts, index, relatedGraphic, {
@@ -1858,7 +1957,7 @@
1858
1957
  });
1859
1958
  }
1860
1959
  });
1861
- this._textMap = currentTextMap;
1960
+ this._graphicToText = currentTextMap;
1862
1961
  }
1863
1962
  _afterRelatedGraphicAttributeUpdate(text, texts, index, relatedGraphic, { mode, duration, easing, to, delay }) {
1864
1963
  const listener = (event) => {
@@ -1909,30 +2008,42 @@
1909
2008
  return listener;
1910
2009
  }
1911
2010
  _smartInvert(labels) {
1912
- if (this.attribute.smartInvert === false) {
1913
- return;
1914
- }
2011
+ const option = (this.attribute.smartInvert || {});
2012
+ const { textType, contrastRatiosThreshold, alternativeColors } = option;
1915
2013
  for (let i = 0; i < labels.length; i++) {
1916
- const label = labels?.[i];
2014
+ const label = labels[i];
1917
2015
  if (!label) {
1918
2016
  continue;
1919
2017
  }
1920
- const isInside = canPlaceInside(vrender.createText(label).AABBBounds, this._relationMap.get(label._relatedIndex)?.AABBBounds);
1921
- if (label.stroke && label.lineWidth > 0) {
1922
- label.fill = labelSmartInvert(label.fill, label.stroke, this.attribute.smartInvert?.textType, this.attribute.smartInvert?.contrastRatiosThreshold, this.attribute.smartInvert?.alternativeColors);
2018
+ const baseMark = this._idToGraphic.get(label.attribute.id);
2019
+ let isInside = canPlaceInside(label.AABBBounds, baseMark?.AABBBounds);
2020
+ if (this.attribute.type === 'arc') {
2021
+ if (this.attribute.position === 'inside') {
2022
+ isInside = true;
2023
+ }
2024
+ else {
2025
+ isInside = false;
2026
+ }
2027
+ }
2028
+ if (label.attribute.stroke && label.attribute.lineWidth > 0) {
2029
+ label.setAttributes({
2030
+ fill: labelSmartInvert(label.attribute.fill, label.attribute.stroke, textType, contrastRatiosThreshold, alternativeColors)
2031
+ });
1923
2032
  }
1924
2033
  else if (isInside) {
1925
- const baseMark = this._relationMap.get(label._relatedIndex);
1926
2034
  const backgroundColor = baseMark.attribute.fill;
1927
- const foregroundColor = label.fill;
1928
- label.fill = labelSmartInvert(foregroundColor, backgroundColor, this.attribute.smartInvert?.textType, this.attribute.smartInvert?.contrastRatiosThreshold, this.attribute.smartInvert?.alternativeColors);
2035
+ const foregroundColor = label.attribute.fill;
2036
+ label.setAttributes({
2037
+ fill: labelSmartInvert(foregroundColor, backgroundColor, textType, contrastRatiosThreshold, alternativeColors)
2038
+ });
1929
2039
  }
1930
- else if (label.lineWidth > 0) {
1931
- const baseMark = this._relationMap.get(label._relatedIndex);
1932
- label.stroke = baseMark.attribute.fill;
1933
- const backgroundColor = label.stroke;
1934
- const foregroundColor = label.fill;
1935
- label.fill = labelSmartInvert(foregroundColor, backgroundColor, this.attribute.smartInvert?.textType, this.attribute.smartInvert?.contrastRatiosThreshold, this.attribute.smartInvert?.alternativeColors);
2040
+ else if (label.attribute.lineWidth > 0) {
2041
+ const backgroundColor = label.attribute.stroke;
2042
+ const foregroundColor = label.attribute.fill;
2043
+ label.setAttributes({
2044
+ stroke: baseMark.attribute.fill,
2045
+ fill: labelSmartInvert(foregroundColor, backgroundColor, textType, contrastRatiosThreshold, alternativeColors)
2046
+ });
1936
2047
  }
1937
2048
  }
1938
2049
  }
@@ -2140,9 +2251,748 @@
2140
2251
  }
2141
2252
  }
2142
2253
 
2254
+ function polarToCartesian(point) {
2255
+ if (!point.radius) {
2256
+ return { x: 0, y: 0 };
2257
+ }
2258
+ return {
2259
+ x: Math.cos(point.angle) * point.radius,
2260
+ y: Math.sin(point.angle) * point.radius
2261
+ };
2262
+ }
2263
+ function circlePoint(x0, y0, radius, radian) {
2264
+ const offset = polarToCartesian({
2265
+ radius,
2266
+ angle: radian
2267
+ });
2268
+ return {
2269
+ x: x0 + offset.x,
2270
+ y: y0 + offset.y
2271
+ };
2272
+ }
2273
+ function isQuadrantLeft(quadrant) {
2274
+ return quadrant === 3 || quadrant === 4;
2275
+ }
2276
+ function isQuadrantRight(quadrant) {
2277
+ return quadrant === 1 || quadrant === 2;
2278
+ }
2279
+ function lineCirclePoints(a, b, c, x0, y0, r) {
2280
+ if ((a === 0 && b === 0) || r <= 0) {
2281
+ return [];
2282
+ }
2283
+ if (a === 0) {
2284
+ const y1 = -c / b;
2285
+ const fy = (y1 - y0) ** 2;
2286
+ const fd = r ** 2 - fy;
2287
+ if (fd < 0) {
2288
+ return [];
2289
+ }
2290
+ else if (fd === 0) {
2291
+ return [{ x: x0, y: y1 }];
2292
+ }
2293
+ const x1 = Math.sqrt(fd) + x0;
2294
+ const x2 = -Math.sqrt(fd) + x0;
2295
+ return [
2296
+ { x: x1, y: y1 },
2297
+ { x: x2, y: y1 }
2298
+ ];
2299
+ }
2300
+ else if (b === 0) {
2301
+ const x1 = -c / a;
2302
+ const fx = (x1 - x0) ** 2;
2303
+ const fd = r ** 2 - fx;
2304
+ if (fd < 0) {
2305
+ return [];
2306
+ }
2307
+ else if (fd === 0) {
2308
+ return [{ x: x1, y: y0 }];
2309
+ }
2310
+ const y1 = Math.sqrt(fd) + y0;
2311
+ const y2 = -Math.sqrt(fd) + y0;
2312
+ return [
2313
+ { x: x1, y: y1 },
2314
+ { x: x1, y: y2 }
2315
+ ];
2316
+ }
2317
+ const fa = (b / a) ** 2 + 1;
2318
+ const fb = 2 * ((c / a + x0) * (b / a) - y0);
2319
+ const fc = (c / a + x0) ** 2 + y0 ** 2 - r ** 2;
2320
+ const fd = fb ** 2 - 4 * fa * fc;
2321
+ if (fd < 0) {
2322
+ return [];
2323
+ }
2324
+ const y1 = (-fb + Math.sqrt(fd)) / (2 * fa);
2325
+ const y2 = (-fb - Math.sqrt(fd)) / (2 * fa);
2326
+ const x1 = -(b * y1 + c) / a;
2327
+ const x2 = -(b * y2 + c) / a;
2328
+ if (fd === 0) {
2329
+ return [{ x: x1, y: y1 }];
2330
+ }
2331
+ return [
2332
+ { x: x1, y: y1 },
2333
+ { x: x2, y: y2 }
2334
+ ];
2335
+ }
2336
+ function connectLineRadian(radius, length) {
2337
+ if (length > radius * 2) {
2338
+ return NaN;
2339
+ }
2340
+ return Math.asin(length / 2 / radius) * 2;
2341
+ }
2342
+ function checkBoundsOverlap(boundsA, boundsB) {
2343
+ const { x1: ax1, y1: ay1, x2: ax2, y2: ay2 } = boundsA;
2344
+ const { x1: bx1, y1: by1, x2: bx2, y2: by2 } = boundsB;
2345
+ return !((ax1 <= bx1 && ax2 <= bx1) ||
2346
+ (ax1 >= bx2 && ax2 >= bx2) ||
2347
+ (ay1 <= by1 && ay2 <= by1) ||
2348
+ (ay1 >= by2 && ay2 >= by2));
2349
+ }
2350
+
2351
+ const PREFIX = '__VCHART';
2352
+ const ARC_K = `${PREFIX}_ARC_K`;
2353
+ const ARC_MIDDLE_ANGLE = `${PREFIX}_ARC_MIDDLE_ANGLE`;
2354
+ const ARC_QUADRANT = `${PREFIX}_ARC_QUADRANT`;
2355
+ const ARC_RADIAN = `${PREFIX}_ARC_RADIAN`;
2356
+
2357
+ class ArcInfo {
2358
+ key;
2359
+ refDatum;
2360
+ center;
2361
+ outerCenter;
2362
+ labelSize;
2363
+ labelPosition;
2364
+ labelLimit;
2365
+ labelVisible;
2366
+ lastLabelY;
2367
+ labelYRange;
2368
+ labelText;
2369
+ pointA;
2370
+ pointB;
2371
+ pointC;
2372
+ quadrant;
2373
+ radian;
2374
+ middleAngle;
2375
+ k;
2376
+ textAlign;
2377
+ textBaseline;
2378
+ angle;
2379
+ constructor(refDatum, center, outerCenter, quadrant, radian, middleAngle, k) {
2380
+ this.refDatum = refDatum;
2381
+ this.center = center;
2382
+ this.outerCenter = outerCenter;
2383
+ this.quadrant = quadrant;
2384
+ this.radian = radian;
2385
+ this.middleAngle = middleAngle;
2386
+ this.k = k;
2387
+ this.labelVisible = true;
2388
+ this.labelLimit = 0;
2389
+ }
2390
+ getLabelBounds() {
2391
+ if (!this.labelPosition || !this.labelSize) {
2392
+ return { x1: 0, x2: 0, y1: 0, y2: 0 };
2393
+ }
2394
+ return {
2395
+ x1: this.labelPosition.x - this.labelSize.width / 2,
2396
+ y1: this.labelPosition.y - this.labelSize.height / 2,
2397
+ x2: this.labelPosition.x + this.labelSize.width / 2,
2398
+ y2: this.labelPosition.y + this.labelSize.height / 2
2399
+ };
2400
+ }
2401
+ }
2402
+ class ArcLabel extends LabelBase {
2403
+ name = 'arc-label';
2404
+ static defaultAttributes = {
2405
+ coverEnable: false,
2406
+ spaceWidth: 5,
2407
+ layoutArcGap: 6,
2408
+ textStyle: {
2409
+ visible: true,
2410
+ fontSize: 14,
2411
+ fontWeight: 'normal',
2412
+ fillOpacity: 1
2413
+ },
2414
+ position: 'outside',
2415
+ offset: 0,
2416
+ line: {
2417
+ visible: true,
2418
+ line1MinLength: 20,
2419
+ line2MinLength: 10
2420
+ },
2421
+ layout: {
2422
+ align: 'arc',
2423
+ strategy: 'priority',
2424
+ tangentConstraint: true
2425
+ }
2426
+ };
2427
+ _ellipsisWidth = 0;
2428
+ _arcLeft = new Map();
2429
+ _arcRight = new Map();
2430
+ constructor(attributes) {
2431
+ super(vutils.merge({}, ArcLabel.defaultAttributes, attributes));
2432
+ }
2433
+ labeling(textBounds, graphicBounds, position = 'outside', offset = 0, graphicAttributes, textData, width, height, attribute) {
2434
+ if (!textBounds || !graphicBounds) {
2435
+ return;
2436
+ }
2437
+ const radiusRatio = this.computeLayoutOuterRadius(graphicAttributes.outerRadius, width, height);
2438
+ const radius = this.computeRadius(radiusRatio, width, height);
2439
+ const center = attribute.center ?? { x: 0, y: 0 };
2440
+ const item = textData;
2441
+ const arcMiddle = circlePoint(center.x, center.y, radius * item[ARC_K], item[ARC_MIDDLE_ANGLE]);
2442
+ const outerArcMiddle = circlePoint(center.x, center.y, radius + attribute.line.line1MinLength, item[ARC_MIDDLE_ANGLE]);
2443
+ const arc = new ArcInfo(item, arcMiddle, outerArcMiddle, item[ARC_QUADRANT], item[ARC_RADIAN], item[ARC_MIDDLE_ANGLE], item[ARC_K]);
2444
+ arc.pointA = circlePoint(center.x, center.y, this.computeDatumRadius(center.x * 2, center.y * 2, graphicAttributes.outerRadius), arc.middleAngle);
2445
+ arc.labelSize = {
2446
+ width: textBounds.x2 - textBounds.x1,
2447
+ height: textBounds.y2 - textBounds.y1
2448
+ };
2449
+ if (isQuadrantRight(arc.quadrant)) {
2450
+ arc.textAlign = 'left';
2451
+ arc.textBaseline = 'bottom';
2452
+ this._arcRight.set(arc.refDatum, arc);
2453
+ }
2454
+ else if (isQuadrantLeft(arc.quadrant)) {
2455
+ arc.textAlign = 'right';
2456
+ arc.textBaseline = 'bottom';
2457
+ this._arcLeft.set(arc.refDatum, arc);
2458
+ }
2459
+ }
2460
+ layoutArcLabels(position, attribute, currentMarks) {
2461
+ const leftArcs = Array.from(this._arcLeft.values());
2462
+ const rightArcs = Array.from(this._arcRight.values());
2463
+ const arcs = [];
2464
+ if (position === 'inside') {
2465
+ arcs.push(...this._layoutInsideLabels(rightArcs, attribute, currentMarks));
2466
+ arcs.push(...this._layoutInsideLabels(leftArcs, attribute, currentMarks));
2467
+ }
2468
+ else {
2469
+ arcs.push(...this._layoutOutsideLabels(rightArcs, attribute, currentMarks));
2470
+ arcs.push(...this._layoutOutsideLabels(leftArcs, attribute, currentMarks));
2471
+ }
2472
+ return arcs;
2473
+ }
2474
+ _layoutInsideLabels(arcs, attribute, currentMarks) {
2475
+ const center = attribute.center ?? { x: 0, y: 0 };
2476
+ const innerRadiusRatio = this.computeLayoutOuterRadius(currentMarks[0].attribute.innerRadius, attribute.width, attribute.height);
2477
+ const outerRadiusRatio = this.computeLayoutOuterRadius(currentMarks[0].attribute.outerRadius, attribute.width, attribute.height);
2478
+ const labelConfig = attribute;
2479
+ const spaceWidth = labelConfig.spaceWidth;
2480
+ arcs.forEach((arc) => {
2481
+ const { labelSize, radian } = arc;
2482
+ const innerRadius = this.computeRadius(innerRadiusRatio, attribute.width, attribute.height, 1);
2483
+ const outerRadius = this.computeRadius(outerRadiusRatio, attribute.width, attribute.height, 1);
2484
+ const minRadian = connectLineRadian(outerRadius, labelSize.height);
2485
+ let limit;
2486
+ if (radian < minRadian) {
2487
+ limit = 0;
2488
+ }
2489
+ else {
2490
+ let minRadius;
2491
+ if (radian >= Math.PI) {
2492
+ minRadius = innerRadius;
2493
+ }
2494
+ else {
2495
+ minRadius = Math.max(innerRadius, labelSize.height / 2 / Math.tan(radian / 2));
2496
+ }
2497
+ limit = outerRadius - minRadius - spaceWidth;
2498
+ }
2499
+ if (labelConfig?.rotate !== true) {
2500
+ limit = outerRadius - spaceWidth;
2501
+ }
2502
+ const text = this._getFormatLabelText(arc.refDatum, limit);
2503
+ arc.labelText = text;
2504
+ const labelWidth = Math.min(limit, arc.labelSize.width);
2505
+ const align = this._computeAlign(arc, attribute);
2506
+ const alignOffset = align === 'left' ? labelWidth : align === 'right' ? 0 : labelWidth / 2;
2507
+ const labelRadius = outerRadius - spaceWidth - alignOffset;
2508
+ arc.labelPosition = circlePoint(center.x, center.y, labelRadius, arc.middleAngle);
2509
+ arc.labelLimit = labelWidth;
2510
+ if (!vutils.isGreater(labelWidth, 0)) {
2511
+ arc.labelVisible = false;
2512
+ }
2513
+ (arc.textAlign = 'center'), (arc.textBaseline = 'middle');
2514
+ arc.angle = arc.middleAngle;
2515
+ });
2516
+ return arcs;
2517
+ }
2518
+ _layoutOutsideLabels(arcs, attribute, currentMarks) {
2519
+ const height = attribute.center.y * 2;
2520
+ const line2MinLength = attribute.line.line2MinLength;
2521
+ const labelLayout = attribute.layout;
2522
+ const spaceWidth = attribute.spaceWidth;
2523
+ arcs.forEach(arc => {
2524
+ const direction = isQuadrantLeft(arc.quadrant) ? -1 : 1;
2525
+ arc.labelPosition = {
2526
+ x: arc.outerCenter.x + direction * (arc.labelSize.width / 2 + line2MinLength + spaceWidth),
2527
+ y: arc.outerCenter.y
2528
+ };
2529
+ });
2530
+ arcs.sort((a, b) => {
2531
+ return a.labelPosition.y - b.labelPosition.y;
2532
+ });
2533
+ if (attribute.coverEnable !== false || labelLayout.strategy === 'none') {
2534
+ for (const arc of arcs) {
2535
+ const { labelPosition, labelSize } = arc;
2536
+ arc.labelLimit = labelSize.width;
2537
+ arc.pointB = isQuadrantLeft(arc.quadrant)
2538
+ ? {
2539
+ x: labelPosition.x + labelSize.width / 2 + line2MinLength + spaceWidth,
2540
+ y: labelPosition.y
2541
+ }
2542
+ : {
2543
+ x: labelPosition.x - labelSize.width / 2 - line2MinLength - spaceWidth,
2544
+ y: labelPosition.y
2545
+ };
2546
+ this._computeX(arc, attribute, currentMarks);
2547
+ }
2548
+ if (attribute.coverEnable === false && labelLayout.strategy === 'none') {
2549
+ this._coverLabels(arcs);
2550
+ }
2551
+ }
2552
+ else {
2553
+ const maxLabels = height / (attribute.textStyle?.fontSize || 16);
2554
+ this._adjustY(arcs, maxLabels, attribute, currentMarks);
2555
+ const { minY, maxY } = arcs.reduce((yInfo, arc) => {
2556
+ const { y1, y2 } = arc.getLabelBounds();
2557
+ yInfo.minY = Math.max(0, Math.min(y1, yInfo.minY));
2558
+ yInfo.maxY = Math.min(height, Math.max(y2, yInfo.maxY));
2559
+ return yInfo;
2560
+ }, { minY: Infinity, maxY: -Infinity });
2561
+ const halfY = Math.max(Math.abs(height / 2 - minY), Math.abs(maxY - height / 2));
2562
+ const r = this._computeLayoutRadius(halfY, attribute, currentMarks);
2563
+ for (const arc of arcs) {
2564
+ this._computePointB(arc, r, attribute, currentMarks);
2565
+ this._computeX(arc, attribute, currentMarks);
2566
+ }
2567
+ }
2568
+ const width = attribute.center.x * 2;
2569
+ arcs.forEach(arc => {
2570
+ if (arc.labelVisible &&
2571
+ (vutils.isLess(arc.pointB.x, line2MinLength + spaceWidth) ||
2572
+ vutils.isGreater(arc.pointB.x, width - line2MinLength - spaceWidth))) {
2573
+ arc.labelVisible = false;
2574
+ }
2575
+ arc.angle = 0;
2576
+ });
2577
+ return arcs;
2578
+ }
2579
+ _computeX(arc, attribute, currentMarks) {
2580
+ const center = attribute.center ?? { x: 0, y: 0 };
2581
+ const plotLayout = { width: attribute.center.x * 2, height: attribute.center.y * 2 };
2582
+ const radiusRatio = this.computeLayoutOuterRadius(currentMarks[0].attribute.outerRadius, attribute.width, attribute.height);
2583
+ const line1MinLength = attribute.line.line1MinLength;
2584
+ const line2MinLength = attribute.line.line2MinLength;
2585
+ const labelLayoutAlign = attribute.layout?.align;
2586
+ const spaceWidth = attribute.spaceWidth;
2587
+ const align = this._computeAlign(arc, attribute);
2588
+ const { labelPosition, quadrant, pointB } = arc;
2589
+ if (!vutils.isValidNumber(pointB.x * pointB.y)) {
2590
+ arc.pointC = { x: NaN, y: NaN };
2591
+ labelPosition.x = NaN;
2592
+ arc.labelLimit = 0;
2593
+ }
2594
+ const radius = this.computeRadius(radiusRatio, attribute.width, attribute.height);
2595
+ const flag = isQuadrantLeft(quadrant) ? -1 : 1;
2596
+ let cx = 0;
2597
+ const restWidth = flag > 0 ? plotLayout.width - pointB.x : pointB.x;
2598
+ let limit = restWidth - line2MinLength - spaceWidth;
2599
+ if (labelLayoutAlign === 'labelLine') {
2600
+ cx = (radius + line1MinLength + line2MinLength) * flag + center.x;
2601
+ limit = (flag > 0 ? plotLayout.width - cx : cx) - spaceWidth;
2602
+ }
2603
+ const text = this._getFormatLabelText(arc.refDatum, limit);
2604
+ arc.labelText = text;
2605
+ let labelWidth = Math.min(limit, arc.labelSize.width);
2606
+ switch (labelLayoutAlign) {
2607
+ case 'labelLine':
2608
+ break;
2609
+ case 'edge':
2610
+ cx = flag > 0 ? plotLayout.width - labelWidth - spaceWidth : labelWidth + spaceWidth;
2611
+ break;
2612
+ case 'arc':
2613
+ default:
2614
+ cx = pointB.x + flag * line2MinLength;
2615
+ break;
2616
+ }
2617
+ labelWidth = Math.max(this._ellipsisWidth, labelWidth);
2618
+ arc.pointC = { x: cx, y: labelPosition.y };
2619
+ if (labelLayoutAlign === 'edge') {
2620
+ const alignOffset = this._computeAlignOffset(align, labelWidth, -flag);
2621
+ labelPosition.x = flag > 0 ? plotLayout.width + alignOffset : alignOffset;
2622
+ }
2623
+ else {
2624
+ const alignOffset = this._computeAlignOffset(align, labelWidth, flag);
2625
+ labelPosition.x = cx + alignOffset + flag * spaceWidth;
2626
+ }
2627
+ arc.labelLimit = labelWidth;
2628
+ }
2629
+ _computeAlignOffset(align, labelWidth, alignFlag) {
2630
+ switch (align) {
2631
+ case 'left':
2632
+ return alignFlag < 0 ? -labelWidth : 0;
2633
+ case 'right':
2634
+ return alignFlag < 0 ? 0 : labelWidth;
2635
+ case 'center':
2636
+ default:
2637
+ return (labelWidth / 2) * alignFlag;
2638
+ }
2639
+ }
2640
+ _computeAlign(arc, attribute) {
2641
+ const labelConfig = attribute;
2642
+ const textAlign = labelConfig.textStyle?.textAlign ?? labelConfig.textStyle?.align;
2643
+ const layoutAlign = labelConfig.layout?.textAlign ?? labelConfig.layout?.align;
2644
+ if (labelConfig.position !== 'inside') {
2645
+ if (vutils.isNil(textAlign) || textAlign === 'auto') {
2646
+ if (layoutAlign === 'edge') {
2647
+ return isQuadrantLeft(arc.quadrant) ? 'left' : 'right';
2648
+ }
2649
+ return isQuadrantLeft(arc.quadrant) ? 'right' : 'left';
2650
+ }
2651
+ return textAlign;
2652
+ }
2653
+ return vutils.isNil(textAlign) || textAlign === 'auto' ? 'center' : textAlign;
2654
+ }
2655
+ _getFormatLabelText(value, limit) {
2656
+ return value.text;
2657
+ }
2658
+ _adjustY(arcs, maxLabels, attribute, currentMarks) {
2659
+ const plotRect = { width: attribute.center.x * 2, height: attribute.center.y * 2 };
2660
+ const labelLayout = attribute.layout;
2661
+ if (labelLayout.strategy === 'vertical') {
2662
+ let lastY = 0;
2663
+ let delta;
2664
+ const len = arcs.length;
2665
+ if (len <= 0) {
2666
+ return;
2667
+ }
2668
+ for (let i = 0; i < len; i++) {
2669
+ const { y1 } = arcs[i].getLabelBounds();
2670
+ delta = y1 - lastY;
2671
+ if (vutils.isLess(delta, 0)) {
2672
+ const index = this._shiftY(arcs, i, len - 1, -delta);
2673
+ this._shiftY(arcs, index, 0, delta / 2);
2674
+ }
2675
+ const { y2 } = arcs[i].getLabelBounds();
2676
+ lastY = y2;
2677
+ }
2678
+ const { y1: firstY1 } = arcs[0].getLabelBounds();
2679
+ delta = firstY1 - 0;
2680
+ if (vutils.isLess(delta, 0)) {
2681
+ this._shiftY(arcs, 0, len - 1, -delta);
2682
+ }
2683
+ for (let i = arcs.length - 1; i >= 0; i--) {
2684
+ if (arcs[i].getLabelBounds().y2 > plotRect.height) {
2685
+ arcs[i].labelVisible = false;
2686
+ }
2687
+ else {
2688
+ break;
2689
+ }
2690
+ }
2691
+ }
2692
+ else if (labelLayout.strategy !== 'none') {
2693
+ const priorityArcs = arcs.map((arc, i) => {
2694
+ return {
2695
+ arc,
2696
+ originIndex: i,
2697
+ priorityIndex: 0
2698
+ };
2699
+ });
2700
+ priorityArcs.sort((a, b) => {
2701
+ return b.arc.radian - a.arc.radian;
2702
+ });
2703
+ priorityArcs.forEach((priorityArc, i) => {
2704
+ priorityArc.priorityIndex = i;
2705
+ priorityArc.arc.labelVisible = false;
2706
+ });
2707
+ let topLabelIndex = Infinity;
2708
+ let bottomLabelIndex = -Infinity;
2709
+ for (let i = 0; i < maxLabels && i < arcs.length; i++) {
2710
+ this._storeY(arcs);
2711
+ const arc = priorityArcs[i].arc;
2712
+ this._computeYRange(arc, attribute, currentMarks);
2713
+ arc.labelVisible = true;
2714
+ const curY = arc.labelPosition.y;
2715
+ const { lastIndex, nextIndex } = this._findNeighborIndex(arcs, priorityArcs[i]);
2716
+ const lastArc = arcs[lastIndex];
2717
+ const nextArc = arcs[nextIndex];
2718
+ if (lastIndex === -1 && nextIndex !== -1) {
2719
+ const nextY = nextArc.labelPosition.y;
2720
+ if (curY > nextY) {
2721
+ arc.labelPosition.y = nextY - nextArc.labelSize.height / 2 - arc.labelSize.height / 2;
2722
+ }
2723
+ else {
2724
+ this._twoWayShift(arcs, arc, nextArc, nextIndex);
2725
+ }
2726
+ }
2727
+ else if (lastIndex !== -1 && nextIndex === -1) {
2728
+ const lastY = lastArc.labelPosition.y;
2729
+ if (curY < lastY) {
2730
+ arc.labelPosition.y = lastY + lastArc.labelSize.height / 2 + arc.labelSize.height / 2;
2731
+ }
2732
+ else {
2733
+ this._twoWayShift(arcs, lastArc, arc, priorityArcs[i].originIndex);
2734
+ }
2735
+ }
2736
+ else if (lastIndex !== -1 && nextIndex !== -1) {
2737
+ const lastY = lastArc.labelPosition.y;
2738
+ const nextY = nextArc.labelPosition.y;
2739
+ if (curY > nextY) {
2740
+ arc.labelPosition.y = nextY - nextArc.labelSize.height / 2 - arc.labelSize.height / 2;
2741
+ this._twoWayShift(arcs, lastArc, arc, priorityArcs[i].originIndex);
2742
+ }
2743
+ else if (curY < lastY) {
2744
+ arc.labelPosition.y = lastY + lastArc.labelSize.height / 2 + arc.labelSize.height / 2;
2745
+ this._twoWayShift(arcs, arc, nextArc, nextIndex);
2746
+ }
2747
+ else {
2748
+ this._twoWayShift(arcs, lastArc, arc, priorityArcs[i].originIndex);
2749
+ this._twoWayShift(arcs, arc, nextArc, nextIndex);
2750
+ }
2751
+ }
2752
+ const nextTopIndex = Math.min(topLabelIndex, priorityArcs[i].originIndex);
2753
+ const nextBottomIndex = Math.max(bottomLabelIndex, priorityArcs[i].originIndex);
2754
+ let delta;
2755
+ delta = arcs[nextBottomIndex].getLabelBounds().y2 - plotRect.height;
2756
+ if (vutils.isGreater(delta, 0)) {
2757
+ this._shiftY(arcs, nextBottomIndex, 0, -delta);
2758
+ }
2759
+ delta = arcs[nextTopIndex].getLabelBounds().y1 - 0;
2760
+ if (vutils.isLess(delta, 0)) {
2761
+ this._shiftY(arcs, nextTopIndex, arcs.length - 1, -delta);
2762
+ }
2763
+ delta = arcs[nextBottomIndex].getLabelBounds().y2 - plotRect.height;
2764
+ if (vutils.isGreater(delta, 0)) {
2765
+ arc.labelVisible = false;
2766
+ this._restoreY(arcs);
2767
+ break;
2768
+ }
2769
+ else if (labelLayout.tangentConstraint && !this._checkYRange(arcs)) {
2770
+ arc.labelVisible = false;
2771
+ this._restoreY(arcs);
2772
+ }
2773
+ else {
2774
+ topLabelIndex = nextTopIndex;
2775
+ bottomLabelIndex = nextBottomIndex;
2776
+ }
2777
+ }
2778
+ }
2779
+ }
2780
+ _shiftY(arcs, start, end, delta) {
2781
+ const direction = start < end ? 1 : -1;
2782
+ let index = start;
2783
+ while (index !== -1) {
2784
+ arcs[index].labelPosition.y += delta;
2785
+ const nextIndex = this._findNextVisibleIndex(arcs, index, end, direction);
2786
+ if (nextIndex >= 0 && nextIndex < arcs.length) {
2787
+ const { y1: curY1, y2: curY2 } = arcs[index].getLabelBounds();
2788
+ const { y1: nextY1, y2: nextY2 } = arcs[nextIndex].getLabelBounds();
2789
+ if ((direction > 0 && curY2 < nextY1) || (direction < 0 && curY1 > nextY2)) {
2790
+ return index;
2791
+ }
2792
+ }
2793
+ index = nextIndex;
2794
+ }
2795
+ return end;
2796
+ }
2797
+ _findNextVisibleIndex(arcs, start, end, direction) {
2798
+ const diff = (end - start) * direction;
2799
+ for (let i = 1; i <= diff; i++) {
2800
+ const index = start + i * direction;
2801
+ if (arcs[index].labelVisible) {
2802
+ return index;
2803
+ }
2804
+ }
2805
+ return -1;
2806
+ }
2807
+ _computePointB(arc, r, attribute, currentMarks) {
2808
+ const labelConfig = attribute;
2809
+ const radiusRatio = this.computeLayoutOuterRadius(currentMarks[0].attribute.outerRadius, attribute.width, attribute.height);
2810
+ const line1MinLength = labelConfig.line.line1MinLength;
2811
+ const labelLayout = labelConfig.layout;
2812
+ if (labelLayout.strategy === 'none') {
2813
+ arc.pointB = {
2814
+ x: arc.outerCenter.x,
2815
+ y: arc.outerCenter.y
2816
+ };
2817
+ }
2818
+ else {
2819
+ const center = attribute.center ?? { x: 0, y: 0 };
2820
+ const radius = this.computeRadius(radiusRatio, attribute.width, attribute.height);
2821
+ const { labelPosition, quadrant } = arc;
2822
+ const outerR = Math.max(radius + line1MinLength, currentMarks[0].attribute.outerRadius);
2823
+ const rd = r - outerR;
2824
+ const x = Math.sqrt(r ** 2 - Math.abs(center.y - labelPosition.y) ** 2) - rd;
2825
+ if (vutils.isValidNumber(x)) {
2826
+ arc.pointB = {
2827
+ x: center.x + x * (isQuadrantLeft(quadrant) ? -1 : 1),
2828
+ y: labelPosition.y
2829
+ };
2830
+ }
2831
+ else {
2832
+ arc.pointB = { x: NaN, y: NaN };
2833
+ }
2834
+ }
2835
+ }
2836
+ _storeY(arcs) {
2837
+ for (const arc of arcs) {
2838
+ if (arc.labelVisible) {
2839
+ arc.lastLabelY = arc.labelPosition.y;
2840
+ }
2841
+ }
2842
+ }
2843
+ _computeYRange(arc, attribute, currentMarks) {
2844
+ const plotRect = { width: attribute.center.x * 2, height: attribute.center.y * 2 };
2845
+ const radiusRatio = this.computeLayoutOuterRadius(currentMarks[0].attribute.outerRadius, attribute.width, attribute.height);
2846
+ const line1MinLength = attribute.line.line1MinLength;
2847
+ const { width, height } = plotRect;
2848
+ const radius = this.computeRadius(radiusRatio, attribute.width, attribute.height);
2849
+ const r = this._computeLayoutRadius(height / 2, attribute, currentMarks);
2850
+ const cx = Math.abs(arc.center.x - width / 2);
2851
+ const cy = arc.center.y - height / 2;
2852
+ let a;
2853
+ let b;
2854
+ let c;
2855
+ if (vutils.isNumberClose(width / 2, cx)) {
2856
+ a = 0;
2857
+ b = 1;
2858
+ c = -cy;
2859
+ }
2860
+ else if (vutils.isNumberClose(height / 2, cy)) {
2861
+ a = 1;
2862
+ b = 0;
2863
+ c = -cx;
2864
+ }
2865
+ else {
2866
+ const k = -1 / (cy / cx);
2867
+ a = k;
2868
+ b = -1;
2869
+ c = cy - k * cx;
2870
+ }
2871
+ const points = lineCirclePoints(a, b, c, line1MinLength + radius - r, 0, r);
2872
+ if (points.length < 2) {
2873
+ return;
2874
+ }
2875
+ let min;
2876
+ let max;
2877
+ if (points[0].x > points[1].x) {
2878
+ points.reverse();
2879
+ }
2880
+ if (points[0].x < 0) {
2881
+ if (vutils.isNumberClose(points[0].y, points[1].y)) {
2882
+ if (Math.abs(arc.middleAngle) < Math.PI / 2) {
2883
+ min = 0;
2884
+ max = points[1].y + height / 2;
2885
+ }
2886
+ else {
2887
+ min = points[1].y + height / 2;
2888
+ max = height;
2889
+ }
2890
+ }
2891
+ else if (points[0].y < points[1].y) {
2892
+ min = 0;
2893
+ max = points[1].y + height / 2;
2894
+ }
2895
+ else {
2896
+ min = points[1].y + height / 2;
2897
+ max = plotRect.height;
2898
+ }
2899
+ }
2900
+ else {
2901
+ min = Math.min(points[0].y, points[1].y) + height / 2;
2902
+ max = Math.max(points[0].y, points[1].y) + height / 2;
2903
+ }
2904
+ arc.labelYRange = [min, max];
2905
+ }
2906
+ _computeLayoutRadius(halfYLength, attribute, currentMarks) {
2907
+ const labelConfig = attribute;
2908
+ const layoutArcGap = labelConfig.layoutArcGap;
2909
+ const line1MinLength = labelConfig.line.line1MinLength;
2910
+ const radiusRatio = this.computeLayoutOuterRadius(currentMarks[0].attribute.outerRadius, attribute.width, attribute.height);
2911
+ const radius = this.computeRadius(radiusRatio, attribute.width, attribute.height);
2912
+ const outerR = radius + line1MinLength;
2913
+ const a = outerR - layoutArcGap;
2914
+ return Math.max((a ** 2 + halfYLength ** 2) / (2 * a), outerR);
2915
+ }
2916
+ _findNeighborIndex(arcs, priorityArc) {
2917
+ const index = priorityArc.originIndex;
2918
+ let lastIndex = -1;
2919
+ let nextIndex = -1;
2920
+ for (let i = index - 1; i >= 0; i--) {
2921
+ if (arcs[i].labelVisible) {
2922
+ lastIndex = i;
2923
+ break;
2924
+ }
2925
+ }
2926
+ for (let i = index + 1; i < arcs.length; i++) {
2927
+ if (arcs[i].labelVisible) {
2928
+ nextIndex = i;
2929
+ break;
2930
+ }
2931
+ }
2932
+ return {
2933
+ lastIndex,
2934
+ nextIndex
2935
+ };
2936
+ }
2937
+ _twoWayShift(arcs, lastArc, nextArc, nextIndex) {
2938
+ const delta = nextArc.getLabelBounds().y1 - lastArc.getLabelBounds().y2;
2939
+ if (vutils.isLess(delta, 0)) {
2940
+ const i = this._shiftY(arcs, nextIndex, arcs.length - 1, -delta);
2941
+ this._shiftY(arcs, i, 0, delta / 2);
2942
+ }
2943
+ }
2944
+ _restoreY(arcs) {
2945
+ for (const arc of arcs) {
2946
+ if (arc.labelVisible) {
2947
+ arc.labelPosition.y = arc.lastLabelY;
2948
+ }
2949
+ }
2950
+ }
2951
+ _checkYRange(arcs) {
2952
+ for (const arc of arcs) {
2953
+ const { labelYRange, labelPosition } = arc;
2954
+ if (arc.labelVisible &&
2955
+ labelYRange &&
2956
+ (vutils.isLess(labelPosition.y, labelYRange[0]) || vutils.isGreater(labelPosition.y, labelYRange[1]))) {
2957
+ return false;
2958
+ }
2959
+ }
2960
+ return true;
2961
+ }
2962
+ _coverLabels(arcs) {
2963
+ if (arcs.length <= 1) {
2964
+ return;
2965
+ }
2966
+ let lastBounds = arcs[0].getLabelBounds();
2967
+ for (let i = 1; i < arcs.length; i++) {
2968
+ const bounds = arcs[i].getLabelBounds();
2969
+ if (!checkBoundsOverlap(lastBounds, bounds)) {
2970
+ lastBounds = bounds;
2971
+ }
2972
+ else {
2973
+ arcs[i].labelVisible = false;
2974
+ }
2975
+ }
2976
+ }
2977
+ computeRadius(r, width, height, k) {
2978
+ return this.computeLayoutRadius(width ? width : 0, height ? height : 0) * r * (vutils.isNil(k) ? 1 : k);
2979
+ }
2980
+ computeLayoutRadius(width, height) {
2981
+ return Math.min(width / 2, height / 2);
2982
+ }
2983
+ computeLayoutOuterRadius(r, width, height) {
2984
+ return r / (Math.min(width, height) / 2);
2985
+ }
2986
+ computeDatumRadius(width, height, outerRadius) {
2987
+ const outerRadiusRatio = this.computeLayoutOuterRadius(outerRadius, width, height);
2988
+ return this.computeLayoutRadius(width ? width : 0, height ? height : 0) * outerRadiusRatio;
2989
+ }
2990
+ }
2991
+
2143
2992
  const labelComponentMap = {
2144
2993
  rect: RectLabel,
2145
- symbol: SymbolLabel
2994
+ symbol: SymbolLabel,
2995
+ arc: ArcLabel
2146
2996
  };
2147
2997
  class DataLabel extends AbstractComponent {
2148
2998
  name = 'data-label';
@@ -9532,9 +10382,11 @@
9532
10382
  }
9533
10383
  }
9534
10384
 
9535
- const version = "0.13.5-alpha.0";
10385
+ const version = "0.13.5-alpha.6";
9536
10386
 
9537
10387
  exports.AbstractComponent = AbstractComponent;
10388
+ exports.ArcInfo = ArcInfo;
10389
+ exports.ArcLabel = ArcLabel;
9538
10390
  exports.BasePlayer = BasePlayer;
9539
10391
  exports.Brush = Brush;
9540
10392
  exports.CircleAxis = CircleAxis;