layerchart 0.13.3 → 0.14.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/{components → dist/components}/AxisX.svelte.d.ts +1 -2
- package/{components → dist/components}/AxisY.svelte.d.ts +1 -2
- package/dist/components/Blur.svelte +16 -0
- package/dist/components/Blur.svelte.d.ts +21 -0
- package/{components → dist/components}/Chart.svelte +31 -8
- package/{components → dist/components}/Chart.svelte.d.ts +6 -1
- package/{components → dist/components}/ChartClipPath.svelte.d.ts +1 -1
- package/dist/components/ClipPathUse.svelte +17 -0
- package/dist/components/ClipPathUse.svelte.d.ts +27 -0
- package/dist/components/ColorRamp.svelte +19 -0
- package/dist/components/ColorRamp.svelte.d.ts +20 -0
- package/dist/components/GeoContext.svelte +55 -0
- package/dist/components/GeoContext.svelte.d.ts +40 -0
- package/dist/components/GeoPath.svelte +56 -0
- package/dist/components/GeoPath.svelte.d.ts +36 -0
- package/dist/components/GeoPoint.svelte +28 -0
- package/dist/components/GeoPoint.svelte.d.ts +23 -0
- package/dist/components/GeoTile.svelte +47 -0
- package/dist/components/GeoTile.svelte.d.ts +24 -0
- package/dist/components/Graticule.svelte +26 -0
- package/dist/components/Graticule.svelte.d.ts +21 -0
- package/{components → dist/components}/Labels.svelte.d.ts +3 -5
- package/dist/components/Legend.svelte +163 -0
- package/dist/components/Legend.svelte.d.ts +32 -0
- package/dist/components/TileImage.svelte +84 -0
- package/dist/components/TileImage.svelte.d.ts +24 -0
- package/{components → dist/components}/Tooltip.svelte +9 -11
- package/{components → dist/components}/TooltipContext.svelte +7 -1
- package/{components → dist/components}/TooltipContext.svelte.d.ts +1 -0
- package/{components → dist/components}/TooltipItem.svelte.d.ts +1 -2
- package/{components → dist/components}/Treemap.svelte.d.ts +1 -1
- package/dist/components/Zoom.svelte +185 -0
- package/{components → dist/components}/Zoom.svelte.d.ts +36 -9
- package/{components → dist/components}/index.d.ts +9 -0
- package/{components → dist/components}/index.js +9 -0
- package/dist/docs/GeoDebug.svelte +43 -0
- package/dist/docs/GeoDebug.svelte.d.ts +16 -0
- package/{docs → dist/docs}/Header1.svelte.d.ts +2 -2
- package/{docs → dist/docs}/Layout.svelte.d.ts +3 -3
- package/{docs → dist/docs}/Link.svelte.d.ts +2 -2
- package/{docs → dist/docs}/Preview.svelte +1 -7
- package/dist/docs/RangeField.svelte +18 -0
- package/dist/docs/RangeField.svelte.d.ts +20 -0
- package/dist/docs/TilesetField.svelte +93 -0
- package/dist/docs/TilesetField.svelte.d.ts +17 -0
- package/dist/docs/ZoomControls.svelte +50 -0
- package/dist/docs/ZoomControls.svelte.d.ts +19 -0
- package/{utils → dist/utils}/event.js +1 -1
- package/{utils → dist/utils}/ticks.d.ts +3 -3
- package/package.json +88 -123
- package/components/Legend.svelte +0 -17
- package/components/Legend.svelte.d.ts +0 -23
- package/components/Zoom.svelte +0 -133
- /package/{components → dist/components}/Arc.svelte +0 -0
- /package/{components → dist/components}/Arc.svelte.d.ts +0 -0
- /package/{components → dist/components}/Area.svelte +0 -0
- /package/{components → dist/components}/Area.svelte.d.ts +0 -0
- /package/{components → dist/components}/AreaStack.svelte +0 -0
- /package/{components → dist/components}/AreaStack.svelte.d.ts +0 -0
- /package/{components → dist/components}/AxisX.svelte +0 -0
- /package/{components → dist/components}/AxisY.svelte +0 -0
- /package/{components → dist/components}/Bars.svelte +0 -0
- /package/{components → dist/components}/Bars.svelte.d.ts +0 -0
- /package/{components → dist/components}/Baseline.svelte +0 -0
- /package/{components → dist/components}/Baseline.svelte.d.ts +0 -0
- /package/{components → dist/components}/Bounds.svelte +0 -0
- /package/{components → dist/components}/Bounds.svelte.d.ts +0 -0
- /package/{components → dist/components}/ChartClipPath.svelte +0 -0
- /package/{components → dist/components}/Circle.svelte +0 -0
- /package/{components → dist/components}/Circle.svelte.d.ts +0 -0
- /package/{components → dist/components}/CircleClipPath.svelte +0 -0
- /package/{components → dist/components}/CircleClipPath.svelte.d.ts +0 -0
- /package/{components → dist/components}/ClipPath.svelte +0 -0
- /package/{components → dist/components}/ClipPath.svelte.d.ts +0 -0
- /package/{components → dist/components}/ConnectedPoints.svelte +0 -0
- /package/{components → dist/components}/ConnectedPoints.svelte.d.ts +0 -0
- /package/{components → dist/components}/Group.svelte +0 -0
- /package/{components → dist/components}/Group.svelte.d.ts +0 -0
- /package/{components → dist/components}/HighlightLine.svelte +0 -0
- /package/{components → dist/components}/HighlightLine.svelte.d.ts +0 -0
- /package/{components → dist/components}/HighlightRect.svelte +0 -0
- /package/{components → dist/components}/HighlightRect.svelte.d.ts +0 -0
- /package/{components → dist/components}/Labels.svelte +0 -0
- /package/{components → dist/components}/Line.svelte +0 -0
- /package/{components → dist/components}/Line.svelte.d.ts +0 -0
- /package/{components → dist/components}/LinearGradient.svelte +0 -0
- /package/{components → dist/components}/LinearGradient.svelte.d.ts +0 -0
- /package/{components → dist/components}/Link.svelte +0 -0
- /package/{components → dist/components}/Link.svelte.d.ts +0 -0
- /package/{components → dist/components}/Pack.svelte +0 -0
- /package/{components → dist/components}/Pack.svelte.d.ts +0 -0
- /package/{components → dist/components}/Partition.svelte +0 -0
- /package/{components → dist/components}/Partition.svelte.d.ts +0 -0
- /package/{components → dist/components}/Path.svelte +0 -0
- /package/{components → dist/components}/Path.svelte.d.ts +0 -0
- /package/{components → dist/components}/Pattern.svelte +0 -0
- /package/{components → dist/components}/Pattern.svelte.d.ts +0 -0
- /package/{components → dist/components}/Pie.svelte +0 -0
- /package/{components → dist/components}/Pie.svelte.d.ts +0 -0
- /package/{components → dist/components}/Points.svelte +0 -0
- /package/{components → dist/components}/Points.svelte.d.ts +0 -0
- /package/{components → dist/components}/Rect.svelte +0 -0
- /package/{components → dist/components}/RectClipPath.svelte +0 -0
- /package/{components → dist/components}/RectClipPath.svelte.d.ts +0 -0
- /package/{components → dist/components}/Sankey.svelte +0 -0
- /package/{components → dist/components}/Sankey.svelte.d.ts +0 -0
- /package/{components → dist/components}/Text.svelte +0 -0
- /package/{components → dist/components}/Text.svelte.d.ts +0 -0
- /package/{components → dist/components}/Threshold.svelte +0 -0
- /package/{components → dist/components}/Threshold.svelte.d.ts +0 -0
- /package/{components → dist/components}/Tooltip.svelte.d.ts +0 -0
- /package/{components → dist/components}/TooltipItem.svelte +0 -0
- /package/{components → dist/components}/TooltipSeparator.svelte +0 -0
- /package/{components → dist/components}/TooltipSeparator.svelte.d.ts +0 -0
- /package/{components → dist/components}/Tree.svelte +0 -0
- /package/{components → dist/components}/Tree.svelte.d.ts +0 -0
- /package/{components → dist/components}/Treemap.svelte +0 -0
- /package/{docs → dist/docs}/Blockquote.svelte +0 -0
- /package/{docs → dist/docs}/Blockquote.svelte.d.ts +0 -0
- /package/{docs → dist/docs}/Code.svelte +0 -0
- /package/{docs → dist/docs}/Code.svelte.d.ts +0 -0
- /package/{docs → dist/docs}/Header1.svelte +0 -0
- /package/{docs → dist/docs}/Layout.svelte +0 -0
- /package/{docs → dist/docs}/Link.svelte +0 -0
- /package/{docs → dist/docs}/Preview.svelte.d.ts +0 -0
- /package/{index.d.ts → dist/index.d.ts} +0 -0
- /package/{index.js → dist/index.js} +0 -0
- /package/{stores → dist/stores}/motionStore.d.ts +0 -0
- /package/{stores → dist/stores}/motionStore.js +0 -0
- /package/{utils → dist/utils}/event.d.ts +0 -0
- /package/{utils → dist/utils}/genData.d.ts +0 -0
- /package/{utils → dist/utils}/genData.js +0 -0
- /package/{utils → dist/utils}/graph.d.ts +0 -0
- /package/{utils → dist/utils}/graph.js +0 -0
- /package/{utils → dist/utils}/hierarchy.d.ts +0 -0
- /package/{utils → dist/utils}/hierarchy.js +0 -0
- /package/{utils → dist/utils}/index.d.ts +0 -0
- /package/{utils → dist/utils}/index.js +0 -0
- /package/{utils → dist/utils}/math.d.ts +0 -0
- /package/{utils → dist/utils}/math.js +0 -0
- /package/{utils → dist/utils}/path.d.ts +0 -0
- /package/{utils → dist/utils}/path.js +0 -0
- /package/{utils → dist/utils}/pivot.d.ts +0 -0
- /package/{utils → dist/utils}/pivot.js +0 -0
- /package/{utils → dist/utils}/quadtree.d.ts +0 -0
- /package/{utils → dist/utils}/quadtree.js +0 -0
- /package/{utils → dist/utils}/scales.d.ts +0 -0
- /package/{utils → dist/utils}/scales.js +0 -0
- /package/{utils → dist/utils}/stack.d.ts +0 -0
- /package/{utils → dist/utils}/stack.js +0 -0
- /package/{utils → dist/utils}/string.d.ts +0 -0
- /package/{utils → dist/utils}/string.js +0 -0
- /package/{utils → dist/utils}/ticks.js +0 -0
- /package/{utils → dist/utils}/treemap.d.ts +0 -0
- /package/{utils → dist/utils}/treemap.js +0 -0
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
<script>import { getContext } from 'svelte';
|
|
2
|
+
import { scaleBand, scaleLinear } from 'd3-scale';
|
|
3
|
+
import { quantize, interpolate, interpolateRound } from 'd3-interpolate';
|
|
4
|
+
import { quantile, range } from 'd3-array';
|
|
5
|
+
import { format } from 'svelte-ux/utils/format';
|
|
6
|
+
import ColorRamp from './ColorRamp.svelte';
|
|
7
|
+
import { cls } from 'svelte-ux/utils/styles';
|
|
8
|
+
const { rScale } = getContext('LayerCake') ?? {};
|
|
9
|
+
export let scale = undefined;
|
|
10
|
+
export let title = '';
|
|
11
|
+
export let width = 320;
|
|
12
|
+
export let height = 10;
|
|
13
|
+
export let ticks = width / 64;
|
|
14
|
+
export let tickFormat;
|
|
15
|
+
export let tickValues;
|
|
16
|
+
export let tickFontSize = 10;
|
|
17
|
+
export let tickSize = 4;
|
|
18
|
+
export let placement = undefined;
|
|
19
|
+
export let classes = {};
|
|
20
|
+
$: if (scale == null && rScale) {
|
|
21
|
+
// Read scale from chart context
|
|
22
|
+
scale = $rScale;
|
|
23
|
+
}
|
|
24
|
+
let xScale;
|
|
25
|
+
let interpolator;
|
|
26
|
+
let swatches;
|
|
27
|
+
let tickLabelOffset = 0;
|
|
28
|
+
let tickLine = true;
|
|
29
|
+
$: if (!scale) {
|
|
30
|
+
// do nothing
|
|
31
|
+
}
|
|
32
|
+
else if (scale.interpolate) {
|
|
33
|
+
// Continuous
|
|
34
|
+
const n = Math.min(scale.domain().length, scale.range().length);
|
|
35
|
+
xScale = scale.copy().rangeRound(quantize(interpolate(0, width), n));
|
|
36
|
+
interpolator = scale.copy().domain(quantize(interpolate(0, 1), n));
|
|
37
|
+
tickFormat = tickFormat ?? xScale.tickFormat?.();
|
|
38
|
+
}
|
|
39
|
+
else if (scale.interpolator) {
|
|
40
|
+
// Sequential
|
|
41
|
+
xScale = Object.assign(scale.copy().interpolator(interpolateRound(0, width)), {
|
|
42
|
+
range() {
|
|
43
|
+
return [0, width];
|
|
44
|
+
}
|
|
45
|
+
});
|
|
46
|
+
interpolator = scale.interpolator();
|
|
47
|
+
// scaleSequentialQuantile doesn’t implement ticks or tickFormat.
|
|
48
|
+
if (!xScale.ticks) {
|
|
49
|
+
if (tickValues === undefined) {
|
|
50
|
+
const n = Math.round(ticks + 1);
|
|
51
|
+
tickValues = range(n).map((i) => quantile(scale.domain(), i / (n - 1)));
|
|
52
|
+
}
|
|
53
|
+
// if (typeof tickFormat !== "function") {
|
|
54
|
+
// tickFormat = d3.format(tickFormat === undefined ? ",f" : tickFormat);
|
|
55
|
+
// }
|
|
56
|
+
}
|
|
57
|
+
tickFormat = tickFormat ?? xScale.tickFormat?.();
|
|
58
|
+
}
|
|
59
|
+
else if (scale.invertExtent) {
|
|
60
|
+
// Threshold
|
|
61
|
+
const thresholds = scale.thresholds
|
|
62
|
+
? scale.thresholds() // scaleQuantize
|
|
63
|
+
: scale.quantiles
|
|
64
|
+
? scale.quantiles() // scaleQuantile
|
|
65
|
+
: scale.domain(); // scaleThreshold
|
|
66
|
+
xScale = scaleLinear()
|
|
67
|
+
.domain([-1, scale.range().length - 1])
|
|
68
|
+
.rangeRound([0, width]);
|
|
69
|
+
swatches = scale.range().map((d, i) => {
|
|
70
|
+
return {
|
|
71
|
+
x: xScale(i - 1),
|
|
72
|
+
y: 0,
|
|
73
|
+
width: xScale(i) - xScale(i - 1),
|
|
74
|
+
height,
|
|
75
|
+
fill: d
|
|
76
|
+
};
|
|
77
|
+
});
|
|
78
|
+
tickValues = range(thresholds.length);
|
|
79
|
+
tickFormat = (i) => {
|
|
80
|
+
const value = thresholds[i];
|
|
81
|
+
return $$props.tickFormat ? format(value, $$props.tickFormat) : value;
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
else {
|
|
85
|
+
// Ordinal
|
|
86
|
+
console.log({ title });
|
|
87
|
+
xScale = scaleBand().domain(scale.domain()).rangeRound([0, width]);
|
|
88
|
+
swatches = scale.domain().map((d) => {
|
|
89
|
+
return {
|
|
90
|
+
x: xScale(d),
|
|
91
|
+
y: 0,
|
|
92
|
+
width: Math.max(0, xScale.bandwidth() - 1),
|
|
93
|
+
height,
|
|
94
|
+
fill: scale(d)
|
|
95
|
+
};
|
|
96
|
+
});
|
|
97
|
+
tickValues = scale.domain();
|
|
98
|
+
tickLabelOffset = xScale.bandwidth() / 2;
|
|
99
|
+
tickLine = false;
|
|
100
|
+
tickSize = 0;
|
|
101
|
+
}
|
|
102
|
+
</script>
|
|
103
|
+
|
|
104
|
+
<div
|
|
105
|
+
class={cls(
|
|
106
|
+
'inline-block',
|
|
107
|
+
{
|
|
108
|
+
'top-left': 'absolute top-0 left-0',
|
|
109
|
+
top: 'absolute top-0 left-1/2 -translate-x-1/2',
|
|
110
|
+
'top-right': 'absolute top-0 right-0',
|
|
111
|
+
left: 'absolute top-1/2 left-0 -translate-y-1/2',
|
|
112
|
+
center: 'absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2',
|
|
113
|
+
right: 'absolute top-1/2 right-0 -translate-y-1/2',
|
|
114
|
+
'bottom-left': 'absolute bottom-0 left-0',
|
|
115
|
+
bottom: 'absolute bottom-0 left-1/2 -translate-x-1/2',
|
|
116
|
+
'bottom-right': 'absolute bottom-0 right-0'
|
|
117
|
+
}[placement],
|
|
118
|
+
classes.root
|
|
119
|
+
)}
|
|
120
|
+
{...$$restProps}
|
|
121
|
+
>
|
|
122
|
+
<div class={cls('text-[10px] font-semibold', classes.title)}>{title}</div>
|
|
123
|
+
<svg
|
|
124
|
+
{width}
|
|
125
|
+
height={height + tickSize + tickFontSize}
|
|
126
|
+
viewBox="0 0 {width} {height + tickSize + tickFontSize}"
|
|
127
|
+
class="overflow-visible"
|
|
128
|
+
>
|
|
129
|
+
<g>
|
|
130
|
+
{#if interpolator}
|
|
131
|
+
<ColorRamp {width} {height} {interpolator} />
|
|
132
|
+
{:else if swatches}
|
|
133
|
+
{#each swatches as swatch, i}
|
|
134
|
+
<rect {...swatch} />
|
|
135
|
+
{/each}
|
|
136
|
+
{/if}
|
|
137
|
+
</g>
|
|
138
|
+
|
|
139
|
+
<g>
|
|
140
|
+
{#each tickValues ?? xScale?.ticks?.(ticks) ?? [] as tick, i}
|
|
141
|
+
<text
|
|
142
|
+
text-anchor="middle"
|
|
143
|
+
x={xScale(tick) + tickLabelOffset}
|
|
144
|
+
y={height + tickSize + tickFontSize}
|
|
145
|
+
style:font-size={tickFontSize}
|
|
146
|
+
class={classes.label}
|
|
147
|
+
>
|
|
148
|
+
{tickFormat ? format(tick, tickFormat) : tick}
|
|
149
|
+
</text>
|
|
150
|
+
|
|
151
|
+
{#if tickLine}
|
|
152
|
+
<line
|
|
153
|
+
x1={xScale(tick)}
|
|
154
|
+
y1={0}
|
|
155
|
+
x2={xScale(tick)}
|
|
156
|
+
y2={height + tickSize}
|
|
157
|
+
class={cls('stroke-black', classes.tick)}
|
|
158
|
+
/>
|
|
159
|
+
{/if}
|
|
160
|
+
{/each}
|
|
161
|
+
</g>
|
|
162
|
+
</svg>
|
|
163
|
+
</div>
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { SvelteComponentTyped } from "svelte";
|
|
2
|
+
declare const __propDef: {
|
|
3
|
+
props: {
|
|
4
|
+
[x: string]: any;
|
|
5
|
+
scale?: any;
|
|
6
|
+
title?: string | undefined;
|
|
7
|
+
width?: number | undefined;
|
|
8
|
+
height?: number | undefined;
|
|
9
|
+
ticks?: number | undefined;
|
|
10
|
+
tickFormat: FormatType;
|
|
11
|
+
tickValues: any[];
|
|
12
|
+
tickFontSize?: number | undefined;
|
|
13
|
+
tickSize?: number | undefined;
|
|
14
|
+
placement?: ("left" | "right" | "top" | "center" | "top-left" | "top-right" | "bottom-left" | "bottom" | "bottom-right") | undefined;
|
|
15
|
+
classes?: {
|
|
16
|
+
root?: string | undefined;
|
|
17
|
+
title?: string | undefined;
|
|
18
|
+
label?: string | undefined;
|
|
19
|
+
tick?: string | undefined;
|
|
20
|
+
} | undefined;
|
|
21
|
+
};
|
|
22
|
+
events: {
|
|
23
|
+
[evt: string]: CustomEvent<any>;
|
|
24
|
+
};
|
|
25
|
+
slots: {};
|
|
26
|
+
};
|
|
27
|
+
export type LegendProps = typeof __propDef.props;
|
|
28
|
+
export type LegendEvents = typeof __propDef.events;
|
|
29
|
+
export type LegendSlots = typeof __propDef.slots;
|
|
30
|
+
export default class Legend extends SvelteComponentTyped<LegendProps, LegendEvents, LegendSlots> {
|
|
31
|
+
}
|
|
32
|
+
export {};
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
<script context="module">"use strict";
|
|
2
|
+
let tileCache = new Map();
|
|
3
|
+
</script>
|
|
4
|
+
|
|
5
|
+
<script>import Text from './Text.svelte';
|
|
6
|
+
export let x;
|
|
7
|
+
export let y;
|
|
8
|
+
export let z;
|
|
9
|
+
/** translate x */
|
|
10
|
+
export let tx;
|
|
11
|
+
/** scale */
|
|
12
|
+
export let ty;
|
|
13
|
+
export let k;
|
|
14
|
+
export let disableCache = false;
|
|
15
|
+
export let debug = false;
|
|
16
|
+
export let url;
|
|
17
|
+
// if disable cache, set href immediately, otherwise set from cache / dataUri
|
|
18
|
+
let href = disableCache ? url(x, y, z) : '';
|
|
19
|
+
function loadImage(url) {
|
|
20
|
+
// const key = [x, y, z].join('-');
|
|
21
|
+
const key = url;
|
|
22
|
+
if (tileCache.has(key)) {
|
|
23
|
+
tileCache.get(key)?.then((dataUri) => {
|
|
24
|
+
// console.log('from cache', { x, y, z });
|
|
25
|
+
href = dataUri;
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
else {
|
|
29
|
+
const promise = new Promise((resolve, reject) => {
|
|
30
|
+
const img = new Image();
|
|
31
|
+
img.crossOrigin = 'anonymous';
|
|
32
|
+
img.onload = function () {
|
|
33
|
+
var canvas = document.createElement('canvas');
|
|
34
|
+
var context = canvas.getContext('2d');
|
|
35
|
+
canvas.height = this.naturalHeight;
|
|
36
|
+
canvas.width = this.naturalWidth;
|
|
37
|
+
context.drawImage(this, 0, 0);
|
|
38
|
+
var dataUri = canvas.toDataURL('image/jpeg');
|
|
39
|
+
// console.log('from load', { x, y, z });
|
|
40
|
+
href = dataUri;
|
|
41
|
+
resolve(dataUri);
|
|
42
|
+
};
|
|
43
|
+
img.onerror = (err) => {
|
|
44
|
+
cache.delete(key);
|
|
45
|
+
reject(err);
|
|
46
|
+
};
|
|
47
|
+
img.src = url;
|
|
48
|
+
});
|
|
49
|
+
tileCache.set(key, promise);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
$: if (!disableCache) {
|
|
53
|
+
// load using cache
|
|
54
|
+
loadImage(url(x, y, z));
|
|
55
|
+
}
|
|
56
|
+
</script>
|
|
57
|
+
|
|
58
|
+
<!-- To avoid aliasing artifacts (thin white lines) between tiles, two layers of tiles are drawn, with the lower layer’s tiles enlarged by one pixel -->
|
|
59
|
+
<image
|
|
60
|
+
xlink:href={href}
|
|
61
|
+
x={(x + tx) * k - 0.5}
|
|
62
|
+
y={(y + ty) * k - 0.5}
|
|
63
|
+
width={k + 1}
|
|
64
|
+
height={k + 1}
|
|
65
|
+
/>
|
|
66
|
+
<image xlink:href={href} x={(x + tx) * k} y={(y + ty) * k} width={k} height={k} />
|
|
67
|
+
{#if debug}
|
|
68
|
+
<rect
|
|
69
|
+
x={(x + tx) * k}
|
|
70
|
+
y={(y + ty) * k}
|
|
71
|
+
width={k}
|
|
72
|
+
height={k}
|
|
73
|
+
class="stroke-red-500/50 fill-none"
|
|
74
|
+
/>
|
|
75
|
+
<Text
|
|
76
|
+
x={(x + tx) * k}
|
|
77
|
+
y={(y + ty) * k}
|
|
78
|
+
verticalAnchor="start"
|
|
79
|
+
dx={2}
|
|
80
|
+
dy={-2}
|
|
81
|
+
value="{x}-{y}-{z}"
|
|
82
|
+
class="text-[8px] fill-black/50"
|
|
83
|
+
/>
|
|
84
|
+
{/if}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { SvelteComponentTyped } from "svelte";
|
|
2
|
+
declare const __propDef: {
|
|
3
|
+
props: {
|
|
4
|
+
x: number;
|
|
5
|
+
y: number;
|
|
6
|
+
z: number;
|
|
7
|
+
/** translate x */ tx: number;
|
|
8
|
+
/** scale */ ty: number;
|
|
9
|
+
k: number;
|
|
10
|
+
disableCache?: boolean | undefined;
|
|
11
|
+
debug?: boolean | undefined;
|
|
12
|
+
url: (x: number, y: number, z: number) => string;
|
|
13
|
+
};
|
|
14
|
+
events: {
|
|
15
|
+
[evt: string]: CustomEvent<any>;
|
|
16
|
+
};
|
|
17
|
+
slots: {};
|
|
18
|
+
};
|
|
19
|
+
export type TileImageProps = typeof __propDef.props;
|
|
20
|
+
export type TileImageEvents = typeof __propDef.events;
|
|
21
|
+
export type TileImageSlots = typeof __propDef.slots;
|
|
22
|
+
export default class TileImage extends SvelteComponentTyped<TileImageProps, TileImageEvents, TileImageSlots> {
|
|
23
|
+
}
|
|
24
|
+
export {};
|
|
@@ -8,14 +8,13 @@ export let leftOffset = 10;
|
|
|
8
8
|
export let contained = 'container'; // TODO: Support 'window' using getBoundingClientRect()
|
|
9
9
|
export let animate = true;
|
|
10
10
|
export let header = undefined;
|
|
11
|
-
const {
|
|
11
|
+
const { containerWidth, containerHeight } = getContext('LayerCake');
|
|
12
12
|
const tooltip = tooltipContext();
|
|
13
13
|
let tooltipWidth = 0;
|
|
14
14
|
let tooltipHeight = 0;
|
|
15
15
|
let top = animate ? spring($tooltip.top) : writable($tooltip.top);
|
|
16
16
|
$: if ($tooltip) {
|
|
17
|
-
|
|
18
|
-
if (contained === 'container' && $tooltip.top + topOffset + tooltipHeight > containerHeight) {
|
|
17
|
+
if (contained === 'container' && $tooltip.top + topOffset + tooltipHeight > $containerHeight) {
|
|
19
18
|
// change side
|
|
20
19
|
$top = $tooltip.top - (topOffset + tooltipHeight);
|
|
21
20
|
}
|
|
@@ -25,8 +24,7 @@ $: if ($tooltip) {
|
|
|
25
24
|
}
|
|
26
25
|
let left = animate ? spring($tooltip.left) : writable($tooltip.left);
|
|
27
26
|
$: if ($tooltip) {
|
|
28
|
-
|
|
29
|
-
if (contained === 'container' && $tooltip.left + leftOffset + tooltipWidth > containerWidth) {
|
|
27
|
+
if (contained === 'container' && $tooltip.left + leftOffset + tooltipWidth > $containerWidth) {
|
|
30
28
|
// change side
|
|
31
29
|
$left = $tooltip.left - (leftOffset + tooltipWidth);
|
|
32
30
|
}
|
|
@@ -45,22 +43,22 @@ $: if ($tooltip) {
|
|
|
45
43
|
bind:clientWidth={tooltipWidth}
|
|
46
44
|
bind:clientHeight={tooltipHeight}
|
|
47
45
|
>
|
|
48
|
-
<!-- <slot data={tooltip?.data} /> -->
|
|
49
|
-
|
|
50
46
|
<div
|
|
51
47
|
class="bg-gray-900/90 backdrop-filter backdrop-blur-[2px] text-white rounded elevation-1 px-2 py-1"
|
|
52
48
|
>
|
|
53
49
|
{#if header || $$slots.header}
|
|
54
|
-
<div class="text-center font-semibold
|
|
50
|
+
<div class="text-center font-semibold whitespace-nowrap">
|
|
55
51
|
<slot name="header">
|
|
56
52
|
{header($tooltip.data)}
|
|
57
53
|
</slot>
|
|
58
54
|
</div>
|
|
59
55
|
{/if}
|
|
60
56
|
|
|
61
|
-
|
|
62
|
-
<
|
|
63
|
-
|
|
57
|
+
{#if $$slots.default}
|
|
58
|
+
<div class="grid grid-cols-[1fr,auto] gap-x-2 gap-y-1 items-center pt-1">
|
|
59
|
+
<slot data={$tooltip.data} />
|
|
60
|
+
</div>
|
|
61
|
+
{/if}
|
|
64
62
|
</div>
|
|
65
63
|
</div>
|
|
66
64
|
{/if}
|
|
@@ -15,7 +15,8 @@ function setTooltipContext(tooltip) {
|
|
|
15
15
|
}
|
|
16
16
|
</script>
|
|
17
17
|
|
|
18
|
-
<script>import {
|
|
18
|
+
<script>import { raise } from 'layercake';
|
|
19
|
+
import { createEventDispatcher } from 'svelte';
|
|
19
20
|
import { writable } from 'svelte/store';
|
|
20
21
|
import { bisector, max, min } from 'd3-array';
|
|
21
22
|
import { Delaunay } from 'd3-delaunay';
|
|
@@ -42,6 +43,8 @@ export let mode = 'bisect-x';
|
|
|
42
43
|
export let snapToDataX = false;
|
|
43
44
|
export let snapToDataY = false;
|
|
44
45
|
export let findTooltipData = 'closest';
|
|
46
|
+
/** Similar to d3-selection's raise, re-insert the event.target as the last child of its parent, so to be the top-most element */
|
|
47
|
+
export let raiseTarget = false;
|
|
45
48
|
export let radius = Infinity;
|
|
46
49
|
export let debug = false;
|
|
47
50
|
const tooltip = writable({ top: 0, left: 0, data: null, show: showTooltip, hide: hideTooltip });
|
|
@@ -160,6 +163,9 @@ function showTooltip(event, tooltipData) {
|
|
|
160
163
|
}
|
|
161
164
|
}
|
|
162
165
|
if (tooltipData) {
|
|
166
|
+
if (raiseTarget) {
|
|
167
|
+
raise(event.target);
|
|
168
|
+
}
|
|
163
169
|
$tooltip = {
|
|
164
170
|
...$tooltip,
|
|
165
171
|
left: snapToDataX ? $xGet(tooltipData) : localX,
|
|
@@ -16,6 +16,7 @@ declare const __propDef: {
|
|
|
16
16
|
snapToDataX?: boolean | undefined;
|
|
17
17
|
snapToDataY?: boolean | undefined;
|
|
18
18
|
findTooltipData?: "closest" | "left" | "right" | undefined;
|
|
19
|
+
/** Similar to d3-selection's raise, re-insert the event.target as the last child of its parent, so to be the top-most element */ raiseTarget?: boolean | undefined;
|
|
19
20
|
radius?: number | undefined;
|
|
20
21
|
debug?: boolean | undefined;
|
|
21
22
|
};
|
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
import { SvelteComponentTyped } from "svelte";
|
|
2
|
-
import type { FormatType } from 'svelte-ux/utils/format';
|
|
3
2
|
declare const __propDef: {
|
|
4
3
|
props: {
|
|
5
4
|
[x: string]: any;
|
|
6
5
|
label: any;
|
|
7
6
|
value?: any;
|
|
8
|
-
format?:
|
|
7
|
+
format?: any;
|
|
9
8
|
valueAlign?: "left" | "right" | "center" | undefined;
|
|
10
9
|
};
|
|
11
10
|
events: {
|
|
@@ -2,7 +2,7 @@ import { SvelteComponentTyped } from "svelte";
|
|
|
2
2
|
import * as d3 from 'd3-hierarchy';
|
|
3
3
|
declare const __propDef: {
|
|
4
4
|
props: {
|
|
5
|
-
tile?: d3.RatioSquarifyTilingFactory | "binary" | "squarify" | "resquarify" | "dice" | "
|
|
5
|
+
tile?: "slice" | d3.RatioSquarifyTilingFactory | "binary" | "squarify" | "resquarify" | "dice" | "sliceDice" | undefined;
|
|
6
6
|
padding?: number | undefined;
|
|
7
7
|
paddingInner?: number | undefined;
|
|
8
8
|
paddingOuter?: number | undefined;
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
<script>import { getContext, createEventDispatcher } from 'svelte';
|
|
2
|
+
import { motionStore } from '../stores/motionStore';
|
|
3
|
+
const { width, height, padding } = getContext('LayerCake');
|
|
4
|
+
export let mode = 'svg';
|
|
5
|
+
export let translateOnScale;
|
|
6
|
+
export let spring = undefined;
|
|
7
|
+
export let tweened = undefined;
|
|
8
|
+
export let disablePointer = false;
|
|
9
|
+
export let scroll = 'none';
|
|
10
|
+
export let clickDistance = 10;
|
|
11
|
+
const dispatch = createEventDispatcher();
|
|
12
|
+
let dragging = false;
|
|
13
|
+
let moved = false;
|
|
14
|
+
export let initialTranslate = { x: 0, y: 0 };
|
|
15
|
+
const translate = motionStore(initialTranslate, { spring, tweened });
|
|
16
|
+
export let initialScale = 1;
|
|
17
|
+
const scale = motionStore(initialScale, { spring, tweened });
|
|
18
|
+
let startPoint = { x: 0, y: 0 };
|
|
19
|
+
let startTranslate = { x: 0, y: 0 };
|
|
20
|
+
let svgEl = null;
|
|
21
|
+
export function reset() {
|
|
22
|
+
$translate = initialTranslate;
|
|
23
|
+
$scale = initialScale;
|
|
24
|
+
}
|
|
25
|
+
export function increase() {
|
|
26
|
+
scaleTo(1.25, { x: $width / 2, y: $height / 2 });
|
|
27
|
+
}
|
|
28
|
+
export function decrease() {
|
|
29
|
+
scaleTo(0.8, { x: $width / 2, y: $height / 2 });
|
|
30
|
+
}
|
|
31
|
+
export function translateCenter() {
|
|
32
|
+
$translate = {
|
|
33
|
+
x: 0,
|
|
34
|
+
y: 0
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
export function zoomTo(center, rect) {
|
|
38
|
+
// TODO: Improve with geo/projection
|
|
39
|
+
$translate = {
|
|
40
|
+
x: $width / 2 - center.x,
|
|
41
|
+
y: $height / 2 - center.y
|
|
42
|
+
};
|
|
43
|
+
if (rect) {
|
|
44
|
+
$scale = $width < $height ? $width / rect.width : $height / rect.height;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
function onMouseDown(e) {
|
|
48
|
+
if (disablePointer)
|
|
49
|
+
return;
|
|
50
|
+
dragging = true;
|
|
51
|
+
moved = false;
|
|
52
|
+
svgEl = e.currentTarget.ownerSVGElement; // capture for reference in mousemove event
|
|
53
|
+
startPoint = localPoint(svgEl, e);
|
|
54
|
+
startTranslate = $translate;
|
|
55
|
+
window.addEventListener('mousemove', onMouseMove);
|
|
56
|
+
window.addEventListener('mouseup', onMouseUp);
|
|
57
|
+
}
|
|
58
|
+
function onMouseMove(e) {
|
|
59
|
+
if (!dragging)
|
|
60
|
+
return;
|
|
61
|
+
const endPoint = localPoint(svgEl, e);
|
|
62
|
+
const deltaX = endPoint.x - startPoint.x;
|
|
63
|
+
const deltaY = endPoint.y - startPoint.y;
|
|
64
|
+
translate.set({
|
|
65
|
+
x: startTranslate.x + deltaX / (mode === 'manual' ? 1 : $scale),
|
|
66
|
+
y: startTranslate.y + deltaY / (mode === 'manual' ? 1 : $scale)
|
|
67
|
+
}, spring ? { hard: true } : tweened ? { duration: 0 } : undefined);
|
|
68
|
+
if (!moved) {
|
|
69
|
+
// If dragged beyond threshold, disable click propagation
|
|
70
|
+
moved = deltaX * deltaX + deltaY * deltaY > clickDistance;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
function onMouseUp(e) {
|
|
74
|
+
dragging = false;
|
|
75
|
+
window.removeEventListener('mousemove', onMouseMove);
|
|
76
|
+
window.removeEventListener('mouseup', onMouseUp);
|
|
77
|
+
}
|
|
78
|
+
function onClick(e) {
|
|
79
|
+
if (moved) {
|
|
80
|
+
// Do not propagate click event to children if drag/moved. Registered in capture phase (top-down)
|
|
81
|
+
e.stopPropagation();
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
function onDoubleClick(e) {
|
|
85
|
+
if (disablePointer)
|
|
86
|
+
return;
|
|
87
|
+
const point = localPoint(svgEl, e);
|
|
88
|
+
scaleTo(e.shiftKey ? 0.5 : 2, point);
|
|
89
|
+
}
|
|
90
|
+
function onWheel(e) {
|
|
91
|
+
if (scroll === 'none' || disablePointer)
|
|
92
|
+
return;
|
|
93
|
+
e.preventDefault();
|
|
94
|
+
svgEl = e.currentTarget.ownerSVGElement;
|
|
95
|
+
const point = (startPoint = localPoint(svgEl, e));
|
|
96
|
+
// Pinch to zoom is registered as a wheel event with control key
|
|
97
|
+
const pinchToZoom = e.ctrlKey;
|
|
98
|
+
if (scroll === 'scale' || pinchToZoom) {
|
|
99
|
+
// https://github.com/d3/d3-zoom#zoom_wheelDelta
|
|
100
|
+
const scaleBy = -e.deltaY * (e.deltaMode === 1 ? 0.05 : e.deltaMode ? 1 : 0.002) * (e.ctrlKey ? 10 : 1);
|
|
101
|
+
scaleTo(Math.pow(2, scaleBy), point, spring ? { hard: true } : tweened ? { duration: 0 } : undefined);
|
|
102
|
+
}
|
|
103
|
+
else if (scroll === 'translate') {
|
|
104
|
+
translate.update((startTranslate) => ({
|
|
105
|
+
x: startTranslate.x + -e.deltaX / (mode === 'manual' ? 1 : $scale),
|
|
106
|
+
y: startTranslate.y + -e.deltaY / (mode === 'manual' ? 1 : $scale)
|
|
107
|
+
}), spring ? { hard: true } : tweened ? { duration: 0 } : undefined);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Apply scale and translate towards point
|
|
112
|
+
*/
|
|
113
|
+
function scaleTo(value, point, options = undefined) {
|
|
114
|
+
const currentScale = $scale;
|
|
115
|
+
const newScale = $scale * value;
|
|
116
|
+
scale.set(newScale, options);
|
|
117
|
+
if (translateOnScale) {
|
|
118
|
+
// Translate towards point (ex. mouse cursor/center) while zooming in/out
|
|
119
|
+
const invertTransformPoint = {
|
|
120
|
+
x: (point.x - $translate.x) / currentScale,
|
|
121
|
+
y: (point.y - $translate.y) / currentScale
|
|
122
|
+
};
|
|
123
|
+
const newTranslate = {
|
|
124
|
+
x: point.x - invertTransformPoint.x * newScale,
|
|
125
|
+
y: point.y - invertTransformPoint.y * newScale
|
|
126
|
+
};
|
|
127
|
+
translate.set(newTranslate, options);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
function localPoint(svgEl, e) {
|
|
131
|
+
if (svgEl) {
|
|
132
|
+
const screenCTM = svgEl.getScreenCTM();
|
|
133
|
+
let point = svgEl.createSVGPoint();
|
|
134
|
+
point.x = e.clientX;
|
|
135
|
+
point.y = e.clientY;
|
|
136
|
+
point = point.matrixTransform(screenCTM?.inverse());
|
|
137
|
+
return {
|
|
138
|
+
x: point.x,
|
|
139
|
+
y: point.y
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
else {
|
|
143
|
+
return {
|
|
144
|
+
x: e.clientX,
|
|
145
|
+
y: e.clientY
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
$: center = { x: $width / 2, y: $height / 2 };
|
|
150
|
+
$: viewportCenter = {
|
|
151
|
+
x: center.x - $translate.x,
|
|
152
|
+
y: center.y - $translate.y
|
|
153
|
+
};
|
|
154
|
+
let transform = '';
|
|
155
|
+
$: if (mode === 'svg') {
|
|
156
|
+
const newTranslate = {
|
|
157
|
+
x: $translate.x * $scale + center.x - center.x * $scale,
|
|
158
|
+
y: $translate.y * $scale + center.y - center.y * $scale
|
|
159
|
+
};
|
|
160
|
+
transform = `translate(${newTranslate.x},${newTranslate.y}) scale(${$scale})`;
|
|
161
|
+
}
|
|
162
|
+
$: dispatch('zoom', { scale: $scale, translate: $translate });
|
|
163
|
+
</script>
|
|
164
|
+
|
|
165
|
+
<g
|
|
166
|
+
on:mousewheel={onWheel}
|
|
167
|
+
on:mousedown={onMouseDown}
|
|
168
|
+
on:dblclick={onDoubleClick}
|
|
169
|
+
on:click|capture={onClick}
|
|
170
|
+
on:click
|
|
171
|
+
on:keydown
|
|
172
|
+
on:keyup
|
|
173
|
+
on:keypress
|
|
174
|
+
>
|
|
175
|
+
<rect
|
|
176
|
+
x={-$padding.left}
|
|
177
|
+
y={-$padding.top}
|
|
178
|
+
width={$width + $padding.left + $padding.right}
|
|
179
|
+
height={$height + $padding.top + $padding.bottom}
|
|
180
|
+
fill="transparent"
|
|
181
|
+
/>
|
|
182
|
+
<g {transform}>
|
|
183
|
+
<slot scale={$scale} {zoomTo} {reset} />
|
|
184
|
+
</g>
|
|
185
|
+
</g>
|
|
@@ -2,29 +2,56 @@ import { SvelteComponentTyped } from "svelte";
|
|
|
2
2
|
import { motionStore } from '../stores/motionStore';
|
|
3
3
|
declare const __propDef: {
|
|
4
4
|
props: {
|
|
5
|
+
mode?: "svg" | "manual" | undefined;
|
|
6
|
+
translateOnScale: false;
|
|
5
7
|
spring?: boolean | Parameters<typeof motionStore>[1]['spring'];
|
|
6
8
|
tweened?: boolean | Parameters<typeof motionStore>[1]['tweened'];
|
|
7
9
|
disablePointer?: boolean | undefined;
|
|
10
|
+
scroll?: "scale" | "translate" | "none" | undefined;
|
|
11
|
+
clickDistance?: number | undefined;
|
|
12
|
+
initialTranslate?: {
|
|
13
|
+
x: number;
|
|
14
|
+
y: number;
|
|
15
|
+
} | undefined;
|
|
16
|
+
initialScale?: number | undefined;
|
|
8
17
|
reset?: (() => void) | undefined;
|
|
9
18
|
increase?: (() => void) | undefined;
|
|
10
19
|
decrease?: (() => void) | undefined;
|
|
11
20
|
translateCenter?: (() => void) | undefined;
|
|
12
|
-
zoomTo?: ((
|
|
13
|
-
x: number;
|
|
14
|
-
y: number;
|
|
15
|
-
}, newScale?: {
|
|
21
|
+
zoomTo?: ((center: {
|
|
16
22
|
x: number;
|
|
17
23
|
y: number;
|
|
18
|
-
}
|
|
24
|
+
}, rect?: {
|
|
25
|
+
width: number;
|
|
26
|
+
height: number;
|
|
27
|
+
} | undefined) => void) | undefined;
|
|
19
28
|
};
|
|
20
29
|
events: {
|
|
21
30
|
click: MouseEvent;
|
|
31
|
+
keydown: KeyboardEvent;
|
|
32
|
+
keyup: KeyboardEvent;
|
|
33
|
+
keypress: KeyboardEvent;
|
|
34
|
+
zoom: CustomEvent<{
|
|
35
|
+
scale: number;
|
|
36
|
+
translate: {
|
|
37
|
+
x: number;
|
|
38
|
+
y: number;
|
|
39
|
+
};
|
|
40
|
+
}>;
|
|
22
41
|
} & {
|
|
23
42
|
[evt: string]: CustomEvent<any>;
|
|
24
43
|
};
|
|
25
44
|
slots: {
|
|
26
45
|
default: {
|
|
27
46
|
scale: any;
|
|
47
|
+
zoomTo: (center: {
|
|
48
|
+
x: number;
|
|
49
|
+
y: number;
|
|
50
|
+
}, rect?: {
|
|
51
|
+
width: number;
|
|
52
|
+
height: number;
|
|
53
|
+
} | undefined) => void;
|
|
54
|
+
reset: () => void;
|
|
28
55
|
};
|
|
29
56
|
};
|
|
30
57
|
};
|
|
@@ -36,12 +63,12 @@ export default class Zoom extends SvelteComponentTyped<ZoomProps, ZoomEvents, Zo
|
|
|
36
63
|
get increase(): () => void;
|
|
37
64
|
get decrease(): () => void;
|
|
38
65
|
get translateCenter(): () => void;
|
|
39
|
-
get zoomTo(): (
|
|
40
|
-
x: number;
|
|
41
|
-
y: number;
|
|
42
|
-
}, newScale?: {
|
|
66
|
+
get zoomTo(): (center: {
|
|
43
67
|
x: number;
|
|
44
68
|
y: number;
|
|
69
|
+
}, rect?: {
|
|
70
|
+
width: number;
|
|
71
|
+
height: number;
|
|
45
72
|
} | undefined) => void;
|
|
46
73
|
}
|
|
47
74
|
export {};
|