@fjader/svelte 0.2.2 → 0.2.3
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/dist/components/axes/BandAxisTicks.svelte +63 -24
- package/dist/components/axes/BandAxisTicks.svelte.d.ts +5 -5
- package/dist/components/charts/ChartContainer.svelte +2 -1
- package/dist/components/guides/legend/ContinuousColorLegend.svelte +2 -1
- package/dist/components/guides/legend/OrdinalColorLegend.svelte +92 -34
- package/dist/components/marks/AreaMarkX.svelte +19 -6
- package/dist/components/marks/AreaMarkY.svelte +19 -6
- package/dist/components/marks/BarMarkX.svelte +3 -0
- package/dist/components/marks/BarMarkY.svelte +3 -0
- package/dist/components/marks/DotsMark.svelte +3 -0
- package/dist/components/marks/LineMark.svelte +3 -0
- package/dist/components/marks/ParallelCoordinatesMark.svelte +6 -0
- package/dist/components/marks/ParallelCoordinatesMark.svelte.d.ts +3 -0
- package/dist/components/marks/RectMark.svelte +3 -0
- package/dist/components/marks/RectXMark.svelte +3 -0
- package/dist/components/marks/RectYMark.svelte +3 -0
- package/dist/components/marks/RuleMarkX.svelte +10 -2
- package/dist/components/marks/RuleMarkY.svelte +10 -2
- package/dist/components/marks/TextMark.svelte +68 -4
- package/dist/components/marks/lifecycle/MarkLifecycleV2.svelte.d.ts +15 -1
- package/dist/components/marks/lifecycle/MarkLifecycleV2.svelte.js +116 -27
- package/dist/components/marks/lifecycle/domain-queries.js +13 -11
- package/dist/components/marks/lifecycle/transform-scale-key.d.ts +16 -0
- package/dist/components/marks/lifecycle/transform-scale-key.js +27 -0
- package/dist/components/marks/utils/area-outline.d.ts +24 -0
- package/dist/components/marks/utils/area-outline.js +10 -0
- package/dist/components/marks/utils/reactive-config.d.ts +1 -1
- package/dist/components/marks/utils/reactive-config.js +3 -0
- package/dist/components/rendering/Areas.svelte +30 -6
- package/dist/components/rendering/Areas.svelte.d.ts +2 -0
- package/dist/components/rendering/BaseGPURenderer.svelte.js +4 -1
- package/dist/components/rendering/Dots.svelte +24 -3
- package/dist/components/rendering/Dots.svelte.d.ts +2 -0
- package/dist/components/rendering/GridLine.svelte +2 -1
- package/dist/components/rendering/Lines.svelte +49 -7
- package/dist/components/rendering/Lines.svelte.d.ts +9 -0
- package/dist/components/rendering/ParallelLines.svelte +26 -7
- package/dist/components/rendering/ParallelLines.svelte.d.ts +2 -0
- package/dist/components/rendering/Rects.svelte +20 -5
- package/dist/components/rendering/Rects.svelte.d.ts +2 -0
- package/dist/components/rendering/RuleX.svelte +20 -5
- package/dist/components/rendering/RuleX.svelte.d.ts +2 -0
- package/dist/components/rendering/RuleY.svelte +20 -5
- package/dist/components/rendering/RuleY.svelte.d.ts +2 -0
- package/dist/components/rendering/activity-reads.d.ts +93 -0
- package/dist/components/rendering/activity-reads.js +135 -0
- package/dist/components/rendering/uniform-sizes.d.ts +26 -0
- package/dist/components/rendering/uniform-sizes.js +28 -0
- package/dist/config/ChartConfig.svelte.d.ts +2 -0
- package/dist/gpu/ColorScaleShaderLib.d.ts +13 -1
- package/dist/gpu/ColorScaleShaderLib.js +56 -5
- package/dist/gpu/GPUCoordinator.svelte.d.ts +8 -0
- package/dist/gpu/GPUCoordinator.svelte.js +68 -32
- package/dist/gpu/ResolveShader.d.ts +2 -2
- package/dist/gpu/ResolveShader.js +2 -2
- package/dist/gpu/ScaleTemplateSystem.d.ts +19 -0
- package/dist/gpu/ScaleTemplateSystem.js +86 -7
- package/dist/gpu/SizeScaleShaderLib.d.ts +4 -4
- package/dist/gpu/SizeScaleShaderLib.js +4 -4
- package/dist/gpu/identity-slot-packing.d.ts +157 -40
- package/dist/gpu/identity-slot-packing.js +262 -62
- package/dist/gpu/tracked-scales.d.ts +14 -0
- package/dist/gpu/tracked-scales.js +18 -0
- package/dist/index.js +1 -0
- package/dist/interactors/BandLabelToggle.svelte +5 -9
- package/dist/interactors/BandLabelToggle.svelte.d.ts +3 -3
- package/dist/interactors/DerivedInterval1D.svelte +26 -54
- package/dist/interactors/Interval1D.svelte +2 -1
- package/dist/interactors/Interval2D.svelte +2 -1
- package/dist/interactors/ParallelAxisSource.svelte +4 -4
- package/dist/interactors/ParallelAxisSource.svelte.d.ts +2 -1
- package/dist/interactors/ParallelBrushes.svelte +8 -9
- package/dist/interactors/ParallelBrushes.svelte.d.ts +3 -3
- package/dist/interactors/Toggle.svelte +17 -36
- package/dist/interactors/Toggle.svelte.d.ts +4 -3
- package/dist/interactors/Tooltip.svelte +2 -1
- package/dist/interactors/TooltipManager.svelte.js +8 -3
- package/dist/interactors/relay-clauses.d.ts +23 -0
- package/dist/interactors/relay-clauses.js +60 -0
- package/dist/query-engine/CrossfilterSelection.svelte.d.ts +88 -15
- package/dist/query-engine/CrossfilterSelection.svelte.js +94 -20
- package/dist/query-engine/FieldActivity.svelte.d.ts +79 -0
- package/dist/query-engine/FieldActivity.svelte.js +207 -0
- package/dist/query-engine/FilterGroup.svelte.d.ts +53 -29
- package/dist/query-engine/FilterGroup.svelte.js +181 -122
- package/dist/query-engine/FilterGroupRegistry.svelte.d.ts +42 -0
- package/dist/query-engine/FilterGroupRegistry.svelte.js +103 -1
- package/dist/query-engine/MarkHandle.svelte.d.ts +9 -1
- package/dist/query-engine/MarkHandle.svelte.js +12 -2
- package/dist/query-engine/QueryEngine.d.ts +52 -16
- package/dist/query-engine/QueryEngine.js +90 -28
- package/dist/query-engine/categorical-identity.d.ts +99 -27
- package/dist/query-engine/categorical-identity.js +210 -51
- package/dist/query-engine/index.d.ts +2 -1
- package/dist/query-engine/index.js +1 -0
- package/dist/query-engine/preagg/Preagg.d.ts +1 -1
- package/dist/query-engine/preagg/Preagg.js +11 -9
- package/dist/query-engine/preagg/plan.d.ts +9 -5
- package/dist/query-engine/preagg/plan.js +13 -11
- package/dist/query-engine/toggle-predicate.js +12 -1
- package/dist/scales/ActivityTable.d.ts +99 -0
- package/dist/scales/ActivityTable.js +211 -0
- package/dist/scales/BandScaleState.svelte.d.ts +28 -7
- package/dist/scales/BandScaleState.svelte.js +55 -20
- package/dist/scales/ChartScales.svelte.d.ts +2 -2
- package/dist/scales/ColorScaleState.svelte.d.ts +36 -8
- package/dist/scales/ColorScaleState.svelte.js +118 -24
- package/dist/scales/DomainResolver.d.ts +2 -0
- package/dist/scales/DomainResolver.js +15 -8
- package/dist/scales/ScaleRegistry.svelte.d.ts +9 -0
- package/dist/scales/ScaleRegistry.svelte.js +22 -1
- package/dist/scales/TimeScaleState.svelte.js +7 -1
- package/dist/spec/index.js +1 -0
- package/dist/spec/types.d.ts +2 -0
- package/dist/transforms/index.d.ts +27 -0
- package/dist/transforms/index.js +97 -3
- package/dist/types.d.ts +30 -0
- package/package.json +1 -1
|
@@ -1,21 +1,25 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
+
import { getContext } from 'svelte';
|
|
2
3
|
import type { BandScaleState, BandTick } from '../../scales/BandScaleState.svelte';
|
|
4
|
+
import type { ChartContext } from '../../types';
|
|
5
|
+
import { categoryLabel } from '../../query-engine/categorical-identity';
|
|
6
|
+
import type { FilterGroupRegistry } from '../../query-engine/FilterGroupRegistry.svelte';
|
|
3
7
|
|
|
4
8
|
/**
|
|
5
9
|
* The labels on a band axis, wherever that axis is drawn.
|
|
6
10
|
*
|
|
7
11
|
* Three components rendered this: AxisBottom, AxisLeft and AxisCenter. The
|
|
8
|
-
* arithmetic was already shared — `tickPosition
|
|
9
|
-
*
|
|
12
|
+
* arithmetic was already shared — `tickPosition` and `tickOpacity` live on
|
|
13
|
+
* the scale — so what was actually duplicated
|
|
10
14
|
* was the markup around it, and what differs between the three is a handful
|
|
11
15
|
* of numbers: which way the ticks point, how long they are, how far the
|
|
12
16
|
* label sits, and where it anchors.
|
|
13
17
|
*
|
|
14
18
|
* Those are props here, so the structure is written once. The structure is
|
|
15
19
|
* the part with the reasons attached: the keyed `{#each}` so a reorder
|
|
16
|
-
* MOVES a label rather than replacing it, the opacity wrapper the scale
|
|
17
|
-
* drives per frame so a label travels
|
|
18
|
-
*
|
|
20
|
+
* MOVES a label rather than replacing it, and the opacity wrapper the scale
|
|
21
|
+
* drives per frame so a label travels, enters, leaves and dims for a
|
|
22
|
+
* selection with its bar, all on the scale's clocks.
|
|
19
23
|
*
|
|
20
24
|
* A band label is positioned through `tickPosition`, which reads the
|
|
21
25
|
* category's CURRENT fractional slot, not through the d3 scale. The d3
|
|
@@ -54,26 +58,66 @@
|
|
|
54
58
|
textAnchor = 'middle'
|
|
55
59
|
}: Props = $props();
|
|
56
60
|
|
|
61
|
+
const chart = getContext<ChartContext | undefined>('chart');
|
|
62
|
+
const filterGroups = getContext<FilterGroupRegistry | undefined>('filter-groups');
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* The filter groups whose selection the labels show: those of the chart's
|
|
66
|
+
* marks. A selection dims the axis's marks in their own group, so a label
|
|
67
|
+
* dims when any of those groups dims its category; a background mark in a
|
|
68
|
+
* group with nothing selected changes nothing.
|
|
69
|
+
*/
|
|
70
|
+
const groups = $derived.by(() => {
|
|
71
|
+
if (!chart || !filterGroups) return [];
|
|
72
|
+
const indices: number[] = [];
|
|
73
|
+
for (const entry of chart.config.entries.values()) {
|
|
74
|
+
// A 'filter' mark never dims; its labels follow it.
|
|
75
|
+
if (entry.selectionResponse === 'filter') continue;
|
|
76
|
+
const index = filterGroups.get(entry.selection).index;
|
|
77
|
+
if (!indices.includes(index)) indices.push(index);
|
|
78
|
+
}
|
|
79
|
+
return indices;
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* The field the axis's selection is kept under: its identity key, or its
|
|
84
|
+
* column before. As for the legend, the two differ for a computed field,
|
|
85
|
+
* so its labels briefly lose their dimming while a reload empties identity.
|
|
86
|
+
*/
|
|
87
|
+
const key = $derived(scale.identityKey ?? scale.sourceField);
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* A label's opacity: the scale's own (travel, clipping) times its selection
|
|
91
|
+
* fade. Read by id where the tick's key is one — the only way to reach an
|
|
92
|
+
* Other bucket, whose label is not a value — and by value before identity.
|
|
93
|
+
*/
|
|
94
|
+
function opacityOf(tick: BandTick): number {
|
|
95
|
+
const selected = !filterGroups
|
|
96
|
+
? 1
|
|
97
|
+
: scale.hasIdentity
|
|
98
|
+
? filterGroups.opacityOfId(key, groups, tick.key)
|
|
99
|
+
: filterGroups.opacityOfValue(key, groups, tick.value);
|
|
100
|
+
return scale.tickOpacity(tick.key) * selected;
|
|
101
|
+
}
|
|
102
|
+
|
|
57
103
|
const tickEnd = $derived(base + dir * tickLength);
|
|
58
104
|
const labelAt = $derived(base + dir * labelGap);
|
|
59
105
|
</script>
|
|
60
106
|
|
|
61
107
|
{#each ticks as tick (tick.key)}
|
|
62
108
|
{@const pos = scale.tickPosition(tick.key, rangeSize, axis)}
|
|
63
|
-
<g opacity={
|
|
64
|
-
|
|
65
|
-
{
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
{
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
{/if}
|
|
76
|
-
</g>
|
|
109
|
+
<g opacity={opacityOf(tick)}>
|
|
110
|
+
{#if axis === 'x'}
|
|
111
|
+
<line x1={pos} x2={pos} y1={base} y2={tickEnd} />
|
|
112
|
+
<text text-anchor={textAnchor} x={pos} y={labelAt}>
|
|
113
|
+
{categoryLabel(tick.value)}
|
|
114
|
+
</text>
|
|
115
|
+
{:else}
|
|
116
|
+
<line x1={base} x2={tickEnd} y1={pos} y2={pos} />
|
|
117
|
+
<text text-anchor={textAnchor} dominant-baseline="middle" x={labelAt} y={pos}>
|
|
118
|
+
{categoryLabel(tick.value)}
|
|
119
|
+
</text>
|
|
120
|
+
{/if}
|
|
77
121
|
</g>
|
|
78
122
|
{/each}
|
|
79
123
|
|
|
@@ -87,9 +131,4 @@
|
|
|
87
131
|
font-family: var(--fjader-font, system-ui, sans-serif);
|
|
88
132
|
font-size: 10px;
|
|
89
133
|
}
|
|
90
|
-
|
|
91
|
-
.tick-dimmed {
|
|
92
|
-
opacity: 0.25;
|
|
93
|
-
transition: opacity 0.15s ease;
|
|
94
|
-
}
|
|
95
134
|
</style>
|
|
@@ -3,17 +3,17 @@ import type { BandScaleState, BandTick } from '../../scales/BandScaleState.svelt
|
|
|
3
3
|
* The labels on a band axis, wherever that axis is drawn.
|
|
4
4
|
*
|
|
5
5
|
* Three components rendered this: AxisBottom, AxisLeft and AxisCenter. The
|
|
6
|
-
* arithmetic was already shared — `tickPosition
|
|
7
|
-
*
|
|
6
|
+
* arithmetic was already shared — `tickPosition` and `tickOpacity` live on
|
|
7
|
+
* the scale — so what was actually duplicated
|
|
8
8
|
* was the markup around it, and what differs between the three is a handful
|
|
9
9
|
* of numbers: which way the ticks point, how long they are, how far the
|
|
10
10
|
* label sits, and where it anchors.
|
|
11
11
|
*
|
|
12
12
|
* Those are props here, so the structure is written once. The structure is
|
|
13
13
|
* the part with the reasons attached: the keyed `{#each}` so a reorder
|
|
14
|
-
* MOVES a label rather than replacing it, the opacity wrapper the scale
|
|
15
|
-
* drives per frame so a label travels
|
|
16
|
-
*
|
|
14
|
+
* MOVES a label rather than replacing it, and the opacity wrapper the scale
|
|
15
|
+
* drives per frame so a label travels, enters, leaves and dims for a
|
|
16
|
+
* selection with its bar, all on the scale's clocks.
|
|
17
17
|
*
|
|
18
18
|
* A band label is positioned through `tickPosition`, which reads the
|
|
19
19
|
* category's CURRENT fractional slot, not through the d3 scale. The d3
|
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
import { identityKeyFor } from '../../query-engine/identity-key';
|
|
14
14
|
import { checkFacetCells } from './facet-limits';
|
|
15
15
|
import ChartCell from './ChartCell.svelte';
|
|
16
|
+
import { categoryLabel } from '../../query-engine/categorical-identity';
|
|
16
17
|
|
|
17
18
|
interface Props {
|
|
18
19
|
xLabel?: string | null;
|
|
@@ -481,7 +482,7 @@
|
|
|
481
482
|
<ChartCell
|
|
482
483
|
cellChartId={facetChartIds[i]}
|
|
483
484
|
facetIndex={i}
|
|
484
|
-
facetLabel={String(cat)}
|
|
485
|
+
facetLabel={String(categoryLabel(cat))}
|
|
485
486
|
margin={{ top: 20, right: 10, bottom: 35, left: 55 }}
|
|
486
487
|
{scales}
|
|
487
488
|
{chartConfig}
|
|
@@ -166,7 +166,8 @@
|
|
|
166
166
|
|
|
167
167
|
const brushHandle: SourceHandle | null = filterGroup
|
|
168
168
|
? filterGroup.register(sourceId, {
|
|
169
|
-
|
|
169
|
+
// No chart: an interval cannot dim, so the chart it sits in filters by
|
|
170
|
+
// it rather than showing nothing.
|
|
170
171
|
// The brush maps the bar linearly onto [min, max], whatever the color
|
|
171
172
|
// transform, so its pixel bins do too: barLength pixels over the domain.
|
|
172
173
|
activeDims: () =>
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import { getContext, onDestroy } from 'svelte';
|
|
3
|
-
import type { ScaleRegistry } from '../../../scales/ScaleRegistry.svelte';
|
|
4
3
|
import type { ColorScaleState } from '../../../scales/ColorScaleState.svelte';
|
|
5
|
-
import type { ActiveValueScale } from '../../../query-engine/FilterGroup.svelte';
|
|
6
4
|
import type { FilterGroupRegistry } from '../../../query-engine/FilterGroupRegistry.svelte';
|
|
5
|
+
import type { ChartContext } from '../../../types';
|
|
6
|
+
import type { BandScaleState } from '../../../scales/BandScaleState.svelte';
|
|
7
|
+
import type { DimValue } from '../../../query-engine/categorical-identity';
|
|
8
|
+
import { categoryLabel } from '../../../query-engine/categorical-identity';
|
|
7
9
|
|
|
8
10
|
interface Props {
|
|
9
11
|
scaleState: ColorScaleState;
|
|
@@ -31,42 +33,102 @@
|
|
|
31
33
|
|
|
32
34
|
const filterGroups = getContext<FilterGroupRegistry | undefined>('filter-groups');
|
|
33
35
|
const filterGroup = filterGroups?.get(selection);
|
|
34
|
-
const scaleRegistry = getContext<ScaleRegistry>('scale-registry');
|
|
35
36
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
37
|
+
const chartContext = getContext<ChartContext | undefined>('chart');
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* The chart's band axis on this legend's field, if it has one. The legend then
|
|
41
|
+
* lists what that axis shows (a top N and its Other, a table's own categories)
|
|
42
|
+
* rather than every category of the field, which is what the colour scale's
|
|
43
|
+
* domain holds: it is shared per field across charts.
|
|
44
|
+
*/
|
|
45
|
+
const bandOnField = $derived.by(() => {
|
|
46
|
+
// Neither identityKey is reactive state, and both are null until identity
|
|
47
|
+
// lands, which is after this first runs: read the signals that change
|
|
48
|
+
// with them, or this stays null for good.
|
|
49
|
+
void scaleState.ranksRevision;
|
|
50
|
+
const key = scaleState.identityKey;
|
|
51
|
+
if (!chartContext || !key) return null;
|
|
52
|
+
for (const axis of ['x', 'y'] as const) {
|
|
53
|
+
const type = chartContext.scaleTypes?.[axis];
|
|
54
|
+
if (type !== 'band' && type !== 'point') continue;
|
|
55
|
+
const band = chartContext[`${axis}ScaleState`] as BandScaleState | null;
|
|
56
|
+
if (!band) continue;
|
|
57
|
+
void band._version;
|
|
58
|
+
if (band.identityKey === key) return band;
|
|
59
|
+
}
|
|
60
|
+
return null;
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
interface Item {
|
|
64
|
+
/** The category's dim id, when the legend follows a band axis. */
|
|
65
|
+
id: number | null;
|
|
66
|
+
value: DimValue;
|
|
67
|
+
color: string;
|
|
68
|
+
/** An Other bucket: shown, not clickable (it names no value). */
|
|
69
|
+
bucket: boolean;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// Reactive: re-renders when the domain, the axis or the palette ranks change.
|
|
73
|
+
const items = $derived.by((): Item[] => {
|
|
74
|
+
const band = bandOnField;
|
|
75
|
+
if (band) {
|
|
76
|
+
void band._version;
|
|
77
|
+
const ids = band.displayOrder;
|
|
78
|
+
const values = band.effectiveDomain;
|
|
79
|
+
const identity = scaleState.identity;
|
|
80
|
+
return Array.from(ids, (id, i) => ({
|
|
81
|
+
id,
|
|
82
|
+
value: values[i],
|
|
83
|
+
color: scaleState.getColor(values[i] as string | number | null),
|
|
84
|
+
bucket: identity?.synthetic.has(id) ?? false
|
|
85
|
+
}));
|
|
86
|
+
}
|
|
87
|
+
return scaleState.domain.map((value) => ({
|
|
88
|
+
id: null,
|
|
39
89
|
value,
|
|
40
|
-
color: scaleState.getColor(value)
|
|
41
|
-
|
|
42
|
-
|
|
90
|
+
color: scaleState.getColor(value),
|
|
91
|
+
bucket: false
|
|
92
|
+
}));
|
|
93
|
+
});
|
|
43
94
|
|
|
44
95
|
// --- Toggle interaction ---
|
|
45
96
|
const isInteractive = $derived(filterGroup != null && field != null);
|
|
46
97
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
98
|
+
/**
|
|
99
|
+
* The field's identity key: what its selection is kept under. The scale's
|
|
100
|
+
* own once it has identity; the field before, as the toggle keys it. For a
|
|
101
|
+
* plain column the two are the same. For a computed field (an expression)
|
|
102
|
+
* they differ, so while a reload empties the identity the legend reads the
|
|
103
|
+
* selection under the field's name and its highlight is briefly lost.
|
|
104
|
+
*/
|
|
105
|
+
const key = $derived(scaleState.identityKey ?? field ?? scaleState.field);
|
|
106
|
+
const groups = $derived(filterGroup ? [filterGroup.index] : []);
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* How visible an entry is now: its group's selection fade on the field, on
|
|
110
|
+
* the same clock and with the same floor as the marks.
|
|
111
|
+
*/
|
|
112
|
+
function opacityOf(item: Item): number {
|
|
113
|
+
if (!filterGroups) return 1;
|
|
114
|
+
// By id where there is one: the only way to reach an Other bucket.
|
|
115
|
+
return item.id !== null
|
|
116
|
+
? filterGroups.opacityOfId(key, groups, item.id)
|
|
117
|
+
: filterGroups.opacityOfValue(key, groups, item.value);
|
|
52
118
|
}
|
|
53
119
|
|
|
54
120
|
// The selection is shared with any Toggle on the same field through its clause.
|
|
55
|
-
// A legend
|
|
121
|
+
// A legend inside a chart skips that chart, as a Toggle there does: its marks
|
|
122
|
+
// keyed by the field dim, the rest keep their data. A standalone legend is in
|
|
123
|
+
// no chart, so every chart in its group is routed by its marks alone.
|
|
56
124
|
const toggle =
|
|
57
125
|
filterGroup && field
|
|
58
|
-
? filterGroup.registerToggle(field, {
|
|
59
|
-
excludeMarkIds: () => new Set<string>(),
|
|
60
|
-
scales: getLegendScaleStates
|
|
61
|
-
})
|
|
126
|
+
? filterGroup.registerToggle(field, { chart: chartContext?.config ?? null })
|
|
62
127
|
: null;
|
|
63
128
|
onDestroy(() => toggle?.destroy());
|
|
64
129
|
|
|
65
|
-
// Derive visual state from the toggle's selection
|
|
66
|
-
const selectedSet = $derived(toggle?.active ? toggle.values : null);
|
|
67
|
-
|
|
68
130
|
// Shift/meta-click adds or removes; selecting every value clears instead.
|
|
69
|
-
function handleClick(value:
|
|
131
|
+
function handleClick(value: DimValue, event: MouseEvent) {
|
|
70
132
|
toggle?.toggle([value], event.shiftKey || event.metaKey, scaleState.domain.length);
|
|
71
133
|
}
|
|
72
134
|
</script>
|
|
@@ -85,11 +147,12 @@
|
|
|
85
147
|
class:legend-columns={columns}
|
|
86
148
|
class:legend-vertical={orientation === 'vertical'}
|
|
87
149
|
>
|
|
88
|
-
{#each items as
|
|
89
|
-
{
|
|
150
|
+
{#each items as item (item.id ?? item.value)}
|
|
151
|
+
{@const { value, color } = item}
|
|
152
|
+
{#if isInteractive && !item.bucket}
|
|
90
153
|
<button
|
|
91
154
|
class="legend-item legend-item-interactive"
|
|
92
|
-
|
|
155
|
+
style:opacity={opacityOf(item)}
|
|
93
156
|
onclick={(e) => handleClick(value, e)}
|
|
94
157
|
>
|
|
95
158
|
<span
|
|
@@ -99,10 +162,10 @@
|
|
|
99
162
|
style:height="{swatchSize}px"
|
|
100
163
|
style:border-radius="{swatchRadius}px"
|
|
101
164
|
></span>
|
|
102
|
-
<span class="legend-label">{value}</span>
|
|
165
|
+
<span class="legend-label">{categoryLabel(value)}</span>
|
|
103
166
|
</button>
|
|
104
167
|
{:else}
|
|
105
|
-
<span class="legend-item">
|
|
168
|
+
<span class="legend-item" style:opacity={opacityOf(item)}>
|
|
106
169
|
<span
|
|
107
170
|
class="legend-swatch"
|
|
108
171
|
style:background={color}
|
|
@@ -110,7 +173,7 @@
|
|
|
110
173
|
style:height="{swatchSize}px"
|
|
111
174
|
style:border-radius="{swatchRadius}px"
|
|
112
175
|
></span>
|
|
113
|
-
<span class="legend-label">{value}</span>
|
|
176
|
+
<span class="legend-label">{categoryLabel(value)}</span>
|
|
114
177
|
</span>
|
|
115
178
|
{/if}
|
|
116
179
|
{/each}
|
|
@@ -157,7 +220,6 @@
|
|
|
157
220
|
align-items: center;
|
|
158
221
|
gap: 4px;
|
|
159
222
|
white-space: nowrap;
|
|
160
|
-
transition: opacity 0.15s ease;
|
|
161
223
|
}
|
|
162
224
|
|
|
163
225
|
.legend-item-interactive {
|
|
@@ -170,10 +232,6 @@
|
|
|
170
232
|
color: inherit;
|
|
171
233
|
}
|
|
172
234
|
|
|
173
|
-
.legend-item-dimmed {
|
|
174
|
-
opacity: 0.2;
|
|
175
|
-
}
|
|
176
|
-
|
|
177
235
|
.legend-swatch {
|
|
178
236
|
display: inline-block;
|
|
179
237
|
flex-shrink: 0;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
+
import { outlineColor } from './utils/area-outline';
|
|
2
3
|
import { getContext, onDestroy, untrack } from 'svelte';
|
|
3
4
|
import { MarkLifecycleV2 } from './lifecycle/MarkLifecycleV2.svelte';
|
|
4
5
|
import { Areas, Lines } from '../rendering';
|
|
@@ -46,6 +47,7 @@
|
|
|
46
47
|
let {
|
|
47
48
|
table,
|
|
48
49
|
selection = undefined,
|
|
50
|
+
selectionResponse = undefined,
|
|
49
51
|
y,
|
|
50
52
|
x,
|
|
51
53
|
x1: x1Prop,
|
|
@@ -98,6 +100,7 @@
|
|
|
98
100
|
strokeWidth: () => strokeWidth,
|
|
99
101
|
transforms: () => transforms,
|
|
100
102
|
selection: () => selection,
|
|
103
|
+
selectionResponse: () => selectionResponse,
|
|
101
104
|
limit: () => limit,
|
|
102
105
|
preferredXScaleType: () => preferredXScaleType,
|
|
103
106
|
preferredYScaleType: () => preferredYScaleType,
|
|
@@ -157,6 +160,9 @@
|
|
|
157
160
|
chartContext
|
|
158
161
|
);
|
|
159
162
|
|
|
163
|
+
/** The outline's colour, and the fill's activity it dims by (see area-outline.ts). */
|
|
164
|
+
const outline = $derived(outlineColor(entry.stroke, markColor));
|
|
165
|
+
|
|
160
166
|
// Detect if x2 is an aggregate expression
|
|
161
167
|
const hasAggregateX = $derived.by(() => {
|
|
162
168
|
return (
|
|
@@ -366,6 +372,7 @@
|
|
|
366
372
|
colorValueData={markColor.data}
|
|
367
373
|
colorMode={markColor.colorMode}
|
|
368
374
|
colorScaleIndex={markColor.colorScaleIndex}
|
|
375
|
+
groupIndex={setup?.groupIndex ?? 0}
|
|
369
376
|
constantColor={markColor.constantColor}
|
|
370
377
|
fillOpacity={entry.fillOpacity ?? 0.5}
|
|
371
378
|
dotRadius={effectiveDotRadius}
|
|
@@ -381,9 +388,12 @@
|
|
|
381
388
|
{yData}
|
|
382
389
|
{seriesData}
|
|
383
390
|
curve={effectiveCurve}
|
|
384
|
-
colorValueData={
|
|
385
|
-
colorMode={
|
|
386
|
-
colorScaleIndex={
|
|
391
|
+
colorValueData={outline.colorValueData}
|
|
392
|
+
colorMode={outline.colorMode}
|
|
393
|
+
colorScaleIndex={outline.colorScaleIndex}
|
|
394
|
+
activityColorMode={outline.activityColorMode}
|
|
395
|
+
activityColorScaleIndex={outline.activityColorScaleIndex}
|
|
396
|
+
groupIndex={setup?.groupIndex ?? 0}
|
|
387
397
|
constantColor={strokeConstantColor}
|
|
388
398
|
strokeWidth={entry.strokeWidth ?? 0}
|
|
389
399
|
zIndex={1}
|
|
@@ -396,9 +406,12 @@
|
|
|
396
406
|
{yData}
|
|
397
407
|
{seriesData}
|
|
398
408
|
curve={effectiveCurve}
|
|
399
|
-
colorValueData={
|
|
400
|
-
colorMode={
|
|
401
|
-
colorScaleIndex={
|
|
409
|
+
colorValueData={outline.colorValueData}
|
|
410
|
+
colorMode={outline.colorMode}
|
|
411
|
+
colorScaleIndex={outline.colorScaleIndex}
|
|
412
|
+
activityColorMode={outline.activityColorMode}
|
|
413
|
+
activityColorScaleIndex={outline.activityColorScaleIndex}
|
|
414
|
+
groupIndex={setup?.groupIndex ?? 0}
|
|
402
415
|
constantColor={strokeConstantColor}
|
|
403
416
|
strokeWidth={entry.strokeWidth ?? 0}
|
|
404
417
|
zIndex={1}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
+
import { outlineColor } from './utils/area-outline';
|
|
2
3
|
import { getContext, onDestroy, untrack } from 'svelte';
|
|
3
4
|
import { MarkLifecycleV2 } from './lifecycle/MarkLifecycleV2.svelte';
|
|
4
5
|
import { Areas, Lines } from '../rendering';
|
|
@@ -46,6 +47,7 @@
|
|
|
46
47
|
let {
|
|
47
48
|
table,
|
|
48
49
|
selection = undefined,
|
|
50
|
+
selectionResponse = undefined,
|
|
49
51
|
x,
|
|
50
52
|
y,
|
|
51
53
|
y1: y1Prop,
|
|
@@ -98,6 +100,7 @@
|
|
|
98
100
|
strokeWidth: () => strokeWidth,
|
|
99
101
|
transforms: () => transforms,
|
|
100
102
|
selection: () => selection,
|
|
103
|
+
selectionResponse: () => selectionResponse,
|
|
101
104
|
limit: () => limit,
|
|
102
105
|
preferredXScaleType: () => preferredXScaleType,
|
|
103
106
|
preferredYScaleType: () => preferredYScaleType,
|
|
@@ -157,6 +160,9 @@
|
|
|
157
160
|
chartContext
|
|
158
161
|
);
|
|
159
162
|
|
|
163
|
+
/** The outline's colour, and the fill's activity it dims by (see area-outline.ts). */
|
|
164
|
+
const outline = $derived(outlineColor(entry.stroke, markColor));
|
|
165
|
+
|
|
160
166
|
// Detect if y2 is an aggregate expression (count, sum, mean, etc.)
|
|
161
167
|
const hasAggregateY = $derived.by(() => {
|
|
162
168
|
return (
|
|
@@ -366,6 +372,7 @@
|
|
|
366
372
|
colorValueData={markColor.data}
|
|
367
373
|
colorMode={markColor.colorMode}
|
|
368
374
|
colorScaleIndex={markColor.colorScaleIndex}
|
|
375
|
+
groupIndex={setup?.groupIndex ?? 0}
|
|
369
376
|
constantColor={markColor.constantColor}
|
|
370
377
|
fillOpacity={entry.fillOpacity ?? 0.5}
|
|
371
378
|
dotRadius={effectiveDotRadius}
|
|
@@ -381,9 +388,12 @@
|
|
|
381
388
|
yData={yTopData}
|
|
382
389
|
{seriesData}
|
|
383
390
|
curve={effectiveCurve}
|
|
384
|
-
colorValueData={
|
|
385
|
-
colorMode={
|
|
386
|
-
colorScaleIndex={
|
|
391
|
+
colorValueData={outline.colorValueData}
|
|
392
|
+
colorMode={outline.colorMode}
|
|
393
|
+
colorScaleIndex={outline.colorScaleIndex}
|
|
394
|
+
activityColorMode={outline.activityColorMode}
|
|
395
|
+
activityColorScaleIndex={outline.activityColorScaleIndex}
|
|
396
|
+
groupIndex={setup?.groupIndex ?? 0}
|
|
387
397
|
constantColor={strokeConstantColor}
|
|
388
398
|
strokeWidth={entry.strokeWidth ?? 0}
|
|
389
399
|
zIndex={1}
|
|
@@ -396,9 +406,12 @@
|
|
|
396
406
|
yData={yBottomData}
|
|
397
407
|
{seriesData}
|
|
398
408
|
curve={effectiveCurve}
|
|
399
|
-
colorValueData={
|
|
400
|
-
colorMode={
|
|
401
|
-
colorScaleIndex={
|
|
409
|
+
colorValueData={outline.colorValueData}
|
|
410
|
+
colorMode={outline.colorMode}
|
|
411
|
+
colorScaleIndex={outline.colorScaleIndex}
|
|
412
|
+
activityColorMode={outline.activityColorMode}
|
|
413
|
+
activityColorScaleIndex={outline.activityColorScaleIndex}
|
|
414
|
+
groupIndex={setup?.groupIndex ?? 0}
|
|
402
415
|
constantColor={strokeConstantColor}
|
|
403
416
|
strokeWidth={entry.strokeWidth ?? 0}
|
|
404
417
|
zIndex={1}
|
|
@@ -40,6 +40,7 @@
|
|
|
40
40
|
let {
|
|
41
41
|
table,
|
|
42
42
|
selection = undefined,
|
|
43
|
+
selectionResponse = undefined,
|
|
43
44
|
x,
|
|
44
45
|
x1: x1Prop,
|
|
45
46
|
x2: x2Prop,
|
|
@@ -81,6 +82,7 @@
|
|
|
81
82
|
opacity: () => opacity,
|
|
82
83
|
transforms: () => transforms,
|
|
83
84
|
selection: () => selection,
|
|
85
|
+
selectionResponse: () => selectionResponse,
|
|
84
86
|
limit: () => limit,
|
|
85
87
|
padding: () => padding,
|
|
86
88
|
paddingInner: () => paddingInner,
|
|
@@ -303,6 +305,7 @@
|
|
|
303
305
|
alphaData={opacityData}
|
|
304
306
|
colorMode={markColor.colorMode}
|
|
305
307
|
colorScaleIndex={markColor.colorScaleIndex}
|
|
308
|
+
groupIndex={setup?.groupIndex ?? 0}
|
|
306
309
|
constantColor={markColor.constantColor}
|
|
307
310
|
facetData={setup?.facetData}
|
|
308
311
|
dataVersion={setup?.dataVersion || 0}
|
|
@@ -39,6 +39,7 @@
|
|
|
39
39
|
let {
|
|
40
40
|
table,
|
|
41
41
|
selection = undefined,
|
|
42
|
+
selectionResponse = undefined,
|
|
42
43
|
x,
|
|
43
44
|
y,
|
|
44
45
|
y1: y1Prop,
|
|
@@ -80,6 +81,7 @@
|
|
|
80
81
|
opacity: () => opacity,
|
|
81
82
|
transforms: () => transforms,
|
|
82
83
|
selection: () => selection,
|
|
84
|
+
selectionResponse: () => selectionResponse,
|
|
83
85
|
limit: () => limit,
|
|
84
86
|
padding: () => padding,
|
|
85
87
|
paddingInner: () => paddingInner,
|
|
@@ -304,6 +306,7 @@
|
|
|
304
306
|
alphaData={opacityData}
|
|
305
307
|
colorMode={markColor.colorMode}
|
|
306
308
|
colorScaleIndex={markColor.colorScaleIndex}
|
|
309
|
+
groupIndex={setup?.groupIndex ?? 0}
|
|
307
310
|
constantColor={markColor.constantColor}
|
|
308
311
|
facetData={setup?.facetData}
|
|
309
312
|
dataVersion={setup?.dataVersion || 0}
|
|
@@ -42,6 +42,7 @@
|
|
|
42
42
|
let {
|
|
43
43
|
table,
|
|
44
44
|
selection = undefined,
|
|
45
|
+
selectionResponse = undefined,
|
|
45
46
|
x,
|
|
46
47
|
y,
|
|
47
48
|
fill = null,
|
|
@@ -80,6 +81,7 @@
|
|
|
80
81
|
radiusRange: () => radiusRange,
|
|
81
82
|
transforms: () => transforms,
|
|
82
83
|
selection: () => selection,
|
|
84
|
+
selectionResponse: () => selectionResponse,
|
|
83
85
|
limit: () => limit,
|
|
84
86
|
preferredXScaleType: () => preferredXScaleType,
|
|
85
87
|
preferredYScaleType: () => preferredYScaleType,
|
|
@@ -306,6 +308,7 @@
|
|
|
306
308
|
colorValueData={markColor.data}
|
|
307
309
|
colorMode={markColor.colorMode}
|
|
308
310
|
colorScaleIndex={markColor.colorScaleIndex}
|
|
311
|
+
groupIndex={setup?.groupIndex ?? 0}
|
|
309
312
|
constantColor={markColor.constantColor}
|
|
310
313
|
sizeMode={markSize.sizeMode}
|
|
311
314
|
sizeScaleIndex={markSize.sizeScaleIndex}
|
|
@@ -70,6 +70,7 @@
|
|
|
70
70
|
let {
|
|
71
71
|
table,
|
|
72
72
|
selection = undefined,
|
|
73
|
+
selectionResponse = undefined,
|
|
73
74
|
x,
|
|
74
75
|
y,
|
|
75
76
|
stroke = null,
|
|
@@ -122,6 +123,7 @@
|
|
|
122
123
|
dotRadius: () => dotRadius,
|
|
123
124
|
transforms: () => transforms,
|
|
124
125
|
selection: () => selection,
|
|
126
|
+
selectionResponse: () => selectionResponse,
|
|
125
127
|
limit: () => limit,
|
|
126
128
|
preferredXScaleType: () => preferredXScaleType,
|
|
127
129
|
preferredYScaleType: () => preferredYScaleType,
|
|
@@ -570,6 +572,7 @@
|
|
|
570
572
|
colorValueData={markColor.data}
|
|
571
573
|
colorMode={markColor.colorMode}
|
|
572
574
|
colorScaleIndex={markColor.colorScaleIndex}
|
|
575
|
+
groupIndex={setup?.groupIndex ?? 0}
|
|
573
576
|
constantColor={markColor.constantColor}
|
|
574
577
|
strokeWidth={entry.strokeWidth ?? 2}
|
|
575
578
|
dotRadius={effectiveDotRadius}
|
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
</script>
|
|
12
12
|
|
|
13
13
|
<script lang="ts">
|
|
14
|
+
import type { SelectionResponse } from '../rendering/activity-reads';
|
|
14
15
|
import { getContext, onDestroy, untrack } from 'svelte';
|
|
15
16
|
import { MarkLifecycleV2 } from './lifecycle/MarkLifecycleV2.svelte';
|
|
16
17
|
import { ParallelLines } from '../rendering';
|
|
@@ -31,6 +32,8 @@
|
|
|
31
32
|
strokeWidth?: number;
|
|
32
33
|
curve?: CurveType;
|
|
33
34
|
selection?: string;
|
|
35
|
+
/** How this mark responds to selections in its group (see BaseMarkProps). */
|
|
36
|
+
selectionResponse?: SelectionResponse;
|
|
34
37
|
transforms?: Transform[];
|
|
35
38
|
}
|
|
36
39
|
|
|
@@ -43,6 +46,7 @@
|
|
|
43
46
|
strokeWidth = 2,
|
|
44
47
|
curve = 'linear',
|
|
45
48
|
selection = undefined,
|
|
49
|
+
selectionResponse = undefined,
|
|
46
50
|
transforms = []
|
|
47
51
|
}: Props = $props();
|
|
48
52
|
|
|
@@ -59,6 +63,7 @@
|
|
|
59
63
|
stroke: () => stroke,
|
|
60
64
|
scheme: () => scheme,
|
|
61
65
|
selection: () => selection,
|
|
66
|
+
selectionResponse: () => selectionResponse,
|
|
62
67
|
transforms: () => transforms
|
|
63
68
|
});
|
|
64
69
|
|
|
@@ -188,6 +193,7 @@
|
|
|
188
193
|
colorValueData={markColor.data}
|
|
189
194
|
colorMode={markColor.colorMode}
|
|
190
195
|
colorScaleIndex={markColor.colorScaleIndex}
|
|
196
|
+
groupIndex={setup?.groupIndex ?? 0}
|
|
191
197
|
constantColor={markColor.constantColor}
|
|
192
198
|
axisOrder={currentAxisOrder}
|
|
193
199
|
axisScaleIds={currentScaleIds}
|
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
export declare const parallelParity: {
|
|
10
10
|
reverseScales: boolean;
|
|
11
11
|
};
|
|
12
|
+
import type { SelectionResponse } from '../rendering/activity-reads';
|
|
12
13
|
import type { FieldRef, ColorScheme, CurveType, Transform } from '../../types';
|
|
13
14
|
interface Props {
|
|
14
15
|
table: string;
|
|
@@ -19,6 +20,8 @@ interface Props {
|
|
|
19
20
|
strokeWidth?: number;
|
|
20
21
|
curve?: CurveType;
|
|
21
22
|
selection?: string;
|
|
23
|
+
/** How this mark responds to selections in its group (see BaseMarkProps). */
|
|
24
|
+
selectionResponse?: SelectionResponse;
|
|
22
25
|
transforms?: Transform[];
|
|
23
26
|
}
|
|
24
27
|
declare const ParallelCoordinatesMark: import("svelte").Component<Props, {}, "">;
|