@fundar/data-chart-telling 1.16.0 → 1.18.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.
- package/CHANGELOG.md +56 -0
- package/dist/configuration/ConfigVars.svelte +14 -0
- package/dist/configuration/ConfigVars.svelte.d.ts +3 -0
- package/dist/configuration/config.svelte.d.ts +5 -0
- package/dist/configuration/config.svelte.js +20 -6
- package/dist/configuration/themes/dark.js +1 -1
- package/dist/configuration/themes/editorial.js +1 -1
- package/dist/index.d.ts +12 -4
- package/dist/index.js +4 -1
- package/dist/layout/base/BasePlotLayout.svelte +1 -1
- package/dist/layout/figure/Figure.svelte +5 -12
- package/dist/layout/figure/FigureChrome.svelte +2 -10
- package/dist/layout/geometry/GeometryLayout.svelte +219 -44
- package/dist/layout/hover/HoverDefaults.d.ts +52 -0
- package/dist/layout/hover/HoverDefaults.js +96 -0
- package/dist/layout/hover/HoverLayers.d.ts +35 -0
- package/dist/layout/hover/HoverLayers.js +122 -0
- package/dist/layout/hover/HoverSettings.js +4 -1
- package/dist/layout/hover/HoverShapes.d.ts +44 -0
- package/dist/layout/hover/HoverShapes.js +103 -0
- package/dist/layout/hover/PlotHover.svelte.d.ts +18 -0
- package/dist/layout/hover/PlotHover.svelte.js +54 -1
- package/dist/layout/legend/DisabledStyle.d.ts +1 -1
- package/dist/layout/legend/DisabledStyle.js +1 -1
- package/dist/layout/legend/DiscreteBadgeItem.svelte +1 -1
- package/dist/layout/legend/DiscreteSection.svelte +1 -1
- package/dist/layout/legend/LegendState.svelte.d.ts +14 -2
- package/dist/layout/legend/LegendState.svelte.js +23 -4
- package/dist/layout/legend/LegendText.d.ts +4 -1
- package/dist/layout/legend/LegendText.js +7 -1
- package/dist/layout/margins/PlotMargins.svelte.d.ts +2 -2
- package/dist/layout/margins/PlotMargins.svelte.js +2 -2
- package/dist/layout/plot/Core.svelte +2 -2
- package/dist/layout/plot/Plot.svelte +4 -2
- package/dist/layout/plot/Plot.svelte.d.ts +2 -1
- package/dist/layout/plot/PublicPlotContext.d.ts +6 -0
- package/dist/layout/plot/PublicPlotContext.js +8 -0
- package/dist/layout/scales/ScalesLayout.svelte +1 -1
- package/dist/layout/styles/ValueLabels.d.ts +43 -4
- package/dist/layout/styles/ValueLabels.js +87 -19
- package/dist/layout/timeline/Timeline.svelte +5 -1
- package/dist/layout/tooltip/TooltipState.svelte.d.ts +8 -9
- package/dist/layout/tooltip/TooltipState.svelte.js +28 -29
- package/dist/markers/MarkerKinds.d.ts +5 -0
- package/dist/markers/MarkerKinds.js +1 -0
- package/dist/markers/area/AreaMarker.svelte +3 -0
- package/dist/markers/arrow/ArrowMarker.svelte +9 -5
- package/dist/markers/band/BandMarker.svelte +74 -0
- package/dist/markers/band/BandMarker.svelte.d.ts +7 -0
- package/dist/markers/band/Bands.d.ts +16 -0
- package/dist/markers/band/Bands.js +48 -0
- package/dist/markers/bar/BarMarker.svelte +50 -96
- package/dist/markers/bollinger/BollingerMarker.svelte +3 -0
- package/dist/markers/box/BoxMarker.svelte +3 -1
- package/dist/markers/cell/CellMarker.svelte +11 -7
- package/dist/markers/contour/ContourMarker.svelte +3 -0
- package/dist/markers/delaunay/DelaunayLinkMarker.svelte +9 -5
- package/dist/markers/delaunay/DelaunayMeshMarker.svelte +3 -0
- package/dist/markers/density/DensityMarker.svelte +3 -0
- package/dist/markers/difference/DifferenceMarker.svelte +3 -0
- package/dist/markers/dot/DotMarker.svelte +11 -6
- package/dist/markers/geo/GraticuleMarker.svelte +3 -0
- package/dist/markers/geo/SphereMarker.svelte +3 -0
- package/dist/markers/hover/HoverMarker.svelte +7 -249
- package/dist/markers/hover/HoverMarker.svelte.d.ts +4 -27
- package/dist/markers/hull/HullMarker.svelte +3 -0
- package/dist/markers/image/ImageMarker.svelte +3 -0
- package/dist/markers/line/LineMarker.svelte +3 -0
- package/dist/markers/link/LinkMarker.svelte +3 -0
- package/dist/markers/raster/RasterMarker.svelte +3 -0
- package/dist/markers/rect/RectMarker.svelte +25 -17
- package/dist/markers/regression/RegressionMarker.svelte +3 -0
- package/dist/markers/rule/RuleMarker.svelte +15 -5
- package/dist/markers/text/TextFit.d.ts +44 -0
- package/dist/markers/text/TextFit.js +86 -0
- package/dist/markers/text/TextMarker.svelte +186 -90
- package/dist/markers/text/TextMarker.svelte.d.ts +2 -0
- package/dist/markers/tick/TickMarker.svelte +9 -3
- package/dist/markers/trail/TrailMarker.svelte +3 -0
- package/dist/markers/utils/BoxLabel.d.ts +58 -0
- package/dist/markers/utils/BoxLabel.js +175 -0
- package/dist/markers/utils/MarkerEvents.d.ts +23 -0
- package/dist/markers/utils/MarkerEvents.js +44 -0
- package/dist/markers/utils/MarkerLabel.svelte +33 -0
- package/dist/markers/utils/MarkerLabel.svelte.d.ts +10 -0
- package/dist/markers/utils/PointPixel.d.ts +37 -0
- package/dist/markers/utils/PointPixel.js +44 -0
- package/dist/markers/utils/RowStroke.d.ts +9 -21
- package/dist/markers/utils/RowStroke.js +10 -21
- package/dist/markers/utils/RowStyle.d.ts +26 -0
- package/dist/markers/utils/RowStyle.js +55 -0
- package/dist/markers/vector/VectorMarker.svelte +3 -0
- package/dist/markers/voronoi/VoronoiMarker.svelte +9 -5
- package/dist/markers/voronoi/VoronoiMeshMarker.svelte +3 -0
- package/dist/markers/waffle/WaffleMarker.svelte +9 -5
- package/dist/phases/Pipeline.d.ts +10 -8
- package/dist/phases/Pipeline.js +13 -9
- package/dist/phases/context/ContextPhase.d.ts +22 -0
- package/dist/phases/context/ContextPhase.js +23 -0
- package/dist/phases/context/RowContext.d.ts +35 -0
- package/dist/phases/context/RowContext.js +95 -0
- package/dist/phases/data/DataPhase.d.ts +4 -4
- package/dist/phases/data/DataPhase.js +53 -12
- package/dist/phases/hover/HoverPhase.d.ts +6 -7
- package/dist/phases/hover/HoverPhase.js +28 -15
- package/dist/phases/mapping/MappingPhase.d.ts +4 -4
- package/dist/phases/mapping/MappingPhase.js +4 -3
- package/dist/phases/markers/MarkerStyles.d.ts +26 -0
- package/dist/phases/markers/MarkerStyles.js +126 -0
- package/dist/phases/markers/MarkersPhase.d.ts +5 -5
- package/dist/phases/markers/MarkersPhase.js +8 -6
- package/dist/phases/scales/ScalesPhase.d.ts +4 -4
- package/dist/phases/scales/ScalesPhase.js +4 -4
- package/dist/phases/sharedScales/SharedScalesPhase.d.ts +2 -2
- package/dist/phases/sharedScales/SharedScalesPhase.js +2 -2
- package/dist/phases/statistics/MarkerGrouping.d.ts +0 -9
- package/dist/phases/statistics/MarkerGrouping.js +0 -16
- package/dist/phases/statistics/StatisticsPhase.js +1 -1
- package/dist/phases/styles/StylesPhase.d.ts +3 -3
- package/dist/phases/styles/StylesPhase.js +2 -2
- package/dist/phases/tooltip/TooltipPhase.d.ts +4 -4
- package/dist/phases/tooltip/TooltipPhase.js +10 -7
- package/dist/phases/transforms/Transforms.js +3 -1
- package/dist/phases/transforms/TransformsPhase.d.ts +3 -3
- package/dist/phases/transforms/TransformsPhase.js +60 -6
- package/dist/phases/transforms/methods/TreemapTransform.d.ts +28 -0
- package/dist/phases/transforms/methods/TreemapTransform.js +119 -0
- package/dist/plots/correlation/heatmap/defaults.d.ts +2 -2
- package/dist/plots/correlation/heatmap/defaults.js +23 -8
- package/dist/plots/correlation/heatmap/markers.d.ts +2 -10
- package/dist/plots/correlation/heatmap/markers.js +11 -37
- package/dist/plots/correlation/scatter/defaults.d.ts +2 -2
- package/dist/plots/correlation/scatter/defaults.js +9 -3
- package/dist/plots/correlation/scatter/markers.d.ts +3 -3
- package/dist/plots/correlation/scatter/markers.js +6 -5
- package/dist/plots/distribution/box/BoxSummaries.d.ts +17 -8
- package/dist/plots/distribution/box/BoxSummaries.js +90 -40
- package/dist/plots/distribution/box/defaults.d.ts +2 -2
- package/dist/plots/distribution/box/defaults.js +9 -6
- package/dist/plots/distribution/box/markers.d.ts +2 -2
- package/dist/plots/distribution/box/markers.js +3 -3
- package/dist/plots/distribution/density/defaults.d.ts +2 -2
- package/dist/plots/distribution/density/defaults.js +17 -1
- package/dist/plots/distribution/density/markers.d.ts +2 -2
- package/dist/plots/distribution/density/markers.js +4 -4
- package/dist/plots/distribution/histogram/defaults.d.ts +2 -2
- package/dist/plots/distribution/histogram/defaults.js +22 -27
- package/dist/plots/distribution/histogram/markers.d.ts +3 -12
- package/dist/plots/distribution/histogram/markers.js +21 -62
- package/dist/plots/distribution/pyramid/defaults.d.ts +2 -2
- package/dist/plots/distribution/pyramid/defaults.js +7 -4
- package/dist/plots/distribution/pyramid/markers.d.ts +2 -12
- package/dist/plots/distribution/pyramid/markers.js +16 -66
- package/dist/plots/distribution/violin/defaults.d.ts +2 -2
- package/dist/plots/distribution/violin/defaults.js +9 -7
- package/dist/plots/distribution/violin/markers.d.ts +2 -2
- package/dist/plots/distribution/violin/markers.js +4 -4
- package/dist/plots/evolution/area/defaults.d.ts +2 -2
- package/dist/plots/evolution/area/defaults.js +1 -1
- package/dist/plots/evolution/area/markers.d.ts +2 -2
- package/dist/plots/evolution/area/markers.js +4 -4
- package/dist/plots/evolution/line/defaults.d.ts +2 -2
- package/dist/plots/evolution/line/defaults.js +1 -1
- package/dist/plots/evolution/line/markers.d.ts +2 -2
- package/dist/plots/evolution/line/markers.js +3 -3
- package/dist/plots/evolution/slope/defaults.d.ts +2 -2
- package/dist/plots/evolution/slope/defaults.js +8 -4
- package/dist/plots/evolution/slope/markers.d.ts +2 -2
- package/dist/plots/evolution/slope/markers.js +3 -3
- package/dist/plots/evolution/sparkline/defaults.d.ts +2 -2
- package/dist/plots/evolution/sparkline/defaults.js +5 -2
- package/dist/plots/evolution/sparkline/markers.d.ts +2 -2
- package/dist/plots/evolution/sparkline/markers.js +3 -3
- package/dist/plots/map/geo/Core.svelte +3 -3
- package/dist/plots/map/geo/defaults.d.ts +2 -2
- package/dist/plots/map/geo/phases/data.d.ts +1 -1
- package/dist/plots/map/geo/phases/data.js +1 -1
- package/dist/plots/map/geo/phases/hover.d.ts +2 -2
- package/dist/plots/map/geo/phases/hover.js +3 -3
- package/dist/plots/map/geo/phases/markers.d.ts +2 -2
- package/dist/plots/map/geo/phases/markers.js +5 -4
- package/dist/plots/map/geo/phases/scales.d.ts +2 -2
- package/dist/plots/map/geo/phases/scales.js +2 -2
- package/dist/plots/part-of-a-whole/treemap/Plot.svelte +47 -0
- package/dist/plots/part-of-a-whole/treemap/Plot.svelte.d.ts +26 -0
- package/dist/plots/part-of-a-whole/treemap/defaults.d.ts +10 -0
- package/dist/plots/part-of-a-whole/treemap/defaults.js +183 -0
- package/dist/plots/ranking/bar/defaults.d.ts +2 -2
- package/dist/plots/ranking/bar/defaults.js +15 -9
- package/dist/plots/ranking/bar/markers.d.ts +4 -14
- package/dist/plots/ranking/bar/markers.js +45 -86
- package/dist/plots/ranking/bullet/defaults.d.ts +2 -2
- package/dist/plots/ranking/bullet/defaults.js +4 -4
- package/dist/plots/ranking/bullet/markers.d.ts +3 -3
- package/dist/plots/ranking/bullet/markers.js +11 -12
- package/dist/plots/ranking/cleveland/ClevelandMarkers.d.ts +3 -3
- package/dist/plots/ranking/cleveland/ClevelandMarkers.js +28 -23
- package/dist/plots/ranking/cleveland/defaults.d.ts +2 -2
- package/dist/plots/ranking/cleveland/defaults.js +7 -4
- package/dist/plots/ranking/dumbbell/defaults.d.ts +2 -2
- package/dist/plots/ranking/forest/defaults.d.ts +2 -2
- package/dist/plots/ranking/lollipop/defaults.d.ts +2 -2
- package/dist/types/configuration/styling.d.ts +31 -2
- package/dist/types/layout/context.d.ts +21 -0
- package/dist/types/layout/context.js +1 -0
- package/dist/types/layout/hover.d.ts +3 -0
- package/dist/types/layout/legend.d.ts +8 -1
- package/dist/types/layout/mapping.d.ts +12 -3
- package/dist/types/layout/scales.d.ts +6 -0
- package/dist/types/layout/styles/values.d.ts +8 -2
- package/dist/types/layout/tooltip.d.ts +11 -4
- package/dist/types/markers/axis/arrow.d.ts +2 -8
- package/dist/types/markers/axis/axisBasedMarkersConfig.d.ts +2 -1
- package/dist/types/markers/axis/band.d.ts +24 -0
- package/dist/types/markers/axis/band.js +1 -0
- package/dist/types/markers/axis/bar.d.ts +6 -10
- package/dist/types/markers/axis/cell.d.ts +5 -5
- package/dist/types/markers/axis/delaunayLink.d.ts +2 -2
- package/dist/types/markers/axis/hover.d.ts +60 -15
- package/dist/types/markers/axis/rect.d.ts +4 -8
- package/dist/types/markers/axis/rule.d.ts +2 -16
- package/dist/types/markers/axis/tick.d.ts +2 -2
- package/dist/types/markers/axis/voronoi.d.ts +2 -2
- package/dist/types/markers/axis/waffle.d.ts +4 -3
- package/dist/types/markers/basic/dot.d.ts +2 -2
- package/dist/types/markers/basic/text.d.ts +56 -14
- package/dist/types/markers/channels/commonMarkerConfig.d.ts +8 -1
- package/dist/types/markers/channels/commonMarkerConfigWithArea.d.ts +1 -2
- package/dist/types/markers/channels/commonMarkerConfigWithLabel.d.ts +10 -0
- package/dist/types/markers/channels/commonMarkerConfigWithLabel.js +1 -0
- package/dist/types/markers/channels/commonMarkerEvents.d.ts +17 -0
- package/dist/types/markers/channels/commonMarkerEvents.js +13 -0
- package/dist/types/markers/common.d.ts +1 -0
- package/dist/types/markers/common.js +1 -0
- package/dist/types/markers/geo/contour.d.ts +2 -1
- package/dist/types/markers/geo/graticule.d.ts +2 -1
- package/dist/types/markers/geo/link.d.ts +2 -1
- package/dist/types/markers/geo/sphere.d.ts +2 -1
- package/dist/types/markers/geo/vector.d.ts +2 -1
- package/dist/types/phases/context/phase.d.ts +7 -0
- package/dist/types/phases/context/phase.js +1 -0
- package/dist/types/phases/data/phase.d.ts +7 -2
- package/dist/types/phases/hover/phase.d.ts +10 -5
- package/dist/types/phases/index.d.ts +2 -1
- package/dist/types/phases/kind.d.ts +11 -8
- package/dist/types/phases/mapping/phase.d.ts +2 -2
- package/dist/types/phases/markers/phase.d.ts +3 -3
- package/dist/types/phases/scales/phase.d.ts +4 -4
- package/dist/types/phases/stage.d.ts +3 -3
- package/dist/types/phases/state.d.ts +8 -1
- package/dist/types/phases/statistics/phase.d.ts +2 -1
- package/dist/types/phases/styles/phase.d.ts +3 -2
- package/dist/types/phases/transforms/phase.d.ts +13 -2
- package/dist/types/plots/constants.d.ts +17 -19
- package/dist/types/plots/correlation/heatmap/props.d.ts +3 -3
- package/dist/types/plots/correlation/heatmap/state.d.ts +2 -2
- package/dist/types/plots/correlation/scatter/props.d.ts +3 -3
- package/dist/types/plots/correlation/scatter/state.d.ts +2 -2
- package/dist/types/plots/data/common.d.ts +19 -6
- package/dist/types/plots/data/geo.d.ts +1 -1
- package/dist/types/plots/distribution/box/props.d.ts +25 -3
- package/dist/types/plots/distribution/box/state.d.ts +6 -17
- package/dist/types/plots/distribution/density/props.d.ts +3 -11
- package/dist/types/plots/distribution/density/state.d.ts +2 -2
- package/dist/types/plots/distribution/histogram/props.d.ts +16 -11
- package/dist/types/plots/distribution/histogram/state.d.ts +2 -2
- package/dist/types/plots/distribution/pyramid/props.d.ts +3 -3
- package/dist/types/plots/distribution/pyramid/state.d.ts +2 -2
- package/dist/types/plots/distribution/violin/props.d.ts +4 -3
- package/dist/types/plots/distribution/violin/state.d.ts +2 -2
- package/dist/types/plots/evolution/area/props.d.ts +3 -3
- package/dist/types/plots/evolution/area/state.d.ts +2 -2
- package/dist/types/plots/evolution/line/props.d.ts +3 -3
- package/dist/types/plots/evolution/line/state.d.ts +2 -2
- package/dist/types/plots/evolution/slope/state.d.ts +2 -2
- package/dist/types/plots/evolution/sparkline/state.d.ts +2 -2
- package/dist/types/plots/map/geo/state.d.ts +1 -1
- package/dist/types/plots/part-of-a-whole/treemap/props.d.ts +29 -0
- package/dist/types/plots/part-of-a-whole/treemap/props.js +1 -0
- package/dist/types/plots/part-of-a-whole/treemap/state.d.ts +6 -0
- package/dist/types/plots/part-of-a-whole/treemap/state.js +1 -0
- package/dist/types/plots/props.d.ts +10 -4
- package/dist/types/plots/ranking/bar/props.d.ts +3 -3
- package/dist/types/plots/ranking/bar/state.d.ts +2 -2
- package/dist/types/plots/ranking/bullet/state.d.ts +2 -2
- package/dist/types/plots/ranking/cleveland/props.d.ts +3 -3
- package/dist/types/plots/ranking/cleveland/state.d.ts +2 -2
- package/dist/types/plots/ranking/dumbbell/props.d.ts +3 -3
- package/dist/types/plots/ranking/dumbbell/state.d.ts +2 -2
- package/dist/types/plots/ranking/forest/props.d.ts +3 -3
- package/dist/types/plots/ranking/forest/state.d.ts +2 -2
- package/dist/types/plots/ranking/lollipop/props.d.ts +3 -3
- package/dist/types/plots/ranking/lollipop/state.d.ts +2 -2
- package/dist/types/plots/styling.d.ts +24 -0
- package/dist/types/transforms/index.d.ts +3 -1
- package/dist/types/transforms/treemap.d.ts +32 -0
- package/dist/types/transforms/treemap.js +5 -0
- package/dist/utils/color/ColorTones.d.ts +19 -0
- package/dist/utils/color/ColorTones.js +64 -0
- package/dist/utils/color/CssColor.d.ts +14 -5
- package/dist/utils/color/CssColor.js +69 -27
- package/dist/utils/color/index.d.ts +4 -0
- package/dist/utils/color/index.js +4 -0
- package/dist/utils/grouping.d.ts +18 -1
- package/dist/utils/grouping.js +31 -0
- package/docs/concepts.md +3 -2
- package/docs/legend.md +8 -5
- package/docs/markers.md +110 -28
- package/docs/plots/evolution/line.md +1 -1
- package/docs/plots/evolution/slope.md +1 -1
- package/docs/plots/part-of-a-whole/treemap.md +103 -0
- package/docs/plots/ranking/bar.md +2 -1
- package/docs/plots/ranking/cleveland.md +1 -1
- package/docs/plots.md +21 -20
- package/docs/scales.md +3 -0
- package/docs/state.md +34 -1
- package/docs/styles-and-segments.md +20 -19
- package/docs/theming.md +6 -12
- package/docs/tooltip-and-hover.md +81 -3
- package/docs/transforms-and-statistics.md +17 -16
- package/examples/LineDates.svelte +1 -1
- package/examples/ResponsiveLine.svelte +3 -1
- package/examples/Treemap.svelte +13 -0
- package/examples/TreemapHover.svelte +25 -0
- package/examples/ValueLabels.svelte +1 -1
- package/examples/datasets/economic-activity.ts +40 -0
- package/examples/datasets/index.ts +1 -0
- package/llms-full.txt +11 -9
- package/llms.txt +4 -1
- package/package.json +3 -1
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
const ELLIPSIS = '…';
|
|
2
|
+
/**
|
|
3
|
+
* How a label that may be too big for its box is written: a smaller size first; failing that the text cut short
|
|
4
|
+
* with an ellipsis on its last line, at the smallest size; failing that its `fallback`; failing that nothing.
|
|
5
|
+
*/
|
|
6
|
+
export class TextFit {
|
|
7
|
+
static fit(options) {
|
|
8
|
+
const whole = TextFit.#shrunk(options.text, options);
|
|
9
|
+
if (whole)
|
|
10
|
+
return whole;
|
|
11
|
+
const size = options.minFontSize;
|
|
12
|
+
const lines = TextFit.wrap(options.text, TextFit.#room(options, size), true, options.minLetters, (t) => options.measure(t, size));
|
|
13
|
+
if (lines)
|
|
14
|
+
return { text: lines.join('\n'), fontSize: size };
|
|
15
|
+
return options.fallback === undefined ? undefined : TextFit.#shrunk(options.fallback, options);
|
|
16
|
+
}
|
|
17
|
+
/** `text` as it is, at the biggest size that holds it all: no cut, or `undefined` at none. */
|
|
18
|
+
static #shrunk(text, options) {
|
|
19
|
+
for (let size = options.fontSize; size >= options.minFontSize; size--) {
|
|
20
|
+
const lines = TextFit.wrap(text, TextFit.#room(options, size), false, options.minLetters, (t) => options.measure(t, size));
|
|
21
|
+
if (lines)
|
|
22
|
+
return { text: lines.join('\n'), fontSize: size };
|
|
23
|
+
}
|
|
24
|
+
return undefined;
|
|
25
|
+
}
|
|
26
|
+
/** How wide the lines are, and how many there are, at `size`. */
|
|
27
|
+
static #room(options, size) {
|
|
28
|
+
return {
|
|
29
|
+
width: options.width,
|
|
30
|
+
lines: Math.floor(options.height / (size * options.lineHeight))
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* `text` on at most `room.lines` lines of `room.width`: whole words per line, a new line after each newline. With `cut`,
|
|
35
|
+
* what does not fit is cut short - the rest of the text on the last line, or a word wider than any line - with an
|
|
36
|
+
* ellipsis; without it, a text that does not fit comes to `undefined`, and so does one whose first line shows
|
|
37
|
+
* under `minLetters` letters.
|
|
38
|
+
*/
|
|
39
|
+
static wrap(text, room, cut, minLetters, measure) {
|
|
40
|
+
if (room.lines < 1)
|
|
41
|
+
return undefined;
|
|
42
|
+
const all = [];
|
|
43
|
+
let overlong = false;
|
|
44
|
+
for (const paragraph of text.split('\n')) {
|
|
45
|
+
let line = '';
|
|
46
|
+
for (const word of paragraph.split(/ +/).filter(Boolean)) {
|
|
47
|
+
const next = line ? `${line} ${word}` : word;
|
|
48
|
+
if (measure(next) <= room.width) {
|
|
49
|
+
line = next;
|
|
50
|
+
continue;
|
|
51
|
+
}
|
|
52
|
+
if (line)
|
|
53
|
+
all.push(line);
|
|
54
|
+
// A word wider than a line goes on one of its own.
|
|
55
|
+
if (measure(word) > room.width) {
|
|
56
|
+
overlong = true;
|
|
57
|
+
all.push(word);
|
|
58
|
+
line = '';
|
|
59
|
+
}
|
|
60
|
+
else {
|
|
61
|
+
line = word;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
if (line)
|
|
65
|
+
all.push(line);
|
|
66
|
+
}
|
|
67
|
+
if (!cut)
|
|
68
|
+
return !overlong && all.length <= room.lines ? all : undefined;
|
|
69
|
+
const lines = all.slice(0, room.lines);
|
|
70
|
+
// The rest of the text goes on the last line, to be cut short there.
|
|
71
|
+
if (all.length > room.lines)
|
|
72
|
+
lines[room.lines - 1] = all.slice(room.lines - 1).join(' ');
|
|
73
|
+
const written = lines.map((line) => TextFit.cut(line, room.width, measure));
|
|
74
|
+
const first = written[0]?.replace(ELLIPSIS, '').replace(/\s/g, '') ?? '';
|
|
75
|
+
return first.length >= minLetters ? written : undefined;
|
|
76
|
+
}
|
|
77
|
+
/** `text` as it fits `width`: as it is, or cut short with an ellipsis. */
|
|
78
|
+
static cut(text, width, measure) {
|
|
79
|
+
if (measure(text) <= width)
|
|
80
|
+
return text;
|
|
81
|
+
let end = text.length;
|
|
82
|
+
while (end > 0 && measure(`${text.slice(0, end).trimEnd()}${ELLIPSIS}`) > width)
|
|
83
|
+
end--;
|
|
84
|
+
return end > 0 ? `${text.slice(0, end).trimEnd()}${ELLIPSIS}` : '';
|
|
85
|
+
}
|
|
86
|
+
}
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
<script lang="ts" generics="TData = Record<string, unknown>">
|
|
2
|
+
import { RowStyle } from '../utils/RowStyle';
|
|
3
|
+
import { MarkerEvents } from '../utils/MarkerEvents';
|
|
2
4
|
import { Text } from 'svelteplot';
|
|
3
5
|
import { usePlot } from '../../layout/plot/usePlot';
|
|
4
6
|
import { getConfiguration } from '../../configuration/config.svelte';
|
|
@@ -6,10 +8,13 @@
|
|
|
6
8
|
import { RowOffset } from '../utils/RowOffset';
|
|
7
9
|
import RowOffsetMarks from '../utils/RowOffsetMarks.svelte';
|
|
8
10
|
import { Declutter } from './Declutter';
|
|
11
|
+
import { SvelteMap } from 'svelte/reactivity';
|
|
12
|
+
import { TextFit, type FittedText } from './TextFit';
|
|
9
13
|
import { NumberFormat } from '../../utils/NumberFormat';
|
|
10
14
|
import { PlotMargins } from '../../layout/margins/PlotMargins.svelte';
|
|
11
15
|
import { Box } from '../../layout/margins/Box';
|
|
12
16
|
import type { TextMarkerConfig } from '../../types/markers/common';
|
|
17
|
+
import type { BoxChannels, BoxSizer } from '../utils/BoxLabel';
|
|
13
18
|
import type { TextAnchor } from '../../types/plots/constants';
|
|
14
19
|
|
|
15
20
|
/**
|
|
@@ -20,7 +25,8 @@
|
|
|
20
25
|
* draws one label per row, inside the plot's content box. With
|
|
21
26
|
* `fitMargins`, the plot's margins grow until the labels fit.
|
|
22
27
|
*/
|
|
23
|
-
const { marker }: { marker: TextMarkerConfig } = $props();
|
|
28
|
+
const { marker, box }: { marker: TextMarkerConfig; box?: BoxChannels | BoxSizer } = $props();
|
|
29
|
+
const events = MarkerEvents.use(() => marker);
|
|
24
30
|
|
|
25
31
|
// A text's anchors as the side of its point it sits on, and back.
|
|
26
32
|
const TEXT_SIDES = { start: 'after', middle: 'middle', end: 'before' } as const;
|
|
@@ -47,15 +53,16 @@
|
|
|
47
53
|
data.length > 0 ? data : placedByRows(x) || placedByRows(y) ? [] : [{} as TData]
|
|
48
54
|
);
|
|
49
55
|
// Per-row accessors give literal values; an empty one takes the flat default.
|
|
50
|
-
const flatFill = $derived(styles?.fill ?? 'currentColor');
|
|
51
56
|
const fill = $derived.by(() => {
|
|
52
|
-
const own =
|
|
53
|
-
if (typeof own !== 'function') return own ??
|
|
54
|
-
return { value: (d: TData) => own(d) ??
|
|
57
|
+
const own = styles?.fill;
|
|
58
|
+
if (typeof own !== 'function') return RowStyle.of(own, displayData) ?? 'currentColor';
|
|
59
|
+
return { value: (d: TData) => own(d) ?? 'currentColor', scale: null };
|
|
55
60
|
});
|
|
56
61
|
const fillOpacity = $derived.by(() => {
|
|
57
|
-
const own =
|
|
58
|
-
return typeof own === 'function'
|
|
62
|
+
const own = styles?.fillOpacity;
|
|
63
|
+
return typeof own === 'function'
|
|
64
|
+
? { value: (d: TData) => own(d) ?? 1, scale: null }
|
|
65
|
+
: RowStyle.opacity(own);
|
|
59
66
|
});
|
|
60
67
|
const fontSize = $derived(styles?.fontSize ?? 12);
|
|
61
68
|
const fontWeight = $derived(styles?.fontWeight ?? 'normal');
|
|
@@ -97,11 +104,7 @@
|
|
|
97
104
|
};
|
|
98
105
|
});
|
|
99
106
|
const perRow = $derived(
|
|
100
|
-
!!declutter ||
|
|
101
|
-
!!marker.edgeAware ||
|
|
102
|
-
!!marker.onPointerEnter ||
|
|
103
|
-
!!marker.onPointerLeave ||
|
|
104
|
-
typeof marker.textAnchor === 'function'
|
|
107
|
+
!!declutter || !!marker.edgeAware || events.any || typeof marker.textAnchor === 'function'
|
|
105
108
|
);
|
|
106
109
|
const dir = $derived(Math.sign(dx) || 1);
|
|
107
110
|
|
|
@@ -128,9 +131,101 @@
|
|
|
128
131
|
return typeof value === 'number' ? numberText(value) : String(value ?? '');
|
|
129
132
|
}
|
|
130
133
|
|
|
134
|
+
/** The pixel size of the box a row's label is fitted to - from the edges it names, or measured by the shape it labels. */
|
|
135
|
+
const boxSizeOf = $derived.by(() => {
|
|
136
|
+
const fit = marker.fit === true ? {} : marker.fit;
|
|
137
|
+
if (!fit) return undefined;
|
|
138
|
+
const own = typeof box === 'function' ? undefined : box;
|
|
139
|
+
const [x1, x2, y1, y2] = [
|
|
140
|
+
fit.x1 ?? own?.x1,
|
|
141
|
+
fit.x2 ?? own?.x2,
|
|
142
|
+
fit.y1 ?? own?.y1,
|
|
143
|
+
fit.y2 ?? own?.y2
|
|
144
|
+
];
|
|
145
|
+
const xScale = plot.scales.x?.fn;
|
|
146
|
+
const yScale = plot.scales.y?.fn;
|
|
147
|
+
if (![x1, x2, y1, y2].includes(undefined)) {
|
|
148
|
+
if (!xScale || !yScale) return undefined;
|
|
149
|
+
const [left, right, top, bottom] = [x1, x2, y1, y2].map(channel);
|
|
150
|
+
const span = (
|
|
151
|
+
scale: typeof xScale,
|
|
152
|
+
from: (d: TData) => unknown,
|
|
153
|
+
to: (d: TData) => unknown,
|
|
154
|
+
d: TData
|
|
155
|
+
) => Math.abs(Number(scale(to(d) as never)) - Number(scale(from(d) as never)));
|
|
156
|
+
return (d: TData) => ({
|
|
157
|
+
width: span(xScale, left, right, d),
|
|
158
|
+
height: span(yScale, top, bottom, d)
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
return typeof box === 'function' ? (d: TData) => box(d, plot.scales as never) : undefined;
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* What each label is written as and at, fitted to its box (`fit`), less the padding. A label with no room is left
|
|
166
|
+
* out, with `undefined`; one with no box to measure is written as it is.
|
|
167
|
+
*/
|
|
168
|
+
const fitted = $derived.by(() => {
|
|
169
|
+
const fit = marker.fit === true ? {} : marker.fit;
|
|
170
|
+
if (!fit || !boxSizeOf) return undefined;
|
|
171
|
+
const padding = fit.padding ?? cfg.text.label.padding;
|
|
172
|
+
const measure = (text: string, size: number) => Box.ofText(text, size, cfg).width;
|
|
173
|
+
const fallback = fit.fallback;
|
|
174
|
+
const fallbackOf = (d: TData) => {
|
|
175
|
+
// As `text` is: a function's result, a field of the row, else the text itself.
|
|
176
|
+
const value =
|
|
177
|
+
typeof fallback === 'function'
|
|
178
|
+
? fallback(d)
|
|
179
|
+
: typeof fallback === 'string' && typeof d === 'object' && d !== null && fallback in d
|
|
180
|
+
? (d as Record<string, unknown>)[fallback]
|
|
181
|
+
: fallback;
|
|
182
|
+
return typeof value === 'number' ? numberText(value) : String(value);
|
|
183
|
+
};
|
|
184
|
+
// Built whole inside this derivation and never changed after it, so it has nothing to react to.
|
|
185
|
+
// eslint-disable-next-line svelte/prefer-svelte-reactivity
|
|
186
|
+
const out = new Map<TData, FittedText | undefined>();
|
|
187
|
+
for (const d of displayData) {
|
|
188
|
+
const size = boxSizeOf(d);
|
|
189
|
+
out.set(
|
|
190
|
+
d,
|
|
191
|
+
size
|
|
192
|
+
? TextFit.fit({
|
|
193
|
+
text: textOf(d),
|
|
194
|
+
fallback: fallback === undefined ? undefined : fallbackOf(d),
|
|
195
|
+
width: size.width - 2 * padding,
|
|
196
|
+
height: size.height - 2 * padding,
|
|
197
|
+
fontSize,
|
|
198
|
+
minFontSize: fit.minFontSize ?? cfg.text.label.minFontSize,
|
|
199
|
+
lineHeight: styles?.lineHeight ?? 1.2,
|
|
200
|
+
minLetters: fit.minLetters ?? cfg.text.label.minLetters,
|
|
201
|
+
measure
|
|
202
|
+
})
|
|
203
|
+
: { text: textOf(d), fontSize }
|
|
204
|
+
);
|
|
205
|
+
}
|
|
206
|
+
return out;
|
|
207
|
+
});
|
|
208
|
+
/** `rows` by the size their labels are written at: svelteplot takes one size for a mark, and a function of the row sets its scales off in a loop. */
|
|
209
|
+
function sizeGroups(rows: TData[]): { size: number; rows: TData[]; texts?: string[] }[] {
|
|
210
|
+
if (!fitted) return [{ size: fontSize, rows }];
|
|
211
|
+
const bySize = new SvelteMap<number, { rows: TData[]; texts: string[] }>();
|
|
212
|
+
for (const d of rows) {
|
|
213
|
+
const own = fitted.get(d);
|
|
214
|
+
const group = bySize.get(own?.fontSize ?? fontSize) ?? { rows: [], texts: [] };
|
|
215
|
+
group.rows.push(d);
|
|
216
|
+
group.texts.push(own?.text ?? '');
|
|
217
|
+
bySize.set(own?.fontSize ?? fontSize, group);
|
|
218
|
+
}
|
|
219
|
+
return [...bySize].map(([size, group]) => ({ size, ...group }));
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
/** The rows with room for a label. */
|
|
223
|
+
const shown = $derived(fitted ? displayData.filter((d) => fitted.get(d)) : displayData);
|
|
224
|
+
|
|
131
225
|
function opacityOf(d: TData): number | undefined {
|
|
132
|
-
const value =
|
|
133
|
-
|
|
226
|
+
const value = styles?.fillOpacity;
|
|
227
|
+
if (typeof value === 'function') return value(d);
|
|
228
|
+
return typeof value === 'string' ? (d as Record<string, number>)[value] : value;
|
|
134
229
|
}
|
|
135
230
|
|
|
136
231
|
/** Each row's pixel position, once both scales resolve. */
|
|
@@ -188,10 +283,10 @@
|
|
|
188
283
|
let groupEl: SVGGElement | undefined = $state();
|
|
189
284
|
|
|
190
285
|
// The plot measures what it draws: how far it reaches out, and with `fitMargins` its margins grow to fit it.
|
|
191
|
-
const measured = $derived(!!plotMargins && (!!marker.
|
|
286
|
+
const measured = $derived(!!plotMargins && (!!marker.onoverflow || !!marker.fitMargins));
|
|
192
287
|
plotMargins?.watch(() => (measured ? groupEl : undefined), {
|
|
193
288
|
grow: () => !!marker.fitMargins,
|
|
194
|
-
|
|
289
|
+
onoverflow: (overflow) => marker.onoverflow?.(overflow),
|
|
195
290
|
// The box isn't tracked reactively: a new layout measures again.
|
|
196
291
|
deps: () => [marker, points]
|
|
197
292
|
});
|
|
@@ -205,38 +300,41 @@
|
|
|
205
300
|
rowLineAnchor: typeof lineAnchor
|
|
206
301
|
)}
|
|
207
302
|
<g transform={projected ? `translate(${rowDx},${rowDy})` : undefined}>
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
303
|
+
{#each sizeGroups(rows) as group (group.size)}
|
|
304
|
+
<Text
|
|
305
|
+
data={group.rows}
|
|
306
|
+
x={x ?? (marker.frameAnchor ? undefined : 0)}
|
|
307
|
+
y={y ?? (marker.frameAnchor ? undefined : 0)}
|
|
308
|
+
frameAnchor={marker.frameAnchor}
|
|
309
|
+
text={((d: TData, index: number) => {
|
|
310
|
+
if (group.texts) return group.texts[index];
|
|
311
|
+
const value = valueOf(d);
|
|
312
|
+
return typeof value === 'number' ? numberText(value) : value;
|
|
313
|
+
}) as (d: TData) => string}
|
|
314
|
+
dx={projected ? 0 : rowDx}
|
|
315
|
+
dy={projected ? 0 : rowDy}
|
|
316
|
+
fill={fill as never}
|
|
317
|
+
fillOpacity={fillOpacity as never}
|
|
318
|
+
fontSize={group.size}
|
|
319
|
+
{fontWeight}
|
|
320
|
+
textAnchor={rowAnchor}
|
|
321
|
+
lineAnchor={rowLineAnchor}
|
|
322
|
+
fontStyle={fontStyleProp}
|
|
323
|
+
lineHeight={styles?.lineHeight}
|
|
324
|
+
rotate={styles?.rotate}
|
|
325
|
+
stroke={RowStyle.of(styles?.stroke, rows)}
|
|
326
|
+
strokeWidth={RowStyle.field(styles?.strokeWidth)}
|
|
327
|
+
paintOrder={styles?.paintOrder}
|
|
328
|
+
class={styles?.class}
|
|
329
|
+
textClass={styles?.textClass}
|
|
330
|
+
/>
|
|
331
|
+
{/each}
|
|
234
332
|
</g>
|
|
235
333
|
{/snippet}
|
|
236
334
|
|
|
237
335
|
{#snippet labels()}
|
|
238
336
|
{#if !perRow}
|
|
239
|
-
<RowOffsetMarks {marker} rows={
|
|
337
|
+
<RowOffsetMarks {marker} rows={shown}>
|
|
240
338
|
{#snippet mark(rows)}
|
|
241
339
|
{@render label(rows, dx, dy, textAnchor, lineAnchor)}
|
|
242
340
|
{/snippet}
|
|
@@ -244,54 +342,52 @@
|
|
|
244
342
|
{:else if (!declutter && !marker.edgeAware) || points}
|
|
245
343
|
<!-- A decluttered or edge-aware label waits for both scales. -->
|
|
246
344
|
{#each displayData as d, i (i)}
|
|
247
|
-
{
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
{
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
345
|
+
{#if !fitted || fitted.get(d)}
|
|
346
|
+
{@const lane = lanes?.get(i)}
|
|
347
|
+
{@const placement = placements?.[i]}
|
|
348
|
+
{@const extraDy = lane?.extraDy ?? 0}
|
|
349
|
+
{@const laneDir = lane?.aligned ? lane.dir : dir}
|
|
350
|
+
{@const labelDx = lane?.aligned ? laneDir * lane.reach : dx}
|
|
351
|
+
{#if declutter && points && (lane?.aligned || extraDy !== 0)}
|
|
352
|
+
{@const { px, py } = points[i]}
|
|
353
|
+
{@const laneX = lane?.aligned ? px + laneDir * lane.laneReach : px + labelDx}
|
|
354
|
+
{@const connector = declutter.connector}
|
|
355
|
+
<path
|
|
356
|
+
d={`M ${px} ${py} H ${laneX} V ${py + extraDy} H ${px + labelDx}`}
|
|
357
|
+
fill="none"
|
|
358
|
+
stroke={connector.stroke}
|
|
359
|
+
stroke-width={connector.strokeWidth}
|
|
360
|
+
stroke-opacity={connector.strokeOpacity ?? opacityOf(d) ?? 1}
|
|
361
|
+
stroke-dasharray={connector.strokeDasharray}
|
|
362
|
+
stroke-linecap={connector.strokeLinecap ?? 'square'}
|
|
363
|
+
stroke-linejoin={connector.strokeLinejoin ?? 'miter'}
|
|
364
|
+
/>
|
|
365
|
+
{/if}
|
|
366
|
+
<!-- svelteplot's Text never wires pointer handlers to its DOM node; a wrapping <g> catches them. -->
|
|
367
|
+
<g role="presentation" {...events.forRow(d, i)}>
|
|
368
|
+
<RowOffsetMarks {marker} rows={[d]}>
|
|
369
|
+
{#snippet mark(rows)}
|
|
370
|
+
{#if placement}
|
|
371
|
+
{@render label(
|
|
372
|
+
rows,
|
|
373
|
+
placement.dx,
|
|
374
|
+
placement.dy + extraDy,
|
|
375
|
+
placement.textAnchor,
|
|
376
|
+
placement.lineAnchor
|
|
377
|
+
)}
|
|
378
|
+
{:else}
|
|
379
|
+
{@render label(
|
|
380
|
+
rows,
|
|
381
|
+
labelDx,
|
|
382
|
+
dy + extraDy,
|
|
383
|
+
lane?.aligned && laneDir !== dir ? flipAnchor(anchorAt(d)) : anchorAt(d),
|
|
384
|
+
lineAnchor
|
|
385
|
+
)}
|
|
386
|
+
{/if}
|
|
387
|
+
{/snippet}
|
|
388
|
+
</RowOffsetMarks>
|
|
389
|
+
</g>
|
|
266
390
|
{/if}
|
|
267
|
-
<!-- svelteplot's Text never wires pointer handlers to its DOM node; a wrapping <g> catches them. -->
|
|
268
|
-
<g
|
|
269
|
-
role="presentation"
|
|
270
|
-
onpointerenter={marker.onPointerEnter && (() => marker.onPointerEnter?.(d))}
|
|
271
|
-
onpointerleave={marker.onPointerLeave && (() => marker.onPointerLeave?.(d))}
|
|
272
|
-
>
|
|
273
|
-
<RowOffsetMarks {marker} rows={[d]}>
|
|
274
|
-
{#snippet mark(rows)}
|
|
275
|
-
{#if placement}
|
|
276
|
-
{@render label(
|
|
277
|
-
rows,
|
|
278
|
-
placement.dx,
|
|
279
|
-
placement.dy + extraDy,
|
|
280
|
-
placement.textAnchor,
|
|
281
|
-
placement.lineAnchor
|
|
282
|
-
)}
|
|
283
|
-
{:else}
|
|
284
|
-
{@render label(
|
|
285
|
-
rows,
|
|
286
|
-
labelDx,
|
|
287
|
-
dy + extraDy,
|
|
288
|
-
lane?.aligned && laneDir !== dir ? flipAnchor(anchorAt(d)) : anchorAt(d),
|
|
289
|
-
lineAnchor
|
|
290
|
-
)}
|
|
291
|
-
{/if}
|
|
292
|
-
{/snippet}
|
|
293
|
-
</RowOffsetMarks>
|
|
294
|
-
</g>
|
|
295
391
|
{/each}
|
|
296
392
|
{/if}
|
|
297
393
|
{/snippet}
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import type { TextMarkerConfig } from '../../types/markers/common';
|
|
2
|
+
import type { BoxChannels, BoxSizer } from '../utils/BoxLabel';
|
|
2
3
|
type $$ComponentProps = {
|
|
3
4
|
marker: TextMarkerConfig;
|
|
5
|
+
box?: BoxChannels | BoxSizer;
|
|
4
6
|
};
|
|
5
7
|
declare function $$render<TData = Record<string, unknown>>(): {
|
|
6
8
|
props: $$ComponentProps;
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
+
import { RowStyle } from '../utils/RowStyle';
|
|
3
|
+
import { MarkerEvents } from '../utils/MarkerEvents';
|
|
2
4
|
import { TickX, TickY } from 'svelteplot';
|
|
3
5
|
import { usePlot } from '../../layout/plot/usePlot';
|
|
4
6
|
import { MarkerChannels } from '../utils/MarkerChannels';
|
|
@@ -7,6 +9,7 @@
|
|
|
7
9
|
|
|
8
10
|
/** Renders one `'tick'` marker as `<TickX>` or `<TickY>`, picked from the way the plot runs (`usePlot().axes`). */
|
|
9
11
|
let { marker }: { marker: TickMarkerConfig } = $props();
|
|
12
|
+
const events = MarkerEvents.use(() => marker);
|
|
10
13
|
|
|
11
14
|
const plot = usePlot();
|
|
12
15
|
const isHorizontal = $derived(plot.axes?.isHorizontal ?? false);
|
|
@@ -15,7 +18,9 @@
|
|
|
15
18
|
const cfg = $derived(getConfiguration());
|
|
16
19
|
const data = $derived(marker.data ?? []);
|
|
17
20
|
const channelStroke = $derived(MarkerChannels.buildFill(data, marker.color, marker.scales, cfg));
|
|
18
|
-
const stroke = $derived(
|
|
21
|
+
const stroke = $derived(
|
|
22
|
+
channelStroke ?? RowStyle.of(marker.styles?.stroke, data) ?? 'currentColor'
|
|
23
|
+
);
|
|
19
24
|
|
|
20
25
|
/**
|
|
21
26
|
* A tick across a band axis spans the whole band, whatever `tickLength` says -
|
|
@@ -33,14 +38,15 @@
|
|
|
33
38
|
</script>
|
|
34
39
|
|
|
35
40
|
<TickMark
|
|
41
|
+
{...events.props}
|
|
36
42
|
{data}
|
|
37
43
|
x={marker.x}
|
|
38
44
|
y={marker.y}
|
|
39
45
|
tickLength={marker.tickLength}
|
|
40
46
|
{...insetProps}
|
|
41
47
|
{stroke}
|
|
42
|
-
strokeWidth={marker.styles?.strokeWidth}
|
|
43
|
-
strokeOpacity={marker.styles?.strokeOpacity}
|
|
48
|
+
strokeWidth={RowStyle.field(marker.styles?.strokeWidth)}
|
|
49
|
+
strokeOpacity={RowStyle.opacity(marker.styles?.strokeOpacity)}
|
|
44
50
|
strokeDasharray={marker.styles?.strokeDasharray}
|
|
45
51
|
strokeLinecap={marker.styles?.strokeLinecap}
|
|
46
52
|
/>
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
+
import { MarkerEvents } from '../utils/MarkerEvents';
|
|
2
3
|
import { Trail } from 'svelteplot';
|
|
3
4
|
import { MarkerChannels } from '../utils/MarkerChannels';
|
|
4
5
|
import { getConfiguration } from '../../configuration/config.svelte';
|
|
@@ -6,6 +7,7 @@
|
|
|
6
7
|
|
|
7
8
|
/** Renders one `'trail'` marker as `<Trail>` - a ribbon whose width follows `r`. */
|
|
8
9
|
let { marker }: { marker: TrailMarkerConfig } = $props();
|
|
10
|
+
const events = MarkerEvents.use(() => marker);
|
|
9
11
|
|
|
10
12
|
const cfg = $derived(getConfiguration());
|
|
11
13
|
const data = $derived(marker.data ?? []);
|
|
@@ -13,6 +15,7 @@
|
|
|
13
15
|
</script>
|
|
14
16
|
|
|
15
17
|
<Trail
|
|
18
|
+
{...events.props}
|
|
16
19
|
{data}
|
|
17
20
|
x={marker.x}
|
|
18
21
|
y={marker.y}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import type { TextMarkerConfig } from '../../types/markers/common';
|
|
2
|
+
import type { TextLabelConfig } from '../../types/markers/basic/text';
|
|
3
|
+
/** Where a row's edge along an axis is: a field of the rows, the symbol a transform keyed it by, a function of the row, or a literal. */
|
|
4
|
+
type Edge = unknown;
|
|
5
|
+
/** The edges of the box each row spans, in the data's own terms. */
|
|
6
|
+
export type BoxChannels = {
|
|
7
|
+
x1: Edge;
|
|
8
|
+
x2: Edge;
|
|
9
|
+
y1: Edge;
|
|
10
|
+
y2: Edge;
|
|
11
|
+
};
|
|
12
|
+
/** The scales a box is measured on. */
|
|
13
|
+
export type BoxScales = Record<string, {
|
|
14
|
+
type?: string;
|
|
15
|
+
fn: any;
|
|
16
|
+
} | undefined>;
|
|
17
|
+
/** The pixel size of the box of a row, for the markers whose boxes are bands of a category axis rather than edges. */
|
|
18
|
+
export type BoxSizer = (row: unknown, scales: BoxScales) => {
|
|
19
|
+
width: number;
|
|
20
|
+
height: number;
|
|
21
|
+
} | undefined;
|
|
22
|
+
/** The `text` marker that labels the boxes a marker draws, and where each label's box is. */
|
|
23
|
+
export type BoxLabelMarker = {
|
|
24
|
+
marker: TextMarkerConfig;
|
|
25
|
+
box: BoxChannels | BoxSizer;
|
|
26
|
+
};
|
|
27
|
+
/** What a marker has to say for its boxes to be labelled. */
|
|
28
|
+
export type Labelled = {
|
|
29
|
+
type?: string;
|
|
30
|
+
data?: unknown[];
|
|
31
|
+
label?: TextLabelConfig;
|
|
32
|
+
x?: Edge;
|
|
33
|
+
y?: Edge;
|
|
34
|
+
x1?: Edge;
|
|
35
|
+
x2?: Edge;
|
|
36
|
+
y1?: Edge;
|
|
37
|
+
y2?: Edge;
|
|
38
|
+
isHorizontal?: boolean;
|
|
39
|
+
role?: string;
|
|
40
|
+
thickness?: number;
|
|
41
|
+
/** The marker's styles: the insets of a cell or a bar are read off them. */
|
|
42
|
+
styles?: object;
|
|
43
|
+
};
|
|
44
|
+
/**
|
|
45
|
+
* How a marker that draws a box per row writes a label in each: the `text` marker for them, centred on the box,
|
|
46
|
+
* and where the box is for it to fit to. A `rect` says it with its edges, a `cell` is a band of each axis, and a bar
|
|
47
|
+
* or a waffle is a band of its category axis and the stretch of its value.
|
|
48
|
+
*/
|
|
49
|
+
export declare class BoxLabel {
|
|
50
|
+
#private;
|
|
51
|
+
/** `undefined` when the marker has no label, or does not say where its boxes are. */
|
|
52
|
+
static of(marker: Labelled, plot?: {
|
|
53
|
+
isHorizontal?: boolean;
|
|
54
|
+
scales?: () => BoxScales | undefined;
|
|
55
|
+
gap?: number;
|
|
56
|
+
}): BoxLabelMarker | undefined;
|
|
57
|
+
}
|
|
58
|
+
export {};
|