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..23878f1973 100644 --- a/src/plot.js +++ b/src/plot.js @@ -2,18 +2,33 @@ import {creator, select} from "d3"; import {createChannel, inferChannelScale} from "./channel.js"; import {createContext} from "./context.js"; import {createDimensions} from "./dimensions.js"; -import {createFacets, recreateFacets, facetExclude, facetGroups, facetTranslator, facetFilter} from "./facet.js"; +import {createFacets, facetExclude, facetFilter, facetGroups, facetTranslator, recreateFacets} from "./facet.js"; import {pointer, pointerX, pointerY} from "./interactions/pointer.js"; import {createLegends, exposeLegends} from "./legends.js"; import {Mark} from "./mark.js"; import {axisFx, axisFy, axisX, axisY, gridFx, gridFy, gridX, gridY} from "./marks/axis.js"; import {frame} from "./marks/frame.js"; import {tip} from "./marks/tip.js"; -import {isColor, isIterable, isNone, isScaleOptions} from "./options.js"; -import {arrayify, map, yes, maybeIntervalTransform, subarray} from "./options.js"; +import { + arrayify, + isColor, + isIterable, + isNone, + isScaleOptions, + map, + maybeIntervalTransform, + subarray, + yes +} from "./options.js"; import {createProjection, getGeometryChannels, hasProjection} from "./projection.js"; -import {createScales, createScaleFunctions, autoScaleRange, exposeScales} from "./scales.js"; -import {innerDimensions, outerDimensions} from "./scales.js"; +import { + autoScaleRange, + createScaleFunctions, + createScales, + exposeScales, + innerDimensions, + outerDimensions +} from "./scales.js"; import {isPosition, registry as scaleRegistry} from "./scales/index.js"; import {applyInlineStyles, maybeClassName} from "./style.js"; import {initializer} from "./transforms/basic.js"; @@ -172,10 +187,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, sticky) => { + if (figure.value === value && context.stickyState === sticky) return; figure.value = value; - figure.dispatchEvent(new Event("input", {bubbles: true})); + context.stickyState = sticky; + figure.dispatchEvent(new StickyEvent("input", {bubbles: true, sticky})); }; // Reinitialize; for deriving channels dependent on other channels. @@ -743,3 +759,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/output/pointerSticky.html b/test/output/pointerSticky.html new file mode 100644 index 0000000000..d320531398 --- /dev/null +++ b/test/output/pointerSticky.html @@ -0,0 +1,403 @@ +
+ + + + + + + + + + + + + 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 diff --git a/test/plots/pointer.ts b/test/plots/pointer.ts index 1e9df45067..5710f40d98 100644 --- a/test/plots/pointer.ts +++ b/test/plots/pointer.ts @@ -45,3 +45,25 @@ 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`