layerchart 0.54.0 → 0.54.1
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 +170 -144
- package/dist/components/Area.svelte +96 -67
- package/dist/components/Area.svelte.d.ts +1 -0
- package/dist/components/Axis.svelte +205 -155
- package/dist/components/Bar.svelte +72 -45
- package/dist/components/Bars.svelte +45 -34
- package/dist/components/Blur.svelte +5 -3
- package/dist/components/Bounds.svelte +37 -21
- package/dist/components/Brush.svelte +181 -110
- package/dist/components/Calendar.svelte +51 -38
- package/dist/components/Chart.svelte +295 -74
- package/dist/components/Chart.svelte.d.ts +17 -17
- package/dist/components/ChartClipPath.svelte +8 -5
- package/dist/components/ChartContext.svelte +243 -93
- package/dist/components/ChartContext.svelte.d.ts +15 -23
- package/dist/components/Circle.svelte +25 -16
- package/dist/components/CircleClipPath.svelte +16 -10
- package/dist/components/ClipPath.svelte +11 -7
- package/dist/components/ColorRamp.svelte +12 -10
- package/dist/components/ForceSimulation.svelte +185 -116
- package/dist/components/Frame.svelte +10 -6
- package/dist/components/GeoCircle.svelte +15 -9
- package/dist/components/GeoContext.svelte +109 -62
- package/dist/components/GeoEdgeFade.svelte +20 -14
- package/dist/components/GeoPath.svelte +107 -69
- package/dist/components/GeoPoint.svelte +32 -18
- package/dist/components/GeoSpline.svelte +30 -22
- package/dist/components/GeoTile.svelte +40 -30
- package/dist/components/GeoVisible.svelte +10 -7
- package/dist/components/Graticule.svelte +14 -8
- package/dist/components/Grid.svelte +75 -48
- package/dist/components/Group.svelte +43 -31
- package/dist/components/Highlight.svelte +284 -243
- package/dist/components/HitCanvas.svelte +75 -42
- package/dist/components/Hull.svelte +40 -20
- package/dist/components/Labels.svelte +81 -70
- package/dist/components/Legend.svelte +105 -74
- package/dist/components/Legend.svelte.d.ts +1 -1
- package/dist/components/Line.svelte +29 -19
- package/dist/components/LinearGradient.svelte +21 -15
- package/dist/components/Link.svelte +44 -22
- package/dist/components/MonthPath.svelte +23 -16
- package/dist/components/MotionPath.svelte +34 -25
- package/dist/components/Pack.svelte +21 -14
- package/dist/components/Partition.svelte +35 -20
- package/dist/components/Pattern.svelte +8 -6
- package/dist/components/Pie.svelte +76 -57
- package/dist/components/Point.svelte +11 -7
- package/dist/components/Points.svelte +178 -143
- package/dist/components/RadialGradient.svelte +25 -18
- package/dist/components/Rect.svelte +33 -19
- package/dist/components/RectClipPath.svelte +16 -11
- package/dist/components/Rule.svelte +50 -42
- package/dist/components/Sankey.svelte +55 -30
- package/dist/components/Spline.svelte +118 -96
- package/dist/components/Text.svelte +137 -104
- package/dist/components/Threshold.svelte +18 -7
- package/dist/components/TileImage.svelte +56 -50
- package/dist/components/TransformContext.svelte +235 -135
- package/dist/components/TransformControls.svelte +57 -29
- package/dist/components/TransformControls.svelte.d.ts +1 -1
- package/dist/components/Tree.svelte +33 -23
- package/dist/components/Treemap.svelte +69 -41
- package/dist/components/Voronoi.svelte +55 -28
- package/dist/components/charts/AreaChart.svelte +128 -77
- package/dist/components/charts/AreaChart.svelte.d.ts +1 -1
- package/dist/components/charts/BarChart.svelte +169 -104
- package/dist/components/charts/BarChart.svelte.d.ts +1 -1
- package/dist/components/charts/LineChart.svelte +87 -43
- package/dist/components/charts/LineChart.svelte.d.ts +1 -1
- package/dist/components/charts/PieChart.svelte +102 -52
- package/dist/components/charts/PieChart.svelte.d.ts +1 -1
- package/dist/components/charts/ScatterChart.svelte +73 -38
- package/dist/components/charts/ScatterChart.svelte.d.ts +1 -1
- package/dist/components/layout/Canvas.svelte +63 -43
- package/dist/components/layout/Html.svelte +28 -18
- package/dist/components/layout/Svg.svelte +47 -32
- package/dist/components/tooltip/Tooltip.svelte +137 -91
- package/dist/components/tooltip/Tooltip.svelte.d.ts +1 -1
- package/dist/components/tooltip/TooltipContext.svelte +315 -249
- package/dist/components/tooltip/TooltipHeader.svelte +9 -3
- package/dist/components/tooltip/TooltipItem.svelte +17 -9
- package/dist/components/tooltip/TooltipList.svelte +2 -1
- package/dist/components/tooltip/TooltipSeparator.svelte +3 -2
- package/dist/docs/Blockquote.svelte +4 -3
- package/dist/docs/Code.svelte +15 -8
- package/dist/docs/CurveMenuField.svelte +17 -12
- package/dist/docs/GeoDebug.svelte +13 -9
- package/dist/docs/Header1.svelte +2 -1
- package/dist/docs/Json.svelte +6 -4
- package/dist/docs/Layout.svelte +6 -6
- package/dist/docs/PathDataMenuField.svelte +52 -44
- package/dist/docs/Preview.svelte +39 -33
- package/dist/docs/TilesetField.svelte +80 -62
- package/dist/docs/TransformDebug.svelte +8 -5
- package/dist/docs/ViewSourceButton.svelte +13 -9
- package/dist/stores/motionStore.d.ts +1 -1
- package/dist/utils/scales.d.ts +3 -3
- package/package.json +29 -30
|
@@ -1,33 +1,55 @@
|
|
|
1
|
-
<script
|
|
2
|
-
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
// https://github.com/d3/d3-sankey
|
|
3
|
+
import { createEventDispatcher } from 'svelte';
|
|
4
|
+
import {
|
|
5
|
+
sankey as d3Sankey,
|
|
6
|
+
sankeyLeft,
|
|
7
|
+
sankeyCenter,
|
|
8
|
+
sankeyRight,
|
|
9
|
+
sankeyJustify,
|
|
10
|
+
type SankeyNode,
|
|
11
|
+
type SankeyLink,
|
|
12
|
+
} from 'd3-sankey';
|
|
13
|
+
|
|
14
|
+
import { chartContext } from './ChartContext.svelte';
|
|
15
|
+
|
|
16
|
+
const dispatch = createEventDispatcher();
|
|
17
|
+
|
|
18
|
+
const { data, width, height } = chartContext();
|
|
19
|
+
|
|
20
|
+
export let nodes = (d: any) => d.nodes;
|
|
21
|
+
export let nodeId = (d: any) => d.index;
|
|
22
|
+
/**
|
|
23
|
+
* see: https://github.com/d3/d3-sankey#alignments
|
|
24
|
+
*/
|
|
25
|
+
export let nodeAlign:
|
|
26
|
+
| ((node: SankeyNode<any, any>, n: number) => number)
|
|
27
|
+
| 'left'
|
|
28
|
+
| 'right'
|
|
29
|
+
| 'center'
|
|
30
|
+
| 'justify' = sankeyJustify;
|
|
31
|
+
export let nodeWidth = 4;
|
|
32
|
+
export let nodePadding = 10;
|
|
33
|
+
export let nodeSort = undefined;
|
|
34
|
+
|
|
35
|
+
export let links = (d: any) => d.links;
|
|
36
|
+
export let linkSort = undefined;
|
|
37
|
+
|
|
38
|
+
$: sankey = d3Sankey()
|
|
19
39
|
.size([$width, $height])
|
|
20
40
|
.nodes(nodes)
|
|
21
41
|
.nodeId(nodeId)
|
|
22
|
-
.nodeAlign(
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
42
|
+
.nodeAlign(
|
|
43
|
+
nodeAlign === 'left'
|
|
44
|
+
? sankeyLeft
|
|
45
|
+
: nodeAlign === 'center'
|
|
46
|
+
? sankeyCenter
|
|
47
|
+
: nodeAlign === 'right'
|
|
27
48
|
? sankeyRight
|
|
28
49
|
: nodeAlign === 'justify'
|
|
29
|
-
|
|
30
|
-
|
|
50
|
+
? sankeyJustify
|
|
51
|
+
: nodeAlign
|
|
52
|
+
)
|
|
31
53
|
.nodeWidth(nodeWidth)
|
|
32
54
|
.nodePadding(nodePadding)
|
|
33
55
|
// @ts-expect-error
|
|
@@ -35,11 +57,14 @@ $: sankey = d3Sankey()
|
|
|
35
57
|
.links(links)
|
|
36
58
|
// @ts-expect-error
|
|
37
59
|
.linkSort(linkSort);
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
$:
|
|
41
|
-
|
|
42
|
-
$:
|
|
60
|
+
|
|
61
|
+
// @ts-expect-error
|
|
62
|
+
$: sankeyData = sankey($data);
|
|
63
|
+
type NodeExtraProperties = Record<string, any>;
|
|
64
|
+
$: _nodes = sankeyData.nodes as SankeyNode<NodeExtraProperties, any>[];
|
|
65
|
+
$: _links = sankeyData.links as SankeyLink<NodeExtraProperties, any>[];
|
|
66
|
+
|
|
67
|
+
$: dispatch('update', sankeyData);
|
|
43
68
|
</script>
|
|
44
69
|
|
|
45
70
|
<slot nodes={_nodes} links={_links} />
|
|
@@ -1,115 +1,137 @@
|
|
|
1
|
-
<script>
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
import
|
|
13
|
-
import {
|
|
14
|
-
|
|
15
|
-
import {
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
/** Override
|
|
24
|
-
export let
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
/**
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { tick } from 'svelte';
|
|
3
|
+
import { writable } from 'svelte/store';
|
|
4
|
+
import { tweened as tweenedStore } from 'svelte/motion';
|
|
5
|
+
import { draw as _drawTransition } from 'svelte/transition';
|
|
6
|
+
import { cubicInOut } from 'svelte/easing';
|
|
7
|
+
|
|
8
|
+
import { line as d3Line, lineRadial } from 'd3-shape';
|
|
9
|
+
import type { CurveFactory, CurveFactoryLineOnly, Line } from 'd3-shape';
|
|
10
|
+
// import { interpolateString } from 'd3-interpolate';
|
|
11
|
+
import { interpolatePath } from 'd3-interpolate-path';
|
|
12
|
+
import { max } from 'd3-array';
|
|
13
|
+
import { cls } from '@layerstack/tailwind';
|
|
14
|
+
|
|
15
|
+
import { chartContext } from './ChartContext.svelte';
|
|
16
|
+
import Group from './Group.svelte';
|
|
17
|
+
import { motionStore } from '../stores/motionStore.js';
|
|
18
|
+
import { accessor, type Accessor } from '../utils/common.js';
|
|
19
|
+
import { isScaleBand } from '../utils/scales.js';
|
|
20
|
+
|
|
21
|
+
const { data: contextData, xScale, yScale, x: contextX, y: contextY, radial } = chartContext();
|
|
22
|
+
|
|
23
|
+
/** Override data instead of using context */
|
|
24
|
+
export let data: any = undefined;
|
|
25
|
+
|
|
26
|
+
/** Pass `<path d={...} />` explicitly instead of calculating from data / context */
|
|
27
|
+
export let pathData: string | undefined | null = undefined;
|
|
28
|
+
|
|
29
|
+
/** Override `x` accessor from Chart context */
|
|
30
|
+
export let x: Accessor = undefined;
|
|
31
|
+
/** Override `y` accessor from Chart context */
|
|
32
|
+
export let y: Accessor = undefined;
|
|
33
|
+
|
|
34
|
+
/** Interpolate path data using d3-interpolate-path. Works best without `draw` enabled */
|
|
35
|
+
export let tweened: boolean | Parameters<typeof tweenedStore>[1] = undefined;
|
|
36
|
+
/** Draw path over time. Works best without `tweened` enabled */
|
|
37
|
+
export let draw: boolean | Parameters<typeof _drawTransition>[1] = undefined;
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Curve of spline drawn. Imported via d3-shape.
|
|
41
|
+
*
|
|
42
|
+
* @example
|
|
43
|
+
* import { curveNatural } from 'd3-shape';
|
|
44
|
+
* <Spline curve={curveNatrual} />
|
|
45
|
+
*
|
|
46
|
+
* @type {CurveFactory | CurveFactoryLineOnly | undefined}
|
|
47
|
+
*/
|
|
48
|
+
export let curve: CurveFactory | CurveFactoryLineOnly | undefined = undefined;
|
|
49
|
+
export let defined: Parameters<Line<any>['defined']>[0] | undefined = undefined;
|
|
50
|
+
|
|
51
|
+
function getScaleValue(data: any, scale: typeof $xScale | typeof $yScale, accessor: Function) {
|
|
41
52
|
let value = accessor(data);
|
|
53
|
+
|
|
42
54
|
if (Array.isArray(value)) {
|
|
43
|
-
|
|
55
|
+
value = max(value);
|
|
44
56
|
}
|
|
57
|
+
|
|
45
58
|
if (scale.domain().length) {
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
return value;
|
|
59
|
+
// If scale is defined with domain, map value
|
|
60
|
+
return scale(value);
|
|
61
|
+
} else {
|
|
62
|
+
// Use raw value
|
|
63
|
+
return value;
|
|
52
64
|
}
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
const
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
const xAccessor = x ? accessor(x) : $contextX;
|
|
68
|
+
const yAccessor = y ? accessor(y) : $contextY;
|
|
69
|
+
|
|
70
|
+
$: xOffset = isScaleBand($xScale) ? $xScale.bandwidth() / 2 : 0;
|
|
71
|
+
$: yOffset = isScaleBand($yScale) ? $yScale.bandwidth() / 2 : 0;
|
|
72
|
+
|
|
73
|
+
let d: string | null = '';
|
|
74
|
+
// @ts-expect-error
|
|
75
|
+
$: tweenedOptions = tweened ? { interpolate: interpolatePath, ...tweened } : false;
|
|
76
|
+
$: tweened_d = motionStore('', { tweened: tweenedOptions });
|
|
77
|
+
$: {
|
|
63
78
|
const path = $radial
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
79
|
+
? lineRadial()
|
|
80
|
+
.angle((d) => getScaleValue(d, $xScale, xAccessor))
|
|
81
|
+
.radius((d) => getScaleValue(d, $yScale, yAccessor))
|
|
82
|
+
: d3Line()
|
|
83
|
+
.x((d) => getScaleValue(d, $xScale, xAccessor) + xOffset)
|
|
84
|
+
.y((d) => getScaleValue(d, $yScale, yAccessor) + yOffset);
|
|
85
|
+
|
|
70
86
|
path.defined(defined ?? ((d) => xAccessor(d) != null && yAccessor(d) != null));
|
|
71
|
-
|
|
72
|
-
|
|
87
|
+
|
|
88
|
+
if (curve) path.curve(curve);
|
|
89
|
+
|
|
73
90
|
d = pathData ?? path(data ?? $contextData) ?? '';
|
|
74
91
|
tweened_d.set(d);
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
$: drawTransition = draw ? _drawTransition : () => ({});
|
|
95
|
+
|
|
96
|
+
let key = Symbol();
|
|
97
|
+
$: if (draw) {
|
|
79
98
|
// Anytime the path data changes, redraw
|
|
80
99
|
$tweened_d;
|
|
81
100
|
key = Symbol();
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
let pathEl: SVGPathElement | undefined = undefined;
|
|
104
|
+
const startPoint = writable<DOMPoint | undefined>(undefined);
|
|
105
|
+
$: endPoint = motionStore<DOMPoint | undefined>(undefined, {
|
|
86
106
|
tweened: draw
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
107
|
+
? {
|
|
108
|
+
duration: (typeof draw === 'object' && draw.duration) || 800,
|
|
109
|
+
easing: (typeof draw === 'object' && draw.easing) || cubicInOut,
|
|
110
|
+
interpolate(a, b) {
|
|
111
|
+
return (t: number) => {
|
|
112
|
+
const totalLength = pathEl?.getTotalLength() ?? 0;
|
|
113
|
+
const point = pathEl?.getPointAtLength(totalLength * t);
|
|
114
|
+
return point;
|
|
115
|
+
};
|
|
116
|
+
},
|
|
97
117
|
}
|
|
98
|
-
|
|
99
|
-
});
|
|
100
|
-
|
|
118
|
+
: false,
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
$: {
|
|
101
122
|
if ($$slots.start || $$slots.end) {
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
}
|
|
123
|
+
// Wait for path data to update DOM, then update
|
|
124
|
+
d;
|
|
125
|
+
tick().then(() => {
|
|
126
|
+
if (pathEl) {
|
|
127
|
+
startPoint.set(pathEl.getPointAtLength(0));
|
|
128
|
+
|
|
129
|
+
const totalLength = pathEl.getTotalLength();
|
|
130
|
+
endPoint.set(pathEl.getPointAtLength(totalLength));
|
|
131
|
+
}
|
|
132
|
+
});
|
|
111
133
|
}
|
|
112
|
-
}
|
|
134
|
+
}
|
|
113
135
|
</script>
|
|
114
136
|
|
|
115
137
|
{#key key}
|
|
@@ -1,134 +1,167 @@
|
|
|
1
|
-
<script>
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
export let
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
export let
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
export let
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
export let
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
/**
|
|
41
|
-
export let
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
let
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
let
|
|
48
|
-
|
|
49
|
-
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { tick } from 'svelte';
|
|
3
|
+
import type { spring as springStore, tweened as tweenedStore } from 'svelte/motion';
|
|
4
|
+
import { cls } from '@layerstack/tailwind';
|
|
5
|
+
|
|
6
|
+
import { getStringWidth } from '../utils/string.js';
|
|
7
|
+
import { motionStore } from '../stores/motionStore.js';
|
|
8
|
+
|
|
9
|
+
/*
|
|
10
|
+
TODO:
|
|
11
|
+
- [ ] Handle styled text (use <slot /> to measure?)
|
|
12
|
+
- [ ] Simplify by using `alignment-baseline` / `dominant-baseline`, rework multiline or drop support, etc
|
|
13
|
+
- https://svelte.dev/repl/f12d3003313a43ba8a0be53e5786f1c7?version=3.44.3
|
|
14
|
+
- https://observablehq.com/@neocartocnrs/cheat-sheet-on-texts-in-svg
|
|
15
|
+
|
|
16
|
+
Reference:
|
|
17
|
+
- https://bl.ocks.org/mbostock/7555321
|
|
18
|
+
- https://github.com/airbnb/visx/blob/master/packages/visx-text/src/Text.tsx
|
|
19
|
+
- https://airbnb.io/visx/text
|
|
20
|
+
- https://github.com/airbnb/visx/blob/master/packages/visx-demo/src/pages/text.tsx
|
|
21
|
+
*/
|
|
22
|
+
|
|
23
|
+
/** text value */
|
|
24
|
+
export let value: string | number = 0;
|
|
25
|
+
|
|
26
|
+
/** Maximum width to occupy (approximate as words are not split) */
|
|
27
|
+
export let width: number | undefined = undefined;
|
|
28
|
+
|
|
29
|
+
/** x position of the text */
|
|
30
|
+
export let x: string | number = 0;
|
|
31
|
+
export let initialX = x;
|
|
32
|
+
|
|
33
|
+
/** y position of the text */
|
|
34
|
+
export let y: string | number = 0;
|
|
35
|
+
export let initialY = y;
|
|
36
|
+
|
|
37
|
+
/** dx offset of the text */
|
|
38
|
+
export let dx: string | number = 0;
|
|
39
|
+
|
|
40
|
+
/** dy offset of the text */
|
|
41
|
+
export let dy: string | number = 0;
|
|
42
|
+
|
|
43
|
+
/** Desired "line height" of the text, implemented as y offsets */
|
|
44
|
+
export let lineHeight = '1em';
|
|
45
|
+
|
|
46
|
+
/** Cap height of the text */
|
|
47
|
+
export let capHeight = '0.71em'; // Magic number from d3
|
|
48
|
+
|
|
49
|
+
/** Whether to scale the fontSize to accommodate the specified width */
|
|
50
|
+
export let scaleToFit: boolean = false;
|
|
51
|
+
|
|
52
|
+
/** Horizontal text anchor */
|
|
53
|
+
export let textAnchor: 'start' | 'middle' | 'end' | 'inherit' = 'start';
|
|
54
|
+
|
|
55
|
+
/** Vertical text anchor */
|
|
56
|
+
export let verticalAnchor: 'start' | 'middle' | 'end' | 'inherit' = 'end'; // default SVG behavior
|
|
57
|
+
|
|
58
|
+
/** Rotational angle of the text */
|
|
59
|
+
export let rotate: number | undefined = undefined;
|
|
60
|
+
|
|
61
|
+
let wordsByLines: { words: string[]; width?: number }[] = [];
|
|
62
|
+
let wordsWithWidth: { word: string; width: number }[] = [];
|
|
63
|
+
let spaceWidth: number = 0;
|
|
64
|
+
|
|
65
|
+
let style: CSSStyleDeclaration | undefined = undefined; // TODO: read from DOM?
|
|
66
|
+
|
|
67
|
+
$: words = value != null ? value.toString().split(/(?:(?!\u00A0+)\s+)/) : [];
|
|
68
|
+
|
|
69
|
+
$: wordsWithWidth = words.map((word) => ({
|
|
50
70
|
word,
|
|
51
71
|
width: getStringWidth(word, style) || 0,
|
|
52
|
-
}));
|
|
53
|
-
|
|
54
|
-
$:
|
|
72
|
+
}));
|
|
73
|
+
|
|
74
|
+
$: spaceWidth = getStringWidth('\u00A0', style) || 0;
|
|
75
|
+
|
|
76
|
+
$: wordsByLines = wordsWithWidth.reduce((result: typeof wordsByLines, item) => {
|
|
55
77
|
const currentLine = result[result.length - 1];
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
78
|
+
|
|
79
|
+
if (
|
|
80
|
+
currentLine &&
|
|
81
|
+
(width == null || scaleToFit || (currentLine.width || 0) + item.width + spaceWidth < width)
|
|
82
|
+
) {
|
|
83
|
+
// Word can be added to an existing line
|
|
84
|
+
currentLine.words.push(item.word);
|
|
85
|
+
currentLine.width = currentLine.width || 0;
|
|
86
|
+
currentLine.width += item.width + spaceWidth;
|
|
87
|
+
} else {
|
|
88
|
+
// Add first word to line or word is too long to scaleToFit on existing line
|
|
89
|
+
const newLine = { words: [item.word], width: item.width };
|
|
90
|
+
result.push(newLine);
|
|
67
91
|
}
|
|
92
|
+
|
|
68
93
|
return result;
|
|
69
|
-
}, []);
|
|
70
|
-
$: lines = wordsByLines.length;
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
94
|
+
}, []);
|
|
95
|
+
$: lines = wordsByLines.length;
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Convert css value to pixel value (ex. 0.71em => 11.36)
|
|
99
|
+
*/
|
|
100
|
+
function getPixelValue(cssValue: string) {
|
|
75
101
|
// TODO: Properly measure pixel values using DOM (handle inherited font size, zoom, etc)
|
|
76
102
|
// @ts-expect-error
|
|
77
103
|
const [match, value, units] = cssValue.match(/([\d.]+)(\D+)/);
|
|
78
104
|
const number = Number(value);
|
|
79
105
|
switch (units) {
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
106
|
+
case 'px':
|
|
107
|
+
return number;
|
|
108
|
+
case 'em':
|
|
109
|
+
case 'rem':
|
|
110
|
+
return number * 16;
|
|
111
|
+
default:
|
|
112
|
+
return 0;
|
|
87
113
|
}
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
let startDy = 0;
|
|
117
|
+
$: if (verticalAnchor === 'start') {
|
|
91
118
|
startDy = getPixelValue(capHeight);
|
|
92
|
-
}
|
|
93
|
-
else if (verticalAnchor === 'middle') {
|
|
119
|
+
} else if (verticalAnchor === 'middle') {
|
|
94
120
|
startDy = ((lines - 1) / 2) * -getPixelValue(lineHeight) + getPixelValue(capHeight) / 2;
|
|
95
|
-
}
|
|
96
|
-
else {
|
|
121
|
+
} else {
|
|
97
122
|
startDy = (lines - 1) * -getPixelValue(lineHeight);
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
let scaleTransform = '';
|
|
126
|
+
$: if (
|
|
127
|
+
scaleToFit &&
|
|
101
128
|
lines > 0 &&
|
|
102
129
|
typeof x == 'number' &&
|
|
103
130
|
typeof y == 'number' &&
|
|
104
|
-
typeof width == 'number'
|
|
131
|
+
typeof width == 'number'
|
|
132
|
+
) {
|
|
105
133
|
const lineWidth = wordsByLines[0].width || 1;
|
|
106
134
|
const sx = width / lineWidth;
|
|
107
135
|
const sy = sx;
|
|
108
136
|
const originX = x - sx * x;
|
|
109
137
|
const originY = y - sy * y;
|
|
110
138
|
scaleTransform = `matrix(${sx}, 0, 0, ${sy}, ${originX}, ${originY})`;
|
|
111
|
-
}
|
|
112
|
-
else {
|
|
139
|
+
} else {
|
|
113
140
|
scaleTransform = '';
|
|
114
|
-
}
|
|
115
|
-
$: rotateTransform = rotate ? `rotate(${rotate}, ${x}, ${y})` : '';
|
|
116
|
-
|
|
117
|
-
|
|
141
|
+
}
|
|
142
|
+
$: rotateTransform = rotate ? `rotate(${rotate}, ${x}, ${y})` : '';
|
|
143
|
+
|
|
144
|
+
$: transform = `${scaleTransform} ${rotateTransform}`;
|
|
145
|
+
|
|
146
|
+
function isValidXOrY(xOrY: string | number | undefined) {
|
|
118
147
|
return (
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
let
|
|
127
|
-
let
|
|
128
|
-
|
|
148
|
+
// number that is not NaN or Infinity
|
|
149
|
+
(typeof xOrY === 'number' && Number.isFinite(xOrY)) ||
|
|
150
|
+
// for percentage
|
|
151
|
+
typeof xOrY === 'string'
|
|
152
|
+
);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
export let spring: boolean | Parameters<typeof springStore>[1] = undefined;
|
|
156
|
+
export let tweened: boolean | Parameters<typeof tweenedStore>[1] = undefined;
|
|
157
|
+
|
|
158
|
+
let tweened_x = motionStore(initialX, { spring, tweened });
|
|
159
|
+
let tweened_y = motionStore(initialY, { spring, tweened });
|
|
160
|
+
|
|
161
|
+
$: tick().then(() => {
|
|
129
162
|
tweened_x.set(x);
|
|
130
163
|
tweened_y.set(y);
|
|
131
|
-
});
|
|
164
|
+
});
|
|
132
165
|
</script>
|
|
133
166
|
|
|
134
167
|
<!-- `overflow: visible` allow contents to be shown outside element -->
|
|
@@ -1,10 +1,21 @@
|
|
|
1
|
-
<script>
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
/*
|
|
3
|
+
See also:
|
|
4
|
+
- https://observablehq.com/@d3/difference-chart
|
|
5
|
+
- https://github.com/airbnb/visx/issues/245
|
|
6
|
+
*/
|
|
7
|
+
import type { ComponentProps } from 'svelte';
|
|
8
|
+
import type { CurveFactory } from 'd3-shape';
|
|
9
|
+
import { min } from 'd3-array';
|
|
10
|
+
|
|
11
|
+
import { chartContext } from './ChartContext.svelte';
|
|
12
|
+
import Area from './Area.svelte';
|
|
13
|
+
import ClipPath from './ClipPath.svelte';
|
|
14
|
+
|
|
15
|
+
const { y, yDomain } = chartContext();
|
|
16
|
+
|
|
17
|
+
export let curve: CurveFactory | undefined = undefined;
|
|
18
|
+
export let defined: ComponentProps<Area>['defined'] | undefined = undefined;
|
|
8
19
|
</script>
|
|
9
20
|
|
|
10
21
|
<!-- Recreate on curve change as otherwise is 1 state change behind for some reason -->
|