layerchart 0.60.2 → 0.70.0
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/Arc.svelte +83 -27
- package/dist/components/Area.svelte +51 -12
- package/dist/components/Bar.svelte +5 -1
- package/dist/components/Circle.svelte +54 -12
- package/dist/components/ComputedStyles.svelte +16 -0
- package/dist/components/ComputedStyles.svelte.d.ts +20 -0
- package/dist/components/GeoPath.svelte +36 -44
- package/dist/components/GeoPath.svelte.d.ts +2 -2
- package/dist/components/GeoPoint.svelte +27 -13
- package/dist/components/GeoTile.svelte +22 -7
- package/dist/components/Graticule.svelte.d.ts +4 -4
- package/dist/components/Group.svelte +46 -18
- package/dist/components/HitCanvas.svelte +7 -21
- package/dist/components/Legend.svelte.d.ts +1 -1
- package/dist/components/Line.svelte +70 -31
- package/dist/components/LinearGradient.svelte +89 -26
- package/dist/components/LinearGradient.svelte.d.ts +2 -2
- package/dist/components/Points.svelte +23 -41
- package/dist/components/Points.svelte.d.ts +2 -1
- package/dist/components/RadialGradient.svelte +86 -28
- package/dist/components/RadialGradient.svelte.d.ts +2 -2
- package/dist/components/Rect.svelte +62 -18
- package/dist/components/Rule.svelte +1 -1
- package/dist/components/Spline.svelte +95 -57
- package/dist/components/Text.svelte +80 -22
- package/dist/components/TransformControls.svelte.d.ts +1 -1
- package/dist/components/charts/AreaChart.svelte +14 -10
- package/dist/components/charts/BarChart.svelte +13 -9
- package/dist/components/charts/LineChart.svelte +13 -9
- package/dist/components/charts/PieChart.svelte +6 -2
- package/dist/components/charts/PieChart.svelte.d.ts +2 -1
- package/dist/components/charts/ScatterChart.svelte +14 -10
- package/dist/components/layout/Canvas.svelte +93 -11
- package/dist/components/layout/Canvas.svelte.d.ts +13 -0
- package/dist/components/layout/Svg.svelte +1 -1
- package/dist/components/tooltip/Tooltip.svelte.d.ts +1 -1
- package/dist/utils/canvas.d.ts +46 -0
- package/dist/utils/canvas.js +146 -0
- package/dist/utils/common.d.ts +10 -1
- package/dist/utils/common.js +13 -0
- package/dist/utils/index.d.ts +2 -0
- package/dist/utils/index.js +2 -0
- package/dist/utils/math.d.ts +2 -0
- package/dist/utils/math.js +10 -0
- package/dist/utils/path.d.ts +7 -0
- package/dist/utils/path.js +17 -3
- package/package.json +3 -4
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
+
import { onDestroy } from 'svelte';
|
|
2
3
|
import { uniqueId } from '@layerstack/utils';
|
|
3
4
|
|
|
5
|
+
import { chartContext } from './ChartContext.svelte';
|
|
6
|
+
import { getCanvasContext } from './layout/Canvas.svelte';
|
|
7
|
+
import { getComputedStyles } from '../utils/canvas.js';
|
|
8
|
+
import { parsePercent } from '../utils/math.js';
|
|
9
|
+
|
|
4
10
|
/** Unique id for linearGradient */
|
|
5
11
|
export let id: string = uniqueId('radialGradient-');
|
|
6
12
|
|
|
@@ -25,33 +31,85 @@
|
|
|
25
31
|
|
|
26
32
|
/** Define the coordinate system for attributes (i.e. gradientUnits) */
|
|
27
33
|
export let units: 'objectBoundingBox' | 'userSpaceOnUse' = 'objectBoundingBox';
|
|
34
|
+
|
|
35
|
+
const { width, height, padding } = chartContext();
|
|
36
|
+
|
|
37
|
+
const canvasContext = getCanvasContext();
|
|
38
|
+
const renderContext = canvasContext ? 'canvas' : 'svg';
|
|
39
|
+
|
|
40
|
+
let canvasGradient: CanvasGradient;
|
|
41
|
+
|
|
42
|
+
function render(ctx: CanvasRenderingContext2D) {
|
|
43
|
+
// TODO: Set correct values: https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/createRadialGradient. See also: LinearGradient
|
|
44
|
+
const gradient = ctx.createRadialGradient(0, 0, 0, 0, 0, 0);
|
|
45
|
+
|
|
46
|
+
// Use `getComputedStyles()` to convert each stop (if using CSS variables and/or classes) to color values
|
|
47
|
+
stops.forEach((stop, i) => {
|
|
48
|
+
if (Array.isArray(stop)) {
|
|
49
|
+
const { fill } = getComputedStyles(ctx.canvas, {
|
|
50
|
+
styles: { fill: stop[1] },
|
|
51
|
+
classes: $$props.class,
|
|
52
|
+
});
|
|
53
|
+
gradient.addColorStop(parsePercent(stop[0]), fill);
|
|
54
|
+
} else {
|
|
55
|
+
const { fill } = getComputedStyles(ctx.canvas, {
|
|
56
|
+
styles: { fill: stop },
|
|
57
|
+
classes: $$props.class,
|
|
58
|
+
});
|
|
59
|
+
gradient.addColorStop(i / (stops.length - 1), fill);
|
|
60
|
+
}
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
canvasGradient = gradient;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
let canvasUnregister: ReturnType<typeof canvasContext.register>;
|
|
67
|
+
$: if (renderContext === 'canvas') {
|
|
68
|
+
canvasUnregister = canvasContext.register({ name: 'Gradient', render });
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
$: if (renderContext === 'canvas') {
|
|
72
|
+
// Redraw when props changes (TODO: styles, class, etc)
|
|
73
|
+
stops && cx && cy && fx && fy && $width && $height;
|
|
74
|
+
canvasContext.invalidate();
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
onDestroy(() => {
|
|
78
|
+
if (renderContext === 'canvas') {
|
|
79
|
+
canvasUnregister();
|
|
80
|
+
}
|
|
81
|
+
});
|
|
28
82
|
</script>
|
|
29
83
|
|
|
30
|
-
|
|
31
|
-
<
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
{
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
{
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
84
|
+
{#if renderContext === 'canvas'}
|
|
85
|
+
<slot {id} gradient={canvasGradient} />
|
|
86
|
+
{:else if renderContext === 'svg'}
|
|
87
|
+
<defs>
|
|
88
|
+
<radialGradient
|
|
89
|
+
{id}
|
|
90
|
+
{cx}
|
|
91
|
+
{cy}
|
|
92
|
+
{fx}
|
|
93
|
+
{fy}
|
|
94
|
+
{r}
|
|
95
|
+
{spreadMethod}
|
|
96
|
+
gradientTransform={transform}
|
|
97
|
+
gradientUnits={units}
|
|
98
|
+
{...$$restProps}
|
|
99
|
+
>
|
|
100
|
+
<slot name="stops">
|
|
101
|
+
{#if stops}
|
|
102
|
+
{#each stops as stop, i}
|
|
103
|
+
{#if Array.isArray(stop)}
|
|
104
|
+
<stop offset={stop[0]} stop-color={stop[1]} />
|
|
105
|
+
{:else}
|
|
106
|
+
<stop offset="{i * (100 / (stops.length - 1))}%" stop-color={stop} />
|
|
107
|
+
{/if}
|
|
108
|
+
{/each}
|
|
109
|
+
{/if}
|
|
110
|
+
</slot>
|
|
111
|
+
</radialGradient>
|
|
112
|
+
</defs>
|
|
113
|
+
|
|
114
|
+
<slot {id} gradient="url(#{id})" />
|
|
115
|
+
{/if}
|
|
@@ -17,11 +17,11 @@ declare const __propDef: {
|
|
|
17
17
|
[evt: string]: CustomEvent<any>;
|
|
18
18
|
};
|
|
19
19
|
slots: {
|
|
20
|
-
stops: {};
|
|
21
20
|
default: {
|
|
22
21
|
id: string;
|
|
23
|
-
|
|
22
|
+
gradient: string;
|
|
24
23
|
};
|
|
24
|
+
stops: {};
|
|
25
25
|
};
|
|
26
26
|
};
|
|
27
27
|
export type RadialGradientProps = typeof __propDef.props;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
-
import { tick } from 'svelte';
|
|
2
|
+
import { onDestroy, tick } from 'svelte';
|
|
3
3
|
import { cls } from '@layerstack/tailwind';
|
|
4
4
|
|
|
5
5
|
import {
|
|
@@ -8,6 +8,8 @@
|
|
|
8
8
|
type SpringOptions,
|
|
9
9
|
type TweenedOptions,
|
|
10
10
|
} from '../stores/motionStore.js';
|
|
11
|
+
import { getCanvasContext } from './layout/Canvas.svelte';
|
|
12
|
+
import { renderRect } from '../index.js/utils/canvas.js';
|
|
11
13
|
|
|
12
14
|
export let x = 0;
|
|
13
15
|
export let initialX = x;
|
|
@@ -21,6 +23,11 @@
|
|
|
21
23
|
export let height: number;
|
|
22
24
|
export let initialHeight = height;
|
|
23
25
|
|
|
26
|
+
export let fill: string | undefined = undefined;
|
|
27
|
+
export let fillOpacity: number | undefined = undefined;
|
|
28
|
+
export let stroke: string | undefined = undefined;
|
|
29
|
+
export let strokeWidth: number | undefined = undefined;
|
|
30
|
+
|
|
24
31
|
export let spring: boolean | SpringOptions | { [prop: string]: SpringOptions } = undefined;
|
|
25
32
|
export let tweened: boolean | TweenedOptions | { [prop: string]: TweenedOptions } = undefined;
|
|
26
33
|
|
|
@@ -35,22 +42,59 @@
|
|
|
35
42
|
tweened_width.set(width);
|
|
36
43
|
tweened_height.set(height);
|
|
37
44
|
});
|
|
45
|
+
|
|
46
|
+
const canvasContext = getCanvasContext();
|
|
47
|
+
const renderContext = canvasContext ? 'canvas' : 'svg';
|
|
48
|
+
|
|
49
|
+
function render(ctx: CanvasRenderingContext2D) {
|
|
50
|
+
renderRect(
|
|
51
|
+
ctx,
|
|
52
|
+
{ x: $tweened_x, y: $tweened_y, width: $tweened_width, height: $tweened_height },
|
|
53
|
+
{
|
|
54
|
+
styles: { fill, fillOpacity, stroke, strokeWidth },
|
|
55
|
+
classes: $$props.class,
|
|
56
|
+
}
|
|
57
|
+
);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
let canvasUnregister: ReturnType<typeof canvasContext.register>;
|
|
61
|
+
$: if (renderContext === 'canvas') {
|
|
62
|
+
canvasUnregister = canvasContext.register({ name: 'Rect', render });
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
$: if (renderContext === 'canvas') {
|
|
66
|
+
// Redraw when props changes (TODO: styles, class, etc)
|
|
67
|
+
$tweened_x && $tweened_y && $tweened_width && $tweened_height;
|
|
68
|
+
canvasContext.invalidate();
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
onDestroy(() => {
|
|
72
|
+
if (renderContext === 'canvas') {
|
|
73
|
+
canvasUnregister();
|
|
74
|
+
}
|
|
75
|
+
});
|
|
38
76
|
</script>
|
|
39
77
|
|
|
40
|
-
|
|
41
|
-
<!-- svelte-ignore a11y-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
78
|
+
{#if renderContext === 'svg'}
|
|
79
|
+
<!-- svelte-ignore a11y-mouse-events-have-key-events -->
|
|
80
|
+
<!-- svelte-ignore a11y-no-static-element-interactions -->
|
|
81
|
+
<rect
|
|
82
|
+
x={$tweened_x}
|
|
83
|
+
y={$tweened_y}
|
|
84
|
+
width={$tweened_width}
|
|
85
|
+
height={$tweened_height}
|
|
86
|
+
class={cls($$props.fill == null && 'fill-surface-content')}
|
|
87
|
+
{fill}
|
|
88
|
+
fill-opacity={fillOpacity}
|
|
89
|
+
{stroke}
|
|
90
|
+
stroke-width={strokeWidth}
|
|
91
|
+
{...$$restProps}
|
|
92
|
+
on:click
|
|
93
|
+
on:pointerenter
|
|
94
|
+
on:pointerover
|
|
95
|
+
on:pointermove
|
|
96
|
+
on:pointerout
|
|
97
|
+
on:pointerleave
|
|
98
|
+
on:dblclick
|
|
99
|
+
/>
|
|
100
|
+
{/if}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
-
import { tick, type ComponentProps } from 'svelte';
|
|
2
|
+
import { onDestroy, tick, type ComponentProps } from 'svelte';
|
|
3
3
|
import { writable } from 'svelte/store';
|
|
4
4
|
import { tweened as tweenedStore } from 'svelte/motion';
|
|
5
5
|
import { draw as _drawTransition } from 'svelte/transition';
|
|
@@ -21,6 +21,8 @@
|
|
|
21
21
|
import { accessor, type Accessor } from '../utils/common.js';
|
|
22
22
|
import { isScaleBand } from '../utils/scales.js';
|
|
23
23
|
import { flattenPathData } from '../utils/path.js';
|
|
24
|
+
import { renderPathData } from '../utils/canvas.js';
|
|
25
|
+
import { getCanvasContext } from './layout/Canvas.svelte';
|
|
24
26
|
|
|
25
27
|
const {
|
|
26
28
|
data: contextData,
|
|
@@ -61,6 +63,11 @@
|
|
|
61
63
|
export let curve: CurveFactory | CurveFactoryLineOnly | undefined = undefined;
|
|
62
64
|
export let defined: Parameters<Line<any>['defined']>[0] | undefined = undefined;
|
|
63
65
|
|
|
66
|
+
export let fill: string | undefined = undefined;
|
|
67
|
+
export let stroke: string | undefined = undefined;
|
|
68
|
+
export let strokeWidth: number | undefined = undefined;
|
|
69
|
+
export let opacity: number | undefined = undefined;
|
|
70
|
+
|
|
64
71
|
/** Marker to attach to start, mid, and end points of path */
|
|
65
72
|
export let marker: ComponentProps<Marker>['type'] | ComponentProps<Marker> | undefined =
|
|
66
73
|
undefined;
|
|
@@ -153,6 +160,31 @@
|
|
|
153
160
|
key = Symbol();
|
|
154
161
|
}
|
|
155
162
|
|
|
163
|
+
const canvasContext = getCanvasContext();
|
|
164
|
+
const renderContext = canvasContext ? 'canvas' : 'svg';
|
|
165
|
+
|
|
166
|
+
function render(ctx: CanvasRenderingContext2D) {
|
|
167
|
+
renderPathData(ctx, $tweened_d, {
|
|
168
|
+
styles: { stroke, fill, strokeWidth, opacity },
|
|
169
|
+
classes: $$props.class,
|
|
170
|
+
});
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
let canvasUnregister: ReturnType<typeof canvasContext.register>;
|
|
174
|
+
$: if (renderContext === 'canvas') {
|
|
175
|
+
canvasUnregister = canvasContext.register({ name: 'Spline', render });
|
|
176
|
+
|
|
177
|
+
tweened_d.subscribe(() => {
|
|
178
|
+
canvasContext.invalidate();
|
|
179
|
+
});
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
onDestroy(() => {
|
|
183
|
+
if (renderContext === 'canvas') {
|
|
184
|
+
canvasUnregister();
|
|
185
|
+
}
|
|
186
|
+
});
|
|
187
|
+
|
|
156
188
|
let pathEl: SVGPathElement | undefined = undefined;
|
|
157
189
|
const startPoint = writable<DOMPoint | undefined>(undefined);
|
|
158
190
|
$: endPoint = motionStore<DOMPoint | undefined>(undefined, {
|
|
@@ -187,63 +219,69 @@
|
|
|
187
219
|
}
|
|
188
220
|
</script>
|
|
189
221
|
|
|
190
|
-
{#
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
222
|
+
{#if renderContext === 'svg'}
|
|
223
|
+
{#key key}
|
|
224
|
+
<!-- svelte-ignore a11y-no-static-element-interactions -->
|
|
225
|
+
<path
|
|
226
|
+
d={$tweened_d}
|
|
227
|
+
{...$$restProps}
|
|
228
|
+
class={cls(
|
|
229
|
+
'path-line',
|
|
230
|
+
!$$props.fill && 'fill-none',
|
|
231
|
+
!$$props.stroke && 'stroke-surface-content',
|
|
232
|
+
$$props.class
|
|
233
|
+
)}
|
|
234
|
+
{fill}
|
|
235
|
+
{stroke}
|
|
236
|
+
stroke-width={strokeWidth}
|
|
237
|
+
{opacity}
|
|
238
|
+
marker-start={markerStartId ? `url(#${markerStartId})` : undefined}
|
|
239
|
+
marker-mid={markerMidId ? `url(#${markerMidId})` : undefined}
|
|
240
|
+
marker-end={markerEndId ? `url(#${markerEndId})` : undefined}
|
|
241
|
+
in:drawTransition|global={typeof draw === 'object' ? draw : undefined}
|
|
242
|
+
on:click
|
|
243
|
+
on:pointerenter
|
|
244
|
+
on:pointermove
|
|
245
|
+
on:pointerleave
|
|
246
|
+
bind:this={pathEl}
|
|
247
|
+
/>
|
|
248
|
+
|
|
249
|
+
<slot name="markerStart" id={markerStartId}>
|
|
250
|
+
{#if markerStart}
|
|
251
|
+
<Marker
|
|
252
|
+
id={markerStartId}
|
|
253
|
+
type={typeof markerStart === 'string' ? markerStart : undefined}
|
|
254
|
+
{...typeof markerStart === 'object' ? markerStart : null}
|
|
255
|
+
/>
|
|
256
|
+
{/if}
|
|
257
|
+
</slot>
|
|
258
|
+
|
|
259
|
+
<slot name="markerMid" id={markerMidId}>
|
|
214
260
|
<Marker
|
|
215
|
-
id={
|
|
216
|
-
type={typeof
|
|
217
|
-
{...typeof
|
|
261
|
+
id={markerMidId}
|
|
262
|
+
type={typeof markerMid === 'string' ? markerMid : undefined}
|
|
263
|
+
{...typeof markerMid === 'object' ? markerMid : null}
|
|
218
264
|
/>
|
|
219
|
-
|
|
220
|
-
</slot>
|
|
265
|
+
</slot>
|
|
221
266
|
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
267
|
+
<slot name="markerEnd" id={markerEndId}>
|
|
268
|
+
<Marker
|
|
269
|
+
id={markerEndId}
|
|
270
|
+
type={typeof markerEnd === 'string' ? markerEnd : undefined}
|
|
271
|
+
{...typeof markerEnd === 'object' ? markerEnd : null}
|
|
272
|
+
/>
|
|
273
|
+
</slot>
|
|
229
274
|
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
{#if $$slots.end && $endPoint}
|
|
245
|
-
<Group x={$endPoint.x} y={$endPoint.y}>
|
|
246
|
-
<slot name="end" point={$endPoint} />
|
|
247
|
-
</Group>
|
|
248
|
-
{/if}
|
|
249
|
-
{/key}
|
|
275
|
+
{#if $$slots.start && $startPoint}
|
|
276
|
+
<Group x={$startPoint.x} y={$startPoint.y}>
|
|
277
|
+
<slot name="start" point={$startPoint} />
|
|
278
|
+
</Group>
|
|
279
|
+
{/if}
|
|
280
|
+
|
|
281
|
+
{#if $$slots.end && $endPoint}
|
|
282
|
+
<Group x={$endPoint.x} y={$endPoint.y}>
|
|
283
|
+
<slot name="end" point={$endPoint} />
|
|
284
|
+
</Group>
|
|
285
|
+
{/if}
|
|
286
|
+
{/key}
|
|
287
|
+
{/if}
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
-
import { tick } from 'svelte';
|
|
2
|
+
import { onDestroy, tick } from 'svelte';
|
|
3
3
|
import type { spring as springStore, tweened as tweenedStore } from 'svelte/motion';
|
|
4
4
|
import { cls } from '@layerstack/tailwind';
|
|
5
5
|
|
|
6
6
|
import { getStringWidth } from '../utils/string.js';
|
|
7
7
|
import { motionStore } from '../stores/motionStore.js';
|
|
8
|
+
import { getCanvasContext } from './layout/Canvas.svelte';
|
|
9
|
+
import { renderText } from '../index.js/utils/canvas.js';
|
|
8
10
|
|
|
9
11
|
/*
|
|
10
12
|
TODO:
|
|
@@ -58,6 +60,11 @@
|
|
|
58
60
|
/** Rotational angle of the text */
|
|
59
61
|
export let rotate: number | undefined = undefined;
|
|
60
62
|
|
|
63
|
+
export let fill: string | undefined = undefined;
|
|
64
|
+
export let fillOpacity: number | undefined = undefined;
|
|
65
|
+
export let stroke: string | undefined = undefined;
|
|
66
|
+
export let strokeWidth: number | undefined = undefined;
|
|
67
|
+
|
|
61
68
|
let wordsByLines: { words: string[]; width?: number }[] = [];
|
|
62
69
|
let wordsWithWidth: { word: string; width: number }[] = [];
|
|
63
70
|
let spaceWidth: number = 0;
|
|
@@ -97,8 +104,13 @@
|
|
|
97
104
|
/**
|
|
98
105
|
* Convert css value to pixel value (ex. 0.71em => 11.36)
|
|
99
106
|
*/
|
|
100
|
-
function getPixelValue(cssValue: string) {
|
|
107
|
+
function getPixelValue(cssValue: number | string) {
|
|
101
108
|
// TODO: Properly measure pixel values using DOM (handle inherited font size, zoom, etc)
|
|
109
|
+
|
|
110
|
+
if (typeof cssValue === 'number') {
|
|
111
|
+
return cssValue;
|
|
112
|
+
}
|
|
113
|
+
|
|
102
114
|
// @ts-expect-error
|
|
103
115
|
const [match, value, units] = cssValue.match(/([\d.]+)(\D+)/);
|
|
104
116
|
const number = Number(value);
|
|
@@ -162,25 +174,71 @@
|
|
|
162
174
|
tweened_x.set(x);
|
|
163
175
|
tweened_y.set(y);
|
|
164
176
|
});
|
|
177
|
+
|
|
178
|
+
const canvasContext = getCanvasContext();
|
|
179
|
+
const renderContext = canvasContext ? 'canvas' : 'svg';
|
|
180
|
+
|
|
181
|
+
function render(ctx: CanvasRenderingContext2D) {
|
|
182
|
+
wordsByLines.forEach((line, index) => {
|
|
183
|
+
renderText(
|
|
184
|
+
ctx,
|
|
185
|
+
line.words.join(' '),
|
|
186
|
+
{
|
|
187
|
+
x: getPixelValue($tweened_x) + getPixelValue(dx),
|
|
188
|
+
y:
|
|
189
|
+
getPixelValue($tweened_y) +
|
|
190
|
+
getPixelValue(dy) +
|
|
191
|
+
(index === 0 ? startDy : getPixelValue(lineHeight)),
|
|
192
|
+
},
|
|
193
|
+
{
|
|
194
|
+
styles: { fill, fillOpacity, stroke, strokeWidth, paintOrder: 'stroke', textAnchor },
|
|
195
|
+
classes: cls(fill === undefined && 'fill-surface-content', $$props.class),
|
|
196
|
+
}
|
|
197
|
+
);
|
|
198
|
+
});
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
let canvasUnregister: ReturnType<typeof canvasContext.register>;
|
|
202
|
+
$: if (renderContext === 'canvas') {
|
|
203
|
+
canvasUnregister = canvasContext.register({ name: 'Text', render });
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
$: if (renderContext === 'canvas') {
|
|
207
|
+
// Redraw when props changes (TODO: styles, class, etc)
|
|
208
|
+
value && $tweened_x && $tweened_y;
|
|
209
|
+
canvasContext.invalidate();
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
onDestroy(() => {
|
|
213
|
+
if (renderContext === 'canvas') {
|
|
214
|
+
canvasUnregister();
|
|
215
|
+
}
|
|
216
|
+
});
|
|
165
217
|
</script>
|
|
166
218
|
|
|
167
|
-
|
|
168
|
-
<!-- `
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
219
|
+
{#if renderContext === 'svg'}
|
|
220
|
+
<!-- `overflow: visible` allow contents to be shown outside element -->
|
|
221
|
+
<!-- `paint-order: stroke` supports stroke outlining text -->
|
|
222
|
+
<svg x={dx} y={dy} class="overflow-visible [paint-order:stroke]">
|
|
223
|
+
{#if isValidXOrY(x) && isValidXOrY(y)}
|
|
224
|
+
<text
|
|
225
|
+
x={$tweened_x}
|
|
226
|
+
y={$tweened_y}
|
|
227
|
+
{transform}
|
|
228
|
+
text-anchor={textAnchor}
|
|
229
|
+
{...$$restProps}
|
|
230
|
+
{fill}
|
|
231
|
+
fill-opacity={fillOpacity}
|
|
232
|
+
{stroke}
|
|
233
|
+
stroke-width={strokeWidth}
|
|
234
|
+
class={cls(fill === undefined && 'fill-surface-content', $$props.class)}
|
|
235
|
+
>
|
|
236
|
+
{#each wordsByLines as line, index}
|
|
237
|
+
<tspan x={$tweened_x} dy={index === 0 ? startDy : lineHeight}>
|
|
238
|
+
{line.words.join(' ')}
|
|
239
|
+
</tspan>
|
|
240
|
+
{/each}
|
|
241
|
+
</text>
|
|
242
|
+
{/if}
|
|
243
|
+
</svg>
|
|
244
|
+
{/if}
|
|
@@ -2,7 +2,7 @@ import { SvelteComponentTyped } from "svelte";
|
|
|
2
2
|
declare const __propDef: {
|
|
3
3
|
props: {
|
|
4
4
|
[x: string]: any;
|
|
5
|
-
placement?: ("center" | "
|
|
5
|
+
placement?: ("center" | "bottom" | "left" | "right" | "top" | "top-left" | "top-right" | "bottom-left" | "bottom-right") | undefined;
|
|
6
6
|
orientation?: "horizontal" | "vertical" | undefined;
|
|
7
7
|
size?: import("svelte-ux").ButtonSize | undefined;
|
|
8
8
|
show?: ("reset" | "scrollMode" | "zoomIn" | "zoomOut" | "center")[] | undefined;
|
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
|
|
8
8
|
import Area from '../Area.svelte';
|
|
9
9
|
import Axis from '../Axis.svelte';
|
|
10
|
+
import Canvas from '../layout/Canvas.svelte';
|
|
10
11
|
import Chart from '../Chart.svelte';
|
|
11
12
|
import Grid from '../Grid.svelte';
|
|
12
13
|
import Highlight from '../Highlight.svelte';
|
|
@@ -18,7 +19,12 @@
|
|
|
18
19
|
import Svg from '../layout/Svg.svelte';
|
|
19
20
|
import * as Tooltip from '../tooltip/index.js';
|
|
20
21
|
|
|
21
|
-
import {
|
|
22
|
+
import {
|
|
23
|
+
accessor,
|
|
24
|
+
chartDataArray,
|
|
25
|
+
defaultChartPadding,
|
|
26
|
+
type Accessor,
|
|
27
|
+
} from '../../utils/common.js';
|
|
22
28
|
|
|
23
29
|
interface $$Props extends ComponentProps<Chart<TData>> {
|
|
24
30
|
axis?: typeof axis;
|
|
@@ -30,6 +36,7 @@
|
|
|
30
36
|
rule?: typeof rule;
|
|
31
37
|
series?: typeof series;
|
|
32
38
|
seriesLayout?: typeof seriesLayout;
|
|
39
|
+
renderContext?: typeof renderContext;
|
|
33
40
|
}
|
|
34
41
|
|
|
35
42
|
export let data: $$Props['data'] = [];
|
|
@@ -74,6 +81,8 @@
|
|
|
74
81
|
labels?: Partial<ComponentProps<Labels>>;
|
|
75
82
|
} = {};
|
|
76
83
|
|
|
84
|
+
export let renderContext: 'svg' | 'canvas' = 'svg';
|
|
85
|
+
|
|
77
86
|
$: allSeriesData = series
|
|
78
87
|
.flatMap((s) => s.data?.map((d) => ({ seriesKey: s.key, ...d })))
|
|
79
88
|
.filter((d) => d) as Array<TData & { stackData?: any }>;
|
|
@@ -126,7 +135,7 @@
|
|
|
126
135
|
? s.value[1]
|
|
127
136
|
: (s.value ?? s.key),
|
|
128
137
|
fill: s.color,
|
|
129
|
-
|
|
138
|
+
fillOpacity: 0.3,
|
|
130
139
|
...props.area,
|
|
131
140
|
...s.props,
|
|
132
141
|
line: {
|
|
@@ -151,12 +160,7 @@
|
|
|
151
160
|
yBaseline={0}
|
|
152
161
|
yNice
|
|
153
162
|
{radial}
|
|
154
|
-
padding={radial
|
|
155
|
-
? undefined
|
|
156
|
-
: {
|
|
157
|
-
left: axis === true || axis === 'y' ? 16 : 0,
|
|
158
|
-
bottom: (axis === true || axis === 'x' ? 16 : 0) + (legend === true ? 32 : 0),
|
|
159
|
-
}}
|
|
163
|
+
padding={radial ? undefined : defaultChartPadding(axis, legend)}
|
|
160
164
|
tooltip={{ mode: 'bisect-x' }}
|
|
161
165
|
{...$$restProps}
|
|
162
166
|
let:x
|
|
@@ -186,7 +190,7 @@
|
|
|
186
190
|
}}
|
|
187
191
|
|
|
188
192
|
<slot {...slotProps}>
|
|
189
|
-
<Svg center={radial}>
|
|
193
|
+
<svelte:component this={renderContext === 'canvas' ? Canvas : Svg} center={radial}>
|
|
190
194
|
<slot name="grid" {...slotProps}>
|
|
191
195
|
{#if grid}
|
|
192
196
|
<Grid x={radial} y {...typeof grid === 'object' ? grid : null} {...props.grid} />
|
|
@@ -261,7 +265,7 @@
|
|
|
261
265
|
{#if labels}
|
|
262
266
|
<Labels {...props.labels} {...typeof labels === 'object' ? labels : null} />
|
|
263
267
|
{/if}
|
|
264
|
-
</
|
|
268
|
+
</svelte:component>
|
|
265
269
|
|
|
266
270
|
<slot name="legend" {...slotProps}>
|
|
267
271
|
{#if legend}
|