layerchart 2.0.0-next.54 → 2.0.0-next.56
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/bench/ComposableLineChart.svelte +1 -1
- package/dist/bench/GeoBench.svelte +1 -8
- package/dist/components/AnnotationRange.svelte +3 -1
- package/dist/components/Arc.svelte +1 -3
- package/dist/components/ArcLabel.svelte.test.js +7 -7
- package/dist/components/Axis.svelte +10 -2
- package/dist/components/Axis.svelte.d.ts +8 -2
- package/dist/components/Bar.svelte +14 -40
- package/dist/components/BoxPlot.svelte +4 -12
- package/dist/components/Cell.svelte +13 -8
- package/dist/components/Chart.svelte +69 -26
- package/dist/components/ChartChildren.svelte +22 -4
- package/dist/components/Circle.svelte +51 -9
- package/dist/components/Circle.svelte.d.ts +6 -0
- package/dist/components/CircleClipPath.svelte +13 -31
- package/dist/components/CircleClipPath.svelte.d.ts +7 -1
- package/dist/components/ClipPath.svelte +58 -21
- package/dist/components/ClipPath.svelte.d.ts +21 -12
- package/dist/components/Connector.svelte +18 -0
- package/dist/components/Connector.svelte.d.ts +5 -0
- package/dist/components/Ellipse.svelte +27 -6
- package/dist/components/GeoClipPath.svelte +14 -17
- package/dist/components/GeoClipPath.svelte.d.ts +6 -0
- package/dist/components/GeoLegend.svelte +1 -3
- package/dist/components/GeoPoint.svelte +25 -3
- package/dist/components/GeoSpline.svelte +1 -4
- package/dist/components/GeoTile.svelte +8 -4
- package/dist/components/Grid.svelte +15 -4
- package/dist/components/Grid.svelte.d.ts +14 -4
- package/dist/components/Group.svelte +11 -5
- package/dist/components/Highlight.svelte +4 -3
- package/dist/components/Image.svelte +42 -30
- package/dist/components/Labels.svelte +2 -4
- package/dist/components/Line.svelte +31 -3
- package/dist/components/Line.svelte.d.ts +7 -0
- package/dist/components/LinearGradient.svelte +8 -4
- package/dist/components/Link.svelte +8 -0
- package/dist/components/Marker.svelte +9 -1
- package/dist/components/Path.svelte +43 -23
- package/dist/components/Pattern.svelte +101 -5
- package/dist/components/Pattern.svelte.d.ts +3 -1
- package/dist/components/Pie.svelte +2 -6
- package/dist/components/RadialGradient.svelte +8 -4
- package/dist/components/Rect.svelte +117 -9
- package/dist/components/Rect.svelte.d.ts +13 -1
- package/dist/components/RectClipPath.svelte +11 -15
- package/dist/components/RectClipPath.svelte.d.ts +6 -0
- package/dist/components/Spline.svelte +22 -4
- package/dist/components/Text.svelte +16 -5
- package/dist/components/Trail.svelte +19 -7
- package/dist/components/Tree.svelte +7 -3
- package/dist/components/Vector.svelte +37 -14
- package/dist/components/Violin.svelte +1 -2
- package/dist/components/charts/ArcChart.svelte +8 -5
- package/dist/components/charts/AreaChart.svelte +6 -1
- package/dist/components/charts/BarChart.svelte +3 -1
- package/dist/components/charts/LineChart.svelte +6 -1
- package/dist/components/charts/PieChart.svelte +10 -3
- package/dist/components/tooltip/Tooltip.svelte +2 -8
- package/dist/contexts/chart.d.ts +1 -1
- package/dist/contexts/chart.js +3 -1
- package/dist/server/TestBarChart.svelte +28 -28
- package/dist/server/TestLineChart.svelte +28 -28
- package/dist/server/index.js +1 -1
- package/dist/states/brush.svelte.js +16 -13
- package/dist/states/chart.svelte.test.js +24 -19
- package/dist/states/geo.svelte.js +1 -4
- package/dist/states/series.svelte.js +1 -1
- package/dist/utils/__screenshots__/canvas.svelte.test.ts/renderPathData-composes-element-opacity-with-inherited-globalAlpha--Group-opacity--1.png +0 -0
- package/dist/utils/__screenshots__/canvas.svelte.test.ts/renderPathData-composes-element-opacity-with-inherited-globalAlpha--Group-opacity--2.png +0 -0
- package/dist/utils/canvas.d.ts +2 -0
- package/dist/utils/canvas.js +20 -11
- package/dist/utils/canvas.svelte.test.js +55 -0
- package/dist/utils/connectorUtils.d.ts +13 -0
- package/dist/utils/connectorUtils.js +120 -1
- package/dist/utils/path.d.ts +19 -0
- package/dist/utils/path.js +72 -0
- package/dist/utils/rect.svelte.d.ts +18 -0
- package/dist/utils/rect.svelte.js +33 -0
- package/dist/utils/trail.js +3 -4
- package/package.json +1 -1
|
@@ -127,10 +127,22 @@
|
|
|
127
127
|
import { getGeoContext } from '../contexts/geo.js';
|
|
128
128
|
import { getLayerContext } from '../contexts/layer.js';
|
|
129
129
|
import { createMotion, createDataMotionMap, type MotionProp } from '../utils/motion.svelte.js';
|
|
130
|
-
import {
|
|
130
|
+
import {
|
|
131
|
+
hasAnyDataProp,
|
|
132
|
+
resolveDataProp,
|
|
133
|
+
extractRawDataValue,
|
|
134
|
+
resolveGeoDataPair,
|
|
135
|
+
resolveStyleProp,
|
|
136
|
+
resolveColorProp,
|
|
137
|
+
} from '../utils/dataProp.js';
|
|
131
138
|
import { chartDataArray } from '../utils/common.js';
|
|
132
139
|
import { cls } from '@layerstack/tailwind';
|
|
133
|
-
import {
|
|
140
|
+
import {
|
|
141
|
+
vectorArrowPath,
|
|
142
|
+
vectorArrowFilledPath,
|
|
143
|
+
vectorSpikePath,
|
|
144
|
+
transformVectorPath,
|
|
145
|
+
} from '../utils/path.js';
|
|
134
146
|
import Path from './Path.svelte';
|
|
135
147
|
|
|
136
148
|
let {
|
|
@@ -169,11 +181,11 @@
|
|
|
169
181
|
// Per-item style mode: when any style prop is a function, we must render individual paths
|
|
170
182
|
const hasPerItemStyles = $derived(
|
|
171
183
|
typeof fill === 'function' ||
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
184
|
+
typeof stroke === 'function' ||
|
|
185
|
+
typeof fillOpacity === 'function' ||
|
|
186
|
+
typeof strokeWidth === 'function' ||
|
|
187
|
+
typeof opacity === 'function' ||
|
|
188
|
+
typeof className === 'function'
|
|
177
189
|
);
|
|
178
190
|
|
|
179
191
|
// Contexts
|
|
@@ -182,9 +194,7 @@
|
|
|
182
194
|
const layerCtx = getLayerContext();
|
|
183
195
|
|
|
184
196
|
// Data to iterate over in data mode
|
|
185
|
-
const resolvedData: any[] = $derived(
|
|
186
|
-
dataMode ? (dataProp ?? chartDataArray(chartCtx.data)) : []
|
|
187
|
-
);
|
|
197
|
+
const resolvedData: any[] = $derived(dataMode ? (dataProp ?? chartDataArray(chartCtx.data)) : []);
|
|
188
198
|
|
|
189
199
|
// Resolve a single data item to pixel coordinates and values
|
|
190
200
|
function resolveVector(d: any) {
|
|
@@ -200,8 +210,14 @@
|
|
|
200
210
|
return {
|
|
201
211
|
x: resolvedX,
|
|
202
212
|
y: resolvedY,
|
|
203
|
-
length: resolveDataProp(
|
|
204
|
-
|
|
213
|
+
length: resolveDataProp(
|
|
214
|
+
lengthProp,
|
|
215
|
+
d,
|
|
216
|
+
chartCtx.rScale,
|
|
217
|
+
typeof lengthProp === 'number' ? lengthProp : 12
|
|
218
|
+
),
|
|
219
|
+
rotate:
|
|
220
|
+
typeof rotateProp === 'number' ? rotateProp : (extractRawDataValue(rotateProp, d) ?? 0),
|
|
205
221
|
};
|
|
206
222
|
}
|
|
207
223
|
|
|
@@ -289,7 +305,11 @@
|
|
|
289
305
|
|
|
290
306
|
const motionX = createMotion(initialX, () => (typeof x === 'number' ? x : 0), motion);
|
|
291
307
|
const motionY = createMotion(initialY, () => (typeof y === 'number' ? y : 0), motion);
|
|
292
|
-
const motionLength = createMotion(
|
|
308
|
+
const motionLength = createMotion(
|
|
309
|
+
initialLength,
|
|
310
|
+
() => (typeof lengthProp === 'number' ? lengthProp : 12),
|
|
311
|
+
motion
|
|
312
|
+
);
|
|
293
313
|
|
|
294
314
|
const pixelRotate = $derived(typeof rotateProp === 'number' ? rotateProp : 0);
|
|
295
315
|
|
|
@@ -346,7 +366,10 @@
|
|
|
346
366
|
stroke={stroke as string}
|
|
347
367
|
strokeWidth={strokeWidth as number}
|
|
348
368
|
opacity={opacity as number}
|
|
349
|
-
class="lc-vector {isFilled ? 'lc-vector-filled' : 'lc-vector-stroked'} {typeof className ===
|
|
369
|
+
class="lc-vector {isFilled ? 'lc-vector-filled' : 'lc-vector-stroked'} {typeof className ===
|
|
370
|
+
'string'
|
|
371
|
+
? className
|
|
372
|
+
: ''}"
|
|
350
373
|
/>
|
|
351
374
|
{/if}
|
|
352
375
|
|
|
@@ -148,8 +148,7 @@
|
|
|
148
148
|
const ext: [number, number] = [sorted[0], sorted[sorted.length - 1]];
|
|
149
149
|
|
|
150
150
|
// Silverman's rule of thumb for bandwidth
|
|
151
|
-
const bw =
|
|
152
|
-
bandwidthProp ?? 1.06 * (deviation(sorted) ?? 1) * Math.pow(sorted.length, -1 / 5);
|
|
151
|
+
const bw = bandwidthProp ?? 1.06 * (deviation(sorted) ?? 1) * Math.pow(sorted.length, -1 / 5);
|
|
153
152
|
|
|
154
153
|
const kernelFn = epanechnikov(bw);
|
|
155
154
|
|
|
@@ -240,9 +240,7 @@
|
|
|
240
240
|
);
|
|
241
241
|
|
|
242
242
|
// Compute series colors locally to avoid derived_references_self cycle through context.series.allSeriesColors
|
|
243
|
-
const allSeriesColors = $derived(
|
|
244
|
-
series.map((s) => s.color).filter((c) => c != null) as string[]
|
|
245
|
-
);
|
|
243
|
+
const allSeriesColors = $derived(series.map((s) => s.color).filter((c) => c != null) as string[]);
|
|
246
244
|
|
|
247
245
|
// Custom tickFormat for ArcChart legends - uses data labels instead of series labels
|
|
248
246
|
const legendTickFormat = (tick: any) => {
|
|
@@ -416,8 +414,13 @@
|
|
|
416
414
|
value={valueAccessor(data)}
|
|
417
415
|
color={snippetProps.context.cScale?.(snippetProps.context.c(data))}
|
|
418
416
|
{format}
|
|
419
|
-
onpointerenter={() => {
|
|
420
|
-
|
|
417
|
+
onpointerenter={() => {
|
|
418
|
+
if (snippetProps.context)
|
|
419
|
+
snippetProps.context.series.highlightKey = keyAccessor(data);
|
|
420
|
+
}}
|
|
421
|
+
onpointerleave={() => {
|
|
422
|
+
if (snippetProps.context) snippetProps.context.series.highlightKey = null;
|
|
423
|
+
}}
|
|
421
424
|
{...props.tooltip?.item}
|
|
422
425
|
/>
|
|
423
426
|
</Tooltip.List>
|
|
@@ -108,7 +108,12 @@
|
|
|
108
108
|
...(typeof tooltipContext === 'object' ? tooltipContext : null),
|
|
109
109
|
}}
|
|
110
110
|
brush={brush
|
|
111
|
-
? {
|
|
111
|
+
? {
|
|
112
|
+
axis: 'x',
|
|
113
|
+
zoomOnBrush: true,
|
|
114
|
+
...(typeof brush === 'object' ? brush : null),
|
|
115
|
+
...props.brush,
|
|
116
|
+
}
|
|
112
117
|
: false}
|
|
113
118
|
{series}
|
|
114
119
|
{seriesLayout}
|
|
@@ -184,7 +184,9 @@
|
|
|
184
184
|
x1={valueAxis === 'y' && isGroupSeries ? (d) => s.value ?? s.key : undefined}
|
|
185
185
|
y1={valueAxis === 'x' && isGroupSeries ? (d) => s.value ?? s.key : undefined}
|
|
186
186
|
rounded={context.series.divergingEdgeKeys
|
|
187
|
-
? context.series.divergingEdgeKeys.has(s.key)
|
|
187
|
+
? context.series.divergingEdgeKeys.has(s.key)
|
|
188
|
+
? 'edge'
|
|
189
|
+
: 'none'
|
|
188
190
|
: context.series.isStacked && i !== context.series.visibleSeries.length - 1
|
|
189
191
|
? 'none'
|
|
190
192
|
: Array.isArray(xProp) || Array.isArray(yProp)
|
|
@@ -133,7 +133,12 @@
|
|
|
133
133
|
...(typeof tooltipContext === 'object' ? tooltipContext : null),
|
|
134
134
|
}}
|
|
135
135
|
brush={brush
|
|
136
|
-
? {
|
|
136
|
+
? {
|
|
137
|
+
axis: 'x',
|
|
138
|
+
zoomOnBrush: true,
|
|
139
|
+
...(typeof brush === 'object' ? brush : null),
|
|
140
|
+
...props.brush,
|
|
141
|
+
}
|
|
137
142
|
: false}
|
|
138
143
|
{series}
|
|
139
144
|
highlight={highlightWithPointClick as any}
|
|
@@ -308,7 +308,9 @@
|
|
|
308
308
|
startAngle: arc.startAngle,
|
|
309
309
|
endAngle: arc.endAngle,
|
|
310
310
|
outerRadius:
|
|
311
|
-
(context?.series.visibleSeries.length ?? 0) > 1
|
|
311
|
+
(context?.series.visibleSeries.length ?? 0) > 1
|
|
312
|
+
? seriesIndex * (outerRadius ?? 0)
|
|
313
|
+
: outerRadius,
|
|
312
314
|
innerRadius,
|
|
313
315
|
cornerRadius,
|
|
314
316
|
padAngle,
|
|
@@ -464,8 +466,13 @@
|
|
|
464
466
|
value={valueAccessor(data)}
|
|
465
467
|
color={snippetProps.context.cScale?.(snippetProps.context.c(data))}
|
|
466
468
|
{format}
|
|
467
|
-
onpointerenter={() => {
|
|
468
|
-
|
|
469
|
+
onpointerenter={() => {
|
|
470
|
+
if (snippetProps.context)
|
|
471
|
+
snippetProps.context.series.highlightKey = keyAccessor(data);
|
|
472
|
+
}}
|
|
473
|
+
onpointerleave={() => {
|
|
474
|
+
if (snippetProps.context) snippetProps.context.series.highlightKey = null;
|
|
475
|
+
}}
|
|
469
476
|
{...props.tooltip?.item}
|
|
470
477
|
/>
|
|
471
478
|
</Tooltip.List>
|
|
@@ -377,10 +377,7 @@
|
|
|
377
377
|
) {
|
|
378
378
|
rect.left = alignValue(xValue, 'end', xOffset, tooltipWidth);
|
|
379
379
|
}
|
|
380
|
-
if (
|
|
381
|
-
(xAlign === 'end' || xAlign === 'center') &&
|
|
382
|
-
containerRect.left + rect.left < 0
|
|
383
|
-
) {
|
|
380
|
+
if ((xAlign === 'end' || xAlign === 'center') && containerRect.left + rect.left < 0) {
|
|
384
381
|
rect.left = alignValue(xValue, 'start', xOffset, tooltipWidth);
|
|
385
382
|
}
|
|
386
383
|
}
|
|
@@ -393,10 +390,7 @@
|
|
|
393
390
|
) {
|
|
394
391
|
rect.top = alignValue(yValue, 'end', yOffset, tooltipHeight);
|
|
395
392
|
}
|
|
396
|
-
if (
|
|
397
|
-
(yAlign === 'end' || yAlign === 'center') &&
|
|
398
|
-
containerRect.top + rect.top < 0
|
|
399
|
-
) {
|
|
393
|
+
if ((yAlign === 'end' || yAlign === 'center') && containerRect.top + rect.top < 0) {
|
|
400
394
|
rect.top = alignValue(yValue, 'start', yOffset, tooltipHeight);
|
|
401
395
|
}
|
|
402
396
|
}
|
package/dist/contexts/chart.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { ChartState } from '../states/chart.svelte.js';
|
|
2
2
|
import type { AnyScale } from '../utils/scales.svelte.js';
|
|
3
3
|
export type { ChartState };
|
|
4
|
-
export type { NodeKind, ComponentNode, RegisterComponentOptions } from '../states/chart.svelte.js';
|
|
4
|
+
export type { NodeKind, ComponentNode, RegisterComponentOptions, } from '../states/chart.svelte.js';
|
|
5
5
|
export declare function getChartContext<T, XScale extends AnyScale = AnyScale, YScale extends AnyScale = AnyScale>(): ChartState<T, XScale, YScale>;
|
|
6
6
|
export declare function setChartContext<T, XScale extends AnyScale = AnyScale, YScale extends AnyScale = AnyScale>(context: ChartState<T, XScale, YScale>): ChartState<T, XScale, YScale>;
|
package/dist/contexts/chart.js
CHANGED
|
@@ -5,7 +5,9 @@ const _ChartContext = new Context('ChartContext');
|
|
|
5
5
|
* Provides safe defaults to prevent runtime errors.
|
|
6
6
|
*/
|
|
7
7
|
const fallbackContext = {
|
|
8
|
-
registerMark: () => () => {
|
|
8
|
+
registerMark: () => () => {
|
|
9
|
+
/* no-op */
|
|
10
|
+
},
|
|
9
11
|
registerComponent: (_options) => ({
|
|
10
12
|
id: Symbol('noop'),
|
|
11
13
|
kind: 'mark',
|
|
@@ -1,35 +1,35 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
2
|
+
import { scaleBand } from 'd3-scale';
|
|
3
|
+
import ServerChart from './ServerChart.svelte';
|
|
4
|
+
import type { CaptureTarget } from './captureStore.js';
|
|
5
|
+
import Bars from '../components/Bars.svelte';
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
7
|
+
let {
|
|
8
|
+
data,
|
|
9
|
+
width,
|
|
10
|
+
height,
|
|
11
|
+
capture,
|
|
12
|
+
onCapture,
|
|
13
|
+
}: {
|
|
14
|
+
data: { category: string; value: number }[];
|
|
15
|
+
width: number;
|
|
16
|
+
height: number;
|
|
17
|
+
capture?: CaptureTarget;
|
|
18
|
+
onCapture?: (data: CaptureTarget) => void;
|
|
19
|
+
} = $props();
|
|
20
20
|
</script>
|
|
21
21
|
|
|
22
22
|
<ServerChart
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
23
|
+
{capture}
|
|
24
|
+
{onCapture}
|
|
25
|
+
{width}
|
|
26
|
+
{height}
|
|
27
|
+
{data}
|
|
28
|
+
x="category"
|
|
29
|
+
xScale={scaleBand().paddingInner(0.2).paddingOuter(0.1)}
|
|
30
|
+
y="value"
|
|
31
|
+
yDomain={[0, null]}
|
|
32
|
+
padding={{ top: 20, right: 20, bottom: 30, left: 40 }}
|
|
33
33
|
>
|
|
34
|
-
|
|
34
|
+
<Bars fill="rgb(59, 130, 246)" radius={4} />
|
|
35
35
|
</ServerChart>
|
|
@@ -1,35 +1,35 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
2
|
+
import ServerChart from './ServerChart.svelte';
|
|
3
|
+
import type { CaptureTarget } from './captureStore.js';
|
|
4
|
+
import Area from '../components/Area.svelte';
|
|
5
|
+
import Spline from '../components/Spline.svelte';
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
7
|
+
let {
|
|
8
|
+
data,
|
|
9
|
+
width,
|
|
10
|
+
height,
|
|
11
|
+
capture,
|
|
12
|
+
onCapture,
|
|
13
|
+
}: {
|
|
14
|
+
data: { date: number; value: number }[];
|
|
15
|
+
width: number;
|
|
16
|
+
height: number;
|
|
17
|
+
capture?: CaptureTarget;
|
|
18
|
+
onCapture?: (data: CaptureTarget) => void;
|
|
19
|
+
} = $props();
|
|
20
20
|
</script>
|
|
21
21
|
|
|
22
22
|
<ServerChart
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
23
|
+
{capture}
|
|
24
|
+
{onCapture}
|
|
25
|
+
{width}
|
|
26
|
+
{height}
|
|
27
|
+
{data}
|
|
28
|
+
x="date"
|
|
29
|
+
y="value"
|
|
30
|
+
yDomain={[0, null]}
|
|
31
|
+
padding={{ top: 20, right: 20, bottom: 20, left: 20 }}
|
|
32
32
|
>
|
|
33
|
-
|
|
34
|
-
|
|
33
|
+
<Area fill="rgba(59, 130, 246, 0.15)" stroke="none" />
|
|
34
|
+
<Spline stroke="rgb(59, 130, 246)" strokeWidth={2} />
|
|
35
35
|
</ServerChart>
|
package/dist/server/index.js
CHANGED
|
@@ -64,7 +64,7 @@ export function renderChart(component, options) {
|
|
|
64
64
|
const captureTarget = {};
|
|
65
65
|
// SSR render to build the component tree and capture chart state
|
|
66
66
|
const rendered = render(component, {
|
|
67
|
-
props: { ...props, width, height, capture: captureTarget }
|
|
67
|
+
props: { ...props, width, height, capture: captureTarget },
|
|
68
68
|
});
|
|
69
69
|
// Force the SSR render to fully flush
|
|
70
70
|
void rendered.body;
|
|
@@ -6,9 +6,7 @@ import { add } from '../utils/math.js';
|
|
|
6
6
|
* For continuous scales, returns the domain unchanged.
|
|
7
7
|
*/
|
|
8
8
|
export function expandBandBrushDomain(brushDomain, baseDomain) {
|
|
9
|
-
if (brushDomain[0] == null ||
|
|
10
|
-
brushDomain[1] == null ||
|
|
11
|
-
typeof brushDomain[0] !== 'string') {
|
|
9
|
+
if (brushDomain[0] == null || brushDomain[1] == null || typeof brushDomain[0] !== 'string') {
|
|
12
10
|
return brushDomain;
|
|
13
11
|
}
|
|
14
12
|
const startIdx = baseDomain.indexOf(brushDomain[0]);
|
|
@@ -109,8 +107,7 @@ export class BrushState {
|
|
|
109
107
|
// Determine active state from current values
|
|
110
108
|
const hasX = this.x[0] != null && this.x[1] != null;
|
|
111
109
|
const hasY = this.y[0] != null && this.y[1] != null;
|
|
112
|
-
this.active =
|
|
113
|
-
this.axis === 'x' ? hasX : this.axis === 'y' ? hasY : hasX || hasY;
|
|
110
|
+
this.active = this.axis === 'x' ? hasX : this.axis === 'y' ? hasY : hasX || hasY;
|
|
114
111
|
}
|
|
115
112
|
/** Set brush to a new range, clamped to domain bounds */
|
|
116
113
|
setRange(startValue, currentValue) {
|
|
@@ -177,12 +174,16 @@ export class BrushState {
|
|
|
177
174
|
const yDomain = this.ctx?.baseYScale.domain() ?? [];
|
|
178
175
|
const xCat = isCategoricalDomain(xDomain);
|
|
179
176
|
const yCat = isCategoricalDomain(yDomain);
|
|
180
|
-
const clampX = (v) => xCat
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
const
|
|
184
|
-
|
|
185
|
-
|
|
177
|
+
const clampX = (v) => xCat
|
|
178
|
+
? clampByIndex(v, this.xDomainMin, this.xDomainMax, xDomain)
|
|
179
|
+
: clamp(v, this.xDomainMin, this.xDomainMax);
|
|
180
|
+
const clampY = (v) => yCat
|
|
181
|
+
? clampByIndex(v, this.yDomainMin, this.yDomainMax, yDomain)
|
|
182
|
+
: clamp(v, this.yDomainMin, this.yDomainMax);
|
|
183
|
+
const ltX = (a, b) => (xCat ? xDomain.indexOf(a) < xDomain.indexOf(b) : a < +b);
|
|
184
|
+
const gtX = (a, b) => (xCat ? xDomain.indexOf(a) > xDomain.indexOf(b) : a > +b);
|
|
185
|
+
const ltY = (a, b) => (yCat ? yDomain.indexOf(a) < yDomain.indexOf(b) : a < +b);
|
|
186
|
+
const gtY = (a, b) => (yCat ? yDomain.indexOf(a) > yDomain.indexOf(b) : a > +b);
|
|
186
187
|
switch (edge) {
|
|
187
188
|
case 'top':
|
|
188
189
|
this.y = [
|
|
@@ -218,10 +219,12 @@ export class BrushState {
|
|
|
218
219
|
const newX = externalX ?? [null, null];
|
|
219
220
|
const newY = externalY ?? [null, null];
|
|
220
221
|
// Only write when values actually differ to avoid reactive loops
|
|
221
|
-
if (this.x[0]?.valueOf() !== newX[0]?.valueOf() ||
|
|
222
|
+
if (this.x[0]?.valueOf() !== newX[0]?.valueOf() ||
|
|
223
|
+
this.x[1]?.valueOf() !== newX[1]?.valueOf()) {
|
|
222
224
|
this.x = newX;
|
|
223
225
|
}
|
|
224
|
-
if (this.y[0]?.valueOf() !== newY[0]?.valueOf() ||
|
|
226
|
+
if (this.y[0]?.valueOf() !== newY[0]?.valueOf() ||
|
|
227
|
+
this.y[1]?.valueOf() !== newY[1]?.valueOf()) {
|
|
225
228
|
this.y = newY;
|
|
226
229
|
}
|
|
227
230
|
const isXAxisActive = externalX != null &&
|
|
@@ -287,17 +287,23 @@ describe('ChartState mark registration', () => {
|
|
|
287
287
|
flushSync();
|
|
288
288
|
expect(state.seriesState.isDefaultSeries).toBe(false);
|
|
289
289
|
expect(state.seriesState.series).toHaveLength(2);
|
|
290
|
-
expect(state.seriesState.series[0]).toMatchObject({
|
|
291
|
-
|
|
290
|
+
expect(state.seriesState.series[0]).toMatchObject({
|
|
291
|
+
key: 'apples',
|
|
292
|
+
color: 'red',
|
|
293
|
+
value: 'apples',
|
|
294
|
+
});
|
|
295
|
+
expect(state.seriesState.series[1]).toMatchObject({
|
|
296
|
+
key: 'bananas',
|
|
297
|
+
color: 'yellow',
|
|
298
|
+
value: 'bananas',
|
|
299
|
+
});
|
|
292
300
|
}
|
|
293
301
|
finally {
|
|
294
302
|
cleanup();
|
|
295
303
|
}
|
|
296
304
|
});
|
|
297
305
|
it('should not generate implicit series when explicit series are provided', () => {
|
|
298
|
-
const data = [
|
|
299
|
-
{ date: '2024-01', apples: 10, bananas: 15 },
|
|
300
|
-
];
|
|
306
|
+
const data = [{ date: '2024-01', apples: 10, bananas: 15 }];
|
|
301
307
|
const { state, cleanup } = createChartState({
|
|
302
308
|
data,
|
|
303
309
|
x: 'date',
|
|
@@ -611,8 +617,16 @@ describe('ChartState geo projection skips markInfo', () => {
|
|
|
611
617
|
// seriesKey/color/label should still create implicit series for legends
|
|
612
618
|
expect(state.seriesState.isDefaultSeries).toBe(false);
|
|
613
619
|
expect(state.seriesState.series).toHaveLength(2);
|
|
614
|
-
expect(state.seriesState.series[0]).toMatchObject({
|
|
615
|
-
|
|
620
|
+
expect(state.seriesState.series[0]).toMatchObject({
|
|
621
|
+
key: 'earthquakes',
|
|
622
|
+
color: 'red',
|
|
623
|
+
label: 'Earthquakes',
|
|
624
|
+
});
|
|
625
|
+
expect(state.seriesState.series[1]).toMatchObject({
|
|
626
|
+
key: 'volcanos',
|
|
627
|
+
color: 'orange',
|
|
628
|
+
label: 'Volcanos',
|
|
629
|
+
});
|
|
616
630
|
// But flatData should not include extra mark data
|
|
617
631
|
expect(state.flatData).toHaveLength(3);
|
|
618
632
|
}
|
|
@@ -861,9 +875,7 @@ describe('ChartState implicit x/y from marks (no x/y on Chart)', () => {
|
|
|
861
875
|
}
|
|
862
876
|
});
|
|
863
877
|
it('should deduplicate repeated mark x keys into a single accessor', () => {
|
|
864
|
-
const data = [
|
|
865
|
-
{ date: new Date(2024, 0, 1), value: 10 },
|
|
866
|
-
];
|
|
878
|
+
const data = [{ date: new Date(2024, 0, 1), value: 10 }];
|
|
867
879
|
const { state, cleanup } = createChartState({});
|
|
868
880
|
try {
|
|
869
881
|
// Two marks, same x='date' — should not create duplicate keys
|
|
@@ -878,9 +890,7 @@ describe('ChartState implicit x/y from marks (no x/y on Chart)', () => {
|
|
|
878
890
|
}
|
|
879
891
|
});
|
|
880
892
|
it('should use explicit x/y from Chart props over mark-derived values', () => {
|
|
881
|
-
const data = [
|
|
882
|
-
{ date: new Date(2024, 0, 1), value: 10 },
|
|
883
|
-
];
|
|
893
|
+
const data = [{ date: new Date(2024, 0, 1), value: 10 }];
|
|
884
894
|
const { state, cleanup } = createChartState({
|
|
885
895
|
x: 'value', // explicit — should override 'date' from marks
|
|
886
896
|
y: 'value',
|
|
@@ -1250,12 +1260,7 @@ describe('ChartState group layout auto-derives x1/y1', () => {
|
|
|
1250
1260
|
{ year: '2016', apples: 480, bananas: 240, cherries: 120, grapes: 50 },
|
|
1251
1261
|
{ year: '2017', apples: 960, bananas: 480, cherries: 240, grapes: 100 },
|
|
1252
1262
|
];
|
|
1253
|
-
const series = [
|
|
1254
|
-
{ key: 'apples' },
|
|
1255
|
-
{ key: 'bananas' },
|
|
1256
|
-
{ key: 'cherries' },
|
|
1257
|
-
{ key: 'grapes' },
|
|
1258
|
-
];
|
|
1263
|
+
const series = [{ key: 'apples' }, { key: 'bananas' }, { key: 'cherries' }, { key: 'grapes' }];
|
|
1259
1264
|
it('should auto-derive x1Domain from series keys when seriesLayout=group and valueAxis=y', () => {
|
|
1260
1265
|
const { state, cleanup } = createChartState({
|
|
1261
1266
|
data: wideData,
|
|
@@ -57,10 +57,7 @@ export class GeoState {
|
|
|
57
57
|
]);
|
|
58
58
|
}
|
|
59
59
|
if (this.transformState?.mode === 'projection' && this.transformApply.translate) {
|
|
60
|
-
_projection.translate([
|
|
61
|
-
this.transformState.translate.x,
|
|
62
|
-
this.transformState.translate.y,
|
|
63
|
-
]);
|
|
60
|
+
_projection.translate([this.transformState.translate.x, this.transformState.translate.y]);
|
|
64
61
|
}
|
|
65
62
|
}
|
|
66
63
|
// Apply center
|
|
@@ -214,7 +214,7 @@ export class SeriesState {
|
|
|
214
214
|
* Check if the series is the default
|
|
215
215
|
*/
|
|
216
216
|
get isDefaultSeries() {
|
|
217
|
-
return this.#series.length === 0 || (this.#series.length === 1 && this.#series[0].key === 'default');
|
|
217
|
+
return (this.#series.length === 0 || (this.#series.length === 1 && this.#series[0].key === 'default'));
|
|
218
218
|
}
|
|
219
219
|
/**
|
|
220
220
|
* Check if series is highlighted
|
|
Binary file
|
|
Binary file
|
package/dist/utils/canvas.d.ts
CHANGED
|
@@ -32,6 +32,8 @@ export declare function renderRect(ctx: CanvasRenderingContext2D, coords: {
|
|
|
32
32
|
height: number;
|
|
33
33
|
rx?: number;
|
|
34
34
|
ry?: number;
|
|
35
|
+
/** Per-corner radii [tl, tr, br, bl]. Takes precedence over `rx`/`ry`. */
|
|
36
|
+
corners?: [number, number, number, number];
|
|
35
37
|
}, styleOptions?: ComputedStylesOptions): void;
|
|
36
38
|
export declare function renderCircle(ctx: CanvasRenderingContext2D, coords: {
|
|
37
39
|
cx: number;
|