@primeui/chart-core 0.0.1-alpha.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +23 -0
- package/README.md +1 -0
- package/dist/animations/index.d.mts +136 -0
- package/dist/animations/index.mjs +18 -0
- package/dist/annotation.utils-Bm0lOO1o.d.mts +290 -0
- package/dist/borderRadius.utils-Cz73LLR_.d.mts +54 -0
- package/dist/canvas-D4vigq47.d.mts +34 -0
- package/dist/canvas.utils-D2WHi2gL.d.mts +167 -0
- package/dist/cartesian/index.d.mts +94 -0
- package/dist/cartesian/index.mjs +93 -0
- package/dist/chunk-22ST6YPP.mjs +304 -0
- package/dist/chunk-2QK2KOBN.mjs +10 -0
- package/dist/chunk-2QRS4YQ5.mjs +18 -0
- package/dist/chunk-3FFJEX4A.mjs +261 -0
- package/dist/chunk-3IYSJ2U7.mjs +567 -0
- package/dist/chunk-3OZLP4I4.mjs +190 -0
- package/dist/chunk-3WEMHXZI.mjs +198 -0
- package/dist/chunk-3Z62EUJN.mjs +138 -0
- package/dist/chunk-4C6EVJ54.mjs +362 -0
- package/dist/chunk-53HW45JB.mjs +102 -0
- package/dist/chunk-55Y3WI6S.mjs +186 -0
- package/dist/chunk-5JCI2DEB.mjs +97 -0
- package/dist/chunk-66T4MRC5.mjs +113 -0
- package/dist/chunk-6HSEJLSR.mjs +376 -0
- package/dist/chunk-6STOLMCA.mjs +187 -0
- package/dist/chunk-7CMVDIOU.mjs +54 -0
- package/dist/chunk-7QQ6ETB4.mjs +228 -0
- package/dist/chunk-A6ZQZFL2.mjs +272 -0
- package/dist/chunk-ADKLH73T.mjs +1 -0
- package/dist/chunk-AGU3NG6D.mjs +22 -0
- package/dist/chunk-AHYIS6EB.mjs +230 -0
- package/dist/chunk-AP3UYWYT.mjs +4 -0
- package/dist/chunk-ARB5T6MP.mjs +326 -0
- package/dist/chunk-ARRGOEFX.mjs +585 -0
- package/dist/chunk-AUF4CHDP.mjs +422 -0
- package/dist/chunk-B4FTADAZ.mjs +561 -0
- package/dist/chunk-BABQKA6K.mjs +339 -0
- package/dist/chunk-BETFQBM2.mjs +197 -0
- package/dist/chunk-BKP26M4K.mjs +413 -0
- package/dist/chunk-BZN2QHGP.mjs +200 -0
- package/dist/chunk-C36VWQ7A.mjs +86 -0
- package/dist/chunk-CHW4RKY3.mjs +16 -0
- package/dist/chunk-CINXJIRR.mjs +120 -0
- package/dist/chunk-DN6AXQYZ.mjs +667 -0
- package/dist/chunk-DP2IZNN3.mjs +92 -0
- package/dist/chunk-DTWTCFRG.mjs +119 -0
- package/dist/chunk-EAMUNLRU.mjs +172 -0
- package/dist/chunk-EDAKJLNA.mjs +17 -0
- package/dist/chunk-ERVQB2VZ.mjs +59 -0
- package/dist/chunk-FFMT6OCO.mjs +92 -0
- package/dist/chunk-FHTC2YDB.mjs +102 -0
- package/dist/chunk-FRST55HY.mjs +16 -0
- package/dist/chunk-HDFGCN2F.mjs +132 -0
- package/dist/chunk-IEGLX7VL.mjs +42 -0
- package/dist/chunk-ILUWFYGY.mjs +220 -0
- package/dist/chunk-IXOWSEHO.mjs +114 -0
- package/dist/chunk-J4RI2C2G.mjs +172 -0
- package/dist/chunk-J65DBT4R.mjs +13 -0
- package/dist/chunk-JGOVWSKH.mjs +179 -0
- package/dist/chunk-JO7VACY2.mjs +25 -0
- package/dist/chunk-JWFBOPM6.mjs +122 -0
- package/dist/chunk-KNDZP446.mjs +895 -0
- package/dist/chunk-KP2TWD4Z.mjs +90 -0
- package/dist/chunk-KQIFO5I3.mjs +225 -0
- package/dist/chunk-KVDEROP6.mjs +59 -0
- package/dist/chunk-LKC7MZKK.mjs +87 -0
- package/dist/chunk-LVMDQ4OJ.mjs +305 -0
- package/dist/chunk-M7B3JF43.mjs +90 -0
- package/dist/chunk-MTGMXRNF.mjs +136 -0
- package/dist/chunk-N3TIT3OH.mjs +1040 -0
- package/dist/chunk-NHRK5KU2.mjs +890 -0
- package/dist/chunk-NKUYIWAP.mjs +243 -0
- package/dist/chunk-NPDZLYIF.mjs +238 -0
- package/dist/chunk-O2X6FF45.mjs +499 -0
- package/dist/chunk-OGJ6IIBW.mjs +176 -0
- package/dist/chunk-OHGCZZPZ.mjs +403 -0
- package/dist/chunk-OWW3K55O.mjs +351 -0
- package/dist/chunk-OXTFAWSK.mjs +60 -0
- package/dist/chunk-PLSDU3C2.mjs +890 -0
- package/dist/chunk-PRDVPOZX.mjs +223 -0
- package/dist/chunk-Q6PPVIHU.mjs +21 -0
- package/dist/chunk-QQBXUDM4.mjs +885 -0
- package/dist/chunk-QS76E3TD.mjs +111 -0
- package/dist/chunk-QWQ6HY4I.mjs +209 -0
- package/dist/chunk-R6Y3R7EW.mjs +135 -0
- package/dist/chunk-RBLZRT5K.mjs +190 -0
- package/dist/chunk-RO4N6YFS.mjs +167 -0
- package/dist/chunk-RQ3CKQOX.mjs +984 -0
- package/dist/chunk-SALTGZFR.mjs +208 -0
- package/dist/chunk-SANZPAJ4.mjs +14 -0
- package/dist/chunk-SDBPQ5CF.mjs +624 -0
- package/dist/chunk-SSLTFJ3U.mjs +364 -0
- package/dist/chunk-SXHVDJGF.mjs +77 -0
- package/dist/chunk-TA4MVAEX.mjs +243 -0
- package/dist/chunk-TAHCOZHF.mjs +1772 -0
- package/dist/chunk-TQ6S34QZ.mjs +152 -0
- package/dist/chunk-UPRXABX5.mjs +90 -0
- package/dist/chunk-VGLSBZDN.mjs +71 -0
- package/dist/chunk-VN7CKCSE.mjs +364 -0
- package/dist/chunk-VVI3OBPJ.mjs +524 -0
- package/dist/chunk-VWF57TS3.mjs +62 -0
- package/dist/chunk-WA3OVISZ.mjs +179 -0
- package/dist/chunk-WCG35U6M.mjs +964 -0
- package/dist/chunk-WFTX4AQJ.mjs +194 -0
- package/dist/chunk-WFVOQ2QZ.mjs +18 -0
- package/dist/chunk-WH3C3Y7P.mjs +149 -0
- package/dist/chunk-WPFUV7K3.mjs +488 -0
- package/dist/chunk-WRULPWHD.mjs +492 -0
- package/dist/chunk-WS64BZXT.mjs +1 -0
- package/dist/chunk-WY4AURRE.mjs +2419 -0
- package/dist/chunk-WYLILAOO.mjs +167 -0
- package/dist/chunk-X4D7FKUS.mjs +62 -0
- package/dist/chunk-X7T34OLW.mjs +139 -0
- package/dist/chunk-XIHBK5D3.mjs +68 -0
- package/dist/chunk-XQQCGFYB.mjs +50 -0
- package/dist/chunk-XTVE4P3L.mjs +214 -0
- package/dist/chunk-XUAASRXW.mjs +579 -0
- package/dist/chunk-Y3L3D4GQ.mjs +685 -0
- package/dist/chunk-YBJ56XJS.mjs +132 -0
- package/dist/chunk-ZQFK6CAE.mjs +1 -0
- package/dist/chunk-ZT2Z7ERM.mjs +874 -0
- package/dist/chunk-ZTL2FQEW.mjs +714 -0
- package/dist/circular/arc/index.d.mts +8 -0
- package/dist/circular/arc/index.mjs +3 -0
- package/dist/circular/index.d.mts +44 -0
- package/dist/circular/index.mjs +13 -0
- package/dist/collect.utils-DiKB4ciO.d.mts +12 -0
- package/dist/computeChartState-BTVIqwyO.d.mts +304 -0
- package/dist/controller-BJE1AZ3q.d.mts +82 -0
- package/dist/controller-BoNigQJr.d.mts +63 -0
- package/dist/controllers/index.d.mts +16 -0
- package/dist/controllers/index.mjs +110 -0
- package/dist/datalabel.utils-CkjGeB8S.d.mts +122 -0
- package/dist/decimation.utils-CcvJVhI4.d.mts +244 -0
- package/dist/geometry-DUUQJXVM.d.mts +60 -0
- package/dist/index-DseIZa1j.d.mts +167 -0
- package/dist/index.d.mts +88 -0
- package/dist/index.mjs +110 -0
- package/dist/orchestrator/index.d.mts +264 -0
- package/dist/orchestrator/index.mjs +33 -0
- package/dist/plugins/index.d.mts +18 -0
- package/dist/plugins/index.mjs +1 -0
- package/dist/property-animations-D433wXzz.d.mts +580 -0
- package/dist/property-store-NORUWFND.d.mts +17 -0
- package/dist/radial/index.d.mts +14 -0
- package/dist/radial/index.mjs +37 -0
- package/dist/renderers/axis/index.d.mts +39 -0
- package/dist/renderers/axis/index.mjs +8 -0
- package/dist/renderers/circular/index.d.mts +13 -0
- package/dist/renderers/circular/index.mjs +13 -0
- package/dist/renderers/index.d.mts +83 -0
- package/dist/renderers/index.mjs +75 -0
- package/dist/renderers/navigator/index.d.mts +103 -0
- package/dist/renderers/navigator/index.mjs +8 -0
- package/dist/resize.utils-D_2qm6rv.d.mts +142 -0
- package/dist/ring.utils-DXvrxMkU.d.mts +138 -0
- package/dist/scale-KFv30jqZ.d.mts +307 -0
- package/dist/scales-Drf8AIhL.d.mts +75 -0
- package/dist/series/bar/canvas/index.d.mts +8 -0
- package/dist/series/bar/canvas/index.mjs +10 -0
- package/dist/series/bar/controller/index.d.mts +105 -0
- package/dist/series/bar/controller/index.mjs +44 -0
- package/dist/series/bar/controller-canvas/index.d.mts +7 -0
- package/dist/series/bar/controller-canvas/index.mjs +49 -0
- package/dist/series/bar/controller-svg/index.d.mts +7 -0
- package/dist/series/bar/controller-svg/index.mjs +49 -0
- package/dist/series/bar/index.d.mts +60 -0
- package/dist/series/bar/index.mjs +13 -0
- package/dist/series/bar/svg/index.d.mts +8 -0
- package/dist/series/bar/svg/index.mjs +11 -0
- package/dist/series/candlestick/canvas/index.d.mts +8 -0
- package/dist/series/candlestick/canvas/index.mjs +8 -0
- package/dist/series/candlestick/controller/index.d.mts +123 -0
- package/dist/series/candlestick/controller/index.mjs +40 -0
- package/dist/series/candlestick/controller-canvas/index.d.mts +7 -0
- package/dist/series/candlestick/controller-canvas/index.mjs +45 -0
- package/dist/series/candlestick/controller-svg/index.d.mts +7 -0
- package/dist/series/candlestick/controller-svg/index.mjs +45 -0
- package/dist/series/candlestick/index.d.mts +11 -0
- package/dist/series/candlestick/index.mjs +10 -0
- package/dist/series/candlestick/svg/index.d.mts +8 -0
- package/dist/series/candlestick/svg/index.mjs +8 -0
- package/dist/series/heatmap/canvas/index.d.mts +16 -0
- package/dist/series/heatmap/canvas/index.mjs +9 -0
- package/dist/series/heatmap/controller/index.d.mts +110 -0
- package/dist/series/heatmap/controller/index.mjs +23 -0
- package/dist/series/heatmap/controller-canvas/index.d.mts +7 -0
- package/dist/series/heatmap/controller-canvas/index.mjs +28 -0
- package/dist/series/heatmap/controller-svg/index.d.mts +7 -0
- package/dist/series/heatmap/controller-svg/index.mjs +28 -0
- package/dist/series/heatmap/index.d.mts +34 -0
- package/dist/series/heatmap/index.mjs +13 -0
- package/dist/series/heatmap/svg/index.d.mts +15 -0
- package/dist/series/heatmap/svg/index.mjs +10 -0
- package/dist/series/line/canvas/index.d.mts +6 -0
- package/dist/series/line/canvas/index.mjs +9 -0
- package/dist/series/line/controller/index.d.mts +111 -0
- package/dist/series/line/controller/index.mjs +47 -0
- package/dist/series/line/controller-canvas/index.d.mts +7 -0
- package/dist/series/line/controller-canvas/index.mjs +54 -0
- package/dist/series/line/controller-svg/index.d.mts +7 -0
- package/dist/series/line/controller-svg/index.mjs +54 -0
- package/dist/series/line/index.d.mts +49 -0
- package/dist/series/line/index.mjs +13 -0
- package/dist/series/line/svg/index.d.mts +6 -0
- package/dist/series/line/svg/index.mjs +9 -0
- package/dist/series/pie/canvas/index.d.mts +8 -0
- package/dist/series/pie/canvas/index.mjs +10 -0
- package/dist/series/pie/controller/index.d.mts +174 -0
- package/dist/series/pie/controller/index.mjs +110 -0
- package/dist/series/pie/controller-canvas/index.d.mts +8 -0
- package/dist/series/pie/controller-canvas/index.mjs +119 -0
- package/dist/series/pie/controller-svg/index.d.mts +8 -0
- package/dist/series/pie/controller-svg/index.mjs +118 -0
- package/dist/series/pie/index.d.mts +59 -0
- package/dist/series/pie/index.mjs +15 -0
- package/dist/series/pie/svg/index.d.mts +6 -0
- package/dist/series/pie/svg/index.mjs +11 -0
- package/dist/series/polar/canvas/index.d.mts +6 -0
- package/dist/series/polar/canvas/index.mjs +7 -0
- package/dist/series/polar/controller/index.d.mts +102 -0
- package/dist/series/polar/controller/index.mjs +46 -0
- package/dist/series/polar/controller-canvas/index.d.mts +8 -0
- package/dist/series/polar/controller-canvas/index.mjs +52 -0
- package/dist/series/polar/controller-svg/index.d.mts +8 -0
- package/dist/series/polar/controller-svg/index.mjs +52 -0
- package/dist/series/polar/index.d.mts +25 -0
- package/dist/series/polar/index.mjs +16 -0
- package/dist/series/polar/svg/index.d.mts +10 -0
- package/dist/series/polar/svg/index.mjs +8 -0
- package/dist/series/radar/canvas/index.d.mts +6 -0
- package/dist/series/radar/canvas/index.mjs +8 -0
- package/dist/series/radar/controller/index.d.mts +121 -0
- package/dist/series/radar/controller/index.mjs +43 -0
- package/dist/series/radar/controller-canvas/index.d.mts +8 -0
- package/dist/series/radar/controller-canvas/index.mjs +51 -0
- package/dist/series/radar/controller-svg/index.d.mts +8 -0
- package/dist/series/radar/controller-svg/index.mjs +51 -0
- package/dist/series/radar/index.d.mts +40 -0
- package/dist/series/radar/index.mjs +13 -0
- package/dist/series/radar/svg/index.d.mts +12 -0
- package/dist/series/radar/svg/index.mjs +9 -0
- package/dist/series/scatter/canvas/index.d.mts +8 -0
- package/dist/series/scatter/canvas/index.mjs +11 -0
- package/dist/series/scatter/controller/index.d.mts +124 -0
- package/dist/series/scatter/controller/index.mjs +44 -0
- package/dist/series/scatter/controller-canvas/index.d.mts +7 -0
- package/dist/series/scatter/controller-canvas/index.mjs +51 -0
- package/dist/series/scatter/controller-svg/index.d.mts +7 -0
- package/dist/series/scatter/controller-svg/index.mjs +51 -0
- package/dist/series/scatter/index.d.mts +25 -0
- package/dist/series/scatter/index.mjs +14 -0
- package/dist/series/scatter/svg/index.d.mts +8 -0
- package/dist/series/scatter/svg/index.mjs +12 -0
- package/dist/series/treemap/canvas/index.d.mts +50 -0
- package/dist/series/treemap/canvas/index.mjs +10 -0
- package/dist/series/treemap/controller/index.d.mts +130 -0
- package/dist/series/treemap/controller/index.mjs +20 -0
- package/dist/series/treemap/controller-canvas/index.d.mts +7 -0
- package/dist/series/treemap/controller-canvas/index.mjs +25 -0
- package/dist/series/treemap/controller-svg/index.d.mts +7 -0
- package/dist/series/treemap/controller-svg/index.mjs +25 -0
- package/dist/series/treemap/index.d.mts +15 -0
- package/dist/series/treemap/index.mjs +12 -0
- package/dist/series/treemap/svg/index.d.mts +15 -0
- package/dist/series/treemap/svg/index.mjs +9 -0
- package/dist/slices-DtewiwJx.d.mts +72 -0
- package/dist/spatialIndex.utils-B_GJkotZ.d.mts +5 -0
- package/dist/squarify.utils-B9CQBpa1.d.mts +50 -0
- package/dist/stacking-CChuAcLN.d.mts +319 -0
- package/dist/streaming.utils-DH-g1gNP.d.mts +49 -0
- package/dist/sync/index.d.mts +130 -0
- package/dist/sync/index.mjs +5 -0
- package/dist/tooltip.renderer-D5wpSlBa.d.mts +210 -0
- package/dist/utils/color/index.d.mts +58 -0
- package/dist/utils/color/index.mjs +4 -0
- package/dist/utils/data/index.d.mts +180 -0
- package/dist/utils/data/index.mjs +7 -0
- package/dist/utils/export/index.d.mts +14 -0
- package/dist/utils/export/index.mjs +6 -0
- package/dist/utils/index.d.mts +49 -0
- package/dist/utils/index.mjs +29 -0
- package/dist/utils/interaction/index.d.mts +255 -0
- package/dist/utils/interaction/index.mjs +9 -0
- package/dist/utils/layout/index.d.mts +3 -0
- package/dist/utils/layout/index.mjs +10 -0
- package/dist/utils/math/index.d.mts +162 -0
- package/dist/utils/math/index.mjs +1 -0
- package/dist/utils/render/index.d.mts +19 -0
- package/dist/utils/render/index.mjs +3 -0
- package/dist/utils/specialized/index.d.mts +37 -0
- package/dist/utils/specialized/index.mjs +66 -0
- package/dist/utils/text/index.d.mts +39 -0
- package/dist/utils/text/index.mjs +8 -0
- package/dist/utils/theme/index.d.mts +295 -0
- package/dist/utils/theme/index.mjs +5 -0
- package/dist/utils/zoom/index.d.mts +90 -0
- package/dist/utils/zoom/index.mjs +3 -0
- package/package.json +56 -0
|
@@ -0,0 +1,362 @@
|
|
|
1
|
+
import { formatDataLabelText } from './chunk-OXTFAWSK.mjs';
|
|
2
|
+
import { wrapText, calculateWrappedTextWidth, calculateWrappedTextHeight } from './chunk-XTVE4P3L.mjs';
|
|
3
|
+
import { DEFAULT_FALLBACK_COLOR } from './chunk-NKUYIWAP.mjs';
|
|
4
|
+
import { makeItemContext, resolveAccessor } from './chunk-O2X6FF45.mjs';
|
|
5
|
+
import { withCanvasState } from './chunk-SSLTFJ3U.mjs';
|
|
6
|
+
import { toRad, pointOnCircle } from './chunk-RQ3CKQOX.mjs';
|
|
7
|
+
|
|
8
|
+
// src/circular/radial.helpers.ts
|
|
9
|
+
function computeSliceGeometry(slice, currentAngle, frame) {
|
|
10
|
+
const { outerRadius, innerRadius, willBeSingleSlice, currentRingRadii, hoverState, hoverOffset, hoverScale } = frame;
|
|
11
|
+
const ringRadii = currentRingRadii.get(String(slice.datasetIndex));
|
|
12
|
+
const baseOuterRadius = ringRadii?.outer ?? outerRadius;
|
|
13
|
+
const sliceInnerRadius = ringRadii?.inner ?? innerRadius;
|
|
14
|
+
const sliceOuterRadius = sliceInnerRadius + (baseOuterRadius - sliceInnerRadius) * slice.radiusRatio;
|
|
15
|
+
const spacing = slice.spacing ?? 0;
|
|
16
|
+
const spacingAngle = spacing > 0 && sliceOuterRadius > 0 ? spacing / sliceOuterRadius * (180 / Math.PI) : 0;
|
|
17
|
+
const halfSpacing = spacingAngle / 2;
|
|
18
|
+
const angle = slice.endAngle - slice.rotation;
|
|
19
|
+
const isFullCircleSlice = willBeSingleSlice || slice.targetAngle >= 355 || angle >= 355;
|
|
20
|
+
const midAngle = currentAngle + angle / 2;
|
|
21
|
+
const midRadius = (sliceOuterRadius + sliceInnerRadius) / 2;
|
|
22
|
+
const isHovered = hoverState.datasetIndex === slice.datasetIndex && hoverState.index === slice.originalIndex;
|
|
23
|
+
const sliceHoverOffset = isHovered && !isFullCircleSlice ? hoverOffset : 0;
|
|
24
|
+
const hoverOffsetX = sliceHoverOffset > 0 ? Math.cos(toRad(midAngle)) * sliceHoverOffset : 0;
|
|
25
|
+
const hoverOffsetY = sliceHoverOffset > 0 ? Math.sin(toRad(midAngle)) * sliceHoverOffset : 0;
|
|
26
|
+
const baseOffset = slice.baseOffset ?? 0;
|
|
27
|
+
const baseOffsetX = baseOffset !== 0 ? Math.cos(toRad(midAngle)) * baseOffset : 0;
|
|
28
|
+
const baseOffsetY = baseOffset !== 0 ? Math.sin(toRad(midAngle)) * baseOffset : 0;
|
|
29
|
+
const scale = isHovered && !isFullCircleSlice && hoverScale > 1 ? hoverScale : 1;
|
|
30
|
+
return {
|
|
31
|
+
sliceOuterRadius,
|
|
32
|
+
sliceInnerRadius,
|
|
33
|
+
isFullCircleSlice,
|
|
34
|
+
midAngle,
|
|
35
|
+
midRadius,
|
|
36
|
+
isHovered,
|
|
37
|
+
offsetX: hoverOffsetX + baseOffsetX,
|
|
38
|
+
offsetY: hoverOffsetY + baseOffsetY,
|
|
39
|
+
scale,
|
|
40
|
+
renderRotation: isFullCircleSlice ? currentAngle : currentAngle + halfSpacing,
|
|
41
|
+
renderAngle: isFullCircleSlice ? angle : Math.max(0, angle - spacingAngle)
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// src/circular/label.utils.ts
|
|
46
|
+
function getLabelSide(angle) {
|
|
47
|
+
const normalized = (angle % 360 + 360) % 360;
|
|
48
|
+
return Math.cos(toRad(normalized)) >= 0 ? "right" : "left";
|
|
49
|
+
}
|
|
50
|
+
function drawCanvasLeaderLine(ctx, layout, centerX, centerY, strokeColor, strokeWidth) {
|
|
51
|
+
const { leaderLine } = layout;
|
|
52
|
+
ctx.beginPath();
|
|
53
|
+
ctx.moveTo(centerX + leaderLine.x1, centerY + leaderLine.y1);
|
|
54
|
+
ctx.lineTo(centerX + leaderLine.x2, centerY + leaderLine.y2);
|
|
55
|
+
ctx.lineTo(centerX + leaderLine.x3, centerY + leaderLine.y3);
|
|
56
|
+
ctx.strokeStyle = strokeColor;
|
|
57
|
+
ctx.lineWidth = strokeWidth;
|
|
58
|
+
ctx.stroke();
|
|
59
|
+
}
|
|
60
|
+
function drawCanvasStraightLeaderLine(ctx, layout, centerX, centerY, strokeColor, strokeWidth) {
|
|
61
|
+
const { leaderLine } = layout;
|
|
62
|
+
ctx.beginPath();
|
|
63
|
+
ctx.moveTo(centerX + leaderLine.x1, centerY + leaderLine.y1);
|
|
64
|
+
ctx.lineTo(centerX + leaderLine.x3, centerY + leaderLine.y3);
|
|
65
|
+
ctx.strokeStyle = strokeColor;
|
|
66
|
+
ctx.lineWidth = strokeWidth;
|
|
67
|
+
ctx.stroke();
|
|
68
|
+
}
|
|
69
|
+
function drawCanvasLabelLines(ctx, layout, centerX, centerY, textColor, options) {
|
|
70
|
+
const { lines, side, x, y } = layout;
|
|
71
|
+
const textX = options.centered ? centerX + x : centerX + x + (side === "right" ? options.textOffset : -options.textOffset);
|
|
72
|
+
const textY = centerY + y;
|
|
73
|
+
const lineHeight = options.fontSize * options.lineHeight;
|
|
74
|
+
const totalHeight = lines.length * lineHeight;
|
|
75
|
+
const startY = textY - totalHeight / 2 + lineHeight / 2;
|
|
76
|
+
withCanvasState(ctx, () => {
|
|
77
|
+
ctx.font = `${options.fontWeight} ${options.fontSize}px ${options.fontFamily}`;
|
|
78
|
+
ctx.fillStyle = textColor;
|
|
79
|
+
ctx.textAlign = options.centered ? "center" : side === "right" ? "left" : "right";
|
|
80
|
+
ctx.textBaseline = "middle";
|
|
81
|
+
for (let i = 0; i < lines.length; i++) {
|
|
82
|
+
ctx.fillText(lines[i], textX, startY + i * lineHeight);
|
|
83
|
+
}
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// src/circular/labelLayout.utils.ts
|
|
88
|
+
var DEFAULT_LABEL_LAYOUT_OPTIONS = {
|
|
89
|
+
fontSize: 12,
|
|
90
|
+
fontWeight: "normal",
|
|
91
|
+
fontFamily: "Arial",
|
|
92
|
+
leaderOffset: 10,
|
|
93
|
+
horizontalOffset: 15,
|
|
94
|
+
textOffset: 4,
|
|
95
|
+
lineHeight: 1.2,
|
|
96
|
+
minRadius: 50,
|
|
97
|
+
alignTo: "labelLine",
|
|
98
|
+
lineStyle: "angled"
|
|
99
|
+
};
|
|
100
|
+
var radialOffset = (radius, angleDeg) => pointOnCircle(0, 0, angleDeg, radius);
|
|
101
|
+
function getAvailableLabelWidth(side, bounds, radius, options) {
|
|
102
|
+
const leaderLength = options.leaderOffset + options.horizontalOffset + options.textOffset;
|
|
103
|
+
if (side === "right") {
|
|
104
|
+
return bounds.right - bounds.centerX - radius - leaderLength;
|
|
105
|
+
}
|
|
106
|
+
return bounds.centerX - radius - leaderLength - bounds.left;
|
|
107
|
+
}
|
|
108
|
+
function createLabelLayoutItem(config, radius, bounds, maxWidth, options) {
|
|
109
|
+
const side = getLabelSide(config.angle);
|
|
110
|
+
const fontSize = config.fontSize ?? options.fontSize;
|
|
111
|
+
const lines = wrapText(config.text, maxWidth, fontSize, options.fontFamily, options.fontWeight);
|
|
112
|
+
const innerR = options.innerRadius ?? 0;
|
|
113
|
+
const sliceRadius = innerR + (radius - innerR) * (config.radiusRatio ?? 1);
|
|
114
|
+
const pieEdge = radialOffset(sliceRadius, config.angle);
|
|
115
|
+
const horizontalDir = side === "right" ? 1 : -1;
|
|
116
|
+
const textWidth = calculateWrappedTextWidth(lines, fontSize, options.fontFamily, options.fontWeight);
|
|
117
|
+
const textHeight = calculateWrappedTextHeight(lines, fontSize, options.lineHeight);
|
|
118
|
+
let elbow;
|
|
119
|
+
let textAnchor;
|
|
120
|
+
if (options.lineStyle === "none") {
|
|
121
|
+
const totalOffset = options.leaderOffset + options.horizontalOffset + options.textOffset;
|
|
122
|
+
const pos = radialOffset(radius + totalOffset, config.angle);
|
|
123
|
+
const absoluteX2 = bounds.centerX + pos.x - textWidth / 2;
|
|
124
|
+
const absoluteY2 = bounds.centerY + pos.y - textHeight / 2;
|
|
125
|
+
return {
|
|
126
|
+
text: config.text,
|
|
127
|
+
lines,
|
|
128
|
+
angle: config.angle,
|
|
129
|
+
side,
|
|
130
|
+
x: pos.x,
|
|
131
|
+
y: pos.y,
|
|
132
|
+
boundingBox: { x: absoluteX2, y: absoluteY2, width: textWidth, height: textHeight },
|
|
133
|
+
leaderLine: { x1: pieEdge.x, y1: pieEdge.y, x2: pos.x, y2: pos.y, x3: pos.x, y3: pos.y },
|
|
134
|
+
index: config.index,
|
|
135
|
+
value: config.value,
|
|
136
|
+
percentage: config.percentage,
|
|
137
|
+
color: config.color,
|
|
138
|
+
fontSize: config.fontSize,
|
|
139
|
+
textColor: config.textColor,
|
|
140
|
+
connectorColor: config.connectorColor,
|
|
141
|
+
connectorWidth: config.connectorWidth
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
if (options.lineStyle === "straight") {
|
|
145
|
+
const lineEnd = pieEdge.x + horizontalDir * (options.leaderOffset + options.horizontalOffset);
|
|
146
|
+
elbow = { x: pieEdge.x, y: pieEdge.y };
|
|
147
|
+
textAnchor = { x: lineEnd, y: pieEdge.y };
|
|
148
|
+
} else if (options.alignTo === "edge") {
|
|
149
|
+
elbow = radialOffset(radius + options.leaderOffset, config.angle);
|
|
150
|
+
const edgeX = side === "right" ? bounds.right - bounds.centerX - options.textOffset - textWidth : bounds.left - bounds.centerX + options.textOffset + textWidth;
|
|
151
|
+
textAnchor = { x: edgeX, y: elbow.y };
|
|
152
|
+
} else {
|
|
153
|
+
elbow = radialOffset(radius + options.leaderOffset, config.angle);
|
|
154
|
+
textAnchor = {
|
|
155
|
+
x: elbow.x + horizontalDir * options.horizontalOffset,
|
|
156
|
+
y: elbow.y
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
const absoluteX = bounds.centerX + textAnchor.x + (side === "right" ? options.textOffset : -options.textOffset - textWidth);
|
|
160
|
+
const absoluteY = bounds.centerY + textAnchor.y - textHeight / 2;
|
|
161
|
+
return {
|
|
162
|
+
text: config.text,
|
|
163
|
+
lines,
|
|
164
|
+
angle: config.angle,
|
|
165
|
+
side,
|
|
166
|
+
x: textAnchor.x,
|
|
167
|
+
y: textAnchor.y,
|
|
168
|
+
boundingBox: {
|
|
169
|
+
x: absoluteX,
|
|
170
|
+
y: absoluteY,
|
|
171
|
+
width: textWidth,
|
|
172
|
+
height: textHeight
|
|
173
|
+
},
|
|
174
|
+
leaderLine: {
|
|
175
|
+
x1: pieEdge.x,
|
|
176
|
+
y1: pieEdge.y,
|
|
177
|
+
x2: elbow.x,
|
|
178
|
+
y2: elbow.y,
|
|
179
|
+
x3: textAnchor.x,
|
|
180
|
+
y3: textAnchor.y
|
|
181
|
+
},
|
|
182
|
+
// Include original data for custom rendering
|
|
183
|
+
index: config.index,
|
|
184
|
+
value: config.value,
|
|
185
|
+
percentage: config.percentage,
|
|
186
|
+
color: config.color,
|
|
187
|
+
fontSize: config.fontSize,
|
|
188
|
+
textColor: config.textColor,
|
|
189
|
+
connectorColor: config.connectorColor,
|
|
190
|
+
connectorWidth: config.connectorWidth
|
|
191
|
+
};
|
|
192
|
+
}
|
|
193
|
+
function createLabelsAtRadius(labelConfigs, radius, bounds, opts) {
|
|
194
|
+
const availableWidthRight = getAvailableLabelWidth("right", bounds, radius, opts);
|
|
195
|
+
const availableWidthLeft = getAvailableLabelWidth("left", bounds, radius, opts);
|
|
196
|
+
return labelConfigs.map((config) => {
|
|
197
|
+
const side = getLabelSide(config.angle);
|
|
198
|
+
const maxWidth = side === "right" ? availableWidthRight : availableWidthLeft;
|
|
199
|
+
return createLabelLayoutItem(config, radius, bounds, Math.max(maxWidth, 30), opts);
|
|
200
|
+
});
|
|
201
|
+
}
|
|
202
|
+
function buildResult(labels, radius) {
|
|
203
|
+
const leftLabels = labels.filter((l) => l.side === "left");
|
|
204
|
+
const rightLabels = labels.filter((l) => l.side === "right");
|
|
205
|
+
return {
|
|
206
|
+
labels,
|
|
207
|
+
radius,
|
|
208
|
+
maxLabelWidthLeft: leftLabels.length > 0 ? Math.max(...leftLabels.map((l) => l.boundingBox.width)) : 0,
|
|
209
|
+
maxLabelWidthRight: rightLabels.length > 0 ? Math.max(...rightLabels.map((l) => l.boundingBox.width)) : 0
|
|
210
|
+
};
|
|
211
|
+
}
|
|
212
|
+
function computeLabelAwareRadius(labelConfigs, initialRadius, bounds, options = {}) {
|
|
213
|
+
if (labelConfigs.length === 0) return initialRadius;
|
|
214
|
+
const opts = { ...DEFAULT_LABEL_LAYOUT_OPTIONS, ...options };
|
|
215
|
+
const chartWidth = bounds.right - bounds.left;
|
|
216
|
+
const chartHeight = bounds.bottom - bounds.top;
|
|
217
|
+
const minChartDim = Math.min(chartWidth, chartHeight);
|
|
218
|
+
const scale = Math.min(1, minChartDim / 300);
|
|
219
|
+
const halfWidth = Math.min(bounds.centerX - bounds.left, bounds.right - bounds.centerX);
|
|
220
|
+
const halfHeight = Math.min(bounds.centerY - bounds.top, bounds.bottom - bounds.centerY);
|
|
221
|
+
if (opts.lineStyle === "none") {
|
|
222
|
+
const totalOffset = opts.leaderOffset * scale + opts.horizontalOffset * scale + opts.textOffset;
|
|
223
|
+
let maxTextWidth2 = 0;
|
|
224
|
+
let maxTextHeight = 0;
|
|
225
|
+
for (const config of labelConfigs) {
|
|
226
|
+
const fontSize = config.fontSize ?? opts.fontSize;
|
|
227
|
+
const lines = wrapText(config.text, halfWidth, fontSize, opts.fontFamily, opts.fontWeight);
|
|
228
|
+
maxTextWidth2 = Math.max(maxTextWidth2, calculateWrappedTextWidth(lines, fontSize, opts.fontFamily, opts.fontWeight));
|
|
229
|
+
maxTextHeight = Math.max(maxTextHeight, calculateWrappedTextHeight(lines, fontSize, opts.lineHeight));
|
|
230
|
+
}
|
|
231
|
+
const maxRadiusH = halfWidth - totalOffset - maxTextWidth2 / 2;
|
|
232
|
+
const maxRadiusV = halfHeight - totalOffset - maxTextHeight / 2;
|
|
233
|
+
return Math.max(Math.min(initialRadius, maxRadiusH, maxRadiusV), opts.minRadius);
|
|
234
|
+
}
|
|
235
|
+
const leaderLength = opts.leaderOffset * scale + opts.horizontalOffset * scale + opts.textOffset;
|
|
236
|
+
let maxTextWidth = 0;
|
|
237
|
+
for (const config of labelConfigs) {
|
|
238
|
+
const fontSize = config.fontSize ?? opts.fontSize;
|
|
239
|
+
const lines = wrapText(config.text, halfWidth, fontSize, opts.fontFamily, opts.fontWeight);
|
|
240
|
+
const w = calculateWrappedTextWidth(lines, fontSize, opts.fontFamily, opts.fontWeight);
|
|
241
|
+
maxTextWidth = Math.max(maxTextWidth, w);
|
|
242
|
+
}
|
|
243
|
+
const margin = 4;
|
|
244
|
+
const maxAllowableRadius = halfWidth - leaderLength - maxTextWidth - margin;
|
|
245
|
+
return Math.max(Math.min(initialRadius, maxAllowableRadius), opts.minRadius);
|
|
246
|
+
}
|
|
247
|
+
function calculateLabelLayout(labelConfigs, initialRadius, bounds, options = {}) {
|
|
248
|
+
const opts = { ...DEFAULT_LABEL_LAYOUT_OPTIONS, ...options };
|
|
249
|
+
if (labelConfigs.length === 0) {
|
|
250
|
+
return { labels: [], radius: initialRadius, maxLabelWidthLeft: 0, maxLabelWidthRight: 0 };
|
|
251
|
+
}
|
|
252
|
+
const chartWidth = bounds.right - bounds.left;
|
|
253
|
+
const chartHeight = bounds.bottom - bounds.top;
|
|
254
|
+
const minChartDim = Math.min(chartWidth, chartHeight);
|
|
255
|
+
const scale = Math.min(1, minChartDim / 300);
|
|
256
|
+
const effectiveOpts = {
|
|
257
|
+
...opts,
|
|
258
|
+
leaderOffset: opts.leaderOffset * scale,
|
|
259
|
+
horizontalOffset: opts.horizontalOffset * scale
|
|
260
|
+
};
|
|
261
|
+
const labels = createLabelsAtRadius(labelConfigs, initialRadius, bounds, effectiveOpts);
|
|
262
|
+
if (opts.lineStyle === "angled" || opts.lineStyle === "none") {
|
|
263
|
+
const margin = 2;
|
|
264
|
+
const sides = ["left", "right"];
|
|
265
|
+
const extendByIndex = /* @__PURE__ */ new Map();
|
|
266
|
+
for (const side of sides) {
|
|
267
|
+
const sideLabels = labels.filter((l) => l.side === side).sort((a, b) => a.boundingBox.y - b.boundingBox.y);
|
|
268
|
+
for (let i = 1; i < sideLabels.length; i++) {
|
|
269
|
+
const prev = sideLabels[i - 1];
|
|
270
|
+
const curr = sideLabels[i];
|
|
271
|
+
const overlap = prev.boundingBox.y + prev.boundingBox.height + margin - curr.boundingBox.y;
|
|
272
|
+
if (overlap > 0) {
|
|
273
|
+
const target = Math.abs(curr.y) <= Math.abs(prev.y) ? curr : prev;
|
|
274
|
+
const existing = extendByIndex.get(target.index) ?? 0;
|
|
275
|
+
extendByIndex.set(target.index, Math.max(existing, overlap * 1.5));
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
if (extendByIndex.size > 0) {
|
|
280
|
+
const availableWidthRight = getAvailableLabelWidth("right", bounds, initialRadius, effectiveOpts);
|
|
281
|
+
const availableWidthLeft = getAvailableLabelWidth("left", bounds, initialRadius, effectiveOpts);
|
|
282
|
+
for (let i = 0; i < labels.length; i++) {
|
|
283
|
+
const extra = extendByIndex.get(labels[i].index);
|
|
284
|
+
if (!extra) continue;
|
|
285
|
+
const config = labelConfigs[i];
|
|
286
|
+
const side = getLabelSide(config.angle);
|
|
287
|
+
const maxW = side === "right" ? availableWidthRight : availableWidthLeft;
|
|
288
|
+
const extendedOpts = { ...effectiveOpts, horizontalOffset: effectiveOpts.horizontalOffset + extra };
|
|
289
|
+
labels[i] = createLabelLayoutItem(config, initialRadius, bounds, Math.max(maxW, 30), extendedOpts);
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
return buildResult(labels, initialRadius);
|
|
294
|
+
}
|
|
295
|
+
function boxAreaToBounds(area) {
|
|
296
|
+
return {
|
|
297
|
+
left: area.x,
|
|
298
|
+
right: area.x + area.width,
|
|
299
|
+
top: area.y,
|
|
300
|
+
bottom: area.y + area.height,
|
|
301
|
+
centerX: area.x + area.width / 2,
|
|
302
|
+
centerY: area.y + area.height / 2
|
|
303
|
+
};
|
|
304
|
+
}
|
|
305
|
+
function buildPieDataLabelLayout(frame, labelConfig, viewport, datasetPropsMap) {
|
|
306
|
+
const configs = [];
|
|
307
|
+
const labelSlices = /* @__PURE__ */ new Map();
|
|
308
|
+
for (const slice of frame.slices) {
|
|
309
|
+
const angle = slice.endAngle - slice.rotation;
|
|
310
|
+
if (angle < 0.5) continue;
|
|
311
|
+
const percentage = slice.targetPercentage;
|
|
312
|
+
if (percentage < (labelConfig.minPercentage ?? 0)) continue;
|
|
313
|
+
const datasetProps = datasetPropsMap.get(slice.datasetIndex);
|
|
314
|
+
const dataItem = datasetProps?.data?.[slice.originalIndex];
|
|
315
|
+
const labelCtx = makeItemContext(dataItem, slice.originalIndex);
|
|
316
|
+
const sliceLabel = String(resolveAccessor(datasetProps?.label, labelCtx) ?? `Item ${slice.originalIndex + 1}`);
|
|
317
|
+
const text = formatDataLabelText(slice.value, percentage, labelConfig.display, labelConfig.formatter, sliceLabel);
|
|
318
|
+
if (!text) continue;
|
|
319
|
+
const perLabelFontSize = labelConfig.fontSizeAccessor ? resolveAccessor(labelConfig.fontSizeAccessor, labelCtx, { arrayMode: "cycle" }) : void 0;
|
|
320
|
+
const perLabelColorRaw = labelConfig.colorAccessor ? resolveAccessor(labelConfig.colorAccessor, labelCtx, { arrayMode: "cycle" }) : void 0;
|
|
321
|
+
const perLabelColor = typeof perLabelColorRaw === "string" ? perLabelColorRaw : void 0;
|
|
322
|
+
const perLabelConnectorColorRaw = labelConfig.connectorColorAccessor ? resolveAccessor(labelConfig.connectorColorAccessor, labelCtx, { arrayMode: "cycle" }) : void 0;
|
|
323
|
+
const perLabelConnectorColor = typeof perLabelConnectorColorRaw === "string" ? perLabelConnectorColorRaw : void 0;
|
|
324
|
+
const perLabelConnectorWidth = labelConfig.connectorWidthAccessor ? resolveAccessor(labelConfig.connectorWidthAccessor, labelCtx, { arrayMode: "clip" }) : void 0;
|
|
325
|
+
configs.push({
|
|
326
|
+
text,
|
|
327
|
+
// Live animated midpoint — matches the drawn slice through entry/reorder animations.
|
|
328
|
+
angle: (slice.rotation + slice.endAngle) / 2,
|
|
329
|
+
index: slice.originalIndex,
|
|
330
|
+
value: slice.value,
|
|
331
|
+
percentage,
|
|
332
|
+
color: slice.color ?? DEFAULT_FALLBACK_COLOR,
|
|
333
|
+
label: sliceLabel,
|
|
334
|
+
radiusRatio: slice.radiusRatio,
|
|
335
|
+
fontSize: perLabelFontSize,
|
|
336
|
+
textColor: perLabelColor,
|
|
337
|
+
connectorColor: perLabelConnectorColor,
|
|
338
|
+
connectorWidth: perLabelConnectorWidth
|
|
339
|
+
});
|
|
340
|
+
labelSlices.set(slice.originalIndex, slice);
|
|
341
|
+
}
|
|
342
|
+
if (configs.length === 0) return null;
|
|
343
|
+
const bounds = { ...boxAreaToBounds({ x: 0, y: 0, width: viewport.width, height: viewport.height }), centerX: frame.center.x, centerY: frame.center.y };
|
|
344
|
+
const layoutOptions = {
|
|
345
|
+
fontSize: labelConfig.fontSize,
|
|
346
|
+
fontWeight: labelConfig.fontWeight,
|
|
347
|
+
fontFamily: labelConfig.fontFamily,
|
|
348
|
+
leaderOffset: labelConfig.leaderOffset,
|
|
349
|
+
horizontalOffset: labelConfig.horizontalOffset,
|
|
350
|
+
textOffset: labelConfig.textOffset,
|
|
351
|
+
lineHeight: labelConfig.lineHeight,
|
|
352
|
+
alignTo: labelConfig.alignTo,
|
|
353
|
+
lineStyle: labelConfig.lineStyle,
|
|
354
|
+
innerRadius: frame.innerRadius
|
|
355
|
+
};
|
|
356
|
+
const labelLayout = calculateLabelLayout(configs, frame.outerRadius, bounds, layoutOptions);
|
|
357
|
+
const configsByIndex = /* @__PURE__ */ new Map();
|
|
358
|
+
for (const config of configs) configsByIndex.set(config.index, config);
|
|
359
|
+
return { labelLayout, configsByIndex, labelSlices };
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
export { DEFAULT_LABEL_LAYOUT_OPTIONS, boxAreaToBounds, buildPieDataLabelLayout, calculateLabelLayout, computeLabelAwareRadius, computeSliceGeometry, drawCanvasLabelLines, drawCanvasLeaderLine, drawCanvasStraightLeaderLine, getLabelSide };
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import { computeItemHoverState, applyHoverEffects } from './chunk-BZN2QHGP.mjs';
|
|
2
|
+
import { FIELD_DEFAULTS, getDefaultColor, resolveDash, resolveAccessor, makeItemContext } from './chunk-O2X6FF45.mjs';
|
|
3
|
+
import { toRad } from './chunk-RQ3CKQOX.mjs';
|
|
4
|
+
|
|
5
|
+
// src/series/pie/shared.ts
|
|
6
|
+
function computeSliceRenderStates(props, layout, theme) {
|
|
7
|
+
const { interaction, effects } = props;
|
|
8
|
+
const { visibleSlices, center, outerRadius, innerRadius, colors, borderColors, isFullCircle: fullCircle } = layout;
|
|
9
|
+
const borderWidth = typeof props.borderStrokeWidth === "number" ? props.borderStrokeWidth : 0;
|
|
10
|
+
const dataArr = props.data ?? [];
|
|
11
|
+
const seriesExtras = { seriesIndex: props.order ?? 0, seriesId: props.id ?? "" };
|
|
12
|
+
const valueAccessor = props.valueField ?? FIELD_DEFAULTS.valueField;
|
|
13
|
+
const categoryAccessor = props.categoryField ?? props.labelField ?? FIELD_DEFAULTS.categoryField;
|
|
14
|
+
const ctxFor = (i) => {
|
|
15
|
+
const value = valueAccessor ? resolveAccessor(valueAccessor, makeItemContext(dataArr[i], i)) ?? null : null;
|
|
16
|
+
const category = categoryAccessor ? resolveAccessor(categoryAccessor, makeItemContext(dataArr[i], i)) ?? void 0 : void 0;
|
|
17
|
+
return makeItemContext(dataArr[i], i, { value, category, ...seriesExtras });
|
|
18
|
+
};
|
|
19
|
+
const resolveSliceBorderDash = (i) => resolveDash(props.borderDash, ctxFor(i));
|
|
20
|
+
const resolveSliceBorderDashOffset = (i) => resolveAccessor(props.borderDashOffset, ctxFor(i), { arrayMode: "clip", fallback: 0 }) ?? 0;
|
|
21
|
+
const resolveSliceOpacity = (i) => resolveAccessor(props.opacity, ctxFor(i), { arrayMode: "clip" });
|
|
22
|
+
const resolveSliceHoverColor = (i) => resolveAccessor(props.hoverColor, ctxFor(i), { arrayMode: "cycle" });
|
|
23
|
+
const resolveSliceHoverBorderColor = (i) => resolveAccessor(props.hoverBorderColor, ctxFor(i), { arrayMode: "cycle" });
|
|
24
|
+
const resolveSliceOffset = (i) => resolveAccessor(props.offset, ctxFor(i), { arrayMode: "clip", fallback: 0 }) ?? 0;
|
|
25
|
+
const borderRadius = typeof props.borderRadius === "number" ? props.borderRadius : typeof props.borderRadius === "object" && props.borderRadius !== null && !Array.isArray(props.borderRadius) ? props.borderRadius : void 0;
|
|
26
|
+
const hoverEnabled = effects !== void 0;
|
|
27
|
+
const slices = visibleSlices.map((slice) => {
|
|
28
|
+
const dataIndex = slice.dataIndex;
|
|
29
|
+
const userFill = colors[dataIndex];
|
|
30
|
+
const borderColor = borderColors[dataIndex];
|
|
31
|
+
const canvasFill = userFill ?? getDefaultColor(dataIndex, theme);
|
|
32
|
+
const hoverState = computeItemHoverState(dataIndex, interaction?.hoveredIndex, hoverEnabled);
|
|
33
|
+
const isInactive = hoverState.hasAnyHover && !hoverState.isHovered;
|
|
34
|
+
const itemHoverColor = resolveSliceHoverColor(dataIndex);
|
|
35
|
+
const itemHoverBorderColor = resolveSliceHoverBorderColor(dataIndex);
|
|
36
|
+
const itemEffects = hoverEnabled && effects && (itemHoverColor !== void 0 || itemHoverBorderColor !== void 0) ? {
|
|
37
|
+
...effects,
|
|
38
|
+
hoverBackgroundColor: itemHoverColor ?? effects.hoverBackgroundColor,
|
|
39
|
+
hoverBorderColor: itemHoverBorderColor ?? effects.hoverBorderColor
|
|
40
|
+
} : hoverEnabled ? effects : void 0;
|
|
41
|
+
const {
|
|
42
|
+
color: effectColor,
|
|
43
|
+
opacity: hoverOpacity,
|
|
44
|
+
borderColor: effectBorderColor,
|
|
45
|
+
borderStrokeWidth: effectBorderWidth,
|
|
46
|
+
borderDash: effectBorderDash,
|
|
47
|
+
borderDashOffset: effectBorderDashOffset
|
|
48
|
+
} = applyHoverEffects(canvasFill, borderColor, borderWidth, resolveSliceBorderDash(dataIndex), resolveSliceBorderDashOffset(dataIndex), hoverState, itemEffects, theme);
|
|
49
|
+
const userOpacity = resolveSliceOpacity(dataIndex);
|
|
50
|
+
const opacity = userOpacity !== void 0 ? hoverOpacity * userOpacity : hoverOpacity;
|
|
51
|
+
const finalEffectColor = effectColor;
|
|
52
|
+
const baseSliceOffset = resolveSliceOffset(dataIndex);
|
|
53
|
+
const offset = baseSliceOffset > 0 || hoverEnabled && effects ? calculateSliceOffset(slice, hoverState.isHovered, hoverEnabled ? effects : void 0, baseSliceOffset) : { dx: 0, dy: 0 };
|
|
54
|
+
const scale = hoverEnabled && hoverState.isHovered && effects?.hoverScale ? effects.hoverScale : 1;
|
|
55
|
+
const arcConfig = {
|
|
56
|
+
rotation: slice.rotation,
|
|
57
|
+
endAngle: slice.endAngle,
|
|
58
|
+
outerRadius,
|
|
59
|
+
innerRadius,
|
|
60
|
+
borderRadius
|
|
61
|
+
};
|
|
62
|
+
return {
|
|
63
|
+
slice,
|
|
64
|
+
dataIndex,
|
|
65
|
+
effectColor: finalEffectColor,
|
|
66
|
+
effectBorderColor,
|
|
67
|
+
effectBorderWidth,
|
|
68
|
+
effectBorderDash,
|
|
69
|
+
effectBorderDashOffset,
|
|
70
|
+
opacity,
|
|
71
|
+
// SVG state — class composition + inline overrides
|
|
72
|
+
userFill,
|
|
73
|
+
userBorder: borderColor === "transparent" ? void 0 : borderColor,
|
|
74
|
+
isInactive,
|
|
75
|
+
offset,
|
|
76
|
+
scale,
|
|
77
|
+
arcConfig,
|
|
78
|
+
isHovered: hoverState.isHovered
|
|
79
|
+
};
|
|
80
|
+
});
|
|
81
|
+
return {
|
|
82
|
+
slices,
|
|
83
|
+
center,
|
|
84
|
+
outerRadius,
|
|
85
|
+
innerRadius,
|
|
86
|
+
isFullCircle: fullCircle
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
function calculateSliceOffset(slice, isHovered, effects, baseOffset = 0) {
|
|
90
|
+
let offset = baseOffset;
|
|
91
|
+
if (isHovered && effects?.hoverOffset) {
|
|
92
|
+
offset = Math.max(offset, effects.hoverOffset);
|
|
93
|
+
}
|
|
94
|
+
if (offset === 0) return { dx: 0, dy: 0 };
|
|
95
|
+
const angleRad = toRad(slice.valueAngle);
|
|
96
|
+
return {
|
|
97
|
+
dx: Math.cos(angleRad) * offset,
|
|
98
|
+
dy: Math.sin(angleRad) * offset
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
export { computeSliceRenderStates };
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
import { getCellLabelInfo, buildCellExtras } from './chunk-VVI3OBPJ.mjs';
|
|
2
|
+
import { createDrawImage } from './chunk-7CMVDIOU.mjs';
|
|
3
|
+
import { resolveFontFamily, DEFAULT_TREEMAP_CELL_BORDER_COLOR, DEFAULT_TREEMAP_HEADER_TEXT_COLOR, DEFAULT_HOVER_DIM_OPACITY, DEFAULT_HOVER_BRIGHTNESS } from './chunk-NKUYIWAP.mjs';
|
|
4
|
+
import { getContrastColor } from './chunk-QS76E3TD.mjs';
|
|
5
|
+
import { resolveAccessor, makeItemContext, resolveDash } from './chunk-O2X6FF45.mjs';
|
|
6
|
+
import { withCanvasState, adjustBrightness } from './chunk-SSLTFJ3U.mjs';
|
|
7
|
+
|
|
8
|
+
// src/series/treemap/canvas/index.ts
|
|
9
|
+
function renderTreemapCanvas(props, layout, ctx, context) {
|
|
10
|
+
const fontFamily = resolveFontFamily(void 0, context?.font);
|
|
11
|
+
const interaction = context?.interaction;
|
|
12
|
+
const anyHovered = interaction?.hoveredIndex != null;
|
|
13
|
+
const treemapDataArr = props.data;
|
|
14
|
+
const defaultBorderColor = context?.theme.treemapCellBorder ?? DEFAULT_TREEMAP_CELL_BORDER_COLOR;
|
|
15
|
+
const cellExtras = (idx) => buildCellExtras(props, treemapDataArr?.[idx], layout, idx);
|
|
16
|
+
const resolveCellBorderColor = (idx) => {
|
|
17
|
+
const v = resolveAccessor(props.borderColor, makeItemContext(treemapDataArr?.[idx], idx, cellExtras(idx)), { fallback: defaultBorderColor });
|
|
18
|
+
return typeof v === "string" ? v : defaultBorderColor;
|
|
19
|
+
};
|
|
20
|
+
const resolveCellBorderWidth = (idx) => resolveAccessor(props.borderStrokeWidth, makeItemContext(treemapDataArr?.[idx], idx, cellExtras(idx)), { arrayMode: "clip", fallback: 1 }) ?? 1;
|
|
21
|
+
const resolveCellLabelColor = (idx) => {
|
|
22
|
+
const v = resolveAccessor(props.labelColor, makeItemContext(treemapDataArr?.[idx], idx, cellExtras(idx)));
|
|
23
|
+
return typeof v === "string" ? v : void 0;
|
|
24
|
+
};
|
|
25
|
+
const resolveCellBorderDash = (idx) => resolveDash(props.borderDash, makeItemContext(treemapDataArr?.[idx], idx, cellExtras(idx)));
|
|
26
|
+
const resolveCellBorderDashOffset = (idx) => resolveAccessor(props.borderDashOffset, makeItemContext(treemapDataArr?.[idx], idx, cellExtras(idx)), { arrayMode: "clip" });
|
|
27
|
+
const resolveCellOpacity = (idx) => resolveAccessor(props.opacity, makeItemContext(treemapDataArr?.[idx], idx, cellExtras(idx)), { arrayMode: "clip" });
|
|
28
|
+
const resolveCellHoverColor = (idx) => {
|
|
29
|
+
const v = resolveAccessor(props.hoverColor, makeItemContext(treemapDataArr?.[idx], idx, cellExtras(idx)), { arrayMode: "cycle" });
|
|
30
|
+
return typeof v === "string" ? v : void 0;
|
|
31
|
+
};
|
|
32
|
+
const resolveCellHoverBorderColor = (idx) => {
|
|
33
|
+
const v = resolveAccessor(props.hoverBorderColor, makeItemContext(treemapDataArr?.[idx], idx, cellExtras(idx)), { arrayMode: "cycle" });
|
|
34
|
+
return typeof v === "string" ? v : void 0;
|
|
35
|
+
};
|
|
36
|
+
const borderJoinStyle = props.borderJoinStyle;
|
|
37
|
+
const borderAlign = props.borderAlign ?? "center";
|
|
38
|
+
const borderRadius = props.borderRadius ?? 2;
|
|
39
|
+
for (const gh of layout.groupHeaders) {
|
|
40
|
+
withCanvasState(ctx, () => {
|
|
41
|
+
ctx.fillStyle = gh.color;
|
|
42
|
+
ctx.beginPath();
|
|
43
|
+
ctx.roundRect(gh.x, gh.y, gh.width, gh.height, 2);
|
|
44
|
+
ctx.fill();
|
|
45
|
+
const headerText = gh.label.toUpperCase();
|
|
46
|
+
const maxChars = Math.floor((gh.width - 16) / 6.5);
|
|
47
|
+
if (maxChars >= 2) {
|
|
48
|
+
const displayText = headerText.length <= maxChars ? headerText : headerText.slice(0, maxChars - 1) + "\u2026";
|
|
49
|
+
ctx.fillStyle = context?.theme.treemapHeaderText ?? DEFAULT_TREEMAP_HEADER_TEXT_COLOR;
|
|
50
|
+
ctx.font = `700 10px ${fontFamily}`;
|
|
51
|
+
ctx.textAlign = "left";
|
|
52
|
+
ctx.textBaseline = "middle";
|
|
53
|
+
ctx.fillText(displayText, gh.x + 8, gh.y + gh.height / 2);
|
|
54
|
+
}
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
for (const cell of layout.cells) {
|
|
58
|
+
if (cell.width < 1 || cell.height < 1) continue;
|
|
59
|
+
const isHovered = anyHovered && cell.index === interaction.hoveredIndex;
|
|
60
|
+
const userCellOpacity = resolveCellOpacity(cell.index);
|
|
61
|
+
const cellOpacity = (anyHovered && !isHovered ? context?.effects?.dimOpacity ?? context?.theme.dimOpacity ?? DEFAULT_HOVER_DIM_OPACITY : 1) * (userCellOpacity ?? 1);
|
|
62
|
+
const cellHoverColor = isHovered ? resolveCellHoverColor(cell.index) : void 0;
|
|
63
|
+
const cellColor = cellHoverColor ?? (isHovered && (context?.effects?.hoverBrightness ?? context?.theme.hoverBrightness) ? adjustBrightness(cell.color, context?.effects?.hoverBrightness ?? context?.theme.hoverBrightness ?? DEFAULT_HOVER_BRIGHTNESS) : cell.color);
|
|
64
|
+
const cellBorderWidth = resolveCellBorderWidth(cell.index);
|
|
65
|
+
const cellBorderColor = (isHovered ? resolveCellHoverBorderColor(cell.index) : void 0) ?? resolveCellBorderColor(cell.index);
|
|
66
|
+
withCanvasState(ctx, () => {
|
|
67
|
+
if (cellOpacity < 1) ctx.globalAlpha = cellOpacity;
|
|
68
|
+
const inset = borderAlign === "inner" ? cellBorderWidth / 2 : 0;
|
|
69
|
+
const cx = cell.x + inset;
|
|
70
|
+
const cy = cell.y + inset;
|
|
71
|
+
const cw = cell.width - inset * 2;
|
|
72
|
+
const ch = cell.height - inset * 2;
|
|
73
|
+
const r = Math.min(borderRadius, cw / 2, ch / 2);
|
|
74
|
+
ctx.fillStyle = cellColor;
|
|
75
|
+
ctx.beginPath();
|
|
76
|
+
ctx.roundRect(cx, cy, cw, ch, r);
|
|
77
|
+
ctx.fill();
|
|
78
|
+
if (cellBorderWidth > 0) {
|
|
79
|
+
const cellBorderDash = resolveCellBorderDash(cell.index);
|
|
80
|
+
const cellBorderDashOffset = resolveCellBorderDashOffset(cell.index);
|
|
81
|
+
ctx.strokeStyle = cellBorderColor;
|
|
82
|
+
ctx.lineWidth = cellBorderWidth;
|
|
83
|
+
ctx.setLineDash(cellBorderDash ?? []);
|
|
84
|
+
if (cellBorderDashOffset) ctx.lineDashOffset = cellBorderDashOffset;
|
|
85
|
+
if (borderJoinStyle) ctx.lineJoin = borderJoinStyle;
|
|
86
|
+
ctx.stroke();
|
|
87
|
+
}
|
|
88
|
+
});
|
|
89
|
+
if (!props.renderContent) {
|
|
90
|
+
const info = getCellLabelInfo(cell, props.labelMinSize);
|
|
91
|
+
if (info.showPrimary) {
|
|
92
|
+
const labelFill = resolveCellLabelColor(cell.index) ?? getContrastColor(cellColor);
|
|
93
|
+
withCanvasState(ctx, () => {
|
|
94
|
+
if (cellOpacity < 1) ctx.globalAlpha = cellOpacity;
|
|
95
|
+
ctx.fillStyle = labelFill;
|
|
96
|
+
ctx.font = `700 ${info.fontSize}px ${fontFamily}`;
|
|
97
|
+
ctx.textAlign = "center";
|
|
98
|
+
ctx.textBaseline = "middle";
|
|
99
|
+
ctx.fillText(cell.label, info.cx, info.primaryY);
|
|
100
|
+
if (info.showSecondary) {
|
|
101
|
+
ctx.globalAlpha = (cellOpacity < 1 ? cellOpacity : 1) * 0.85;
|
|
102
|
+
ctx.fillStyle = labelFill;
|
|
103
|
+
ctx.font = `500 ${info.secondaryFontSize}px ${fontFamily}`;
|
|
104
|
+
ctx.fillText(cell.secondaryLabel, info.cx, info.secondaryY);
|
|
105
|
+
}
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
function renderCanvasTreemapContent(ctx, layouts, onImageLoad) {
|
|
112
|
+
for (const [, { props, layout }] of layouts) {
|
|
113
|
+
const renderFn = props.renderContent;
|
|
114
|
+
if (!renderFn || !props.data) continue;
|
|
115
|
+
const drawImage = createDrawImage(ctx, onImageLoad ?? (() => {
|
|
116
|
+
}));
|
|
117
|
+
for (const cell of layout.cells) {
|
|
118
|
+
const dataItem = props.data[cell.index];
|
|
119
|
+
if (!dataItem) continue;
|
|
120
|
+
ctx.save();
|
|
121
|
+
ctx.beginPath();
|
|
122
|
+
ctx.rect(cell.x, cell.y, cell.width, cell.height);
|
|
123
|
+
ctx.clip();
|
|
124
|
+
renderFn({
|
|
125
|
+
data: dataItem,
|
|
126
|
+
index: cell.index,
|
|
127
|
+
label: cell.label,
|
|
128
|
+
secondaryLabel: cell.secondaryLabel,
|
|
129
|
+
value: cell.value,
|
|
130
|
+
color: cell.color,
|
|
131
|
+
x: cell.x,
|
|
132
|
+
y: cell.y,
|
|
133
|
+
width: cell.width,
|
|
134
|
+
height: cell.height,
|
|
135
|
+
nodeId: cell.nodeId,
|
|
136
|
+
parentId: cell.parentId,
|
|
137
|
+
hasChildren: cell.hasChildren,
|
|
138
|
+
depth: cell.depth,
|
|
139
|
+
drilldownParentId: props.drilldownParentId ?? null,
|
|
140
|
+
ctx,
|
|
141
|
+
drawImage
|
|
142
|
+
});
|
|
143
|
+
ctx.restore();
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
function renderTreemapCanvasClipped(ctx, area, transform, draw) {
|
|
148
|
+
if (transform?.zoom) {
|
|
149
|
+
const { tx, ty, sx, sy, progress, direction } = transform.zoom;
|
|
150
|
+
ctx.save();
|
|
151
|
+
ctx.beginPath();
|
|
152
|
+
ctx.rect(area.x, area.y, area.width, area.height);
|
|
153
|
+
ctx.clip();
|
|
154
|
+
ctx.translate(tx, ty);
|
|
155
|
+
ctx.scale(sx, sy);
|
|
156
|
+
if (direction === "out") ctx.globalAlpha = progress;
|
|
157
|
+
draw();
|
|
158
|
+
ctx.restore();
|
|
159
|
+
return;
|
|
160
|
+
}
|
|
161
|
+
if (transform?.wipe) {
|
|
162
|
+
ctx.save();
|
|
163
|
+
ctx.beginPath();
|
|
164
|
+
ctx.rect(area.x, area.y, area.width * transform.wipe.progress, area.height);
|
|
165
|
+
ctx.clip();
|
|
166
|
+
draw();
|
|
167
|
+
ctx.restore();
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
170
|
+
draw();
|
|
171
|
+
}
|
|
172
|
+
function renderTreemapGroupHoverCanvas(ctx, bg) {
|
|
173
|
+
ctx.save();
|
|
174
|
+
ctx.fillStyle = "rgba(0,0,0,0.15)";
|
|
175
|
+
ctx.beginPath();
|
|
176
|
+
ctx.roundRect(bg.x, bg.y, bg.width, bg.height, 2);
|
|
177
|
+
ctx.fill();
|
|
178
|
+
ctx.strokeStyle = "rgba(255,255,255,0.6)";
|
|
179
|
+
ctx.lineWidth = 2;
|
|
180
|
+
ctx.beginPath();
|
|
181
|
+
ctx.roundRect(bg.x, bg.y, bg.width, bg.height, 2);
|
|
182
|
+
ctx.stroke();
|
|
183
|
+
ctx.restore();
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
export { renderCanvasTreemapContent, renderTreemapCanvas, renderTreemapCanvasClipped, renderTreemapGroupHoverCanvas };
|