Skip to content

Commit 5ed113f

Browse files
committed
fix: Interaction errors.
1 parent 4189065 commit 5ed113f

File tree

8 files changed

+2029
-965
lines changed

8 files changed

+2029
-965
lines changed

package-lock.json

Lines changed: 1952 additions & 865 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,11 @@
1515
"docs:build": "vitepress build docs",
1616
"docs:preview": "vitepress preview docs",
1717
"prebuild": "rimraf dist && mkdir dist",
18-
"build": "rollup -c",
18+
"build": "rollup -c -w",
1919
"lint": "eslint src test --ext .js",
2020
"test": "mocha 'test/node/**/*-test.js'",
2121
"prepublishOnly": "npm run test && npm run lint && npm run build",
22-
"serve": "wds --watch"
22+
"serve": "wds --watch --open public"
2323
},
2424
"devDependencies": {
2525
"@rollup/plugin-commonjs": "^25.0.7",
@@ -37,7 +37,7 @@
3737
"rollup-plugin-bundle-size": "^1.0.3",
3838
"rollup-plugin-postcss": "^4.0.2",
3939
"rollup-plugin-svg": "^2.0.0",
40-
"vitepress": "^1.1.4"
40+
"vitepress": "^1.6.3"
4141
},
4242
"dependencies": {
4343
"arquero": "^5.4.0",
@@ -49,7 +49,6 @@
4949
"d3-path": "^3.1.0",
5050
"d3-scale": "^4.0.2",
5151
"d3-selection": "^3.0.0",
52-
"d3-svg-annotation": "^2.5.1",
5352
"d3-time-format": "^4.1.0",
5453
"d3-transition": "^3.0.1",
5554
"svg-path-parser": "^1.1.0"

src/handlers/brush.js

Lines changed: 31 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -1,94 +1,54 @@
11
import { pointer, select } from 'd3-selection';
22

3-
let brush;
4-
5-
function getBrush(svg) {
3+
function getBrusher(svg) {
64
return select(svg)
75
.append('rect')
8-
.attr('opacity', 0.35)
6+
.attr('opacity', 0.25)
97
.attr('x', 0)
108
.attr('y', 0)
119
.attr('width', 0)
1210
.attr('height', 0)
1311
.attr('id', svg.id + '-brush-rect')
1412
.style('fill', 'gray')
15-
.style('stroke', '#fff');
16-
}
17-
18-
export function brushStart(state, event) {
19-
brush = getBrush(state.svg);
20-
const [x, y] = pointer(event, state.svg);
21-
brush.attr('x', x)
22-
.attr('y', y);
13+
.style('stroke', '#fff')
14+
.style('stroke-width', '1px');
2315
}
2416

25-
export function brushMove(state, event) {
26-
event.preventDefault();
17+
export function brush(state) {
18+
const { svg } = state;
19+
let brusher, x, y;
2720

28-
const [x, y] = pointer(event, state.svg);
29-
const rectX = +brush.node().getAttribute('x'); const rectY = +brush.node().getAttribute('y');
30-
const width = x - rectX; const height = y - rectY;
31-
const xTranslate = width < 0 ? width : 0;
32-
const yTranslate = height < 0 ? height : 0;
21+
function brushStart(event) {
22+
event.preventDefault();
3323

34-
brush.attr('width', Math.abs(width))
35-
.attr('height', Math.abs(height))
36-
.attr('transform', 'translate(' + xTranslate + ',' + yTranslate + ')');
37-
return [rectX, rectY, width, height];
38-
}
24+
brusher = getBrusher(svg);
25+
[x, y] = pointer(event, svg);
26+
brusher.attr('x', x)
27+
.attr('y', y);
3928

40-
export function brushEnd(event) {
41-
brush.remove();
42-
}
29+
svg.addEventListener('mousemove', brushMove);
30+
svg.addEventListener('mouseup', brushEnd);
31+
}
4332

44-
function brusher(event) {
45-
let x1, x2, y1, y2;
46-
function bMove(event) {
47-
event.stopPropagation();
33+
function brushMove(event) {
4834
event.preventDefault();
49-
// filter(
50-
// state,
51-
// +rect.getAttribute("x") + +svg.getBoundingClientRect().left + x_translate,
52-
// +rect.getAttribute("y") + +svg.getBoundingClientRect().top + y_translate,
53-
// Math.abs(+rect.getAttribute("width")),
54-
// Math.abs(+rect.getAttribute("height")),
55-
// e.ctrlKey || e.metaKey || e.altKey || e.shiftKey
56-
// );
57-
const mousePos = pointer(event);
58-
if (Math.hypot(mouseStart[0] - mousePos[0], mouseStart[1] - mousePos[1]) < 5) return;
59-
mouseMoved = true;
6035

61-
const [x, y, width, height] = brushMove(state, event);
62-
x1 = state.xAxis.scale.invert(x);
63-
x2 = state.xAxis.scale.invert(x + width);
64-
y1 = state.yAxis.scale.invert(y);
65-
y2 = state.yAxis.scale.invert(y + height);
66-
// brushedMarks = state.svgMarks.filter(function(d) {
67-
// const xField = d.__inferred__data__[state.xAxis.title.innerHTML];
68-
// const yField = d.__inferred__data__[state.yAxis.title.innerHTML];
69-
// return xField >= min([x1, x2]) && xField <= max([x1, x2]) && yField >= min([y1, y2]) && yField <= max([y1, y2]);
70-
// });
71-
}
36+
const [newX, newY] = pointer(event, svg);
37+
const width = newX - x;
38+
const height = newY - y;
39+
const xTranslate = width < 0 ? width : 0;
40+
const yTranslate = height < 0 ? height : 0;
7241

73-
function bEnd(event) {
74-
brushEnd(state, event);
75-
if (mouseMoved) {
76-
const p = generateBrushPredicates(state.xAxis.title.innerHTML.toLowerCase(),
77-
state.yAxis.title.innerHTML.toLowerCase(), [x1, x2], [y1, y2]);
78-
walkQueryPath(roots, p, isMetaKey(event));
79-
applySelections(states);
80-
}
81-
// selectMarks(state.svgMarks, brushedMarks);
82-
// propogateSelection(state.xAxis, brushedMarks);
83-
state.svg.removeEventListener('mousemove', bMove);
84-
state.svg.removeEventListener('mouseup', bEnd);
42+
brusher.attr('width', Math.abs(width))
43+
.attr('height', Math.abs(height))
44+
.attr('transform', 'translate(' + xTranslate + ',' + yTranslate + ')');
8545
}
8646

87-
mouseMoved = false;
88-
const mouseStart = pointer(event);
47+
function brushEnd(_) {
48+
svg.removeEventListener('mousemove', brushMove);
49+
svg.removeEventListener('mouseup', brushEnd);
50+
brusher.remove();
51+
}
8952

90-
if (!state.interactions.brush) return;
91-
brushStart(state, event);
92-
state.svg.addEventListener('mousemove', bMove);
93-
state.svg.addEventListener('mouseup', bEnd);
53+
svg.addEventListener('mousedown', brushStart);
9454
}

src/handlers/zoom.js

Lines changed: 35 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,48 @@
11
import { zoomTransform, zoom as _zoom, zoomIdentity } from '../_d3/zoom';
22
import { select, selectAll } from 'd3-selection';
33
import { Transform } from '../util/transform.js';
4+
import { MarkRole } from '../state/constants.js';
45

56
function addClipping(svg, marks, xAxis, yAxis) {
7+
const nodes = marks.nodes();
8+
if (nodes.length === 0) return;
9+
10+
// Find shared parent of all nodes
11+
let sharedParent = nodes[0].parentElement;
12+
if (!sharedParent) return;
13+
14+
for (let i = 1; i < nodes.length; ++i) {
15+
const current = nodes[i].parentElement;
16+
if (!current) continue;
17+
18+
if (current.contains(sharedParent)) {
19+
sharedParent = current;
20+
} else {
21+
while (!sharedParent.contains(current)) {
22+
sharedParent = sharedParent.parentElement;
23+
}
24+
}
25+
}
26+
27+
xAxis.range = xAxis.range.map(d => d - (sharedParent.localTransform?.translate.x || 0));
28+
yAxis.range = yAxis.range.map(d => d - (sharedParent.localTransform?.translate.y || 0));
29+
630
svg.append('defs')
731
.append('clipPath')
832
.attr('id', 'clip-' + svg.node().id)
933
.append('rect')
10-
.attr('x', 0)
11-
.attr('y', 0)
12-
.attr('width', Math.abs(xAxis.range[1] - xAxis.range[0]))
13-
.attr('height', Math.abs(yAxis.range[0] - yAxis.range[1]));
14-
15-
for (const node of marks.nodes()) {
16-
if (node.parentElement.hasAttribute('clip-path')) continue;
17-
let container = node.parentElement;
18-
if (container.id !== '_g_clip') {
19-
container = document.createElementNS('http://www.w3.org/2000/svg', 'g');
20-
container.id = '_g_clip';
21-
container.setAttribute('clip-path', 'url(#clip-' + svg.node().id + ')');
22-
23-
node.parentElement.appendChild(container);
34+
.attr('x', xAxis.range[0])
35+
.attr('y', yAxis.range[1])
36+
.attr('width', xAxis.range[1] - xAxis.range[0])
37+
.attr('height', yAxis.range[0] - yAxis.range[1]);
38+
39+
const container = select(sharedParent).append('g');
40+
container.attr('clip-path', 'url(#clip-' + svg.node().id + ')');
41+
42+
for (const child of [...sharedParent.children]) {
43+
if (child.hasAttribute(MarkRole)) {
44+
container.node().appendChild(child);
2445
}
25-
container.appendChild(node);
2646
}
2747
}
2848

@@ -70,8 +90,6 @@ export function zoom(state) {
7090
svg = select(svg);
7191
marks = selectAll(marks);
7292

73-
xAxis.axis.scale(xAxis.scale).ticks(xAxis.ticks.length)();
74-
yAxis.axis.scale(yAxis.scale).ticks(yAxis.ticks.length)();
7593
addClipping(svg, marks, xAxis, yAxis);
7694

7795
const gXAxis = svg.append('g').attr('id', 'x-axis-zoom-accessor');

src/orchestration/coordinator.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
import { inspect } from './inspect.js';
22
import { getRootNodes, link, walkQueryPath } from '../parsers/multi-view/link-parser.js';
33
import { parseChart } from '../parsers/engine/parser-engine.js';
4-
import { createMenu } from '../toolbar/menu.js';
4+
// import { createMenu } from '../toolbar/menu.js';
55
import { applySelections, selectPoint } from '../handlers/select.js';
66
import { isMetaKey } from '../util/util.js';
77
import { zoom } from '../handlers/zoom.js';
8+
import { brush } from '../handlers/brush.js';
89

910
export function coordinate(svg, extState) {
1011
const states = svg.map(d => parseChart(inspect(d)));
@@ -28,5 +29,6 @@ function coordinateInteractions(states) {
2829
const { svg } = state;
2930
svg.addEventListener('click', select(state));
3031
// zoom(state);
32+
brush(state);
3133
}
3234
}

src/orchestration/inspect.js

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -44,10 +44,7 @@ function extractElementInformation(svg, element, parent = false) {
4444
};
4545
};
4646

47-
element.globalPosition = new Transform(
48-
element.getBBoxCustom()[CenterX] - svg.getBBoxCustom().left,
49-
element.getBBoxCustom()[CenterY] - svg.getBBoxCustom().top
50-
);
47+
element.globalPosition = new Transform(element.getBBoxCustom()[CenterX], element.getBBoxCustom()[CenterY]);
5148
element.localTransform = parseTransform(element);
5249
}
5350

@@ -101,6 +98,7 @@ function analyzeDomTree(element, state, transform, parent = false) {
10198
if (!element.id) element.id = DefaultSvgId + '-' + id++;
10299
} else if (element.nodeName === 'g') { // Maintain <g> element transforms.
103100
parseTransform(element, transform);
101+
element.localTransform = transform;
104102
} else if (element.nodeName === '#text' && element.textContent.trim() !== '') { // Instantiate text elements for non-empty references.
105103
let el = element.parentElement;
106104
if (el.nodeName !== 'text') {

src/parsers/helpers/axis-parser.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ function computeAxisDomain(axis) {
7979
}
8080
}
8181

82-
function computeAxisRange(axis, isX) {
82+
function computeAxisRange(axis, svg, isX) {
8383
const axisTicks = axis.ticks;
8484
const firstTickBBox = axisTicks[0].marks[0].getBBoxCustom();
8585
const lastTickBBox = axisTicks[axisTicks.length - 1].marks[0].getBBoxCustom();
@@ -142,7 +142,7 @@ export function inferAxes(state, textGroups, markGroups) {
142142

143143
describeAxis(a, axisContainer);
144144
computeAxisDomain(axisContainer);
145-
computeAxisRange(axisContainer, isX);
145+
computeAxisRange(axisContainer, svg, isX);
146146
computeScale(state, axisContainer, isX);
147147
});
148148

test/browser/index.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
<div id="mocha"></div>
1616
<div id="root"></div>
1717

18-
<script src="https://www.chaijs.com/chai.js"></script>
18+
<script src="https://unpkg.com/chai@4/chai.js"></script>
1919
<script src="https://unpkg.com/mocha/mocha.js"></script>
2020

2121
<script class="mocha-init">

0 commit comments

Comments
 (0)