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

Legend Marker Vertical Alignment #3263

Merged
merged 7 commits into from
Nov 21, 2018
Merged

Legend Marker Vertical Alignment #3263

merged 7 commits into from
Nov 21, 2018

Conversation

antoinerg
Copy link
Contributor

Closes #2798 (never mind the issue number in the branch's name which is wrong!)

var valignFactor = 0;
if(gd._fullLayout.legend.valign === 'top') valignFactor = 1.0;
if(gd._fullLayout.legend.valign === 'bottom') valignFactor = -1.0;
var markerOffsetY = valignFactor * (0.5 * (d[0].lineHeight - d[0].height + 3));
Copy link
Contributor

@etpinard etpinard Nov 20, 2018

Choose a reason for hiding this comment

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

Nice use of lineHeight 🎉

"width": 800,
"legend": {
"bgcolor": "rgba(0,255,255,1)",
"valign": "top",
Copy link
Contributor

Choose a reason for hiding this comment

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

Can you add another mock testing valign: "middle" ?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Absolutely! Done in a02910a

@etpinard etpinard added this to the v1.43.0 milestone Nov 20, 2018
valType: 'enumerated',
values: ['top', 'middle', 'bottom'],
dflt: 'middle',
role: 'style',
Copy link
Contributor

@etpinard etpinard Nov 20, 2018

Choose a reason for hiding this comment

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

... and let's add one jasmine test 🔒 ing down relayout for 'valign'

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Nice catch! Thank you so much! Test can be found in a375c99

@@ -30,7 +30,7 @@ module.exports = function style(s, gd) {
if(gd._fullLayout.legend.valign === 'top') valignFactor = 1.0;
if(gd._fullLayout.legend.valign === 'bottom') valignFactor = -1.0;
var markerOffsetY = valignFactor * (0.5 * (d[0].lineHeight - d[0].height + 3));
if(markerOffsetY) layers.attr('transform', 'translate(0,' + markerOffsetY + ')');
Copy link
Contributor Author

@antoinerg antoinerg Nov 20, 2018

Choose a reason for hiding this comment

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

Fix bug when valign equals middle. Because markerOffsetY is zero when at middle position, I had to change this line.

Copy link
Contributor

@etpinard etpinard Nov 20, 2018

Choose a reason for hiding this comment

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

Hmm. But 'middle' is the default value isn't it? Why didn't our tests catch sooner?

Copy link
Contributor Author

@antoinerg antoinerg Nov 20, 2018

Choose a reason for hiding this comment

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

All the mocks were rendered properly because the transform attribute was not added. However, if there's already a transform attribute on the svg group because valign was top, then it needs to be removed on relayout if valign is switched back to middle.

Copy link
Contributor

Choose a reason for hiding this comment

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

However, if there's already a transform attribute on the svg group because valign was top, then it needs to be removed on relayout if valign is switched back to middle.

OK this makes sense. I don't understand how the transform gets removed and why this patch fixes the bug though. Boolean(NaN) is false so the old and this new line look equivalent to me.

Copy link
Contributor

Choose a reason for hiding this comment

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

Wouldn't something like

var valign = gd._fullLayout.valign;

if(valign === 'middle') {
  layers.attr('transform', null); // this here is a fun d3 trick to unset DOM attributes
} else {
  var factor = {top: 1, bottom: -1}[valign];
  var markerOffsetY = factor * (0.5 * (d[0].lineHeight - d[0].height + 3));
  layers.attr('transform', 'translate(0,' + markerOffsetY + ')');
}

be what we're looking for?

Copy link
Contributor Author

@antoinerg antoinerg Nov 20, 2018

Choose a reason for hiding this comment

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

Your solution would work except that we should check whether markerOffsetY is a number. It might not be when this function is visited and errors would be thrown in the console because of garbage translate(0, NaN). This is why I added if(!isNaN(markerOffsetY))!

Copy link
Contributor Author

@antoinerg antoinerg Nov 20, 2018

Choose a reason for hiding this comment

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

I'd have to check to make sure but I think it's called on first draw to figure out how big the legend will be. At this point, d[0].lineHeight d[0].height are not defined and we get a NaN. Although everything renders correctly in the end, we get the following in the console:
d3.js:663 Error: <g> attribute transform: Trailing garbage, "translate(0,NaN)".

Copy link
Contributor Author

@antoinerg antoinerg Nov 20, 2018

Choose a reason for hiding this comment

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

That is indeed what is happening which is why if(!isNaN(markerOffsetY)) is required.

Copy link
Contributor

Choose a reason for hiding this comment

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

Ok, in this case if we know that lineHeight/height are sometimes undefined, we should not even attempt to compute markerOffsetY. So something like:

var valign = gd._fullLayout.valign;
var lineHeight = d[0].lineHeight;
var height = d[0].height;

if(valign === 'middle' || !lineHeigth || !lheight) {
  layers.attr('transform', null); // this here is a fun d3 trick to unset DOM attributes
} else {
  var factor = {top: 1, bottom: -1}[valign];
  var markerOffsetY = factor * (0.5 * lineHeight - height + 3));
  layers.attr('transform', 'translate(0,' + markerOffsetY + ')');
}

would make that clearer.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

In commit c1b871d, I reused most of the above 😄 !

afterEach(destroyGraphDiv);

function markerOffsetY() {
var translateY = d3.select('.legend .traces .layers').attr('transform').match(/translate\(\d+,(-?\d+)\)/)[1];
Copy link
Contributor

Choose a reason for hiding this comment

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

Just noticed this. Using Drawing.getTranslate would be cleaner.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thanks! 🔍

Done in c1b871d!

@etpinard
Copy link
Contributor

Nicely done 💃

@antoinerg antoinerg merged commit 11bec79 into master Nov 21, 2018
@antoinerg antoinerg deleted the 2789-valign-legend branch November 21, 2018 16:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants