Skip to content

Commit 19829d5

Browse files
committed
pointer improvements
1 parent 2112eab commit 19829d5

10 files changed

+2248
-14
lines changed

src/marks/pointer.js

Lines changed: 25 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
import {create, namespaces, pointer as pointerof, quickselect, union} from "d3";
2-
import {identity, maybeFrameAnchor, maybeTuple} from "../options.js";
2+
import {identity, maybeTuple} from "../options.js";
33
import {Mark} from "../plot.js";
44
import {selection} from "../selection.js";
5-
import {applyDirectStyles, applyFrameAnchor, applyIndirectStyles} from "../style.js";
5+
import {applyDirectStyles, applyIndirectStyles} from "../style.js";
66

77
const defaults = {
88
ariaLabel: "pointer",
@@ -15,10 +15,9 @@ export class Pointer extends Mark {
1515
constructor(data, {
1616
x,
1717
y,
18-
n = Infinity,
18+
n = 1,
1919
r = isFinite(n) ? 120 : 20,
2020
mode = "auto",
21-
frameAnchor,
2221
...options
2322
} = {}) {
2423
super(
@@ -33,12 +32,10 @@ export class Pointer extends Mark {
3332
this.n = +n;
3433
this.r = +r;
3534
this.mode = maybeMode(mode, x, y);
36-
this.frameAnchor = maybeFrameAnchor(frameAnchor);
3735
}
38-
render(index, scales, {x: X, y: Y}, dimensions) {
36+
render(index, {x, y}, {x: X, y: Y}, dimensions) {
3937
const {marginLeft, width, marginRight, marginTop, height, marginBottom} = dimensions;
4038
const {mode, n, r} = this;
41-
const [cx, cy] = applyFrameAnchor(this, dimensions);
4239
const r2 = r * r; // the squared radius; to determine points in proximity to the pointer
4340
const down = new Set(); // the set of pointers that are currently down
4441
let C = []; // a sparse index from index[i] to an svg:circle element
@@ -63,11 +60,14 @@ export class Pointer extends Mark {
6360
S.forEach(i => {
6461
let c = C[i];
6562
if (!c) {
66-
c = document.createElementNS(namespaces.svg, "circle");
67-
c.setAttribute("id", i);
68-
c.setAttribute("r", 4);
69-
c.setAttribute("cx", X ? X[i] : cx);
70-
c.setAttribute("cy", Y ? Y[i] : cy);
63+
c = X && Y ? (x.bandwidth && y.bandwidth ? element("rect", {x: X[i], y: Y[i], width: x.bandwidth(), height: y.bandwidth()})
64+
: x.bandwidth ? element("line", {x1: X[i], x2: X[i] + x.bandwidth(), y1: Y[i], y2: Y[i]})
65+
: y.bandwidth ? element("line", {x1: X[i], x2: X[i], y1: Y[i], y2: Y[i] + y.bandwidth()})
66+
: element("circle", {cx: X[i], cy: Y[i], r: 4}))
67+
: X ? (x.bandwidth ? element("rect", {x: X[i], y: marginTop, width: x.bandwidth(), height: height - marginBottom - marginTop})
68+
: element("line", {x1: X[i], x2: X[i], y1: marginTop, y2: height - marginBottom}))
69+
: (y.bandwidth ? element("rect", {x: marginLeft, y: Y[i], width: width - marginRight - marginLeft, height: y.bandwidth()})
70+
: element("line", {y1: Y[i], y2: Y[i], x1: marginLeft, x2: width - marginRight}));
7171
parent.appendChild(c);
7272
changed = true;
7373
}
@@ -119,11 +119,16 @@ export class Pointer extends Mark {
119119
// If any pointer is down, only consider pointers that are down.
120120
if (P && !down.has(event.pointerId)) return;
121121

122+
// Adjust the pointer to account for band scales; for band scales, the
123+
// data is mapped to the start of the band (e.g., a bar’s left edge).
124+
let [mx, my] = pointerof(event);
125+
if (x.bandwidth) mx -= x.bandwidth() / 2;
126+
if (y.bandwidth) my -= y.bandwidth() / 2;
127+
122128
// Compute the current selection, S: the subset of index that is
123129
// logically selected. Normally this should be an in-order subset of
124130
// index, but it isn’t here because quickselect will reorder in-place
125131
// if the n option is used!
126-
const [mx, my] = pointerof(event);
127132
let S = index;
128133
switch (mode) {
129134
case "xy": {
@@ -185,7 +190,7 @@ export class Pointer extends Mark {
185190
.on("pointerup", event => {
186191
// On pointerup, if the selection is empty, clear the persistent to
187192
// selection to allow the ephemeral selection on subsequent hover.
188-
if (!P.length) select(P = null);
193+
if (P && !P.length) select(P = null);
189194
down.delete(event.pointerId);
190195
})
191196
.on("pointerout", () => {
@@ -211,6 +216,12 @@ function maybeMode(mode = "auto", x, y) {
211216
return mode;
212217
}
213218

219+
function element(name, attrs) {
220+
const e = document.createElementNS(namespaces.svg, name);
221+
for (const key in attrs) e.setAttribute(key, attrs[key]);
222+
return e;
223+
}
224+
214225
export function pointer(data, {x, y, ...options} = {}) {
215226
([x, y] = maybeTuple(x, y));
216227
return new Pointer(data, {...options, x, y});

test/output/aaplVolumeBrushX.svg

Lines changed: 106 additions & 0 deletions
Loading

test/output/aaplVolumePointerX.svg

Lines changed: 104 additions & 0 deletions
Loading

0 commit comments

Comments
 (0)