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
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
}: Props = $props();
|
|
35
35
|
</script>
|
|
36
36
|
|
|
37
|
-
<Chart {data} {x} {y} {width} {height} {series}
|
|
37
|
+
<Chart {data} {x} {y} {width} {height} {series} {xDomain} {yDomain}>
|
|
38
38
|
<Layer type={layer}>
|
|
39
39
|
{#if axis}
|
|
40
40
|
<Axis placement="left" />
|
|
@@ -12,14 +12,7 @@
|
|
|
12
12
|
width?: number;
|
|
13
13
|
};
|
|
14
14
|
|
|
15
|
-
let {
|
|
16
|
-
features,
|
|
17
|
-
fitGeojson,
|
|
18
|
-
projection,
|
|
19
|
-
layer = 'svg',
|
|
20
|
-
height = 400,
|
|
21
|
-
width,
|
|
22
|
-
}: Props = $props();
|
|
15
|
+
let { features, fitGeojson, projection, layer = 'svg', height = 400, width }: Props = $props();
|
|
23
16
|
</script>
|
|
24
17
|
|
|
25
18
|
<Chart geo={{ projection, fitGeojson }} {width} {height}>
|
|
@@ -78,7 +78,9 @@
|
|
|
78
78
|
const y0 = y ? ctx.yScale(y[0] ?? ctx.yDomain[0]) : ctx.yRange[0];
|
|
79
79
|
const y1 = y ? ctx.yScale(y[1] ?? ctx.yDomain[1]) : ctx.yRange[1];
|
|
80
80
|
|
|
81
|
-
const bandPadding = isScaleBand(ctx.xScale)
|
|
81
|
+
const bandPadding = isScaleBand(ctx.xScale)
|
|
82
|
+
? (ctx.xScale.padding() * ctx.xScale.step()) / 2
|
|
83
|
+
: 0;
|
|
82
84
|
const bandStep = isScaleBand(ctx.xScale) ? ctx.xScale.step() : 0;
|
|
83
85
|
|
|
84
86
|
return {
|
|
@@ -255,9 +255,7 @@
|
|
|
255
255
|
|
|
256
256
|
const endAngle = $derived(
|
|
257
257
|
endAngleProp ??
|
|
258
|
-
degreesToRadians(
|
|
259
|
-
(ctx.config.xRange ? max(ctx.config.xRange as number[]) : max(range))!
|
|
260
|
-
)
|
|
258
|
+
degreesToRadians((ctx.config.xRange ? max(ctx.config.xRange as number[]) : max(range))!)
|
|
261
259
|
);
|
|
262
260
|
|
|
263
261
|
const motionEndAngle = createMotion(initialValue, () => value, motion);
|
|
@@ -19,7 +19,7 @@ describe('ArcLabel', () => {
|
|
|
19
19
|
childComponents: [
|
|
20
20
|
{
|
|
21
21
|
component: ArcLabel,
|
|
22
|
-
props: ({ centroid, startAngle, endAngle, innerRadius, outerRadius, getArcTextProps }) => ({
|
|
22
|
+
props: ({ centroid, startAngle, endAngle, innerRadius, outerRadius, getArcTextProps, }) => ({
|
|
23
23
|
centroid,
|
|
24
24
|
startAngle,
|
|
25
25
|
endAngle,
|
|
@@ -46,7 +46,7 @@ describe('ArcLabel', () => {
|
|
|
46
46
|
childComponents: [
|
|
47
47
|
{
|
|
48
48
|
component: ArcLabel,
|
|
49
|
-
props: ({ centroid, startAngle, endAngle, innerRadius, outerRadius, getArcTextProps }) => ({
|
|
49
|
+
props: ({ centroid, startAngle, endAngle, innerRadius, outerRadius, getArcTextProps, }) => ({
|
|
50
50
|
centroid,
|
|
51
51
|
startAngle,
|
|
52
52
|
endAngle,
|
|
@@ -77,7 +77,7 @@ describe('ArcLabel', () => {
|
|
|
77
77
|
childComponents: [
|
|
78
78
|
{
|
|
79
79
|
component: ArcLabel,
|
|
80
|
-
props: ({ centroid, startAngle, endAngle, innerRadius, outerRadius, getArcTextProps }) => ({
|
|
80
|
+
props: ({ centroid, startAngle, endAngle, innerRadius, outerRadius, getArcTextProps, }) => ({
|
|
81
81
|
centroid,
|
|
82
82
|
startAngle,
|
|
83
83
|
endAngle,
|
|
@@ -109,7 +109,7 @@ describe('ArcLabel', () => {
|
|
|
109
109
|
childComponents: [
|
|
110
110
|
{
|
|
111
111
|
component: ArcLabel,
|
|
112
|
-
props: ({ centroid, startAngle, endAngle, innerRadius, outerRadius, getArcTextProps }) => ({
|
|
112
|
+
props: ({ centroid, startAngle, endAngle, innerRadius, outerRadius, getArcTextProps, }) => ({
|
|
113
113
|
centroid,
|
|
114
114
|
startAngle,
|
|
115
115
|
endAngle,
|
|
@@ -141,7 +141,7 @@ describe('ArcLabel', () => {
|
|
|
141
141
|
childComponents: [
|
|
142
142
|
{
|
|
143
143
|
component: ArcLabel,
|
|
144
|
-
props: ({ centroid, startAngle, endAngle, innerRadius, outerRadius, getArcTextProps }) => ({
|
|
144
|
+
props: ({ centroid, startAngle, endAngle, innerRadius, outerRadius, getArcTextProps, }) => ({
|
|
145
145
|
centroid,
|
|
146
146
|
startAngle,
|
|
147
147
|
endAngle,
|
|
@@ -180,7 +180,7 @@ describe('ArcLabel', () => {
|
|
|
180
180
|
childComponents: [
|
|
181
181
|
{
|
|
182
182
|
component: ArcLabel,
|
|
183
|
-
props: ({ centroid, startAngle, endAngle, innerRadius, outerRadius, getArcTextProps }) => ({
|
|
183
|
+
props: ({ centroid, startAngle, endAngle, innerRadius, outerRadius, getArcTextProps, }) => ({
|
|
184
184
|
centroid,
|
|
185
185
|
startAngle,
|
|
186
186
|
endAngle,
|
|
@@ -210,7 +210,7 @@ describe('ArcLabel', () => {
|
|
|
210
210
|
childComponents: [
|
|
211
211
|
{
|
|
212
212
|
component: ArcLabel,
|
|
213
|
-
props: ({ centroid, startAngle, endAngle, innerRadius, outerRadius, getArcTextProps }) => ({
|
|
213
|
+
props: ({ centroid, startAngle, endAngle, innerRadius, outerRadius, getArcTextProps, }) => ({
|
|
214
214
|
centroid,
|
|
215
215
|
startAngle,
|
|
216
216
|
endAngle,
|
|
@@ -33,10 +33,18 @@
|
|
|
33
33
|
rule?: boolean | Partial<ComponentProps<typeof Rule>>;
|
|
34
34
|
|
|
35
35
|
/**
|
|
36
|
-
* Draw grid lines
|
|
36
|
+
* Draw grid lines. Pass props (class, style, stroke, strokeWidth, opacity,
|
|
37
|
+
* dashArray) to forward onto the underlying grid line.
|
|
37
38
|
* @default false
|
|
38
39
|
*/
|
|
39
|
-
grid?:
|
|
40
|
+
grid?:
|
|
41
|
+
| boolean
|
|
42
|
+
| (Pick<SVGAttributes<SVGElement>, 'class' | 'style'> & {
|
|
43
|
+
stroke?: string;
|
|
44
|
+
strokeWidth?: number;
|
|
45
|
+
opacity?: number;
|
|
46
|
+
dashArray?: number | number[] | string;
|
|
47
|
+
});
|
|
40
48
|
|
|
41
49
|
/**
|
|
42
50
|
* Control the number of ticks
|
|
@@ -28,10 +28,16 @@ export type AxisPropsWithoutHTML<In extends Transition = Transition> = {
|
|
|
28
28
|
*/
|
|
29
29
|
rule?: boolean | Partial<ComponentProps<typeof Rule>>;
|
|
30
30
|
/**
|
|
31
|
-
* Draw grid lines
|
|
31
|
+
* Draw grid lines. Pass props (class, style, stroke, strokeWidth, opacity,
|
|
32
|
+
* dashArray) to forward onto the underlying grid line.
|
|
32
33
|
* @default false
|
|
33
34
|
*/
|
|
34
|
-
grid?: boolean | Pick<SVGAttributes<SVGElement>, 'class' | 'style'
|
|
35
|
+
grid?: boolean | (Pick<SVGAttributes<SVGElement>, 'class' | 'style'> & {
|
|
36
|
+
stroke?: string;
|
|
37
|
+
strokeWidth?: number;
|
|
38
|
+
opacity?: number;
|
|
39
|
+
dashArray?: number | number[] | string;
|
|
40
|
+
});
|
|
35
41
|
/**
|
|
36
42
|
* Control the number of ticks
|
|
37
43
|
*/
|
|
@@ -105,14 +105,13 @@
|
|
|
105
105
|
import { greatestAbs } from '@layerstack/utils';
|
|
106
106
|
|
|
107
107
|
import Rect from './Rect.svelte';
|
|
108
|
-
import Path from './Path.svelte';
|
|
109
108
|
|
|
110
109
|
import { isScaleBand, isScaleTime } from '../utils/scales.svelte.js';
|
|
111
110
|
import { accessor, type Accessor } from '../utils/common.js';
|
|
112
111
|
import { getChartContext } from '../contexts/chart.js';
|
|
113
112
|
import type { CommonEvents, CommonStyleProps, Without } from '../utils/types.js';
|
|
114
113
|
import { extractLayerProps } from '../utils/attributes.js';
|
|
115
|
-
import {
|
|
114
|
+
import { type MotionProp } from '../utils/motion.svelte.js';
|
|
116
115
|
import Arc from './Arc.svelte';
|
|
117
116
|
|
|
118
117
|
const ctx = getChartContext();
|
|
@@ -254,41 +253,31 @@
|
|
|
254
253
|
const topRight = $derived(['all', 'top', 'right', 'top-right'].includes(rounded));
|
|
255
254
|
const bottomLeft = $derived(['all', 'bottom', 'left', 'bottom-left'].includes(rounded));
|
|
256
255
|
const bottomRight = $derived(['all', 'bottom', 'right', 'bottom-right'].includes(rounded));
|
|
257
|
-
const width = $derived(dimensions.width);
|
|
258
|
-
const height = $derived(dimensions.height);
|
|
259
256
|
|
|
260
|
-
//
|
|
261
|
-
const
|
|
262
|
-
|
|
257
|
+
// Per-corner radii: [tl, tr, br, bl], matching CSS `border-radius` shorthand.
|
|
258
|
+
const corners = $derived<[number, number, number, number]>([
|
|
259
|
+
topLeft ? radius : 0,
|
|
260
|
+
topRight ? radius : 0,
|
|
261
|
+
bottomRight ? radius : 0,
|
|
262
|
+
bottomLeft ? radius : 0,
|
|
263
|
+
]);
|
|
263
264
|
|
|
264
265
|
// Auto-compute initial values for mount animation when motion is configured
|
|
265
266
|
const resolvedInitialY = $derived(
|
|
266
|
-
initialY ??
|
|
267
|
+
initialY ??
|
|
268
|
+
(motion && ctx.valueAxis === 'y' ? Math.max(ctx.yRange[0], ctx.yRange[1]) : undefined)
|
|
267
269
|
);
|
|
268
270
|
const resolvedInitialHeight = $derived(
|
|
269
271
|
initialHeight ?? (motion && ctx.valueAxis === 'y' ? 0 : undefined)
|
|
270
272
|
);
|
|
271
273
|
const resolvedInitialX = $derived(
|
|
272
|
-
initialX ??
|
|
274
|
+
initialX ??
|
|
275
|
+
(motion && ctx.valueAxis === 'x' ? Math.min(ctx.xRange[0], ctx.xRange[1]) : undefined)
|
|
273
276
|
);
|
|
274
277
|
const resolvedInitialWidth = $derived(
|
|
275
278
|
initialWidth ?? (motion && ctx.valueAxis === 'x' ? 0 : undefined)
|
|
276
279
|
);
|
|
277
280
|
|
|
278
|
-
const pathData = $derived(
|
|
279
|
-
`M${dimensions.x + r},${dimensions.y} h${width - diameter}
|
|
280
|
-
${topRight ? `a${r},${r} 0 0 1 ${r},${r}` : `h${r}v${r}`}
|
|
281
|
-
v${height - diameter}
|
|
282
|
-
${bottomRight ? `a${r},${r} 0 0 1 ${-r},${r}` : `v${r}h${-r}`}
|
|
283
|
-
h${diameter - width}
|
|
284
|
-
${bottomLeft ? `a${r},${r} 0 0 1 ${-r},${-r}` : `h${-r}v${-r}`}
|
|
285
|
-
v${diameter - height}
|
|
286
|
-
${topLeft ? `a${r},${r} 0 0 1 ${r},${-r}` : `v${-r}h${r}`}
|
|
287
|
-
z`
|
|
288
|
-
.split('\n')
|
|
289
|
-
.join('')
|
|
290
|
-
);
|
|
291
|
-
|
|
292
281
|
const onPointerEnter: PointerEventHandler<Element> = (e) => {
|
|
293
282
|
onpointerenter?.(e);
|
|
294
283
|
if (tooltip) ctx.tooltip.show(e, data);
|
|
@@ -322,14 +311,14 @@
|
|
|
322
311
|
onpointerleave={onPointerLeave}
|
|
323
312
|
{...extractLayerProps(restProps, 'lc-bar')}
|
|
324
313
|
/>
|
|
325
|
-
{:else
|
|
314
|
+
{:else}
|
|
326
315
|
<Rect
|
|
327
316
|
{fill}
|
|
328
317
|
{fillOpacity}
|
|
329
318
|
{stroke}
|
|
330
319
|
{strokeWidth}
|
|
331
320
|
{opacity}
|
|
332
|
-
|
|
321
|
+
{corners}
|
|
333
322
|
{motion}
|
|
334
323
|
initialX={resolvedInitialX}
|
|
335
324
|
initialY={resolvedInitialY}
|
|
@@ -341,19 +330,4 @@
|
|
|
341
330
|
onpointerleave={onPointerLeave}
|
|
342
331
|
{...extractLayerProps(restProps, 'lc-bar')}
|
|
343
332
|
/>
|
|
344
|
-
{:else}
|
|
345
|
-
{@const tweenMotion = extractTweenConfig(motion)}
|
|
346
|
-
<Path
|
|
347
|
-
{pathData}
|
|
348
|
-
{fill}
|
|
349
|
-
{fillOpacity}
|
|
350
|
-
{stroke}
|
|
351
|
-
{strokeWidth}
|
|
352
|
-
{opacity}
|
|
353
|
-
motion={tweenMotion}
|
|
354
|
-
onpointerenter={onPointerEnter}
|
|
355
|
-
onpointermove={onPointerMove}
|
|
356
|
-
onpointerleave={onPointerLeave}
|
|
357
|
-
{...extractLayerProps(restProps, 'lc-bar')}
|
|
358
|
-
/>
|
|
359
333
|
{/if}
|
|
@@ -134,21 +134,13 @@
|
|
|
134
134
|
});
|
|
135
135
|
|
|
136
136
|
// Resolve final statistics: explicit props take priority over computed values
|
|
137
|
-
const minVal = $derived(
|
|
138
|
-
|
|
139
|
-
);
|
|
140
|
-
const q1Val = $derived(
|
|
141
|
-
q1Prop != null ? accessor(q1Prop)(data) : computedStats?.q1
|
|
142
|
-
);
|
|
137
|
+
const minVal = $derived(minProp != null ? accessor(minProp)(data) : computedStats?.min);
|
|
138
|
+
const q1Val = $derived(q1Prop != null ? accessor(q1Prop)(data) : computedStats?.q1);
|
|
143
139
|
const medianVal = $derived(
|
|
144
140
|
medianProp != null ? accessor(medianProp)(data) : computedStats?.median
|
|
145
141
|
);
|
|
146
|
-
const q3Val = $derived(
|
|
147
|
-
|
|
148
|
-
);
|
|
149
|
-
const maxVal = $derived(
|
|
150
|
-
maxProp != null ? accessor(maxProp)(data) : computedStats?.max
|
|
151
|
-
);
|
|
142
|
+
const q3Val = $derived(q3Prop != null ? accessor(q3Prop)(data) : computedStats?.q3);
|
|
143
|
+
const maxVal = $derived(maxProp != null ? accessor(maxProp)(data) : computedStats?.max);
|
|
152
144
|
const outliersVal = $derived<number[]>(
|
|
153
145
|
outliersProp != null ? (accessor(outliersProp)(data) ?? []) : (computedStats?.outliers ?? [])
|
|
154
146
|
);
|
|
@@ -4,7 +4,18 @@
|
|
|
4
4
|
|
|
5
5
|
type BaseRectCellProps = Omit<
|
|
6
6
|
RectProps,
|
|
7
|
-
|
|
7
|
+
| 'width'
|
|
8
|
+
| 'height'
|
|
9
|
+
| 'x0'
|
|
10
|
+
| 'x1'
|
|
11
|
+
| 'y0'
|
|
12
|
+
| 'y1'
|
|
13
|
+
| 'initialX'
|
|
14
|
+
| 'initialY'
|
|
15
|
+
| 'initialWidth'
|
|
16
|
+
| 'initialHeight'
|
|
17
|
+
| 'motion'
|
|
18
|
+
| 'ref'
|
|
8
19
|
>;
|
|
9
20
|
|
|
10
21
|
export type CellProps = BaseRectCellProps & {
|
|
@@ -36,13 +47,7 @@
|
|
|
36
47
|
import Circle from './Circle.svelte';
|
|
37
48
|
import Group from './Group.svelte';
|
|
38
49
|
|
|
39
|
-
let {
|
|
40
|
-
shape = 'rect',
|
|
41
|
-
r,
|
|
42
|
-
x,
|
|
43
|
-
y,
|
|
44
|
-
...restProps
|
|
45
|
-
}: CellProps = $props();
|
|
50
|
+
let { shape = 'rect', r, x, y, ...restProps }: CellProps = $props();
|
|
46
51
|
|
|
47
52
|
const chartCtx = getChartContext();
|
|
48
53
|
const cellWidth = $derived(isScaleBand(chartCtx.xScale) ? chartCtx.xScale.bandwidth() : 0);
|
|
@@ -22,7 +22,11 @@
|
|
|
22
22
|
import { geoFitObjectTransform } from '../utils/geo.js';
|
|
23
23
|
import TransformContext from './TransformContext.svelte';
|
|
24
24
|
import BrushContext from './BrushContext.svelte';
|
|
25
|
-
import {
|
|
25
|
+
import {
|
|
26
|
+
type BrushDomainType,
|
|
27
|
+
type BrushState,
|
|
28
|
+
expandBandBrushDomain,
|
|
29
|
+
} from '../states/brush.svelte.js';
|
|
26
30
|
|
|
27
31
|
import { setChartContext } from '../contexts/chart.js';
|
|
28
32
|
import { ChartState } from '../states/chart.svelte.js';
|
|
@@ -741,7 +745,8 @@
|
|
|
741
745
|
|
|
742
746
|
// Resolve which projection properties the transform state applies to
|
|
743
747
|
const resolvedApply = $derived.by(() => {
|
|
744
|
-
if (transform?.mode !== 'projection')
|
|
748
|
+
if (transform?.mode !== 'projection')
|
|
749
|
+
return { rotation: false, scale: false, translate: false };
|
|
745
750
|
|
|
746
751
|
// Auto-detect globe projections from clipAngle (flat projections return 0, globes return > 0)
|
|
747
752
|
let isGlobe = false;
|
|
@@ -773,7 +778,10 @@
|
|
|
773
778
|
});
|
|
774
779
|
|
|
775
780
|
const initialTransform = $derived(
|
|
776
|
-
transform?.mode === 'projection' &&
|
|
781
|
+
transform?.mode === 'projection' &&
|
|
782
|
+
(resolvedApply.translate || resolvedApply.scale) &&
|
|
783
|
+
geo?.fitGeojson &&
|
|
784
|
+
geo?.projection
|
|
777
785
|
? geoFitObjectTransform(
|
|
778
786
|
geo.projection(),
|
|
779
787
|
[chartState.width, chartState.height],
|
|
@@ -827,7 +835,9 @@
|
|
|
827
835
|
axisScale: number,
|
|
828
836
|
dimension: number,
|
|
829
837
|
baseDomain: number[],
|
|
830
|
-
extent:
|
|
838
|
+
extent:
|
|
839
|
+
| { min?: number | Date | 'data'; max?: number | Date | 'data'; minRange?: number }
|
|
840
|
+
| undefined
|
|
831
841
|
): number => {
|
|
832
842
|
if (!extent || baseDomain.length < 2 || dimension <= 0) return axisTranslate;
|
|
833
843
|
|
|
@@ -844,13 +854,17 @@
|
|
|
844
854
|
|
|
845
855
|
// Normalize reversed domains by flipping the translate
|
|
846
856
|
const reversed = rawD0 > rawD1;
|
|
847
|
-
const normTranslate = reversed
|
|
857
|
+
const normTranslate = reversed
|
|
858
|
+
? dimension * axisScale - axisTranslate - dimension
|
|
859
|
+
: axisTranslate;
|
|
848
860
|
const numMin = Math.min(rawD0, rawD1);
|
|
849
861
|
|
|
850
862
|
const rawMinVal = resolveValue(extent.min, baseDomain[0]);
|
|
851
863
|
const rawMaxVal = resolveValue(extent.max, baseDomain[1]);
|
|
852
|
-
const minVal =
|
|
853
|
-
|
|
864
|
+
const minVal =
|
|
865
|
+
rawMinVal != null && rawMaxVal != null ? Math.min(rawMinVal, rawMaxVal) : rawMinVal;
|
|
866
|
+
const maxVal =
|
|
867
|
+
rawMinVal != null && rawMaxVal != null ? Math.max(rawMinVal, rawMaxVal) : rawMaxVal;
|
|
854
868
|
|
|
855
869
|
// Current visible domain from translate/scale
|
|
856
870
|
const f0 = -normTranslate / axisScale / dimension;
|
|
@@ -869,11 +883,15 @@
|
|
|
869
883
|
// Enforce domain min/max (pan boundaries)
|
|
870
884
|
if (minVal != null && visMin < minVal) {
|
|
871
885
|
visMin = minVal;
|
|
872
|
-
visMax =
|
|
886
|
+
visMax =
|
|
887
|
+
visMin +
|
|
888
|
+
(extent.minRange != null && visRange < extent.minRange ? extent.minRange : visRange);
|
|
873
889
|
}
|
|
874
890
|
if (maxVal != null && visMax > maxVal) {
|
|
875
891
|
visMax = maxVal;
|
|
876
|
-
visMin =
|
|
892
|
+
visMin =
|
|
893
|
+
visMax -
|
|
894
|
+
(extent.minRange != null && visRange < extent.minRange ? extent.minRange : visRange);
|
|
877
895
|
if (minVal != null && visMin < minVal) visMin = minVal;
|
|
878
896
|
}
|
|
879
897
|
|
|
@@ -930,10 +948,9 @@
|
|
|
930
948
|
|
|
931
949
|
// Whether this is a band scale domain transform (affects scaleExtent and constrain defaults)
|
|
932
950
|
const isBandDomainTransform = $derived(
|
|
933
|
-
transform?.mode === 'domain' &&
|
|
934
|
-
((transform.axis ?? 'both') !== 'y' && isScaleBand(chartState._xScaleProp)) ||
|
|
935
|
-
|
|
936
|
-
)
|
|
951
|
+
transform?.mode === 'domain' &&
|
|
952
|
+
(((transform.axis ?? 'both') !== 'y' && isScaleBand(chartState._xScaleProp)) ||
|
|
953
|
+
((transform.axis ?? 'both') !== 'x' && isScaleBand(chartState._yScaleProp)))
|
|
937
954
|
);
|
|
938
955
|
|
|
939
956
|
// For projection mode, scaleExtent is relative to the initial fitted scale (like d3-zoom).
|
|
@@ -942,10 +959,10 @@
|
|
|
942
959
|
const resolvedScaleExtent = $derived.by(() => {
|
|
943
960
|
if (transform?.mode === 'projection' && transform?.scaleExtent && initialTransform) {
|
|
944
961
|
const baseScale = initialTransform.scale;
|
|
945
|
-
return [
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
]
|
|
962
|
+
return [transform.scaleExtent[0] * baseScale, transform.scaleExtent[1] * baseScale] as [
|
|
963
|
+
number,
|
|
964
|
+
number,
|
|
965
|
+
];
|
|
949
966
|
}
|
|
950
967
|
if (!isBandDomainTransform) return transform?.scaleExtent;
|
|
951
968
|
const userExtent = transform?.scaleExtent;
|
|
@@ -972,7 +989,12 @@
|
|
|
972
989
|
// The viewport (at current zoom) must overlap with the translateExtent world bounds.
|
|
973
990
|
// As zoom increases, the allowed translate range grows proportionally.
|
|
974
991
|
const projectionTranslateConstrain = $derived.by(() => {
|
|
975
|
-
if (
|
|
992
|
+
if (
|
|
993
|
+
transform?.mode !== 'projection' ||
|
|
994
|
+
!transform?.translateExtent ||
|
|
995
|
+
!initialTransform ||
|
|
996
|
+
resolvedApply.rotation
|
|
997
|
+
) {
|
|
976
998
|
return undefined;
|
|
977
999
|
}
|
|
978
1000
|
|
|
@@ -998,10 +1020,8 @@
|
|
|
998
1020
|
// Default constrain for band scale domain transforms: prevent panning past data boundaries
|
|
999
1021
|
const bandScaleConstrain = $derived.by(() => {
|
|
1000
1022
|
if (!isBandDomainTransform) return undefined;
|
|
1001
|
-
const xIsBand =
|
|
1002
|
-
|
|
1003
|
-
const yIsBand =
|
|
1004
|
-
(transform!.axis ?? 'both') !== 'x' && isScaleBand(chartState._yScaleProp);
|
|
1023
|
+
const xIsBand = (transform!.axis ?? 'both') !== 'y' && isScaleBand(chartState._xScaleProp);
|
|
1024
|
+
const yIsBand = (transform!.axis ?? 'both') !== 'x' && isScaleBand(chartState._yScaleProp);
|
|
1005
1025
|
|
|
1006
1026
|
return (t: { scale: number; translate: { x: number; y: number } }) => {
|
|
1007
1027
|
let { scale, translate } = t;
|
|
@@ -1021,7 +1041,17 @@
|
|
|
1021
1041
|
// Compose user-provided constrain with domainExtent constrain and band scale constrain
|
|
1022
1042
|
const composedConstrain = $derived.by(() => {
|
|
1023
1043
|
const userConstrain = transform?.constrain;
|
|
1024
|
-
const constrains = [
|
|
1044
|
+
const constrains = [
|
|
1045
|
+
bandScaleConstrain,
|
|
1046
|
+
domainExtentConstrain,
|
|
1047
|
+
projectionTranslateConstrain,
|
|
1048
|
+
userConstrain,
|
|
1049
|
+
].filter(Boolean) as Array<
|
|
1050
|
+
(t: { scale: number; translate: { x: number; y: number } }) => {
|
|
1051
|
+
scale: number;
|
|
1052
|
+
translate: { x: number; y: number };
|
|
1053
|
+
}
|
|
1054
|
+
>;
|
|
1025
1055
|
if (constrains.length === 0) return undefined;
|
|
1026
1056
|
if (constrains.length === 1) return constrains[0];
|
|
1027
1057
|
return (t: { scale: number; translate: { x: number; y: number } }) => {
|
|
@@ -1089,7 +1119,14 @@
|
|
|
1089
1119
|
>
|
|
1090
1120
|
{#key chartState.isMounted}
|
|
1091
1121
|
<!-- svelte-ignore ownership_invalid_binding -->
|
|
1092
|
-
{@const {
|
|
1122
|
+
{@const {
|
|
1123
|
+
domainExtent: _de,
|
|
1124
|
+
constrain: _uc,
|
|
1125
|
+
apply: _apply,
|
|
1126
|
+
scaleExtent: _se,
|
|
1127
|
+
translateExtent: _te,
|
|
1128
|
+
...transformProps
|
|
1129
|
+
} = transform ?? {}}
|
|
1093
1130
|
<TransformContext
|
|
1094
1131
|
bind:state={chartState.transformState}
|
|
1095
1132
|
mode={transform?.mode ?? 'none'}
|
|
@@ -1100,7 +1137,9 @@
|
|
|
1100
1137
|
scaleExtent={resolvedScaleExtent}
|
|
1101
1138
|
translateExtent={resolvedTranslateExtent}
|
|
1102
1139
|
constrain={composedConstrain}
|
|
1103
|
-
disablePointer={
|
|
1140
|
+
disablePointer={brush === true ||
|
|
1141
|
+
(typeof brush === 'object' && !brush.disabled) ||
|
|
1142
|
+
transform?.disablePointer}
|
|
1104
1143
|
{ondragstart}
|
|
1105
1144
|
{onTransform}
|
|
1106
1145
|
{ondragend}
|
|
@@ -1108,7 +1147,11 @@
|
|
|
1108
1147
|
<!-- svelte-ignore ownership_invalid_binding -->
|
|
1109
1148
|
<BrushContext {...enhancedBrushProps} bind:state={chartState.brushState}>
|
|
1110
1149
|
<!-- svelte-ignore ownership_invalid_binding -->
|
|
1111
|
-
<TooltipContext
|
|
1150
|
+
<TooltipContext
|
|
1151
|
+
onclick={onTooltipClick}
|
|
1152
|
+
{...getObjectOrNull(tooltipContext)}
|
|
1153
|
+
bind:state={chartState.tooltipState}
|
|
1154
|
+
>
|
|
1112
1155
|
<ChartChildren {children} {tooltipContext} {...restProps} />
|
|
1113
1156
|
</TooltipContext>
|
|
1114
1157
|
</BrushContext>
|
|
@@ -195,7 +195,12 @@
|
|
|
195
195
|
{#if typeof grid === 'function'}
|
|
196
196
|
{@render grid(snippetProps)}
|
|
197
197
|
{:else if grid}
|
|
198
|
-
<Grid
|
|
198
|
+
<Grid
|
|
199
|
+
x={context.valueAxis === 'x' || context.radial}
|
|
200
|
+
y={context.valueAxis === 'y' || context.radial}
|
|
201
|
+
{...getObjectOrNull(grid)}
|
|
202
|
+
{...props.grid}
|
|
203
|
+
/>
|
|
199
204
|
{/if}
|
|
200
205
|
|
|
201
206
|
<ChartClipPath disabled={!context.props.brush && context.transformState?.mode !== 'domain'}>
|
|
@@ -212,7 +217,12 @@
|
|
|
212
217
|
{#if typeof rule === 'function'}
|
|
213
218
|
{@render rule(snippetProps)}
|
|
214
219
|
{:else if rule}
|
|
215
|
-
<Rule
|
|
220
|
+
<Rule
|
|
221
|
+
x={context.valueAxis === 'x' ? 0 : false}
|
|
222
|
+
y={context.valueAxis === 'y' ? 0 : false}
|
|
223
|
+
{...getObjectOrNull(rule)}
|
|
224
|
+
{...props.rule}
|
|
225
|
+
/>
|
|
216
226
|
{/if}
|
|
217
227
|
{:else if axis}
|
|
218
228
|
{#if axis !== 'x'}
|
|
@@ -236,12 +246,20 @@
|
|
|
236
246
|
{#if typeof rule === 'function'}
|
|
237
247
|
{@render rule(snippetProps)}
|
|
238
248
|
{:else if rule}
|
|
239
|
-
<Rule
|
|
249
|
+
<Rule
|
|
250
|
+
x={context.valueAxis === 'x' ? 0 : false}
|
|
251
|
+
y={context.valueAxis === 'y' ? 0 : false}
|
|
252
|
+
{...getObjectOrNull(rule)}
|
|
253
|
+
{...props.rule}
|
|
254
|
+
/>
|
|
240
255
|
{/if}
|
|
241
256
|
{/if}
|
|
242
257
|
|
|
243
258
|
<!-- Use `full` to allow labels on edge to not be cropped (bleed into padding) -->
|
|
244
|
-
<ChartClipPath
|
|
259
|
+
<ChartClipPath
|
|
260
|
+
disabled={!context.props.brush && context.transformState?.mode !== 'domain'}
|
|
261
|
+
full
|
|
262
|
+
>
|
|
245
263
|
{#if typeof points === 'function'}
|
|
246
264
|
{@render points(snippetProps)}
|
|
247
265
|
{:else if points}
|