-
Notifications
You must be signed in to change notification settings - Fork 346
/
drag.js
132 lines (111 loc) 路 3.32 KB
/
drag.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
/**
* Copyright (c) 2017 ~ present NAVER Corp.
* billboard.js project is licensed under the MIT license
*/
import {select as d3Select} from "d3-selection";
import ChartInternal from "../internals/ChartInternal";
import CLASS from "../config/classes";
import {extend, getPathBox} from "../internals/util";
extend(ChartInternal.prototype, {
/**
* Called when dragging.
* Data points can be selected.
* @private
* @param {Object} mouse Object
*/
drag(mouse) {
const $$ = this;
const config = $$.config;
const main = $$.main;
if ($$.hasArcType() ||
!config.data_selection_enabled || // do nothing if not selectable
(config.zoom_enabled && !$$.zoom.altDomain) || // skip if zoomable because of conflict drag behavior
!config.data_selection_multiple // skip when single selection because drag is used for multiple selection
) {
return;
}
const [sx, sy] = $$.dragStart;
const [mx, my] = mouse;
const minX = Math.min(sx, mx);
const maxX = Math.max(sx, mx);
const minY = config.data_selection_grouped ? $$.margin.top : Math.min(sy, my);
const maxY = config.data_selection_grouped ? $$.height : Math.max(sy, my);
main.select(`.${CLASS.dragarea}`)
.attr("x", minX)
.attr("y", minY)
.attr("width", maxX - minX)
.attr("height", maxY - minY);
// TODO: binary search when multiple xs
main.selectAll(`.${CLASS.shapes}`)
.selectAll(`.${CLASS.shape}`)
.filter(d => config.data_selection_isselectable(d))
.each(function(d, i) {
const shape = d3Select(this);
const isSelected = shape.classed(CLASS.SELECTED);
const isIncluded = shape.classed(CLASS.INCLUDED);
let toggle;
let isWithin = false;
if (shape.classed(CLASS.circle)) {
const x = shape.attr("cx") * 1;
const y = shape.attr("cy") * 1;
toggle = $$.togglePoint;
isWithin = minX < x && x < maxX && minY < y && y < maxY;
} else if (shape.classed(CLASS.bar)) {
const {x, y, width, height} = getPathBox(this);
toggle = $$.togglePath;
isWithin = !(maxX < x || x + width < minX) && !(maxY < y || y + height < minY);
} else {
// line/area selection not supported yet
return;
}
if (isWithin ^ isIncluded) {
shape.classed(CLASS.INCLUDED, !isIncluded);
// TODO: included/unincluded callback here
shape.classed(CLASS.SELECTED, !isSelected);
toggle.call($$, !isSelected, shape, d, i);
}
});
},
/**
* Called when the drag starts.
* Adds and Shows the drag area.
* @private
* @param {Object} mouse Object
*/
dragstart(mouse) {
const $$ = this;
const config = $$.config;
if ($$.hasArcType() || !config.data_selection_enabled) {
return;
}
$$.dragStart = mouse;
$$.main.select(`.${CLASS.chart}`)
.append("rect")
.attr("class", CLASS.dragarea)
.style("opacity", "0.1");
$$.setDragStatus(true);
},
/**
* Called when the drag finishes.
* Removes the drag area.
* @private
*/
dragend() {
const $$ = this;
const config = $$.config;
if ($$.hasArcType() || !config.data_selection_enabled) { // do nothing if not selectable
return;
}
$$.main.select(`.${CLASS.dragarea}`)
.transition()
.duration(100)
.style("opacity", "0")
.remove();
$$.main.selectAll(`.${CLASS.shape}`)
.classed(CLASS.INCLUDED, false);
$$.setDragStatus(false);
},
setDragStatus(isDragging) {
this.dragging = isDragging;
}
});