layerchart 0.30.1 → 0.31.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/Area.svelte +14 -7
- package/dist/components/Area.svelte.d.ts +2 -0
- package/dist/components/AreaStack.svelte +18 -16
- package/dist/components/AreaStack.svelte.d.ts +5 -1
- package/dist/components/Axis.svelte +70 -7
- package/dist/components/Axis.svelte.d.ts +1 -1
- package/dist/components/Chart.svelte +12 -0
- package/dist/components/Chart.svelte.d.ts +4 -0
- package/dist/components/Circle.svelte +1 -1
- package/dist/components/Points.svelte +7 -3
- package/dist/components/Points.svelte.d.ts +1 -0
- package/dist/components/Rect.svelte +1 -1
- package/dist/components/Spline.svelte +13 -7
- package/dist/components/Spline.svelte.d.ts +1 -0
- package/dist/components/Tooltip.svelte +7 -7
- package/dist/components/Tooltip.svelte.d.ts +1 -1
- package/dist/components/TooltipContext.svelte +13 -39
- package/dist/components/Voronoi.svelte +33 -0
- package/dist/components/Voronoi.svelte.d.ts +34 -0
- package/dist/components/Zoom.svelte.d.ts +1 -1
- package/dist/components/index.d.ts +1 -0
- package/dist/components/index.js +1 -0
- package/dist/utils/math.d.ts +21 -0
- package/dist/utils/math.js +29 -0
- package/package.json +2 -2
|
@@ -1,15 +1,17 @@
|
|
|
1
1
|
<script>import { getContext } from 'svelte';
|
|
2
|
-
import { area as d3Area } from 'd3-shape';
|
|
2
|
+
import { area as d3Area, areaRadial } from 'd3-shape';
|
|
3
3
|
import { max } from 'd3-array';
|
|
4
4
|
import { interpolatePath } from 'd3-interpolate-path';
|
|
5
5
|
import { cls } from 'svelte-ux';
|
|
6
6
|
import { motionStore } from '../stores/motionStore';
|
|
7
7
|
import Spline from './Spline.svelte';
|
|
8
|
-
const { data: contextData, xGet, yGet, yRange } = getContext('LayerCake');
|
|
8
|
+
const { data: contextData, xScale, yScale, xGet, yGet, yRange } = getContext('LayerCake');
|
|
9
9
|
/** Override data instead of using context */
|
|
10
10
|
export let data = undefined;
|
|
11
11
|
/** Pass `<path d={...} />` explicitly instead of calculating from data / context */
|
|
12
12
|
export let pathData = undefined;
|
|
13
|
+
/** Use radial instead of cartesian area generator, mapping `x` to `angle` and `y0`/`y1 to `innerRadius`/`outerRadius. Radial lines are positioned relative to the origin, use transform (ex. `<Group center>`) to change the origin */
|
|
14
|
+
export let radial = false;
|
|
13
15
|
/** Override x accessor */
|
|
14
16
|
export let x = undefined; // TODO: Update Type
|
|
15
17
|
/** Override y0 accessor. Defaults to max($yRange) */
|
|
@@ -26,10 +28,15 @@ export let line = false;
|
|
|
26
28
|
$: tweenedOptions = tweened ? { interpolate: interpolatePath, ...tweened } : false;
|
|
27
29
|
$: tweened_d = motionStore('', { tweened: tweenedOptions });
|
|
28
30
|
$: {
|
|
29
|
-
const path =
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
31
|
+
const path = radial
|
|
32
|
+
? areaRadial()
|
|
33
|
+
.angle((d) => (x ? $xScale(x(d)) : $xGet(d)))
|
|
34
|
+
.innerRadius((d) => (y0 ? $yScale(y0(d)) : max($yRange)))
|
|
35
|
+
.outerRadius((d) => (y1 ? $yScale(y1(d)) : $yGet(d)))
|
|
36
|
+
: d3Area()
|
|
37
|
+
.x((d) => (x ? $xScale(x(d)) : $xGet(d)))
|
|
38
|
+
.y0((d) => (y0 ? $yScale(y0(d)) : max($yRange)))
|
|
39
|
+
.y1((d) => (y1 ? $yScale(y1(d)) : $yGet(d)));
|
|
33
40
|
if (curve)
|
|
34
41
|
path.curve(curve);
|
|
35
42
|
if (defined)
|
|
@@ -40,7 +47,7 @@ $: {
|
|
|
40
47
|
</script>
|
|
41
48
|
|
|
42
49
|
{#if line}
|
|
43
|
-
<Spline {data} {curve} {defined} {tweened} {...typeof line === 'object' ? line : null} />
|
|
50
|
+
<Spline {data} y={y1} {curve} {defined} {tweened} {...typeof line === 'object' ? line : null} />
|
|
44
51
|
{/if}
|
|
45
52
|
|
|
46
53
|
<path
|
|
@@ -7,6 +7,7 @@ declare const __propDef: {
|
|
|
7
7
|
[x: string]: any;
|
|
8
8
|
data?: any;
|
|
9
9
|
pathData?: string | undefined | null;
|
|
10
|
+
radial?: boolean | undefined;
|
|
10
11
|
x?: any;
|
|
11
12
|
y0?: any;
|
|
12
13
|
y1?: any;
|
|
@@ -18,6 +19,7 @@ declare const __propDef: {
|
|
|
18
19
|
[x: string]: any;
|
|
19
20
|
data?: any;
|
|
20
21
|
pathData?: string | null | undefined;
|
|
22
|
+
radial?: boolean | undefined;
|
|
21
23
|
x?: any;
|
|
22
24
|
y?: any;
|
|
23
25
|
tweened?: boolean | import("svelte/motion").TweenedOptions<unknown> | undefined;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
<script>import { getContext } from 'svelte';
|
|
2
2
|
import Area from './Area.svelte';
|
|
3
3
|
import Spline from './Spline.svelte';
|
|
4
|
-
const { data,
|
|
4
|
+
const { data, rGet } = getContext('LayerCake');
|
|
5
5
|
export let curve = undefined;
|
|
6
6
|
export let defined = undefined;
|
|
7
7
|
export let opacity = 0.3;
|
|
@@ -16,7 +16,7 @@ $: lineData = [...$data].reverse();
|
|
|
16
16
|
{#each lineData as seriesData}
|
|
17
17
|
<Spline
|
|
18
18
|
data={seriesData}
|
|
19
|
-
y={(d) =>
|
|
19
|
+
y={(d) => d[1]}
|
|
20
20
|
stroke={$rGet(seriesData)}
|
|
21
21
|
{curve}
|
|
22
22
|
{defined}
|
|
@@ -27,17 +27,19 @@ $: lineData = [...$data].reverse();
|
|
|
27
27
|
</g>
|
|
28
28
|
{/if}
|
|
29
29
|
|
|
30
|
-
<
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
30
|
+
<slot data={$data}>
|
|
31
|
+
<g class="area-group">
|
|
32
|
+
{#each $data as seriesData}
|
|
33
|
+
<Area
|
|
34
|
+
data={seriesData}
|
|
35
|
+
y0={(d) => d[0]}
|
|
36
|
+
y1={(d) => d[1]}
|
|
37
|
+
fill={$rGet(seriesData)}
|
|
38
|
+
{curve}
|
|
39
|
+
{defined}
|
|
40
|
+
{opacity}
|
|
41
|
+
{tweened}
|
|
42
|
+
/>
|
|
43
|
+
{/each}
|
|
44
|
+
</g>
|
|
45
|
+
</slot>
|
|
@@ -14,7 +14,11 @@ declare const __propDef: {
|
|
|
14
14
|
events: {
|
|
15
15
|
[evt: string]: CustomEvent<any>;
|
|
16
16
|
};
|
|
17
|
-
slots: {
|
|
17
|
+
slots: {
|
|
18
|
+
default: {
|
|
19
|
+
data: any;
|
|
20
|
+
};
|
|
21
|
+
};
|
|
18
22
|
};
|
|
19
23
|
export type AreaStackProps = typeof __propDef.props;
|
|
20
24
|
export type AreaStackEvents = typeof __propDef.events;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
<script>import { getContext } from 'svelte';
|
|
2
2
|
import { format as formatValue, cls } from 'svelte-ux';
|
|
3
3
|
import { extent } from 'd3-array';
|
|
4
|
+
import { pointRadial } from 'd3-shape';
|
|
4
5
|
import Text from './Text.svelte';
|
|
5
6
|
import { isScaleBand } from '../utils/scales';
|
|
6
7
|
const { xScale, yScale, xRange, yRange, width } = getContext('LayerCake');
|
|
@@ -16,8 +17,15 @@ export let ticks = placement === 'left' || placement === 'right' ? 4 : undefined
|
|
|
16
17
|
export let tickSize = 4;
|
|
17
18
|
export let format = undefined;
|
|
18
19
|
export let labelProps = undefined;
|
|
19
|
-
$: orientation =
|
|
20
|
-
|
|
20
|
+
$: orientation =
|
|
21
|
+
placement === 'angle'
|
|
22
|
+
? 'angle'
|
|
23
|
+
: placement === 'radius'
|
|
24
|
+
? 'radius'
|
|
25
|
+
: ['top', 'bottom'].includes(placement)
|
|
26
|
+
? 'horizontal'
|
|
27
|
+
: 'vertical';
|
|
28
|
+
$: scale = ['horizontal', 'angle'].includes(orientation) ? $xScale : $yScale;
|
|
21
29
|
$: [xRangeMin, xRangeMax] = extent($xRange);
|
|
22
30
|
$: [yRangeMin, yRangeMax] = extent($yRange);
|
|
23
31
|
$: tickVals = Array.isArray(ticks)
|
|
@@ -47,9 +55,19 @@ function getCoords(tick) {
|
|
|
47
55
|
x: xRangeMax,
|
|
48
56
|
y: $yScale(tick) + (isScaleBand($yScale) ? $yScale.bandwidth() / 2 : 0),
|
|
49
57
|
};
|
|
58
|
+
case 'angle':
|
|
59
|
+
return {
|
|
60
|
+
x: $xScale(tick),
|
|
61
|
+
y: yRangeMax,
|
|
62
|
+
};
|
|
63
|
+
case 'radius':
|
|
64
|
+
return {
|
|
65
|
+
x: xRangeMin,
|
|
66
|
+
y: $yScale(tick),
|
|
67
|
+
};
|
|
50
68
|
}
|
|
51
69
|
}
|
|
52
|
-
function getDefaultLabelProps() {
|
|
70
|
+
function getDefaultLabelProps(tick) {
|
|
53
71
|
switch (placement) {
|
|
54
72
|
case 'top':
|
|
55
73
|
return {
|
|
@@ -77,6 +95,21 @@ function getDefaultLabelProps() {
|
|
|
77
95
|
dx: 4,
|
|
78
96
|
dy: -2, // manually adjusted until Text supports custom styles
|
|
79
97
|
};
|
|
98
|
+
case 'angle':
|
|
99
|
+
const xValue = $xScale(tick);
|
|
100
|
+
return {
|
|
101
|
+
textAnchor: xValue === 0 || xValue === Math.PI ? 'middle' : xValue > Math.PI ? 'end' : 'start',
|
|
102
|
+
verticalAnchor: 'middle',
|
|
103
|
+
dx: 0,
|
|
104
|
+
dy: -2, // manually adjusted until Text supports custom styles
|
|
105
|
+
};
|
|
106
|
+
case 'radius':
|
|
107
|
+
return {
|
|
108
|
+
textAnchor: 'middle',
|
|
109
|
+
verticalAnchor: 'middle',
|
|
110
|
+
dx: 2,
|
|
111
|
+
dy: -2, // manually adjusted until Text supports custom styles
|
|
112
|
+
};
|
|
80
113
|
}
|
|
81
114
|
}
|
|
82
115
|
</script>
|
|
@@ -105,10 +138,22 @@ function getDefaultLabelProps() {
|
|
|
105
138
|
class={cls('rule stroke-surface-content/50', lineProps?.class)}
|
|
106
139
|
/>
|
|
107
140
|
{/if}
|
|
141
|
+
|
|
142
|
+
<!-- TODO: angle rule? -->
|
|
143
|
+
|
|
144
|
+
{#if orientation === 'radius'}
|
|
145
|
+
<circle
|
|
146
|
+
r={$yRange[0] || 0}
|
|
147
|
+
{...lineProps}
|
|
148
|
+
class={cls('rule stroke-surface-content/20 fill-none', lineProps?.class)}
|
|
149
|
+
/>
|
|
150
|
+
{/if}
|
|
108
151
|
{/if}
|
|
109
152
|
|
|
110
153
|
{#each tickVals as tick, i}
|
|
111
154
|
{@const tickCoords = getCoords(tick)}
|
|
155
|
+
{@const radialTickCoords = pointRadial(tickCoords.x, tickCoords.y)}
|
|
156
|
+
|
|
112
157
|
<g>
|
|
113
158
|
{#if grid !== false}
|
|
114
159
|
{@const lineProps = typeof grid === 'object' ? grid : null}
|
|
@@ -130,6 +175,24 @@ function getDefaultLabelProps() {
|
|
|
130
175
|
{...lineProps}
|
|
131
176
|
class={cls('grid stroke-surface-content/10', lineProps?.class)}
|
|
132
177
|
/>
|
|
178
|
+
{:else if orientation === 'angle'}
|
|
179
|
+
{@const [x1, y1] = pointRadial(tickCoords.x, yRangeMin)}
|
|
180
|
+
{@const [x2, y2] = pointRadial(tickCoords.x, yRangeMax)}
|
|
181
|
+
|
|
182
|
+
<line
|
|
183
|
+
{x1}
|
|
184
|
+
{y1}
|
|
185
|
+
{x2}
|
|
186
|
+
{y2}
|
|
187
|
+
{...lineProps}
|
|
188
|
+
class={cls('test grid stroke-surface-content/10', lineProps?.class)}
|
|
189
|
+
/>
|
|
190
|
+
{:else if orientation === 'radius'}
|
|
191
|
+
<circle
|
|
192
|
+
r={tickCoords.y}
|
|
193
|
+
{...lineProps}
|
|
194
|
+
class={cls('grid stroke-surface-content/10 fill-none', lineProps?.class)}
|
|
195
|
+
/>
|
|
133
196
|
{/if}
|
|
134
197
|
{/if}
|
|
135
198
|
|
|
@@ -153,10 +216,10 @@ function getDefaultLabelProps() {
|
|
|
153
216
|
{/if}
|
|
154
217
|
|
|
155
218
|
<Text
|
|
156
|
-
x={tickCoords.x}
|
|
157
|
-
y={tickCoords.y}
|
|
158
|
-
value={formatValue(tick, format ?? scale.tickFormat?.())}
|
|
159
|
-
{...getDefaultLabelProps()}
|
|
219
|
+
x={orientation === 'angle' ? radialTickCoords[0] : tickCoords.x}
|
|
220
|
+
y={orientation === 'angle' ? radialTickCoords[1] : tickCoords.y}
|
|
221
|
+
value={formatValue(tick, format ?? scale.tickFormat?.() ?? ((v) => v))}
|
|
222
|
+
{...getDefaultLabelProps(tick)}
|
|
160
223
|
{...labelProps}
|
|
161
224
|
class={cls(
|
|
162
225
|
'label text-[10px] stroke-surface-100 [stroke-width:2px] font-light',
|
|
@@ -4,7 +4,7 @@ import type { SVGAttributes } from 'svelte/elements';
|
|
|
4
4
|
import Text from './Text.svelte';
|
|
5
5
|
declare const __propDef: {
|
|
6
6
|
props: {
|
|
7
|
-
/** Location of axis */ placement: 'top' | 'bottom' | 'left' | 'right';
|
|
7
|
+
/** Location of axis */ placement: 'top' | 'bottom' | 'left' | 'right' | 'angle' | 'radius';
|
|
8
8
|
/** Draw a rule line. Use Rule component for greater rendering order control */ rule?: boolean | SVGAttributes<SVGLineElement> | undefined;
|
|
9
9
|
/** Draw a grid lines */ grid?: boolean | SVGAttributes<SVGLineElement> | undefined;
|
|
10
10
|
/** Control the number of ticks*/ ticks?: number | any[] | Function | undefined;
|
|
@@ -79,9 +79,13 @@ export let geo = undefined;
|
|
|
79
79
|
let:width
|
|
80
80
|
let:element
|
|
81
81
|
let:xScale
|
|
82
|
+
let:xGet
|
|
82
83
|
let:yScale
|
|
84
|
+
let:yGet
|
|
83
85
|
let:zScale
|
|
86
|
+
let:zGet
|
|
84
87
|
let:rScale
|
|
88
|
+
let:rGet
|
|
85
89
|
let:padding
|
|
86
90
|
let:data
|
|
87
91
|
let:flatData
|
|
@@ -100,9 +104,13 @@ export let geo = undefined;
|
|
|
100
104
|
{projection}
|
|
101
105
|
{tooltip}
|
|
102
106
|
{xScale}
|
|
107
|
+
{xGet}
|
|
103
108
|
{yScale}
|
|
109
|
+
{yGet}
|
|
104
110
|
{zScale}
|
|
111
|
+
{zGet}
|
|
105
112
|
{rScale}
|
|
113
|
+
{rGet}
|
|
106
114
|
{padding}
|
|
107
115
|
{data}
|
|
108
116
|
{flatData}
|
|
@@ -118,9 +126,13 @@ export let geo = undefined;
|
|
|
118
126
|
{element}
|
|
119
127
|
{projection}
|
|
120
128
|
{xScale}
|
|
129
|
+
{xGet}
|
|
121
130
|
{yScale}
|
|
131
|
+
{yGet}
|
|
122
132
|
{zScale}
|
|
133
|
+
{zGet}
|
|
123
134
|
{rScale}
|
|
135
|
+
{rGet}
|
|
124
136
|
{padding}
|
|
125
137
|
{data}
|
|
126
138
|
{flatData}
|
|
@@ -32,9 +32,13 @@ declare const __propDef: {
|
|
|
32
32
|
element: Element;
|
|
33
33
|
projection: import("d3-geo").GeoProjection | import("d3-geo").GeoIdentityTransform;
|
|
34
34
|
xScale: any;
|
|
35
|
+
xGet: any;
|
|
35
36
|
yScale: any;
|
|
37
|
+
yGet: any;
|
|
36
38
|
zScale: any;
|
|
39
|
+
zGet: any;
|
|
37
40
|
rScale: any;
|
|
41
|
+
rGet: any;
|
|
38
42
|
padding: {
|
|
39
43
|
top: number;
|
|
40
44
|
right: number;
|
|
@@ -23,7 +23,7 @@ $: tick().then(() => {
|
|
|
23
23
|
cx={$tweened_cx}
|
|
24
24
|
cy={$tweened_cy}
|
|
25
25
|
r={$tweened_r}
|
|
26
|
-
class={cls($$props.fill
|
|
26
|
+
class={cls($$props.fill == null && 'fill-surface-content')}
|
|
27
27
|
{...$$restProps}
|
|
28
28
|
on:click
|
|
29
29
|
on:mousemove
|
|
@@ -4,11 +4,14 @@ import { notNull } from 'svelte-ux';
|
|
|
4
4
|
import Circle from './Circle.svelte';
|
|
5
5
|
import Link from './Link.svelte';
|
|
6
6
|
import { isScaleBand } from '../utils/scales';
|
|
7
|
+
import { pointRadial } from 'd3-shape';
|
|
7
8
|
const context = getContext('LayerCake');
|
|
8
9
|
const { data, xGet, y, yGet, xScale, yScale, rGet, config } = context;
|
|
9
10
|
export let r = 5;
|
|
10
11
|
export let offsetX = undefined;
|
|
11
12
|
export let offsetY = undefined;
|
|
13
|
+
/** Use radial instead of cartesian line generator, mapping `x` to `angle` and `y` to `radius`. Radial points are positioned relative to the origin, use transform (ex. `<Group center>`) to change the origin */
|
|
14
|
+
export let radial = false;
|
|
12
15
|
/** Enable showing links between related points (array x/y accessors) */
|
|
13
16
|
export let links = false;
|
|
14
17
|
function getOffset(value, offset, scale) {
|
|
@@ -18,7 +21,7 @@ function getOffset(value, offset, scale) {
|
|
|
18
21
|
else if (offset != null) {
|
|
19
22
|
return offset;
|
|
20
23
|
}
|
|
21
|
-
else if (isScaleBand(scale)) {
|
|
24
|
+
else if (isScaleBand(scale) && !radial) {
|
|
22
25
|
return scale.bandwidth() / 2;
|
|
23
26
|
}
|
|
24
27
|
else {
|
|
@@ -123,9 +126,10 @@ $: _links = $data.flatMap((d) => {
|
|
|
123
126
|
|
|
124
127
|
<g class="point-group">
|
|
125
128
|
{#each points as point}
|
|
129
|
+
{@const radialPoint = pointRadial(point.x, point.y)}
|
|
126
130
|
<Circle
|
|
127
|
-
cx={point.x}
|
|
128
|
-
cy={point.y}
|
|
131
|
+
cx={radial ? radialPoint[0] : point.x}
|
|
132
|
+
cy={radial ? radialPoint[1] : point.y}
|
|
129
133
|
{r}
|
|
130
134
|
fill={$config.r ? $rGet(point.data) : null}
|
|
131
135
|
{...$$restProps}
|
|
@@ -5,6 +5,7 @@ declare const __propDef: {
|
|
|
5
5
|
r?: number | undefined;
|
|
6
6
|
offsetX?: number | ((value: number, context: any) => number) | undefined;
|
|
7
7
|
offsetY?: number | ((value: number, context: any) => number) | undefined;
|
|
8
|
+
radial?: boolean | undefined;
|
|
8
9
|
links?: boolean | Partial<{
|
|
9
10
|
[x: string]: any;
|
|
10
11
|
data?: any;
|
|
@@ -29,7 +29,7 @@ $: tick().then(() => {
|
|
|
29
29
|
y={$tweened_y}
|
|
30
30
|
width={$tweened_width}
|
|
31
31
|
height={$tweened_height}
|
|
32
|
-
class={cls($$props.fill
|
|
32
|
+
class={cls($$props.fill == null && 'fill-surface-content')}
|
|
33
33
|
{...$$restProps}
|
|
34
34
|
on:click
|
|
35
35
|
on:mouseover
|
|
@@ -3,20 +3,22 @@ import { writable } from 'svelte/store';
|
|
|
3
3
|
import { tweened as tweenedStore } from 'svelte/motion';
|
|
4
4
|
import { draw as _drawTransition } from 'svelte/transition';
|
|
5
5
|
import { cubicInOut } from 'svelte/easing';
|
|
6
|
-
import { line as d3Line } from 'd3-shape';
|
|
6
|
+
import { line as d3Line, lineRadial } from 'd3-shape';
|
|
7
7
|
// import { interpolateString } from 'd3-interpolate';
|
|
8
8
|
import { interpolatePath } from 'd3-interpolate-path';
|
|
9
9
|
import { cls } from 'svelte-ux';
|
|
10
10
|
import { motionStore } from '../stores/motionStore';
|
|
11
11
|
import Group from './Group.svelte';
|
|
12
|
-
const { data: contextData, xGet, yGet } = getContext('LayerCake');
|
|
12
|
+
const { data: contextData, xScale, yScale, xGet, yGet } = getContext('LayerCake');
|
|
13
13
|
/** Override data instead of using context */
|
|
14
14
|
export let data = undefined;
|
|
15
15
|
/** Pass `<path d={...} />` explicitly instead of calculating from data / context */
|
|
16
16
|
export let pathData = undefined;
|
|
17
|
-
/**
|
|
17
|
+
/** Use radial instead of cartesian line generator, mapping `x` to `angle` and `y` to `radius`. Radial lines are positioned relative to the origin, use transform (ex. `<Group center>`) to change the origin */
|
|
18
|
+
export let radial = false;
|
|
19
|
+
/** Override `x` accessor from Chart context. Applies to `angle` when `radial=true` */
|
|
18
20
|
export let x = undefined; // TODO: Update Type
|
|
19
|
-
/** Override y accessor */
|
|
21
|
+
/** Override `y` accessor from Chart context. Applies to `radius` when `radial=true` */
|
|
20
22
|
export let y = undefined; // TODO: Update Type
|
|
21
23
|
/** Interpolate path data using d3-interpolate-path. Works best without `draw` enabled */
|
|
22
24
|
export let tweened = undefined;
|
|
@@ -37,9 +39,13 @@ let d = '';
|
|
|
37
39
|
$: tweenedOptions = tweened ? { interpolate: interpolatePath, ...tweened } : false;
|
|
38
40
|
$: tweened_d = motionStore('', { tweened: tweenedOptions });
|
|
39
41
|
$: {
|
|
40
|
-
const path =
|
|
41
|
-
|
|
42
|
-
|
|
42
|
+
const path = radial
|
|
43
|
+
? lineRadial()
|
|
44
|
+
.angle((d) => (x ? $xScale(x(d)) : $xGet(d)))
|
|
45
|
+
.radius((d) => (y ? $yScale(y(d)) : $yGet(d)))
|
|
46
|
+
: d3Line()
|
|
47
|
+
.x((d) => (x ? $xScale(x(d)) : $xGet(d)))
|
|
48
|
+
.y((d) => (y ? $yScale(y(d)) : $yGet(d)));
|
|
43
49
|
if (curve)
|
|
44
50
|
path.curve(curve);
|
|
45
51
|
if (defined)
|
|
@@ -15,7 +15,7 @@ export let yOffset = typeof x === 'number' || typeof y === 'number' ? 0 : 10;
|
|
|
15
15
|
export let anchor = 'top-left';
|
|
16
16
|
export let contained = 'container'; // TODO: Support 'window' using getBoundingClientRect()
|
|
17
17
|
export let animate = true;
|
|
18
|
-
export let variant = '
|
|
18
|
+
export let variant = 'default';
|
|
19
19
|
export let header = undefined;
|
|
20
20
|
export let classes = {};
|
|
21
21
|
const { padding, xGet, yGet, containerWidth, containerHeight } = getContext('LayerCake');
|
|
@@ -115,13 +115,13 @@ $: if ($tooltip?.data) {
|
|
|
115
115
|
['[&_.value]:text-sm [&_.value]:tabular-nums'],
|
|
116
116
|
],
|
|
117
117
|
{
|
|
118
|
-
|
|
119
|
-
'bg-
|
|
120
|
-
'[&_.label]:text-
|
|
118
|
+
default: [
|
|
119
|
+
'bg-surface-100/90 dark:bg-surface-300/90 backdrop-filter backdrop-blur-[2px] text-surface-content',
|
|
120
|
+
'[&_.label]:text-surface-content/75',
|
|
121
121
|
],
|
|
122
|
-
|
|
123
|
-
'bg-
|
|
124
|
-
'[&_.label]:text-surface-
|
|
122
|
+
invert: [
|
|
123
|
+
'bg-surface-content/90 backdrop-filter backdrop-blur-[2px] text-surface-100 border border-surface-content',
|
|
124
|
+
'[&_.label]:text-surface-100/50',
|
|
125
125
|
],
|
|
126
126
|
none: '',
|
|
127
127
|
}[variant],
|
|
@@ -9,7 +9,7 @@ declare const __propDef: {
|
|
|
9
9
|
anchor?: ("center" | "top" | "bottom" | "left" | "right" | "top-left" | "top-right" | "bottom-left" | "bottom-right") | undefined;
|
|
10
10
|
contained?: false | "container" | undefined;
|
|
11
11
|
animate?: boolean | undefined;
|
|
12
|
-
variant?: "
|
|
12
|
+
variant?: "default" | "none" | "invert" | undefined;
|
|
13
13
|
header?: ((data: any) => any) | undefined;
|
|
14
14
|
classes?: {
|
|
15
15
|
root?: string | undefined;
|
|
@@ -18,11 +18,11 @@ function setTooltipContext(tooltip) {
|
|
|
18
18
|
<script>import { raise } from 'layercake';
|
|
19
19
|
import { writable } from 'svelte/store';
|
|
20
20
|
import { bisector, max, min } from 'd3-array';
|
|
21
|
-
import { Delaunay } from 'd3-delaunay';
|
|
22
21
|
import { quadtree as d3Quadtree } from 'd3-quadtree';
|
|
23
|
-
import { sortFunc } from 'svelte-ux';
|
|
22
|
+
import { cls, sortFunc } from 'svelte-ux';
|
|
24
23
|
import { Svg, Html } from './Chart.svelte';
|
|
25
24
|
import ChartClipPath from './ChartClipPath.svelte';
|
|
25
|
+
import Voronoi from './Voronoi.svelte';
|
|
26
26
|
import { localPoint } from '../utils/event';
|
|
27
27
|
import { isScaleBand, scaleInvert } from '../utils/scales';
|
|
28
28
|
import { quadtreeRects } from '../utils/quadtree';
|
|
@@ -187,20 +187,6 @@ function hideTooltip() {
|
|
|
187
187
|
$tooltip = { ...$tooltip, data: null };
|
|
188
188
|
});
|
|
189
189
|
}
|
|
190
|
-
let points;
|
|
191
|
-
let voronoi;
|
|
192
|
-
$: if (mode === 'voronoi') {
|
|
193
|
-
points = $flatData.map((d) => {
|
|
194
|
-
const xValue = $xGet(d);
|
|
195
|
-
const yValue = $yGet(d);
|
|
196
|
-
const x = Array.isArray(xValue) ? min(xValue) : xValue;
|
|
197
|
-
const y = Array.isArray(yValue) ? min(yValue) : yValue;
|
|
198
|
-
const point = [x, y];
|
|
199
|
-
point.data = d;
|
|
200
|
-
return point;
|
|
201
|
-
});
|
|
202
|
-
voronoi = Delaunay.from(points).voronoi([0, 0, Math.max($width, 0), Math.max($height, 0)]); // width and/or height can sometimes be negative (when loading data remotely and updately)
|
|
203
|
-
}
|
|
204
190
|
let quadtree;
|
|
205
191
|
$: if (mode === 'quadtree') {
|
|
206
192
|
quadtree = d3Quadtree()
|
|
@@ -287,10 +273,9 @@ $: if (mode === 'bounds' || mode === 'band') {
|
|
|
287
273
|
{#if ['bisect-x', 'bisect-y', 'bisect-band', 'quadtree'].includes(mode)}
|
|
288
274
|
<Html>
|
|
289
275
|
<div
|
|
290
|
-
class="tooltip-trigger absolute"
|
|
291
276
|
style:width="{$width}px"
|
|
292
277
|
style:height="{$height}px"
|
|
293
|
-
|
|
278
|
+
class={cls('tooltip-trigger absolute', debug && 'bg-danger/10 outline outline-danger')}
|
|
294
279
|
on:touchstart={showTooltip}
|
|
295
280
|
on:touchmove={showTooltip}
|
|
296
281
|
on:mousemove={showTooltip}
|
|
@@ -302,21 +287,14 @@ $: if (mode === 'bounds' || mode === 'band') {
|
|
|
302
287
|
</Html>
|
|
303
288
|
{:else if mode === 'voronoi'}
|
|
304
289
|
<Svg>
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
on:mouseleave={hideTooltip}
|
|
314
|
-
on:click={(e) => {
|
|
315
|
-
onClick({ data: point.data });
|
|
316
|
-
}}
|
|
317
|
-
/>
|
|
318
|
-
</g>
|
|
319
|
-
{/each}
|
|
290
|
+
<Voronoi
|
|
291
|
+
on:mousemove={(e) => showTooltip(e.detail.event, e.detail.point.data)}
|
|
292
|
+
on:mouseleave={hideTooltip}
|
|
293
|
+
on:click={(e) => {
|
|
294
|
+
onClick({ data: e.detail.point.data });
|
|
295
|
+
}}
|
|
296
|
+
classes={{ path: cls(debug && 'fill-danger/10 stroke-danger') }}
|
|
297
|
+
/>
|
|
320
298
|
</Svg>
|
|
321
299
|
{:else if mode === 'bounds' || mode === 'band'}
|
|
322
300
|
<Svg>
|
|
@@ -327,9 +305,7 @@ $: if (mode === 'bounds' || mode === 'band') {
|
|
|
327
305
|
y={rect.y}
|
|
328
306
|
width={rect.width}
|
|
329
307
|
height={rect.height}
|
|
330
|
-
|
|
331
|
-
style:fill-opacity={debug ? 0.1 : 0}
|
|
332
|
-
style:stroke={debug ? 'red' : 'transparent'}
|
|
308
|
+
class={cls(debug ? 'fill-danger/10 stroke-danger' : 'fill-transparent')}
|
|
333
309
|
on:mousemove={(e) => showTooltip(e, rect.data)}
|
|
334
310
|
on:mouseleave={hideTooltip}
|
|
335
311
|
on:click={(e) => {
|
|
@@ -351,9 +327,7 @@ $: if (mode === 'bounds' || mode === 'band') {
|
|
|
351
327
|
y={rect.y}
|
|
352
328
|
width={rect.width}
|
|
353
329
|
height={rect.height}
|
|
354
|
-
|
|
355
|
-
style:fill-opacity={debug ? 0.1 : 0}
|
|
356
|
-
stroke="red"
|
|
330
|
+
class={cls(debug ? 'fill-danger/10 stroke-danger' : 'fill-transparent')}
|
|
357
331
|
/>
|
|
358
332
|
{/each}
|
|
359
333
|
</g>
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
<script>import { createEventDispatcher, getContext } from 'svelte';
|
|
2
|
+
import { draw as _drawTransition } from 'svelte/transition';
|
|
3
|
+
import { Delaunay } from 'd3-delaunay';
|
|
4
|
+
import { min } from 'd3-array';
|
|
5
|
+
import { cls } from 'svelte-ux';
|
|
6
|
+
const { flatData, xGet, yGet, width, height } = getContext('LayerCake');
|
|
7
|
+
/** Override data instead of using context */
|
|
8
|
+
export let data = undefined;
|
|
9
|
+
export let classes = {};
|
|
10
|
+
const dispatch = createEventDispatcher();
|
|
11
|
+
$: points = (data ?? $flatData).map((d) => {
|
|
12
|
+
const xValue = $xGet(d);
|
|
13
|
+
const yValue = $yGet(d);
|
|
14
|
+
const x = Array.isArray(xValue) ? min(xValue) : xValue;
|
|
15
|
+
const y = Array.isArray(yValue) ? min(yValue) : yValue;
|
|
16
|
+
const point = [x, y];
|
|
17
|
+
point.data = d;
|
|
18
|
+
return point;
|
|
19
|
+
});
|
|
20
|
+
$: voronoi = Delaunay.from(points).voronoi([0, 0, Math.max($width, 0), Math.max($height, 0)]); // width and/or height can sometimes be negative (when loading data remotely and updately)
|
|
21
|
+
</script>
|
|
22
|
+
|
|
23
|
+
<g {...$$restProps} class={cls(classes.root, $$props.class)}>
|
|
24
|
+
{#each points as point, i}
|
|
25
|
+
<path
|
|
26
|
+
d={voronoi.renderCell(i)}
|
|
27
|
+
class={cls('fill-transparent', classes.path)}
|
|
28
|
+
on:mousemove={(e) => dispatch('mousemove', { point, event: e })}
|
|
29
|
+
on:mouseleave
|
|
30
|
+
on:click={(e) => dispatch('click', { point })}
|
|
31
|
+
/>
|
|
32
|
+
{/each}
|
|
33
|
+
</g>
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { SvelteComponentTyped } from "svelte";
|
|
2
|
+
declare const __propDef: {
|
|
3
|
+
props: {
|
|
4
|
+
[x: string]: any;
|
|
5
|
+
data?: any;
|
|
6
|
+
classes?: {
|
|
7
|
+
root?: string | undefined;
|
|
8
|
+
path?: string | undefined;
|
|
9
|
+
} | undefined;
|
|
10
|
+
};
|
|
11
|
+
events: {
|
|
12
|
+
mouseleave: MouseEvent;
|
|
13
|
+
click: CustomEvent<{
|
|
14
|
+
point: {
|
|
15
|
+
data: any;
|
|
16
|
+
};
|
|
17
|
+
}>;
|
|
18
|
+
mousemove: CustomEvent<{
|
|
19
|
+
point: {
|
|
20
|
+
data: any;
|
|
21
|
+
};
|
|
22
|
+
event: MouseEvent;
|
|
23
|
+
}>;
|
|
24
|
+
} & {
|
|
25
|
+
[evt: string]: CustomEvent<any>;
|
|
26
|
+
};
|
|
27
|
+
slots: {};
|
|
28
|
+
};
|
|
29
|
+
export type VoronoiProps = typeof __propDef.props;
|
|
30
|
+
export type VoronoiEvents = typeof __propDef.events;
|
|
31
|
+
export type VoronoiSlots = typeof __propDef.slots;
|
|
32
|
+
export default class Voronoi extends SvelteComponentTyped<VoronoiProps, VoronoiEvents, VoronoiSlots> {
|
|
33
|
+
}
|
|
34
|
+
export {};
|
|
@@ -7,7 +7,7 @@ declare const __propDef: {
|
|
|
7
7
|
spring?: boolean | Parameters<typeof motionStore>[1]['spring'];
|
|
8
8
|
tweened?: boolean | Parameters<typeof motionStore>[1]['tweened'];
|
|
9
9
|
disablePointer?: boolean | undefined;
|
|
10
|
-
scroll?: "
|
|
10
|
+
scroll?: "scale" | "translate" | "none" | undefined;
|
|
11
11
|
clickDistance?: number | undefined;
|
|
12
12
|
initialTranslate?: {
|
|
13
13
|
x: number;
|
|
@@ -47,4 +47,5 @@ export { default as TooltipItem } from './TooltipItem.svelte';
|
|
|
47
47
|
export { default as TooltipSeparator } from './TooltipSeparator.svelte';
|
|
48
48
|
export { default as Tree } from './Tree.svelte';
|
|
49
49
|
export { default as Treemap } from './Treemap.svelte';
|
|
50
|
+
export { default as Voronoi } from './Voronoi.svelte';
|
|
50
51
|
export { default as Zoom } from './Zoom.svelte';
|
package/dist/components/index.js
CHANGED
|
@@ -47,4 +47,5 @@ export { default as TooltipItem } from './TooltipItem.svelte';
|
|
|
47
47
|
export { default as TooltipSeparator } from './TooltipSeparator.svelte';
|
|
48
48
|
export { default as Tree } from './Tree.svelte';
|
|
49
49
|
export { default as Treemap } from './Treemap.svelte';
|
|
50
|
+
export { default as Voronoi } from './Voronoi.svelte';
|
|
50
51
|
export { default as Zoom } from './Zoom.svelte';
|
package/dist/utils/math.d.ts
CHANGED
|
@@ -6,3 +6,24 @@ export declare function degreesToRadians(degrees: number): number;
|
|
|
6
6
|
* Convert radians to degrees
|
|
7
7
|
*/
|
|
8
8
|
export declare function radiansToDegrees(radians: number): number;
|
|
9
|
+
/**
|
|
10
|
+
* Convert polar to cartesian coordinate system.
|
|
11
|
+
* see also: https://d3js.org/d3-shape/symbol#pointRadial
|
|
12
|
+
* @param angle - Angle in radians
|
|
13
|
+
* @param radius - Radius
|
|
14
|
+
*/
|
|
15
|
+
export declare function polarToCartesian(angle: number, radius: number): {
|
|
16
|
+
x: number;
|
|
17
|
+
y: number;
|
|
18
|
+
};
|
|
19
|
+
/**
|
|
20
|
+
* Convert cartesian to polar coordinate system. Angle in radians
|
|
21
|
+
*/
|
|
22
|
+
export declare function cartesianToPolar(x: number, y: number): {
|
|
23
|
+
radius: number;
|
|
24
|
+
angle: number;
|
|
25
|
+
};
|
|
26
|
+
/** Convert celsius temperature to fahrenheit */
|
|
27
|
+
export declare function celsiusToFahrenheit(temperature: number): number;
|
|
28
|
+
/** Convert fahrenheit temperature to celsius */
|
|
29
|
+
export declare function fahrenheitToCelsius(temperature: number): number;
|
package/dist/utils/math.js
CHANGED
|
@@ -10,3 +10,32 @@ export function degreesToRadians(degrees) {
|
|
|
10
10
|
export function radiansToDegrees(radians) {
|
|
11
11
|
return radians * (180 / Math.PI);
|
|
12
12
|
}
|
|
13
|
+
/**
|
|
14
|
+
* Convert polar to cartesian coordinate system.
|
|
15
|
+
* see also: https://d3js.org/d3-shape/symbol#pointRadial
|
|
16
|
+
* @param angle - Angle in radians
|
|
17
|
+
* @param radius - Radius
|
|
18
|
+
*/
|
|
19
|
+
export function polarToCartesian(angle, radius) {
|
|
20
|
+
return {
|
|
21
|
+
x: radius * Math.cos(angle),
|
|
22
|
+
y: radius * Math.sin(angle),
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Convert cartesian to polar coordinate system. Angle in radians
|
|
27
|
+
*/
|
|
28
|
+
export function cartesianToPolar(x, y) {
|
|
29
|
+
return {
|
|
30
|
+
radius: Math.sqrt(x ** 2 + y ** 2),
|
|
31
|
+
angle: Math.atan(y / x),
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
/** Convert celsius temperature to fahrenheit */
|
|
35
|
+
export function celsiusToFahrenheit(temperature) {
|
|
36
|
+
return temperature * (9 / 5) + 32;
|
|
37
|
+
}
|
|
38
|
+
/** Convert fahrenheit temperature to celsius */
|
|
39
|
+
export function fahrenheitToCelsius(temperature) {
|
|
40
|
+
return (temperature - 32) * (5 / 9);
|
|
41
|
+
}
|
package/package.json
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
"author": "Sean Lynch <techniq35@gmail.com>",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": "techniq/layerchart",
|
|
7
|
-
"version": "0.
|
|
7
|
+
"version": "0.31.0",
|
|
8
8
|
"devDependencies": {
|
|
9
9
|
"@changesets/cli": "^2.27.1",
|
|
10
10
|
"@mdi/js": "^7.4.47",
|
|
@@ -83,7 +83,7 @@
|
|
|
83
83
|
"lodash-es": "^4.17.21",
|
|
84
84
|
"posthog-js": "^1.105.8",
|
|
85
85
|
"shapefile": "^0.6.6",
|
|
86
|
-
"svelte-ux": "0.60
|
|
86
|
+
"svelte-ux": ">=0.60",
|
|
87
87
|
"topojson-client": "^3.1.0"
|
|
88
88
|
},
|
|
89
89
|
"peerDependencies": {
|