svelteplot 0.4.2 → 0.4.3
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/Mark.svelte +4 -2
- package/dist/core/Plot.svelte +1 -2
- package/dist/helpers/index.d.ts +1 -2
- package/dist/helpers/index.js +1 -6
- package/dist/helpers/resolve.js +4 -4
- package/dist/marks/Area.svelte +3 -3
- package/dist/marks/Arrow.svelte +16 -15
- package/dist/marks/Arrow.svelte.d.ts +1 -1
- package/dist/marks/AxisX.svelte +1 -1
- package/dist/marks/AxisX.svelte.d.ts +1 -1
- package/dist/marks/Dot.svelte +5 -5
- package/dist/marks/Geo.svelte +3 -3
- package/dist/marks/GridX.svelte +26 -8
- package/dist/marks/GridX.svelte.d.ts +8 -6
- package/dist/marks/GridY.svelte +16 -4
- package/dist/marks/GridY.svelte.d.ts +8 -6
- package/dist/marks/Link.svelte +7 -10
- package/dist/marks/Pointer.svelte +2 -2
- package/dist/marks/RuleX.svelte +1 -1
- package/dist/marks/RuleX.svelte.d.ts +1 -1
- package/dist/marks/Text.svelte +2 -1
- package/dist/marks/Vector.svelte +6 -5
- package/dist/marks/helpers/BaseAxisX.svelte +17 -12
- package/dist/marks/helpers/BaseAxisY.svelte +15 -10
- package/dist/marks/helpers/MarkerPath.svelte +10 -2
- package/dist/marks/helpers/RectPath.svelte +8 -13
- package/dist/marks/helpers/RectPath.svelte.d.ts +64 -3
- package/dist/marks/helpers/events.d.ts +5 -6
- package/dist/marks/helpers/events.js +47 -35
- package/dist/transforms/recordize.d.ts +12 -7
- package/dist/transforms/recordize.js +23 -24
- package/dist/transforms/sort.d.ts +1 -1
- package/dist/types/channel.d.ts +1 -1
- package/dist/types/data.d.ts +2 -0
- package/dist/types/index.d.ts +6 -6
- package/package.json +1 -1
|
@@ -9,11 +9,14 @@
|
|
|
9
9
|
ConstantAccessor,
|
|
10
10
|
PlotState,
|
|
11
11
|
RawValue,
|
|
12
|
+
ScaledDataRecord,
|
|
12
13
|
ScaleType
|
|
13
14
|
} from '../../types/index.js';
|
|
14
15
|
import { resolveProp, resolveStyles } from '../../helpers/resolve.js';
|
|
15
16
|
import { max } from 'd3-array';
|
|
16
17
|
import { randomId, testFilter } from '../../helpers/index.js';
|
|
18
|
+
import { INDEX } from '../../constants';
|
|
19
|
+
import { RAW_VALUE } from '../../transforms/recordize';
|
|
17
20
|
|
|
18
21
|
type BaseAxisXProps = {
|
|
19
22
|
scaleFn: (d: RawValue) => number;
|
|
@@ -76,11 +79,12 @@
|
|
|
76
79
|
const positionedTicks = $derived.by(() => {
|
|
77
80
|
let tickObjects = removeIdenticalLines(
|
|
78
81
|
ticks.map((tick, i) => {
|
|
82
|
+
const datum = { [RAW_VALUE]: tick, [INDEX]: i };
|
|
79
83
|
return {
|
|
80
|
-
|
|
84
|
+
...datum,
|
|
81
85
|
hidden: false,
|
|
82
|
-
dx: +resolveProp(options.dx,
|
|
83
|
-
dy: +resolveProp(options.dy,
|
|
86
|
+
dx: +resolveProp(options.dx, datum, 0),
|
|
87
|
+
dy: +resolveProp(options.dy, datum, 0),
|
|
84
88
|
x: scaleFn(tick) + (scaleType === 'band' ? scaleFn.bandwidth() * 0.5 : 0),
|
|
85
89
|
text: splitTick(tickFormat(tick, i)),
|
|
86
90
|
element: null as SVGTextElement | null
|
|
@@ -101,7 +105,7 @@
|
|
|
101
105
|
}
|
|
102
106
|
}
|
|
103
107
|
}
|
|
104
|
-
return tickObjects;
|
|
108
|
+
return tickObjects as ScaledDataRecord[];
|
|
105
109
|
});
|
|
106
110
|
|
|
107
111
|
$effect(() => {
|
|
@@ -114,11 +118,11 @@
|
|
|
114
118
|
max(
|
|
115
119
|
positionedTicks.map((tick, i) => {
|
|
116
120
|
if (
|
|
117
|
-
resolveProp(options.anchor, tick
|
|
121
|
+
resolveProp(options.anchor, tick, outsideTextAnchor) !==
|
|
118
122
|
outsideTextAnchor
|
|
119
123
|
)
|
|
120
124
|
return 0;
|
|
121
|
-
if (tick.hidden || !testFilter(tick
|
|
125
|
+
if (tick.hidden || !testFilter(tick, options)) return 0;
|
|
122
126
|
if (tickTextElements[i])
|
|
123
127
|
return tickTextElements[i].getBoundingClientRect().height;
|
|
124
128
|
return 0;
|
|
@@ -148,8 +152,9 @@
|
|
|
148
152
|
|
|
149
153
|
<g class="axis-x">
|
|
150
154
|
{#each positionedTicks as tick, t (t)}
|
|
151
|
-
{#if testFilter(tick
|
|
152
|
-
{@const tickClass_ = resolveProp(tickClass, tick
|
|
155
|
+
{#if testFilter(tick, options) && !tick.hidden}
|
|
156
|
+
{@const tickClass_ = resolveProp(tickClass, tick)}
|
|
157
|
+
{@const tickFontSize_ = +resolveProp(tickFontSize, tick, 10)}
|
|
153
158
|
<g
|
|
154
159
|
class="tick {tickClass_ || ''}"
|
|
155
160
|
transform="translate({tick.x + tick.dx}, {tickY + tick.dy})"
|
|
@@ -157,7 +162,7 @@
|
|
|
157
162
|
{#if tickSize}
|
|
158
163
|
{@const [tickLineStyle, tickLineClass] = resolveStyles(
|
|
159
164
|
plot,
|
|
160
|
-
tick,
|
|
165
|
+
{ datum: tick },
|
|
161
166
|
options,
|
|
162
167
|
'stroke',
|
|
163
168
|
{ x: true },
|
|
@@ -174,15 +179,15 @@
|
|
|
174
179
|
{@const prevTextLines = t && positionedTicks[t - 1].text}
|
|
175
180
|
|
|
176
181
|
{@const moveDown =
|
|
177
|
-
(tickSize + tickPadding + (tickRotate !== 0 ?
|
|
182
|
+
(tickSize + tickPadding + (tickRotate !== 0 ? tickFontSize_ * 0.35 : 0)) *
|
|
178
183
|
(anchor === 'bottom' ? 1 : -1)}
|
|
179
184
|
{@const [textStyle, textClass] = resolveStyles(
|
|
180
185
|
plot,
|
|
181
|
-
tick,
|
|
186
|
+
{ datum: tick },
|
|
182
187
|
{
|
|
183
188
|
fontVariant: isQuantitative ? 'tabular-nums' : 'normal',
|
|
184
189
|
...options,
|
|
185
|
-
fontSize:
|
|
190
|
+
fontSize: tickFontSize_,
|
|
186
191
|
stroke: null
|
|
187
192
|
},
|
|
188
193
|
'fill',
|
|
@@ -6,10 +6,14 @@
|
|
|
6
6
|
import type {
|
|
7
7
|
AutoMarginStores,
|
|
8
8
|
ConstantAccessor,
|
|
9
|
+
DataRecord,
|
|
9
10
|
PlotState,
|
|
10
11
|
RawValue,
|
|
12
|
+
ScaledDataRecord,
|
|
11
13
|
ScaleType
|
|
12
14
|
} from '../../types/index.js';
|
|
15
|
+
import { RAW_VALUE } from '../../transforms/recordize';
|
|
16
|
+
import { INDEX } from '../../constants';
|
|
13
17
|
|
|
14
18
|
type BaseAxisYProps = {
|
|
15
19
|
scaleFn: (d: RawValue) => number;
|
|
@@ -61,13 +65,14 @@
|
|
|
61
65
|
|
|
62
66
|
const positionedTicks = $derived.by(() => {
|
|
63
67
|
let tickObjects = ticks.map((tick, i) => {
|
|
68
|
+
const datum = { [RAW_VALUE]: tick, [INDEX]: i };
|
|
64
69
|
return {
|
|
65
|
-
|
|
70
|
+
...datum,
|
|
66
71
|
hidden: false,
|
|
67
|
-
dx: +resolveProp(options.dx,
|
|
68
|
-
dy: +resolveProp(options.dy,
|
|
72
|
+
dx: +resolveProp(options.dx, datum, 0),
|
|
73
|
+
dy: +resolveProp(options.dy, datum, 0),
|
|
69
74
|
y: scaleFn(tick) + (scaleType === 'band' ? scaleFn.bandwidth() * 0.5 : 0),
|
|
70
|
-
text: tickFormat(tick),
|
|
75
|
+
text: tickFormat(tick, i),
|
|
71
76
|
element: null as SVGTextElement | null
|
|
72
77
|
};
|
|
73
78
|
});
|
|
@@ -107,11 +112,11 @@
|
|
|
107
112
|
max(
|
|
108
113
|
positionedTicks.map((tick, i) => {
|
|
109
114
|
if (
|
|
110
|
-
resolveProp(options.textAnchor, tick
|
|
115
|
+
resolveProp(options.textAnchor, tick, outsideTextAnchor) !==
|
|
111
116
|
outsideTextAnchor
|
|
112
117
|
)
|
|
113
118
|
return 0;
|
|
114
|
-
if (tick.hidden || !testFilter(tick
|
|
119
|
+
if (tick.hidden || !testFilter(tick, options)) return 0;
|
|
115
120
|
if (tickTexts[i]) return tickTexts[i].getBoundingClientRect().width;
|
|
116
121
|
return 0;
|
|
117
122
|
}) as number[]
|
|
@@ -150,11 +155,11 @@
|
|
|
150
155
|
|
|
151
156
|
<g class="axis-y">
|
|
152
157
|
{#each positionedTicks as tick, t (t)}
|
|
153
|
-
{#if testFilter(tick
|
|
154
|
-
{@const tickClass_ = resolveProp(tickClass, tick
|
|
158
|
+
{#if testFilter(tick, options) && !tick.hidden}
|
|
159
|
+
{@const tickClass_ = resolveProp(tickClass, tick)}
|
|
155
160
|
{@const [textStyle, textClass] = resolveStyles(
|
|
156
161
|
plot,
|
|
157
|
-
tick,
|
|
162
|
+
{ datum: tick },
|
|
158
163
|
{
|
|
159
164
|
fontVariant: isQuantitative ? 'tabular-nums' : 'normal',
|
|
160
165
|
...options,
|
|
@@ -173,7 +178,7 @@
|
|
|
173
178
|
{#if tickSize}
|
|
174
179
|
{@const [tickLineStyle, tickLineClass] = resolveStyles(
|
|
175
180
|
plot,
|
|
176
|
-
tick,
|
|
181
|
+
{ datum: tick },
|
|
177
182
|
options,
|
|
178
183
|
'stroke',
|
|
179
184
|
{ y: true },
|
|
@@ -95,7 +95,11 @@
|
|
|
95
95
|
{transform}
|
|
96
96
|
class={className}
|
|
97
97
|
stroke-width={strokeWidth_}
|
|
98
|
-
|
|
98
|
+
{@attach addEventHandlers({
|
|
99
|
+
getPlotState,
|
|
100
|
+
options: mark.options,
|
|
101
|
+
datum: datum
|
|
102
|
+
})}>
|
|
99
103
|
{#each Object.entries( { start: markerStart, mid: markerMid, end: markerEnd, all: marker } ) as [key, marker] (key)}
|
|
100
104
|
{@const markerId = `marker-${key === 'all' ? '' : `${key}-`}${id}`}
|
|
101
105
|
{#if isSnippet(marker)}
|
|
@@ -122,7 +126,11 @@
|
|
|
122
126
|
marker-end={markerEnd || marker ? `url(#marker-${markerEnd ? 'end-' : ''}${id})` : null}
|
|
123
127
|
{d}
|
|
124
128
|
{style}
|
|
125
|
-
|
|
129
|
+
{@attach addEventHandlers({
|
|
130
|
+
getPlotState,
|
|
131
|
+
options: mark.options,
|
|
132
|
+
datum: datum
|
|
133
|
+
})} />
|
|
126
134
|
{#if text}
|
|
127
135
|
<!-- since textPath.side is not yet supported, we have to use an invisible
|
|
128
136
|
path in order to keep the text from turning upside down -->
|
|
@@ -28,18 +28,13 @@ Helper component for rendering rectangular marks in SVG
|
|
|
28
28
|
|
|
29
29
|
import { resolveProp, resolveStyles } from '../../helpers/resolve';
|
|
30
30
|
import { roundedRect } from '../../helpers/roundedRect';
|
|
31
|
-
import type {
|
|
32
|
-
BaseMarkProps,
|
|
33
|
-
BaseRectMarkProps,
|
|
34
|
-
BorderRadius,
|
|
35
|
-
ScaledDataRecord,
|
|
36
|
-
UsedScales,
|
|
37
|
-
PlotContext,
|
|
38
|
-
DataRecord
|
|
39
|
-
} from '../../index.js';
|
|
40
31
|
import { addEventHandlers } from './events.js';
|
|
41
32
|
import { getContext } from 'svelte';
|
|
42
33
|
import Anchor from './Anchor.svelte';
|
|
34
|
+
import type { BaseMarkProps, BaseRectMarkProps, BorderRadius } from '../../types/mark.js';
|
|
35
|
+
import type { DataRecord, ScaledDataRecord } from '../../types/data.js';
|
|
36
|
+
import type { PlotContext, UsedScales } from '../../types/index.js';
|
|
37
|
+
import { RAW_VALUE } from '../../transforms/recordize.js';
|
|
43
38
|
|
|
44
39
|
let {
|
|
45
40
|
datum,
|
|
@@ -116,11 +111,11 @@ Helper component for rendering rectangular marks in SVG
|
|
|
116
111
|
)}
|
|
117
112
|
class={[styleClass, className]}
|
|
118
113
|
{style}
|
|
119
|
-
|
|
114
|
+
{@attach addEventHandlers({
|
|
120
115
|
getPlotState,
|
|
121
116
|
options,
|
|
122
117
|
datum: datum?.datum
|
|
123
|
-
}} />
|
|
118
|
+
})} />
|
|
124
119
|
{:else}
|
|
125
120
|
<rect
|
|
126
121
|
transform="translate({x + insetLeft},{y + insetBottom})"
|
|
@@ -128,10 +123,10 @@ Helper component for rendering rectangular marks in SVG
|
|
|
128
123
|
height={height - insetTop - insetBottom}
|
|
129
124
|
class={[styleClass, className]}
|
|
130
125
|
{style}
|
|
131
|
-
|
|
126
|
+
{@attach addEventHandlers({
|
|
132
127
|
getPlotState,
|
|
133
128
|
options,
|
|
134
129
|
datum: datum?.datum
|
|
135
|
-
}} />
|
|
130
|
+
})} />
|
|
136
131
|
{/if}
|
|
137
132
|
</Anchor>
|
|
@@ -1,13 +1,74 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { BaseRectMarkProps } from '../../types/mark.js';
|
|
2
|
+
import type { DataRecord, ScaledDataRecord } from '../../types/data.js';
|
|
3
|
+
import type { UsedScales } from '../../types/index.js';
|
|
2
4
|
declare class __sveltets_Render<Datum extends DataRecord> {
|
|
3
5
|
props(): {
|
|
4
|
-
datum: ScaledDataRecord<
|
|
6
|
+
datum: ScaledDataRecord<Datum>;
|
|
5
7
|
class: string | null;
|
|
6
8
|
x: number;
|
|
7
9
|
y: number;
|
|
8
10
|
width: number;
|
|
9
11
|
height: number;
|
|
10
|
-
options: BaseRectMarkProps<
|
|
12
|
+
options: BaseRectMarkProps<Datum> & Partial<{
|
|
13
|
+
filter?: import("../../types/index.js").ConstantAccessor<boolean, Datum>;
|
|
14
|
+
facet?: "auto" | "include" | "exclude";
|
|
15
|
+
fx: import("../../types/index.js").ChannelAccessor<Datum>;
|
|
16
|
+
fy: import("../../types/index.js").ChannelAccessor<Datum>;
|
|
17
|
+
dx: import("../../types/index.js").ConstantAccessor<number, Datum>;
|
|
18
|
+
dy: import("../../types/index.js").ConstantAccessor<number, Datum>;
|
|
19
|
+
fill: import("../../types/index.js").ChannelAccessor<Datum>;
|
|
20
|
+
fillOpacity: import("../../types/index.js").ConstantAccessor<number, Datum>;
|
|
21
|
+
sort: {
|
|
22
|
+
channel: string;
|
|
23
|
+
order?: "ascending" | "descending";
|
|
24
|
+
} | ((a: import("../../types/data.js").RawValue, b: import("../../types/data.js").RawValue) => number) | import("../../types/index.js").ConstantAccessor<import("../../types/data.js").RawValue, Datum>;
|
|
25
|
+
stroke: import("../../types/index.js").ChannelAccessor<Datum>;
|
|
26
|
+
strokeWidth: import("../../types/index.js").ConstantAccessor<number, Datum>;
|
|
27
|
+
strokeOpacity: import("../../types/index.js").ConstantAccessor<number, Datum>;
|
|
28
|
+
strokeLinejoin: import("../../types/index.js").ConstantAccessor<import("csstype").Property.StrokeLinejoin, Datum>;
|
|
29
|
+
strokeLinecap: import("../../types/index.js").ConstantAccessor<import("csstype").Property.StrokeLinecap, Datum>;
|
|
30
|
+
strokeMiterlimit: import("../../types/index.js").ConstantAccessor<number, Datum>;
|
|
31
|
+
opacity: import("../../types/index.js").ChannelAccessor<Datum>;
|
|
32
|
+
strokeDasharray: import("../../types/index.js").ConstantAccessor<string, Datum>;
|
|
33
|
+
strokeDashoffset: import("../../types/index.js").ConstantAccessor<number, Datum>;
|
|
34
|
+
mixBlendMode: import("../../types/index.js").ConstantAccessor<import("csstype").Property.MixBlendMode, Datum>;
|
|
35
|
+
clipPath: string;
|
|
36
|
+
imageFilter: import("../../types/index.js").ConstantAccessor<string, Datum>;
|
|
37
|
+
shapeRendering: import("../../types/index.js").ConstantAccessor<import("csstype").Property.ShapeRendering, Datum>;
|
|
38
|
+
paintOrder: import("../../types/index.js").ConstantAccessor<string, Datum>;
|
|
39
|
+
onclick?: import("svelte/elements.js").MouseEventHandler<SVGPathElement>;
|
|
40
|
+
ondblclick?: import("svelte/elements.js").MouseEventHandler<SVGPathElement>;
|
|
41
|
+
onmouseup?: import("svelte/elements.js").MouseEventHandler<SVGPathElement>;
|
|
42
|
+
onmousedown?: import("svelte/elements.js").MouseEventHandler<SVGPathElement>;
|
|
43
|
+
onmouseenter?: import("svelte/elements.js").MouseEventHandler<SVGPathElement>;
|
|
44
|
+
onmousemove?: import("svelte/elements.js").MouseEventHandler<SVGPathElement>;
|
|
45
|
+
onmouseleave?: import("svelte/elements.js").MouseEventHandler<SVGPathElement>;
|
|
46
|
+
onmouseout?: import("svelte/elements.js").MouseEventHandler<SVGPathElement>;
|
|
47
|
+
onmouseover?: import("svelte/elements.js").MouseEventHandler<SVGPathElement>;
|
|
48
|
+
onpointercancel?: import("svelte/elements.js").MouseEventHandler<SVGPathElement>;
|
|
49
|
+
onpointerdown?: import("svelte/elements.js").MouseEventHandler<SVGPathElement>;
|
|
50
|
+
onpointerup?: import("svelte/elements.js").MouseEventHandler<SVGPathElement>;
|
|
51
|
+
onpointerenter?: import("svelte/elements.js").MouseEventHandler<SVGPathElement>;
|
|
52
|
+
onpointerleave?: import("svelte/elements.js").MouseEventHandler<SVGPathElement>;
|
|
53
|
+
onpointermove?: import("svelte/elements.js").MouseEventHandler<SVGPathElement>;
|
|
54
|
+
onpointerover?: import("svelte/elements.js").MouseEventHandler<SVGPathElement>;
|
|
55
|
+
onpointerout?: import("svelte/elements.js").MouseEventHandler<SVGPathElement>;
|
|
56
|
+
ondrag?: import("svelte/elements.js").MouseEventHandler<SVGPathElement>;
|
|
57
|
+
ondrop?: import("svelte/elements.js").MouseEventHandler<SVGPathElement>;
|
|
58
|
+
ondragstart?: import("svelte/elements.js").MouseEventHandler<SVGPathElement>;
|
|
59
|
+
ondragenter?: import("svelte/elements.js").MouseEventHandler<SVGPathElement>;
|
|
60
|
+
ondragleave?: import("svelte/elements.js").MouseEventHandler<SVGPathElement>;
|
|
61
|
+
ondragover?: import("svelte/elements.js").MouseEventHandler<SVGPathElement>;
|
|
62
|
+
ondragend?: import("svelte/elements.js").MouseEventHandler<SVGPathElement>;
|
|
63
|
+
ontouchstart?: import("svelte/elements.js").MouseEventHandler<SVGPathElement>;
|
|
64
|
+
ontouchmove?: import("svelte/elements.js").MouseEventHandler<SVGPathElement>;
|
|
65
|
+
ontouchend?: import("svelte/elements.js").MouseEventHandler<SVGPathElement>;
|
|
66
|
+
ontouchcancel?: import("svelte/elements.js").MouseEventHandler<SVGPathElement>;
|
|
67
|
+
oncontextmenu?: import("svelte/elements.js").MouseEventHandler<SVGPathElement>;
|
|
68
|
+
onwheel?: import("svelte/elements.js").MouseEventHandler<SVGPathElement>;
|
|
69
|
+
class: string | null;
|
|
70
|
+
cursor: import("../../types/index.js").ConstantAccessor<import("csstype").Property.Cursor, Datum>;
|
|
71
|
+
}>;
|
|
11
72
|
/**
|
|
12
73
|
* By default, the `inset` property is applied to all four insets. Mark components
|
|
13
74
|
* can tweak this behavior for insetTop and insetBottom by setting the
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import type { BaseMarkProps, DataRecord, PlotState } from '../../types/index.js';
|
|
1
|
+
import type { BaseMarkProps, DataRecord, DataRow, PlotState } from '../../types/index.js';
|
|
2
|
+
import type { Attachment } from 'svelte/attachments';
|
|
2
3
|
declare global {
|
|
3
4
|
interface MouseEvent {
|
|
4
5
|
layerX?: number;
|
|
@@ -12,10 +13,8 @@ declare global {
|
|
|
12
13
|
* of the plot frame, regardless of which element triggered the event
|
|
13
14
|
*/
|
|
14
15
|
export declare function clientToLayerCoordinates(event: MouseEvent, plotBody: HTMLElement | null | undefined): [number, number];
|
|
15
|
-
export declare function addEventHandlers
|
|
16
|
-
options: BaseMarkProps
|
|
16
|
+
export declare function addEventHandlers<T extends DataRow>({ options, datum, getPlotState }: {
|
|
17
|
+
options: BaseMarkProps<T>;
|
|
17
18
|
datum: DataRecord;
|
|
18
19
|
getPlotState: () => PlotState;
|
|
19
|
-
}):
|
|
20
|
-
destroy(): void;
|
|
21
|
-
};
|
|
20
|
+
}): Attachment;
|
|
@@ -19,7 +19,7 @@ export function clientToLayerCoordinates(event, plotBody) {
|
|
|
19
19
|
// Calculate the coordinates relative to the plot body
|
|
20
20
|
return [event.clientX - plotBodyRect.left, event.clientY - plotBodyRect.top];
|
|
21
21
|
}
|
|
22
|
-
export function addEventHandlers(
|
|
22
|
+
export function addEventHandlers({ options, datum, getPlotState }) {
|
|
23
23
|
const events = pick(options, [
|
|
24
24
|
'onclick',
|
|
25
25
|
'oncontextmenu',
|
|
@@ -51,50 +51,62 @@ export function addEventHandlers(node, { options, datum, getPlotState }) {
|
|
|
51
51
|
'ontouchmove',
|
|
52
52
|
'onwheel'
|
|
53
53
|
]);
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
const
|
|
60
|
-
|
|
61
|
-
if (
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
54
|
+
return (node) => {
|
|
55
|
+
const listeners = new Map();
|
|
56
|
+
// attach event handlers
|
|
57
|
+
for (const [eventName, eventHandler] of Object.entries(events)) {
|
|
58
|
+
if (eventHandler) {
|
|
59
|
+
const wrappedHandler = (origEvent) => {
|
|
60
|
+
const { scales, body, options } = getPlotState();
|
|
61
|
+
if (origEvent instanceof MouseEvent || origEvent instanceof PointerEvent) {
|
|
62
|
+
let facetEl = origEvent.target;
|
|
63
|
+
while (facetEl &&
|
|
64
|
+
!facetEl.classList.contains('facet') &&
|
|
65
|
+
facetEl.parentElement) {
|
|
66
|
+
// ensure that parentElement is SVGElement
|
|
67
|
+
if (!(facetEl.parentElement instanceof SVGElement))
|
|
68
|
+
break;
|
|
69
|
+
facetEl = facetEl.parentElement;
|
|
70
|
+
}
|
|
71
|
+
const facetRect = (facetEl?.firstElementChild ?? body).getBoundingClientRect();
|
|
72
|
+
const relativeX = origEvent.clientX - facetRect.left + (options.marginLeft ?? 0);
|
|
73
|
+
const relativeY = origEvent.clientY - facetRect.top + (options.marginTop ?? 0);
|
|
74
|
+
if (scales.projection) {
|
|
75
|
+
const [x, y] = scales.projection.invert([relativeX, relativeY]);
|
|
76
|
+
origEvent.dataX = x;
|
|
77
|
+
origEvent.dataY = y;
|
|
78
|
+
}
|
|
79
|
+
else {
|
|
80
|
+
origEvent.dataX = invertScale(scales.x, relativeX);
|
|
81
|
+
origEvent.dataY = invertScale(scales.y, relativeY);
|
|
82
|
+
}
|
|
68
83
|
}
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
eventHandler(origEvent, datum.hasOwnProperty(RAW_VALUE) ? datum[RAW_VALUE] : datum, datum[INDEX]);
|
|
75
|
-
};
|
|
76
|
-
listeners.set(eventName, wrappedHandler);
|
|
77
|
-
node.addEventListener(eventName.substring(2), wrappedHandler);
|
|
84
|
+
eventHandler(origEvent, datum.hasOwnProperty(RAW_VALUE) ? datum[RAW_VALUE] : datum, datum[INDEX]);
|
|
85
|
+
};
|
|
86
|
+
listeners.set(eventName, wrappedHandler);
|
|
87
|
+
node.addEventListener(eventName.substring(2), wrappedHandler);
|
|
88
|
+
}
|
|
78
89
|
}
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
return {
|
|
85
|
-
destroy() {
|
|
90
|
+
if (events.onclick || events.onmousedown || events.onmouseup) {
|
|
91
|
+
// force role button
|
|
92
|
+
node.setAttribute('role', 'button');
|
|
93
|
+
}
|
|
94
|
+
return () => {
|
|
86
95
|
for (const [eventName, handler] of listeners.entries()) {
|
|
87
96
|
node.removeEventListener(eventName.substring(2), handler);
|
|
88
97
|
}
|
|
89
|
-
}
|
|
98
|
+
};
|
|
90
99
|
};
|
|
91
100
|
}
|
|
92
101
|
function invertScale(scale, position) {
|
|
93
102
|
if (scale.type === 'band') {
|
|
94
|
-
|
|
103
|
+
const range = scale.fn.range();
|
|
104
|
+
const domain = scale.fn.domain();
|
|
95
105
|
const eachBand = scale.fn.step();
|
|
96
|
-
const
|
|
97
|
-
|
|
106
|
+
const extent = range[1] - range[0];
|
|
107
|
+
const posInRange = (position - range[0]) * Math.sign(extent);
|
|
108
|
+
const index = Math.floor(posInRange / eachBand);
|
|
109
|
+
return domain[index];
|
|
98
110
|
}
|
|
99
111
|
return scale.fn.invert ? scale.fn.invert(position) : undefined;
|
|
100
112
|
}
|
|
@@ -1,16 +1,21 @@
|
|
|
1
1
|
import type { TransformArgsRow, TransformArgsRecord } from '../types/index.js';
|
|
2
|
-
|
|
2
|
+
import { INDEX } from '../constants';
|
|
3
|
+
export declare const X: unique symbol;
|
|
4
|
+
export declare const Y: unique symbol;
|
|
3
5
|
export declare const RAW_VALUE: unique symbol;
|
|
4
|
-
export declare function
|
|
6
|
+
export declare function indexData<T extends object>(data: T[]): (T & {
|
|
7
|
+
[INDEX]: number;
|
|
8
|
+
})[];
|
|
9
|
+
export declare function recordizeX<T>({ data, ...channels }: TransformArgsRow<T>, { withIndex }?: {
|
|
5
10
|
withIndex: boolean;
|
|
6
|
-
}): TransformArgsRecord
|
|
7
|
-
export declare function recordizeY({ data, ...channels }: TransformArgsRow
|
|
11
|
+
}): TransformArgsRecord<T>;
|
|
12
|
+
export declare function recordizeY<T>({ data, ...channels }: TransformArgsRow<T>, { withIndex }?: {
|
|
8
13
|
withIndex: boolean;
|
|
9
|
-
}): TransformArgsRecord
|
|
14
|
+
}): TransformArgsRecord<T>;
|
|
10
15
|
/**
|
|
11
16
|
* This transform is used to allow users to pass an [[x0, y0], [x1, y1], ...] array
|
|
12
17
|
* as dataset to marks that support it. It transforms the arrays into records, so
|
|
13
18
|
* the rest of our code doesn't have to deal with this case anymore.
|
|
14
19
|
*/
|
|
15
|
-
export declare function recordizeXY({ data, ...channels }: TransformArgsRow): TransformArgsRecord
|
|
16
|
-
export declare function recordize({ data, ...channels }: TransformArgsRow): TransformArgsRecord
|
|
20
|
+
export declare function recordizeXY<T>({ data, ...channels }: TransformArgsRow<T>): TransformArgsRecord<T>;
|
|
21
|
+
export declare function recordize<T>({ data, ...channels }: TransformArgsRow<T>): TransformArgsRecord<T>;
|
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
import isDataRecord from '../helpers/isDataRecord.js';
|
|
2
|
-
|
|
2
|
+
import { INDEX } from '../constants';
|
|
3
|
+
export const X = Symbol('x');
|
|
4
|
+
export const Y = Symbol('y');
|
|
3
5
|
export const RAW_VALUE = Symbol('originalValue');
|
|
6
|
+
export function indexData(data) {
|
|
7
|
+
return data.map((d, i) => ({ ...d, [INDEX]: i }));
|
|
8
|
+
}
|
|
4
9
|
/*
|
|
5
10
|
* This transform takes an array of raw values as input and returns data records
|
|
6
11
|
* in which the values are interpreted as x channel and their index as y
|
|
@@ -10,16 +15,15 @@ export function recordizeX({ data, ...channels }, { withIndex } = { withIndex: t
|
|
|
10
15
|
if (dataIsRawValueArray) {
|
|
11
16
|
return {
|
|
12
17
|
data: data.map((value, index) => ({
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
[RAW_VALUE]: value
|
|
18
|
+
[RAW_VALUE]: value,
|
|
19
|
+
[INDEX]: index
|
|
16
20
|
})),
|
|
17
21
|
...channels,
|
|
18
22
|
x: RAW_VALUE,
|
|
19
23
|
...(withIndex ? { y: INDEX } : {})
|
|
20
24
|
};
|
|
21
25
|
}
|
|
22
|
-
return { data: data, ...channels };
|
|
26
|
+
return { data: indexData(data), ...channels };
|
|
23
27
|
}
|
|
24
28
|
/*
|
|
25
29
|
* This transform takes an array of raw values as input and returns data records
|
|
@@ -32,22 +36,15 @@ export function recordizeY({ data, ...channels }, { withIndex } = { withIndex: t
|
|
|
32
36
|
if (dataIsRawValueArray) {
|
|
33
37
|
return {
|
|
34
38
|
data: Array.from(data).map((value, index) => ({
|
|
35
|
-
|
|
39
|
+
[INDEX]: index,
|
|
36
40
|
[RAW_VALUE]: value
|
|
37
41
|
})),
|
|
38
42
|
...channels,
|
|
39
|
-
...(withIndex ? { x:
|
|
43
|
+
...(withIndex ? { x: INDEX } : {}),
|
|
40
44
|
y: RAW_VALUE
|
|
41
45
|
};
|
|
42
46
|
}
|
|
43
|
-
return {
|
|
44
|
-
data: Array.from(data).map((d, index) => ({
|
|
45
|
-
...d,
|
|
46
|
-
...(withIndex ? { __index: index } : {})
|
|
47
|
-
})),
|
|
48
|
-
x: '__index',
|
|
49
|
-
...channels
|
|
50
|
-
};
|
|
47
|
+
return { data: indexData(data), ...channels };
|
|
51
48
|
}
|
|
52
49
|
/**
|
|
53
50
|
* This transform is used to allow users to pass an [[x0, y0], [x1, y1], ...] array
|
|
@@ -62,28 +59,30 @@ export function recordizeXY({ data, ...channels }) {
|
|
|
62
59
|
channels.x === undefined &&
|
|
63
60
|
channels.y === undefined) {
|
|
64
61
|
return {
|
|
65
|
-
data: data.map(([x, y, ...rest]) => ({
|
|
62
|
+
data: data.map(([x, y, ...rest], i) => ({
|
|
66
63
|
[RAW_VALUE]: [x, y, ...rest],
|
|
67
|
-
|
|
68
|
-
|
|
64
|
+
[INDEX]: i,
|
|
65
|
+
[X]: x,
|
|
66
|
+
[Y]: y
|
|
69
67
|
})),
|
|
70
68
|
...channels,
|
|
71
|
-
x:
|
|
72
|
-
y:
|
|
69
|
+
x: X,
|
|
70
|
+
y: Y
|
|
73
71
|
};
|
|
74
72
|
}
|
|
75
|
-
return { data, ...channels };
|
|
73
|
+
return { data: data, ...channels };
|
|
76
74
|
}
|
|
77
75
|
export function recordize({ data, ...channels }) {
|
|
78
76
|
if (!data)
|
|
79
77
|
return { data, ...channels };
|
|
80
78
|
if (!isDataRecord(data[0])) {
|
|
81
79
|
return {
|
|
82
|
-
data: data.map((d) => ({
|
|
83
|
-
[RAW_VALUE]: d
|
|
80
|
+
data: data.map((d, i) => ({
|
|
81
|
+
[RAW_VALUE]: d,
|
|
82
|
+
[INDEX]: i
|
|
84
83
|
})),
|
|
85
84
|
...channels
|
|
86
85
|
};
|
|
87
86
|
}
|
|
88
|
-
return { data, ...channels };
|
|
87
|
+
return { data: indexData(data), ...channels };
|
|
89
88
|
}
|
|
@@ -7,7 +7,7 @@ export declare function sort<T>({ data, ...channels }: TransformArg<T>, options?
|
|
|
7
7
|
[IS_SORTED]: string | number | true | symbol | Date | {
|
|
8
8
|
channel: string;
|
|
9
9
|
order?: "ascending" | "descending";
|
|
10
|
-
} | ((a: import("../types/index.js").RawValue, b: import("../types/index.js").RawValue) => number) | ((d: T) => import("../types/index.js").RawValue);
|
|
10
|
+
} | ((a: import("../types/index.js").RawValue, b: import("../types/index.js").RawValue) => number) | ((d: T, index: number) => import("../types/index.js").RawValue);
|
|
11
11
|
sort: null;
|
|
12
12
|
filter?: import("../types/index.js").ConstantAccessor<boolean, T>;
|
|
13
13
|
facet?: "auto" | "include" | "exclude" | undefined;
|
package/dist/types/channel.d.ts
CHANGED
|
@@ -6,7 +6,7 @@ export type ChannelAccessor<T = Record<string | symbol, RawValue>> = ChannelValu
|
|
|
6
6
|
/** you can bypass the scale by passing null */
|
|
7
7
|
scale: boolean | null;
|
|
8
8
|
};
|
|
9
|
-
export type ChannelValue<T = Record<string | symbol, RawValue>> = RawValue | keyof T | ((d: T) => RawValue) | null | undefined;
|
|
9
|
+
export type ChannelValue<T = Record<string | symbol, RawValue>> = RawValue | keyof T | ((d: T, index: number) => RawValue) | null | undefined;
|
|
10
10
|
export type ScaledChannelName = 'fill' | 'fillOpacity' | 'opacity' | 'r' | 'length' | 'stroke' | 'strokeOpacity' | 'symbol' | 'fx' | 'fy' | 'x' | 'x1' | 'x2' | 'y' | 'y1' | 'y2';
|
|
11
11
|
export type ScaledChannelType<T extends ScaledChannelName> = T extends 'fill' | 'stroke' | 'symbol' ? string : number;
|
|
12
12
|
export type ChannelName = ScaledChannelName | 'z' | 'sort' | 'filter' | 'interval';
|
package/dist/types/data.d.ts
CHANGED
|
@@ -3,6 +3,7 @@ export type RawValue = number | Date | boolean | string | symbol;
|
|
|
3
3
|
export type DataRecord<T = Record<string | symbol, RawValue>> = T;
|
|
4
4
|
export type ResolvedDataRecord<T = Record<string | symbol, RawValue>> = Partial<Record<ScaledChannelName, any>> & {
|
|
5
5
|
datum: DataRecord<T>;
|
|
6
|
+
index: number;
|
|
6
7
|
};
|
|
7
8
|
export type ScaledDataRecord<T = Record<string | symbol, RawValue>> = Partial<{
|
|
8
9
|
[K in ScaledChannelName]?: ScaledChannelType<K>;
|
|
@@ -11,5 +12,6 @@ export type ScaledDataRecord<T = Record<string | symbol, RawValue>> = Partial<{
|
|
|
11
12
|
dy: number;
|
|
12
13
|
datum: DataRecord<T>;
|
|
13
14
|
valid: Boolean;
|
|
15
|
+
index: number;
|
|
14
16
|
};
|
|
15
17
|
export type DataRow<T = Record<string | symbol, RawValue>> = DataRecord<T> | RawValue | [number, number] | null;
|
package/dist/types/index.d.ts
CHANGED
|
@@ -2,7 +2,7 @@ import type { Snippet } from 'svelte';
|
|
|
2
2
|
import type { Writable } from 'svelte/store';
|
|
3
3
|
import type { MarkerShape } from '../marks/helpers/Marker.svelte';
|
|
4
4
|
import type { Channels, ScaledChannelName } from './channel.js';
|
|
5
|
-
import type {
|
|
5
|
+
import type { RawValue } from './data.js';
|
|
6
6
|
import type { BaseMarkProps } from './mark.js';
|
|
7
7
|
export type GenericMarkOptions = Record<string | symbol, any>;
|
|
8
8
|
export type CurveName = 'basis' | 'basis-closed' | 'basis-open' | 'bundle' | 'bump-x' | 'bump-y' | 'cardinal' | 'cardinal-closed' | 'cardinal-open' | 'catmull-rom' | 'catmull-rom-closed' | 'catmull-rom-open' | 'linear' | 'linear-closed' | 'monotone-x' | 'monotone-y' | 'natural' | 'step' | 'step-after' | 'step-before';
|
|
@@ -24,18 +24,18 @@ export type MarkerOptions = {
|
|
|
24
24
|
*/
|
|
25
25
|
marker?: boolean | MarkerShape | Snippet;
|
|
26
26
|
};
|
|
27
|
-
export type ConstantAccessor<K, T = Record<string | symbol, RawValue>> = K | ((d: T) => K) | null | undefined;
|
|
27
|
+
export type ConstantAccessor<K, T = Record<string | symbol, RawValue>> = K | ((d: T, index: number) => K) | null | undefined;
|
|
28
28
|
export type TransformArg<T> = Channels<T> & BaseMarkProps<T> & {
|
|
29
29
|
data: T[];
|
|
30
30
|
};
|
|
31
31
|
export type MapArg<T> = Channels<T> & {
|
|
32
32
|
data: T[];
|
|
33
33
|
};
|
|
34
|
-
export type TransformArgsRow = Partial<Channels
|
|
35
|
-
data:
|
|
34
|
+
export type TransformArgsRow<T extends RawValue & object> = Partial<Channels<T>> & {
|
|
35
|
+
data: T[];
|
|
36
36
|
};
|
|
37
|
-
export type TransformArgsRecord = Partial<Channels
|
|
38
|
-
data:
|
|
37
|
+
export type TransformArgsRecord<T extends object> = Partial<Channels<T>> & {
|
|
38
|
+
data: T[];
|
|
39
39
|
};
|
|
40
40
|
export type AutoMarginStores = {
|
|
41
41
|
autoMarginTop: Writable<Map<string, number>>;
|