From b9e91cdbc5f99298f1f7a397c0d7d7d46a8f2e56 Mon Sep 17 00:00:00 2001 From: Yuri Vishnevsky Date: Tue, 30 Jan 2024 18:50:50 -0500 Subject: [PATCH 01/15] prototype support for distinguishing hover & click events via the CustomEvent detail option --- src/interactions/pointer.js | 2 +- src/plot.js | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/interactions/pointer.js b/src/interactions/pointer.js index c92addcff7..787e591dfe 100644 --- a/src/interactions/pointer.js +++ b/src/interactions/pointer.js @@ -126,7 +126,7 @@ function pointerK(kx, ky, {x, y, px, py, maxRadius = 40, channels, render, ...op // Dispatch the value. When simultaneously exiting this facet and // entering a new one, prioritize the entering facet. - if (!(i == null && facetState?.size > 1)) context.dispatchValue(i == null ? null : data[i]); + if (!(i == null && facetState?.size > 1)) context.dispatchValue(i == null ? null : data[i], s); return r; } diff --git a/src/plot.js b/src/plot.js index 541218f306..08316c12ea 100644 --- a/src/plot.js +++ b/src/plot.js @@ -172,10 +172,11 @@ export function plot(options = {}) { }; // Allows e.g. the pointer transform to support viewof. - context.dispatchValue = (value) => { - if (figure.value === value) return; + context.dispatchValue = (value, detail) => { + if (figure.value === value && figure._detail === detail) return; figure.value = value; - figure.dispatchEvent(new Event("input", {bubbles: true})); + figure._detail = detail; + figure.dispatchEvent(new CustomEvent("input", {bubbles: true, detail})); }; // Reinitialize; for deriving channels dependent on other channels. From cd5988fb3c4b27cc568d713f6b3bf85044e38029 Mon Sep 17 00:00:00 2001 From: Yuri Vishnevsky Date: Tue, 30 Jan 2024 21:56:57 -0500 Subject: [PATCH 02/15] dispatch a subclass of Event with a sticky option --- src/plot.js | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/plot.js b/src/plot.js index 08316c12ea..e030467191 100644 --- a/src/plot.js +++ b/src/plot.js @@ -172,11 +172,11 @@ export function plot(options = {}) { }; // Allows e.g. the pointer transform to support viewof. - context.dispatchValue = (value, detail) => { - if (figure.value === value && figure._detail === detail) return; + context.dispatchValue = (value, sticky) => { + if (figure.value === value && figure._sticky === sticky) return; figure.value = value; - figure._detail = detail; - figure.dispatchEvent(new CustomEvent("input", {bubbles: true, detail})); + figure._sticky = sticky; + figure.dispatchEvent(new StickyEvent("input", {bubbles: true, sticky})); }; // Reinitialize; for deriving channels dependent on other channels. @@ -744,3 +744,10 @@ function outerRange(scale) { if (x2 < x1) [x1, x2] = [x2, x1]; return [x1, x2 + scale.bandwidth()]; } + +class StickyEvent extends Event { + constructor(type, options) { + super(type, options) + this.sticky = options.sticky + } +} From 3687112c0e01345acea90c76d34799781e687e85 Mon Sep 17 00:00:00 2001 From: Yuri Vishnevsky Date: Tue, 30 Jan 2024 23:04:45 -0500 Subject: [PATCH 03/15] move the StickyEvent definition inside the `plot` function --- src/plot.js | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/plot.js b/src/plot.js index e030467191..e67b063ca6 100644 --- a/src/plot.js +++ b/src/plot.js @@ -171,6 +171,13 @@ export function plot(options = {}) { return {...state, channels: {...state.channels, ...facetState?.channels}}; }; + class StickyEvent extends Event { + constructor(type, options) { + super(type, options) + this.sticky = options.sticky + } + } + // Allows e.g. the pointer transform to support viewof. context.dispatchValue = (value, sticky) => { if (figure.value === value && figure._sticky === sticky) return; @@ -744,10 +751,3 @@ function outerRange(scale) { if (x2 < x1) [x1, x2] = [x2, x1]; return [x1, x2 + scale.bandwidth()]; } - -class StickyEvent extends Event { - constructor(type, options) { - super(type, options) - this.sticky = options.sticky - } -} From ca18ec31810d435eafe3a6fba8dbeadc38b256d5 Mon Sep 17 00:00:00 2001 From: Yuri Vishnevsky Date: Tue, 30 Jan 2024 23:07:56 -0500 Subject: [PATCH 04/15] fix formatting --- src/plot.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/plot.js b/src/plot.js index e67b063ca6..1b8419d2f2 100644 --- a/src/plot.js +++ b/src/plot.js @@ -173,8 +173,8 @@ export function plot(options = {}) { class StickyEvent extends Event { constructor(type, options) { - super(type, options) - this.sticky = options.sticky + super(type, options); + this.sticky = options.sticky; } } From 73a0e6731cf8a4f3af460254c1057090a1f13400 Mon Sep 17 00:00:00 2001 From: Yuri Vishnevsky Date: Tue, 30 Jan 2024 23:14:43 -0500 Subject: [PATCH 05/15] let's see what happens if we move the event back out to the top level, but alias the global jsdom EventTarget to the window EventTarget... --- src/plot.js | 14 +++++++------- test/jsdom.js | 2 ++ 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/src/plot.js b/src/plot.js index 1b8419d2f2..7cfad4bda4 100644 --- a/src/plot.js +++ b/src/plot.js @@ -171,13 +171,6 @@ export function plot(options = {}) { return {...state, channels: {...state.channels, ...facetState?.channels}}; }; - class StickyEvent extends Event { - constructor(type, options) { - super(type, options); - this.sticky = options.sticky; - } - } - // Allows e.g. the pointer transform to support viewof. context.dispatchValue = (value, sticky) => { if (figure.value === value && figure._sticky === sticky) return; @@ -751,3 +744,10 @@ function outerRange(scale) { if (x2 < x1) [x1, x2] = [x2, x1]; return [x1, x2 + scale.bandwidth()]; } + +class StickyEvent extends Event { + constructor(type, options) { + super(type, options); + this.sticky = options.sticky; + } +} diff --git a/test/jsdom.js b/test/jsdom.js index 94e9193c25..0035112496 100644 --- a/test/jsdom.js +++ b/test/jsdom.js @@ -21,6 +21,7 @@ function withJsdom(run) { global.document = jsdom.window.document; global.navigator = jsdom.window.navigator; global.Event = jsdom.window.Event; + global.EventTarget = jsdom.window.EventTarget; global.Node = jsdom.window.Node; global.NodeList = jsdom.window.NodeList; global.HTMLCollection = jsdom.window.HTMLCollection; @@ -32,6 +33,7 @@ function withJsdom(run) { delete global.document; delete global.navigator; delete global.Event; + delete global.EventTarget; delete global.Node; delete global.NodeList; delete global.HTMLCollection; From 411a6ceb6af297300516245299f36c22d1a2ed8f Mon Sep 17 00:00:00 2001 From: Yuri Vishnevsky Date: Tue, 30 Jan 2024 23:16:24 -0500 Subject: [PATCH 06/15] Revert "let's see what happens if we move the event back out to the top level, but alias the global jsdom EventTarget to the window EventTarget..." This reverts commit 73a0e6731cf8a4f3af460254c1057090a1f13400. --- src/plot.js | 14 +++++++------- test/jsdom.js | 2 -- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/src/plot.js b/src/plot.js index 7cfad4bda4..1b8419d2f2 100644 --- a/src/plot.js +++ b/src/plot.js @@ -171,6 +171,13 @@ export function plot(options = {}) { return {...state, channels: {...state.channels, ...facetState?.channels}}; }; + class StickyEvent extends Event { + constructor(type, options) { + super(type, options); + this.sticky = options.sticky; + } + } + // Allows e.g. the pointer transform to support viewof. context.dispatchValue = (value, sticky) => { if (figure.value === value && figure._sticky === sticky) return; @@ -744,10 +751,3 @@ function outerRange(scale) { if (x2 < x1) [x1, x2] = [x2, x1]; return [x1, x2 + scale.bandwidth()]; } - -class StickyEvent extends Event { - constructor(type, options) { - super(type, options); - this.sticky = options.sticky; - } -} diff --git a/test/jsdom.js b/test/jsdom.js index 0035112496..94e9193c25 100644 --- a/test/jsdom.js +++ b/test/jsdom.js @@ -21,7 +21,6 @@ function withJsdom(run) { global.document = jsdom.window.document; global.navigator = jsdom.window.navigator; global.Event = jsdom.window.Event; - global.EventTarget = jsdom.window.EventTarget; global.Node = jsdom.window.Node; global.NodeList = jsdom.window.NodeList; global.HTMLCollection = jsdom.window.HTMLCollection; @@ -33,7 +32,6 @@ function withJsdom(run) { delete global.document; delete global.navigator; delete global.Event; - delete global.EventTarget; delete global.Node; delete global.NodeList; delete global.HTMLCollection; From 9ce5bc47cd3cdf09287fdc9e55f0efb5134463c9 Mon Sep 17 00:00:00 2001 From: Yuri Vishnevsky Date: Mon, 5 Feb 2024 14:45:03 -0500 Subject: [PATCH 07/15] store sticky state in a context field rather than on the figure element --- src/plot.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/plot.js b/src/plot.js index 1b8419d2f2..9deb4f82f0 100644 --- a/src/plot.js +++ b/src/plot.js @@ -178,11 +178,13 @@ export function plot(options = {}) { } } + context.stickyState = undefined; + // Allows e.g. the pointer transform to support viewof. context.dispatchValue = (value, sticky) => { - if (figure.value === value && figure._sticky === sticky) return; + if (figure.value === value && context.stickyState === sticky) return; figure.value = value; - figure._sticky = sticky; + context.stickyState = sticky; figure.dispatchEvent(new StickyEvent("input", {bubbles: true, sticky})); }; From 2ff8a1b68e823f52180c550f1de44007160f1d5f Mon Sep 17 00:00:00 2001 From: Yuri Vishnevsky Date: Mon, 5 Feb 2024 14:46:30 -0500 Subject: [PATCH 08/15] add an interactive test for sticky pointers which displays the clicked value --- test/plots/pointer.ts | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/test/plots/pointer.ts b/test/plots/pointer.ts index 1e9df45067..ed96d87c3e 100644 --- a/test/plots/pointer.ts +++ b/test/plots/pointer.ts @@ -45,3 +45,26 @@ export async function pointerNonFaceted() { ] }); } + +export async function pointerSticky() { + const penguins = await d3.csv("data/penguins.csv", d3.autoType); + const plot = Plot.dot(penguins, { + x: "culmen_length_mm", + y: "culmen_depth_mm", + tip: true + }).plot(); + let prevSticky = false; + const textarea = html` \ No newline at end of file From 91000aa24ef34a478b968936d12974fde825ab51 Mon Sep 17 00:00:00 2001 From: Yuri Vishnevsky Date: Mon, 5 Feb 2024 15:12:55 -0500 Subject: [PATCH 11/15] align output formatting with the pointerViewof test --- test/output/pointerSticky.html | 412 ++++++++++++++++++++++++++++++++- 1 file changed, 401 insertions(+), 11 deletions(-) diff --git a/test/output/pointerSticky.html b/test/output/pointerSticky.html index f5a7eb7f64..5e0b22fd66 100644 --- a/test/output/pointerSticky.html +++ b/test/output/pointerSticky.html @@ -1,11 +1,401 @@ -
1415161718192021↑ culmen_depth_mm3540455055culmen_length_mm →
\ No newline at end of file +
+ + + + + + + + + + + + + 14 + 15 + 16 + 17 + 18 + 19 + 20 + 21 + + + ↑ culmen_depth_mm + + + + + + + + + + 35 + 40 + 45 + 50 + 55 + + + culmen_length_mm → + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
\ No newline at end of file From 138b91736bc2fa98e52db4dedad34d34388f1c80 Mon Sep 17 00:00:00 2001 From: Yuri Date: Mon, 5 Feb 2024 16:56:36 -0500 Subject: [PATCH 12/15] remove explicit initialization of context.stickyState MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Philippe Rivière --- src/plot.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/plot.js b/src/plot.js index 9deb4f82f0..f16ac5f58d 100644 --- a/src/plot.js +++ b/src/plot.js @@ -178,8 +178,6 @@ export function plot(options = {}) { } } - context.stickyState = undefined; - // Allows e.g. the pointer transform to support viewof. context.dispatchValue = (value, sticky) => { if (figure.value === value && context.stickyState === sticky) return; From 615ff9480aad5efef70ac0c630eeefc70f3fb19d Mon Sep 17 00:00:00 2001 From: Yuri Vishnevsky Date: Mon, 5 Feb 2024 19:49:02 -0500 Subject: [PATCH 13/15] prettier --- test/plots/pointer.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/plots/pointer.ts b/test/plots/pointer.ts index e5079bd87a..5710f40d98 100644 --- a/test/plots/pointer.ts +++ b/test/plots/pointer.ts @@ -66,4 +66,4 @@ export async function pointerSticky() { textarea.value = JSON.stringify(null); // initialize the textarea to null plot.oninput = oninput; // update during interaction return html`
${plot}${textarea}
`; -} \ No newline at end of file +} From 02023a9acb63981795e98e1e806bdfc94a782f1a Mon Sep 17 00:00:00 2001 From: Yuri Vishnevsky Date: Mon, 5 Feb 2024 19:49:09 -0500 Subject: [PATCH 14/15] add generated snapshot test --- test/output/pointerSticky.html | 38 ++++++++++++++++++---------------- 1 file changed, 20 insertions(+), 18 deletions(-) diff --git a/test/output/pointerSticky.html b/test/output/pointerSticky.html index 5e0b22fd66..d320531398 100644 --- a/test/output/pointerSticky.html +++ b/test/output/pointerSticky.html @@ -1,17 +1,19 @@ -
-