Skip to content
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

Image and shape clip paths #1453

Merged
merged 6 commits into from
Mar 9, 2017
Merged

Image and shape clip paths #1453

merged 6 commits into from
Mar 9, 2017

Conversation

alexcjohnson
Copy link
Collaborator

In testing axis reference changes for integrating v1.24 into the workspace, I noticed some strange situations with clip paths for shapes and images. Turns out they had different issues but related symptoms. There's one particular edge case that I didn't sort out here because it's a much bigger structural question, so I described it in #1452 instead.

@etpinard please review.

@alexcjohnson
Copy link
Collaborator Author

Note: annotations do not have these issues, as they don't use clip paths. We will happily allow the arrow and text box of an annotation to go outside the plot area as long as its reference point is visible.

thisImage.call(Drawing.setClipUrl, clipAxes ?
('clip' + fullLayout._uid + clipAxes) :
null
);
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Needed to unset the clip path if you change from data-referenced to fully paper-referenced.


function getShape(index) {
var s = d3.selectAll('path[data-index="' + index + '"]');
expect(s.size()).toBe(1);
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

before the fix above, the shape was drawn twice in its initial configuration xref: 'x', yref: 'paper': once on subplot xy and again on xy2

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good eyes. Thanks very much!


path.call(Drawing.setClipUrl, clipAxes ?
('clip' + gd._fullLayout._uid + clipAxes) :
null
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice way to unset a clip path. 👍

@@ -425,23 +425,38 @@ describe('images log/linear axis changes', function() {
// we don't try to figure out the position on a new axis / canvas
// automatically when you change xref / yref, we leave it to the caller.

// initial clip path should end in 'xy' to match xref/yref
expect(d3.select('image').attr('clip-path') || '').toMatch(/xy\)$/);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ha. I didn't know about .toMatch. Pretty handy 🔨

expect(d3.select('image').attr('clip-path') || '').toMatch(/x\)$/);

// change to full paper-referenced, to make sure the clip path disappears
return Plotly.relayout(gd, {'images[0].xref': 'paper'});
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm surprised we weren't testing this before. Oh well, now it's 🔒 ed

@etpinard
Copy link
Contributor

etpinard commented Mar 8, 2017

Looks like shapes_below_traces produced a diff

image

is that on purpose?

@alexcjohnson
Copy link
Collaborator Author

Looks like shapes_below_traces produced a diff, is that on purpose?

Hmm, maybe #1452 needs to be addressed together with this PR after all, that's what's going on here. You'll see that the data in the lower left subplot gets covered up in the new result for that image. But the original is clearly wrong in how it breaks the two shapes that span that subplot and either the one above or to the right into two disjoint pieces.

From a slack chat:

the reason I said (in #1452 ) "I'm not sure this really has a solution even theoretically” is that there really isn’t a layering that puts the shape in front of the plot area backgrounds but behind the traces, at least not when you consider inset subplots that want to have their own backgrounds in front of the main plot traces.

One easy thing we could do is put the below shapes completely below the plot layers… then you have to make plot_bgcolor transparent to see the shapes.

A trickier thing we could do is pull the background rects out of the subplot layers, putting them behind everything else, UNLESS we detect overlapping (but not overlaying) subplots.

That would cover all the use cases I can think of except below shapes that are half referenced to an axis of an inset subplot… which would be an exceedingly weird situation.

@etpinard suggested:

Maybe we should disallow shapes that span multiple subplots

That would certainly make this easier (the restriction would only apply to layer: 'below' shapes and images) - then we'd just have to figure out which subplot contains the shape. But there are some cool uses of subplot-spanning shapes - for example on the standard finance chart that has candlesticks/OHLC in the main plot and volume in a little lower subplot, if you want to highlight a time range. It would look weird to force these to be two separate shapes. Would also be annoying to try and enforce this restriction during editing (particularly via drag)

So I'm leaning toward the "trickier thing": pulling the plot backgrounds back to their own layer except for inset plots.

Thoughts?

@alexcjohnson
Copy link
Collaborator Author

#1390 is wrapped up in this too... better fix that at the same time.

@etpinard
Copy link
Contributor

etpinard commented Mar 8, 2017

So I'm leaning toward the "trickier thing": pulling the plot backgrounds back to their own layer except for inset plots.

This is definitely the best solution from a user's perspective. If you feel like taking a shot at this, go for it 👍

@alexcjohnson
Copy link
Collaborator Author

2102b0f fixes #1390 and #1452 - I still want to add a couple of tests of the inset vs flat background behavior though


// filter out overlaid plots (which havd their images on the main plot)
// and gl2d plots (which don't support below images, at least not yet)
if(!subplotObj.imagelayer) continue;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good 👍

@@ -308,8 +308,7 @@ Plotly.plot = function(gd, data, layout, config) {

// keep reference to shape layers in subplots
var layerSubplot = fullLayout._paper.selectAll('.layer-subplot');
fullLayout._imageSubplotLayer = layerSubplot.selectAll('.imagelayer');
fullLayout._shapeSubplotLayer = layerSubplot.selectAll('.shapelayer');
fullLayout._shapeSubplotLayers = layerSubplot.selectAll('.shapelayer');
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✏️ nicely done

expect(gd.querySelectorAll('.bg').length).toBe(behindCount + x2y2Count);
}

Plotly.plot(gd, [
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fantastic test 🎉

@etpinard
Copy link
Contributor

etpinard commented Mar 9, 2017

💃 nicely done!

Don't forget to close off #1390 and #1452 after merging 🍻

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug something broken
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants