-
-
Notifications
You must be signed in to change notification settings - Fork 1.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Selection re-ordering for scatter traces with ids
#1709
Conversation
- this reorders the object-constant nodes (i.e. for traces w/ ids) correctly 🎉 - BUT, this also brakes the update pattern for traces with non-numeric (x,y), as the .remove call in Drawing.translatePoint throws the join selections out-of-sync, leading an exception!
FYI: more info on |
src/traces/scatter/plot.js
Outdated
@@ -483,6 +485,8 @@ function plotOne(gd, idx, plotinfo, cdscatter, cdscatterAll, element, transition | |||
}); | |||
}); | |||
|
|||
join.order(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🆘 IMPORTANT 🆘
This commit breaks scatter/plot.js
for traces with non-numeric (x,y) positions.
That is due to Drawing.translatePoint
which is called on the enter and merge selections. When points with non-numeric (x,y) are detected, Drawing.translatePoint
removes them. Unfortunately, this makes the join
selections out-of-sync with the DOM and leads to 'TypeError: Cannot read property 'textContent' of null
exception thrown by d3.
So, I have two questions for the d3-heads looking at this PR:
- Is there a way to re-select the join and call
order()
on that selection? - Or should we make our updates more d3-esque by filtering data items with non-numeric position before binding them to the selections?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How about join.filter(onlyNumeric).order()
?
I'm not sure I understand how makePoints
works.
Shouldn't these lines:
enter.call(Drawing.pointStyle, trace)
.call(Drawing.translatePoints, xa, ya, trace);
be:
join.call(Drawing.pointStyle, trace)
.call(Drawing.translatePoints, xa, ya, trace);
Otherwise DOM and data won't be in sync. Here's a codepen showing a similar issue.
... and order nodes on merge selection before styling/translating/removing-non-numeric item so that the order call acts on a merge selection in-sync with the DOM
@@ -419,9 +419,6 @@ function plotOne(gd, idx, plotinfo, cdscatter, cdscatterAll, element, transition | |||
var enter = join.enter().append('path') | |||
.classed('point', true); | |||
|
|||
enter.call(Drawing.pointStyle, trace) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@n-riesco thanks very much 🎉
Your solution appears to work:
My only concern now is how this interacts with animations. I think the reason why translatePoints
and pointStyle
are called on enter selection and merge selection has to do with this block below where entering nodes have their opacity transitioned from 0 to 1. I suspect this commit will break this behavior (although the tests are passing) has the entering aren't positioned and styled properly before opacity transition cc @rreusser . It would be nice to write a test case here 😏
I'm thinking instead, we could keep those enter.call()
, make Drawing.translatePoints
not (and maybe never) remove nodes and make the merge selection .each
block below (which comes after the .order()
) handle the cases where nodes need to be removed.
Thoughts?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the point you make about animations is important.
And the solution you propose (i.e. remove nodes only after we're done with the enter selection) is more robust.
👍 from me.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@etpinard after thinking a little bit about it. I'm still think that translatePoints
and pointStyle
should be applied to the merge selection to keep in sync DOM and trace.
I haven't tested it, but .order
should take care of my concern.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- handle that in scatter/plot.js - call Drawing.pointStyle and Drawing.translatePoints on enter selection to ensure that added point are drawn in with a smooth transition
test/jasmine/tests/scatter_test.js
Outdated
@@ -539,6 +539,42 @@ describe('end-to-end scatter tests', function() { | |||
.catch(fail) | |||
.then(done); | |||
}); | |||
|
|||
it('should smoothly add/remove nodes tags with *ids* during animations', function(done) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This test is failing after c8c3197
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@@ -56,7 +56,7 @@ drawing.setRect = function(s, x, y, w, h) { | |||
* | |||
* @return {boolean} : | |||
* true if selection got translated | |||
* false if selection got removed | |||
* false if selection could not get translated | |||
*/ | |||
drawing.translatePoint = function(d, sel, xa, ya) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Tagging this as Thanks again @n-riesco for your help! |
@@ -430,6 +427,8 @@ function plotOne(gd, idx, plotinfo, cdscatter, cdscatterAll, element, transition | |||
var markerScale = showMarkers && Drawing.tryColorscale(trace.marker, ''); | |||
var lineScale = showMarkers && Drawing.tryColorscale(trace.marker, 'line'); | |||
|
|||
join.order(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why do we need join.order()
twice?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
one for marker nodes, one for text nodes
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ah right - didn't notice join
got reassigned between 👍
Looks great, nice work! 💃 |
fixes #1706 (an attempt at least)