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

frameAnchor; fix multiline text #686

Merged
merged 4 commits into from
Jan 19, 2022
Merged

frameAnchor; fix multiline text #686

merged 4 commits into from
Jan 19, 2022

Conversation

mbostock
Copy link
Member

Fixes #683.

@mbostock mbostock requested a review from Fil January 19, 2022 18:48
src/style.js Outdated
Comment on lines 231 to 232
/-?left$/.test(frameAnchor) ? marginLeft : /-?right$/.test(frameAnchor) ? width - marginRight : (marginLeft + width - marginRight) / 2,
/^top-?/.test(frameAnchor) ? marginTop : /^bottom-?/.test(frameAnchor) ? height - marginBottom : (marginTop + height - marginBottom) / 2
Copy link
Contributor

Choose a reason for hiding this comment

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

I don't think we need the -? here since the keywords have already been validated.

Copy link
Member Author

Choose a reason for hiding this comment

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

We do, because you can have e.g. “top” or “top-left” and we want to match on both.

Copy link
Member Author

@mbostock mbostock Jan 19, 2022

Choose a reason for hiding this comment

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

Oh, I see what you mean, because /^top/ will match both, and nothing else. That’s true, but I was a little worried that we’d introduce another name in the future that would coincidentally match the same prefix. I think it’s clearer to have the hyphen as an explicit delimiter even though it’s not strictly necessary.

Copy link
Contributor

Choose a reason for hiding this comment

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

I meant that matching "top" or "left" seems to be enough. Just a nit.

Copy link
Member Author

Choose a reason for hiding this comment

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

Okay, I thought about /^top($|-)/ instead, but we’d have to change this code if we introduce new frameAnchor values anyway, so it feels fine to take your suggestion.

@Fil
Copy link
Contributor

Fil commented Jan 19, 2022

I'm confused by something—writing it quickly since we're having dinner.

I'm trying to add a multiline explainer on top of the aapl-bollinger example.

Ideally I should be able to say

Plot.text([`Multiline\nexplainer`], {frameAnchor: "top-right", text: d => d})

But this fails in two ways:

  1. If my text is a single line, I have to pass explicit x: null, y: null options, otherwise things just don't work
  2. Multiline just doesn't work, the x/y is not used.

For the point 1, I suppose we could have frameAnchor setting the default x and y. For point 2 it's probably due to something I didn't see in #682.

Capture d’écran 2022-01-19 à 20 20 05

bbl

@mbostock
Copy link
Member Author

mbostock commented Jan 19, 2022

For the first, that’s expected because Plot.text defaults x and y to first and second, respectively, using maybeTuple.

([x, y] = maybeTuple(x, y));

plot/src/options.js

Lines 96 to 99 in b5a1724

// For marks that have x and y channels (e.g., cell, dot, line, text).
export function maybeTuple(x, y) {
return x === undefined && y === undefined ? [first, second] : [x, y];
}

If you want to change that, we’d need to do something like type inference on the data, and default x and y to null if it’s an array of strings. Or perhaps on the presence of the frameAnchor option? Maybe that’s useful for text annotations? 🤷

For the second, that’s the brokenness I was expecting here #682 (review). With #682, you get something like this:

<text x="639.5" y="0.5">
  <tspan x="0" y="-0.18em">Multiline</tspan>
  <tspan x="0" y="0.8200000000000001em">explainer</tspan>
</text>

But the x and y on the tspans aren’t additive with those on the text: the x and y on the text are now ignored. So we have to use a transform attribute when we generate multiline text. I’ll revert this part.

@mbostock
Copy link
Member Author

mbostock commented Jan 19, 2022

This seems to work pretty well:

untitled-245

Plot.plot({
  marks: [
    Plot.frame(),
    Plot.text([`Multiline\nexplainer`], {
      textAnchor: "end",
      lineAnchor: "top",
      frameAnchor: "top-right",
      text: d => d
    })
  ]
})

Another thing we could do here is change the defaults for textAnchor and lineAnchor based on the specified frameAnchor… but I think we probably don’t want to do this as it would be more difficult to remember the behavior.

@mbostock mbostock changed the title frameAnchor frameAnchor; fix multiline text Jan 19, 2022
@mbostock
Copy link
Member Author

Okay, changed it so that if you specify a frameAnchor option, x and y now default to null instead of maybeTuple. That makes sense to me, since you’d never use the two of them together.

@mbostock mbostock merged commit 704937b into main Jan 19, 2022
@mbostock mbostock deleted the mbostock/frame-anchor branch January 19, 2022 20:17
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

A frameAnchor option for positioning otherwise position-less marks relative to the frame
2 participants