@fundar/data-chart-telling 1.18.0 → 1.19.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 +35 -0
- package/README.md +2 -1
- package/dist/configuration/config.svelte.js +1 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.js +2 -1
- package/dist/layout/coordinates/CoordinatesLayout.svelte +3 -1
- package/dist/layout/geometry/GeometryLayout.svelte +57 -22
- package/dist/layout/geometry/ScaleFreeContext.d.ts +31 -0
- package/dist/layout/geometry/ScaleFreeContext.js +65 -0
- package/dist/layout/geometry/ScaleFreeMarks.svelte +14 -0
- package/dist/layout/geometry/ScaleFreeMarks.svelte.d.ts +7 -0
- package/dist/layout/geometry/ScaleGate.svelte.d.ts +8 -0
- package/dist/layout/geometry/ScaleGate.svelte.js +95 -0
- package/dist/layout/geometry/ScaleGateMarks.svelte +15 -0
- package/dist/layout/geometry/ScaleGateMarks.svelte.d.ts +7 -0
- package/dist/layout/hover/HoverShapes.d.ts +20 -8
- package/dist/layout/hover/HoverShapes.js +119 -59
- package/dist/layout/margins/Box.d.ts +4 -0
- package/dist/layout/margins/Box.js +14 -0
- package/dist/layout/margins/PlotMargins.svelte.js +26 -1
- package/dist/layout/plot/{Plot.svelte.d.ts → AbstractPlot.svelte.d.ts} +3 -3
- package/dist/layout/styles/ValueLabels.d.ts +109 -58
- package/dist/layout/styles/ValueLabels.js +299 -141
- package/dist/markers/MarkerKinds.d.ts +79 -1
- package/dist/markers/MarkerKinds.js +149 -23
- package/dist/markers/area/AreaMarker.svelte +1 -1
- package/dist/markers/bar/BarMarker.svelte +8 -6
- package/dist/markers/bollinger/BollingerMarker.svelte +1 -1
- package/dist/markers/box/BoxMarker.svelte +1 -1
- package/dist/markers/dot/DotRadius.d.ts +11 -0
- package/dist/markers/dot/DotRadius.js +21 -0
- package/dist/markers/labels/CurveLabel.svelte +56 -0
- package/dist/markers/labels/CurveLabel.svelte.d.ts +9 -0
- package/dist/markers/labels/LabelMerge.d.ts +11 -0
- package/dist/markers/labels/LabelMerge.js +87 -0
- package/dist/markers/labels/MarkerLabel.svelte +36 -0
- package/dist/markers/labels/MarkerLabel.svelte.d.ts +10 -0
- package/dist/markers/labels/MarkerLabels.d.ts +52 -0
- package/dist/markers/labels/MarkerLabels.js +97 -0
- package/dist/markers/labels/geometry/BoxGeometry.d.ts +8 -0
- package/dist/markers/labels/geometry/BoxGeometry.js +101 -0
- package/dist/markers/labels/geometry/CurveGeometry.d.ts +34 -0
- package/dist/markers/labels/geometry/CurveGeometry.js +193 -0
- package/dist/markers/labels/geometry/PointGeometry.d.ts +9 -0
- package/dist/markers/labels/geometry/PointGeometry.js +22 -0
- package/dist/markers/labels/layouts/BoxLayout.d.ts +10 -0
- package/dist/markers/labels/layouts/BoxLayout.js +49 -0
- package/dist/markers/labels/layouts/PathLayout.d.ts +11 -0
- package/dist/markers/labels/layouts/PathLayout.js +91 -0
- package/dist/markers/labels/layouts/PointLayout.d.ts +19 -0
- package/dist/markers/labels/layouts/PointLayout.js +94 -0
- package/dist/markers/regression/RegressionMarker.svelte +1 -1
- package/dist/markers/text/Covering.d.ts +13 -0
- package/dist/markers/text/Covering.js +29 -0
- package/dist/markers/text/Declutter.d.ts +24 -3
- package/dist/markers/text/Declutter.js +46 -3
- package/dist/markers/text/TextMarker.svelte +90 -17
- package/dist/markers/text/TextMarker.svelte.d.ts +1 -1
- package/dist/markers/tick/TickMarker.svelte +1 -1
- package/dist/markers/utils/MarkerChannels.d.ts +1 -1
- package/dist/markers/utils/MarkerChannels.js +3 -2
- package/dist/markers/violin/ViolinMarker.svelte +1 -1
- package/dist/markers/waffle/WaffleMarker.svelte +1 -1
- package/dist/phases/context/RowContext.d.ts +2 -0
- package/dist/phases/context/RowContext.js +2 -0
- package/dist/phases/markers/MarkerStyles.js +14 -11
- package/dist/phases/markers/MarkersPhase.d.ts +2 -3
- package/dist/phases/markers/MarkersPhase.js +17 -11
- package/dist/phases/statistics/MarkerGrouping.js +5 -32
- package/dist/phases/statistics/MarkerInheritance.d.ts +11 -0
- package/dist/phases/statistics/MarkerInheritance.js +25 -0
- package/dist/phases/statistics/MarkerOrientation.d.ts +26 -0
- package/dist/phases/statistics/MarkerOrientation.js +29 -0
- package/dist/phases/statistics/StatisticsPhase.js +15 -15
- package/dist/phases/transforms/TransformsPhase.js +5 -3
- package/dist/plots/correlation/heatmap/Plot.svelte +2 -2
- package/dist/plots/correlation/heatmap/Plot.svelte.d.ts +0 -1
- package/dist/plots/correlation/heatmap/defaults.js +14 -1
- package/dist/plots/correlation/heatmap/markers.d.ts +0 -6
- package/dist/plots/correlation/heatmap/markers.js +5 -9
- package/dist/plots/correlation/scatter/Plot.svelte +2 -2
- package/dist/plots/correlation/scatter/Plot.svelte.d.ts +0 -1
- package/dist/plots/correlation/scatter/defaults.js +9 -3
- package/dist/plots/correlation/scatter/markers.d.ts +0 -9
- package/dist/plots/correlation/scatter/markers.js +21 -28
- package/dist/plots/distribution/box/BoxSummaries.d.ts +5 -0
- package/dist/plots/distribution/box/BoxSummaries.js +9 -0
- package/dist/plots/distribution/box/Plot.svelte +2 -2
- package/dist/plots/distribution/box/Plot.svelte.d.ts +0 -1
- package/dist/plots/distribution/box/defaults.js +11 -0
- package/dist/plots/distribution/box/markers.js +10 -1
- package/dist/plots/distribution/density/Plot.svelte +2 -2
- package/dist/plots/distribution/density/Plot.svelte.d.ts +0 -1
- package/dist/plots/distribution/density/defaults.js +16 -0
- package/dist/plots/distribution/density/markers.js +5 -1
- package/dist/plots/distribution/histogram/Plot.svelte +2 -2
- package/dist/plots/distribution/histogram/Plot.svelte.d.ts +0 -1
- package/dist/plots/distribution/histogram/defaults.js +16 -11
- package/dist/plots/distribution/histogram/markers.js +3 -3
- package/dist/plots/distribution/pyramid/Plot.svelte +2 -2
- package/dist/plots/distribution/pyramid/Plot.svelte.d.ts +0 -1
- package/dist/plots/distribution/pyramid/defaults.js +9 -2
- package/dist/plots/distribution/pyramid/markers.d.ts +0 -8
- package/dist/plots/distribution/pyramid/markers.js +6 -16
- package/dist/plots/distribution/violin/Plot.svelte +2 -2
- package/dist/plots/distribution/violin/Plot.svelte.d.ts +0 -1
- package/dist/plots/distribution/violin/defaults.js +11 -0
- package/dist/plots/distribution/violin/markers.js +27 -3
- package/dist/plots/evolution/area/Plot.svelte +2 -2
- package/dist/plots/evolution/area/Plot.svelte.d.ts +0 -1
- package/dist/plots/evolution/area/defaults.js +4 -7
- package/dist/plots/evolution/area/markers.js +3 -1
- package/dist/plots/evolution/line/Plot.svelte +2 -2
- package/dist/plots/evolution/line/Plot.svelte.d.ts +0 -1
- package/dist/plots/evolution/line/defaults.js +4 -6
- package/dist/plots/evolution/line/markers.js +3 -1
- package/dist/plots/evolution/slope/Plot.svelte +2 -2
- package/dist/plots/evolution/slope/Plot.svelte.d.ts +0 -1
- package/dist/plots/evolution/slope/defaults.js +4 -3
- package/dist/plots/evolution/slope/markers.d.ts +4 -3
- package/dist/plots/evolution/slope/markers.js +16 -9
- package/dist/plots/evolution/sparkline/Plot.svelte +2 -2
- package/dist/plots/evolution/sparkline/Plot.svelte.d.ts +0 -1
- package/dist/plots/evolution/sparkline/defaults.js +1 -1
- package/dist/plots/evolution/sparkline/markers.js +3 -1
- package/dist/plots/generic/Plot.svelte +42 -0
- package/dist/plots/generic/Plot.svelte.d.ts +25 -0
- package/dist/plots/generic/defaults.d.ts +4 -0
- package/dist/plots/generic/defaults.js +7 -0
- package/dist/plots/map/geo/Plot.svelte +2 -2
- package/dist/plots/map/geo/Plot.svelte.d.ts +0 -1
- package/dist/plots/part-of-a-whole/treemap/Plot.svelte +2 -2
- package/dist/plots/part-of-a-whole/treemap/Plot.svelte.d.ts +0 -1
- package/dist/plots/part-of-a-whole/treemap/defaults.js +2 -2
- package/dist/plots/ranking/bar/Plot.svelte +2 -2
- package/dist/plots/ranking/bar/Plot.svelte.d.ts +0 -1
- package/dist/plots/ranking/bar/defaults.js +13 -3
- package/dist/plots/ranking/bar/markers.js +10 -27
- package/dist/plots/ranking/bullet/Plot.svelte +2 -2
- package/dist/plots/ranking/bullet/Plot.svelte.d.ts +0 -1
- package/dist/plots/ranking/bullet/defaults.js +20 -0
- package/dist/plots/ranking/bullet/markers.js +7 -1
- package/dist/plots/ranking/cleveland/ClevelandMarkers.d.ts +2 -9
- package/dist/plots/ranking/cleveland/ClevelandMarkers.js +65 -47
- package/dist/plots/ranking/cleveland/Plot.svelte +2 -2
- package/dist/plots/ranking/cleveland/Plot.svelte.d.ts +0 -1
- package/dist/plots/ranking/cleveland/defaults.js +33 -2
- package/dist/plots/ranking/dumbbell/Plot.svelte +2 -2
- package/dist/plots/ranking/dumbbell/Plot.svelte.d.ts +0 -1
- package/dist/plots/ranking/forest/Plot.svelte +2 -2
- package/dist/plots/ranking/forest/Plot.svelte.d.ts +0 -1
- package/dist/plots/ranking/lollipop/Plot.svelte +2 -2
- package/dist/plots/ranking/lollipop/Plot.svelte.d.ts +0 -1
- package/dist/types/layout/context.d.ts +2 -0
- package/dist/types/layout/styles/bullet.d.ts +4 -1
- package/dist/types/layout/styles/values.d.ts +51 -11
- package/dist/types/markers/axis/area.d.ts +5 -1
- package/dist/types/markers/axis/bar.d.ts +5 -2
- package/dist/types/markers/axis/bollinger.d.ts +2 -1
- package/dist/types/markers/axis/box.d.ts +2 -1
- package/dist/types/markers/axis/cell.d.ts +4 -1
- package/dist/types/markers/axis/line.d.ts +4 -1
- package/dist/types/markers/axis/rect.d.ts +4 -1
- package/dist/types/markers/axis/regression.d.ts +2 -1
- package/dist/types/markers/axis/tick.d.ts +2 -1
- package/dist/types/markers/axis/trail.d.ts +4 -1
- package/dist/types/markers/axis/violin.d.ts +2 -1
- package/dist/types/markers/axis/waffle.d.ts +5 -1
- package/dist/types/markers/basic/dot.d.ts +4 -1
- package/dist/types/markers/basic/text.d.ts +25 -21
- package/dist/types/markers/channels/commonMarkerConfigWithLabel.d.ts +5 -9
- package/dist/types/markers/channels/commonMarkerConfigWithOrientation.d.ts +5 -0
- package/dist/types/markers/channels/commonMarkerConfigWithOrientation.js +1 -0
- package/dist/types/markers/labels/box.d.ts +57 -0
- package/dist/types/markers/labels/box.js +1 -0
- package/dist/types/markers/labels/common.d.ts +15 -0
- package/dist/types/markers/labels/common.js +1 -0
- package/dist/types/markers/labels/path.d.ts +52 -0
- package/dist/types/markers/labels/path.js +1 -0
- package/dist/types/markers/labels/point.d.ts +40 -0
- package/dist/types/markers/labels/point.js +1 -0
- package/dist/types/markers/traits.d.ts +10 -0
- package/dist/types/phases/markers/phase.d.ts +1 -8
- package/dist/types/phases/statistics/phase.d.ts +8 -3
- package/dist/types/phases/styles/phase.d.ts +15 -3
- package/dist/types/phases/transforms/phase.d.ts +2 -0
- package/dist/types/plots/constants.d.ts +0 -12
- package/dist/types/plots/correlation/heatmap/props.d.ts +3 -2
- package/dist/types/plots/correlation/scatter/props.d.ts +3 -2
- package/dist/types/plots/distribution/box/props.d.ts +6 -2
- package/dist/types/plots/distribution/density/props.d.ts +2 -1
- package/dist/types/plots/distribution/histogram/props.d.ts +3 -2
- package/dist/types/plots/distribution/pyramid/props.d.ts +3 -2
- package/dist/types/plots/distribution/violin/props.d.ts +4 -1
- package/dist/types/plots/evolution/area/props.d.ts +3 -2
- package/dist/types/plots/evolution/line/props.d.ts +3 -2
- package/dist/types/plots/generic/props.d.ts +16 -0
- package/dist/types/plots/generic/props.js +1 -0
- package/dist/types/plots/generic/state.d.ts +4 -0
- package/dist/types/plots/generic/state.js +1 -0
- package/dist/types/plots/part-of-a-whole/treemap/props.d.ts +4 -2
- package/dist/types/plots/ranking/bar/props.d.ts +3 -2
- package/dist/types/plots/ranking/cleveland/props.d.ts +3 -2
- package/dist/types/plots/ranking/dumbbell/props.d.ts +3 -2
- package/dist/types/plots/ranking/forest/props.d.ts +5 -2
- package/dist/types/plots/ranking/lollipop/props.d.ts +3 -2
- package/docs/architecture.md +9 -9
- package/docs/markers.md +2 -4
- package/docs/plots/ranking/cleveland.md +1 -1
- package/docs/styles-and-segments.md +1 -14
- package/docs/value-labels.md +159 -0
- package/examples/BarValues.svelte +1 -1
- package/llms-full.txt +2 -2
- package/llms.txt +1 -0
- package/package.json +3 -1
- package/dist/markers/utils/BoxLabel.d.ts +0 -58
- package/dist/markers/utils/BoxLabel.js +0 -175
- package/dist/markers/utils/MarkerLabel.svelte +0 -33
- package/dist/markers/utils/MarkerLabel.svelte.d.ts +0 -10
- /package/dist/layout/plot/{Plot.svelte → AbstractPlot.svelte} +0 -0
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
|
|
17
17
|
const plot = usePlot();
|
|
18
18
|
const cfg = $derived(getConfiguration());
|
|
19
|
-
const isHorizontal = $derived(plot.axes?.isHorizontal ?? false);
|
|
19
|
+
const isHorizontal = $derived(marker.isHorizontal ?? plot.axes?.isHorizontal ?? false);
|
|
20
20
|
const categoryScale = $derived(
|
|
21
21
|
isHorizontal ? plot.svelteplot.scales.y : plot.svelteplot.scales.x
|
|
22
22
|
);
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
const events = MarkerEvents.use(() => marker);
|
|
13
13
|
|
|
14
14
|
const plot = usePlot();
|
|
15
|
-
const isHorizontal = $derived(plot.axes?.isHorizontal ?? false);
|
|
15
|
+
const isHorizontal = $derived(marker.isHorizontal ?? plot.axes?.isHorizontal ?? false);
|
|
16
16
|
const WaffleMark = $derived(isHorizontal ? WaffleX : WaffleY);
|
|
17
17
|
|
|
18
18
|
const cfg = $derived(getConfiguration());
|
|
@@ -19,6 +19,8 @@ export declare class RowContext {
|
|
|
19
19
|
* for it, with the row itself. A row no plot drew reads as its series alone.
|
|
20
20
|
*/
|
|
21
21
|
static of<TContext extends PlotRowContext = PlotRowContext>(row: unknown): TContext;
|
|
22
|
+
/** The key a row's context is kept under: no scale reads it, so a copy of a row with a new context is no new row to them. */
|
|
23
|
+
static readonly key: symbol;
|
|
22
24
|
/** Keeps `context` on `row`, for {@link of} to read back. */
|
|
23
25
|
static tag(row: ProcessedRow, context: PlotRowContext): void;
|
|
24
26
|
/** Whether `row` carries a context already. */
|
|
@@ -24,6 +24,8 @@ export class RowContext {
|
|
|
24
24
|
const series = record[SERIES_KEY];
|
|
25
25
|
return { ...(typeof series === 'string' ? { series } : {}), row };
|
|
26
26
|
}
|
|
27
|
+
/** The key a row's context is kept under: no scale reads it, so a copy of a row with a new context is no new row to them. */
|
|
28
|
+
static key = KEY;
|
|
27
29
|
/** Keeps `context` on `row`, for {@link of} to read back. */
|
|
28
30
|
static tag(row, context) {
|
|
29
31
|
row[KEY] = context;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { MarkerChannels } from '../../markers/utils/MarkerChannels';
|
|
2
2
|
import { RowStyle } from '../../markers/utils/RowStyle';
|
|
3
3
|
import { CssColor } from '../../utils/color/CssColor';
|
|
4
|
+
import { MarkerLabels } from '../../markers/labels/MarkerLabels';
|
|
4
5
|
/**
|
|
5
6
|
* A plot's markers with their styles as svelteplot reads them, before any is drawn: a named line style
|
|
6
7
|
* (`strokeDasharray: 'dashed'`) is the SVG dash pattern it stands for, wherever in a marker's config it is
|
|
@@ -33,28 +34,30 @@ export class MarkerStyles {
|
|
|
33
34
|
* that read best on the shape's old one reads best on its new one.
|
|
34
35
|
*/
|
|
35
36
|
static restyle(marker, plot = {}) {
|
|
36
|
-
const
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
37
|
+
const fresh = MarkerLabels.map(marker, (label) => {
|
|
38
|
+
const fill = label.styles?.fill;
|
|
39
|
+
return typeof fill === 'function' && MarkerStyles.#contrasts.has(fill)
|
|
40
|
+
? { ...label, styles: { ...label.styles, fill: undefined } }
|
|
41
|
+
: label;
|
|
42
|
+
});
|
|
41
43
|
return MarkerStyles.resolveAll([fresh], plot)[0];
|
|
42
44
|
}
|
|
43
|
-
/**
|
|
45
|
+
/** Writes each label on its shape in the color that reads best on it. */
|
|
44
46
|
static #contrasted(marker, plot) {
|
|
45
47
|
const { cfg } = plot;
|
|
46
48
|
if (!cfg || !MarkerStyles.#isPlain(marker))
|
|
47
49
|
return marker;
|
|
48
|
-
const
|
|
49
|
-
|
|
50
|
+
const unset = (label) => MarkerStyles.#isPlain(label) &&
|
|
51
|
+
MarkerLabels.isOnShape(marker, label) &&
|
|
52
|
+
label.styles?.fill === undefined;
|
|
53
|
+
if (!MarkerLabels.list(marker).some(unset))
|
|
50
54
|
return marker;
|
|
51
|
-
}
|
|
52
55
|
const colorOf = MarkerStyles.#shapeColor(marker, marker.data ?? plot.rows ?? [], cfg);
|
|
53
56
|
if (!colorOf)
|
|
54
57
|
return marker;
|
|
55
58
|
const candidates = cfg.text.label.contrast;
|
|
56
59
|
const opacityOf = MarkerStyles.#opacity(marker.styles?.fillOpacity);
|
|
57
|
-
//
|
|
60
|
+
// The shape's color as seen: blended with the background by its opacity.
|
|
58
61
|
const fill = (row) => {
|
|
59
62
|
const color = colorOf(row);
|
|
60
63
|
if (!color)
|
|
@@ -63,7 +66,7 @@ export class MarkerStyles {
|
|
|
63
66
|
return CssColor.contrastText(seen, candidates);
|
|
64
67
|
};
|
|
65
68
|
MarkerStyles.#contrasts.add(fill);
|
|
66
|
-
return
|
|
69
|
+
return MarkerLabels.map(marker, (label) => unset(label) ? { ...label, styles: { ...label.styles, fill } } : label);
|
|
67
70
|
}
|
|
68
71
|
/** The opacity each row's shape is drawn with: a number, the field of the rows a string names, a function of the row. */
|
|
69
72
|
static #opacity(style) {
|
|
@@ -2,9 +2,8 @@ import type { AxisPlotEnv, AxisPlotState, MarkersStageOptions, PhaseStage } from
|
|
|
2
2
|
/**
|
|
3
3
|
* The shared "markers" phase: everything the plot draws, bottom to top - the
|
|
4
4
|
* plot kind's own marks, then what the "statistics" phase left in
|
|
5
|
-
* `state.markers` (the author's markers and the plot's statistics), then
|
|
6
|
-
*
|
|
7
|
-
* label shares ({@link ValueLabels.hooks}), and every style as svelteplot reads it ({@link MarkerStyles}).
|
|
5
|
+
* `state.markers` (the author's markers and the plot's statistics), then the
|
|
6
|
+
* `'point'` labels of all of them, and every style as svelteplot reads it ({@link MarkerStyles}).
|
|
8
7
|
*/
|
|
9
8
|
export declare class MarkersPhase<TState extends AxisPlotState<any, any, any, any>, TEnv extends AxisPlotEnv> implements PhaseStage<TState, TEnv> {
|
|
10
9
|
#private;
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import { MarkerChannels } from '../../markers/utils/MarkerChannels';
|
|
2
2
|
import { MarkerStyles } from './MarkerStyles';
|
|
3
|
+
import { MarkerLabels } from '../../markers/labels/MarkerLabels';
|
|
4
|
+
import { PlotAxes } from '../data/PlotAxes';
|
|
3
5
|
/**
|
|
4
6
|
* The shared "markers" phase: everything the plot draws, bottom to top - the
|
|
5
7
|
* plot kind's own marks, then what the "statistics" phase left in
|
|
6
|
-
* `state.markers` (the author's markers and the plot's statistics), then
|
|
7
|
-
*
|
|
8
|
-
* label shares ({@link ValueLabels.hooks}), and every style as svelteplot reads it ({@link MarkerStyles}).
|
|
8
|
+
* `state.markers` (the author's markers and the plot's statistics), then the
|
|
9
|
+
* `'point'` labels of all of them, and every style as svelteplot reads it ({@link MarkerStyles}).
|
|
9
10
|
*/
|
|
10
11
|
export class MarkersPhase {
|
|
11
12
|
phase = 'markers';
|
|
@@ -15,16 +16,21 @@ export class MarkersPhase {
|
|
|
15
16
|
}
|
|
16
17
|
run = (state, env) => {
|
|
17
18
|
const options = this.#options;
|
|
18
|
-
const
|
|
19
|
-
const
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
:
|
|
19
|
+
const rows = state.processedData?.data;
|
|
20
|
+
const positioned = MarkerChannels.inheritPosition(MarkerChannels.inheritAll([...options.marks(state, env), ...(state.markers ?? [])], state.scales), state.processedData);
|
|
21
|
+
// Point labels draw last, merged across markers so they declutter together.
|
|
22
|
+
const { markers, labels: pointLabels } = MarkerLabels.extractPoints(positioned, {
|
|
23
|
+
rows,
|
|
24
|
+
valueAxis: PlotAxes.valueOf(state),
|
|
25
|
+
isHorizontal: state.axes?.isHorizontal,
|
|
26
|
+
gap: env.cfg.text?.label.gap
|
|
27
|
+
});
|
|
25
28
|
return {
|
|
26
29
|
...state,
|
|
27
|
-
markers: MarkerStyles.resolveAll(
|
|
30
|
+
markers: MarkerStyles.resolveAll([...markers, ...pointLabels], {
|
|
31
|
+
cfg: env.cfg,
|
|
32
|
+
rows
|
|
33
|
+
})
|
|
28
34
|
};
|
|
29
35
|
};
|
|
30
36
|
}
|
|
@@ -1,33 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
const GROUPING_KINDS = new Set([
|
|
3
|
-
'area',
|
|
4
|
-
'density',
|
|
5
|
-
'line',
|
|
6
|
-
'hull',
|
|
7
|
-
'trail',
|
|
8
|
-
'delaunayLink',
|
|
9
|
-
'delaunayMesh',
|
|
10
|
-
'voronoi',
|
|
11
|
-
'voronoiMesh'
|
|
12
|
-
]);
|
|
13
|
-
/** Marker kinds whose per-row `color` resolves through the plot's own color scale. */
|
|
14
|
-
const COLOR_KINDS = new Set([
|
|
15
|
-
'area',
|
|
16
|
-
'bar',
|
|
17
|
-
'cell',
|
|
18
|
-
'density',
|
|
19
|
-
'delaunayLink',
|
|
20
|
-
'delaunayMesh',
|
|
21
|
-
'dot',
|
|
22
|
-
'hull',
|
|
23
|
-
'line',
|
|
24
|
-
'rect',
|
|
25
|
-
'tick',
|
|
26
|
-
'trail',
|
|
27
|
-
'voronoi',
|
|
28
|
-
'voronoiMesh',
|
|
29
|
-
'waffle'
|
|
30
|
-
]);
|
|
1
|
+
import { MarkerKinds } from '../../markers/MarkerKinds';
|
|
31
2
|
/** Kinds that draw only a line, so their flat color is `stroke` alone. */
|
|
32
3
|
const LINE_KINDS = new Set(['line', 'regression', 'bollinger', 'delta']);
|
|
33
4
|
/** Flat color style keys - when a marker sets one, it keeps that color instead of inheriting one. */
|
|
@@ -86,9 +57,11 @@ export class MarkerGrouping {
|
|
|
86
57
|
if (grouping === undefined)
|
|
87
58
|
return MarkerGrouping.withSeriesColor(m, plot.defaultColor);
|
|
88
59
|
const updates = {};
|
|
89
|
-
if (
|
|
60
|
+
if (MarkerKinds.inherits(m.type, 'grouping') && m.grouping === undefined)
|
|
90
61
|
updates.grouping = grouping;
|
|
91
|
-
if (
|
|
62
|
+
if (MarkerKinds.inherits(m.type, 'color') &&
|
|
63
|
+
m.color === undefined &&
|
|
64
|
+
!MarkerGrouping.#hasFlatColor(m)) {
|
|
92
65
|
updates.color = plot.color ?? plot.grouping;
|
|
93
66
|
}
|
|
94
67
|
return Object.keys(updates).length ? { ...m, ...updates } : marker;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { InheritedChannel } from '../../types/markers/traits';
|
|
2
|
+
/** How a plot's position and value channels reach the markers its author adds. */
|
|
3
|
+
export declare class MarkerInheritance {
|
|
4
|
+
/**
|
|
5
|
+
* `marker` with the plot's `x`/`y` on each axis it sets no position for (`x`, `x1` or `x2`...), and the
|
|
6
|
+
* plot's other channels it sets none of, as far as its kind inherits them.
|
|
7
|
+
*/
|
|
8
|
+
static inherit<T extends {
|
|
9
|
+
type: string;
|
|
10
|
+
}>(marker: T, plot: Partial<Record<InheritedChannel, unknown>>): T;
|
|
11
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { MarkerKinds } from '../../markers/MarkerKinds';
|
|
2
|
+
/** The value channels a marker takes as they are; `grouping` and `color` are `MarkerGrouping`'s. */
|
|
3
|
+
const VALUES = ['opacity', 'symbol', 'r', 'length'];
|
|
4
|
+
/** How a plot's position and value channels reach the markers its author adds. */
|
|
5
|
+
export class MarkerInheritance {
|
|
6
|
+
/**
|
|
7
|
+
* `marker` with the plot's `x`/`y` on each axis it sets no position for (`x`, `x1` or `x2`...), and the
|
|
8
|
+
* plot's other channels it sets none of, as far as its kind inherits them.
|
|
9
|
+
*/
|
|
10
|
+
static inherit(marker, plot) {
|
|
11
|
+
const own = marker;
|
|
12
|
+
const takes = (channel) => plot[channel] !== undefined && MarkerKinds.inherits(own.type, channel);
|
|
13
|
+
const taken = {};
|
|
14
|
+
for (const axis of ['x', 'y']) {
|
|
15
|
+
const unset = [axis, `${axis}1`, `${axis}2`].every((key) => own[key] === undefined);
|
|
16
|
+
if (unset && takes(axis))
|
|
17
|
+
taken[axis] = plot[axis];
|
|
18
|
+
}
|
|
19
|
+
for (const channel of VALUES) {
|
|
20
|
+
if (own[channel] === undefined && takes(channel))
|
|
21
|
+
taken[channel] = plot[channel];
|
|
22
|
+
}
|
|
23
|
+
return Object.keys(taken).length ? { ...own, ...taken } : marker;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
type Marker = {
|
|
2
|
+
type: string;
|
|
3
|
+
isHorizontal?: boolean;
|
|
4
|
+
data?: unknown[];
|
|
5
|
+
} & Record<string, unknown>;
|
|
6
|
+
type AxisScales = {
|
|
7
|
+
x?: {
|
|
8
|
+
type?: string;
|
|
9
|
+
};
|
|
10
|
+
y?: {
|
|
11
|
+
type?: string;
|
|
12
|
+
};
|
|
13
|
+
};
|
|
14
|
+
/** Which way an oriented marker runs when its plot has no position channels to say it. */
|
|
15
|
+
export declare class MarkerOrientation {
|
|
16
|
+
/** `marker` with `isHorizontal` taken from its own channels, unless it sets one or can't tell. */
|
|
17
|
+
static orient<T extends {
|
|
18
|
+
type: string;
|
|
19
|
+
}>(marker: T, rows: unknown[], scales?: AxisScales): T;
|
|
20
|
+
/**
|
|
21
|
+
* A band (`x1`/`x2` or `y1`/`y2`) runs across its own axis; two channels run as a plot's
|
|
22
|
+
* would; a single channel is the measured value.
|
|
23
|
+
*/
|
|
24
|
+
static of(marker: Marker, rows: unknown[], scales?: AxisScales): boolean | undefined;
|
|
25
|
+
}
|
|
26
|
+
export {};
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { MarkerKinds } from '../../markers/MarkerKinds';
|
|
2
|
+
import { PlotAxes } from '../data/PlotAxes';
|
|
3
|
+
/** Which way an oriented marker runs when its plot has no position channels to say it. */
|
|
4
|
+
export class MarkerOrientation {
|
|
5
|
+
/** `marker` with `isHorizontal` taken from its own channels, unless it sets one or can't tell. */
|
|
6
|
+
static orient(marker, rows, scales) {
|
|
7
|
+
const own = marker;
|
|
8
|
+
if (own.isHorizontal !== undefined || !MarkerKinds.of(own.type)?.oriented)
|
|
9
|
+
return marker;
|
|
10
|
+
const isHorizontal = MarkerOrientation.of(own, rows, scales);
|
|
11
|
+
return isHorizontal === undefined ? marker : { ...own, isHorizontal };
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* A band (`x1`/`x2` or `y1`/`y2`) runs across its own axis; two channels run as a plot's
|
|
15
|
+
* would; a single channel is the measured value.
|
|
16
|
+
*/
|
|
17
|
+
static of(marker, rows, scales) {
|
|
18
|
+
const set = (...keys) => keys.some((key) => marker[key] !== undefined);
|
|
19
|
+
const [xBand, yBand] = [set('x1', 'x2'), set('y1', 'y2')];
|
|
20
|
+
if (xBand !== yBand)
|
|
21
|
+
return xBand;
|
|
22
|
+
const [x, y] = [set('x'), set('y')];
|
|
23
|
+
if (x && y) {
|
|
24
|
+
const data = marker.data ?? rows;
|
|
25
|
+
return PlotAxes.build({ series: [{ x: marker.x, y: marker.y, data }], scales }).isHorizontal;
|
|
26
|
+
}
|
|
27
|
+
return x !== y ? x : undefined;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { AuthorMarkers } from './AuthorMarkers';
|
|
2
2
|
import { Statistics } from './Statistics';
|
|
3
|
+
import { MarkerInheritance } from './MarkerInheritance';
|
|
4
|
+
import { MarkerOrientation } from './MarkerOrientation';
|
|
3
5
|
import { PANEL_KEY, FacetPanels } from '../facet/FacetPanels';
|
|
4
6
|
import { PlotAxes } from '../data/PlotAxes';
|
|
5
|
-
/** Marker kinds that draw from a channel pair, so they take the plot's `x`/`y` when the author leaves one out. */
|
|
6
|
-
const POSITIONED_KINDS = new Set(['line', 'area', 'dot']);
|
|
7
7
|
/**
|
|
8
8
|
* The "statistics" phase every axis-based plot shares: seeds `state.markers`
|
|
9
9
|
* with the plot-level `statistics` resolved against every series, followed by
|
|
@@ -38,23 +38,23 @@ export class StatisticsPhase {
|
|
|
38
38
|
#resolve(state) {
|
|
39
39
|
const options = this.#options;
|
|
40
40
|
const { resolvedSeries = [], flat = [], colorForSeries, statistics, authorMarkers = [] } = state;
|
|
41
|
-
const { inheritGrouping = true
|
|
41
|
+
const { inheritGrouping = true } = options;
|
|
42
42
|
const defaultColor = options.defaultColor
|
|
43
43
|
? options.defaultColor(state)
|
|
44
44
|
: resolvedSeries[0] && colorForSeries?.(resolvedSeries[0].name);
|
|
45
45
|
const onProcessed = authorMarkers.map((marker) => AuthorMarkers.withProcessedRows(marker, state.processedData));
|
|
46
|
-
const
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
46
|
+
const unpositioned = !state.axes?.x && !state.axes?.y;
|
|
47
|
+
const positioned = onProcessed.map((marker) => {
|
|
48
|
+
const inherited = MarkerInheritance.inherit(marker, {
|
|
49
|
+
x: resolvedSeries[0]?.x ?? state.x,
|
|
50
|
+
y: resolvedSeries[0]?.y ?? state.y,
|
|
51
|
+
opacity: state.opacity,
|
|
52
|
+
symbol: state.symbol,
|
|
53
|
+
r: state.r,
|
|
54
|
+
length: state.length
|
|
55
|
+
});
|
|
56
|
+
return unpositioned ? MarkerOrientation.orient(inherited, flat, state.scales) : inherited;
|
|
57
|
+
});
|
|
58
58
|
// A series setting no value of its own (a histogram's) measures its processed rows: its bins.
|
|
59
59
|
const valueAxis = PlotAxes.valueOf(state);
|
|
60
60
|
const measured = state.processedData && resolvedSeries.some((s) => s[valueAxis] === undefined)
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { ValueLabels } from '../../layout/styles/ValueLabels';
|
|
1
2
|
import { Transforms } from './Transforms';
|
|
2
3
|
import { ValueSelection } from './ValueSelection';
|
|
3
4
|
import { ProcessedPositions } from './ProcessedPositions';
|
|
@@ -129,17 +130,18 @@ export class TransformsPhase {
|
|
|
129
130
|
#labelled(state) {
|
|
130
131
|
const options = this.#options.labels;
|
|
131
132
|
const values = state.values;
|
|
132
|
-
if (!options || !(values
|
|
133
|
+
if (!options || !ValueLabels.shows(values, options.show))
|
|
133
134
|
return {};
|
|
134
135
|
const processed = state.processedData;
|
|
135
|
-
const
|
|
136
|
+
const measure = options.measure?.(state);
|
|
137
|
+
const valueAxis = measure ? 'y' : PlotAxes.valueOf(state);
|
|
136
138
|
const select = values?.select ?? options.select;
|
|
137
139
|
const selections = ValueSelection.transforms(select, values?.series, valueAxis);
|
|
138
140
|
const position = ProcessedPositions.of(processed, valueAxis);
|
|
139
141
|
const skip = options.skip?.(state);
|
|
140
142
|
const channels = {
|
|
141
143
|
x: position.x,
|
|
142
|
-
y: position.y,
|
|
144
|
+
y: measure ?? position.y,
|
|
143
145
|
group: options.group === 'category'
|
|
144
146
|
? position[PlotAxes.categoryOf(state)]
|
|
145
147
|
: SERIES_ID_KEY
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<script lang="ts" generics="TData extends Record<string, unknown>">
|
|
2
|
-
import
|
|
2
|
+
import AbstractPlot from '../../../layout/plot/AbstractPlot.svelte';
|
|
3
3
|
import { buildHeatmapDefaults } from './defaults';
|
|
4
4
|
import type {
|
|
5
5
|
HeatmapPlotProps,
|
|
@@ -44,7 +44,7 @@
|
|
|
44
44
|
});
|
|
45
45
|
</script>
|
|
46
46
|
|
|
47
|
-
<
|
|
47
|
+
<AbstractPlot
|
|
48
48
|
core={core as HeatmapPlotCoreProps<TData>}
|
|
49
49
|
defaults={buildHeatmapDefaults}
|
|
50
50
|
bind:margins
|
|
@@ -85,7 +85,20 @@ export function buildHeatmapDefaults() {
|
|
|
85
85
|
defaults: () => ({ x: { labelAnchor: 'right' } }),
|
|
86
86
|
extend: extendWithColorScales
|
|
87
87
|
},
|
|
88
|
-
|
|
88
|
+
transforms: {
|
|
89
|
+
// A cell's value is its color: `'min'` and `'max'` compare that.
|
|
90
|
+
labels: {
|
|
91
|
+
show: true,
|
|
92
|
+
measure: (state) => state.channels?.color.accessor
|
|
93
|
+
}
|
|
94
|
+
},
|
|
95
|
+
styles: {
|
|
96
|
+
values: {
|
|
97
|
+
show: true,
|
|
98
|
+
layout: 'box',
|
|
99
|
+
layouts: { path: { edge: 'top', side: 'inside' }, point: { anchor: 'top', side: 'above' } }
|
|
100
|
+
}
|
|
101
|
+
},
|
|
89
102
|
markers: { marks: buildMarks },
|
|
90
103
|
hover: {
|
|
91
104
|
// A cell writes its own value: the hover only restyles the cells - the hovered one outlined.
|
|
@@ -1,9 +1,3 @@
|
|
|
1
1
|
import type { HeatmapPlotState, HeatmapPlotEnv } from '../../../types/plots/correlation/heatmap/state';
|
|
2
2
|
import type { AxisBasedMarkersConfig } from '../../../types/markers/common';
|
|
3
|
-
/**
|
|
4
|
-
* HeatmapPlot's "markers" phase: one `'cell'` marker per resolved-style
|
|
5
|
-
* bucket - svelteplot's opacity/numeric scale machinery requires
|
|
6
|
-
* `fillOpacity`/`strokeWidth` to be constant per mark instance, unlike
|
|
7
|
-
* `fill`, which stays a per-row accessor.
|
|
8
|
-
*/
|
|
9
3
|
export declare function buildMarks<TData extends Record<string, unknown>>(state: HeatmapPlotState<TData>, env: HeatmapPlotEnv): AxisBasedMarkersConfig[];
|
|
@@ -8,12 +8,6 @@ function readChannel(channel) {
|
|
|
8
8
|
return resolveAccessor(channel);
|
|
9
9
|
}
|
|
10
10
|
const OPACITY_STEPS = 32;
|
|
11
|
-
/**
|
|
12
|
-
* HeatmapPlot's "markers" phase: one `'cell'` marker per resolved-style
|
|
13
|
-
* bucket - svelteplot's opacity/numeric scale machinery requires
|
|
14
|
-
* `fillOpacity`/`strokeWidth` to be constant per mark instance, unlike
|
|
15
|
-
* `fill`, which stays a per-row accessor.
|
|
16
|
-
*/
|
|
17
11
|
export function buildMarks(state, env) {
|
|
18
12
|
const { segments, channels, resolveColor, resolveOpacity } = state;
|
|
19
13
|
const { range } = env;
|
|
@@ -111,9 +105,11 @@ export function buildMarks(state, env) {
|
|
|
111
105
|
inset: 0.5
|
|
112
106
|
},
|
|
113
107
|
hover: 'style',
|
|
114
|
-
// Each cell writes its own value, in the middle of it.
|
|
115
|
-
label: labels?.
|
|
116
|
-
|
|
108
|
+
// Each cell writes its own value, in the middle of it by default.
|
|
109
|
+
label: labels?.label(env, (d) => labels.text(d), {
|
|
110
|
+
fill: 'currentColor',
|
|
111
|
+
fontWeight: 600,
|
|
112
|
+
labelled: state.labelled
|
|
117
113
|
})
|
|
118
114
|
}));
|
|
119
115
|
return markers;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<script lang="ts" generics="TData extends Record<string, unknown>">
|
|
2
|
-
import
|
|
2
|
+
import AbstractPlot from '../../../layout/plot/AbstractPlot.svelte';
|
|
3
3
|
import { buildScatterDefaults } from './defaults';
|
|
4
4
|
import type {
|
|
5
5
|
ScatterPlotProps,
|
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
}: ScatterPlotProps<TData> = $props();
|
|
28
28
|
</script>
|
|
29
29
|
|
|
30
|
-
<
|
|
30
|
+
<AbstractPlot
|
|
31
31
|
core={core as ScatterPlotCoreProps<TData>}
|
|
32
32
|
defaults={buildScatterDefaults}
|
|
33
33
|
bind:margins
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { ProcessedPositions } from '../../../phases/transforms/ProcessedPositions';
|
|
2
2
|
import { HoverDefaults } from '../../../layout/hover/HoverDefaults';
|
|
3
|
-
import { buildMarks
|
|
3
|
+
import { buildMarks } from './markers';
|
|
4
4
|
import { Margins } from '../../../layout/margins/Margins';
|
|
5
5
|
import { MarkerAxisValues } from '../../../phases/scales/MarkerAxisValues';
|
|
6
6
|
/** Stand-in max render radius for a channel-bound `r` (svelteplot's own auto sqrt scale). */
|
|
@@ -68,9 +68,15 @@ export function buildScatterDefaults() {
|
|
|
68
68
|
base: { flat: 'dot' }
|
|
69
69
|
}
|
|
70
70
|
},
|
|
71
|
-
transforms: { groups: 'runs' },
|
|
71
|
+
transforms: { groups: 'runs', labels: {} },
|
|
72
72
|
scales: { fit: fitDomains },
|
|
73
|
-
|
|
73
|
+
styles: {
|
|
74
|
+
values: {
|
|
75
|
+
layout: 'point',
|
|
76
|
+
layouts: { point: { side: 'above', gap: 8 }, path: { side: 'outside' } }
|
|
77
|
+
}
|
|
78
|
+
},
|
|
79
|
+
markers: { marks: buildMarks },
|
|
74
80
|
hover: {
|
|
75
81
|
strategy: 'punctual',
|
|
76
82
|
// A crosshair through the hovered point, and its label - the point is a dot already.
|
|
@@ -1,14 +1,5 @@
|
|
|
1
1
|
import type { ScatterPlotState, ScatterPlotEnv } from '../../../types/plots/correlation/scatter/state';
|
|
2
|
-
import type { TextMarkerConfig } from '../../../types/markers/common';
|
|
3
|
-
import { ValueLabels } from '../../../layout/styles/ValueLabels';
|
|
4
2
|
import type { AxisBasedMarkersConfig } from '../../../types/markers/common';
|
|
5
|
-
/**
|
|
6
|
-
* ScatterPlot's `styles.values` as one `'text'` marker over the same
|
|
7
|
-
* processed rows its dots draw, each labelled with its own `y` value. A label
|
|
8
|
-
* sits beside its point and flips to the other side where its text would
|
|
9
|
-
* cross the plot's edge (`edgeAware`).
|
|
10
|
-
*/
|
|
11
|
-
export declare function buildValueLabels<TData extends Record<string, unknown>>(labels: ValueLabels, state: ScatterPlotState<TData>): TextMarkerConfig[];
|
|
12
3
|
/**
|
|
13
4
|
* ScatterPlot's "markers" phase: one `'dot'` marker per visual segment of the
|
|
14
5
|
* rows the "transforms" phase left, in their own order, so a reordering
|
|
@@ -1,38 +1,28 @@
|
|
|
1
|
-
import { ProcessedPositions } from '../../../phases/transforms/ProcessedPositions';
|
|
2
1
|
import { SERIES_KEY } from '../../../phases/transforms/TransformsPhase';
|
|
3
2
|
import { ValueLabels } from '../../../layout/styles/ValueLabels';
|
|
4
3
|
/**
|
|
5
|
-
* ScatterPlot's `styles.values` as
|
|
6
|
-
*
|
|
7
|
-
* sits beside its point and flips to the other side where its text would
|
|
8
|
-
* cross the plot's edge (`edgeAware`).
|
|
4
|
+
* ScatterPlot's `styles.values` as labels of its dots: each labelled row with its own value, by default on a free
|
|
5
|
+
* spot around its point (`declutter: 'around'`) - a label with none is left out - or around its rim (`'path'`).
|
|
9
6
|
*/
|
|
10
|
-
|
|
11
|
-
const
|
|
12
|
-
if (
|
|
7
|
+
function buildValueLabels(labels, state, env) {
|
|
8
|
+
const rows = new Set(state.labelled ?? []);
|
|
9
|
+
if (rows.size === 0)
|
|
13
10
|
return [];
|
|
14
|
-
const { font, format } = labels;
|
|
15
|
-
const position = ProcessedPositions.of(processedData);
|
|
16
11
|
const nameOf = (d) => String(d[SERIES_KEY]);
|
|
17
|
-
const
|
|
12
|
+
const label = labels.label(env, (d) => labels.text(d), {
|
|
13
|
+
fill: 'currentColor',
|
|
14
|
+
seriesColor: (d) => state.colorForSeries?.(nameOf(d)),
|
|
15
|
+
fontSize: 11,
|
|
16
|
+
fontWeight: 500
|
|
17
|
+
});
|
|
18
|
+
if (labels.layout !== 'point')
|
|
19
|
+
return [label];
|
|
18
20
|
return [
|
|
19
21
|
{
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
text: (d) => format(Number(valueOf(d)), d, nameOf(d)),
|
|
25
|
-
styles: {
|
|
26
|
-
...font,
|
|
27
|
-
fill: font?.fill ?? 'currentColor',
|
|
28
|
-
fontSize: font?.fontSize ?? 11,
|
|
29
|
-
fontWeight: font?.fontWeight ?? 500,
|
|
30
|
-
dx: font?.dx ?? 8,
|
|
31
|
-
dy: font?.dy ?? 0,
|
|
32
|
-
textAnchor: labels.textAnchor ?? 'start',
|
|
33
|
-
lineAnchor: font?.lineAnchor ?? 'middle'
|
|
34
|
-
},
|
|
35
|
-
edgeAware: true
|
|
22
|
+
...label,
|
|
23
|
+
select: (row) => rows.has(row),
|
|
24
|
+
// A label on its own dot stays there; one beside it moves around it to a free spot.
|
|
25
|
+
declutter: labels.side === 'on' ? undefined : 'around'
|
|
36
26
|
}
|
|
37
27
|
];
|
|
38
28
|
}
|
|
@@ -126,5 +116,8 @@ export function buildMarks(state, env) {
|
|
|
126
116
|
});
|
|
127
117
|
}
|
|
128
118
|
});
|
|
129
|
-
|
|
119
|
+
const labels = state.valueLabels?.show
|
|
120
|
+
? buildValueLabels(state.valueLabels, state, env)
|
|
121
|
+
: undefined;
|
|
122
|
+
return ValueLabels.onMarkers(markers, 'dot', labels);
|
|
130
123
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { HoverPosition, ProcessedRow } from '../../../types/phases';
|
|
2
2
|
import type { BoxPlotState, BoxSummaryRow } from '../../../types/plots/distribution/box/state';
|
|
3
3
|
import type { BoxSummary } from '../../../types/plots/distribution/box/props';
|
|
4
|
+
import type { PointGeometryOf } from '../../../types/markers/labels/point';
|
|
4
5
|
/**
|
|
5
6
|
* The boxes a box plot draws, one per series, category and facet panel - the same quartiles and whiskers
|
|
6
7
|
* svelteplot's `BoxX`/`BoxY` compute, worked out once as each value's context ({@link context}), so its hover and
|
|
@@ -18,6 +19,10 @@ export declare class BoxSummaries {
|
|
|
18
19
|
* Its own context is the box's, with the median for its value, and where it sits for `x` and `y`.
|
|
19
20
|
*/
|
|
20
21
|
static of<TData extends Record<string, unknown>>(state: BoxPlotState<TData>): BoxSummaryRow[];
|
|
22
|
+
/** Where each part of a box its value labels can write sits: beside the box, at the height of its value. */
|
|
23
|
+
static partPlacements<TData extends Record<string, unknown>>(state: BoxPlotState<TData>): Record<string, Record<string, unknown>>;
|
|
24
|
+
/** Where a box's part label sits: at its category, level with the part's value, beside its band. */
|
|
25
|
+
static labelPoint<TData extends Record<string, unknown>>(state: BoxPlotState<TData>): (value: symbol) => PointGeometryOf;
|
|
21
26
|
/** Where a box's summary sits for hover: at its category, level with its median. */
|
|
22
27
|
static position<TData extends Record<string, unknown>>(state: BoxPlotState<TData>): HoverPosition;
|
|
23
28
|
/**
|