layerchart 2.0.0-next.4 → 2.0.0-next.41
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 +15 -2
- package/dist/components/AnnotationPoint.svelte +29 -11
- package/dist/components/AnnotationRange.svelte +18 -4
- package/dist/components/Arc.svelte +5 -5
- package/dist/components/Area.svelte +10 -2
- package/dist/components/Axis.svelte +175 -58
- package/dist/components/Axis.svelte.d.ts +23 -6
- package/dist/components/Bar.svelte +20 -15
- package/dist/components/Bar.svelte.d.ts +2 -2
- package/dist/components/Bars.svelte +4 -4
- package/dist/components/Blur.svelte +7 -6
- package/dist/components/Blur.svelte.d.ts +2 -5
- package/dist/components/BrushContext.svelte +45 -45
- package/dist/components/Calendar.svelte +31 -10
- package/dist/components/Calendar.svelte.d.ts +2 -1
- package/dist/components/Chart.svelte +76 -27
- package/dist/components/Chart.svelte.d.ts +26 -8
- package/dist/components/ChartClipPath.svelte +1 -1
- package/dist/components/Circle.svelte +44 -3
- package/dist/components/CircleClipPath.svelte +8 -1
- package/dist/components/ClipPath.svelte +1 -2
- package/dist/components/ColorRamp.svelte +1 -1
- package/dist/components/ComputedStyles.svelte +9 -2
- package/dist/components/Connector.svelte +3 -3
- package/dist/components/Connector.svelte.d.ts +1 -1
- package/dist/components/Ellipse.svelte +228 -0
- package/dist/components/Ellipse.svelte.d.ts +64 -0
- package/dist/components/ForceSimulation.svelte +184 -50
- package/dist/components/ForceSimulation.svelte.d.ts +95 -21
- package/dist/components/Frame.svelte +1 -1
- package/dist/components/GeoCircle.svelte +1 -1
- package/dist/components/GeoEdgeFade.svelte +1 -1
- package/dist/components/GeoPath.svelte +30 -8
- package/dist/components/GeoPoint.svelte +4 -5
- package/dist/components/GeoSpline.svelte +5 -5
- package/dist/components/GeoSpline.svelte.d.ts +1 -1
- package/dist/components/GeoTile.svelte +1 -1
- package/dist/components/Graticule.svelte +5 -5
- package/dist/components/Grid.svelte +60 -63
- package/dist/components/Group.svelte +13 -8
- package/dist/components/Group.svelte.d.ts +10 -3
- package/dist/components/Highlight.svelte +55 -28
- package/dist/components/Highlight.svelte.d.ts +4 -0
- package/dist/components/Hull.svelte +12 -5
- package/dist/components/Labels.svelte +24 -13
- package/dist/components/Labels.svelte.d.ts +12 -5
- package/dist/components/Legend.svelte +143 -70
- package/dist/components/Legend.svelte.d.ts +12 -8
- package/dist/components/Line.svelte +40 -3
- package/dist/components/LinearGradient.svelte +35 -4
- package/dist/components/Link.svelte +1 -1
- package/dist/components/Marker.svelte +37 -26
- package/dist/components/MonthPath.svelte +26 -12
- package/dist/components/MonthPath.svelte.d.ts +4 -3
- package/dist/components/MotionPath.svelte +1 -1
- package/dist/components/Pack.svelte.d.ts +10 -3
- package/dist/components/Partition.svelte.d.ts +10 -3
- package/dist/components/Pattern.svelte +5 -5
- package/dist/components/Pie.svelte +1 -2
- package/dist/components/Points.svelte +11 -72
- package/dist/components/Points.svelte.d.ts +1 -8
- package/dist/components/Polygon.svelte +309 -0
- package/dist/components/Polygon.svelte.d.ts +115 -0
- package/dist/components/RadialGradient.svelte +4 -6
- package/dist/components/Rect.svelte +55 -5
- package/dist/components/Rect.svelte.d.ts +2 -2
- package/dist/components/RectClipPath.svelte +4 -3
- package/dist/components/RectClipPath.svelte.d.ts +2 -2
- package/dist/components/Rule.svelte +167 -77
- package/dist/components/Rule.svelte.d.ts +7 -2
- package/dist/components/Spline.svelte +59 -28
- package/dist/components/Spline.svelte.d.ts +12 -4
- package/dist/components/Text.svelte +121 -73
- package/dist/components/Text.svelte.d.ts +6 -0
- package/dist/components/TileImage.svelte +19 -4
- package/dist/components/TransformContext.svelte +9 -3
- package/dist/components/TransformControls.svelte +89 -38
- package/dist/components/Tree.svelte.d.ts +10 -3
- package/dist/components/Treemap.svelte +63 -26
- package/dist/components/Treemap.svelte.d.ts +21 -14
- package/dist/components/Voronoi.svelte +12 -13
- package/dist/components/charts/ArcChart.svelte +43 -71
- package/dist/components/charts/ArcChart.svelte.d.ts +10 -3
- package/dist/components/charts/AreaChart.svelte +29 -59
- package/dist/components/charts/AreaChart.svelte.d.ts +10 -3
- package/dist/components/charts/BarChart.svelte +79 -71
- package/dist/components/charts/BarChart.svelte.d.ts +10 -3
- package/dist/components/charts/DefaultTooltip.svelte +3 -3
- package/dist/components/charts/DefaultTooltip.svelte.d.ts +1 -1
- package/dist/components/charts/LineChart.svelte +69 -75
- package/dist/components/charts/LineChart.svelte.d.ts +21 -8
- package/dist/components/charts/PieChart.svelte +44 -71
- package/dist/components/charts/PieChart.svelte.d.ts +10 -3
- package/dist/components/charts/ScatterChart.svelte +10 -39
- package/dist/components/charts/ScatterChart.svelte.d.ts +10 -3
- package/dist/components/charts/utils.svelte.d.ts +1 -19
- package/dist/components/charts/utils.svelte.js +7 -35
- package/dist/components/index.d.ts +4 -0
- package/dist/components/index.js +5 -1
- package/dist/components/layout/Canvas.svelte +96 -69
- package/dist/components/layout/Canvas.svelte.d.ts +6 -0
- package/dist/components/layout/Html.svelte +15 -9
- package/dist/components/layout/Layer.svelte +6 -4
- package/dist/components/layout/Layer.svelte.d.ts +6 -4
- package/dist/components/layout/Svg.svelte +19 -11
- package/dist/components/layout/WebGL.svelte +26 -6
- package/dist/components/layout/WebGL.svelte.d.ts +5 -2
- package/dist/components/tooltip/Tooltip.svelte +73 -36
- package/dist/components/tooltip/Tooltip.svelte.d.ts +10 -3
- package/dist/components/tooltip/TooltipContext.svelte +167 -54
- package/dist/components/tooltip/TooltipContext.svelte.d.ts +19 -5
- package/dist/components/tooltip/TooltipHeader.svelte +32 -18
- package/dist/components/tooltip/TooltipHeader.svelte.d.ts +3 -3
- package/dist/components/tooltip/TooltipItem.svelte +46 -37
- package/dist/components/tooltip/TooltipItem.svelte.d.ts +3 -3
- package/dist/components/tooltip/TooltipList.svelte +12 -10
- package/dist/components/tooltip/TooltipSeparator.svelte +18 -10
- package/dist/components/tooltip/tooltipMetaContext.d.ts +2 -2
- package/dist/docs/Blockquote.svelte +6 -4
- package/dist/docs/Blockquote.svelte.d.ts +4 -19
- package/dist/docs/Code.svelte +70 -28
- package/dist/docs/Code.svelte.d.ts +9 -24
- package/dist/docs/Header1.svelte +4 -2
- package/dist/docs/Header1.svelte.d.ts +4 -28
- package/dist/docs/Json.svelte +11 -3
- package/dist/docs/Json.svelte.d.ts +9 -21
- package/dist/docs/Layout.svelte +10 -7
- package/dist/docs/Layout.svelte.d.ts +4 -19
- package/dist/docs/Link.svelte +7 -3
- package/dist/docs/Link.svelte.d.ts +4 -38
- package/dist/docs/Preview.svelte +22 -23
- package/dist/docs/Preview.svelte.d.ts +5 -6
- package/dist/docs/TilesetField.svelte +20 -19
- package/dist/docs/TilesetField.svelte.d.ts +5 -22
- package/dist/docs/ViewSourceButton.svelte +10 -7
- package/dist/docs/ViewSourceButton.svelte.d.ts +7 -21
- package/dist/states/series.svelte.d.ts +30 -0
- package/dist/states/series.svelte.js +54 -0
- package/dist/styles/daisyui-5.css +6 -0
- package/dist/styles/shadcn-svelte.css +11 -0
- package/dist/styles/skeleton-3.css +15 -0
- package/dist/utils/arcText.svelte.js +4 -4
- package/dist/utils/array.d.ts +11 -0
- package/dist/utils/array.js +23 -0
- package/dist/utils/array.test.d.ts +1 -0
- package/dist/utils/array.test.js +200 -0
- package/dist/utils/attributes.d.ts +3 -13
- package/dist/utils/attributes.js +4 -18
- package/dist/utils/canvas.d.ts +77 -0
- package/dist/utils/canvas.js +105 -41
- package/dist/utils/common.d.ts +9 -0
- package/dist/utils/common.js +18 -1
- package/dist/utils/common.test.js +26 -1
- package/dist/utils/genData.d.ts +22 -8
- package/dist/utils/genData.js +34 -14
- package/dist/utils/graph/dagre.d.ts +4 -4
- package/dist/utils/graph/dagre.js +5 -7
- package/dist/utils/index.d.ts +1 -0
- package/dist/utils/index.js +1 -0
- package/dist/utils/math.d.ts +17 -0
- package/dist/utils/math.js +17 -0
- package/dist/utils/motion.svelte.js +1 -1
- package/dist/utils/path.d.ts +10 -0
- package/dist/utils/path.js +30 -0
- package/dist/utils/rect.svelte.d.ts +2 -2
- package/dist/utils/rect.svelte.js +73 -1
- package/dist/utils/scales.svelte.d.ts +9 -3
- package/dist/utils/scales.svelte.js +47 -4
- package/dist/utils/shape.d.ts +43 -0
- package/dist/utils/shape.js +59 -0
- package/dist/utils/stack.js +1 -1
- package/dist/utils/string.d.ts +49 -0
- package/dist/utils/string.js +4 -2
- package/dist/utils/ticks.d.ts +15 -4
- package/dist/utils/ticks.js +140 -159
- package/dist/utils/ticks.test.js +16 -26
- package/dist/utils/treemap.d.ts +1 -1
- package/dist/utils/types.d.ts +15 -2
- package/package.json +36 -35
- package/dist/utils/object.js +0 -2
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
<script lang="ts" module>
|
|
2
|
+
import type { CommonStyleProps, Without } from '../utils/types.js';
|
|
3
|
+
|
|
4
|
+
export type EllipsePropsWithoutHTML = {
|
|
5
|
+
/**
|
|
6
|
+
* The center x position of the ellipse.
|
|
7
|
+
*
|
|
8
|
+
* @default 0
|
|
9
|
+
*/
|
|
10
|
+
cx?: number;
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* The initial center x position of the ellipse.
|
|
14
|
+
*
|
|
15
|
+
* @default cx
|
|
16
|
+
*/
|
|
17
|
+
initialCx?: number;
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* The center y position of the ellipse.
|
|
21
|
+
*
|
|
22
|
+
* @default 0
|
|
23
|
+
*/
|
|
24
|
+
cy?: number;
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* The initial center y position of the ellipse.
|
|
28
|
+
*
|
|
29
|
+
* @default cy
|
|
30
|
+
*/
|
|
31
|
+
initialCy?: number;
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* The radius of the ellipse on the x-axis.
|
|
35
|
+
*
|
|
36
|
+
* @default 1
|
|
37
|
+
*/
|
|
38
|
+
rx?: number;
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* The initial radius of the ellipse on the x-axis.
|
|
42
|
+
*
|
|
43
|
+
* @default rx
|
|
44
|
+
*/
|
|
45
|
+
initialRx?: number;
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* The radius of the ellipse on the y-axis.
|
|
49
|
+
*
|
|
50
|
+
* @default 1
|
|
51
|
+
*/
|
|
52
|
+
ry?: number;
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* The initial radius of the ellipse on the y-axis.
|
|
56
|
+
*
|
|
57
|
+
* @default ry
|
|
58
|
+
*/
|
|
59
|
+
initialRy?: number;
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* A bindable reference to the `<ellipse>` element
|
|
63
|
+
*
|
|
64
|
+
* @bindable
|
|
65
|
+
*/
|
|
66
|
+
ref?: SVGEllipseElement;
|
|
67
|
+
|
|
68
|
+
motion?: MotionProp;
|
|
69
|
+
} & CommonStyleProps;
|
|
70
|
+
|
|
71
|
+
export type EllipseProps = EllipsePropsWithoutHTML &
|
|
72
|
+
Without<SVGAttributes<Element>, EllipsePropsWithoutHTML>;
|
|
73
|
+
</script>
|
|
74
|
+
|
|
75
|
+
<script lang="ts">
|
|
76
|
+
import { cls } from '@layerstack/tailwind';
|
|
77
|
+
import { merge } from 'lodash-es';
|
|
78
|
+
|
|
79
|
+
import { getRenderContext } from './Chart.svelte';
|
|
80
|
+
import { createMotion, type MotionProp } from '../utils/motion.svelte.js';
|
|
81
|
+
import { registerCanvasComponent } from './layout/Canvas.svelte';
|
|
82
|
+
import { renderEllipse, type ComputedStylesOptions } from '../utils/canvas.js';
|
|
83
|
+
import type { SVGAttributes } from 'svelte/elements';
|
|
84
|
+
import { createKey } from '../utils/key.svelte.js';
|
|
85
|
+
|
|
86
|
+
let {
|
|
87
|
+
cx = 0,
|
|
88
|
+
initialCx: initialCxProp,
|
|
89
|
+
cy = 0,
|
|
90
|
+
initialCy: initialCyProp,
|
|
91
|
+
rx = 1,
|
|
92
|
+
initialRx: initialRxProp,
|
|
93
|
+
ry = 1,
|
|
94
|
+
initialRy: initialRyProp,
|
|
95
|
+
motion,
|
|
96
|
+
fill,
|
|
97
|
+
fillOpacity,
|
|
98
|
+
stroke,
|
|
99
|
+
strokeWidth,
|
|
100
|
+
opacity,
|
|
101
|
+
class: className,
|
|
102
|
+
ref: refProp = $bindable(),
|
|
103
|
+
...restProps
|
|
104
|
+
}: EllipseProps = $props();
|
|
105
|
+
|
|
106
|
+
let ref = $state<SVGEllipseElement>();
|
|
107
|
+
|
|
108
|
+
$effect.pre(() => {
|
|
109
|
+
refProp = ref;
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
const initialCx = initialCxProp ?? cx;
|
|
113
|
+
const initialCy = initialCyProp ?? cy;
|
|
114
|
+
const initialRx = initialRxProp ?? rx;
|
|
115
|
+
const initialRy = initialRyProp ?? ry;
|
|
116
|
+
|
|
117
|
+
const renderCtx = getRenderContext();
|
|
118
|
+
|
|
119
|
+
const motionCx = createMotion(initialCx, () => cx, motion);
|
|
120
|
+
const motionCy = createMotion(initialCy, () => cy, motion);
|
|
121
|
+
const motionRx = createMotion(initialRx, () => rx, motion);
|
|
122
|
+
const motionRy = createMotion(initialRy, () => ry, motion);
|
|
123
|
+
|
|
124
|
+
function render(
|
|
125
|
+
ctx: CanvasRenderingContext2D,
|
|
126
|
+
styleOverrides: ComputedStylesOptions | undefined
|
|
127
|
+
) {
|
|
128
|
+
renderEllipse(
|
|
129
|
+
ctx,
|
|
130
|
+
{ cx: motionCx.current, cy: motionCy.current, rx: motionRx.current, ry: motionRy.current },
|
|
131
|
+
styleOverrides
|
|
132
|
+
? merge({ styles: { strokeWidth } }, styleOverrides)
|
|
133
|
+
: {
|
|
134
|
+
styles: { fill, fillOpacity, stroke, strokeWidth, opacity },
|
|
135
|
+
classes: cls('lc-ellipse', className),
|
|
136
|
+
}
|
|
137
|
+
);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
// TODO: Use objectId to work around Svelte 4 reactivity issue (even when memoizing gradients)
|
|
141
|
+
const fillKey = createKey(() => fill);
|
|
142
|
+
const strokeKey = createKey(() => stroke);
|
|
143
|
+
|
|
144
|
+
if (renderCtx === 'canvas') {
|
|
145
|
+
registerCanvasComponent({
|
|
146
|
+
name: 'Ellipse',
|
|
147
|
+
render,
|
|
148
|
+
events: {
|
|
149
|
+
click: restProps.onclick,
|
|
150
|
+
pointerdown: restProps.onpointerdown,
|
|
151
|
+
pointerenter: restProps.onpointerenter,
|
|
152
|
+
pointermove: restProps.onpointermove,
|
|
153
|
+
pointerleave: restProps.onpointerleave,
|
|
154
|
+
},
|
|
155
|
+
deps: () => [
|
|
156
|
+
motionCx.current,
|
|
157
|
+
motionCy.current,
|
|
158
|
+
motionRx.current,
|
|
159
|
+
motionRy.current,
|
|
160
|
+
fillKey.current,
|
|
161
|
+
fillOpacity,
|
|
162
|
+
strokeKey.current,
|
|
163
|
+
strokeWidth,
|
|
164
|
+
opacity,
|
|
165
|
+
className,
|
|
166
|
+
],
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
</script>
|
|
170
|
+
|
|
171
|
+
{#if renderCtx === 'svg'}
|
|
172
|
+
<ellipse
|
|
173
|
+
bind:this={ref}
|
|
174
|
+
cx={motionCx.current}
|
|
175
|
+
cy={motionCy.current}
|
|
176
|
+
rx={motionRx.current}
|
|
177
|
+
ry={motionRy.current}
|
|
178
|
+
{fill}
|
|
179
|
+
fill-opacity={fillOpacity}
|
|
180
|
+
{stroke}
|
|
181
|
+
stroke-width={strokeWidth}
|
|
182
|
+
{opacity}
|
|
183
|
+
class={cls('lc-ellipse', className)}
|
|
184
|
+
{...restProps}
|
|
185
|
+
/>
|
|
186
|
+
{:else if renderCtx === 'html'}
|
|
187
|
+
<div
|
|
188
|
+
style:position="absolute"
|
|
189
|
+
style:left="{motionCx.current}px"
|
|
190
|
+
style:top="{motionCy.current}px"
|
|
191
|
+
style:width="{motionRx.current * 2}px"
|
|
192
|
+
style:height="{motionRy.current * 2}px"
|
|
193
|
+
style:border-radius="50%"
|
|
194
|
+
style:background-color={fill}
|
|
195
|
+
style:opacity
|
|
196
|
+
style:border-width={strokeWidth}
|
|
197
|
+
style:border-color={stroke}
|
|
198
|
+
style:border-style="solid"
|
|
199
|
+
style:transform="translate(-50%, -50%)"
|
|
200
|
+
class={cls('lc-ellipse', className)}
|
|
201
|
+
{...restProps}
|
|
202
|
+
></div>
|
|
203
|
+
{/if}
|
|
204
|
+
|
|
205
|
+
<style>
|
|
206
|
+
@layer base {
|
|
207
|
+
:global(:where(.lc-ellipse)) {
|
|
208
|
+
--fill-color: var(--color-surface-content, currentColor);
|
|
209
|
+
--stroke-color: initial;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
/* Svg | Canvas layers */
|
|
213
|
+
:global(:where(.lc-layout-svg .lc-ellipse, svg.lc-ellipse):not([fill])) {
|
|
214
|
+
fill: var(--fill-color);
|
|
215
|
+
}
|
|
216
|
+
:global(:where(.lc-layout-svg .lc-ellipse, svg.lc-ellipse):not([stroke])) {
|
|
217
|
+
stroke: var(--stroke-color);
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
/* Html layers */
|
|
221
|
+
:global(:where(.lc-layout-html .lc-ellipse):not([background-color])) {
|
|
222
|
+
background-color: var(--fill-color);
|
|
223
|
+
}
|
|
224
|
+
:global(:where(.lc-layout-html .lc-ellipse):not([border-color])) {
|
|
225
|
+
border-color: var(--stroke-color);
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
</style>
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import type { CommonStyleProps, Without } from '../utils/types.js';
|
|
2
|
+
export type EllipsePropsWithoutHTML = {
|
|
3
|
+
/**
|
|
4
|
+
* The center x position of the ellipse.
|
|
5
|
+
*
|
|
6
|
+
* @default 0
|
|
7
|
+
*/
|
|
8
|
+
cx?: number;
|
|
9
|
+
/**
|
|
10
|
+
* The initial center x position of the ellipse.
|
|
11
|
+
*
|
|
12
|
+
* @default cx
|
|
13
|
+
*/
|
|
14
|
+
initialCx?: number;
|
|
15
|
+
/**
|
|
16
|
+
* The center y position of the ellipse.
|
|
17
|
+
*
|
|
18
|
+
* @default 0
|
|
19
|
+
*/
|
|
20
|
+
cy?: number;
|
|
21
|
+
/**
|
|
22
|
+
* The initial center y position of the ellipse.
|
|
23
|
+
*
|
|
24
|
+
* @default cy
|
|
25
|
+
*/
|
|
26
|
+
initialCy?: number;
|
|
27
|
+
/**
|
|
28
|
+
* The radius of the ellipse on the x-axis.
|
|
29
|
+
*
|
|
30
|
+
* @default 1
|
|
31
|
+
*/
|
|
32
|
+
rx?: number;
|
|
33
|
+
/**
|
|
34
|
+
* The initial radius of the ellipse on the x-axis.
|
|
35
|
+
*
|
|
36
|
+
* @default rx
|
|
37
|
+
*/
|
|
38
|
+
initialRx?: number;
|
|
39
|
+
/**
|
|
40
|
+
* The radius of the ellipse on the y-axis.
|
|
41
|
+
*
|
|
42
|
+
* @default 1
|
|
43
|
+
*/
|
|
44
|
+
ry?: number;
|
|
45
|
+
/**
|
|
46
|
+
* The initial radius of the ellipse on the y-axis.
|
|
47
|
+
*
|
|
48
|
+
* @default ry
|
|
49
|
+
*/
|
|
50
|
+
initialRy?: number;
|
|
51
|
+
/**
|
|
52
|
+
* A bindable reference to the `<ellipse>` element
|
|
53
|
+
*
|
|
54
|
+
* @bindable
|
|
55
|
+
*/
|
|
56
|
+
ref?: SVGEllipseElement;
|
|
57
|
+
motion?: MotionProp;
|
|
58
|
+
} & CommonStyleProps;
|
|
59
|
+
export type EllipseProps = EllipsePropsWithoutHTML & Without<SVGAttributes<Element>, EllipsePropsWithoutHTML>;
|
|
60
|
+
import { type MotionProp } from '../utils/motion.svelte.js';
|
|
61
|
+
import type { SVGAttributes } from 'svelte/elements';
|
|
62
|
+
declare const Ellipse: import("svelte").Component<EllipseProps, {}, "ref">;
|
|
63
|
+
type Ellipse = ReturnType<typeof Ellipse>;
|
|
64
|
+
export default Ellipse;
|
|
@@ -1,8 +1,22 @@
|
|
|
1
1
|
<script lang="ts" module>
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
forceSimulation,
|
|
4
|
+
type Force,
|
|
5
|
+
type Simulation,
|
|
6
|
+
type SimulationLinkDatum,
|
|
7
|
+
type SimulationNodeDatum,
|
|
8
|
+
} from 'd3-force';
|
|
3
9
|
import type { Snippet } from 'svelte';
|
|
4
10
|
|
|
5
|
-
type Forces
|
|
11
|
+
export type Forces<
|
|
12
|
+
NodeDatum extends SimulationNodeDatum,
|
|
13
|
+
LinkDatum extends SimulationLinkDatum<NodeDatum> | undefined,
|
|
14
|
+
> = Record<string, Force<NodeDatum, LinkDatum>>;
|
|
15
|
+
|
|
16
|
+
export type Data<TNode = any, TLink = any> = {
|
|
17
|
+
nodes: TNode[];
|
|
18
|
+
links?: TLink[];
|
|
19
|
+
};
|
|
6
20
|
|
|
7
21
|
export type LinkPosition = {
|
|
8
22
|
x1: number;
|
|
@@ -11,44 +25,115 @@
|
|
|
11
25
|
y2: number;
|
|
12
26
|
};
|
|
13
27
|
|
|
14
|
-
export type
|
|
28
|
+
export type OnStartEvent<
|
|
29
|
+
NodeDatum extends SimulationNodeDatum,
|
|
30
|
+
LinkDatum extends SimulationLinkDatum<NodeDatum> | undefined,
|
|
31
|
+
> = {
|
|
32
|
+
alpha: number;
|
|
33
|
+
alphaTarget: number;
|
|
34
|
+
simulation: Simulation<NodeDatum, LinkDatum>;
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
export type OnTickEvent<
|
|
38
|
+
NodeDatum extends SimulationNodeDatum,
|
|
39
|
+
LinkDatum extends SimulationLinkDatum<NodeDatum> | undefined,
|
|
40
|
+
> = {
|
|
41
|
+
alpha: number;
|
|
42
|
+
alphaTarget: number;
|
|
43
|
+
nodes: NodeDatum[];
|
|
44
|
+
links: LinkDatum[];
|
|
45
|
+
simulation: Simulation<NodeDatum, LinkDatum>;
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
export type OnEndEvent<
|
|
49
|
+
NodeDatum extends SimulationNodeDatum,
|
|
50
|
+
LinkDatum extends SimulationLinkDatum<NodeDatum> | undefined,
|
|
51
|
+
> = {
|
|
52
|
+
alpha: number;
|
|
53
|
+
alphaTarget: number;
|
|
54
|
+
simulation: Simulation<NodeDatum, LinkDatum>;
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
export type OnNodesChangeEvent<
|
|
58
|
+
NodeDatum extends SimulationNodeDatum,
|
|
59
|
+
LinkDatum extends SimulationLinkDatum<NodeDatum> | undefined,
|
|
60
|
+
> = {
|
|
61
|
+
alpha: number;
|
|
62
|
+
alphaTarget: number;
|
|
63
|
+
nodes: NodeDatum[];
|
|
64
|
+
links: LinkDatum[];
|
|
65
|
+
simulation: Simulation<NodeDatum, LinkDatum>;
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Default initial alpha value of the simulation.
|
|
70
|
+
*/
|
|
71
|
+
export const DEFAULT_ALPHA: number = 1;
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Default target alpha value for the simulation.
|
|
75
|
+
*/
|
|
76
|
+
export const DEFAULT_ALPHA_TARGET: number = 0;
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Default alpha decay rate per tick.
|
|
80
|
+
*
|
|
81
|
+
* Formula: `1 - Math.pow(0.001, 1 / 300)`.
|
|
82
|
+
*/
|
|
83
|
+
export const DEFAULT_ALPHA_DECAY: number = 1 - Math.pow(0.001, 1 / 300);
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Default minimum alpha value at which simulation stops.
|
|
87
|
+
*/
|
|
88
|
+
export const DEFAULT_ALPHA_MIN: number = 0.01;
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Default velocity decay factor applied to nodes each tick.
|
|
92
|
+
*/
|
|
93
|
+
export const DEFAULT_VELOCITY_DECAY: number = 0.4;
|
|
94
|
+
|
|
95
|
+
export type ForceSimulationProps<
|
|
96
|
+
NodeDatum extends SimulationNodeDatum,
|
|
97
|
+
LinkDatum extends SimulationLinkDatum<NodeDatum> | undefined,
|
|
98
|
+
> = {
|
|
15
99
|
/**
|
|
16
100
|
* Force simulation parameters
|
|
17
101
|
*/
|
|
18
|
-
forces: Forces
|
|
102
|
+
forces: Forces<NodeDatum, LinkDatum>;
|
|
19
103
|
|
|
20
104
|
/**
|
|
21
|
-
* An
|
|
105
|
+
* An object with arrays of nodes and links,
|
|
106
|
+
* to be used for position calculation.
|
|
22
107
|
*/
|
|
23
|
-
|
|
108
|
+
data: Data<NodeDatum, LinkDatum>;
|
|
24
109
|
|
|
25
110
|
/**
|
|
26
111
|
* Current alpha value of the simulation
|
|
27
|
-
* @default
|
|
112
|
+
* @default DEFAULT_ALPHA
|
|
28
113
|
*/
|
|
29
114
|
alpha?: number;
|
|
30
115
|
|
|
31
116
|
/**
|
|
32
117
|
* Target alpha value for the simulation
|
|
33
|
-
* @default
|
|
118
|
+
* @default DEFAULT_ALPHA_TARGET
|
|
34
119
|
*/
|
|
35
120
|
alphaTarget?: number;
|
|
36
121
|
|
|
37
122
|
/**
|
|
38
123
|
* Alpha decay rate per tick
|
|
39
|
-
* @default
|
|
124
|
+
* @default DEFAULT_ALPHA_DECAY
|
|
40
125
|
*/
|
|
41
126
|
alphaDecay?: number;
|
|
42
127
|
|
|
43
128
|
/**
|
|
44
129
|
* Minimum alpha value at which simulation stops
|
|
45
|
-
* @default
|
|
130
|
+
* @default DEFAULT_ALPHA_MIN
|
|
46
131
|
*/
|
|
47
132
|
alphaMin?: number;
|
|
48
133
|
|
|
49
134
|
/**
|
|
50
135
|
* Velocity decay factor applied to nodes each tick
|
|
51
|
-
* @default
|
|
136
|
+
* @default DEFAULT_VELOCITY_DECAY
|
|
52
137
|
*/
|
|
53
138
|
velocityDecay?: number;
|
|
54
139
|
|
|
@@ -73,65 +158,78 @@
|
|
|
73
158
|
/**
|
|
74
159
|
* Callback function triggered when simulation starts
|
|
75
160
|
*/
|
|
76
|
-
onStart?: () => void;
|
|
161
|
+
onStart?: (e: OnStartEvent<NodeDatum, LinkDatum | undefined>) => void;
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* Callback function triggered right before nodes get passed to the simulation
|
|
165
|
+
*/
|
|
166
|
+
onNodesChange?: (e: OnNodesChangeEvent<NodeDatum, LinkDatum | undefined>) => void;
|
|
77
167
|
|
|
78
168
|
/**
|
|
79
169
|
* Callback function triggered on each simulation tick
|
|
80
170
|
*/
|
|
81
|
-
onTick?: (e:
|
|
171
|
+
onTick?: (e: OnTickEvent<NodeDatum, LinkDatum | undefined>) => void;
|
|
82
172
|
|
|
83
173
|
/**
|
|
84
174
|
* Callback function triggered when simulation ends
|
|
85
175
|
*/
|
|
86
|
-
onEnd?: () => void;
|
|
176
|
+
onEnd?: (e: OnEndEvent<NodeDatum, LinkDatum | undefined>) => void;
|
|
87
177
|
|
|
88
178
|
children?: Snippet<
|
|
89
179
|
[
|
|
90
180
|
{
|
|
91
|
-
nodes:
|
|
92
|
-
|
|
181
|
+
nodes: NodeDatum[];
|
|
182
|
+
links: LinkDatum[];
|
|
93
183
|
linkPositions: LinkPosition[];
|
|
184
|
+
simulation: Simulation<NodeDatum, LinkDatum>;
|
|
94
185
|
},
|
|
95
186
|
]
|
|
96
187
|
>;
|
|
97
188
|
};
|
|
98
189
|
</script>
|
|
99
190
|
|
|
100
|
-
<script
|
|
101
|
-
|
|
191
|
+
<script
|
|
192
|
+
lang="ts"
|
|
193
|
+
generics="NodeDatum extends SimulationNodeDatum,
|
|
194
|
+
LinkDatum extends SimulationLinkDatum<NodeDatum> | undefined,"
|
|
195
|
+
>
|
|
102
196
|
import { watch } from 'runed';
|
|
103
197
|
|
|
104
198
|
let {
|
|
105
199
|
forces,
|
|
106
|
-
|
|
107
|
-
alpha = $bindable(
|
|
108
|
-
alphaTarget =
|
|
109
|
-
alphaDecay =
|
|
110
|
-
alphaMin =
|
|
111
|
-
velocityDecay =
|
|
200
|
+
data,
|
|
201
|
+
alpha = $bindable(DEFAULT_ALPHA),
|
|
202
|
+
alphaTarget = DEFAULT_ALPHA_TARGET,
|
|
203
|
+
alphaDecay = DEFAULT_ALPHA_DECAY,
|
|
204
|
+
alphaMin = DEFAULT_ALPHA_MIN,
|
|
205
|
+
velocityDecay = DEFAULT_VELOCITY_DECAY,
|
|
112
206
|
stopped = false,
|
|
113
207
|
static: staticProp,
|
|
114
|
-
onStart: onStartProp
|
|
115
|
-
|
|
116
|
-
|
|
208
|
+
onStart: onStartProp,
|
|
209
|
+
onNodesChange: onNodesChangeProp,
|
|
210
|
+
onTick: onTickProp,
|
|
211
|
+
onEnd: onEndProp,
|
|
117
212
|
children,
|
|
118
213
|
cloneNodes = false,
|
|
119
|
-
}: ForceSimulationProps = $props();
|
|
120
|
-
|
|
121
|
-
const ctx = getChartContext();
|
|
214
|
+
}: ForceSimulationProps<NodeDatum, LinkDatum> = $props();
|
|
122
215
|
|
|
123
216
|
// MARK: Public Props
|
|
124
217
|
|
|
125
218
|
// MARK: Private Props
|
|
126
219
|
|
|
127
|
-
let nodes: SimulationNodeDatum[] = $state([]);
|
|
128
220
|
let linkPositions: LinkPosition[] = $state([]);
|
|
221
|
+
let simulatedNodes: NodeDatum[] = $state([]);
|
|
222
|
+
let simulatedLinks: LinkDatum[] = $derived(data.links ?? []);
|
|
129
223
|
|
|
130
|
-
|
|
224
|
+
// This casting is unfortunately necessary, due to unfortunate
|
|
225
|
+
// overloading choices made, over at `@typed/d3-force`:
|
|
226
|
+
const simulation: Simulation<NodeDatum, LinkDatum> = (
|
|
227
|
+
forceSimulation<NodeDatum>() as Simulation<NodeDatum, LinkDatum>
|
|
228
|
+
).stop();
|
|
131
229
|
|
|
132
230
|
// d3.Simulation does not provide a `.forces()` getter, so we need to
|
|
133
231
|
// keep track of previous forces ourselves, for diffing against `forces`.
|
|
134
|
-
let previousForces: Forces = {};
|
|
232
|
+
let previousForces: Forces<NodeDatum, LinkDatum> = {};
|
|
135
233
|
|
|
136
234
|
let paused: boolean = true;
|
|
137
235
|
|
|
@@ -166,11 +264,12 @@
|
|
|
166
264
|
);
|
|
167
265
|
|
|
168
266
|
watch.pre(
|
|
169
|
-
() =>
|
|
267
|
+
() => data,
|
|
170
268
|
() => {
|
|
171
|
-
// Any time the `data` store gets changed
|
|
172
|
-
// pass them to the internal d3 simulation object:
|
|
173
|
-
|
|
269
|
+
// Any time the `nodes` prop, or the `data` store gets changed
|
|
270
|
+
// we pass them to the internal d3 simulation object:
|
|
271
|
+
onNodesChange();
|
|
272
|
+
pushNodesToSimulation(data.nodes);
|
|
174
273
|
runOrResumeSimulation();
|
|
175
274
|
}
|
|
176
275
|
);
|
|
@@ -192,12 +291,8 @@
|
|
|
192
291
|
// pass it to the internal d3 simulation object:
|
|
193
292
|
pushAlphaToSimulation(alpha);
|
|
194
293
|
|
|
195
|
-
//
|
|
196
|
-
|
|
197
|
-
// otherwise our simulation will never terminate:
|
|
198
|
-
if (simulation.alpha() >= simulation.alphaMin()) {
|
|
199
|
-
runOrResumeSimulation();
|
|
200
|
-
}
|
|
294
|
+
// Then we attempt to resume the simulation:
|
|
295
|
+
runOrResumeSimulation();
|
|
201
296
|
}
|
|
202
297
|
);
|
|
203
298
|
|
|
@@ -235,7 +330,7 @@
|
|
|
235
330
|
simulation.nodes(nodes);
|
|
236
331
|
}
|
|
237
332
|
|
|
238
|
-
function pushForcesToSimulation(forces: Forces) {
|
|
333
|
+
function pushForcesToSimulation(forces: Forces<NodeDatum, LinkDatum>) {
|
|
239
334
|
// Evict obsolete forces:
|
|
240
335
|
const names = Object.keys(previousForces);
|
|
241
336
|
for (const name of names) {
|
|
@@ -259,7 +354,7 @@
|
|
|
259
354
|
// Keeping the link positions in sync with the simulation
|
|
260
355
|
// so we don't need to recalculate _all_ link positions on each tick
|
|
261
356
|
// which bogs down the simulation
|
|
262
|
-
linkPositions =
|
|
357
|
+
linkPositions = simulatedLinks.map((link: any) => ({
|
|
263
358
|
x1: link.source.x ?? 0,
|
|
264
359
|
y1: link.source.y ?? 0,
|
|
265
360
|
x2: link.target.x ?? 0,
|
|
@@ -270,7 +365,8 @@
|
|
|
270
365
|
// MARK: Pull State
|
|
271
366
|
|
|
272
367
|
function pullNodesFromSimulation() {
|
|
273
|
-
|
|
368
|
+
const simulationNodes = simulation.nodes();
|
|
369
|
+
simulatedNodes = cloneNodes ? structuredClone(simulationNodes) : simulationNodes;
|
|
274
370
|
}
|
|
275
371
|
|
|
276
372
|
function pullAlphaFromSimulation() {
|
|
@@ -337,6 +433,13 @@
|
|
|
337
433
|
return;
|
|
338
434
|
}
|
|
339
435
|
|
|
436
|
+
if (simulation.alpha() < simulation.alphaMin()) {
|
|
437
|
+
// Only resume the simulation as long as `alpha`
|
|
438
|
+
// is above the cut-off threshold of `alphaMin`,
|
|
439
|
+
// otherwise our simulation will never terminate:
|
|
440
|
+
return;
|
|
441
|
+
}
|
|
442
|
+
|
|
340
443
|
onStart();
|
|
341
444
|
simulation.restart();
|
|
342
445
|
|
|
@@ -364,7 +467,12 @@
|
|
|
364
467
|
}
|
|
365
468
|
|
|
366
469
|
paused = false;
|
|
367
|
-
|
|
470
|
+
|
|
471
|
+
onStartProp?.({
|
|
472
|
+
alpha,
|
|
473
|
+
alphaTarget,
|
|
474
|
+
simulation,
|
|
475
|
+
});
|
|
368
476
|
}
|
|
369
477
|
|
|
370
478
|
function onTick() {
|
|
@@ -372,7 +480,13 @@
|
|
|
372
480
|
pullAlphaFromSimulation();
|
|
373
481
|
updateLinkPositions();
|
|
374
482
|
|
|
375
|
-
onTickProp({
|
|
483
|
+
onTickProp?.({
|
|
484
|
+
alpha,
|
|
485
|
+
alphaTarget,
|
|
486
|
+
nodes: simulatedNodes,
|
|
487
|
+
links: simulatedLinks,
|
|
488
|
+
simulation,
|
|
489
|
+
});
|
|
376
490
|
}
|
|
377
491
|
|
|
378
492
|
function onEnd() {
|
|
@@ -382,7 +496,22 @@
|
|
|
382
496
|
}
|
|
383
497
|
|
|
384
498
|
paused = true;
|
|
385
|
-
|
|
499
|
+
|
|
500
|
+
onEndProp?.({
|
|
501
|
+
alpha,
|
|
502
|
+
alphaTarget,
|
|
503
|
+
simulation,
|
|
504
|
+
});
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
function onNodesChange() {
|
|
508
|
+
onNodesChangeProp?.({
|
|
509
|
+
alpha,
|
|
510
|
+
alphaTarget,
|
|
511
|
+
nodes: data.nodes,
|
|
512
|
+
links: data.links ?? [],
|
|
513
|
+
simulation,
|
|
514
|
+
});
|
|
386
515
|
}
|
|
387
516
|
|
|
388
517
|
$effect(() => {
|
|
@@ -393,4 +522,9 @@
|
|
|
393
522
|
});
|
|
394
523
|
</script>
|
|
395
524
|
|
|
396
|
-
{@render children?.({
|
|
525
|
+
{@render children?.({
|
|
526
|
+
nodes: simulatedNodes,
|
|
527
|
+
links: simulatedLinks,
|
|
528
|
+
simulation,
|
|
529
|
+
linkPositions,
|
|
530
|
+
})}
|