stickyflow 0.6.0 → 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (62) hide show
  1. package/CHANGELOG.md +39 -0
  2. package/dist/binding/index.cjs +9 -9
  3. package/dist/binding/index.d.cts +4 -4
  4. package/dist/binding/index.d.ts +4 -4
  5. package/dist/binding/index.js +3 -3
  6. package/dist/{chunk-MFNUJA26.js → chunk-CZW3ARXQ.js} +156 -23
  7. package/dist/chunk-CZW3ARXQ.js.map +1 -0
  8. package/dist/{chunk-WRDVNMFS.js → chunk-EDOPENSE.js} +848 -38
  9. package/dist/chunk-EDOPENSE.js.map +1 -0
  10. package/dist/{chunk-4LENHH6C.cjs → chunk-FQ7GMLCM.cjs} +15 -15
  11. package/dist/{chunk-4LENHH6C.cjs.map → chunk-FQ7GMLCM.cjs.map} +1 -1
  12. package/dist/{chunk-4G2R7PEL.js → chunk-GLZVHUSW.js} +220 -12
  13. package/dist/chunk-GLZVHUSW.js.map +1 -0
  14. package/dist/{chunk-KTNCDNDB.cjs → chunk-IR2T47NW.cjs} +876 -66
  15. package/dist/chunk-IR2T47NW.cjs.map +1 -0
  16. package/dist/{chunk-ULQZ6CZW.js → chunk-LFEGZJWC.js} +3 -3
  17. package/dist/{chunk-ULQZ6CZW.js.map → chunk-LFEGZJWC.js.map} +1 -1
  18. package/dist/{chunk-XJ4W6TW4.cjs → chunk-LNW5VIEA.cjs} +225 -11
  19. package/dist/chunk-LNW5VIEA.cjs.map +1 -0
  20. package/dist/{chunk-FVHVOJS2.js → chunk-MAPNY7MJ.js} +872 -174
  21. package/dist/chunk-MAPNY7MJ.js.map +1 -0
  22. package/dist/{chunk-WQRT5PVT.cjs → chunk-VOYX6JMW.cjs} +1479 -780
  23. package/dist/chunk-VOYX6JMW.cjs.map +1 -0
  24. package/dist/{chunk-JIJMZMGY.cjs → chunk-XPM3E7NV.cjs} +170 -37
  25. package/dist/chunk-XPM3E7NV.cjs.map +1 -0
  26. package/dist/index.cjs +42 -34
  27. package/dist/index.d.cts +34 -6
  28. package/dist/index.d.ts +34 -6
  29. package/dist/index.js +5 -5
  30. package/dist/interaction/index.cjs +266 -235
  31. package/dist/interaction/index.cjs.map +1 -1
  32. package/dist/interaction/index.d.cts +2 -2
  33. package/dist/interaction/index.d.ts +2 -2
  34. package/dist/interaction/index.js +42 -11
  35. package/dist/interaction/index.js.map +1 -1
  36. package/dist/{render-Db0eSz_s.d.cts → render-Bp2FLEzv.d.cts} +14 -1
  37. package/dist/{render-Db0eSz_s.d.ts → render-Bp2FLEzv.d.ts} +14 -1
  38. package/dist/{runtime-n2yG-_j-.d.ts → runtime-CWIGxRcL.d.ts} +2 -2
  39. package/dist/{runtime-BhivvBeL.d.cts → runtime-DIag-XBa.d.cts} +2 -2
  40. package/dist/{runtimeTypes-DnI7mRF5.d.ts → runtimeTypes-BYODuxHk.d.cts} +2 -1
  41. package/dist/{runtimeTypes-CrkMHvVi.d.cts → runtimeTypes-C7sSLfOK.d.ts} +2 -1
  42. package/dist/stickyflow-diagram.global.js +490 -36
  43. package/dist/stickyflow-diagram.global.js.map +1 -1
  44. package/dist/{types-D4cH4f1a.d.ts → types-B9QM_H3R.d.ts} +1 -1
  45. package/dist/{types-BHfUKT4s.d.cts → types-D2w6D_wG.d.cts} +1 -1
  46. package/dist/viewer/index.cjs +9 -9
  47. package/dist/viewer/index.d.cts +5 -4
  48. package/dist/viewer/index.d.ts +5 -4
  49. package/dist/viewer/index.js +4 -4
  50. package/dist/web-component/index.cjs +6 -6
  51. package/dist/web-component/index.d.cts +2 -2
  52. package/dist/web-component/index.d.ts +2 -2
  53. package/dist/web-component/index.js +4 -4
  54. package/package.json +1 -1
  55. package/dist/chunk-4G2R7PEL.js.map +0 -1
  56. package/dist/chunk-FVHVOJS2.js.map +0 -1
  57. package/dist/chunk-JIJMZMGY.cjs.map +0 -1
  58. package/dist/chunk-KTNCDNDB.cjs.map +0 -1
  59. package/dist/chunk-MFNUJA26.js.map +0 -1
  60. package/dist/chunk-WQRT5PVT.cjs.map +0 -1
  61. package/dist/chunk-WRDVNMFS.js.map +0 -1
  62. package/dist/chunk-XJ4W6TW4.cjs.map +0 -1
@@ -1,4 +1,4 @@
1
- import { componentRegistryVersion, isDimensionObject, isIsometricObject, sflToCanvasState, registerComponentDescriptor, isBuiltInComponentType, getComponentDescriptor, tag, EMPTY_BOUNDS, DOM_CONTRACT_VERSION, edgePointToward, elementCenter, VISIBLE_ISOMETRIC_FACES, isometricFaceCenter, finite, freeformPathData, rotatedBounds, DEFAULT_FONT, isGenericComponent, cleanFootprint, pointAtNormalizedPort, boxBounds, cornersRoundedRectPath, calculateLinkRoute, labelGapDash, getLineMidpoint, personLabelArea, wrapText, heuristicRichMeasure, shadeFill, extrudeFootprint, isometricFaces, roundedPolygonPath, stackSequence, stackRank, topRoundedRectPath, rightRoundedRectPath, leftRoundedRectPath, bottomRoundedRectPath, isHorizontalBar, paint, CHART_TITLE_PROP, chartText, chartTicks, mapChartValue, roundedOrthogonalPathData, localShapePath, pillCornerRadius, isometricBounds, AXIS_SIN, deriveFaceFills, resolveChartShadow, CHART_COLORS, angleForAxisValue, horizontalRows, rowTop, categoryProp, isometricTopFaceCenter, ISOMETRIC_SIZE_ATTR, CORNER_RADIUS_ATTR, ISOMETRIC_LABEL_OFFSET_ATTR, PATH_POINTS_ATTR, PATH_TENSION_ATTR, PATH_CLOSED_ATTR, SYMBOL_BOUNDS_ATTR, SYMBOL_POINTS_ATTR, SYMBOL_TENSION_ATTR, SQUARE_CORNER_ATTR, resolvePieRadii, radarCategoryCount, radarRadius, createPieGeometry, DEFAULT_HEX_RADIUS, DEFAULT_HEATMAP_ZONES, axisBands, DEFAULT_ZONE_FILL, representativeColor, computeBoxplotStats, barCategoryCount, ruleAtProp, ruleTextProp, seriesLabelProp, axisLabelProp, seriesColorProp, seriesValueProp, radarSeriesPath, radarRadiusForValue, createPieSlicePath, clipSegmentToRect, formatFieldValue, renderPieLabels, interpolateHexColorStops, contrastTextColor, sameHueTint, isLightColor, barShapePath, linePathData, colorWithAlpha, estimateTextWidth, segmentedBarPath, roundedBarPath, radarPointAt, gapInsetAngle, pieUsesInnerArc, maxPieCornerRadius, pieApexRadius, maxApexCornerRadius, pieArcPoint, sameHueContrastColor, zoneColorAtValue, ellipsizeToWidth, barPath, seriesValueColorProp, stackedSegment, errorBarRange, createVerticalErrorWhiskerNode, formatBarLabel, barLabelSize, CATEGORY_LABEL_ROW, BAR_LABEL, pillPath, resolveRollingNumberStyle, formatRollingNumber } from './chunk-4G2R7PEL.js';
1
+ import { componentRegistryVersion, isDimensionObject, isIsometricObject, sflToCanvasState, registerComponentDescriptor, isBuiltInComponentType, getComponentDescriptor, tag, EMPTY_BOUNDS, DOM_CONTRACT_VERSION, edgePointToward, elementCenter, VISIBLE_ISOMETRIC_FACES, isometricFaceCenter, finite, freeformPathData, rotatedBounds, DEFAULT_FONT, isGenericComponent, cleanFootprint, pointAtNormalizedPort, boxBounds, cornersRoundedRectPath, calculateLinkRoute, labelGapDash, getLineMidpoint, personLabelArea, wrapText, heuristicRichMeasure, shadeFill, extrudeFootprint, isometricFaces, roundedPolygonPath, stackSequence, stackRank, topRoundedRectPath, rightRoundedRectPath, leftRoundedRectPath, bottomRoundedRectPath, isHorizontalBar, paint, CHART_TITLE_PROP, chartText, chartTicks, mapChartValue, roundedOrthogonalPathData, localShapePath, pillCornerRadius, isometricBounds, AXIS_SIN, deriveFaceFills, labelTilt, tiltedLabelRoom, resolveChartShadow, CHART_COLORS, angleForAxisValue, horizontalRows, rowTop, categoryProp, isometricTopFaceCenter, ISOMETRIC_SIZE_ATTR, CORNER_RADIUS_ATTR, ISOMETRIC_LABEL_OFFSET_ATTR, PATH_POINTS_ATTR, PATH_TENSION_ATTR, PATH_CLOSED_ATTR, SYMBOL_BOUNDS_ATTR, SYMBOL_POINTS_ATTR, SYMBOL_TENSION_ATTR, SQUARE_CORNER_ATTR, resolvePieRadii, radarCategoryCount, radarRadius, createPieGeometry, DEFAULT_HEX_RADIUS, DEFAULT_HEATMAP_ZONES, axisBands, DEFAULT_ZONE_FILL, representativeColor, computeBoxplotStats, barCategoryCount, ruleAtProp, ruleTextProp, labelBelowFrame, seriesLabelProp, axisLabelProp, seriesColorProp, seriesValueProp, radarSeriesPath, radarRadiusForValue, createPieSlicePath, clipSegmentToRect, formatFieldValue, renderPieLabels, interpolateHexColorStops, contrastTextColor, sameHueTint, isLightColor, barShapePath, linePathData, colorWithAlpha, estimateTextWidth, segmentedBarPath, roundedBarPath, radarPointAt, gapInsetAngle, pieUsesInnerArc, maxPieCornerRadius, pieApexRadius, maxApexCornerRadius, pieArcPoint, sameHueContrastColor, zoneColorAtValue, ellipsizeToWidth, barPath, labelAboveFrame, seriesValueColorProp, stackedSegment, errorBarRange, createVerticalErrorWhiskerNode, formatBarLabel, barLabelSize, CATEGORY_LABEL_ROW, BAR_LABEL, pillPath, resolveRollingNumberStyle, formatRollingNumber } from './chunk-GLZVHUSW.js';
2
2
 
3
3
  // src/renderInput/styleDecoding/colorToken.ts
4
4
  var COLOR_TOKEN_PATTERN = String.raw`rgba?\([^)]*\)|#[0-9a-fA-F]+|[a-zA-Z][\w-]*`;
@@ -240,6 +240,14 @@ function axesOf(p) {
240
240
  axisLineStyle: p.axisLineStyle === "dashed" || p.axisLineStyle === "dotted" ? p.axisLineStyle : void 0,
241
241
  tickLength: numOf(p.tickLength),
242
242
  axisFontSize: numOf(p.axisFontSize),
243
+ axisLabelAngle: numOf(p.axisLabelAngle),
244
+ axisLabelSpace: numOf(p.axisLabelSpace),
245
+ rowLabelSide: p.rowLabelSide === "left" || p.rowLabelSide === "right" ? p.rowLabelSide : void 0,
246
+ columnLabelSide: p.columnLabelSide === "top" || p.columnLabelSide === "bottom" ? p.columnLabelSide : void 0,
247
+ legendSide: p.legendSide === "top" || p.legendSide === "bottom" || p.legendSide === "left" || p.legendSide === "right" ? p.legendSide : void 0,
248
+ xLabelGap: numOf(p.xLabelGap),
249
+ yLabelGap: numOf(p.yLabelGap),
250
+ axisLabelAlign: p.axisLabelAlign === "left" || p.axisLabelAlign === "center" || p.axisLabelAlign === "right" ? p.axisLabelAlign : void 0,
243
251
  axisFontFamily: p.axisFontFamily,
244
252
  showValueAxis: p.showValueAxis !== "false",
245
253
  categoryAlign: p.categoryAlign === "left" || p.categoryAlign === "inside" ? p.categoryAlign : void 0,
@@ -250,6 +258,7 @@ function textOf(p) {
250
258
  return {
251
259
  textColor: p.textColor ?? "#0f172a",
252
260
  titleSize: numOf(p.titleSize),
261
+ titleAlign: p.titleAlign === "left" || p.titleAlign === "center" || p.titleAlign === "right" ? p.titleAlign : void 0,
253
262
  titleWeight: p.titleWeight === "normal" ? "normal" : void 0,
254
263
  titleColor: p.titleColor,
255
264
  fontSize: numOf(p.fontSize) ?? 12,
@@ -259,6 +268,7 @@ function textOf(p) {
259
268
  function legendOf(p) {
260
269
  return {
261
270
  legendColor: p.legendColor,
271
+ legendGap: numOf(p.legendGap),
262
272
  showLegend: p.showLegend === "true",
263
273
  legendPosition: legendPositionOf(p.legendPosition)
264
274
  };
@@ -1332,7 +1342,7 @@ function buildTickScale(component, index) {
1332
1342
  }
1333
1343
  function buildTickLabels(component, box) {
1334
1344
  const labels = component.labels ?? {};
1335
- const ticks = Math.max(1, finite(Number(component.parameters.ticks), 48));
1345
+ const ticks2 = Math.max(1, finite(Number(component.parameters.ticks), 48));
1336
1346
  const major = Math.max(1, finite(Number(component.parameters.major), 5));
1337
1347
  const start = finite(Number(component.parameters.start), 225) * Math.PI / 180;
1338
1348
  const sweep = finite(Number(component.parameters.sweep), 270) * Math.PI / 180;
@@ -1340,10 +1350,10 @@ function buildTickLabels(component, box) {
1340
1350
  const fontSize = finite(labels.size, 12);
1341
1351
  const centerX = box.x + box.width / 2;
1342
1352
  const centerY = box.y + box.height / 2;
1343
- const count = Math.floor(ticks / major);
1353
+ const count = Math.floor(ticks2 / major);
1344
1354
  const nodes = [];
1345
1355
  for (let step = 0; step <= count; step += 1) {
1346
- const fraction = step * major / ticks;
1356
+ const fraction = step * major / ticks2;
1347
1357
  const angle = start - fraction * sweep;
1348
1358
  const labelX2 = centerX + Math.cos(angle) * radius * (box.width / 2);
1349
1359
  const labelY = centerY - Math.sin(angle) * radius * (box.height / 2);
@@ -1398,7 +1408,7 @@ function buildRuler(component, index) {
1398
1408
  function buildRulerLabels(component, box) {
1399
1409
  const labels = component.labels ?? {};
1400
1410
  const horizontal = component.parameters.axis === "horizontal";
1401
- const ticks = Math.max(1, finite(Number(component.parameters.ticks), 50));
1411
+ const ticks2 = Math.max(1, finite(Number(component.parameters.ticks), 50));
1402
1412
  const major = Math.max(1, finite(Number(component.parameters.major), 5));
1403
1413
  const inset = finite(Number(component.parameters.inset), 0.05) > 0 ? finite(Number(component.parameters.inset), 0.05) : 0.05;
1404
1414
  const line = finite(Number(component.parameters.line), 0.7) > 0 ? finite(Number(component.parameters.line), 0.7) : 0.7;
@@ -1406,10 +1416,10 @@ function buildRulerLabels(component, box) {
1406
1416
  const tickLength = (finite(Number(component.parameters.length), 0.1) > 0 ? finite(Number(component.parameters.length), 0.1) : 0.1) * across * 1.9;
1407
1417
  const edge = line * across - 0.12 * across - tickLength - finite(labels.offset, 0.04) * across;
1408
1418
  const fontSize = finite(labels.size, 12);
1409
- const count = Math.floor(ticks / major);
1419
+ const count = Math.floor(ticks2 / major);
1410
1420
  const nodes = [];
1411
1421
  for (let step = 0; step <= count; step += 1) {
1412
- const fraction = step * major / ticks;
1422
+ const fraction = step * major / ticks2;
1413
1423
  const along2 = inset + (1 - 2 * inset) * fraction;
1414
1424
  const labelBox = horizontal ? { x: box.x + box.width * along2 - 24, y: box.y + edge - fontSize * 2, width: 48, height: fontSize * 2 } : { x: box.x + edge - 48, y: box.y + box.height * (1 - along2) - fontSize, width: 48, height: fontSize * 2 };
1415
1425
  nodes.push({
@@ -1447,7 +1457,9 @@ var numberProperty2 = (component, key) => Number(component.properties[key] ?? 0)
1447
1457
  var solid = (color) => ({ kind: "solid", color });
1448
1458
  var ink = (component, color) => component.disabled ? DISABLED_INK : color;
1449
1459
  function fade(component, style) {
1450
- return component.disabled ? { ...style, opacity: 0.4 } : style;
1460
+ const animate = Number(component.properties.animate ?? 0);
1461
+ const shown = component.disabled ? { ...style, opacity: 0.4 } : style;
1462
+ return animate > 0 ? { ...shown, transition: animate } : shown;
1451
1463
  }
1452
1464
  function hitArea(component, box) {
1453
1465
  return {
@@ -1580,6 +1592,463 @@ function buildCheckbox(component, index) {
1580
1592
  ];
1581
1593
  }
1582
1594
 
1595
+ // src/renderScene/artifacts/component/knob.ts
1596
+ var DOT_RATIO = 0.62;
1597
+ function decimals(step) {
1598
+ return step > 0 ? String(step).split(".")[1]?.length ?? 0 : 0;
1599
+ }
1600
+ function readout(component, fraction) {
1601
+ const display = textProperty(component, "display");
1602
+ if (display === "percent") {
1603
+ return `${Math.round(fraction * 100)}%`;
1604
+ }
1605
+ return display === "value" ? Number(component.value).toFixed(decimals(numberProperty2(component, "step"))) : "";
1606
+ }
1607
+ function buildKnob(component, index) {
1608
+ const box = controlBox(component, index, { width: 96, height: 96 });
1609
+ const min = numberProperty2(component, "min");
1610
+ const max = numberProperty2(component, "max");
1611
+ const fraction = Math.min(1, Math.max(0, (Number(component.value) - min) / (max - min || 1)));
1612
+ const start = numberProperty2(component, "start");
1613
+ const sweep = Math.min(360, Math.max(1, numberProperty2(component, "sweep")));
1614
+ const thickness = Math.min(numberProperty2(component, "thickness"), Math.min(box.width, box.height) / 3);
1615
+ const cx = box.x + box.width / 2;
1616
+ const cy = box.y + box.height / 2;
1617
+ const radius = Math.max(1, Math.min(box.width, box.height) / 2 - thickness / 2);
1618
+ const circumference = 2 * Math.PI * radius;
1619
+ const round2 = textProperty(component, "rounded") !== "false";
1620
+ const angle = (start - fraction * sweep) * Math.PI / 180;
1621
+ const arc = (part, order, color, length, extra = {}) => ({
1622
+ id: `widget-${component.id}-${part}`,
1623
+ type: "ellipse",
1624
+ order: box.order + order,
1625
+ bounds: rotatedBounds({ x: cx - radius, y: cy - radius, width: radius * 2, height: radius * 2 }, 0, thickness),
1626
+ cx,
1627
+ cy,
1628
+ rx: radius,
1629
+ ry: radius,
1630
+ rotation: -start,
1631
+ style: fade(component, {
1632
+ fill: { kind: "none" },
1633
+ stroke: solid(color),
1634
+ strokeWidth: thickness,
1635
+ dash: [Math.max(1e-3, length), circumference],
1636
+ lineCap: round2 ? "round" : "butt",
1637
+ ...extra
1638
+ })
1639
+ });
1640
+ const faceRadius = Math.max(1, radius - thickness / 2 - Math.max(2, thickness * 0.4));
1641
+ const dotRadius = thickness / 2 * DOT_RATIO + 1;
1642
+ const nodes = [
1643
+ hitArea(component, box),
1644
+ arc("track", 0.1, textProperty(component, "track"), sweep / 360 * circumference),
1645
+ arc("fill", 0.2, textProperty(component, "accent"), fraction * sweep / 360 * circumference, {
1646
+ opacity: fraction > 0 ? 1 : 0
1647
+ }),
1648
+ {
1649
+ id: `widget-${component.id}-face`,
1650
+ type: "ellipse",
1651
+ order: box.order + 0.3,
1652
+ bounds: rotatedBounds(
1653
+ { x: cx - faceRadius, y: cy - faceRadius, width: faceRadius * 2, height: faceRadius * 2 },
1654
+ 0,
1655
+ 0
1656
+ ),
1657
+ cx,
1658
+ cy,
1659
+ rx: faceRadius,
1660
+ ry: faceRadius,
1661
+ style: fade(component, { fill: solid(textProperty(component, "face")), stroke: { kind: "none" } })
1662
+ },
1663
+ {
1664
+ id: `widget-${component.id}-dot`,
1665
+ type: "ellipse",
1666
+ order: box.order + 0.4,
1667
+ bounds: rotatedBounds(
1668
+ {
1669
+ x: cx + radius * Math.cos(angle) - dotRadius,
1670
+ y: cy - radius * Math.sin(angle) - dotRadius,
1671
+ width: dotRadius * 2,
1672
+ height: dotRadius * 2
1673
+ },
1674
+ 0,
1675
+ 0
1676
+ ),
1677
+ cx: cx + radius * Math.cos(angle),
1678
+ cy: cy - radius * Math.sin(angle),
1679
+ rx: dotRadius,
1680
+ ry: dotRadius,
1681
+ style: fade(component, { fill: solid(textProperty(component, "dot")), stroke: { kind: "none" } })
1682
+ }
1683
+ ];
1684
+ const text = readout(component, fraction);
1685
+ if (text) {
1686
+ const label = {
1687
+ text,
1688
+ color: ink(component, textProperty(component, "textColor")),
1689
+ fontSize: numberProperty2(component, "fontSize"),
1690
+ align: "center"
1691
+ };
1692
+ nodes.push(
1693
+ labelText(
1694
+ component,
1695
+ "value",
1696
+ { x: cx - faceRadius, y: cy - faceRadius, width: faceRadius * 2, height: faceRadius * 2 },
1697
+ label,
1698
+ box.order + 0.5
1699
+ )
1700
+ );
1701
+ }
1702
+ return nodes;
1703
+ }
1704
+
1705
+ // src/renderScene/artifacts/component/progress.ts
1706
+ function readout2(component, fraction) {
1707
+ const display = textProperty(component, "display");
1708
+ if (display === "percent") {
1709
+ return `${Math.round(fraction * 100)}%`;
1710
+ }
1711
+ return display === "value" ? String(Number(component.value)) : "";
1712
+ }
1713
+ function buildProgress(component, index) {
1714
+ const box = controlBox(component, index, { width: 220, height: 12 });
1715
+ const min = numberProperty2(component, "min");
1716
+ const max = numberProperty2(component, "max");
1717
+ const fraction = Math.min(1, Math.max(0, (Number(component.value) - min) / (max - min || 1)));
1718
+ const round2 = textProperty(component, "rounded") !== "false";
1719
+ const nodes = [hitArea(component, box)];
1720
+ if (textProperty(component, "variant") === "ring") {
1721
+ const thickness = Math.min(numberProperty2(component, "thickness"), Math.min(box.width, box.height) / 2);
1722
+ const radius = Math.max(1, Math.min(box.width, box.height) / 2 - thickness / 2);
1723
+ const circumference = 2 * Math.PI * radius;
1724
+ const cx = box.x + box.width / 2;
1725
+ const cy = box.y + box.height / 2;
1726
+ const ring = (part, order, color, extra) => ({
1727
+ id: `widget-${component.id}-${part}`,
1728
+ type: "ellipse",
1729
+ order: box.order + order,
1730
+ bounds: rotatedBounds({ x: cx - radius, y: cy - radius, width: radius * 2, height: radius * 2 }, 0, thickness),
1731
+ cx,
1732
+ cy,
1733
+ rx: radius,
1734
+ ry: radius,
1735
+ rotation: -90,
1736
+ style: fade(component, { fill: { kind: "none" }, stroke: solid(color), strokeWidth: thickness, ...extra })
1737
+ });
1738
+ nodes.push(ring("track", 0.1, textProperty(component, "track"), {}));
1739
+ nodes.push(
1740
+ ring("fill", 0.2, textProperty(component, "accent"), {
1741
+ dash: [Math.max(1e-3, fraction * circumference), circumference],
1742
+ lineCap: round2 ? "round" : "butt",
1743
+ opacity: fraction > 0 ? 1 : 0
1744
+ })
1745
+ );
1746
+ } else {
1747
+ const vertical = textProperty(component, "direction") === "vertical";
1748
+ const radius = round2 ? (vertical ? box.width : box.height) / 2 : 0;
1749
+ const bar = (part, order, length, color, opacity) => {
1750
+ const shape = vertical ? { x: box.x, y: box.y + box.height - length, width: box.width, height: length } : { x: box.x, y: box.y, width: length, height: box.height };
1751
+ return {
1752
+ id: `widget-${component.id}-${part}`,
1753
+ type: "rect",
1754
+ order: box.order + order,
1755
+ bounds: rotatedBounds(shape, 0, 0),
1756
+ ...shape,
1757
+ rx: radius,
1758
+ style: fade(component, {
1759
+ fill: solid(color),
1760
+ stroke: { kind: "none" },
1761
+ ...opacity === void 0 ? {} : { opacity }
1762
+ })
1763
+ };
1764
+ };
1765
+ const full = vertical ? box.height : box.width;
1766
+ nodes.push(bar("track", 0.1, full, textProperty(component, "track")));
1767
+ nodes.push(bar("fill", 0.2, Math.max(0, fraction * full), textProperty(component, "accent"), fraction > 0 ? 1 : 0));
1768
+ }
1769
+ const text = readout2(component, fraction);
1770
+ if (text) {
1771
+ const label = {
1772
+ text,
1773
+ color: ink(component, textProperty(component, "textColor")),
1774
+ fontSize: numberProperty2(component, "fontSize"),
1775
+ align: "center"
1776
+ };
1777
+ nodes.push(labelText(component, "value", box, label, box.order + 0.3));
1778
+ }
1779
+ return nodes;
1780
+ }
1781
+
1782
+ // src/renderScene/artifacts/component/segmented.ts
1783
+ function buildSegmented(component, index) {
1784
+ const box = controlBox(component, index, { width: 300, height: 40 });
1785
+ const options = textProperty(component, "options").split(",").map((option) => option.trim()).filter(Boolean);
1786
+ const count = Math.max(1, options.length);
1787
+ const active = Math.min(count - 1, Math.max(0, Math.round(Number(component.value)) || 0));
1788
+ const inset = Math.min(numberProperty2(component, "inset"), box.height / 2);
1789
+ const radius = Math.min(numberProperty2(component, "radius"), box.height / 2);
1790
+ const cellWidth = (box.width - inset * 2) / count;
1791
+ const cell = { y: box.y + inset, height: box.height - inset * 2 };
1792
+ const nodes = [
1793
+ hitArea(component, box),
1794
+ {
1795
+ id: `widget-${component.id}-track`,
1796
+ type: "rect",
1797
+ order: box.order + 0.1,
1798
+ bounds: rotatedBounds(box, 0, 0),
1799
+ x: box.x,
1800
+ y: box.y,
1801
+ width: box.width,
1802
+ height: box.height,
1803
+ rx: radius,
1804
+ style: fade(component, { fill: solid(textProperty(component, "track")), stroke: { kind: "none" } })
1805
+ },
1806
+ {
1807
+ id: `widget-${component.id}-active`,
1808
+ type: "rect",
1809
+ order: box.order + 0.2,
1810
+ bounds: rotatedBounds({ x: box.x + inset + active * cellWidth, width: cellWidth, ...cell }, 0, 0),
1811
+ x: box.x + inset + active * cellWidth,
1812
+ y: cell.y,
1813
+ width: cellWidth,
1814
+ height: cell.height,
1815
+ rx: Math.max(0, radius - inset),
1816
+ style: fade(component, {
1817
+ fill: solid(textProperty(component, "accent")),
1818
+ stroke: { kind: "none" },
1819
+ shadow: { color: "#000000", opacity: 0.18, blur: 3, dx: 0, dy: 1 }
1820
+ })
1821
+ }
1822
+ ];
1823
+ options.forEach((option, position) => {
1824
+ const area = { x: box.x + inset + position * cellWidth, width: cellWidth, ...cell };
1825
+ const color = ink(component, textProperty(component, position === active ? "activeTextColor" : "textColor"));
1826
+ nodes.push(
1827
+ labelText(
1828
+ component,
1829
+ `option-${position}`,
1830
+ area,
1831
+ { text: option, color, fontSize: numberProperty2(component, "fontSize"), align: "center" },
1832
+ box.order + 0.3
1833
+ )
1834
+ );
1835
+ });
1836
+ return nodes;
1837
+ }
1838
+
1839
+ // src/model/component/sliderReach.ts
1840
+ function sliderReach(variant2, height) {
1841
+ return variant2 === "field" ? Math.min(8, height / 2) : height / 2;
1842
+ }
1843
+
1844
+ // src/renderScene/artifacts/component/slider.ts
1845
+ var HANDLE_WIDTH = 4;
1846
+ var TEXT_PADDING = 12;
1847
+ var TICK_LENGTH = 5;
1848
+ var TICK_THICKNESS = 1.5;
1849
+ function decimals2(step) {
1850
+ return step > 0 ? String(step).split(".")[1]?.length ?? 0 : 0;
1851
+ }
1852
+ function readout3(component, thumbs) {
1853
+ const display = textProperty(component, "display");
1854
+ const places = decimals2(numberProperty2(component, "step"));
1855
+ const parts = display === "percent" ? thumbs.two ? [thumbs.from, thumbs.to].map((fraction) => `${Math.round(fraction * 100)}%`) : [`${Math.round(thumbs.to * 100)}%`] : display === "value" ? thumbs.values.map((value) => value.toFixed(places)) : [];
1856
+ return parts.join(" \u2013 ");
1857
+ }
1858
+ var rect = (component, box, part, order, shape, color, extra = {}) => ({
1859
+ id: `widget-${component.id}-${part}`,
1860
+ type: "rect",
1861
+ order: box.order + order,
1862
+ bounds: rotatedBounds(shape, 0, 0),
1863
+ ...shape,
1864
+ style: fade(component, { fill: solid(color), stroke: { kind: "none" }, ...extra })
1865
+ });
1866
+ function ticks(component, box, vertical, reach, offset) {
1867
+ const count = Math.round(numberProperty2(component, "ticks"));
1868
+ const color = textProperty(component, "tickColor");
1869
+ return Array.from({ length: count >= 2 ? count : 0 }, (_, index) => {
1870
+ const t = index / (count - 1);
1871
+ const shape = vertical ? {
1872
+ x: box.x + offset,
1873
+ y: box.y + box.height - reach - t * (box.height - reach * 2) - TICK_THICKNESS / 2,
1874
+ width: TICK_LENGTH,
1875
+ height: TICK_THICKNESS,
1876
+ rx: TICK_THICKNESS / 2
1877
+ } : {
1878
+ x: box.x + reach + t * (box.width - reach * 2) - TICK_THICKNESS / 2,
1879
+ y: box.y + offset,
1880
+ width: TICK_THICKNESS,
1881
+ height: TICK_LENGTH,
1882
+ rx: TICK_THICKNESS / 2
1883
+ };
1884
+ return rect(component, box, `tick-${index}`, 0.15, shape, color);
1885
+ });
1886
+ }
1887
+ function buildLine(component, box, thumbs, vertical) {
1888
+ const reach = sliderReach("line", vertical ? box.width : box.height);
1889
+ const radius = reach * numberProperty2(component, "thumbSize") / 100;
1890
+ const thickness = Math.min(numberProperty2(component, "trackHeight"), vertical ? box.width : box.height);
1891
+ const mid = vertical ? box.x + box.width / 2 : box.y + box.height / 2;
1892
+ const along2 = (fraction) => vertical ? box.y + box.height - reach - fraction * (box.height - reach * 2) : box.x + reach + fraction * (box.width - reach * 2);
1893
+ const line = (start, end) => vertical ? {
1894
+ x: mid - thickness / 2,
1895
+ y: Math.min(start, end),
1896
+ width: thickness,
1897
+ height: Math.abs(end - start),
1898
+ rx: thickness / 2
1899
+ } : {
1900
+ x: Math.min(start, end),
1901
+ y: mid - thickness / 2,
1902
+ width: Math.abs(end - start),
1903
+ height: thickness,
1904
+ rx: thickness / 2
1905
+ };
1906
+ const whole = vertical ? line(box.y, box.y + box.height) : line(box.x, box.x + box.width);
1907
+ const filled = line(thumbs.two ? along2(thumbs.from) : vertical ? box.y + box.height : box.x, along2(thumbs.to));
1908
+ const thumb = (part, fraction, order) => {
1909
+ const cx = vertical ? mid : along2(fraction);
1910
+ const cy = vertical ? along2(fraction) : mid;
1911
+ return {
1912
+ id: `widget-${component.id}-${part}`,
1913
+ type: "ellipse",
1914
+ order: box.order + order,
1915
+ bounds: rotatedBounds({ x: cx - radius, y: cy - radius, width: radius * 2, height: radius * 2 }, 0, 0),
1916
+ cx,
1917
+ cy,
1918
+ rx: radius,
1919
+ ry: radius,
1920
+ style: fade(component, {
1921
+ fill: solid(textProperty(component, "thumb")),
1922
+ stroke: { kind: "none" },
1923
+ shadow: { color: "#000000", opacity: 0.25, blur: 3, dx: 0, dy: 1 }
1924
+ })
1925
+ };
1926
+ };
1927
+ return [
1928
+ rect(component, box, "track", 0.1, whole, textProperty(component, "track")),
1929
+ ...ticks(
1930
+ component,
1931
+ box,
1932
+ vertical,
1933
+ reach,
1934
+ vertical ? box.width / 2 + thickness / 2 + 5 : box.height / 2 + thickness / 2 + 5
1935
+ ),
1936
+ rect(component, box, "fill", 0.2, filled, textProperty(component, "accent")),
1937
+ ...thumbs.two ? [thumb("thumb-start", thumbs.from, 0.3)] : [],
1938
+ thumb(thumbs.two ? "thumb-end" : "thumb", thumbs.to, 0.31)
1939
+ ];
1940
+ }
1941
+ function buildField(component, box, thumbs, vertical) {
1942
+ const reach = sliderReach("field", vertical ? box.width : box.height);
1943
+ const radius = Math.min(numberProperty2(component, "radius"), Math.min(box.width, box.height) / 2);
1944
+ const whole = { x: box.x, y: box.y, width: box.width, height: box.height, rx: radius };
1945
+ const along2 = (fraction) => vertical ? box.y + box.height - reach - fraction * (box.height - reach * 2) : box.x + reach + fraction * (box.width - reach * 2);
1946
+ const start = thumbs.two ? along2(thumbs.from) : vertical ? box.y + box.height : box.x;
1947
+ const end = along2(thumbs.to);
1948
+ const first = Math.min(start, end) - (thumbs.two ? HANDLE_WIDTH / 2 : 0);
1949
+ const last = Math.max(start, end) + HANDLE_WIDTH / 2;
1950
+ const filled = vertical ? {
1951
+ ...whole,
1952
+ y: thumbs.two ? first : end - HANDLE_WIDTH / 2,
1953
+ height: thumbs.two ? last - first : Math.max(0, box.y + box.height - end + HANDLE_WIDTH / 2),
1954
+ rx: thumbs.two ? 0 : radius
1955
+ } : {
1956
+ ...whole,
1957
+ x: thumbs.two ? first : box.x,
1958
+ width: thumbs.two ? last - first : Math.max(0, end + HANDLE_WIDTH / 2 - box.x),
1959
+ rx: thumbs.two ? 0 : radius
1960
+ };
1961
+ const handleLength = (vertical ? box.width : box.height) * 0.5;
1962
+ const handle = (part, at) => {
1963
+ const shape = vertical ? {
1964
+ x: box.x + (box.width - handleLength) / 2,
1965
+ y: at - HANDLE_WIDTH / 2,
1966
+ width: handleLength,
1967
+ height: HANDLE_WIDTH,
1968
+ rx: HANDLE_WIDTH / 2
1969
+ } : {
1970
+ x: at - HANDLE_WIDTH / 2,
1971
+ y: box.y + (box.height - handleLength) / 2,
1972
+ width: HANDLE_WIDTH,
1973
+ height: handleLength,
1974
+ rx: HANDLE_WIDTH / 2
1975
+ };
1976
+ return rect(component, box, part, 0.3, shape, textProperty(component, "accent"));
1977
+ };
1978
+ const nodes = [
1979
+ rect(component, box, "track", 0.1, whole, textProperty(component, "surface")),
1980
+ rect(component, box, "fill", 0.2, filled, textProperty(component, "fill")),
1981
+ ...thumbs.two ? [handle("handle-start", start)] : [],
1982
+ handle(thumbs.two ? "handle-end" : "handle", end)
1983
+ ];
1984
+ const text = {
1985
+ color: ink(component, textProperty(component, "textColor")),
1986
+ fontSize: numberProperty2(component, "fontSize")
1987
+ };
1988
+ const value = readout3(component, thumbs);
1989
+ if (vertical) {
1990
+ if (value) {
1991
+ nodes.push(
1992
+ labelText(
1993
+ component,
1994
+ "value",
1995
+ { x: box.x, y: box.y + 6, width: box.width, height: 20 },
1996
+ { ...text, text: value, align: "center" },
1997
+ box.order + 0.4
1998
+ )
1999
+ );
2000
+ }
2001
+ return nodes;
2002
+ }
2003
+ const inner = { y: box.y, height: box.height, width: Math.max(0, box.width / 2 - TEXT_PADDING) };
2004
+ if (component.label) {
2005
+ nodes.push(
2006
+ labelText(
2007
+ component,
2008
+ "label",
2009
+ { x: box.x + TEXT_PADDING, ...inner },
2010
+ { ...text, text: component.label, align: "left" },
2011
+ box.order + 0.4
2012
+ )
2013
+ );
2014
+ }
2015
+ if (value) {
2016
+ nodes.push(
2017
+ labelText(
2018
+ component,
2019
+ "value",
2020
+ { x: box.x + box.width / 2, ...inner },
2021
+ { ...text, text: value, align: "right" },
2022
+ box.order + 0.4
2023
+ )
2024
+ );
2025
+ }
2026
+ nodes.push(...ticks(component, box, false, reach, box.height - TICK_LENGTH - 5));
2027
+ return nodes;
2028
+ }
2029
+ function buildSlider(component, index) {
2030
+ const field = textProperty(component, "variant") === "field";
2031
+ const vertical = textProperty(component, "direction") === "vertical";
2032
+ const fallback = vertical ? { width: field ? 56 : 28, height: 180 } : { width: 220, height: field ? 36 : 28 };
2033
+ const box = controlBox(component, index, fallback);
2034
+ const min = numberProperty2(component, "min");
2035
+ const max = numberProperty2(component, "max");
2036
+ const fractionOf = (value) => Math.min(1, Math.max(0, (value - min) / (max - min || 1)));
2037
+ const two = component.type === "range";
2038
+ const low = Number(component.value);
2039
+ const high = two ? Number(component.properties.valueEnd ?? max) : low;
2040
+ const thumbs = {
2041
+ from: fractionOf(two ? Math.min(low, high) : min),
2042
+ to: fractionOf(two ? Math.max(low, high) : low),
2043
+ values: two ? [Math.min(low, high), Math.max(low, high)] : [low],
2044
+ two
2045
+ };
2046
+ return [
2047
+ hitArea(component, box),
2048
+ ...field ? buildField(component, box, thumbs, vertical) : buildLine(component, box, thumbs, vertical)
2049
+ ];
2050
+ }
2051
+
1583
2052
  // src/renderScene/artifacts/component/switch.ts
1584
2053
  var PADDING_RATIO = 0.12;
1585
2054
  function buildSwitch(component, index) {
@@ -1668,7 +2137,12 @@ var builders = /* @__PURE__ */ new Map([
1668
2137
  ["switch", asComponentBuilder(buildSwitch)],
1669
2138
  ["checkbox", asComponentBuilder(buildCheckbox)],
1670
2139
  ["toggleButton", asComponentBuilder(buildToggleButton)],
1671
- ["button", asComponentBuilder(buildButton)]
2140
+ ["button", asComponentBuilder(buildButton)],
2141
+ ["slider", asComponentBuilder(buildSlider)],
2142
+ ["progress", asComponentBuilder(buildProgress)],
2143
+ ["segmented", asComponentBuilder(buildSegmented)],
2144
+ ["knob", asComponentBuilder(buildKnob)],
2145
+ ["range", asComponentBuilder(buildSlider)]
1672
2146
  ]);
1673
2147
  function registerComponentBuilder(type, builder) {
1674
2148
  builders.set(type, builder);
@@ -3073,6 +3547,52 @@ function renderShapeGeometry(context) {
3073
3547
  return renderer(context);
3074
3548
  }
3075
3549
 
3550
+ // src/renderScene/artifacts/shape/shaderSurface.ts
3551
+ var RECT_PROGRAMS = /* @__PURE__ */ new Set([
3552
+ "reactivePanel",
3553
+ "ledMatrix",
3554
+ "lightBand",
3555
+ "silkFolds",
3556
+ "glowCard"
3557
+ ]);
3558
+ function shaderMask(context) {
3559
+ if (context.shape.shapeType === "circle" || context.shape.shapeType === "oval") {
3560
+ return "ellipse";
3561
+ }
3562
+ const rectangular = context.shape.shapeType === "rectangle" || context.shape.shapeType === "rounded_rectangle";
3563
+ if (rectangular && context.shape.shader && RECT_PROGRAMS.has(context.shape.shader.program)) {
3564
+ return "rect";
3565
+ }
3566
+ return void 0;
3567
+ }
3568
+ function renderShapeShaderSurface(context) {
3569
+ if (!context.shape.shader) {
3570
+ return void 0;
3571
+ }
3572
+ const mask = shaderMask(context);
3573
+ if (!mask) {
3574
+ return void 0;
3575
+ }
3576
+ const padding = mask === "rect" ? Math.max(0, context.shape.shader.surfacePadding ?? 0) : 0;
3577
+ const surfaceBounds = {
3578
+ x: context.x - padding,
3579
+ y: context.y - padding,
3580
+ width: context.width + padding * 2,
3581
+ height: context.height + padding * 2
3582
+ };
3583
+ return {
3584
+ id: `${context.id}-shader`,
3585
+ type: "shader-surface",
3586
+ order: context.order,
3587
+ bounds: rotatedBounds(surfaceBounds, context.rotation, 0),
3588
+ ...surfaceBounds,
3589
+ rotation: context.rotation,
3590
+ shader: context.shape.shader,
3591
+ mask,
3592
+ fillColor: context.style.fill?.kind === "solid" ? context.style.fill.color : void 0
3593
+ };
3594
+ }
3595
+
3076
3596
  // src/renderScene/artifacts/shape/style.ts
3077
3597
  var REMOVED_SHAPE_HINTS = {
3078
3598
  container_rectangle: " (use 'rectangle' with strokeStyle: dashed)"
@@ -3315,32 +3835,13 @@ function createRenderContext(shape, index, diagnostics) {
3315
3835
  }
3316
3836
  };
3317
3837
  }
3318
- function renderShaderSurface(context) {
3319
- if (!context.shape.shader || context.shape.shapeType !== "circle" && context.shape.shapeType !== "oval") {
3320
- return void 0;
3321
- }
3322
- return {
3323
- id: `${context.id}-shader`,
3324
- type: "shader-surface",
3325
- order: context.order,
3326
- bounds: context.bounds,
3327
- x: context.x,
3328
- y: context.y,
3329
- width: context.width,
3330
- height: context.height,
3331
- rotation: context.rotation,
3332
- shader: context.shape.shader,
3333
- mask: "ellipse",
3334
- fillColor: context.style.fill?.kind === "solid" ? context.style.fill.color : void 0
3335
- };
3336
- }
3337
3838
  function buildShape(shape, index, diagnostics, measureText) {
3338
3839
  if (shape.isVisible === false) {
3339
3840
  return [];
3340
3841
  }
3341
3842
  const { context, strokeWidth } = createRenderContext(shape, index, diagnostics);
3342
3843
  const nodes = shape.strokeStyle === "double" ? renderDoubleStroke(context, strokeWidth || 1) : renderShapeGeometry(context);
3343
- const shader = renderShaderSurface(context);
3844
+ const shader = renderShapeShaderSurface(context);
3344
3845
  if (shader) {
3345
3846
  for (const node of nodes) {
3346
3847
  if (node.type === "ellipse" || node.type === "path" || node.type === "rect") {
@@ -3572,6 +4073,12 @@ function hasCartesianDecorations(chart) {
3572
4073
  function tickOffset(chart) {
3573
4074
  return hasCartesianDecorations(chart) ? Math.max(0, finite(chart.tickLength, 0)) : 0;
3574
4075
  }
4076
+ function xLabelOffset(chart) {
4077
+ return tickOffset(chart) + (hasCartesianDecorations(chart) ? Math.max(0, finite(chart.xLabelGap, 0)) : 0);
4078
+ }
4079
+ function yLabelOffset(chart) {
4080
+ return tickOffset(chart) + (hasCartesianDecorations(chart) ? Math.max(0, finite(chart.yLabelGap, 0)) : 0);
4081
+ }
3575
4082
  function isHorizontalBoxplot(chart) {
3576
4083
  return chart.chartType === "boxplot" && chart.config?.orientation === "horizontal";
3577
4084
  }
@@ -3593,6 +4100,9 @@ function barCategoryLabelWidth(chart) {
3593
4100
  return Math.max(0, ...categories.map((category) => category.length)) * fontSize * 0.58 + 16;
3594
4101
  }
3595
4102
  function leftLabelWidth(chart) {
4103
+ if (chart.axisLabelSpace && chart.axisLabelSpace > 0 && (isHorizontalBoxplot(chart) || isHorizontalBar(chart))) {
4104
+ return chart.axisLabelSpace;
4105
+ }
3596
4106
  if (isHorizontalBoxplot(chart)) {
3597
4107
  return boxplotCategoryLabelWidth(chart);
3598
4108
  }
@@ -3604,6 +4114,14 @@ function leftLabelWidth(chart) {
3604
4114
  }
3605
4115
  return chart.axisY.label ? 60 : 46;
3606
4116
  }
4117
+ function tiltedBottomRoom(chart) {
4118
+ const tilt = labelTilt(chart);
4119
+ if (tilt <= 0) {
4120
+ return 0;
4121
+ }
4122
+ const labels = chart.chartType === "bar" && !isHorizontalBar(chart) ? chart.config?.categories ?? [] : chart.chartType === "boxplot" && !isHorizontalBoxplot(chart) ? chart.series.map((series) => series.label || series.id) : [];
4123
+ return labels.length > 0 ? Math.max(0, tiltedLabelRoom(chart, labels, tilt) - 18) : 0;
4124
+ }
3607
4125
  function decorations(chart) {
3608
4126
  const showLabels = chart.showAxisLabels !== false;
3609
4127
  const showLegend = chart.showLegend !== false;
@@ -3613,15 +4131,16 @@ function decorations(chart) {
3613
4131
  const legendStacked = hasLegendItems && isStackedLegendPosition(legendPosition);
3614
4132
  const sideColumnWidth = legendStacked ? stackedLegendColumnWidth(chart) + LEGEND_COLUMN_GAP : 0;
3615
4133
  const treemapSide = treemapSideLegendSide(chart, showLegend);
3616
- const tick = tickOffset(chart);
3617
- const padLeft = tick + (showLabels ? leftLabelWidth(chart) : 12) + (legendPosition === "bottomLeft" ? sideColumnWidth : 0) + (treemapSide === "left" ? TREEMAP_SIDE_LEGEND_WIDTH : 0);
4134
+ const tickX = xLabelOffset(chart);
4135
+ const tickY = yLabelOffset(chart);
4136
+ const padLeft = tickY + (showLabels ? leftLabelWidth(chart) : 12) + (legendPosition === "bottomLeft" ? sideColumnWidth : 0) + (treemapSide === "left" ? TREEMAP_SIDE_LEGEND_WIDTH : 0);
3618
4137
  const padRight = 24 + (legendPosition === "bottomRight" ? sideColumnWidth : 0) + (treemapSide === "right" ? TREEMAP_SIDE_LEGEND_WIDTH : 0);
3619
4138
  const valueRow = chart.chartType === "bar" && chart.config?.showBarLabels === true && chart.config.barLabelPosition === "axis";
3620
4139
  const horizontalValueAxis = isHorizontalBar(chart) && chart.showValueAxis !== false;
3621
4140
  const basePadBottom = showLabels ? isHorizontalBar(chart) ? horizontalValueAxis ? 34 : 12 : (chart.axisX.label ? 52 : 34) + (valueRow ? 18 : 0) : 12;
3622
4141
  const hasColorBar = chart.chartType === "field" && showLegend && Boolean(chart.config?.scale?.stops.length);
3623
4142
  const legendAtBottomRow = hasLegendItems && !legendAtTop && !legendStacked;
3624
- const padBottom = tick + basePadBottom + (hasColorBar ? 44 : 0) + (legendAtBottomRow ? 16 + LEGEND_ROW_HEIGHT : 0);
4143
+ const padBottom = tickX + basePadBottom + (showLabels ? tiltedBottomRoom(chart) : 0) + (hasColorBar ? 44 : 0) + (legendAtBottomRow ? 16 + LEGEND_ROW_HEIGHT : 0);
3625
4144
  const titleHeight = chart.title ? Math.max(44, 20 + finite(chart.titleSize, 14) * 1.6) : 0;
3626
4145
  const padTop = titleHeight || (legendAtTop && hasLegendItems ? 44 : 24);
3627
4146
  return {
@@ -3653,6 +4172,7 @@ function buildCategoricalXAxisTicks(chart, layout, order) {
3653
4172
  const slotWidth = layout.plot.width / count;
3654
4173
  const labels = categoryLabels(chart, count);
3655
4174
  const editable = Boolean(chart.config?.categories?.length);
4175
+ const tilt = labelTilt(chart);
3656
4176
  const left = chart.categoryAlign === "left";
3657
4177
  const groupGap = left ? Math.min(
3658
4178
  Math.max(0, finite(chart.config?.barGroupGap, 8)),
@@ -3660,6 +4180,27 @@ function buildCategoricalXAxisTicks(chart, layout, order) {
3660
4180
  ) : 0;
3661
4181
  return Array.from({ length: count }, (_value, index) => {
3662
4182
  const centerX = layout.plot.x + (index + 0.5) * slotWidth;
4183
+ if (tilt > 0) {
4184
+ const text = labels[index] ?? String(index + 1);
4185
+ const { frame, rotation } = labelBelowFrame(chart, text, tilt, {
4186
+ x: centerX,
4187
+ y: layout.plot.y + layout.plot.height + 4 + xLabelOffset(chart)
4188
+ });
4189
+ return {
4190
+ ...chartText({
4191
+ role: "axis",
4192
+ id: `chart-x-tick-${chart.id}-${index}`,
4193
+ order: order + index,
4194
+ bounds: layout.bounds,
4195
+ frame,
4196
+ text,
4197
+ chart,
4198
+ align: "right",
4199
+ rotation
4200
+ }),
4201
+ prop: editable ? categoryProp(index) : void 0
4202
+ };
4203
+ }
3663
4204
  return {
3664
4205
  ...chartText({
3665
4206
  role: "axis",
@@ -3668,7 +4209,7 @@ function buildCategoricalXAxisTicks(chart, layout, order) {
3668
4209
  bounds: layout.bounds,
3669
4210
  frame: {
3670
4211
  x: left ? layout.plot.x + index * slotWidth + groupGap / 2 : centerX - slotWidth / 2,
3671
- y: layout.plot.y + layout.plot.height + 4 + tickOffset(chart),
4212
+ y: layout.plot.y + layout.plot.height + 4 + xLabelOffset(chart),
3672
4213
  width: left ? slotWidth - groupGap : slotWidth,
3673
4214
  height: 18
3674
4215
  },
@@ -3683,8 +4224,30 @@ function buildCategoricalXAxisTicks(chart, layout, order) {
3683
4224
  function buildSeriesXAxisTicks(chart, layout, order) {
3684
4225
  const count = Math.max(1, chart.series.length);
3685
4226
  const slotWidth = layout.plot.width / count;
4227
+ const tilt = labelTilt(chart);
3686
4228
  return chart.series.map((series, index) => {
3687
4229
  const centerX = layout.plot.x + (index + 0.5) * slotWidth;
4230
+ if (tilt > 0) {
4231
+ const text = series.label || series.id;
4232
+ const { frame, rotation } = labelBelowFrame(chart, text, tilt, {
4233
+ x: centerX,
4234
+ y: layout.plot.y + layout.plot.height + 4 + xLabelOffset(chart)
4235
+ });
4236
+ return {
4237
+ ...chartText({
4238
+ role: "axis",
4239
+ id: `chart-x-tick-${chart.id}-${index}`,
4240
+ order: order + index,
4241
+ bounds: layout.bounds,
4242
+ frame,
4243
+ text,
4244
+ chart,
4245
+ align: "right",
4246
+ rotation
4247
+ }),
4248
+ prop: seriesLabelProp(series.id)
4249
+ };
4250
+ }
3688
4251
  return {
3689
4252
  ...chartText({
3690
4253
  role: "axis",
@@ -3693,7 +4256,7 @@ function buildSeriesXAxisTicks(chart, layout, order) {
3693
4256
  bounds: layout.bounds,
3694
4257
  frame: {
3695
4258
  x: centerX - slotWidth / 2,
3696
- y: layout.plot.y + layout.plot.height + 4 + tickOffset(chart),
4259
+ y: layout.plot.y + layout.plot.height + 4 + xLabelOffset(chart),
3697
4260
  width: slotWidth,
3698
4261
  height: 18
3699
4262
  },
@@ -3715,7 +4278,7 @@ function buildNumericXAxisTicks(chart, layout, order) {
3715
4278
  id: `chart-x-tick-${chart.id}-${tick}`,
3716
4279
  order: order + index,
3717
4280
  bounds: layout.bounds,
3718
- frame: { x: x - 20, y: layout.plot.y + layout.plot.height + 10 + tickOffset(chart), width: 40, height: 18 },
4281
+ frame: { x: x - 20, y: layout.plot.y + layout.plot.height + 10 + xLabelOffset(chart), width: 40, height: 18 },
3719
4282
  text: String(tick),
3720
4283
  chart,
3721
4284
  align: "center"
@@ -3732,7 +4295,7 @@ function buildNumericYAxisTicks(chart, layout, order) {
3732
4295
  id: `chart-y-tick-${chart.id}-${tick}`,
3733
4296
  order: order + index,
3734
4297
  bounds: layout.bounds,
3735
- frame: { x: chart.x, y: y - 6, width: layout.padLeft - 14 - tickOffset(chart), height: 18 },
4298
+ frame: { x: chart.x, y: y - 6, width: layout.padLeft - 14 - yLabelOffset(chart), height: 18 },
3736
4299
  text: String(tick),
3737
4300
  chart,
3738
4301
  align: "right"
@@ -4172,19 +4735,19 @@ function buildChartBackdrop(chart, bounds, order) {
4172
4735
  if (!chart.fillImage) {
4173
4736
  return [];
4174
4737
  }
4175
- const rect = chartImageRect(chart);
4738
+ const rect2 = chartImageRect(chart);
4176
4739
  const nodes = [
4177
4740
  {
4178
4741
  type: "image",
4179
4742
  id: `chart-image-${chart.id}`,
4180
4743
  order: order.next(),
4181
4744
  bounds,
4182
- x: rect.x,
4183
- y: rect.y,
4184
- width: rect.width,
4185
- height: rect.height,
4745
+ x: rect2.x,
4746
+ y: rect2.y,
4747
+ width: rect2.width,
4748
+ height: rect2.height,
4186
4749
  href: chart.fillImage.url,
4187
- style: { clip: { type: "rect", ...rect }, pointerEvents: "none" }
4750
+ style: { clip: { type: "rect", ...rect2 }, pointerEvents: "none" }
4188
4751
  }
4189
4752
  ];
4190
4753
  if (chart.fillImage.overlay) {
@@ -4193,11 +4756,11 @@ function buildChartBackdrop(chart, bounds, order) {
4193
4756
  id: `chart-image-overlay-${chart.id}`,
4194
4757
  order: order.next(),
4195
4758
  bounds,
4196
- x: rect.x,
4197
- y: rect.y,
4198
- width: rect.width,
4199
- height: rect.height,
4200
- rx: rect.rx,
4759
+ x: rect2.x,
4760
+ y: rect2.y,
4761
+ width: rect2.width,
4762
+ height: rect2.height,
4763
+ rx: rect2.rx,
4201
4764
  style: { fill: { kind: "solid", color: chart.fillImage.overlay }, pointerEvents: "none" }
4202
4765
  });
4203
4766
  }
@@ -4211,17 +4774,17 @@ function createGlassBackdropNodes(context, id, d) {
4211
4774
  if (blur <= 0 || !chart.fillImage) {
4212
4775
  return [];
4213
4776
  }
4214
- const rect = chartImageRect(chart);
4777
+ const rect2 = chartImageRect(chart);
4215
4778
  const nodes = [
4216
4779
  {
4217
4780
  type: "image",
4218
4781
  id: `chart-bar-glass-${chart.id}-${id}`,
4219
4782
  order: nextOrder(),
4220
4783
  bounds,
4221
- x: rect.x,
4222
- y: rect.y,
4223
- width: rect.width,
4224
- height: rect.height,
4784
+ x: rect2.x,
4785
+ y: rect2.y,
4786
+ width: rect2.width,
4787
+ height: rect2.height,
4225
4788
  href: chart.fillImage.url,
4226
4789
  style: {
4227
4790
  blur,
@@ -5806,92 +6369,74 @@ function createCellValueLabel(context, layout, cell) {
5806
6369
  };
5807
6370
  }
5808
6371
 
5809
- // src/renderScene/charts/renderers/heatmap/headers.ts
5810
- function renderHeatmapHeaders(context, layout) {
5811
- return [...renderRowHeaders(context, layout), ...renderColumnHeaders(context, layout)];
5812
- }
5813
- function renderRowHeaders(context, layout) {
5814
- if (layout.reservedSpace.rowHeaders <= 0) {
5815
- return [];
5816
- }
5817
- return layout.rows.map((series, rowIndex) => createRowHeader(context, layout, series, rowIndex));
5818
- }
5819
- function createRowHeader(context, layout, series, rowIndex) {
5820
- const { chart, plot, bounds, nextOrder } = context;
5821
- return chartText({
5822
- id: `chart-heatmap-row-${chart.id}-${series.id}`,
5823
- order: nextOrder(),
5824
- bounds,
5825
- frame: {
5826
- x: plot.x,
5827
- y: layout.grid.y + rowIndex * layout.grid.cellHeight + layout.grid.cellHeight / 2 - layout.fontSize / 2,
5828
- width: layout.reservedSpace.rowHeaders - 8,
5829
- height: layout.fontSize + 2
5830
- },
5831
- text: series.label,
5832
- chart
5833
- });
5834
- }
5835
- function renderColumnHeaders(context, layout) {
5836
- if (layout.reservedSpace.columnHeaders <= 0) {
5837
- return [];
5838
- }
5839
- return layout.columns.map((label, columnIndex) => createColumnHeader(context, layout, label, columnIndex));
5840
- }
5841
- function createColumnHeader(context, layout, label, columnIndex) {
5842
- const { chart, plot, bounds, nextOrder } = context;
5843
- return chartText({
5844
- id: `chart-heatmap-col-${chart.id}-${columnIndex}`,
5845
- order: nextOrder(),
5846
- bounds,
5847
- frame: {
5848
- x: layout.grid.x + columnIndex * layout.grid.cellWidth,
5849
- y: plot.y,
5850
- width: layout.grid.cellWidth,
5851
- height: layout.fontSize + 2
5852
- },
5853
- text: label,
5854
- chart,
5855
- align: "center"
5856
- });
5857
- }
5858
-
5859
6372
  // src/renderScene/charts/renderers/heatmap/layout.ts
5860
6373
  function createHeatmapLayout(context) {
5861
6374
  const { chart } = context;
5862
6375
  const columns = heatmapColumns(context);
5863
- const reservedSpace = heatmapReservedSpace(context);
6376
+ const sides = heatmapSides(context);
6377
+ const reservedSpace = heatmapReservedSpace(context, sides);
5864
6378
  return {
5865
6379
  rows: chart.series,
5866
6380
  columns,
5867
6381
  bands: axisBands(chart.axisY),
5868
6382
  zones: chart.config?.zones?.length ? chart.config.zones : DEFAULT_HEATMAP_ZONES,
5869
6383
  fontSize: Math.max(9, finite(chart.fontSize, 12)),
6384
+ headerFontSize: headerFontSize(chart),
6385
+ legendGap: legendGap(chart),
6386
+ sides,
5870
6387
  reservedSpace,
5871
- grid: createHeatmapGrid(context, reservedSpace, columns.length)
6388
+ grid: createHeatmapGrid(context, reservedSpace, sides, columns.length)
6389
+ };
6390
+ }
6391
+ var headerFontSize = (chart) => Math.max(9, finite(chart.axisFontSize ?? chart.fontSize, 12));
6392
+ var rowGap = (chart) => Math.min(120, Math.max(0, finite(chart.yLabelGap, 6)));
6393
+ var columnGap = (chart) => Math.min(120, Math.max(0, finite(chart.xLabelGap, 4)));
6394
+ var legendGap = (chart) => Math.min(80, Math.max(0, finite(chart.legendGap, 6)));
6395
+ function heatmapSides(context) {
6396
+ const { chart } = context;
6397
+ return {
6398
+ rows: chart.rowLabelSide === "right" ? "right" : "left",
6399
+ columns: chart.columnLabelSide === "bottom" ? "bottom" : "top",
6400
+ legend: chart.legendSide ?? "bottom"
5872
6401
  };
5873
6402
  }
5874
6403
  function heatmapColumns(context) {
5875
6404
  const { chart } = context;
5876
6405
  return chart.config?.categories?.length ? chart.config.categories : chart.series[0]?.values?.map((_, index) => String(index + 1)) ?? [];
5877
6406
  }
5878
- function heatmapReservedSpace(context) {
6407
+ var LEGEND_ACROSS = 32;
6408
+ var LEGEND_BESIDE = 56;
6409
+ function heatmapReservedSpace(context, sides) {
5879
6410
  const { chart } = context;
5880
- const fontSize = Math.max(9, finite(chart.fontSize, 12));
6411
+ const fontSize = headerFontSize(chart);
5881
6412
  const longestLabel = chart.series.reduce(
5882
6413
  (max, series) => Math.max(max, estimateTextWidth(series.label ?? "", fontSize, false)),
5883
6414
  0
5884
6415
  );
6416
+ const vertical = sides.legend === "left" || sides.legend === "right";
5885
6417
  return {
5886
- rowHeaders: context.showLabels ? Math.min(96, longestLabel + 12) : 0,
5887
- columnHeaders: context.showLabels ? 24 : 0,
5888
- legend: context.showLegend ? 38 : 0
6418
+ // The names get the room they ask for, or as much as the longest needs. They never take more than most of the plot.
6419
+ rowHeaders: context.showLabels ? Math.min(
6420
+ context.plot.width * 0.7,
6421
+ chart.axisLabelSpace && chart.axisLabelSpace > 0 ? chart.axisLabelSpace : longestLabel + 6 + rowGap(chart)
6422
+ ) : 0,
6423
+ columnHeaders: context.showLabels ? columnHeaderRoom(context) : 0,
6424
+ legend: context.showLegend ? (vertical ? LEGEND_BESIDE : LEGEND_ACROSS) + legendGap(chart) : 0
5889
6425
  };
5890
6426
  }
5891
- function createHeatmapGrid(context, reservedSpace, columnCount) {
6427
+ function columnHeaderRoom(context) {
6428
+ const { chart } = context;
6429
+ const tilt = labelTilt(chart);
6430
+ return tilt > 0 ? Math.min(context.plot.height * 0.4, tiltedLabelRoom(chart, heatmapColumns(context), tilt) + columnGap(chart) + 4) : headerFontSize(chart) + 2 + columnGap(chart) + 6;
6431
+ }
6432
+ function createHeatmapGrid(context, reservedSpace, sides, columnCount) {
5892
6433
  const { chart } = context;
5893
- const width = Math.max(1, context.plot.width - reservedSpace.rowHeaders);
5894
- const height = Math.max(1, context.plot.height - reservedSpace.columnHeaders - reservedSpace.legend);
6434
+ const left = (sides.rows === "left" ? reservedSpace.rowHeaders : 0) + (sides.legend === "left" ? reservedSpace.legend : 0);
6435
+ const right = (sides.rows === "right" ? reservedSpace.rowHeaders : 0) + (sides.legend === "right" ? reservedSpace.legend : 0);
6436
+ const top = (sides.columns === "top" ? reservedSpace.columnHeaders : 0) + (sides.legend === "top" ? reservedSpace.legend : 0);
6437
+ const bottom = (sides.columns === "bottom" ? reservedSpace.columnHeaders : 0) + (sides.legend === "bottom" ? reservedSpace.legend : 0);
6438
+ const width = Math.max(1, context.plot.width - left - right);
6439
+ const height = Math.max(1, context.plot.height - top - bottom);
5895
6440
  const rowCount = chart.series.length;
5896
6441
  const cellGap = Math.max(0, finite(chart.config?.cellGap, 0));
5897
6442
  let cellWidth = columnCount ? width / columnCount : width;
@@ -5906,8 +6451,8 @@ function createHeatmapGrid(context, reservedSpace, columnCount) {
5906
6451
  gridHeight = cellSize * rowCount;
5907
6452
  }
5908
6453
  return {
5909
- x: context.plot.x + reservedSpace.rowHeaders,
5910
- y: context.plot.y + reservedSpace.columnHeaders,
6454
+ x: context.plot.x + left,
6455
+ y: context.plot.y + top,
5911
6456
  width: gridWidth,
5912
6457
  height: gridHeight,
5913
6458
  cellWidth,
@@ -5917,30 +6462,151 @@ function createHeatmapGrid(context, reservedSpace, columnCount) {
5917
6462
  };
5918
6463
  }
5919
6464
 
6465
+ // src/renderScene/charts/renderers/heatmap/headers.ts
6466
+ function renderHeatmapHeaders(context, layout) {
6467
+ return [...renderRowHeaders(context, layout), ...renderColumnHeaders(context, layout)];
6468
+ }
6469
+ function renderRowHeaders(context, layout) {
6470
+ if (layout.reservedSpace.rowHeaders <= 0) {
6471
+ return [];
6472
+ }
6473
+ return layout.rows.map((series, rowIndex) => createRowHeader(context, layout, series, rowIndex));
6474
+ }
6475
+ function createRowHeader(context, layout, series, rowIndex) {
6476
+ const { chart, bounds, nextOrder } = context;
6477
+ const room = layout.reservedSpace.rowHeaders;
6478
+ const gap = rowGap(chart);
6479
+ const x = layout.sides.rows === "left" ? layout.grid.x - room : layout.grid.x + layout.grid.width + gap;
6480
+ return chartText({
6481
+ id: `chart-heatmap-row-${chart.id}-${series.id}`,
6482
+ order: nextOrder(),
6483
+ bounds,
6484
+ frame: {
6485
+ x,
6486
+ y: layout.grid.y + rowIndex * layout.grid.cellHeight + layout.grid.cellHeight / 2 - layout.headerFontSize / 2,
6487
+ width: Math.max(1, room - gap),
6488
+ height: layout.headerFontSize + 2
6489
+ },
6490
+ text: series.label,
6491
+ chart,
6492
+ align: chart.axisLabelAlign ?? "left",
6493
+ role: "axis"
6494
+ });
6495
+ }
6496
+ function renderColumnHeaders(context, layout) {
6497
+ if (layout.reservedSpace.columnHeaders <= 0) {
6498
+ return [];
6499
+ }
6500
+ return layout.columns.map((label, columnIndex) => createColumnHeader(context, layout, label, columnIndex));
6501
+ }
6502
+ function createColumnHeader(context, layout, label, columnIndex) {
6503
+ const { chart, bounds, nextOrder } = context;
6504
+ const above = layout.sides.columns === "top";
6505
+ const centerX = layout.grid.x + (columnIndex + 0.5) * layout.grid.cellWidth;
6506
+ const tilt = labelTilt(chart);
6507
+ const gap = columnGap(chart);
6508
+ const id = `chart-heatmap-col-${chart.id}-${columnIndex}`;
6509
+ if (tilt > 0) {
6510
+ const { frame, rotation } = above ? labelAboveFrame(chart, label, tilt, { x: centerX, y: layout.grid.y - gap }) : labelBelowFrame(chart, label, tilt, { x: centerX, y: layout.grid.y + layout.grid.height + gap });
6511
+ return chartText({
6512
+ id,
6513
+ order: nextOrder(),
6514
+ bounds,
6515
+ frame,
6516
+ text: label,
6517
+ chart,
6518
+ align: above ? "left" : "right",
6519
+ rotation,
6520
+ role: "axis"
6521
+ });
6522
+ }
6523
+ return chartText({
6524
+ id,
6525
+ order: nextOrder(),
6526
+ bounds,
6527
+ frame: {
6528
+ x: layout.grid.x + columnIndex * layout.grid.cellWidth,
6529
+ y: above ? layout.grid.y - gap - (layout.headerFontSize + 2) : layout.grid.y + layout.grid.height + gap,
6530
+ width: layout.grid.cellWidth,
6531
+ height: layout.headerFontSize + 2
6532
+ },
6533
+ text: label,
6534
+ chart,
6535
+ align: "center",
6536
+ role: "axis"
6537
+ });
6538
+ }
6539
+
5920
6540
  // src/renderScene/charts/renderers/heatmap/legend.ts
5921
- var BAR_HEIGHT = 10;
5922
- var TICK_HEIGHT = 4;
6541
+ var BAR_THICKNESS = 10;
6542
+ var TICK_LENGTH2 = 4;
5923
6543
  var ROW_GAP = 2;
6544
+ var LABEL_WIDTH = 48;
6545
+ function barPlace(layout) {
6546
+ const { grid, sides, reservedSpace, legendGap: legendGap2 } = layout;
6547
+ const rowRoom = reservedSpace.rowHeaders;
6548
+ const columnRoom = reservedSpace.columnHeaders;
6549
+ switch (sides.legend) {
6550
+ case "top": {
6551
+ const edge = grid.y - (sides.columns === "top" ? columnRoom : 0);
6552
+ return {
6553
+ x: grid.x,
6554
+ y: edge - legendGap2 - BAR_THICKNESS,
6555
+ width: grid.width,
6556
+ height: BAR_THICKNESS,
6557
+ vertical: false,
6558
+ numbers: "top"
6559
+ };
6560
+ }
6561
+ case "left": {
6562
+ const edge = grid.x - (sides.rows === "left" ? rowRoom : 0);
6563
+ return {
6564
+ x: edge - legendGap2 - BAR_THICKNESS,
6565
+ y: grid.y,
6566
+ width: BAR_THICKNESS,
6567
+ height: grid.height,
6568
+ vertical: true,
6569
+ numbers: "left"
6570
+ };
6571
+ }
6572
+ case "right": {
6573
+ const edge = grid.x + grid.width + (sides.rows === "right" ? rowRoom : 0);
6574
+ return {
6575
+ x: edge + legendGap2,
6576
+ y: grid.y,
6577
+ width: BAR_THICKNESS,
6578
+ height: grid.height,
6579
+ vertical: true,
6580
+ numbers: "right"
6581
+ };
6582
+ }
6583
+ default: {
6584
+ const edge = grid.y + grid.height + (sides.columns === "bottom" ? columnRoom : 0);
6585
+ return {
6586
+ x: grid.x,
6587
+ y: edge + legendGap2,
6588
+ width: grid.width,
6589
+ height: BAR_THICKNESS,
6590
+ vertical: false,
6591
+ numbers: "bottom"
6592
+ };
6593
+ }
6594
+ }
6595
+ }
5924
6596
  function renderHeatmapLegend(context, layout) {
5925
6597
  if (layout.reservedSpace.legend <= 0 || layout.zones.length === 0) {
5926
6598
  return [];
5927
6599
  }
5928
- const barX = layout.grid.x;
5929
- const barWidth = layout.grid.width;
5930
- const labelHeight = layout.fontSize + 2;
5931
- const barY = layout.grid.y + layout.grid.height + 6;
5932
- const barBounds = boxBounds({ x: barX, y: barY, width: barWidth, height: BAR_HEIGHT });
5933
- return [
5934
- createGradientBar(context, layout, barX, barY, barWidth, barBounds),
5935
- ...createBoundaryTicks(context, layout, barX, barY, barWidth, labelHeight)
5936
- ];
6600
+ const place = barPlace(layout);
6601
+ const barBounds = boxBounds({ x: place.x, y: place.y, width: place.width, height: place.height });
6602
+ return [createGradientBar(context, layout, place, barBounds), ...createBoundaryTicks(context, layout, place)];
5937
6603
  }
5938
6604
  function bandRatio(layout, value) {
5939
6605
  const first = layout.bands[0];
5940
6606
  const last = layout.bands[layout.bands.length - 1];
5941
6607
  return last === first ? 0 : (value - first) / (last - first);
5942
6608
  }
5943
- function createGradientBar(context, layout, barX, barY, barWidth, barBounds) {
6609
+ function createGradientBar(context, layout, place, barBounds) {
5944
6610
  const { chart, nextOrder } = context;
5945
6611
  const bandCount = Math.max(0, layout.bands.length - 1);
5946
6612
  const zones = layout.zones.slice(0, bandCount);
@@ -5953,53 +6619,77 @@ function createGradientBar(context, layout, barX, barY, barWidth, barBounds) {
5953
6619
  id: `chart-heatmap-legend-bar-${chart.id}`,
5954
6620
  order: nextOrder(),
5955
6621
  bounds: barBounds,
5956
- x: barX,
5957
- y: barY,
5958
- width: barWidth,
5959
- height: BAR_HEIGHT,
6622
+ x: place.x,
6623
+ y: place.y,
6624
+ width: place.width,
6625
+ height: place.height,
5960
6626
  rx: 3,
5961
6627
  zoneGradient: { axis: "y", min: chart.axisY.min, max: chart.axisY.max },
5962
6628
  style: {
5963
- fill: stops.length ? { kind: "linear-gradient", angle: 0, stops } : { kind: "solid", color: DEFAULT_ZONE_FILL },
6629
+ // Across the grid it runs from the lowest value on the left; beside it from the lowest at the bottom.
6630
+ fill: stops.length ? { kind: "linear-gradient", angle: place.vertical ? 270 : 0, stops } : { kind: "solid", color: DEFAULT_ZONE_FILL },
5964
6631
  stroke: { kind: "solid", color: chart.gridColor ?? "#e2e8f0" },
5965
6632
  strokeWidth: 1
5966
6633
  }
5967
6634
  };
5968
6635
  }
5969
- function createBoundaryTicks(context, layout, barX, barY, barWidth, labelHeight) {
6636
+ function createBoundaryTicks(context, layout, place) {
5970
6637
  const { chart, bounds, nextOrder } = context;
5971
- const labelY = barY + BAR_HEIGHT + TICK_HEIGHT + ROW_GAP;
5972
- const labelWidth = 48;
6638
+ const labelHeight = layout.fontSize + 2;
6639
+ const lastIndex = layout.bands.length - 1;
5973
6640
  return layout.bands.flatMap((value, index) => {
5974
- const x = barX + bandRatio(layout, value) * barWidth;
6641
+ const ratio = bandRatio(layout, value);
6642
+ const at = place.vertical ? place.y + place.height - ratio * place.height : place.x + ratio * place.width;
6643
+ const tickPath = tickPathAt(place, at);
5975
6644
  const tick = {
5976
6645
  type: "path",
5977
6646
  id: `chart-heatmap-legend-tick-${chart.id}-${index}`,
5978
6647
  order: nextOrder(),
5979
6648
  bounds,
5980
- d: `M ${x} ${barY + BAR_HEIGHT} L ${x} ${barY + BAR_HEIGHT + TICK_HEIGHT}`,
6649
+ d: tickPath,
5981
6650
  style: {
5982
6651
  fill: { kind: "none" },
5983
6652
  stroke: { kind: "solid", color: chart.gridColor ?? "#e2e8f0" },
5984
6653
  strokeWidth: 1
5985
6654
  }
5986
6655
  };
5987
- const isFirst = index === 0;
5988
- const isLast = index === layout.bands.length - 1;
5989
- const align = isFirst ? "left" : isLast ? "right" : "center";
5990
- const frameX = isFirst ? x : isLast ? x - labelWidth : x - labelWidth / 2;
5991
6656
  const label = chartText({
5992
6657
  id: `chart-heatmap-legend-tick-label-${chart.id}-${index}`,
5993
6658
  order: nextOrder(),
5994
6659
  bounds,
5995
- frame: { x: frameX, y: labelY, width: labelWidth, height: labelHeight },
6660
+ ...labelAt(place, at, index === 0, index === lastIndex, labelHeight),
5996
6661
  text: formatFieldValue(value),
5997
- chart,
5998
- align
6662
+ chart
5999
6663
  });
6000
6664
  return [tick, label];
6001
6665
  });
6002
6666
  }
6667
+ function tickPathAt(place, at) {
6668
+ if (place.vertical) {
6669
+ const from2 = place.numbers === "right" ? place.x + place.width : place.x;
6670
+ const to2 = place.numbers === "right" ? from2 + TICK_LENGTH2 : from2 - TICK_LENGTH2;
6671
+ return `M ${from2} ${at} L ${to2} ${at}`;
6672
+ }
6673
+ const from = place.numbers === "bottom" ? place.y + place.height : place.y;
6674
+ const to = place.numbers === "bottom" ? from + TICK_LENGTH2 : from - TICK_LENGTH2;
6675
+ return `M ${at} ${from} L ${at} ${to}`;
6676
+ }
6677
+ function labelAt(place, at, first, last, labelHeight) {
6678
+ if (place.vertical) {
6679
+ const onRight = place.numbers === "right";
6680
+ const x2 = onRight ? place.x + place.width + TICK_LENGTH2 + ROW_GAP : place.x - TICK_LENGTH2 - ROW_GAP - LABEL_WIDTH;
6681
+ return {
6682
+ frame: { x: x2, y: at - labelHeight / 2, width: LABEL_WIDTH, height: labelHeight },
6683
+ align: onRight ? "left" : "right"
6684
+ };
6685
+ }
6686
+ const y = place.numbers === "bottom" ? place.y + place.height + TICK_LENGTH2 + ROW_GAP : place.y - TICK_LENGTH2 - ROW_GAP - labelHeight;
6687
+ const x = first ? at : last ? at - LABEL_WIDTH : at - LABEL_WIDTH / 2;
6688
+ return {
6689
+ frame: { x, y, width: LABEL_WIDTH, height: labelHeight },
6690
+ align: first ? "left" : last ? "right" : "center"
6691
+ };
6692
+ }
6003
6693
 
6004
6694
  // src/renderScene/charts/renderers/heatmap.ts
6005
6695
  function renderHeatmap(context) {
@@ -6774,14 +7464,14 @@ function createMekkoLayout(context) {
6774
7464
  const labelGutterWidth = context.showLabels ? 30 : 0;
6775
7465
  const grid = createMekkoGrid(context, labelGutterWidth);
6776
7466
  const fontSize = Math.max(9, finite(context.chart.fontSize, 12));
6777
- const columnGap = Math.max(0, finite(context.chart.config?.mekkoColumnGap, 4));
7467
+ const columnGap2 = Math.max(0, finite(context.chart.config?.mekkoColumnGap, 4));
6778
7468
  const smallFontSize = Math.max(8, fontSize - 1);
6779
7469
  return {
6780
- columns: createMekkoColumns(context, grid, labels, columnGap),
7470
+ columns: createMekkoColumns(context, grid, labels, columnGap2),
6781
7471
  fontSize,
6782
7472
  smallFontSize,
6783
7473
  labelGutterWidth,
6784
- columnGap,
7474
+ columnGap: columnGap2,
6785
7475
  labelSize: Math.max(6, finite(context.chart.config?.mekkoLabelSize, smallFontSize)),
6786
7476
  valueSize: Math.max(6, finite(context.chart.config?.mekkoValueSize, smallFontSize)),
6787
7477
  grid
@@ -6801,20 +7491,20 @@ function createMekkoGrid(context, labelGutterWidth) {
6801
7491
  height: Math.max(1, context.plot.height - topGutter - bottomGutter)
6802
7492
  };
6803
7493
  }
6804
- function createMekkoColumns(context, grid, labels, columnGap) {
7494
+ function createMekkoColumns(context, grid, labels, columnGap2) {
6805
7495
  const totals = labels.map(
6806
7496
  (_, columnIndex) => context.chart.series.reduce((sum, series) => sum + (series.values[columnIndex] ?? 0), 0)
6807
7497
  );
6808
7498
  const grandTotal = totals.reduce((sum, total) => sum + total, 0);
6809
7499
  const maximumTotal = Math.max(1, ...totals);
6810
- const availableWidth = Math.max(1, grid.width - columnGap * Math.max(0, labels.length - 1));
7500
+ const availableWidth = Math.max(1, grid.width - columnGap2 * Math.max(0, labels.length - 1));
6811
7501
  let nextX = grid.x;
6812
7502
  return labels.map((label, index) => {
6813
7503
  const total = totals[index];
6814
7504
  const width = grandTotal > 0 ? total / grandTotal * availableWidth : availableWidth / labels.length;
6815
7505
  const height = context.chart.config?.mekkoVaryHeight ? grid.height * (total / maximumTotal) : grid.height;
6816
7506
  const column = { label, total, x: nextX, y: grid.y + grid.height - height, width, height };
6817
- nextX += width + columnGap;
7507
+ nextX += width + columnGap2;
6818
7508
  return column;
6819
7509
  });
6820
7510
  }
@@ -7181,7 +7871,7 @@ function renderPie(context) {
7181
7871
  var TOP2 = -Math.PI / 2;
7182
7872
  var TRACK_COLOR_FALLBACK = "#e2e8f0";
7183
7873
  var MIN_LABEL_SWEEP = 14 * Math.PI / 180;
7184
- var LABEL_WIDTH = 80;
7874
+ var LABEL_WIDTH2 = 80;
7185
7875
  var LABEL_RADIUS_FRACTION = 0.62;
7186
7876
  var OUTSIDE_GAP = 14;
7187
7877
  var LEADER_INSET = 3;
@@ -7356,7 +8046,7 @@ function labelPlacement2(context, geometry, angles, series, fillColor) {
7356
8046
  const hasManualOffset = labelOffsetX !== 0 || labelOffsetY !== 0;
7357
8047
  const tooThin = ringThickness < lineHeight * 2 + 6;
7358
8048
  const chordWidth = 2 * geometry.outerRadius * Math.sin(Math.abs(angles.end - angles.start) / 2);
7359
- const fitsInline = !tooThin && chordWidth >= LABEL_WIDTH;
8049
+ const fitsInline = !tooThin && chordWidth >= LABEL_WIDTH2;
7360
8050
  const outsideLabels = context.chart.config?.polarOutsideLabels ?? false;
7361
8051
  if (!fitsInline && !hasManualOffset && !outsideLabels) {
7362
8052
  return void 0;
@@ -7379,7 +8069,7 @@ function createWedgeLabel(context, geometry, angles, series, value, fillColor) {
7379
8069
  const { point, color, outside, mid, tickStart } = placement;
7380
8070
  const { nameSize, valueSize } = labelSizes(chart);
7381
8071
  const lineHeight = Math.max(nameSize, valueSize) * 1.2;
7382
- const tickEnd = outside ? clipSegmentToRect(tickStart, point, LABEL_WIDTH / 2, lineHeight) : tickStart;
8072
+ const tickEnd = outside ? clipSegmentToRect(tickStart, point, LABEL_WIDTH2 / 2, lineHeight) : tickStart;
7383
8073
  const tick = {
7384
8074
  type: "path",
7385
8075
  id: `chart-polar-area-label-tick-${chart.id}-${series.id}`,
@@ -7399,8 +8089,8 @@ function createWedgeLabel(context, geometry, angles, series, value, fillColor) {
7399
8089
  };
7400
8090
  const base = {
7401
8091
  bounds,
7402
- x: point.x - LABEL_WIDTH / 2,
7403
- width: LABEL_WIDTH,
8092
+ x: point.x - LABEL_WIDTH2 / 2,
8093
+ width: LABEL_WIDTH2,
7404
8094
  fontFamily: chart.fontFamily ?? DEFAULT_FONT,
7405
8095
  align: "center",
7406
8096
  verticalAlign: "middle",
@@ -8190,8 +8880,8 @@ function treemapLeafColor(leaf, layout) {
8190
8880
  }
8191
8881
 
8192
8882
  // src/renderScene/charts/renderers/treemap/legend.ts
8193
- var BAR_THICKNESS = 10;
8194
- var TICK_LENGTH = 4;
8883
+ var BAR_THICKNESS2 = 10;
8884
+ var TICK_LENGTH3 = 4;
8195
8885
  var ROW_GAP2 = 2;
8196
8886
  var CHART_GAP = 16;
8197
8887
  var LABEL_SIZE = 34;
@@ -8220,7 +8910,7 @@ function renderBottomLegend(context, layout) {
8220
8910
  const barWidth = layout.gridWidth;
8221
8911
  const labelHeight = layout.fontSize + 2;
8222
8912
  const barY = plot.y + layout.gridHeight + CHART_GAP;
8223
- const barBounds = boxBounds({ x: barX, y: barY, width: barWidth, height: BAR_THICKNESS });
8913
+ const barBounds = boxBounds({ x: barX, y: barY, width: barWidth, height: BAR_THICKNESS2 });
8224
8914
  const stops = bandStops(layout);
8225
8915
  const bar = {
8226
8916
  type: "rect",
@@ -8230,7 +8920,7 @@ function renderBottomLegend(context, layout) {
8230
8920
  x: barX,
8231
8921
  y: barY,
8232
8922
  width: barWidth,
8233
- height: BAR_THICKNESS,
8923
+ height: BAR_THICKNESS2,
8234
8924
  rx: 3,
8235
8925
  zoneGradient: { axis: "y", min: chart.axisY.min, max: chart.axisY.max },
8236
8926
  style: {
@@ -8239,14 +8929,14 @@ function renderBottomLegend(context, layout) {
8239
8929
  strokeWidth: 1
8240
8930
  }
8241
8931
  };
8242
- const ticks = layout.bands.flatMap((value, index) => {
8932
+ const ticks2 = layout.bands.flatMap((value, index) => {
8243
8933
  const x = barX + bandRatio2(layout, value) * barWidth;
8244
8934
  const tick = {
8245
8935
  type: "path",
8246
8936
  id: `chart-treemap-legend-tick-${chart.id}-${index}`,
8247
8937
  order: nextOrder(),
8248
8938
  bounds,
8249
- d: `M ${x} ${barY + BAR_THICKNESS} L ${x} ${barY + BAR_THICKNESS + TICK_LENGTH}`,
8939
+ d: `M ${x} ${barY + BAR_THICKNESS2} L ${x} ${barY + BAR_THICKNESS2 + TICK_LENGTH3}`,
8250
8940
  style: {
8251
8941
  fill: { kind: "none" },
8252
8942
  stroke: { kind: "solid", color: chart.gridColor ?? "#e2e8f0" },
@@ -8261,22 +8951,22 @@ function renderBottomLegend(context, layout) {
8261
8951
  id: `chart-treemap-legend-tick-label-${chart.id}-${index}`,
8262
8952
  order: nextOrder(),
8263
8953
  bounds,
8264
- frame: { x: frameX, y: barY + BAR_THICKNESS + TICK_LENGTH + ROW_GAP2, width: LABEL_SIZE, height: labelHeight },
8954
+ frame: { x: frameX, y: barY + BAR_THICKNESS2 + TICK_LENGTH3 + ROW_GAP2, width: LABEL_SIZE, height: labelHeight },
8265
8955
  text: formatFieldValue(value),
8266
8956
  chart,
8267
8957
  align
8268
8958
  });
8269
8959
  return [tick, label];
8270
8960
  });
8271
- return [bar, ...ticks];
8961
+ return [bar, ...ticks2];
8272
8962
  }
8273
8963
  function renderSideLegend(context, layout) {
8274
8964
  const { chart, plot, bounds, nextOrder } = context;
8275
8965
  const side = layout.legendPosition;
8276
8966
  const barTop = plot.y;
8277
8967
  const barHeight = layout.gridHeight;
8278
- const barX = side === "left" ? plot.x - CHART_GAP - BAR_THICKNESS : plot.x + layout.gridWidth + CHART_GAP;
8279
- const barBounds = boxBounds({ x: barX, y: barTop, width: BAR_THICKNESS, height: barHeight });
8968
+ const barX = side === "left" ? plot.x - CHART_GAP - BAR_THICKNESS2 : plot.x + layout.gridWidth + CHART_GAP;
8969
+ const barBounds = boxBounds({ x: barX, y: barTop, width: BAR_THICKNESS2, height: barHeight });
8280
8970
  const stops = bandStops(layout);
8281
8971
  const bar = {
8282
8972
  type: "rect",
@@ -8285,7 +8975,7 @@ function renderSideLegend(context, layout) {
8285
8975
  bounds: barBounds,
8286
8976
  x: barX,
8287
8977
  y: barTop,
8288
- width: BAR_THICKNESS,
8978
+ width: BAR_THICKNESS2,
8289
8979
  height: barHeight,
8290
8980
  rx: 3,
8291
8981
  zoneGradient: { axis: "y", min: chart.axisY.min, max: chart.axisY.max },
@@ -8295,10 +8985,10 @@ function renderSideLegend(context, layout) {
8295
8985
  strokeWidth: 1
8296
8986
  }
8297
8987
  };
8298
- const tickX = side === "left" ? barX : barX + BAR_THICKNESS;
8299
- const tickEndX = side === "left" ? tickX - TICK_LENGTH : tickX + TICK_LENGTH;
8988
+ const tickX = side === "left" ? barX : barX + BAR_THICKNESS2;
8989
+ const tickEndX = side === "left" ? tickX - TICK_LENGTH3 : tickX + TICK_LENGTH3;
8300
8990
  const labelX2 = side === "left" ? tickEndX - ROW_GAP2 - LABEL_SIZE : tickEndX + ROW_GAP2;
8301
- const ticks = layout.bands.flatMap((value, index) => {
8991
+ const ticks2 = layout.bands.flatMap((value, index) => {
8302
8992
  const y = barTop + (1 - bandRatio2(layout, value)) * barHeight;
8303
8993
  const tick = {
8304
8994
  type: "path",
@@ -8323,7 +9013,7 @@ function renderSideLegend(context, layout) {
8323
9013
  });
8324
9014
  return [tick, label];
8325
9015
  });
8326
- return [bar, ...ticks];
9016
+ return [bar, ...ticks2];
8327
9017
  }
8328
9018
 
8329
9019
  // src/renderScene/charts/renderers/treemap/tiles.ts
@@ -8720,7 +9410,8 @@ function buildChartTitle(chart, bounds, plot, renderOrder) {
8720
9410
  bounds,
8721
9411
  frame: { x: plot.x, y: chart.y + 12, width: plot.width, height: 20 },
8722
9412
  text: chart.title,
8723
- chart
9413
+ chart,
9414
+ align: chart.titleAlign ?? "left"
8724
9415
  }),
8725
9416
  ...chart.titleColor ? { color: chart.titleColor } : {},
8726
9417
  fontWeight: chart.titleWeight ?? "bold",
@@ -9148,6 +9839,12 @@ function addStrokeAttrs(attrs, style) {
9148
9839
  if (style.pointerEvents) {
9149
9840
  attrs.push(`pointer-events="${style.pointerEvents}"`);
9150
9841
  }
9842
+ if (style.transition && style.transition > 0) {
9843
+ const time = `${num(style.transition)}ms ease`;
9844
+ attrs.push(
9845
+ `style="transition: x ${time}, y ${time}, width ${time}, height ${time}, cx ${time}, cy ${time}, rx ${time}, ry ${time}, fill ${time}, stroke ${time}, stroke-width ${time}, stroke-dasharray ${time}, opacity ${time}"`
9846
+ );
9847
+ }
9151
9848
  }
9152
9849
  function elementSize(node) {
9153
9850
  const shape = node;
@@ -9397,8 +10094,9 @@ function lineOffset(index, linePx) {
9397
10094
  function shaderSurfaceSvg(node, defs) {
9398
10095
  const rotation = transform(node.rotation, { x: node.x + node.width / 2, y: node.y + node.height / 2 });
9399
10096
  const parameters = xml(JSON.stringify(node.shader.parameters));
10097
+ const surfacePadding = node.shader.surfacePadding ?? 0;
9400
10098
  const fillColor = node.fillColor ? ` data-sf-shader-fill="${xml(node.fillColor)}"` : "";
9401
- return `<foreignObject id="${defs.elementId(node.id)}"${contractAttrs(node)} data-sf-shader="${xml(node.shader.program)}" data-sf-shader-name="${xml(node.shader.name)}" data-sf-shader-params="${parameters}" data-sf-shader-mask="${node.mask}"${fillColor} x="${num(node.x)}" y="${num(node.y)}" width="${num(node.width)}" height="${num(node.height)}"${rotation} pointer-events="${node.shader.program === "ruler" || node.identity?.role === "widget" ? "all" : "none"}"><canvas xmlns="http://www.w3.org/1999/xhtml" data-sf-shader-canvas="true" style="display:block;width:100%;height:100%;pointer-events:none"></canvas></foreignObject>`;
10099
+ return `<foreignObject id="${defs.elementId(node.id)}"${contractAttrs(node)} data-sf-shader="${xml(node.shader.program)}" data-sf-shader-name="${xml(node.shader.name)}" data-sf-shader-params="${parameters}" data-sf-shader-mask="${node.mask}" data-sf-shader-padding="${num(surfacePadding)}"${fillColor} x="${num(node.x)}" y="${num(node.y)}" width="${num(node.width)}" height="${num(node.height)}"${rotation} pointer-events="${node.shader.program === "ruler" || node.identity?.role === "widget" ? "all" : "none"}"><canvas xmlns="http://www.w3.org/1999/xhtml" data-sf-shader-canvas="true" style="display:block;width:100%;height:100%;pointer-events:none"></canvas></foreignObject>`;
9402
10100
  }
9403
10101
  function rollingDigitSvg(character, node) {
9404
10102
  const style = node.componentStyle;
@@ -9513,6 +10211,6 @@ function defineComponent(definition) {
9513
10211
  };
9514
10212
  }
9515
10213
 
9516
- export { collectCanvasObjects, decodeColor, decodeShadow, defineComponent, render, renderCanvas, sflToRenderInput };
9517
- //# sourceMappingURL=chunk-FVHVOJS2.js.map
9518
- //# sourceMappingURL=chunk-FVHVOJS2.js.map
10214
+ export { collectCanvasObjects, decodeColor, decodeShadow, defineComponent, render, renderCanvas, sflToRenderInput, sliderReach };
10215
+ //# sourceMappingURL=chunk-MAPNY7MJ.js.map
10216
+ //# sourceMappingURL=chunk-MAPNY7MJ.js.map