layerchart 2.0.0-next.56 → 2.0.0-next.58
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/AnnotationLine.svelte +112 -66
- package/dist/components/AnnotationLine.svelte.d.ts +10 -2
- package/dist/components/AnnotationPoint.svelte +97 -23
- package/dist/components/AnnotationPoint.svelte.d.ts +8 -1
- package/dist/components/AnnotationRange.svelte +17 -6
- package/dist/components/GeoPath.svelte +4 -4
- package/dist/components/Link.svelte +261 -75
- package/dist/components/Link.svelte.d.ts +69 -26
- package/dist/components/Spline.svelte +2 -2
- package/dist/components/Text.svelte +1 -1
- package/dist/components/Voronoi.svelte +35 -6
- package/dist/components/Voronoi.svelte.d.ts +9 -0
- package/dist/components/charts/__screenshots__/BarChart.svelte.test.ts/BarChart-separate-data-per-series-should-render-stacked-series-with-separate-data-arrays-1.png +0 -0
- package/dist/components/charts/__screenshots__/BarChart.svelte.test.ts/BarChart-separate-data-per-series-should-render-stacked-series-with-separate-data-arrays-2.png +0 -0
- package/dist/components/charts/__screenshots__/DefaultTooltip.svelte.test.ts/DefaultTooltip-ScatterChart--single-point--quadtree-mode--should-show-series-header-for-multi-series-1.png +0 -0
- package/dist/components/charts/__screenshots__/DefaultTooltip.svelte.test.ts/DefaultTooltip-ScatterChart--single-point--quadtree-mode--should-show-series-header-for-multi-series-2.png +0 -0
- package/dist/components/index.d.ts +0 -2
- package/dist/components/index.js +0 -2
- package/dist/components/tooltip/TooltipContext.svelte +39 -10
- package/dist/components/tooltip/TooltipContext.svelte.d.ts +14 -0
- package/dist/states/brush.svelte.d.ts +1 -1
- package/dist/states/chart.svelte.js +38 -12
- package/dist/states/chart.svelte.test.js +227 -0
- package/dist/utils/linkUtils.d.ts +42 -0
- package/dist/utils/{connectorUtils.js → linkUtils.js} +56 -6
- package/package.json +1 -1
- package/dist/components/Connector.svelte +0 -167
- package/dist/components/Connector.svelte.d.ts +0 -56
- package/dist/utils/connectorUtils.d.ts +0 -34
|
@@ -58,27 +58,63 @@ function createRoundedPath(opts) {
|
|
|
58
58
|
return `M ${source.x} ${source.y} L ${pBeforeCorner.x} ${pBeforeCorner.y} A ${effectiveRadius} ${effectiveRadius} 0 0 ${sweepFlag} ${pAfterCorner.x} ${pAfterCorner.y} L ${target.x} ${target.y}`;
|
|
59
59
|
}
|
|
60
60
|
}
|
|
61
|
+
/**
|
|
62
|
+
* Swoop: circular arc between source and target. Equivalent to ObservablePlot's
|
|
63
|
+
* Arrow `bend` option — positive angle bends right (clockwise from source to
|
|
64
|
+
* target), negative bends left, 0 is a straight line.
|
|
65
|
+
*/
|
|
66
|
+
function createSwoopPath({ source, target, dx, dy, bend = 22.5 }) {
|
|
67
|
+
const chordLen = Math.hypot(dx, dy);
|
|
68
|
+
const bendRad = (bend * Math.PI) / 180;
|
|
69
|
+
if (Math.abs(bendRad) < 1e-6 || chordLen < 1e-6) {
|
|
70
|
+
return createDirectPath(source, target);
|
|
71
|
+
}
|
|
72
|
+
// Half-chord subtends `bend` at the arc center, so radius = chord / (2 * sin(bend))
|
|
73
|
+
const arcRadius = chordLen / (2 * Math.sin(Math.abs(bendRad)));
|
|
74
|
+
const largeArc = Math.abs(bend) > 90 ? 1 : 0;
|
|
75
|
+
const sweepFlag = bend > 0 ? 1 : 0;
|
|
76
|
+
return `M${source.x},${source.y}A${arcRadius},${arcRadius} 0 ${largeArc} ${sweepFlag} ${target.x},${target.y}`;
|
|
77
|
+
}
|
|
61
78
|
const pathStrategies = {
|
|
62
79
|
square: createSquarePath,
|
|
63
80
|
beveled: createBeveledPath,
|
|
64
81
|
rounded: createRoundedPath,
|
|
82
|
+
swoop: createSwoopPath,
|
|
65
83
|
};
|
|
66
|
-
export function
|
|
84
|
+
export function getLinkPresetPath(opts) {
|
|
67
85
|
const { source, target, type } = opts;
|
|
68
86
|
if (isSamePoint(source, target))
|
|
69
87
|
return '';
|
|
70
88
|
const dx = target.x - source.x;
|
|
71
89
|
const dy = target.y - source.y;
|
|
72
|
-
// straight line cases
|
|
73
|
-
if (type === 'straight' || isNearZero(dx) || isNearZero(dy)) {
|
|
90
|
+
// straight line cases (swoop still bends even when axis-aligned)
|
|
91
|
+
if (type === 'straight' || (type !== 'swoop' && (isNearZero(dx) || isNearZero(dy)))) {
|
|
74
92
|
return createDirectPath(source, target);
|
|
75
93
|
}
|
|
76
94
|
return (pathStrategies[type] || pathStrategies.square)({ ...opts, dx, dy });
|
|
77
95
|
}
|
|
78
96
|
const FALLBACK_PATH = 'M0,0L0,0';
|
|
79
|
-
export function
|
|
97
|
+
export function getLinkD3Path({ source, target, sweep, curve, orientation = 'horizontal', }) {
|
|
80
98
|
const dx = target.x - source.x;
|
|
81
99
|
const dy = target.y - source.y;
|
|
100
|
+
// d3 step curves always step along x. For vertical orientation, emit a
|
|
101
|
+
// y-axis step manually so the step sits between parent/child along depth.
|
|
102
|
+
if (orientation === 'vertical' && sweep === 'none') {
|
|
103
|
+
const { x: sx, y: sy } = source;
|
|
104
|
+
const { x: tx, y: ty } = target;
|
|
105
|
+
if (curve === curveStep) {
|
|
106
|
+
const my = (sy + ty) / 2;
|
|
107
|
+
return `M${sx},${sy}L${sx},${my}L${tx},${my}L${tx},${ty}`;
|
|
108
|
+
}
|
|
109
|
+
if (curve === curveStepBefore) {
|
|
110
|
+
// Bump near source: sibling (x) changes first, then depth (y)
|
|
111
|
+
return `M${sx},${sy}L${tx},${sy}L${tx},${ty}`;
|
|
112
|
+
}
|
|
113
|
+
if (curve === curveStepAfter) {
|
|
114
|
+
// Bump near target: depth (y) changes first, then sibling (x)
|
|
115
|
+
return `M${sx},${sy}L${sx},${ty}L${tx},${ty}`;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
82
118
|
const line = d3Line().curve(curve);
|
|
83
119
|
let points = [];
|
|
84
120
|
const isAligned = isNearZero(dx) || isNearZero(dy);
|
|
@@ -135,12 +171,26 @@ function radialGeometry(source, target) {
|
|
|
135
171
|
sweepFlag,
|
|
136
172
|
};
|
|
137
173
|
}
|
|
138
|
-
export function
|
|
174
|
+
export function getLinkRadialPresetPath({ source, target, type, radius, bend = 22.5, }) {
|
|
139
175
|
const g = radialGeometry(source, target);
|
|
140
176
|
const { sr, ta, tr, sc, ss, tc, ts, sx, sy, tx, ty, sweepFlag } = g;
|
|
141
177
|
if (type === 'straight') {
|
|
142
178
|
return `M${sx},${sy}L${tx},${ty}`;
|
|
143
179
|
}
|
|
180
|
+
if (type === 'swoop') {
|
|
181
|
+
// Circular arc in cartesian space between the polar-converted endpoints.
|
|
182
|
+
const dx = tx - sx;
|
|
183
|
+
const dy = ty - sy;
|
|
184
|
+
const chordLen = Math.hypot(dx, dy);
|
|
185
|
+
const bendRad = (bend * Math.PI) / 180;
|
|
186
|
+
if (Math.abs(bendRad) < 1e-6 || chordLen < 1e-6) {
|
|
187
|
+
return `M${sx},${sy}L${tx},${ty}`;
|
|
188
|
+
}
|
|
189
|
+
const arcRadius = chordLen / (2 * Math.sin(Math.abs(bendRad)));
|
|
190
|
+
const largeArc = Math.abs(bend) > 90 ? 1 : 0;
|
|
191
|
+
const arcSweep = bend > 0 ? 1 : 0;
|
|
192
|
+
return `M${sx},${sy}A${arcRadius},${arcRadius} 0 ${largeArc} ${arcSweep} ${tx},${ty}`;
|
|
193
|
+
}
|
|
144
194
|
if (type === 'rounded') {
|
|
145
195
|
// visx LinkRadialCurve: cubic Bezier with rotated offset (percent controls tension)
|
|
146
196
|
const percent = 0.2;
|
|
@@ -183,7 +233,7 @@ export function getConnectorRadialPresetPath({ source, target, type, radius, })
|
|
|
183
233
|
const p2y = cornerY + radialDir * r * ts;
|
|
184
234
|
return `M${sx},${sy}L${p1x},${p1y}L${p2x},${p2y}L${tx},${ty}`;
|
|
185
235
|
}
|
|
186
|
-
export function
|
|
236
|
+
export function getLinkRadialD3Path({ source, target, curve, }) {
|
|
187
237
|
const g = radialGeometry(source, target);
|
|
188
238
|
const { sr, tr, sc, ss, tc, ts, sx, sy, tx, ty, sweepFlag } = g;
|
|
189
239
|
// Step curves render as polar arcs/radials rather than cartesian stairs.
|
package/package.json
CHANGED
|
@@ -1,167 +0,0 @@
|
|
|
1
|
-
<script lang="ts" module>
|
|
2
|
-
export type ConnectorPropsWithoutHTML = {
|
|
3
|
-
/**
|
|
4
|
-
* The coordinates of the start point of the connector.
|
|
5
|
-
* @default { x: 0, y: 0 }
|
|
6
|
-
*/
|
|
7
|
-
source: ConnectorCoords;
|
|
8
|
-
|
|
9
|
-
/**
|
|
10
|
-
* The coordinates of the end point of the connector.
|
|
11
|
-
*
|
|
12
|
-
* @default { x: 100, y: 100 }
|
|
13
|
-
*/
|
|
14
|
-
target: ConnectorCoords;
|
|
15
|
-
|
|
16
|
-
/**
|
|
17
|
-
* The sweep direction of the connector.
|
|
18
|
-
*
|
|
19
|
-
* @default 'horizontal-vertical'
|
|
20
|
-
*/
|
|
21
|
-
sweep?: ConnectorSweep;
|
|
22
|
-
|
|
23
|
-
/**
|
|
24
|
-
* The type of the connector.
|
|
25
|
-
*
|
|
26
|
-
* Set to `'d3'` to use a D3 curve function via the `curve` prop.
|
|
27
|
-
*
|
|
28
|
-
* @default 'rounded'
|
|
29
|
-
*/
|
|
30
|
-
type?: ConnectorType;
|
|
31
|
-
|
|
32
|
-
/**
|
|
33
|
-
* The radius of the connector.
|
|
34
|
-
*
|
|
35
|
-
* Only used when type is `'beveled'` or `'rounded'`
|
|
36
|
-
*
|
|
37
|
-
* @default 20
|
|
38
|
-
*/
|
|
39
|
-
radius?: number;
|
|
40
|
-
|
|
41
|
-
/**
|
|
42
|
-
* The D3 curve function to use for the connector.
|
|
43
|
-
*
|
|
44
|
-
* Only used when type is `'d3'`
|
|
45
|
-
*
|
|
46
|
-
* @default `d3.curveLinear`
|
|
47
|
-
*/
|
|
48
|
-
curve?: CurveFactory;
|
|
49
|
-
|
|
50
|
-
/**
|
|
51
|
-
* Interpret `source`/`target` as polar coordinates (`x` = angle, `y` = radius)
|
|
52
|
-
* and render the path in radial space. Defaults to `ctx.radial` when unset.
|
|
53
|
-
*/
|
|
54
|
-
radial?: boolean;
|
|
55
|
-
} & PathPropsWithoutHTML;
|
|
56
|
-
|
|
57
|
-
export type ConnectorProps = ConnectorPropsWithoutHTML &
|
|
58
|
-
Without<PathProps, ConnectorPropsWithoutHTML>;
|
|
59
|
-
</script>
|
|
60
|
-
|
|
61
|
-
<script lang="ts">
|
|
62
|
-
import { type CurveFactory, curveLinear } from 'd3-shape';
|
|
63
|
-
import {
|
|
64
|
-
getConnectorD3Path,
|
|
65
|
-
getConnectorPresetPath,
|
|
66
|
-
getConnectorRadialD3Path,
|
|
67
|
-
getConnectorRadialPresetPath,
|
|
68
|
-
type ConnectorCoords,
|
|
69
|
-
type ConnectorSweep,
|
|
70
|
-
type ConnectorType,
|
|
71
|
-
} from '../utils/connectorUtils.js';
|
|
72
|
-
import { getChartContext } from '../contexts/chart.js';
|
|
73
|
-
import Path, { type PathProps, type PathPropsWithoutHTML } from './Path.svelte';
|
|
74
|
-
import type { Without } from '../utils/types.js';
|
|
75
|
-
import { createId } from '../utils/createId.js';
|
|
76
|
-
import { extractLayerProps } from '../utils/attributes.js';
|
|
77
|
-
import MarkerWrapper from './MarkerWrapper.svelte';
|
|
78
|
-
import {
|
|
79
|
-
createMotion,
|
|
80
|
-
extractTweenConfig,
|
|
81
|
-
type ResolvedMotion,
|
|
82
|
-
} from '../utils/motion.svelte.js';
|
|
83
|
-
import { interpolatePath } from 'd3-interpolate-path';
|
|
84
|
-
|
|
85
|
-
const uid = $props.id();
|
|
86
|
-
|
|
87
|
-
let {
|
|
88
|
-
source = { x: 0, y: 0 },
|
|
89
|
-
target = { x: 100, y: 100 },
|
|
90
|
-
sweep: sweepProp,
|
|
91
|
-
type = 'rounded',
|
|
92
|
-
radius = 20,
|
|
93
|
-
curve = curveLinear,
|
|
94
|
-
radial: radialProp,
|
|
95
|
-
pathRef = $bindable(),
|
|
96
|
-
pathData: pathDataProp,
|
|
97
|
-
marker,
|
|
98
|
-
markerStart,
|
|
99
|
-
markerMid,
|
|
100
|
-
markerEnd,
|
|
101
|
-
motion,
|
|
102
|
-
...restProps
|
|
103
|
-
}: ConnectorProps = $props();
|
|
104
|
-
|
|
105
|
-
const ctx = getChartContext();
|
|
106
|
-
const radial = $derived(radialProp ?? ctx.radial ?? false);
|
|
107
|
-
|
|
108
|
-
const sweep = $derived.by(() => {
|
|
109
|
-
if (sweepProp) return sweepProp;
|
|
110
|
-
if (type === 'd3') return 'none';
|
|
111
|
-
return 'horizontal-vertical';
|
|
112
|
-
});
|
|
113
|
-
|
|
114
|
-
const markerStartId = $derived(markerStart || marker ? createId('marker-start', uid) : '');
|
|
115
|
-
const markerMidId = $derived(markerMid || marker ? createId('marker-mid', uid) : '');
|
|
116
|
-
const markerEndId = $derived(markerEnd || marker ? createId('marker-end', uid) : '');
|
|
117
|
-
|
|
118
|
-
const extractedTween = extractTweenConfig(motion);
|
|
119
|
-
|
|
120
|
-
const tweenOptions: ResolvedMotion | undefined = extractedTween
|
|
121
|
-
? {
|
|
122
|
-
type: extractedTween.type,
|
|
123
|
-
options: {
|
|
124
|
-
interpolate: interpolatePath,
|
|
125
|
-
...extractedTween.options,
|
|
126
|
-
},
|
|
127
|
-
}
|
|
128
|
-
: undefined;
|
|
129
|
-
|
|
130
|
-
const pathData = $derived.by(() => {
|
|
131
|
-
if (pathDataProp) return pathDataProp;
|
|
132
|
-
if (radial) {
|
|
133
|
-
return type === 'd3'
|
|
134
|
-
? getConnectorRadialD3Path({ source, target, curve })
|
|
135
|
-
: getConnectorRadialPresetPath({ source, target, type, radius });
|
|
136
|
-
}
|
|
137
|
-
if (type === 'd3') {
|
|
138
|
-
return getConnectorD3Path({
|
|
139
|
-
source,
|
|
140
|
-
target,
|
|
141
|
-
sweep,
|
|
142
|
-
curve,
|
|
143
|
-
});
|
|
144
|
-
} else {
|
|
145
|
-
return getConnectorPresetPath({ source, target, sweep, type, radius });
|
|
146
|
-
}
|
|
147
|
-
});
|
|
148
|
-
|
|
149
|
-
const motionPath = createMotion(
|
|
150
|
-
'',
|
|
151
|
-
() => pathData,
|
|
152
|
-
tweenOptions ? tweenOptions : { type: 'none' }
|
|
153
|
-
);
|
|
154
|
-
</script>
|
|
155
|
-
|
|
156
|
-
<Path
|
|
157
|
-
pathData={motionPath.current}
|
|
158
|
-
bind:pathRef
|
|
159
|
-
marker-start={markerStartId ? `url(#${markerStartId})` : undefined}
|
|
160
|
-
marker-mid={markerMidId ? `url(#${markerMidId})` : undefined}
|
|
161
|
-
marker-end={markerEndId ? `url(#${markerEndId})` : undefined}
|
|
162
|
-
{...extractLayerProps(restProps, 'lc-connector')}
|
|
163
|
-
{...restProps}
|
|
164
|
-
/>
|
|
165
|
-
<MarkerWrapper id={markerStartId} marker={markerStart} />
|
|
166
|
-
<MarkerWrapper id={markerMidId} marker={markerMid} />
|
|
167
|
-
<MarkerWrapper id={markerEndId} marker={markerEnd} />
|
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
export type ConnectorPropsWithoutHTML = {
|
|
2
|
-
/**
|
|
3
|
-
* The coordinates of the start point of the connector.
|
|
4
|
-
* @default { x: 0, y: 0 }
|
|
5
|
-
*/
|
|
6
|
-
source: ConnectorCoords;
|
|
7
|
-
/**
|
|
8
|
-
* The coordinates of the end point of the connector.
|
|
9
|
-
*
|
|
10
|
-
* @default { x: 100, y: 100 }
|
|
11
|
-
*/
|
|
12
|
-
target: ConnectorCoords;
|
|
13
|
-
/**
|
|
14
|
-
* The sweep direction of the connector.
|
|
15
|
-
*
|
|
16
|
-
* @default 'horizontal-vertical'
|
|
17
|
-
*/
|
|
18
|
-
sweep?: ConnectorSweep;
|
|
19
|
-
/**
|
|
20
|
-
* The type of the connector.
|
|
21
|
-
*
|
|
22
|
-
* Set to `'d3'` to use a D3 curve function via the `curve` prop.
|
|
23
|
-
*
|
|
24
|
-
* @default 'rounded'
|
|
25
|
-
*/
|
|
26
|
-
type?: ConnectorType;
|
|
27
|
-
/**
|
|
28
|
-
* The radius of the connector.
|
|
29
|
-
*
|
|
30
|
-
* Only used when type is `'beveled'` or `'rounded'`
|
|
31
|
-
*
|
|
32
|
-
* @default 20
|
|
33
|
-
*/
|
|
34
|
-
radius?: number;
|
|
35
|
-
/**
|
|
36
|
-
* The D3 curve function to use for the connector.
|
|
37
|
-
*
|
|
38
|
-
* Only used when type is `'d3'`
|
|
39
|
-
*
|
|
40
|
-
* @default `d3.curveLinear`
|
|
41
|
-
*/
|
|
42
|
-
curve?: CurveFactory;
|
|
43
|
-
/**
|
|
44
|
-
* Interpret `source`/`target` as polar coordinates (`x` = angle, `y` = radius)
|
|
45
|
-
* and render the path in radial space. Defaults to `ctx.radial` when unset.
|
|
46
|
-
*/
|
|
47
|
-
radial?: boolean;
|
|
48
|
-
} & PathPropsWithoutHTML;
|
|
49
|
-
export type ConnectorProps = ConnectorPropsWithoutHTML & Without<PathProps, ConnectorPropsWithoutHTML>;
|
|
50
|
-
import { type CurveFactory } from 'd3-shape';
|
|
51
|
-
import { type ConnectorCoords, type ConnectorSweep, type ConnectorType } from '../utils/connectorUtils.js';
|
|
52
|
-
import { type PathProps, type PathPropsWithoutHTML } from './Path.svelte';
|
|
53
|
-
import type { Without } from '../utils/types.js';
|
|
54
|
-
declare const Connector: import("svelte").Component<ConnectorProps, {}, "pathRef">;
|
|
55
|
-
type Connector = ReturnType<typeof Connector>;
|
|
56
|
-
export default Connector;
|
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
import { type CurveFactory } from 'd3-shape';
|
|
2
|
-
export type ConnectorCoords = {
|
|
3
|
-
x: number;
|
|
4
|
-
y: number;
|
|
5
|
-
};
|
|
6
|
-
export type PresetConnectorType = 'straight' | 'square' | 'beveled' | 'rounded';
|
|
7
|
-
export type ConnectorType = PresetConnectorType | 'd3';
|
|
8
|
-
export type ConnectorSweep = 'horizontal-vertical' | 'vertical-horizontal' | 'none';
|
|
9
|
-
type GetConnectorPresetPathProps = {
|
|
10
|
-
source: ConnectorCoords;
|
|
11
|
-
target: ConnectorCoords;
|
|
12
|
-
radius: number;
|
|
13
|
-
type: PresetConnectorType;
|
|
14
|
-
sweep: ConnectorSweep;
|
|
15
|
-
};
|
|
16
|
-
export declare function getConnectorPresetPath(opts: GetConnectorPresetPathProps): string;
|
|
17
|
-
type GetConnectorD3PathProps = Omit<GetConnectorPresetPathProps, 'radius' | 'type'> & {
|
|
18
|
-
curve: CurveFactory;
|
|
19
|
-
};
|
|
20
|
-
export declare function getConnectorD3Path({ source, target, sweep, curve }: GetConnectorD3PathProps): string;
|
|
21
|
-
type GetConnectorRadialPresetPathProps = {
|
|
22
|
-
source: ConnectorCoords;
|
|
23
|
-
target: ConnectorCoords;
|
|
24
|
-
type: PresetConnectorType;
|
|
25
|
-
radius: number;
|
|
26
|
-
};
|
|
27
|
-
export declare function getConnectorRadialPresetPath({ source, target, type, radius, }: GetConnectorRadialPresetPathProps): string;
|
|
28
|
-
type GetConnectorRadialD3PathProps = {
|
|
29
|
-
source: ConnectorCoords;
|
|
30
|
-
target: ConnectorCoords;
|
|
31
|
-
curve?: CurveFactory;
|
|
32
|
-
};
|
|
33
|
-
export declare function getConnectorRadialD3Path({ source, target, curve, }: GetConnectorRadialD3PathProps): string;
|
|
34
|
-
export {};
|