Skip to content

Commit 7130a0e

Browse files
committed
internals: lasso local replace d3-lasso
1 parent 68d3a65 commit 7130a0e

File tree

6 files changed

+274
-12
lines changed

6 files changed

+274
-12
lines changed

DESCRIPTION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
Type: Package
22
Package: ggiraph
33
Title: Make 'ggplot2' Graphics Interactive
4-
Version: 0.9.4.001
4+
Version: 0.9.4.002
55
Authors@R: c(
66
person("David", "Gohel", , "david.gohel@ardata.fr", role = c("aut", "cre")),
77
person("Panagiotis", "Skintzos", , "sigmapi@posteo.net", role = "aut"),

NEWS.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# ggiraph 0.9.4
22

33
- toolbar gains new button "fullscreen".
4-
4+
- internals: lasso local replace d3-lasso and ggiraph is using the latest version od d3.js.
55

66
# ggiraph 0.9.3
77

inst/htmlwidgets/girafe.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

srcjs/modules/lasso.js

Lines changed: 264 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,264 @@
1+
import * as d3 from 'd3';
2+
import classifyPoint from 'robust-point-in-polygon';
3+
4+
export function lasso() {
5+
var items = [],
6+
closePathDistance = 75,
7+
closePathSelect = true,
8+
isPathClosed = false,
9+
hoverSelect = true,
10+
targetArea,
11+
on = {
12+
start: function () {},
13+
draw: function () {},
14+
end: function () {}
15+
};
16+
17+
// Function to execute on call
18+
function lasso(_this) {
19+
// add a new group for the lasso
20+
var g = _this.append('g').attr('class', 'lasso');
21+
22+
// add the drawn path for the lasso
23+
var dyn_path = g.append('path').attr('class', 'drawn');
24+
25+
// add a closed path
26+
var close_path = g.append('path').attr('class', 'loop_close');
27+
28+
// add an origin node
29+
var origin_node = g.append('circle').attr('class', 'origin');
30+
31+
// The transformed lasso path for rendering
32+
var tpath;
33+
34+
// The lasso origin for calculations
35+
var origin;
36+
37+
// The transformed lasso origin for rendering
38+
var torigin;
39+
40+
// Store off coordinates drawn
41+
var drawnCoords;
42+
43+
// Apply drag behaviors
44+
var dragAction = d3
45+
.drag()
46+
.on('start', dragstart)
47+
.on('drag', dragmove)
48+
.on('end', dragend);
49+
50+
// Call drag
51+
targetArea.call(dragAction);
52+
53+
function dragstart() {
54+
// Init coordinates
55+
drawnCoords = [];
56+
57+
// Initialize paths
58+
tpath = '';
59+
dyn_path.attr('d', null);
60+
close_path.attr('d', null);
61+
62+
// Set every item to have a false selection and reset their center point and counters
63+
items.nodes().forEach(function (e) {
64+
e.__lasso.possible = false;
65+
e.__lasso.selected = false;
66+
e.__lasso.hoverSelect = false;
67+
e.__lasso.loopSelect = false;
68+
69+
var box = e.getBoundingClientRect();
70+
e.__lasso.lassoPoint = [
71+
Math.round(box.left + box.width / 2),
72+
Math.round(box.top + box.height / 2)
73+
];
74+
});
75+
76+
// if hover is on, add hover function
77+
if (hoverSelect) {
78+
items.on('mouseover.lasso', function () {
79+
// if hovered, change lasso selection attribute to true
80+
this.__lasso.hoverSelect = true;
81+
});
82+
}
83+
84+
// Run user defined start function
85+
on.start();
86+
}
87+
88+
function dragmove(event) {
89+
// Get mouse position within body, used for calculations
90+
var x, y;
91+
if (event.sourceEvent.type === 'touchmove') {
92+
x = event.sourceEvent.touches[0].clientX;
93+
y = event.sourceEvent.touches[0].clientY;
94+
} else {
95+
x = event.sourceEvent.clientX;
96+
y = event.sourceEvent.clientY;
97+
}
98+
99+
// Get mouse position within drawing area, used for rendering
100+
var point = d3.pointer(event, this);
101+
var tx = point[0];
102+
var ty = point[1];
103+
104+
// Initialize the path or add the latest point to it
105+
if (tpath === '') {
106+
tpath = tpath + 'M ' + tx + ' ' + ty;
107+
origin = [x, y];
108+
torigin = [tx, ty];
109+
// Draw origin node
110+
origin_node
111+
.attr('cx', tx)
112+
.attr('cy', ty)
113+
.attr('r', 7)
114+
.attr('display', null);
115+
} else {
116+
tpath = tpath + ' L ' + tx + ' ' + ty;
117+
}
118+
119+
drawnCoords.push([x, y]);
120+
121+
// Calculate the current distance from the lasso origin
122+
var distance = Math.sqrt(
123+
Math.pow(x - origin[0], 2) + Math.pow(y - origin[1], 2)
124+
);
125+
126+
// Set the closed path line
127+
var close_draw_path =
128+
'M ' + tx + ' ' + ty + ' L ' + torigin[0] + ' ' + torigin[1];
129+
130+
// Draw the lines
131+
dyn_path.attr('d', tpath);
132+
133+
close_path.attr('d', close_draw_path);
134+
135+
// Check if the path is closed
136+
isPathClosed = distance <= closePathDistance ? true : false;
137+
138+
// If within the closed path distance parameter, show the closed path. otherwise, hide it
139+
if (isPathClosed && closePathSelect) {
140+
close_path.attr('display', null);
141+
} else {
142+
close_path.attr('display', 'none');
143+
}
144+
145+
items.nodes().forEach(function (n) {
146+
n.__lasso.loopSelect =
147+
isPathClosed && closePathSelect
148+
? classifyPoint(drawnCoords, n.__lasso.lassoPoint) < 1
149+
: false;
150+
n.__lasso.possible = n.__lasso.hoverSelect || n.__lasso.loopSelect;
151+
});
152+
153+
on.draw();
154+
}
155+
156+
function dragend() {
157+
// Remove mouseover tagging function
158+
items.on('mouseover.lasso', null);
159+
160+
items.nodes().forEach(function (n) {
161+
n.__lasso.selected = n.__lasso.possible;
162+
n.__lasso.possible = false;
163+
});
164+
165+
// Clear lasso
166+
dyn_path.attr('d', null);
167+
close_path.attr('d', null);
168+
origin_node.attr('display', 'none');
169+
170+
// Run user defined end function
171+
on.end();
172+
}
173+
}
174+
175+
// Set or get list of items for lasso to select
176+
lasso.items = function (_) {
177+
if (!arguments.length) return items;
178+
items = _;
179+
var nodes = items.nodes();
180+
nodes.forEach(function (n) {
181+
n.__lasso = {
182+
possible: false,
183+
selected: false
184+
};
185+
});
186+
return lasso;
187+
};
188+
189+
// Return possible items
190+
lasso.possibleItems = function () {
191+
return items.filter(function () {
192+
return this.__lasso.possible;
193+
});
194+
};
195+
196+
// Return selected items
197+
lasso.selectedItems = function () {
198+
return items.filter(function () {
199+
return this.__lasso.selected;
200+
});
201+
};
202+
203+
// Return not possible items
204+
lasso.notPossibleItems = function () {
205+
return items.filter(function () {
206+
return !this.__lasso.possible;
207+
});
208+
};
209+
210+
// Return not selected items
211+
lasso.notSelectedItems = function () {
212+
return items.filter(function () {
213+
return !this.__lasso.selected;
214+
});
215+
};
216+
217+
// Distance required before path auto closes loop
218+
lasso.closePathDistance = function (_) {
219+
if (!arguments.length) return closePathDistance;
220+
closePathDistance = _;
221+
return lasso;
222+
};
223+
224+
// Option to loop select or not
225+
lasso.closePathSelect = function (_) {
226+
if (!arguments.length) return closePathSelect;
227+
closePathSelect = _ === true ? true : false;
228+
return lasso;
229+
};
230+
231+
// Not sure what this is for
232+
lasso.isPathClosed = function (_) {
233+
if (!arguments.length) return isPathClosed;
234+
isPathClosed = _ === true ? true : false;
235+
return lasso;
236+
};
237+
238+
// Option to select on hover or not
239+
lasso.hoverSelect = function (_) {
240+
if (!arguments.length) return hoverSelect;
241+
hoverSelect = _ === true ? true : false;
242+
return lasso;
243+
};
244+
245+
// Events
246+
lasso.on = function (type, _) {
247+
if (!arguments.length) return on;
248+
if (arguments.length === 1) return on[type];
249+
var types = ['start', 'draw', 'end'];
250+
if (types.indexOf(type) > -1) {
251+
on[type] = _;
252+
}
253+
return lasso;
254+
};
255+
256+
// Area where lasso can be triggered from
257+
lasso.targetArea = function (_) {
258+
if (!arguments.length) return targetArea;
259+
targetArea = _;
260+
return lasso;
261+
};
262+
263+
return lasso;
264+
}

srcjs/modules/selection.js

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,5 @@
11
import * as d3 from 'd3';
2-
import { lasso } from 'd3-lasso';
3-
4-
// Make d3 available globally for d3-lasso
5-
window.d3 = d3;
2+
import { lasso } from './lasso';
63

74
export default class SelectionHandler {
85
constructor(svgid, options) {

srcjs/modules/zoom.js

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -114,8 +114,8 @@ export default class ZoomHandler {
114114
.on('start', function () {
115115
targetEl.style('cursor', 'move');
116116
})
117-
.on('zoom', function () {
118-
targetEl.attr('transform', d3.event.transform);
117+
.on('zoom', function (event) {
118+
targetEl.attr('transform', event.transform);
119119
})
120120
.on('end', function () {
121121
targetEl.style('cursor', 'auto');
@@ -296,10 +296,11 @@ function dragrect() {
296296
on.start();
297297
}
298298

299-
function dragmove() {
299+
function dragmove(event) {
300300
// mouse position within drawing area
301-
const tx = d3.mouse(this)[0];
302-
const ty = d3.mouse(this)[1];
301+
const point = d3.pointer(event, this);
302+
const tx = point[0];
303+
const ty = point[1];
303304

304305
// initialize the points or set the latest point
305306
if (!p1) {

0 commit comments

Comments
 (0)