stickyflow 0.7.0 → 0.9.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 (63) hide show
  1. package/CHANGELOG.md +23 -0
  2. package/README.md +1 -1
  3. package/dist/binding/index.cjs +9 -9
  4. package/dist/binding/index.d.cts +4 -4
  5. package/dist/binding/index.d.ts +4 -4
  6. package/dist/binding/index.js +3 -3
  7. package/dist/{chunk-OWNVXKXN.cjs → chunk-B3YRZVMR.cjs} +23 -23
  8. package/dist/chunk-B3YRZVMR.cjs.map +1 -0
  9. package/dist/{chunk-JCRPLPKV.js → chunk-BUVUJMWT.js} +5 -5
  10. package/dist/chunk-BUVUJMWT.js.map +1 -0
  11. package/dist/{chunk-ZNHYW47T.js → chunk-CM35H45Z.js} +3 -3
  12. package/dist/{chunk-ZNHYW47T.js.map → chunk-CM35H45Z.js.map} +1 -1
  13. package/dist/{chunk-JQK4IGXJ.js → chunk-D2266VBZ.js} +440 -8
  14. package/dist/chunk-D2266VBZ.js.map +1 -0
  15. package/dist/{chunk-SDMQRSRW.js → chunk-FS6L462E.js} +455 -136
  16. package/dist/chunk-FS6L462E.js.map +1 -0
  17. package/dist/{chunk-EKAWJFJQ.cjs → chunk-OUWGWDJ2.cjs} +15 -15
  18. package/dist/{chunk-EKAWJFJQ.cjs.map → chunk-OUWGWDJ2.cjs.map} +1 -1
  19. package/dist/{chunk-KXYSO6GC.cjs → chunk-QL7MNEMT.cjs} +444 -7
  20. package/dist/chunk-QL7MNEMT.cjs.map +1 -0
  21. package/dist/{chunk-BUOWM3LC.cjs → chunk-SQBF2BKT.cjs} +382 -73
  22. package/dist/chunk-SQBF2BKT.cjs.map +1 -0
  23. package/dist/{chunk-A73UJ5AQ.cjs → chunk-YSXD5IVZ.cjs} +1074 -755
  24. package/dist/chunk-YSXD5IVZ.cjs.map +1 -0
  25. package/dist/{chunk-MUKIGLR5.js → chunk-ZCGZJBAT.js} +353 -44
  26. package/dist/chunk-ZCGZJBAT.js.map +1 -0
  27. package/dist/index.cjs +36 -36
  28. package/dist/index.d.cts +5 -5
  29. package/dist/index.d.ts +5 -5
  30. package/dist/index.js +5 -5
  31. package/dist/interaction/index.cjs +268 -235
  32. package/dist/interaction/index.cjs.map +1 -1
  33. package/dist/interaction/index.d.cts +2 -2
  34. package/dist/interaction/index.d.ts +2 -2
  35. package/dist/interaction/index.js +44 -11
  36. package/dist/interaction/index.js.map +1 -1
  37. package/dist/{render-BU2uYzjG.d.cts → render-DU4lYbRl.d.cts} +29 -11
  38. package/dist/{render-BU2uYzjG.d.ts → render-DU4lYbRl.d.ts} +29 -11
  39. package/dist/{runtime-B7KiTmn8.d.cts → runtime-DG8X3Fwf.d.cts} +2 -2
  40. package/dist/{runtime-BPzyD-Nd.d.ts → runtime-kqD1RS17.d.ts} +2 -2
  41. package/dist/{runtimeTypes-DalvhScn.d.ts → runtimeTypes-CvjlBZds.d.cts} +7 -3
  42. package/dist/{runtimeTypes-BIP70z72.d.cts → runtimeTypes-vRaHOIHi.d.ts} +7 -3
  43. package/dist/stickyflow-diagram.global.js +294 -39
  44. package/dist/stickyflow-diagram.global.js.map +1 -1
  45. package/dist/{types-D_2NZ6lL.d.cts → types-B5jrEEcF.d.cts} +1 -1
  46. package/dist/{types-DMWs27Hn.d.ts → types-B7IkZ0w4.d.ts} +1 -1
  47. package/dist/viewer/index.cjs +9 -9
  48. package/dist/viewer/index.d.cts +4 -4
  49. package/dist/viewer/index.d.ts +4 -4
  50. package/dist/viewer/index.js +4 -4
  51. package/dist/web-component/index.cjs +6 -6
  52. package/dist/web-component/index.d.cts +2 -2
  53. package/dist/web-component/index.d.ts +2 -2
  54. package/dist/web-component/index.js +4 -4
  55. package/package.json +1 -1
  56. package/dist/chunk-A73UJ5AQ.cjs.map +0 -1
  57. package/dist/chunk-BUOWM3LC.cjs.map +0 -1
  58. package/dist/chunk-JCRPLPKV.js.map +0 -1
  59. package/dist/chunk-JQK4IGXJ.js.map +0 -1
  60. package/dist/chunk-KXYSO6GC.cjs.map +0 -1
  61. package/dist/chunk-MUKIGLR5.js.map +0 -1
  62. package/dist/chunk-OWNVXKXN.cjs.map +0 -1
  63. package/dist/chunk-SDMQRSRW.js.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-JQK4IGXJ.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-D2266VBZ.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-]*`;
@@ -161,6 +161,23 @@ var PATH_TYPES = ["straight", "curved", "orthogonal"];
161
161
  function optionalOneOf(value, allowed) {
162
162
  return value !== void 0 && allowed.includes(value) ? value : void 0;
163
163
  }
164
+ var BLEND_MODES = [
165
+ "multiply",
166
+ "screen",
167
+ "overlay",
168
+ "darken",
169
+ "lighten",
170
+ "color-dodge",
171
+ "color-burn",
172
+ "hard-light",
173
+ "soft-light",
174
+ "difference",
175
+ "exclusion",
176
+ "hue",
177
+ "saturation",
178
+ "color",
179
+ "luminosity"
180
+ ];
164
181
  var SHAPE_STROKE_STYLES = ["solid", "dashed", "dotted", "double"];
165
182
  var MARKER_TYPES = [
166
183
  "none",
@@ -240,6 +257,14 @@ function axesOf(p) {
240
257
  axisLineStyle: p.axisLineStyle === "dashed" || p.axisLineStyle === "dotted" ? p.axisLineStyle : void 0,
241
258
  tickLength: numOf(p.tickLength),
242
259
  axisFontSize: numOf(p.axisFontSize),
260
+ axisLabelAngle: numOf(p.axisLabelAngle),
261
+ axisLabelSpace: numOf(p.axisLabelSpace),
262
+ rowLabelSide: p.rowLabelSide === "left" || p.rowLabelSide === "right" ? p.rowLabelSide : void 0,
263
+ columnLabelSide: p.columnLabelSide === "top" || p.columnLabelSide === "bottom" ? p.columnLabelSide : void 0,
264
+ legendSide: p.legendSide === "top" || p.legendSide === "bottom" || p.legendSide === "left" || p.legendSide === "right" ? p.legendSide : void 0,
265
+ xLabelGap: numOf(p.xLabelGap),
266
+ yLabelGap: numOf(p.yLabelGap),
267
+ axisLabelAlign: p.axisLabelAlign === "left" || p.axisLabelAlign === "center" || p.axisLabelAlign === "right" ? p.axisLabelAlign : void 0,
243
268
  axisFontFamily: p.axisFontFamily,
244
269
  showValueAxis: p.showValueAxis !== "false",
245
270
  categoryAlign: p.categoryAlign === "left" || p.categoryAlign === "inside" ? p.categoryAlign : void 0,
@@ -250,6 +275,7 @@ function textOf(p) {
250
275
  return {
251
276
  textColor: p.textColor ?? "#0f172a",
252
277
  titleSize: numOf(p.titleSize),
278
+ titleAlign: p.titleAlign === "left" || p.titleAlign === "center" || p.titleAlign === "right" ? p.titleAlign : void 0,
253
279
  titleWeight: p.titleWeight === "normal" ? "normal" : void 0,
254
280
  titleColor: p.titleColor,
255
281
  fontSize: numOf(p.fontSize) ?? 12,
@@ -259,6 +285,7 @@ function textOf(p) {
259
285
  function legendOf(p) {
260
286
  return {
261
287
  legendColor: p.legendColor,
288
+ legendGap: numOf(p.legendGap),
262
289
  showLegend: p.showLegend === "true",
263
290
  legendPosition: legendPositionOf(p.legendPosition)
264
291
  };
@@ -886,6 +913,7 @@ function frameObject(e) {
886
913
  showLabel: p.showLabel !== "false",
887
914
  labelPosition: oneOf(p.labelPosition, LABEL_POSITIONS, "top"),
888
915
  shadow: p.shadow !== "false",
916
+ clip: p.clip === "true" || void 0,
889
917
  order: e.order,
890
918
  sourceIndex: e.sourceIndex
891
919
  };
@@ -913,6 +941,7 @@ function isometricObject(canvasObject) {
913
941
  strokeColor: solidColor(presentation.stroke) ?? "#111827",
914
942
  strokeWidth: numOf(presentation.strokeWidth) ?? 1,
915
943
  cornerRadius: numOf(presentation.cornerRadius) ?? (canvasObject.isometric.footprint ? 0 : 8),
944
+ seams: presentation.seams === "false" ? false : void 0,
916
945
  hasShadow: shadowStyle?.enabled ?? false,
917
946
  shadowStyle,
918
947
  labelOffsetX: numOf(presentation.labelOffsetX) ?? 0,
@@ -1017,6 +1046,8 @@ function shapeObject(e, shaders) {
1017
1046
  dash: dashArray(p.dash),
1018
1047
  strokeStyle: optionalOneOf(p.strokeStyle, SHAPE_STROKE_STYLES),
1019
1048
  opacity: numOf(p.opacity),
1049
+ blur: numOf(p.blur),
1050
+ blend: optionalOneOf(p.blend, BLEND_MODES),
1020
1051
  parentFrameId: e.parentFrameId,
1021
1052
  order: e.order,
1022
1053
  sourceIndex: e.sourceIndex,
@@ -2947,10 +2978,10 @@ function buildBox(object, index) {
2947
2978
  const hullPath = roundedPolygonPath(silhouette(object), cornerRadius);
2948
2979
  const hullClip = { type: "path", d: hullPath };
2949
2980
  const groundShadow = groundShadowNode(context, faces.top);
2950
- const seams = seamsNode(context, faces, hullClip);
2981
+ const seams = object.seams === false ? void 0 : seamsNode(context, faces, hullClip);
2951
2982
  const hull = hullNode(context, hullPath, cornerRadius);
2952
2983
  const facesNodes = faceNodes(context, faces, hullClip);
2953
- const objectNodes = groundShadow ? [hull, ...facesNodes, groundShadow, seams] : [hull, ...facesNodes, seams];
2984
+ const objectNodes = groundShadow ? [hull, ...facesNodes, groundShadow, ...seams ? [seams] : []] : [hull, ...facesNodes, ...seams ? [seams] : []];
2954
2985
  return object.text ? [...objectNodes, ...labelNodes(context, object.text)] : objectNodes;
2955
2986
  }
2956
2987
 
@@ -3538,7 +3569,14 @@ function renderShapeGeometry(context) {
3538
3569
  }
3539
3570
 
3540
3571
  // src/renderScene/artifacts/shape/shaderSurface.ts
3541
- var RECT_PROGRAMS = /* @__PURE__ */ new Set(["reactivePanel", "ledMatrix", "lightBand", "silkFolds"]);
3572
+ var RECT_PROGRAMS = /* @__PURE__ */ new Set([
3573
+ "reactivePanel",
3574
+ "ledMatrix",
3575
+ "lightBand",
3576
+ "silkFolds",
3577
+ "glowCard",
3578
+ "glassDots"
3579
+ ]);
3542
3580
  function shaderMask(context) {
3543
3581
  if (context.shape.shapeType === "circle" || context.shape.shapeType === "oval") {
3544
3582
  return "ellipse";
@@ -3648,6 +3686,8 @@ function shapeStyle(shape, diagnostics) {
3648
3686
  dash: shapeDash(shape, strokeWidth),
3649
3687
  lineCap: shape.strokeStyle === "dotted" ? "round" : "butt",
3650
3688
  opacity: finite(shape.opacity, defaults.opacity),
3689
+ blur: shape.blur !== void 0 && shape.blur > 0 ? shape.blur : void 0,
3690
+ blend: shape.blend,
3651
3691
  shadow: shadow?.enabled ? {
3652
3692
  color: shadow.color ?? "#000000",
3653
3693
  opacity: finite(shadow.opacity, 0.25),
@@ -4057,6 +4097,12 @@ function hasCartesianDecorations(chart) {
4057
4097
  function tickOffset(chart) {
4058
4098
  return hasCartesianDecorations(chart) ? Math.max(0, finite(chart.tickLength, 0)) : 0;
4059
4099
  }
4100
+ function xLabelOffset(chart) {
4101
+ return tickOffset(chart) + (hasCartesianDecorations(chart) ? Math.max(0, finite(chart.xLabelGap, 0)) : 0);
4102
+ }
4103
+ function yLabelOffset(chart) {
4104
+ return tickOffset(chart) + (hasCartesianDecorations(chart) ? Math.max(0, finite(chart.yLabelGap, 0)) : 0);
4105
+ }
4060
4106
  function isHorizontalBoxplot(chart) {
4061
4107
  return chart.chartType === "boxplot" && chart.config?.orientation === "horizontal";
4062
4108
  }
@@ -4078,6 +4124,9 @@ function barCategoryLabelWidth(chart) {
4078
4124
  return Math.max(0, ...categories.map((category) => category.length)) * fontSize * 0.58 + 16;
4079
4125
  }
4080
4126
  function leftLabelWidth(chart) {
4127
+ if (chart.axisLabelSpace && chart.axisLabelSpace > 0 && (isHorizontalBoxplot(chart) || isHorizontalBar(chart))) {
4128
+ return chart.axisLabelSpace;
4129
+ }
4081
4130
  if (isHorizontalBoxplot(chart)) {
4082
4131
  return boxplotCategoryLabelWidth(chart);
4083
4132
  }
@@ -4089,6 +4138,14 @@ function leftLabelWidth(chart) {
4089
4138
  }
4090
4139
  return chart.axisY.label ? 60 : 46;
4091
4140
  }
4141
+ function tiltedBottomRoom(chart) {
4142
+ const tilt = labelTilt(chart);
4143
+ if (tilt <= 0) {
4144
+ return 0;
4145
+ }
4146
+ const labels = chart.chartType === "bar" && !isHorizontalBar(chart) ? chart.config?.categories ?? [] : chart.chartType === "boxplot" && !isHorizontalBoxplot(chart) ? chart.series.map((series) => series.label || series.id) : [];
4147
+ return labels.length > 0 ? Math.max(0, tiltedLabelRoom(chart, labels, tilt) - 18) : 0;
4148
+ }
4092
4149
  function decorations(chart) {
4093
4150
  const showLabels = chart.showAxisLabels !== false;
4094
4151
  const showLegend = chart.showLegend !== false;
@@ -4098,15 +4155,16 @@ function decorations(chart) {
4098
4155
  const legendStacked = hasLegendItems && isStackedLegendPosition(legendPosition);
4099
4156
  const sideColumnWidth = legendStacked ? stackedLegendColumnWidth(chart) + LEGEND_COLUMN_GAP : 0;
4100
4157
  const treemapSide = treemapSideLegendSide(chart, showLegend);
4101
- const tick = tickOffset(chart);
4102
- const padLeft = tick + (showLabels ? leftLabelWidth(chart) : 12) + (legendPosition === "bottomLeft" ? sideColumnWidth : 0) + (treemapSide === "left" ? TREEMAP_SIDE_LEGEND_WIDTH : 0);
4158
+ const tickX = xLabelOffset(chart);
4159
+ const tickY = yLabelOffset(chart);
4160
+ const padLeft = tickY + (showLabels ? leftLabelWidth(chart) : 12) + (legendPosition === "bottomLeft" ? sideColumnWidth : 0) + (treemapSide === "left" ? TREEMAP_SIDE_LEGEND_WIDTH : 0);
4103
4161
  const padRight = 24 + (legendPosition === "bottomRight" ? sideColumnWidth : 0) + (treemapSide === "right" ? TREEMAP_SIDE_LEGEND_WIDTH : 0);
4104
4162
  const valueRow = chart.chartType === "bar" && chart.config?.showBarLabels === true && chart.config.barLabelPosition === "axis";
4105
4163
  const horizontalValueAxis = isHorizontalBar(chart) && chart.showValueAxis !== false;
4106
4164
  const basePadBottom = showLabels ? isHorizontalBar(chart) ? horizontalValueAxis ? 34 : 12 : (chart.axisX.label ? 52 : 34) + (valueRow ? 18 : 0) : 12;
4107
4165
  const hasColorBar = chart.chartType === "field" && showLegend && Boolean(chart.config?.scale?.stops.length);
4108
4166
  const legendAtBottomRow = hasLegendItems && !legendAtTop && !legendStacked;
4109
- const padBottom = tick + basePadBottom + (hasColorBar ? 44 : 0) + (legendAtBottomRow ? 16 + LEGEND_ROW_HEIGHT : 0);
4167
+ const padBottom = tickX + basePadBottom + (showLabels ? tiltedBottomRoom(chart) : 0) + (hasColorBar ? 44 : 0) + (legendAtBottomRow ? 16 + LEGEND_ROW_HEIGHT : 0);
4110
4168
  const titleHeight = chart.title ? Math.max(44, 20 + finite(chart.titleSize, 14) * 1.6) : 0;
4111
4169
  const padTop = titleHeight || (legendAtTop && hasLegendItems ? 44 : 24);
4112
4170
  return {
@@ -4138,6 +4196,7 @@ function buildCategoricalXAxisTicks(chart, layout, order) {
4138
4196
  const slotWidth = layout.plot.width / count;
4139
4197
  const labels = categoryLabels(chart, count);
4140
4198
  const editable = Boolean(chart.config?.categories?.length);
4199
+ const tilt = labelTilt(chart);
4141
4200
  const left = chart.categoryAlign === "left";
4142
4201
  const groupGap = left ? Math.min(
4143
4202
  Math.max(0, finite(chart.config?.barGroupGap, 8)),
@@ -4145,6 +4204,27 @@ function buildCategoricalXAxisTicks(chart, layout, order) {
4145
4204
  ) : 0;
4146
4205
  return Array.from({ length: count }, (_value, index) => {
4147
4206
  const centerX = layout.plot.x + (index + 0.5) * slotWidth;
4207
+ if (tilt > 0) {
4208
+ const text = labels[index] ?? String(index + 1);
4209
+ const { frame, rotation } = labelBelowFrame(chart, text, tilt, {
4210
+ x: centerX,
4211
+ y: layout.plot.y + layout.plot.height + 4 + xLabelOffset(chart)
4212
+ });
4213
+ return {
4214
+ ...chartText({
4215
+ role: "axis",
4216
+ id: `chart-x-tick-${chart.id}-${index}`,
4217
+ order: order + index,
4218
+ bounds: layout.bounds,
4219
+ frame,
4220
+ text,
4221
+ chart,
4222
+ align: "right",
4223
+ rotation
4224
+ }),
4225
+ prop: editable ? categoryProp(index) : void 0
4226
+ };
4227
+ }
4148
4228
  return {
4149
4229
  ...chartText({
4150
4230
  role: "axis",
@@ -4153,7 +4233,7 @@ function buildCategoricalXAxisTicks(chart, layout, order) {
4153
4233
  bounds: layout.bounds,
4154
4234
  frame: {
4155
4235
  x: left ? layout.plot.x + index * slotWidth + groupGap / 2 : centerX - slotWidth / 2,
4156
- y: layout.plot.y + layout.plot.height + 4 + tickOffset(chart),
4236
+ y: layout.plot.y + layout.plot.height + 4 + xLabelOffset(chart),
4157
4237
  width: left ? slotWidth - groupGap : slotWidth,
4158
4238
  height: 18
4159
4239
  },
@@ -4168,8 +4248,30 @@ function buildCategoricalXAxisTicks(chart, layout, order) {
4168
4248
  function buildSeriesXAxisTicks(chart, layout, order) {
4169
4249
  const count = Math.max(1, chart.series.length);
4170
4250
  const slotWidth = layout.plot.width / count;
4251
+ const tilt = labelTilt(chart);
4171
4252
  return chart.series.map((series, index) => {
4172
4253
  const centerX = layout.plot.x + (index + 0.5) * slotWidth;
4254
+ if (tilt > 0) {
4255
+ const text = series.label || series.id;
4256
+ const { frame, rotation } = labelBelowFrame(chart, text, tilt, {
4257
+ x: centerX,
4258
+ y: layout.plot.y + layout.plot.height + 4 + xLabelOffset(chart)
4259
+ });
4260
+ return {
4261
+ ...chartText({
4262
+ role: "axis",
4263
+ id: `chart-x-tick-${chart.id}-${index}`,
4264
+ order: order + index,
4265
+ bounds: layout.bounds,
4266
+ frame,
4267
+ text,
4268
+ chart,
4269
+ align: "right",
4270
+ rotation
4271
+ }),
4272
+ prop: seriesLabelProp(series.id)
4273
+ };
4274
+ }
4173
4275
  return {
4174
4276
  ...chartText({
4175
4277
  role: "axis",
@@ -4178,7 +4280,7 @@ function buildSeriesXAxisTicks(chart, layout, order) {
4178
4280
  bounds: layout.bounds,
4179
4281
  frame: {
4180
4282
  x: centerX - slotWidth / 2,
4181
- y: layout.plot.y + layout.plot.height + 4 + tickOffset(chart),
4283
+ y: layout.plot.y + layout.plot.height + 4 + xLabelOffset(chart),
4182
4284
  width: slotWidth,
4183
4285
  height: 18
4184
4286
  },
@@ -4200,7 +4302,7 @@ function buildNumericXAxisTicks(chart, layout, order) {
4200
4302
  id: `chart-x-tick-${chart.id}-${tick}`,
4201
4303
  order: order + index,
4202
4304
  bounds: layout.bounds,
4203
- frame: { x: x - 20, y: layout.plot.y + layout.plot.height + 10 + tickOffset(chart), width: 40, height: 18 },
4305
+ frame: { x: x - 20, y: layout.plot.y + layout.plot.height + 10 + xLabelOffset(chart), width: 40, height: 18 },
4204
4306
  text: String(tick),
4205
4307
  chart,
4206
4308
  align: "center"
@@ -4217,7 +4319,7 @@ function buildNumericYAxisTicks(chart, layout, order) {
4217
4319
  id: `chart-y-tick-${chart.id}-${tick}`,
4218
4320
  order: order + index,
4219
4321
  bounds: layout.bounds,
4220
- frame: { x: chart.x, y: y - 6, width: layout.padLeft - 14 - tickOffset(chart), height: 18 },
4322
+ frame: { x: chart.x, y: y - 6, width: layout.padLeft - 14 - yLabelOffset(chart), height: 18 },
4221
4323
  text: String(tick),
4222
4324
  chart,
4223
4325
  align: "right"
@@ -6291,92 +6393,74 @@ function createCellValueLabel(context, layout, cell) {
6291
6393
  };
6292
6394
  }
6293
6395
 
6294
- // src/renderScene/charts/renderers/heatmap/headers.ts
6295
- function renderHeatmapHeaders(context, layout) {
6296
- return [...renderRowHeaders(context, layout), ...renderColumnHeaders(context, layout)];
6297
- }
6298
- function renderRowHeaders(context, layout) {
6299
- if (layout.reservedSpace.rowHeaders <= 0) {
6300
- return [];
6301
- }
6302
- return layout.rows.map((series, rowIndex) => createRowHeader(context, layout, series, rowIndex));
6303
- }
6304
- function createRowHeader(context, layout, series, rowIndex) {
6305
- const { chart, plot, bounds, nextOrder } = context;
6306
- return chartText({
6307
- id: `chart-heatmap-row-${chart.id}-${series.id}`,
6308
- order: nextOrder(),
6309
- bounds,
6310
- frame: {
6311
- x: plot.x,
6312
- y: layout.grid.y + rowIndex * layout.grid.cellHeight + layout.grid.cellHeight / 2 - layout.fontSize / 2,
6313
- width: layout.reservedSpace.rowHeaders - 8,
6314
- height: layout.fontSize + 2
6315
- },
6316
- text: series.label,
6317
- chart
6318
- });
6319
- }
6320
- function renderColumnHeaders(context, layout) {
6321
- if (layout.reservedSpace.columnHeaders <= 0) {
6322
- return [];
6323
- }
6324
- return layout.columns.map((label, columnIndex) => createColumnHeader(context, layout, label, columnIndex));
6325
- }
6326
- function createColumnHeader(context, layout, label, columnIndex) {
6327
- const { chart, plot, bounds, nextOrder } = context;
6328
- return chartText({
6329
- id: `chart-heatmap-col-${chart.id}-${columnIndex}`,
6330
- order: nextOrder(),
6331
- bounds,
6332
- frame: {
6333
- x: layout.grid.x + columnIndex * layout.grid.cellWidth,
6334
- y: plot.y,
6335
- width: layout.grid.cellWidth,
6336
- height: layout.fontSize + 2
6337
- },
6338
- text: label,
6339
- chart,
6340
- align: "center"
6341
- });
6342
- }
6343
-
6344
6396
  // src/renderScene/charts/renderers/heatmap/layout.ts
6345
6397
  function createHeatmapLayout(context) {
6346
6398
  const { chart } = context;
6347
6399
  const columns = heatmapColumns(context);
6348
- const reservedSpace = heatmapReservedSpace(context);
6400
+ const sides = heatmapSides(context);
6401
+ const reservedSpace = heatmapReservedSpace(context, sides);
6349
6402
  return {
6350
6403
  rows: chart.series,
6351
6404
  columns,
6352
6405
  bands: axisBands(chart.axisY),
6353
6406
  zones: chart.config?.zones?.length ? chart.config.zones : DEFAULT_HEATMAP_ZONES,
6354
6407
  fontSize: Math.max(9, finite(chart.fontSize, 12)),
6408
+ headerFontSize: headerFontSize(chart),
6409
+ legendGap: legendGap(chart),
6410
+ sides,
6355
6411
  reservedSpace,
6356
- grid: createHeatmapGrid(context, reservedSpace, columns.length)
6412
+ grid: createHeatmapGrid(context, reservedSpace, sides, columns.length)
6413
+ };
6414
+ }
6415
+ var headerFontSize = (chart) => Math.max(9, finite(chart.axisFontSize ?? chart.fontSize, 12));
6416
+ var rowGap = (chart) => Math.min(120, Math.max(0, finite(chart.yLabelGap, 6)));
6417
+ var columnGap = (chart) => Math.min(120, Math.max(0, finite(chart.xLabelGap, 4)));
6418
+ var legendGap = (chart) => Math.min(80, Math.max(0, finite(chart.legendGap, 6)));
6419
+ function heatmapSides(context) {
6420
+ const { chart } = context;
6421
+ return {
6422
+ rows: chart.rowLabelSide === "right" ? "right" : "left",
6423
+ columns: chart.columnLabelSide === "bottom" ? "bottom" : "top",
6424
+ legend: chart.legendSide ?? "bottom"
6357
6425
  };
6358
6426
  }
6359
6427
  function heatmapColumns(context) {
6360
6428
  const { chart } = context;
6361
6429
  return chart.config?.categories?.length ? chart.config.categories : chart.series[0]?.values?.map((_, index) => String(index + 1)) ?? [];
6362
6430
  }
6363
- function heatmapReservedSpace(context) {
6431
+ var LEGEND_ACROSS = 32;
6432
+ var LEGEND_BESIDE = 56;
6433
+ function heatmapReservedSpace(context, sides) {
6364
6434
  const { chart } = context;
6365
- const fontSize = Math.max(9, finite(chart.fontSize, 12));
6435
+ const fontSize = headerFontSize(chart);
6366
6436
  const longestLabel = chart.series.reduce(
6367
6437
  (max, series) => Math.max(max, estimateTextWidth(series.label ?? "", fontSize, false)),
6368
6438
  0
6369
6439
  );
6440
+ const vertical = sides.legend === "left" || sides.legend === "right";
6370
6441
  return {
6371
- rowHeaders: context.showLabels ? Math.min(96, longestLabel + 12) : 0,
6372
- columnHeaders: context.showLabels ? 24 : 0,
6373
- legend: context.showLegend ? 38 : 0
6442
+ // The names get the room they ask for, or as much as the longest needs. They never take more than most of the plot.
6443
+ rowHeaders: context.showLabels ? Math.min(
6444
+ context.plot.width * 0.7,
6445
+ chart.axisLabelSpace && chart.axisLabelSpace > 0 ? chart.axisLabelSpace : longestLabel + 6 + rowGap(chart)
6446
+ ) : 0,
6447
+ columnHeaders: context.showLabels ? columnHeaderRoom(context) : 0,
6448
+ legend: context.showLegend ? (vertical ? LEGEND_BESIDE : LEGEND_ACROSS) + legendGap(chart) : 0
6374
6449
  };
6375
6450
  }
6376
- function createHeatmapGrid(context, reservedSpace, columnCount) {
6451
+ function columnHeaderRoom(context) {
6377
6452
  const { chart } = context;
6378
- const width = Math.max(1, context.plot.width - reservedSpace.rowHeaders);
6379
- const height = Math.max(1, context.plot.height - reservedSpace.columnHeaders - reservedSpace.legend);
6453
+ const tilt = labelTilt(chart);
6454
+ return tilt > 0 ? Math.min(context.plot.height * 0.4, tiltedLabelRoom(chart, heatmapColumns(context), tilt) + columnGap(chart) + 4) : headerFontSize(chart) + 2 + columnGap(chart) + 6;
6455
+ }
6456
+ function createHeatmapGrid(context, reservedSpace, sides, columnCount) {
6457
+ const { chart } = context;
6458
+ const left = (sides.rows === "left" ? reservedSpace.rowHeaders : 0) + (sides.legend === "left" ? reservedSpace.legend : 0);
6459
+ const right = (sides.rows === "right" ? reservedSpace.rowHeaders : 0) + (sides.legend === "right" ? reservedSpace.legend : 0);
6460
+ const top = (sides.columns === "top" ? reservedSpace.columnHeaders : 0) + (sides.legend === "top" ? reservedSpace.legend : 0);
6461
+ const bottom = (sides.columns === "bottom" ? reservedSpace.columnHeaders : 0) + (sides.legend === "bottom" ? reservedSpace.legend : 0);
6462
+ const width = Math.max(1, context.plot.width - left - right);
6463
+ const height = Math.max(1, context.plot.height - top - bottom);
6380
6464
  const rowCount = chart.series.length;
6381
6465
  const cellGap = Math.max(0, finite(chart.config?.cellGap, 0));
6382
6466
  let cellWidth = columnCount ? width / columnCount : width;
@@ -6391,8 +6475,8 @@ function createHeatmapGrid(context, reservedSpace, columnCount) {
6391
6475
  gridHeight = cellSize * rowCount;
6392
6476
  }
6393
6477
  return {
6394
- x: context.plot.x + reservedSpace.rowHeaders,
6395
- y: context.plot.y + reservedSpace.columnHeaders,
6478
+ x: context.plot.x + left,
6479
+ y: context.plot.y + top,
6396
6480
  width: gridWidth,
6397
6481
  height: gridHeight,
6398
6482
  cellWidth,
@@ -6402,30 +6486,151 @@ function createHeatmapGrid(context, reservedSpace, columnCount) {
6402
6486
  };
6403
6487
  }
6404
6488
 
6489
+ // src/renderScene/charts/renderers/heatmap/headers.ts
6490
+ function renderHeatmapHeaders(context, layout) {
6491
+ return [...renderRowHeaders(context, layout), ...renderColumnHeaders(context, layout)];
6492
+ }
6493
+ function renderRowHeaders(context, layout) {
6494
+ if (layout.reservedSpace.rowHeaders <= 0) {
6495
+ return [];
6496
+ }
6497
+ return layout.rows.map((series, rowIndex) => createRowHeader(context, layout, series, rowIndex));
6498
+ }
6499
+ function createRowHeader(context, layout, series, rowIndex) {
6500
+ const { chart, bounds, nextOrder } = context;
6501
+ const room = layout.reservedSpace.rowHeaders;
6502
+ const gap = rowGap(chart);
6503
+ const x = layout.sides.rows === "left" ? layout.grid.x - room : layout.grid.x + layout.grid.width + gap;
6504
+ return chartText({
6505
+ id: `chart-heatmap-row-${chart.id}-${series.id}`,
6506
+ order: nextOrder(),
6507
+ bounds,
6508
+ frame: {
6509
+ x,
6510
+ y: layout.grid.y + rowIndex * layout.grid.cellHeight + layout.grid.cellHeight / 2 - layout.headerFontSize / 2,
6511
+ width: Math.max(1, room - gap),
6512
+ height: layout.headerFontSize + 2
6513
+ },
6514
+ text: series.label,
6515
+ chart,
6516
+ align: chart.axisLabelAlign ?? "left",
6517
+ role: "axis"
6518
+ });
6519
+ }
6520
+ function renderColumnHeaders(context, layout) {
6521
+ if (layout.reservedSpace.columnHeaders <= 0) {
6522
+ return [];
6523
+ }
6524
+ return layout.columns.map((label, columnIndex) => createColumnHeader(context, layout, label, columnIndex));
6525
+ }
6526
+ function createColumnHeader(context, layout, label, columnIndex) {
6527
+ const { chart, bounds, nextOrder } = context;
6528
+ const above = layout.sides.columns === "top";
6529
+ const centerX = layout.grid.x + (columnIndex + 0.5) * layout.grid.cellWidth;
6530
+ const tilt = labelTilt(chart);
6531
+ const gap = columnGap(chart);
6532
+ const id = `chart-heatmap-col-${chart.id}-${columnIndex}`;
6533
+ if (tilt > 0) {
6534
+ 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 });
6535
+ return chartText({
6536
+ id,
6537
+ order: nextOrder(),
6538
+ bounds,
6539
+ frame,
6540
+ text: label,
6541
+ chart,
6542
+ align: above ? "left" : "right",
6543
+ rotation,
6544
+ role: "axis"
6545
+ });
6546
+ }
6547
+ return chartText({
6548
+ id,
6549
+ order: nextOrder(),
6550
+ bounds,
6551
+ frame: {
6552
+ x: layout.grid.x + columnIndex * layout.grid.cellWidth,
6553
+ y: above ? layout.grid.y - gap - (layout.headerFontSize + 2) : layout.grid.y + layout.grid.height + gap,
6554
+ width: layout.grid.cellWidth,
6555
+ height: layout.headerFontSize + 2
6556
+ },
6557
+ text: label,
6558
+ chart,
6559
+ align: "center",
6560
+ role: "axis"
6561
+ });
6562
+ }
6563
+
6405
6564
  // src/renderScene/charts/renderers/heatmap/legend.ts
6406
- var BAR_HEIGHT = 10;
6407
- var TICK_HEIGHT = 4;
6565
+ var BAR_THICKNESS = 10;
6566
+ var TICK_LENGTH2 = 4;
6408
6567
  var ROW_GAP = 2;
6568
+ var LABEL_WIDTH = 48;
6569
+ function barPlace(layout) {
6570
+ const { grid, sides, reservedSpace, legendGap: legendGap2 } = layout;
6571
+ const rowRoom = reservedSpace.rowHeaders;
6572
+ const columnRoom = reservedSpace.columnHeaders;
6573
+ switch (sides.legend) {
6574
+ case "top": {
6575
+ const edge = grid.y - (sides.columns === "top" ? columnRoom : 0);
6576
+ return {
6577
+ x: grid.x,
6578
+ y: edge - legendGap2 - BAR_THICKNESS,
6579
+ width: grid.width,
6580
+ height: BAR_THICKNESS,
6581
+ vertical: false,
6582
+ numbers: "top"
6583
+ };
6584
+ }
6585
+ case "left": {
6586
+ const edge = grid.x - (sides.rows === "left" ? rowRoom : 0);
6587
+ return {
6588
+ x: edge - legendGap2 - BAR_THICKNESS,
6589
+ y: grid.y,
6590
+ width: BAR_THICKNESS,
6591
+ height: grid.height,
6592
+ vertical: true,
6593
+ numbers: "left"
6594
+ };
6595
+ }
6596
+ case "right": {
6597
+ const edge = grid.x + grid.width + (sides.rows === "right" ? rowRoom : 0);
6598
+ return {
6599
+ x: edge + legendGap2,
6600
+ y: grid.y,
6601
+ width: BAR_THICKNESS,
6602
+ height: grid.height,
6603
+ vertical: true,
6604
+ numbers: "right"
6605
+ };
6606
+ }
6607
+ default: {
6608
+ const edge = grid.y + grid.height + (sides.columns === "bottom" ? columnRoom : 0);
6609
+ return {
6610
+ x: grid.x,
6611
+ y: edge + legendGap2,
6612
+ width: grid.width,
6613
+ height: BAR_THICKNESS,
6614
+ vertical: false,
6615
+ numbers: "bottom"
6616
+ };
6617
+ }
6618
+ }
6619
+ }
6409
6620
  function renderHeatmapLegend(context, layout) {
6410
6621
  if (layout.reservedSpace.legend <= 0 || layout.zones.length === 0) {
6411
6622
  return [];
6412
6623
  }
6413
- const barX = layout.grid.x;
6414
- const barWidth = layout.grid.width;
6415
- const labelHeight = layout.fontSize + 2;
6416
- const barY = layout.grid.y + layout.grid.height + 6;
6417
- const barBounds = boxBounds({ x: barX, y: barY, width: barWidth, height: BAR_HEIGHT });
6418
- return [
6419
- createGradientBar(context, layout, barX, barY, barWidth, barBounds),
6420
- ...createBoundaryTicks(context, layout, barX, barY, barWidth, labelHeight)
6421
- ];
6624
+ const place = barPlace(layout);
6625
+ const barBounds = boxBounds({ x: place.x, y: place.y, width: place.width, height: place.height });
6626
+ return [createGradientBar(context, layout, place, barBounds), ...createBoundaryTicks(context, layout, place)];
6422
6627
  }
6423
6628
  function bandRatio(layout, value) {
6424
6629
  const first = layout.bands[0];
6425
6630
  const last = layout.bands[layout.bands.length - 1];
6426
6631
  return last === first ? 0 : (value - first) / (last - first);
6427
6632
  }
6428
- function createGradientBar(context, layout, barX, barY, barWidth, barBounds) {
6633
+ function createGradientBar(context, layout, place, barBounds) {
6429
6634
  const { chart, nextOrder } = context;
6430
6635
  const bandCount = Math.max(0, layout.bands.length - 1);
6431
6636
  const zones = layout.zones.slice(0, bandCount);
@@ -6438,53 +6643,77 @@ function createGradientBar(context, layout, barX, barY, barWidth, barBounds) {
6438
6643
  id: `chart-heatmap-legend-bar-${chart.id}`,
6439
6644
  order: nextOrder(),
6440
6645
  bounds: barBounds,
6441
- x: barX,
6442
- y: barY,
6443
- width: barWidth,
6444
- height: BAR_HEIGHT,
6646
+ x: place.x,
6647
+ y: place.y,
6648
+ width: place.width,
6649
+ height: place.height,
6445
6650
  rx: 3,
6446
6651
  zoneGradient: { axis: "y", min: chart.axisY.min, max: chart.axisY.max },
6447
6652
  style: {
6448
- fill: stops.length ? { kind: "linear-gradient", angle: 0, stops } : { kind: "solid", color: DEFAULT_ZONE_FILL },
6653
+ // Across the grid it runs from the lowest value on the left; beside it from the lowest at the bottom.
6654
+ fill: stops.length ? { kind: "linear-gradient", angle: place.vertical ? 270 : 0, stops } : { kind: "solid", color: DEFAULT_ZONE_FILL },
6449
6655
  stroke: { kind: "solid", color: chart.gridColor ?? "#e2e8f0" },
6450
6656
  strokeWidth: 1
6451
6657
  }
6452
6658
  };
6453
6659
  }
6454
- function createBoundaryTicks(context, layout, barX, barY, barWidth, labelHeight) {
6660
+ function createBoundaryTicks(context, layout, place) {
6455
6661
  const { chart, bounds, nextOrder } = context;
6456
- const labelY = barY + BAR_HEIGHT + TICK_HEIGHT + ROW_GAP;
6457
- const labelWidth = 48;
6662
+ const labelHeight = layout.fontSize + 2;
6663
+ const lastIndex = layout.bands.length - 1;
6458
6664
  return layout.bands.flatMap((value, index) => {
6459
- const x = barX + bandRatio(layout, value) * barWidth;
6665
+ const ratio = bandRatio(layout, value);
6666
+ const at = place.vertical ? place.y + place.height - ratio * place.height : place.x + ratio * place.width;
6667
+ const tickPath = tickPathAt(place, at);
6460
6668
  const tick = {
6461
6669
  type: "path",
6462
6670
  id: `chart-heatmap-legend-tick-${chart.id}-${index}`,
6463
6671
  order: nextOrder(),
6464
6672
  bounds,
6465
- d: `M ${x} ${barY + BAR_HEIGHT} L ${x} ${barY + BAR_HEIGHT + TICK_HEIGHT}`,
6673
+ d: tickPath,
6466
6674
  style: {
6467
6675
  fill: { kind: "none" },
6468
6676
  stroke: { kind: "solid", color: chart.gridColor ?? "#e2e8f0" },
6469
6677
  strokeWidth: 1
6470
6678
  }
6471
6679
  };
6472
- const isFirst = index === 0;
6473
- const isLast = index === layout.bands.length - 1;
6474
- const align = isFirst ? "left" : isLast ? "right" : "center";
6475
- const frameX = isFirst ? x : isLast ? x - labelWidth : x - labelWidth / 2;
6476
6680
  const label = chartText({
6477
6681
  id: `chart-heatmap-legend-tick-label-${chart.id}-${index}`,
6478
6682
  order: nextOrder(),
6479
6683
  bounds,
6480
- frame: { x: frameX, y: labelY, width: labelWidth, height: labelHeight },
6684
+ ...labelAt(place, at, index === 0, index === lastIndex, labelHeight),
6481
6685
  text: formatFieldValue(value),
6482
- chart,
6483
- align
6686
+ chart
6484
6687
  });
6485
6688
  return [tick, label];
6486
6689
  });
6487
6690
  }
6691
+ function tickPathAt(place, at) {
6692
+ if (place.vertical) {
6693
+ const from2 = place.numbers === "right" ? place.x + place.width : place.x;
6694
+ const to2 = place.numbers === "right" ? from2 + TICK_LENGTH2 : from2 - TICK_LENGTH2;
6695
+ return `M ${from2} ${at} L ${to2} ${at}`;
6696
+ }
6697
+ const from = place.numbers === "bottom" ? place.y + place.height : place.y;
6698
+ const to = place.numbers === "bottom" ? from + TICK_LENGTH2 : from - TICK_LENGTH2;
6699
+ return `M ${at} ${from} L ${at} ${to}`;
6700
+ }
6701
+ function labelAt(place, at, first, last, labelHeight) {
6702
+ if (place.vertical) {
6703
+ const onRight = place.numbers === "right";
6704
+ const x2 = onRight ? place.x + place.width + TICK_LENGTH2 + ROW_GAP : place.x - TICK_LENGTH2 - ROW_GAP - LABEL_WIDTH;
6705
+ return {
6706
+ frame: { x: x2, y: at - labelHeight / 2, width: LABEL_WIDTH, height: labelHeight },
6707
+ align: onRight ? "left" : "right"
6708
+ };
6709
+ }
6710
+ const y = place.numbers === "bottom" ? place.y + place.height + TICK_LENGTH2 + ROW_GAP : place.y - TICK_LENGTH2 - ROW_GAP - labelHeight;
6711
+ const x = first ? at : last ? at - LABEL_WIDTH : at - LABEL_WIDTH / 2;
6712
+ return {
6713
+ frame: { x, y, width: LABEL_WIDTH, height: labelHeight },
6714
+ align: first ? "left" : last ? "right" : "center"
6715
+ };
6716
+ }
6488
6717
 
6489
6718
  // src/renderScene/charts/renderers/heatmap.ts
6490
6719
  function renderHeatmap(context) {
@@ -7259,14 +7488,14 @@ function createMekkoLayout(context) {
7259
7488
  const labelGutterWidth = context.showLabels ? 30 : 0;
7260
7489
  const grid = createMekkoGrid(context, labelGutterWidth);
7261
7490
  const fontSize = Math.max(9, finite(context.chart.fontSize, 12));
7262
- const columnGap = Math.max(0, finite(context.chart.config?.mekkoColumnGap, 4));
7491
+ const columnGap2 = Math.max(0, finite(context.chart.config?.mekkoColumnGap, 4));
7263
7492
  const smallFontSize = Math.max(8, fontSize - 1);
7264
7493
  return {
7265
- columns: createMekkoColumns(context, grid, labels, columnGap),
7494
+ columns: createMekkoColumns(context, grid, labels, columnGap2),
7266
7495
  fontSize,
7267
7496
  smallFontSize,
7268
7497
  labelGutterWidth,
7269
- columnGap,
7498
+ columnGap: columnGap2,
7270
7499
  labelSize: Math.max(6, finite(context.chart.config?.mekkoLabelSize, smallFontSize)),
7271
7500
  valueSize: Math.max(6, finite(context.chart.config?.mekkoValueSize, smallFontSize)),
7272
7501
  grid
@@ -7286,20 +7515,20 @@ function createMekkoGrid(context, labelGutterWidth) {
7286
7515
  height: Math.max(1, context.plot.height - topGutter - bottomGutter)
7287
7516
  };
7288
7517
  }
7289
- function createMekkoColumns(context, grid, labels, columnGap) {
7518
+ function createMekkoColumns(context, grid, labels, columnGap2) {
7290
7519
  const totals = labels.map(
7291
7520
  (_, columnIndex) => context.chart.series.reduce((sum, series) => sum + (series.values[columnIndex] ?? 0), 0)
7292
7521
  );
7293
7522
  const grandTotal = totals.reduce((sum, total) => sum + total, 0);
7294
7523
  const maximumTotal = Math.max(1, ...totals);
7295
- const availableWidth = Math.max(1, grid.width - columnGap * Math.max(0, labels.length - 1));
7524
+ const availableWidth = Math.max(1, grid.width - columnGap2 * Math.max(0, labels.length - 1));
7296
7525
  let nextX = grid.x;
7297
7526
  return labels.map((label, index) => {
7298
7527
  const total = totals[index];
7299
7528
  const width = grandTotal > 0 ? total / grandTotal * availableWidth : availableWidth / labels.length;
7300
7529
  const height = context.chart.config?.mekkoVaryHeight ? grid.height * (total / maximumTotal) : grid.height;
7301
7530
  const column = { label, total, x: nextX, y: grid.y + grid.height - height, width, height };
7302
- nextX += width + columnGap;
7531
+ nextX += width + columnGap2;
7303
7532
  return column;
7304
7533
  });
7305
7534
  }
@@ -7666,7 +7895,7 @@ function renderPie(context) {
7666
7895
  var TOP2 = -Math.PI / 2;
7667
7896
  var TRACK_COLOR_FALLBACK = "#e2e8f0";
7668
7897
  var MIN_LABEL_SWEEP = 14 * Math.PI / 180;
7669
- var LABEL_WIDTH = 80;
7898
+ var LABEL_WIDTH2 = 80;
7670
7899
  var LABEL_RADIUS_FRACTION = 0.62;
7671
7900
  var OUTSIDE_GAP = 14;
7672
7901
  var LEADER_INSET = 3;
@@ -7841,7 +8070,7 @@ function labelPlacement2(context, geometry, angles, series, fillColor) {
7841
8070
  const hasManualOffset = labelOffsetX !== 0 || labelOffsetY !== 0;
7842
8071
  const tooThin = ringThickness < lineHeight * 2 + 6;
7843
8072
  const chordWidth = 2 * geometry.outerRadius * Math.sin(Math.abs(angles.end - angles.start) / 2);
7844
- const fitsInline = !tooThin && chordWidth >= LABEL_WIDTH;
8073
+ const fitsInline = !tooThin && chordWidth >= LABEL_WIDTH2;
7845
8074
  const outsideLabels = context.chart.config?.polarOutsideLabels ?? false;
7846
8075
  if (!fitsInline && !hasManualOffset && !outsideLabels) {
7847
8076
  return void 0;
@@ -7864,7 +8093,7 @@ function createWedgeLabel(context, geometry, angles, series, value, fillColor) {
7864
8093
  const { point, color, outside, mid, tickStart } = placement;
7865
8094
  const { nameSize, valueSize } = labelSizes(chart);
7866
8095
  const lineHeight = Math.max(nameSize, valueSize) * 1.2;
7867
- const tickEnd = outside ? clipSegmentToRect(tickStart, point, LABEL_WIDTH / 2, lineHeight) : tickStart;
8096
+ const tickEnd = outside ? clipSegmentToRect(tickStart, point, LABEL_WIDTH2 / 2, lineHeight) : tickStart;
7868
8097
  const tick = {
7869
8098
  type: "path",
7870
8099
  id: `chart-polar-area-label-tick-${chart.id}-${series.id}`,
@@ -7884,8 +8113,8 @@ function createWedgeLabel(context, geometry, angles, series, value, fillColor) {
7884
8113
  };
7885
8114
  const base = {
7886
8115
  bounds,
7887
- x: point.x - LABEL_WIDTH / 2,
7888
- width: LABEL_WIDTH,
8116
+ x: point.x - LABEL_WIDTH2 / 2,
8117
+ width: LABEL_WIDTH2,
7889
8118
  fontFamily: chart.fontFamily ?? DEFAULT_FONT,
7890
8119
  align: "center",
7891
8120
  verticalAlign: "middle",
@@ -8675,8 +8904,8 @@ function treemapLeafColor(leaf, layout) {
8675
8904
  }
8676
8905
 
8677
8906
  // src/renderScene/charts/renderers/treemap/legend.ts
8678
- var BAR_THICKNESS = 10;
8679
- var TICK_LENGTH2 = 4;
8907
+ var BAR_THICKNESS2 = 10;
8908
+ var TICK_LENGTH3 = 4;
8680
8909
  var ROW_GAP2 = 2;
8681
8910
  var CHART_GAP = 16;
8682
8911
  var LABEL_SIZE = 34;
@@ -8705,7 +8934,7 @@ function renderBottomLegend(context, layout) {
8705
8934
  const barWidth = layout.gridWidth;
8706
8935
  const labelHeight = layout.fontSize + 2;
8707
8936
  const barY = plot.y + layout.gridHeight + CHART_GAP;
8708
- const barBounds = boxBounds({ x: barX, y: barY, width: barWidth, height: BAR_THICKNESS });
8937
+ const barBounds = boxBounds({ x: barX, y: barY, width: barWidth, height: BAR_THICKNESS2 });
8709
8938
  const stops = bandStops(layout);
8710
8939
  const bar = {
8711
8940
  type: "rect",
@@ -8715,7 +8944,7 @@ function renderBottomLegend(context, layout) {
8715
8944
  x: barX,
8716
8945
  y: barY,
8717
8946
  width: barWidth,
8718
- height: BAR_THICKNESS,
8947
+ height: BAR_THICKNESS2,
8719
8948
  rx: 3,
8720
8949
  zoneGradient: { axis: "y", min: chart.axisY.min, max: chart.axisY.max },
8721
8950
  style: {
@@ -8731,7 +8960,7 @@ function renderBottomLegend(context, layout) {
8731
8960
  id: `chart-treemap-legend-tick-${chart.id}-${index}`,
8732
8961
  order: nextOrder(),
8733
8962
  bounds,
8734
- d: `M ${x} ${barY + BAR_THICKNESS} L ${x} ${barY + BAR_THICKNESS + TICK_LENGTH2}`,
8963
+ d: `M ${x} ${barY + BAR_THICKNESS2} L ${x} ${barY + BAR_THICKNESS2 + TICK_LENGTH3}`,
8735
8964
  style: {
8736
8965
  fill: { kind: "none" },
8737
8966
  stroke: { kind: "solid", color: chart.gridColor ?? "#e2e8f0" },
@@ -8746,7 +8975,7 @@ function renderBottomLegend(context, layout) {
8746
8975
  id: `chart-treemap-legend-tick-label-${chart.id}-${index}`,
8747
8976
  order: nextOrder(),
8748
8977
  bounds,
8749
- frame: { x: frameX, y: barY + BAR_THICKNESS + TICK_LENGTH2 + ROW_GAP2, width: LABEL_SIZE, height: labelHeight },
8978
+ frame: { x: frameX, y: barY + BAR_THICKNESS2 + TICK_LENGTH3 + ROW_GAP2, width: LABEL_SIZE, height: labelHeight },
8750
8979
  text: formatFieldValue(value),
8751
8980
  chart,
8752
8981
  align
@@ -8760,8 +8989,8 @@ function renderSideLegend(context, layout) {
8760
8989
  const side = layout.legendPosition;
8761
8990
  const barTop = plot.y;
8762
8991
  const barHeight = layout.gridHeight;
8763
- const barX = side === "left" ? plot.x - CHART_GAP - BAR_THICKNESS : plot.x + layout.gridWidth + CHART_GAP;
8764
- const barBounds = boxBounds({ x: barX, y: barTop, width: BAR_THICKNESS, height: barHeight });
8992
+ const barX = side === "left" ? plot.x - CHART_GAP - BAR_THICKNESS2 : plot.x + layout.gridWidth + CHART_GAP;
8993
+ const barBounds = boxBounds({ x: barX, y: barTop, width: BAR_THICKNESS2, height: barHeight });
8765
8994
  const stops = bandStops(layout);
8766
8995
  const bar = {
8767
8996
  type: "rect",
@@ -8770,7 +8999,7 @@ function renderSideLegend(context, layout) {
8770
8999
  bounds: barBounds,
8771
9000
  x: barX,
8772
9001
  y: barTop,
8773
- width: BAR_THICKNESS,
9002
+ width: BAR_THICKNESS2,
8774
9003
  height: barHeight,
8775
9004
  rx: 3,
8776
9005
  zoneGradient: { axis: "y", min: chart.axisY.min, max: chart.axisY.max },
@@ -8780,8 +9009,8 @@ function renderSideLegend(context, layout) {
8780
9009
  strokeWidth: 1
8781
9010
  }
8782
9011
  };
8783
- const tickX = side === "left" ? barX : barX + BAR_THICKNESS;
8784
- const tickEndX = side === "left" ? tickX - TICK_LENGTH2 : tickX + TICK_LENGTH2;
9012
+ const tickX = side === "left" ? barX : barX + BAR_THICKNESS2;
9013
+ const tickEndX = side === "left" ? tickX - TICK_LENGTH3 : tickX + TICK_LENGTH3;
8785
9014
  const labelX2 = side === "left" ? tickEndX - ROW_GAP2 - LABEL_SIZE : tickEndX + ROW_GAP2;
8786
9015
  const ticks2 = layout.bands.flatMap((value, index) => {
8787
9016
  const y = barTop + (1 - bandRatio2(layout, value)) * barHeight;
@@ -9205,7 +9434,8 @@ function buildChartTitle(chart, bounds, plot, renderOrder) {
9205
9434
  bounds,
9206
9435
  frame: { x: plot.x, y: chart.y + 12, width: plot.width, height: 20 },
9207
9436
  text: chart.title,
9208
- chart
9437
+ chart,
9438
+ align: chart.titleAlign ?? "left"
9209
9439
  }),
9210
9440
  ...chart.titleColor ? { color: chart.titleColor } : {},
9211
9441
  fontWeight: chart.titleWeight ?? "bold",
@@ -9267,6 +9497,86 @@ function buildCharts(charts, diagnostics) {
9267
9497
  );
9268
9498
  }
9269
9499
 
9500
+ // src/renderScene/scene/frameClip.ts
9501
+ var ARC_STEPS = 8;
9502
+ function turnOf(node) {
9503
+ const turned = node;
9504
+ if (!turned.rotation) {
9505
+ return void 0;
9506
+ }
9507
+ if (turned.rotationCenter) {
9508
+ return { angle: turned.rotation, x: turned.rotationCenter.x, y: turned.rotationCenter.y };
9509
+ }
9510
+ if (turned.cx !== void 0 && turned.cy !== void 0) {
9511
+ return { angle: turned.rotation, x: turned.cx, y: turned.cy };
9512
+ }
9513
+ if (turned.x !== void 0 && turned.y !== void 0 && turned.width !== void 0 && turned.height !== void 0) {
9514
+ return { angle: turned.rotation, x: turned.x + turned.width / 2, y: turned.y + turned.height / 2 };
9515
+ }
9516
+ return void 0;
9517
+ }
9518
+ function roundedRectPoints(frame) {
9519
+ const { x, y, width, height } = frame;
9520
+ const r = Math.max(0, Math.min(frame.cornerRadius, width / 2, height / 2));
9521
+ if (r === 0) {
9522
+ return [
9523
+ [x, y],
9524
+ [x + width, y],
9525
+ [x + width, y + height],
9526
+ [x, y + height]
9527
+ ];
9528
+ }
9529
+ const corners = [
9530
+ [x + width - r, y + r, -90],
9531
+ [x + width - r, y + height - r, 0],
9532
+ [x + r, y + height - r, 90],
9533
+ [x + r, y + r, 180]
9534
+ ];
9535
+ return corners.flatMap(
9536
+ ([cx, cy, start]) => Array.from({ length: ARC_STEPS + 1 }, (_, step) => {
9537
+ const angle = (start + 90 * step / ARC_STEPS) * Math.PI / 180;
9538
+ return [cx + r * Math.cos(angle), cy + r * Math.sin(angle)];
9539
+ })
9540
+ );
9541
+ }
9542
+ function clipFor(frame, turn) {
9543
+ if (!turn) {
9544
+ return { type: "rect", x: frame.x, y: frame.y, width: frame.width, height: frame.height, rx: frame.cornerRadius };
9545
+ }
9546
+ const back = -turn.angle * Math.PI / 180;
9547
+ const cos = Math.cos(back);
9548
+ const sin = Math.sin(back);
9549
+ const points = roundedRectPoints(frame).map(([px, py]) => {
9550
+ const dx = px - turn.x;
9551
+ const dy = py - turn.y;
9552
+ return [turn.x + dx * cos - dy * sin, turn.y + dx * sin + dy * cos];
9553
+ });
9554
+ const round2 = (value) => Math.round(value * 100) / 100;
9555
+ return { type: "path", d: `M${points.map(([px, py]) => `${round2(px)} ${round2(py)}`).join("L")}Z` };
9556
+ }
9557
+ function applyFrameClips(nodes, frames) {
9558
+ const clipping = new Map(frames.filter((frame) => frame.clip).map((frame) => [frame.id, frame]));
9559
+ if (clipping.size === 0) {
9560
+ return;
9561
+ }
9562
+ const inside = /* @__PURE__ */ new Map();
9563
+ for (const node of nodes) {
9564
+ const parent = node.identity?.parentFrameId;
9565
+ const frame = parent ? clipping.get(parent) : void 0;
9566
+ if (node.identity && frame) {
9567
+ inside.set(`${node.identity.role}:${node.identity.id}`, frame);
9568
+ }
9569
+ }
9570
+ for (const node of nodes) {
9571
+ const frame = node.identity ? inside.get(`${node.identity.role}:${node.identity.id}`) : void 0;
9572
+ const styled = node;
9573
+ if (frame && styled.style) {
9574
+ const edge = clipFor(frame, turnOf(node));
9575
+ styled.style = { ...styled.style, clip: styled.style.clip ? { ...styled.style.clip, within: edge } : edge };
9576
+ }
9577
+ }
9578
+ }
9579
+
9270
9580
  // src/renderScene/scene/build.ts
9271
9581
  function sceneBounds(nodes) {
9272
9582
  if (!nodes.length) {
@@ -9325,6 +9635,7 @@ function buildRenderScene(input, options = {}) {
9325
9635
  ...buildIsometricObjects(input.isometricObjects ?? []),
9326
9636
  ...buildDimensions(input.dimensions ?? [])
9327
9637
  ];
9638
+ applyFrameClips(nodes, input.frames);
9328
9639
  stampStacking(nodes, input);
9329
9640
  nodes.sort(
9330
9641
  (a, b) => (a.rank ?? 0) - (b.rank ?? 0) || (a.sequence ?? 0) - (b.sequence ?? 0) || a.order - b.order || (a.id < b.id ? -1 : a.id > b.id ? 1 : 0)
@@ -9347,17 +9658,17 @@ var SvgClipDefinitions = class {
9347
9658
  prefix;
9348
9659
  ids = /* @__PURE__ */ new Map();
9349
9660
  clip(style) {
9350
- if (!style.clip) {
9351
- return void 0;
9352
- }
9353
- const key = JSON.stringify(style.clip);
9661
+ return style.clip ? this.define(style.clip) : void 0;
9662
+ }
9663
+ define(clip) {
9664
+ const key = JSON.stringify(clip);
9354
9665
  let id = this.ids.get(key);
9355
9666
  if (!id) {
9667
+ const outer = clip.within ? this.define(clip.within) : void 0;
9356
9668
  id = safeId(`${this.prefix}clip-${this.ids.size}`);
9357
9669
  this.ids.set(key, id);
9358
- const clip = style.clip;
9359
9670
  const shape = clip.type === "path" ? `<path clip-rule="evenodd" d="${xml(clip.d)}"/>` : `<rect x="${num(clip.x)}" y="${num(clip.y)}" width="${num(clip.width)}" height="${num(clip.height)}" rx="${num(clip.rx)}"/>`;
9360
- this.addDefinition(`<clipPath id="${id}">${shape}</clipPath>`);
9671
+ this.addDefinition(`<clipPath id="${id}"${outer ? ` clip-path="url(#${outer})"` : ""}>${shape}</clipPath>`);
9361
9672
  }
9362
9673
  return id;
9363
9674
  }
@@ -9386,7 +9697,8 @@ var SvgFilterDefinitions = class {
9386
9697
  );
9387
9698
  }
9388
9699
  if (style.blur || style.saturate !== void 0) {
9389
- return this.define(nodeId, { blur: style.blur ?? 0, saturate: style.saturate ?? 1 }, blurPrimitives);
9700
+ const margin = size && size > 0 && style.blur ? Math.max(0.5, style.blur * 1.5 / size) : 0.5;
9701
+ return this.define(nodeId, { blur: style.blur ?? 0, saturate: style.saturate ?? 1 }, blurPrimitives, margin);
9390
9702
  }
9391
9703
  return void 0;
9392
9704
  }
@@ -9633,12 +9945,19 @@ function addStrokeAttrs(attrs, style) {
9633
9945
  if (style.pointerEvents) {
9634
9946
  attrs.push(`pointer-events="${style.pointerEvents}"`);
9635
9947
  }
9948
+ const css = [];
9636
9949
  if (style.transition && style.transition > 0) {
9637
9950
  const time = `${num(style.transition)}ms ease`;
9638
- attrs.push(
9639
- `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}"`
9951
+ css.push(
9952
+ `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}`
9640
9953
  );
9641
9954
  }
9955
+ if (style.blend) {
9956
+ css.push(`mix-blend-mode: ${xml(style.blend)}`);
9957
+ }
9958
+ if (css.length > 0) {
9959
+ attrs.push(`style="${css.join("; ")}"`);
9960
+ }
9642
9961
  }
9643
9962
  function elementSize(node) {
9644
9963
  const shape = node;
@@ -10006,5 +10325,5 @@ function defineComponent(definition) {
10006
10325
  }
10007
10326
 
10008
10327
  export { collectCanvasObjects, decodeColor, decodeShadow, defineComponent, render, renderCanvas, sflToRenderInput, sliderReach };
10009
- //# sourceMappingURL=chunk-SDMQRSRW.js.map
10010
- //# sourceMappingURL=chunk-SDMQRSRW.js.map
10328
+ //# sourceMappingURL=chunk-FS6L462E.js.map
10329
+ //# sourceMappingURL=chunk-FS6L462E.js.map