Skip to content

Commit a824d85

Browse files
committed
split new draw code into multiple files
1 parent 6dbbd5c commit a824d85

File tree

7 files changed

+994
-932
lines changed

7 files changed

+994
-932
lines changed

src/components/shapes/draw.js

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,8 @@ var Registry = require('../../registry');
1313
var Lib = require('../../lib');
1414
var Axes = require('../../plots/cartesian/axes');
1515

16-
var drawNewShape = require('./draw_newshape/draw');
17-
var readPaths = drawNewShape.readPaths;
18-
var displayOutlines = drawNewShape.displayOutlines;
16+
var readPaths = require('./draw_newshape/helpers').readPaths;
17+
var displayOutlines = require('./draw_newshape/display_outlines');
1918

2019
var clearOutlineControllers = require('../../plots/cartesian/handle_outline').clearOutlineControllers;
2120

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
/**
2+
* Copyright 2012-2020, Plotly, Inc.
3+
* All rights reserved.
4+
*
5+
* This source code is licensed under the MIT license found in the
6+
* LICENSE file in the root directory of this source tree.
7+
*/
8+
9+
'use strict';
10+
11+
var CIRCLE_SIDES = 32; // should be divisible by 4
12+
13+
module.exports = {
14+
CIRCLE_SIDES: CIRCLE_SIDES,
15+
i000: 0,
16+
i090: CIRCLE_SIDES / 4,
17+
i180: CIRCLE_SIDES / 2,
18+
i270: CIRCLE_SIDES / 4 * 3,
19+
cos45: Math.cos(Math.PI / 4),
20+
sin45: Math.sin(Math.PI / 4),
21+
SQRT2: Math.sqrt(2)
22+
};
Lines changed: 359 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,359 @@
1+
/**
2+
* Copyright 2012-2020, Plotly, Inc.
3+
* All rights reserved.
4+
*
5+
* This source code is licensed under the MIT license found in the
6+
* LICENSE file in the root directory of this source tree.
7+
*/
8+
9+
10+
'use strict';
11+
12+
var dragElement = require('../../dragelement');
13+
var dragHelpers = require('../../dragelement/helpers');
14+
var drawMode = dragHelpers.drawMode;
15+
16+
var Registry = require('../../../registry');
17+
var Lib = require('../../../lib');
18+
var setCursor = require('../../../lib/setcursor');
19+
20+
var MINSELECT = require('../../../plots/cartesian/constants').MINSELECT;
21+
var constants = require('./constants');
22+
var i000 = constants.i000;
23+
var i090 = constants.i090;
24+
var i180 = constants.i180;
25+
var i270 = constants.i270;
26+
27+
var handleOutline = require('../../../plots/cartesian/handle_outline');
28+
var clearOutlineControllers = handleOutline.clearOutlineControllers;
29+
30+
var helpers = require('./helpers');
31+
var pointsShapeRectangle = helpers.pointsShapeRectangle;
32+
var pointsShapeEllipse = helpers.pointsShapeEllipse;
33+
var writePaths = helpers.writePaths;
34+
var newShapes = require('./newshapes');
35+
36+
module.exports = function displayOutlines(polygons, outlines, dragOptions, nCalls) {
37+
if(!nCalls) nCalls = 0;
38+
39+
var gd = dragOptions.gd;
40+
41+
function redraw() {
42+
// recursive call
43+
displayOutlines(polygons, outlines, dragOptions, nCalls++);
44+
45+
dragOptions.isActiveShape = false; // i.e. to disable controllers
46+
var shapes = newShapes(outlines, dragOptions);
47+
if(shapes) {
48+
Registry.call('_guiRelayout', gd, {
49+
shapes: shapes // update active shape
50+
});
51+
}
52+
}
53+
54+
55+
// remove previous controllers - only if there is an active shape
56+
if(gd._fullLayout._activeShapeIndex >= 0) clearOutlineControllers(gd);
57+
58+
var isActiveShape = dragOptions.isActiveShape;
59+
var fullLayout = gd._fullLayout;
60+
var zoomLayer = fullLayout._zoomlayer;
61+
62+
var dragmode = dragOptions.dragmode;
63+
var isDrawMode = drawMode(dragmode);
64+
65+
if(isDrawMode) gd._fullLayout._drawing = true;
66+
67+
// make outline
68+
outlines.attr('d', writePaths(polygons));
69+
70+
// add controllers
71+
var rVertexController = MINSELECT * 1.5; // bigger vertex buttons
72+
var vertexDragOptions;
73+
var shapeDragOptions;
74+
var indexI; // cell index
75+
var indexJ; // vertex or cell-controller index
76+
var copyPolygons;
77+
78+
copyPolygons = recordPositions([], polygons);
79+
80+
if(isActiveShape) {
81+
var g = zoomLayer.append('g').attr('class', 'outline-controllers');
82+
addVertexControllers(g);
83+
addShapeControllers();
84+
}
85+
86+
function startDragVertex(evt) {
87+
indexI = +evt.srcElement.getAttribute('data-i');
88+
indexJ = +evt.srcElement.getAttribute('data-j');
89+
90+
vertexDragOptions[indexI][indexJ].moveFn = moveVertexController;
91+
}
92+
93+
function moveVertexController(dx, dy) {
94+
if(!polygons.length) return;
95+
96+
var x0 = copyPolygons[indexI][indexJ][1];
97+
var y0 = copyPolygons[indexI][indexJ][2];
98+
99+
var cell = polygons[indexI];
100+
var len = cell.length;
101+
if(pointsShapeRectangle(cell)) {
102+
for(var q = 0; q < len; q++) {
103+
if(q === indexJ) continue;
104+
105+
// move other corners of rectangle
106+
var pos = cell[q];
107+
108+
if(pos[1] === cell[indexJ][1]) {
109+
pos[1] = x0 + dx;
110+
}
111+
112+
if(pos[2] === cell[indexJ][2]) {
113+
pos[2] = y0 + dy;
114+
}
115+
}
116+
// move the corner
117+
cell[indexJ][1] = x0 + dx;
118+
cell[indexJ][2] = y0 + dy;
119+
120+
if(!pointsShapeRectangle(cell)) {
121+
// reject result to rectangles with ensure areas
122+
for(var j = 0; j < len; j++) {
123+
for(var k = 0; k < cell[j].length; k++) {
124+
cell[j][k] = copyPolygons[indexI][j][k];
125+
}
126+
}
127+
}
128+
} else { // other polylines
129+
cell[indexJ][1] = x0 + dx;
130+
cell[indexJ][2] = y0 + dy;
131+
}
132+
133+
redraw();
134+
}
135+
136+
function endDragVertexController(evt) {
137+
Lib.noop(evt);
138+
}
139+
140+
function removeVertex() {
141+
if(!polygons.length) return;
142+
if(!polygons[indexI]) return;
143+
if(!polygons[indexI].length) return;
144+
145+
var newPolygon = [];
146+
for(var j = 0; j < polygons[indexI].length; j++) {
147+
if(j !== indexJ) {
148+
newPolygon.push(
149+
polygons[indexI][j]
150+
);
151+
}
152+
}
153+
154+
if(newPolygon.length > 1 && !(
155+
newPolygon.length === 2 && newPolygon[1][0] === 'Z')
156+
) {
157+
if(indexJ === 0) {
158+
newPolygon[0][0] = 'M';
159+
}
160+
161+
polygons[indexI] = newPolygon;
162+
163+
redraw();
164+
}
165+
}
166+
167+
function clickVertexController(numClicks, evt) {
168+
if(numClicks === 2) {
169+
indexI = +evt.srcElement.getAttribute('data-i');
170+
indexJ = +evt.srcElement.getAttribute('data-j');
171+
172+
var cell = polygons[indexI];
173+
if(
174+
!pointsShapeRectangle(cell) &&
175+
!pointsShapeEllipse(cell)
176+
) {
177+
removeVertex();
178+
}
179+
}
180+
}
181+
182+
function addVertexControllers(g) {
183+
vertexDragOptions = [];
184+
185+
for(var i = 0; i < polygons.length; i++) {
186+
var cell = polygons[i];
187+
188+
var onRect = pointsShapeRectangle(cell);
189+
var onEllipse = !onRect && pointsShapeEllipse(cell);
190+
191+
var minX;
192+
var minY;
193+
var maxX;
194+
var maxY;
195+
if(onRect) {
196+
// compute bounding box
197+
minX = calcMin(cell, 1);
198+
minY = calcMin(cell, 2);
199+
maxX = calcMax(cell, 1);
200+
maxY = calcMax(cell, 2);
201+
}
202+
203+
vertexDragOptions[i] = [];
204+
for(var j = 0; j < cell.length; j++) {
205+
if(cell[j][0] === 'Z') continue;
206+
207+
if(onEllipse &&
208+
j !== i000 &&
209+
j !== i090 &&
210+
j !== i180 &&
211+
j !== i270
212+
) {
213+
continue;
214+
}
215+
216+
var x = cell[j][1];
217+
var y = cell[j][2];
218+
219+
var rIcon = 3;
220+
var button = g.append(onRect ? 'rect' : 'circle')
221+
.style({
222+
'mix-blend-mode': 'luminosity',
223+
fill: 'black',
224+
stroke: 'white',
225+
'stroke-width': 1
226+
});
227+
228+
if(onRect) {
229+
button
230+
.attr('x', x - rIcon)
231+
.attr('y', y - rIcon)
232+
.attr('width', 2 * rIcon)
233+
.attr('height', 2 * rIcon);
234+
} else {
235+
button
236+
.attr('cx', x)
237+
.attr('cy', y)
238+
.attr('r', rIcon);
239+
}
240+
241+
var vertex = g.append(onRect ? 'rect' : 'circle')
242+
.attr('data-i', i)
243+
.attr('data-j', j)
244+
.style({
245+
opacity: 0
246+
});
247+
248+
if(onRect) {
249+
var ratioX = (x - minX) / (maxX - minX);
250+
var ratioY = (y - minY) / (maxY - minY);
251+
if(isFinite(ratioX) && isFinite(ratioY)) {
252+
setCursor(
253+
vertex,
254+
dragElement.getCursor(ratioX, 1 - ratioY)
255+
);
256+
}
257+
258+
vertex
259+
.attr('x', x - rVertexController)
260+
.attr('y', y - rVertexController)
261+
.attr('width', 2 * rVertexController)
262+
.attr('height', 2 * rVertexController);
263+
} else {
264+
vertex
265+
.classed('cursor-grab', true)
266+
.attr('cx', x)
267+
.attr('cy', y)
268+
.attr('r', rVertexController);
269+
}
270+
271+
vertexDragOptions[i][j] = {
272+
element: vertex.node(),
273+
gd: gd,
274+
prepFn: startDragVertex,
275+
doneFn: endDragVertexController,
276+
clickFn: clickVertexController
277+
};
278+
279+
dragElement.init(vertexDragOptions[i][j]);
280+
}
281+
}
282+
}
283+
284+
function moveShape(dx, dy) {
285+
if(!polygons.length) return;
286+
287+
for(var i = 0; i < polygons.length; i++) {
288+
for(var j = 0; j < polygons[i].length; j++) {
289+
for(var k = 0; k + 2 < polygons[i][j].length; k += 2) {
290+
polygons[i][j][k + 1] = copyPolygons[i][j][k + 1] + dx;
291+
polygons[i][j][k + 2] = copyPolygons[i][j][k + 2] + dy;
292+
}
293+
}
294+
}
295+
}
296+
297+
function moveShapeController(dx, dy) {
298+
moveShape(dx, dy);
299+
300+
redraw();
301+
}
302+
303+
function startDragShapeController(evt) {
304+
indexI = +evt.srcElement.getAttribute('data-i');
305+
if(!indexI) indexI = 0; // ensure non-existing move button get zero index
306+
307+
shapeDragOptions[indexI].moveFn = moveShapeController;
308+
}
309+
310+
function endDragShapeController(evt) {
311+
Lib.noop(evt);
312+
}
313+
314+
function addShapeControllers() {
315+
shapeDragOptions = [];
316+
317+
if(!polygons.length) return;
318+
319+
var i = 0;
320+
shapeDragOptions[i] = {
321+
element: outlines[0][0],
322+
gd: gd,
323+
prepFn: startDragShapeController,
324+
doneFn: endDragShapeController
325+
};
326+
327+
dragElement.init(shapeDragOptions[i]);
328+
}
329+
};
330+
331+
function calcMin(cell, dim) {
332+
var v = Infinity;
333+
for(var i = 0; i < cell.length; i++) {
334+
v = Math.min(v, cell[i][dim]);
335+
}
336+
return v;
337+
}
338+
339+
function calcMax(cell, dim) {
340+
var v = -Infinity;
341+
for(var i = 0; i < cell.length; i++) {
342+
v = Math.max(v, cell[i][dim]);
343+
}
344+
return v;
345+
}
346+
347+
function recordPositions(polygonsOut, polygonsIn) {
348+
for(var i = 0; i < polygonsIn.length; i++) {
349+
var cell = polygonsIn[i];
350+
polygonsOut[i] = [];
351+
for(var j = 0; j < cell.length; j++) {
352+
polygonsOut[i][j] = [];
353+
for(var k = 0; k < cell[j].length; k++) {
354+
polygonsOut[i][j][k] = cell[j][k];
355+
}
356+
}
357+
}
358+
return polygonsOut;
359+
}

0 commit comments

Comments
 (0)