Skip to content

Commit 98900a2

Browse files
committedMar 28, 2017
refactor dragbox
1 parent 6c60a32 commit 98900a2

File tree

4 files changed

+230
-188
lines changed

4 files changed

+230
-188
lines changed
 

‎src/constants/numerical.js

+6-1
Original file line numberDiff line numberDiff line change
@@ -42,5 +42,10 @@ module.exports = {
4242
* For fast conversion btwn world calendars and epoch ms, the Julian Day Number
4343
* of the unix epoch. From calendars.instance().newDate(1970, 1, 1).toJD()
4444
*/
45-
EPOCHJD: 2440587.5
45+
EPOCHJD: 2440587.5,
46+
47+
/*
48+
* Are two values nearly equal? Compare to 1PPM
49+
*/
50+
ALMOST_EQUAL: 1 - 1e-6
4651
};

‎src/plots/cartesian/constraints.js

+4-12
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,13 @@
1010
'use strict';
1111

1212
var id2name = require('./axis_ids').id2name;
13+
var scaleZoom = require('./scale_zoom');
1314

14-
var ALMOST_EQUAL = 1 - 1e-6;
15+
var ALMOST_EQUAL = require('../../constants/numerical').ALMOST_EQUAL;
1516

1617

1718
module.exports = function enforceAxisConstraints(gd) {
1819
var fullLayout = gd._fullLayout;
19-
var layout = gd.layout;
2020
var constraintGroups = fullLayout._axisConstraintGroups;
2121

2222
var i, j, axisID, ax, normScale;
@@ -52,16 +52,8 @@ module.exports = function enforceAxisConstraints(gd) {
5252
for(j = 0; j < axisIDs.length; j++) {
5353
axisID = axisIDs[j];
5454
normScale = normScales[axisID];
55-
if(normScale > minScale) {
56-
ax = axes[axisID];
57-
var rangeLinear = [ax.r2l(ax.range[0]), ax.r2l(ax.range[1])];
58-
var center = (rangeLinear[0] + rangeLinear[1]) / 2;
59-
var newHalfSpan = (center - rangeLinear[0]) * normScale / minScale;
60-
ax.range = layout[id2name(axisID)].range = [
61-
ax.l2r(center - newHalfSpan),
62-
ax.l2r(center + newHalfSpan)
63-
];
64-
}
55+
56+
if(normScale > minScale) scaleZoom(axes[axisID], normScale / minScale);
6557
}
6658
}
6759
};

‎src/plots/cartesian/dragbox.js

+197-175
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,11 @@ var dragElement = require('../../components/dragelement');
2323

2424
var Axes = require('./axes');
2525
var prepSelect = require('./select');
26+
var scaleZoom = require('./scale_zoom');
27+
2628
var constants = require('./constants');
29+
var MINDRAG = constants.MINDRAG;
30+
var MINZOOM = constants.MINZOOM;
2731

2832

2933
// flag for showing "doubleclick to zoom out" only at the beginning
@@ -46,48 +50,48 @@ module.exports = function dragBox(gd, plotinfo, x, y, w, h, ns, ew) {
4650
// dragged stores whether a drag has occurred, so we don't have to
4751
// redraw unnecessarily, ie if no move bigger than MINDRAG or MINZOOM px
4852
var fullLayout = gd._fullLayout,
53+
zoomlayer = gd._fullLayout._zoomlayer,
54+
isMainDrag = (ns + ew === 'nsew'),
55+
subplots,
56+
xa,
57+
ya,
58+
xs,
59+
ys,
60+
pw,
61+
ph,
62+
allaxes,
63+
xActive,
64+
yActive,
65+
cursor;
66+
67+
function recomputeAxisLists() {
68+
xa = [plotinfo.xaxis];
69+
ya = [plotinfo.yaxis];
70+
var xa0 = xa[0];
71+
var ya0 = ya[0];
72+
pw = xa0._length;
73+
ph = ya0._length;
74+
4975
// if we're dragging two axes at once, also drag overlays
50-
subplots = [plotinfo].concat((ns && ew) ? plotinfo.overlays : []),
51-
xa = [plotinfo.xaxis],
52-
ya = [plotinfo.yaxis],
53-
pw = xa[0]._length,
54-
ph = ya[0]._length,
55-
MINDRAG = constants.MINDRAG,
56-
MINZOOM = constants.MINZOOM,
57-
isMainDrag = (ns + ew === 'nsew');
58-
59-
for(var i = 1; i < subplots.length; i++) {
60-
var subplotXa = subplots[i].xaxis,
61-
subplotYa = subplots[i].yaxis;
62-
if(xa.indexOf(subplotXa) === -1) xa.push(subplotXa);
63-
if(ya.indexOf(subplotYa) === -1) ya.push(subplotYa);
64-
}
76+
subplots = [plotinfo].concat((ns && ew) ? plotinfo.overlays : []);
6577

66-
function isDirectionActive(axList, activeVal) {
67-
for(var i = 0; i < axList.length; i++) {
68-
if(!axList[i].fixedrange) return activeVal;
78+
for(var i = 1; i < subplots.length; i++) {
79+
var subplotXa = subplots[i].xaxis,
80+
subplotYa = subplots[i].yaxis;
81+
if(xa.indexOf(subplotXa) === -1) xa.push(subplotXa);
82+
if(ya.indexOf(subplotYa) === -1) ya.push(subplotYa);
6983
}
70-
return '';
84+
allaxes = xa.concat(ya);
85+
xActive = isDirectionActive(xa, ew);
86+
yActive = isDirectionActive(ya, ns);
87+
cursor = getDragCursor(yActive + xActive, fullLayout.dragmode);
88+
xs = xa0._offset;
89+
ys = ya0._offset;
7190
}
7291

73-
var allaxes = xa.concat(ya),
74-
xActive = isDirectionActive(xa, ew),
75-
yActive = isDirectionActive(ya, ns),
76-
cursor = getDragCursor(yActive + xActive, fullLayout.dragmode),
77-
dragClass = ns + ew + 'drag';
92+
recomputeAxisLists();
7893

79-
var dragger3 = plotinfo.draglayer.selectAll('.' + dragClass).data([0]);
80-
81-
dragger3.enter().append('rect')
82-
.classed('drag', true)
83-
.classed(dragClass, true)
84-
.style({fill: 'transparent', 'stroke-width': 0})
85-
.attr('data-subplot', plotinfo.id);
86-
87-
dragger3.call(Drawing.setRect, x, y, w, h)
88-
.call(setCursor, cursor);
89-
90-
var dragger = dragger3.node();
94+
var dragger = makeDragger(plotinfo, ns + ew + 'drag', cursor, x, y, w, h);
9195

9296
// still need to make the element if the axes are disabled
9397
// but nuke its events (except for maindrag which needs them for hover)
@@ -102,8 +106,6 @@ module.exports = function dragBox(gd, plotinfo, x, y, w, h, ns, ew) {
102106
element: dragger,
103107
gd: gd,
104108
plotinfo: plotinfo,
105-
xaxes: xa,
106-
yaxes: ya,
107109
doubleclick: doubleClick,
108110
prepFn: function(e, startX, startY) {
109111
var dragModeNow = gd._fullLayout.dragmode;
@@ -130,7 +132,7 @@ module.exports = function dragBox(gd, plotinfo, x, y, w, h, ns, ew) {
130132
else if(dragModeNow === 'pan') {
131133
dragOptions.moveFn = plotDrag;
132134
dragOptions.doneFn = dragDone;
133-
clearSelect();
135+
clearSelect(zoomlayer);
134136
}
135137
else if(isSelectOrLasso(dragModeNow)) {
136138
prepSelect(e, startX, startY, dragOptions, dragModeNow);
@@ -140,10 +142,7 @@ module.exports = function dragBox(gd, plotinfo, x, y, w, h, ns, ew) {
140142

141143
dragElement.init(dragOptions);
142144

143-
var zoomlayer = gd._fullLayout._zoomlayer,
144-
xs = plotinfo.xaxis._offset,
145-
ys = plotinfo.yaxis._offset,
146-
x0,
145+
var x0,
147146
y0,
148147
box,
149148
lum,
@@ -153,28 +152,6 @@ module.exports = function dragBox(gd, plotinfo, x, y, w, h, ns, ew) {
153152
zb,
154153
corners;
155154

156-
function recomputeAxisLists() {
157-
xa = [plotinfo.xaxis];
158-
ya = [plotinfo.yaxis];
159-
pw = xa[0]._length;
160-
ph = ya[0]._length;
161-
162-
for(var i = 1; i < subplots.length; i++) {
163-
var subplotXa = subplots[i].xaxis,
164-
subplotYa = subplots[i].yaxis;
165-
if(xa.indexOf(subplotXa) === -1) xa.push(subplotXa);
166-
if(ya.indexOf(subplotYa) === -1) ya.push(subplotYa);
167-
}
168-
allaxes = xa.concat(ya);
169-
xActive = isDirectionActive(xa, ew);
170-
yActive = isDirectionActive(ya, ns);
171-
cursor = getDragCursor(yActive + xActive, fullLayout.dragmode);
172-
xs = plotinfo.xaxis._offset;
173-
ys = plotinfo.yaxis._offset;
174-
dragOptions.xa = xa;
175-
dragOptions.ya = ya;
176-
}
177-
178155
function zoomPrep(e, startX, startY) {
179156
var dragBBox = dragger.getBoundingClientRect();
180157
x0 = startX - dragBBox.left;
@@ -187,34 +164,11 @@ module.exports = function dragBox(gd, plotinfo, x, y, w, h, ns, ew) {
187164
dimmed = false;
188165
zoomMode = 'xy';
189166

190-
zb = zoomlayer.append('path')
191-
.attr('class', 'zoombox')
192-
.style({
193-
'fill': lum > 0.2 ? 'rgba(0,0,0,0)' : 'rgba(255,255,255,0)',
194-
'stroke-width': 0
195-
})
196-
.attr('transform', 'translate(' + xs + ', ' + ys + ')')
197-
.attr('d', path0 + 'Z');
198-
199-
corners = zoomlayer.append('path')
200-
.attr('class', 'zoombox-corners')
201-
.style({
202-
fill: Color.background,
203-
stroke: Color.defaultLine,
204-
'stroke-width': 1,
205-
opacity: 0
206-
})
207-
.attr('transform', 'translate(' + xs + ', ' + ys + ')')
208-
.attr('d', 'M0,0Z');
209-
210-
clearSelect();
211-
}
167+
zb = makeZoombox(zoomlayer, lum, xs, ys, path0);
168+
169+
corners = makeCorners(zoomlayer, xs, ys);
212170

213-
function clearSelect() {
214-
// until we get around to persistent selections, remove the outline
215-
// here. The selection itself will be removed when the plot redraws
216-
// at the end.
217-
zoomlayer.selectAll('.select-outline').remove();
171+
clearSelect(zoomlayer);
218172
}
219173

220174
function zoomMove(dx0, dy0) {
@@ -225,8 +179,7 @@ module.exports = function dragBox(gd, plotinfo, x, y, w, h, ns, ew) {
225179
var x1 = Math.max(0, Math.min(pw, dx0 + x0)),
226180
y1 = Math.max(0, Math.min(ph, dy0 + y0)),
227181
dx = Math.abs(x1 - x0),
228-
dy = Math.abs(y1 - y0),
229-
clen = Math.floor(Math.min(dy, dx, MINZOOM) / 2);
182+
dy = Math.abs(y1 - y0);
230183

231184
box.l = Math.min(x0, x1);
232185
box.r = Math.max(x0, x1);
@@ -246,72 +199,24 @@ module.exports = function dragBox(gd, plotinfo, x, y, w, h, ns, ew) {
246199
box.t = 0;
247200
box.b = ph;
248201
zoomMode = 'x';
249-
corners.attr('d',
250-
'M' + (box.l - 0.5) + ',' + (y0 - MINZOOM - 0.5) +
251-
'h-3v' + (2 * MINZOOM + 1) + 'h3ZM' +
252-
(box.r + 0.5) + ',' + (y0 - MINZOOM - 0.5) +
253-
'h3v' + (2 * MINZOOM + 1) + 'h-3Z');
202+
corners.attr('d', xCorners(box, y0));
254203
}
255204
}
256205
else if(!xActive || dx < Math.min(dy * 0.6, MINZOOM)) {
257206
box.l = 0;
258207
box.r = pw;
259208
zoomMode = 'y';
260-
corners.attr('d',
261-
'M' + (x0 - MINZOOM - 0.5) + ',' + (box.t - 0.5) +
262-
'v-3h' + (2 * MINZOOM + 1) + 'v3ZM' +
263-
(x0 - MINZOOM - 0.5) + ',' + (box.b + 0.5) +
264-
'v3h' + (2 * MINZOOM + 1) + 'v-3Z');
209+
corners.attr('d', yCorners(box, x0));
265210
}
266211
else {
267212
zoomMode = 'xy';
268-
corners.attr('d',
269-
'M' + (box.l - 3.5) + ',' + (box.t - 0.5 + clen) + 'h3v' + (-clen) +
270-
'h' + clen + 'v-3h-' + (clen + 3) + 'ZM' +
271-
(box.r + 3.5) + ',' + (box.t - 0.5 + clen) + 'h-3v' + (-clen) +
272-
'h' + (-clen) + 'v-3h' + (clen + 3) + 'ZM' +
273-
(box.r + 3.5) + ',' + (box.b + 0.5 - clen) + 'h-3v' + clen +
274-
'h' + (-clen) + 'v3h' + (clen + 3) + 'ZM' +
275-
(box.l - 3.5) + ',' + (box.b + 0.5 - clen) + 'h3v' + clen +
276-
'h' + clen + 'v3h-' + (clen + 3) + 'Z');
213+
corners.attr('d', xyCorners(box, Math.floor(Math.min(dy, dx, MINZOOM) / 2)));
277214
}
278215
box.w = box.r - box.l;
279216
box.h = box.b - box.t;
280217

281-
// Not sure about the addition of window.scrollX/Y...
282-
// seems to work but doesn't seem robust.
283-
zb.attr('d',
284-
path0 + 'M' + (box.l) + ',' + (box.t) + 'v' + (box.h) +
285-
'h' + (box.w) + 'v-' + (box.h) + 'h-' + (box.w) + 'Z');
286-
if(!dimmed) {
287-
zb.transition()
288-
.style('fill', lum > 0.2 ? 'rgba(0,0,0,0.4)' :
289-
'rgba(255,255,255,0.3)')
290-
.duration(200);
291-
corners.transition()
292-
.style('opacity', 1)
293-
.duration(200);
294-
dimmed = true;
295-
}
296-
}
297-
298-
function zoomAxRanges(axList, r0Fraction, r1Fraction) {
299-
var i,
300-
axi,
301-
axRangeLinear0,
302-
axRangeLinearSpan;
303-
304-
for(i = 0; i < axList.length; i++) {
305-
axi = axList[i];
306-
if(axi.fixedrange) continue;
307-
308-
axRangeLinear0 = axi._rl[0];
309-
axRangeLinearSpan = axi._rl[1] - axRangeLinear0;
310-
axi.range = [
311-
axi.l2r(axRangeLinear0 + axRangeLinearSpan * r0Fraction),
312-
axi.l2r(axRangeLinear0 + axRangeLinearSpan * r1Fraction)
313-
];
314-
}
218+
updateZoombox(zb, corners, box, path0, dimmed, lum);
219+
dimmed = true;
315220
}
316221

317222
function zoomDone(dragged, numClicks) {
@@ -354,7 +259,7 @@ module.exports = function dragBox(gd, plotinfo, x, y, w, h, ns, ew) {
354259
else if(ew === 'e') hAlign = 'right';
355260

356261
if(gd._context.showAxisRangeEntryBoxes) {
357-
dragger3
262+
d3.select(dragger)
358263
.call(svgTextUtils.makeEditable, null, {
359264
immediate: true,
360265
background: fullLayout.paper_bgcolor,
@@ -426,10 +331,12 @@ module.exports = function dragBox(gd, plotinfo, x, y, w, h, ns, ew) {
426331
function zoomWheelOneAxis(ax, centerFraction, zoom) {
427332
if(ax.fixedrange) return;
428333

429-
var axRange = Lib.simpleMap(ax.range, ax.r2l),
430-
v0 = axRange[0] + (axRange[1] - axRange[0]) * centerFraction;
431-
function doZoom(v) { return ax.l2r(v0 + (v - v0) * zoom); }
432-
ax.range = axRange.map(doZoom);
334+
// var axRange = Lib.simpleMap(ax.range, ax.r2l),
335+
// v0 = axRange[0] + (axRange[1] - axRange[0]) * centerFraction;
336+
// function doZoom(v) { return ax.l2r(v0 + (v - v0) * zoom); }
337+
// ax.range = axRange.map(doZoom);
338+
339+
scaleZoom(ax, zoom, centerFraction);
433340
}
434341

435342
if(ew) {
@@ -473,18 +380,6 @@ module.exports = function dragBox(gd, plotinfo, x, y, w, h, ns, ew) {
473380

474381
recomputeAxisLists();
475382

476-
function dragAxList(axList, pix) {
477-
for(var i = 0; i < axList.length; i++) {
478-
var axi = axList[i];
479-
if(!axi.fixedrange) {
480-
axi.range = [
481-
axi.l2r(axi._rl[0] - pix / axi._m),
482-
axi.l2r(axi._rl[1] - pix / axi._m)
483-
];
484-
}
485-
}
486-
}
487-
488383
if(xActive === 'ew' || yActive === 'ns') {
489384
if(xActive) dragAxList(xa, dx);
490385
if(yActive) dragAxList(ya, dy);
@@ -493,16 +388,6 @@ module.exports = function dragBox(gd, plotinfo, x, y, w, h, ns, ew) {
493388
return;
494389
}
495390

496-
// common transform for dragging one end of an axis
497-
// d>0 is compressing scale (cursor is over the plot,
498-
// the axis end should move with the cursor)
499-
// d<0 is expanding (cursor is off the plot, axis end moves
500-
// nonlinearly so you can expand far)
501-
function dZoom(d) {
502-
return 1 - ((d >= 0) ? Math.min(d, 0.9) :
503-
1 / (1 / Math.max(d, -0.3) + 3.222));
504-
}
505-
506391
// dz: set a new value for one end (0 or 1) of an axis array axArray,
507392
// and return a pixel shift for that end for the viewbox
508393
// based on pixel drag distance d
@@ -648,7 +533,7 @@ module.exports = function dragBox(gd, plotinfo, x, y, w, h, ns, ew) {
648533
if(axi._r[0] !== axi.range[0]) attrs[axi._name + '.range[0]'] = axi.range[0];
649534
if(axi._r[1] !== axi.range[1]) attrs[axi._name + '.range[1]'] = axi.range[1];
650535

651-
axi.range = axi._r.slice();
536+
axi.range = axi._input.range = axi._r.slice();
652537
}
653538

654539
updateSubplots([0, 0, pw, ph]);
@@ -724,6 +609,28 @@ module.exports = function dragBox(gd, plotinfo, x, y, w, h, ns, ew) {
724609
return dragger;
725610
};
726611

612+
function makeDragger(plotinfo, dragClass, cursor, x, y, w, h) {
613+
var dragger3 = plotinfo.draglayer.selectAll('.' + dragClass).data([0]);
614+
615+
dragger3.enter().append('rect')
616+
.classed('drag', true)
617+
.classed(dragClass, true)
618+
.style({fill: 'transparent', 'stroke-width': 0})
619+
.attr('data-subplot', plotinfo.id);
620+
621+
dragger3.call(Drawing.setRect, x, y, w, h)
622+
.call(setCursor, cursor);
623+
624+
return dragger3.node();
625+
}
626+
627+
function isDirectionActive(axList, activeVal) {
628+
for(var i = 0; i < axList.length; i++) {
629+
if(!axList[i].fixedrange) return activeVal;
630+
}
631+
return '';
632+
}
633+
727634
function getEndText(ax, end) {
728635
var initialVal = ax.range[end],
729636
diff = Math.abs(initialVal - ax.range[1 - end]),
@@ -745,6 +652,47 @@ function getEndText(ax, end) {
745652
}
746653
}
747654

655+
function zoomAxRanges(axList, r0Fraction, r1Fraction) {
656+
var i,
657+
axi,
658+
axRangeLinear0,
659+
axRangeLinearSpan;
660+
661+
for(i = 0; i < axList.length; i++) {
662+
axi = axList[i];
663+
if(axi.fixedrange) continue;
664+
665+
axRangeLinear0 = axi._rl[0];
666+
axRangeLinearSpan = axi._rl[1] - axRangeLinear0;
667+
axi.range = [
668+
axi.l2r(axRangeLinear0 + axRangeLinearSpan * r0Fraction),
669+
axi.l2r(axRangeLinear0 + axRangeLinearSpan * r1Fraction)
670+
];
671+
}
672+
}
673+
674+
function dragAxList(axList, pix) {
675+
for(var i = 0; i < axList.length; i++) {
676+
var axi = axList[i];
677+
if(!axi.fixedrange) {
678+
axi.range = [
679+
axi.l2r(axi._rl[0] - pix / axi._m),
680+
axi.l2r(axi._rl[1] - pix / axi._m)
681+
];
682+
}
683+
}
684+
}
685+
686+
// common transform for dragging one end of an axis
687+
// d>0 is compressing scale (cursor is over the plot,
688+
// the axis end should move with the cursor)
689+
// d<0 is expanding (cursor is off the plot, axis end moves
690+
// nonlinearly so you can expand far)
691+
function dZoom(d) {
692+
return 1 - ((d >= 0) ? Math.min(d, 0.9) :
693+
1 / (1 / Math.max(d, -0.3) + 3.222));
694+
}
695+
748696
function getDragCursor(nsew, dragmode) {
749697
if(!nsew) return 'pointer';
750698
if(nsew === 'nsew') {
@@ -754,6 +702,52 @@ function getDragCursor(nsew, dragmode) {
754702
return nsew.toLowerCase() + '-resize';
755703
}
756704

705+
function makeZoombox(zoomlayer, lum, xs, ys, path0) {
706+
return zoomlayer.append('path')
707+
.attr('class', 'zoombox')
708+
.style({
709+
'fill': lum > 0.2 ? 'rgba(0,0,0,0)' : 'rgba(255,255,255,0)',
710+
'stroke-width': 0
711+
})
712+
.attr('transform', 'translate(' + xs + ', ' + ys + ')')
713+
.attr('d', path0 + 'Z');
714+
}
715+
716+
function makeCorners(zoomlayer, xs, ys) {
717+
return zoomlayer.append('path')
718+
.attr('class', 'zoombox-corners')
719+
.style({
720+
fill: Color.background,
721+
stroke: Color.defaultLine,
722+
'stroke-width': 1,
723+
opacity: 0
724+
})
725+
.attr('transform', 'translate(' + xs + ', ' + ys + ')')
726+
.attr('d', 'M0,0Z');
727+
}
728+
729+
function clearSelect(zoomlayer) {
730+
// until we get around to persistent selections, remove the outline
731+
// here. The selection itself will be removed when the plot redraws
732+
// at the end.
733+
zoomlayer.selectAll('.select-outline').remove();
734+
}
735+
736+
function updateZoombox(zb, corners, box, path0, dimmed, lum) {
737+
zb.attr('d',
738+
path0 + 'M' + (box.l) + ',' + (box.t) + 'v' + (box.h) +
739+
'h' + (box.w) + 'v-' + (box.h) + 'h-' + (box.w) + 'Z');
740+
if(!dimmed) {
741+
zb.transition()
742+
.style('fill', lum > 0.2 ? 'rgba(0,0,0,0.4)' :
743+
'rgba(255,255,255,0.3)')
744+
.duration(200);
745+
corners.transition()
746+
.style('opacity', 1)
747+
.duration(200);
748+
}
749+
}
750+
757751
function removeZoombox(gd) {
758752
d3.select(gd)
759753
.selectAll('.zoombox,.js-zoombox-backdrop,.js-zoombox-menu,.zoombox-corners')
@@ -765,3 +759,31 @@ function isSelectOrLasso(dragmode) {
765759

766760
return modes.indexOf(dragmode) !== -1;
767761
}
762+
763+
function xCorners(box, y0) {
764+
return 'M' +
765+
(box.l - 0.5) + ',' + (y0 - MINZOOM - 0.5) +
766+
'h-3v' + (2 * MINZOOM + 1) + 'h3ZM' +
767+
(box.r + 0.5) + ',' + (y0 - MINZOOM - 0.5) +
768+
'h3v' + (2 * MINZOOM + 1) + 'h-3Z';
769+
}
770+
771+
function yCorners(box, x0) {
772+
return 'M' +
773+
(x0 - MINZOOM - 0.5) + ',' + (box.t - 0.5) +
774+
'v-3h' + (2 * MINZOOM + 1) + 'v3ZM' +
775+
(x0 - MINZOOM - 0.5) + ',' + (box.b + 0.5) +
776+
'v3h' + (2 * MINZOOM + 1) + 'v-3Z';
777+
}
778+
779+
function xyCorners(box, clen) {
780+
return 'M' +
781+
(box.l - 3.5) + ',' + (box.t - 0.5 + clen) + 'h3v' + (-clen) +
782+
'h' + clen + 'v-3h-' + (clen + 3) + 'ZM' +
783+
(box.r + 3.5) + ',' + (box.t - 0.5 + clen) + 'h-3v' + (-clen) +
784+
'h' + (-clen) + 'v-3h' + (clen + 3) + 'ZM' +
785+
(box.r + 3.5) + ',' + (box.b + 0.5 - clen) + 'h-3v' + clen +
786+
'h' + (-clen) + 'v3h' + (clen + 3) + 'ZM' +
787+
(box.l - 3.5) + ',' + (box.b + 0.5 - clen) + 'h3v' + clen +
788+
'h' + clen + 'v3h-' + (clen + 3) + 'Z';
789+
}

‎src/plots/cartesian/scale_zoom.js

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
/**
2+
* Copyright 2012-2017, 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+
module.exports = function scaleZoom(ax, factor, centerFraction) {
13+
if(centerFraction === undefined) centerFraction = 0.5;
14+
15+
var rangeLinear = [ax.r2l(ax.range[0]), ax.r2l(ax.range[1])];
16+
var center = rangeLinear[0] + (rangeLinear[1] - rangeLinear[0]) * centerFraction;
17+
var newHalfSpan = (center - rangeLinear[0]) * factor;
18+
19+
ax.range = ax._input.range = [
20+
ax.l2r(center - newHalfSpan),
21+
ax.l2r(center + newHalfSpan)
22+
];
23+
};

0 commit comments

Comments
 (0)
Please sign in to comment.