Skip to content

Commit 58f2a0b

Browse files
committed
Merge remote-tracking branch 'origin/master' into v4.0
2 parents ba74af7 + c061695 commit 58f2a0b

6 files changed

Lines changed: 115 additions & 9 deletions

File tree

draftlogs/7815_fix.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
- Defer automargin during scroll-wheel zoom, to prevent erratic jittering while zooming [[#7815](https://github.com/plotly/plotly.js/pull/7815)], with thanks to @keilogic for the contribution!

draftlogs/7959_fix.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
- Fix numeric color sorting for bundled parallel-categories (parcats) paths [[#7959](https://github.com/plotly/plotly.js/pull/7959)], with thanks to @CAOShurong for the contribution!

src/plots/cartesian/dragbox.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -486,6 +486,10 @@ function makeDragBox(gd, plotinfo, x, y, w, h, ns, ew) {
486486
return;
487487
}
488488

489+
// Keep automargin from changing plot size while wheel zoom is still
490+
// debouncing. The final dragTail relayout will release this guard.
491+
gd._fullLayout._replotting = true;
492+
489493
var zoom = Math.exp(-Math.min(Math.max(wheelDelta, -20), 20) / 200);
490494
var gbb = mainplot.draglayer.select('.nsewdrag').node().getBoundingClientRect();
491495
var xfrac = (e.clientX - gbb.left) / gbb.width;

src/traces/parcats/parcats.js

Lines changed: 29 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -370,6 +370,33 @@ function compareRawColor(a, b) {
370370
}
371371
}
372372

373+
/**
374+
* Compare two sort arrays element by element in ascending order.
375+
* Values that do not order against each other, for example NaN, sort last.
376+
* The shorter array sorts first when one array is a prefix of the other.
377+
*
378+
* @param {Array} a
379+
* @param {Array} b
380+
*/
381+
function compareArrays(a, b) {
382+
for(var i = 0; i < Math.min(a.length, b.length); i++) {
383+
var valA = a[i];
384+
var valB = b[i];
385+
386+
if(valA < valB) return -1;
387+
if(valA > valB) return 1;
388+
// Handle values that do not order against each other (NaN, undefined, etc.)
389+
if(valA !== valB) {
390+
// Sort these after every orderable value.
391+
var badA = isNaN(valA);
392+
var badB = isNaN(valB);
393+
if(badA !== badB) return badA ? 1 : -1;
394+
}
395+
}
396+
397+
return a.length - b.length;
398+
}
399+
373400
/**
374401
* Handle path mouseover
375402
* @param {PathViewModel} d
@@ -1732,15 +1759,8 @@ function updatePathViewModels(parcatsViewModel) {
17321759
sortArray2.unshift(v2.rawColor);
17331760
}
17341761

1735-
// colors equal, sort by display categories
1736-
if(sortArray1 < sortArray2) {
1737-
return -1;
1738-
}
1739-
if(sortArray1 > sortArray2) {
1740-
return 1;
1741-
}
1742-
1743-
return 0;
1762+
// Sort by color, then display categories
1763+
return compareArrays(sortArray1, sortArray2);
17441764
});
17451765

17461766
// Create path models

test/jasmine/tests/cartesian_interact_test.js

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ var d3SelectAll = require('../../strict-d3').selectAll;
44
var Plotly = require('../../../lib/index');
55
var Lib = require('../../../src/lib');
66
var Axes = require('../../../src/plots/cartesian/axes');
7+
var Plots = require('../../../src/plots/plots');
78
var Drawing = require('../../../src/components/drawing');
89
var constants = require('../../../src/plots/cartesian/constants');
910

@@ -691,6 +692,36 @@ describe('axis zoom/pan and main plot zoom', function() {
691692
.then(done, done.fail);
692693
});
693694

695+
it('should defer automargin while zooming via mouse wheel', function(done) {
696+
var doAutoMarginSpy;
697+
var data = [{y: [0, 12]}];
698+
var layout = {
699+
width: 500,
700+
height: 400,
701+
yaxis: {automargin: true}
702+
};
703+
704+
Plotly.newPlot(gd, data, layout, {scrollZoom: true})
705+
.then(function() {
706+
doAutoMarginSpy = spyOn(Plots, 'doAutoMargin').and.callThrough();
707+
708+
var dragger = getDragger('xy', 'nsew');
709+
var coords = getNodeCoords(dragger, 'se');
710+
711+
mouseEvent('scroll', coords.x, coords.y, {deltaY: 100, element: dragger});
712+
713+
expect(gd._fullLayout._replotting).toBe(true);
714+
expect(doAutoMarginSpy).not.toHaveBeenCalled();
715+
716+
return delay(constants.REDRAWDELAY + 10)();
717+
})
718+
.then(function() {
719+
expect(gd._fullLayout._replotting).toBe(false);
720+
expect(doAutoMarginSpy).toHaveBeenCalled();
721+
})
722+
.then(done, done.fail);
723+
});
724+
694725
it('handles xy, x-only and y-only zoombox updates', function(done) {
695726
function _assert(msg, xrng, yrng) {
696727
expect(gd.layout.xaxis.range).toBeCloseToArray(xrng, 2, 'xrng - ' + msg);

test/jasmine/tests/parcats_test.js

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -284,6 +284,55 @@ describe('Basic parcats trace', function() {
284284
.then(done, done.fail);
285285
});
286286

287+
it('should sort bundled paths by numeric color values', function(done) {
288+
var trace = {
289+
type: 'parcats',
290+
dimensions: [
291+
{values: ['a', 'a', 'a', 'a']},
292+
{values: ['b', 'b', 'b', 'b']}
293+
],
294+
line: {color: [1, 10, 2, 20]},
295+
bundlecolors: true
296+
};
297+
298+
Plotly.newPlot(gd, [trace])
299+
.then(function() {
300+
var parcatsViewModel = d3Select('g.trace.parcats').datum();
301+
var pathColors = parcatsViewModel.paths.map(function(path) {
302+
return path.model.rawColor;
303+
});
304+
305+
expect(pathColors).toEqual([1, 2, 10, 20]);
306+
})
307+
.then(done, done.fail);
308+
});
309+
310+
it('should sort NaN color values after orderable values', function(done) {
311+
var trace = {
312+
type: 'parcats',
313+
dimensions: [
314+
{values: ['a', 'a', 'a', 'a']},
315+
{values: ['b', 'b', 'b', 'b']}
316+
],
317+
line: {color: [10, NaN, 2, NaN]},
318+
bundlecolors: true
319+
};
320+
321+
Plotly.newPlot(gd, [trace])
322+
.then(function() {
323+
var parcatsViewModel = d3Select('g.trace.parcats').datum();
324+
var pathColors = parcatsViewModel.paths.map(function(path) {
325+
return path.model.rawColor;
326+
});
327+
328+
// Orderable values sort first, NaN values sort last
329+
expect(pathColors.length).toBe(3)
330+
expect(pathColors.slice(0, 2)).toEqual([2, 10]);
331+
expect(isNaN(pathColors[2])).toBe(true);
332+
})
333+
.then(done, done.fail);
334+
});
335+
287336
it('should compute initial model views properly', function(done) {
288337
Plotly.newPlot(gd, basicMock)
289338
.then(function() {

0 commit comments

Comments
 (0)