Skip to content

Commit b26164d

Browse files
committed
simplify mouse interactions, add defaults to LineChartWrapper, and refine label placement
1 parent eeed6cd commit b26164d

File tree

8 files changed

+261
-301
lines changed

8 files changed

+261
-301
lines changed

src/lib/components/data-vis/line-chart/Line.svelte

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,9 @@
3030
yFunction,
3131
lineEnding,
3232
dataId,
33-
onClickLine,
34-
onMouseEnterLine,
35-
onMouseLeaveLine,
33+
onClickSeries,
34+
onMouseEnterSeries,
35+
onMouseLeaveSeries,
3636
halo,
3737
chartBackgroundColor,
3838
invisibleStrokeWidth,
@@ -44,18 +44,20 @@
4444
// labelText,
4545
// labelColor,
4646
// labelTextColor,
47-
lineClicked,
48-
lineHovered,
47+
clickedSeries,
48+
hoveredSeries,
4949
activeMarkerId,
5050
series,
5151
y,
52+
id,
5253
x,
5354
markers,
5455
markerFill,
5556
markerRadius,
5657
markerShape,
5758
markerStroke,
5859
markerStrokeWidth,
60+
tier,
5961
} = $props();
6062
6163
let linePath = $derived(lineFunction(dataArray));
@@ -87,17 +89,15 @@
8789

8890
<g
8991
data-id={dataId}
90-
onclick={interactive ? (e) => onClickLine(e, dataArray, dataId) : null}
91-
onmouseenter={interactive
92-
? (e) => onMouseEnterLine(e, dataArray, dataId)
93-
: null}
94-
onmouseleave={interactive
95-
? (e) => onMouseLeaveLine(e, dataArray, dataId)
96-
: null}
92+
{id}
93+
onclick={interactive ? (e) => onClickSeries(dataId, tier) : null}
94+
onmouseenter={interactive ? (e) => onMouseEnterSeries(dataId, tier) : null}
95+
onmouseleave={interactive ? (e) => onMouseLeaveSeries(dataId, tier) : null}
9796
role="button"
9897
tabindex="0"
99-
onkeydown={(e) => e.key === "Enter" && onClickLine(e, dataArray)}
98+
onkeydown={(e) => e.key === "Enter" && onClickSeries(e, dataArray)}
10099
{opacity}
100+
pointer-events={interactive ? null : "none"}
101101
>
102102
{#if includeArea}
103103
<path d={areaFunction(dataArray)} fill={areaFillColor}></path>

src/lib/components/data-vis/line-chart/LineChart.svelte

Lines changed: 86 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -9,45 +9,85 @@
99
import Lines from "$lib/components/data-vis/line-chart/Lines.svelte";
1010
1111
let {
12-
getColor,
13-
tieredLineParams,
14-
colors,
15-
xFunction,
16-
yFunction,
17-
lineFunction,
18-
lineClicked,
19-
lineHovered,
20-
labelClicked,
21-
labelHovered,
22-
svgWidth = $bindable(500),
23-
activeMarkerId,
24-
onClickLine,
25-
onMouseEnterLine,
26-
onMouseLeaveLine,
27-
onClickLabel,
28-
onMouseEnterLabel,
29-
onMouseLeaveLabel,
12+
// Required
13+
series,
14+
y,
15+
x,
16+
lineChartData,
17+
18+
// ask
19+
xFunction = (number) => {
20+
return scaleLinear()
21+
.domain([2015, 2022])
22+
.range([0, svgWidth - paddingLeft - paddingRight])(number);
23+
},
24+
yFunction = (number) => {
25+
return scaleLinear()
26+
.domain([0, 100])
27+
.range([svgHeight - paddingTop - paddingBottom, 0])(number);
28+
},
29+
lineFunction = line()
30+
.x((d) => xFunction(d[x]))
31+
.y((d) => yFunction(d[y]))
32+
.curve(curveLinear),
33+
labelText,
34+
35+
basicLineParams, // contains functions
36+
tooltipContent, // snippet
37+
38+
onClickSeries = (series, tier) => {
39+
if (clickedSeries === dataId) {
40+
clickedSeries = null;
41+
} else {
42+
clickedSeries = series;
43+
clickedTier = tier;
44+
}
45+
},
46+
onMouseLeaveSeries = (series, tier) => {
47+
if (hoveredSeries === series) {
48+
hoveredSeries = null;
49+
hoveredTier = null;
50+
}
51+
},
52+
onMouseEnterSeries = (series, tier) => {
53+
if (hoveredSeries !== series) {
54+
hoveredSeries = series;
55+
hoveredTier = tier;
56+
}
57+
},
3058
onClickMarker,
3159
onMouseEnterMarker,
3260
onMouseLeaveMarker,
61+
62+
// Optional
63+
clickedSeries = $bindable(undefined),
64+
hoveredSeries = undefined,
65+
overrideLineParams = () => ({}),
66+
getLine = () => true,
67+
nothingSelected = true,
68+
svgWidth = $bindable(500),
3369
svgHeight = 500,
3470
paddingTop = 50,
3571
paddingBottom = 50,
3672
paddingLeft = 50,
3773
paddingRight = 150,
38-
lineChartData,
39-
interactiveLines,
40-
chartBackgroundColor,
41-
getLine,
42-
basicLineParams,
43-
overrideLineParams,
44-
nothingSelected = $bindable(),
45-
globalTierRules,
46-
labelText,
47-
series,
48-
y,
49-
x,
50-
seriesLabels = $bindable(),
74+
activeMarkerId = undefined,
75+
chartBackgroundColor = "#f5f5f5",
76+
seriesLabels = $bindable(false),
77+
globalTierRules = {
78+
otherTier: {},
79+
secondary: {
80+
opacity: nothingSelected ? 1 : 0.5,
81+
},
82+
primary: {
83+
opacity: nothingSelected ? 1 : 0.4,
84+
},
85+
hover: { opacity: 1 },
86+
clicked: { opacity: 1 },
87+
},
88+
tieredLineParams = {
89+
all: {},
90+
},
5191
} = $props();
5292
5393
let chartWidth = $derived(svgWidth - paddingLeft - paddingRight);
@@ -61,19 +101,19 @@
61101
// );
62102
63103
let selectedLine = $derived([
64-
lineHovered,
65-
lineClicked,
66-
labelHovered,
67-
labelClicked,
104+
hoveredSeries,
105+
clickedSeries,
106+
hoveredSeries,
107+
clickedSeries,
68108
]);
69109
70110
function handleClickOutside(event) {
71111
if (
72-
lineClicked != event.target.parentElement.dataset.id ||
73-
(labelClicked && !event.target.closest('[id^="label"]'))
112+
clickedSeries &&
113+
!event.target.closest('[id^="line"]') &&
114+
!event.target.closest('[id^="label"]')
74115
) {
75-
labelClicked = null;
76-
lineClicked = null;
116+
clickedSeries = null;
77117
}
78118
}
79119
@@ -151,20 +191,15 @@
151191
{chartWidth}
152192
{xFunction}
153193
{yFunction}
154-
bind:labelClicked
155-
bind:labelHovered
156-
lineHovered
157-
lineClicked
194+
{hoveredSeries}
195+
{clickedSeries}
158196
{chartHeight}
159197
{globalTierRules}
160198
{chartBackgroundColor}
161-
bind:nothingSelected
162-
{onMouseEnterLine}
163-
{onMouseLeaveLine}
164-
{onClickLine}
165-
{onClickLabel}
166-
{onMouseEnterLabel}
167-
{onMouseLeaveLabel}
199+
{nothingSelected}
200+
{onMouseEnterSeries}
201+
{onClickSeries}
202+
{onMouseLeaveSeries}
168203
{onClickMarker}
169204
{onMouseEnterMarker}
170205
{onMouseLeaveMarker}
@@ -173,6 +208,7 @@
173208
{series}
174209
{y}
175210
{x}
211+
{tooltipContent}
176212
></Lines>
177213
</g>
178214
<g data-role="y-axis">

src/lib/components/data-vis/line-chart/Lines.svelte

Lines changed: 37 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -15,20 +15,15 @@
1515
chartWidth,
1616
xFunction,
1717
yFunction,
18-
labelClicked,
19-
labelHovered,
20-
lineHovered,
21-
lineClicked,
18+
clickedSeries,
19+
hoveredSeries,
2220
chartHeight,
2321
globalTierRules,
2422
chartBackgroundColor = "#fafafa",
25-
nothingSelected = $bindable(),
26-
onMouseEnterLine,
27-
onMouseLeaveLine,
28-
onClickLine,
29-
onMouseEnterLabel,
30-
onMouseLeaveLabel,
31-
onClickLabel,
23+
nothingSelected,
24+
onMouseEnterSeries,
25+
onMouseLeaveSeries,
26+
onClickSeries,
3227
onMouseEnterMarker,
3328
onMouseLeaveMarker,
3429
onClickMarker,
@@ -37,14 +32,15 @@
3732
series,
3833
y,
3934
x,
35+
tooltipContent,
4036
} = $props();
4137
4238
let bounds = $state([0, chartHeight]);
4339
4440
let transformed = $derived(
4541
Object.values(tieredDataObject)
4642
.filter(Array.isArray)
47-
.flatMap((tier) => tier.filter((item) => item.showLabel === true))
43+
.flatMap((tier) => tier.filter((item) => item.placeLabel === true))
4844
4945
.filter(
5046
(item, index, self) =>
@@ -72,16 +68,17 @@
7268
{#each tieredDataObject[tier] as line, i}
7369
<Line
7470
{...line}
71+
id={`line-${line[series]}`}
7572
{tier}
7673
{chartBackgroundColor}
7774
{lineFunction}
7875
{xFunction}
7976
{yFunction}
80-
{onMouseEnterLine}
81-
{onMouseLeaveLine}
82-
{onClickLine}
83-
lineClicked
84-
lineHovered
77+
{onMouseEnterSeries}
78+
{onMouseLeaveSeries}
79+
{onClickSeries}
80+
{clickedSeries}
81+
{hoveredSeries}
8582
{series}
8683
{y}
8784
{x}
@@ -96,29 +93,28 @@
9693
<g>
9794
{#each tieredDataObject[tier] as line, i}
9895
{#if line.showLabel}
99-
{console.log("@", labelClicked == line[series])}
100-
{#if !labelClicked || (labelClicked && line[series] == labelClicked)}
101-
{@const newY = labelsPlaced.find(
102-
(el) => el.datum[series] === line[series],
103-
)?.[y]}
104-
<SeriesLabel
105-
id={`label-${line[series]}`}
106-
{labelClicked}
107-
{labelHovered}
108-
{chartWidth}
109-
{lineFunction}
110-
dataArray={line}
111-
{xFunction}
112-
{yFunction}
113-
{newY}
114-
{onClickLabel}
115-
{onMouseEnterLabel}
116-
{onMouseLeaveLabel}
117-
{labelText}
118-
{series}
119-
{y}
120-
></SeriesLabel>
121-
{/if}
96+
{@const newY = labelsPlaced.find(
97+
(el) => el.datum[series] === line[series],
98+
)?.[y]}
99+
<SeriesLabel
100+
interactive={line.interactive}
101+
id={`label-${line[series]}`}
102+
{clickedSeries}
103+
{hoveredSeries}
104+
{chartWidth}
105+
{lineFunction}
106+
dataArray={line}
107+
{xFunction}
108+
{yFunction}
109+
{newY}
110+
{onClickSeries}
111+
{onMouseEnterSeries}
112+
{onMouseLeaveSeries}
113+
{labelText}
114+
{series}
115+
{y}
116+
{tier}
117+
></SeriesLabel>
122118
{/if}
123119
{/each}
124120
</g>
@@ -130,7 +126,7 @@
130126
{activeMarkerId}
131127
labelColor="grey"
132128
labelTextColor="black"
133-
textContent={`this string contains some <strong>HTML!!!</strong>`}
129+
{tooltipContent}
134130
{xFunction}
135131
{yFunction}
136132
{x}

0 commit comments

Comments
 (0)