r-lib / marquee

Markdown Parser and Renderer for R Graphics
https://marquee.r-lib.org
Other
82 stars 1 forks source link

Implement `xDetails` / `yDetails` methods? #11

Closed teunbrand closed 5 months ago

teunbrand commented 5 months ago

Hi Thomas,

I know it is early days for marquee, but could I ask that the xDetails() and yDetails() grid methods be implemented for marquee grobs? It is not of a very high priority.

The main reason I'm asking is because it might allow integration with {ggrepel}, which I think would be exciting. I've an open PR (https://github.com/slowkow/ggrepel/pull/249) that allows one to swap out the grob generating function, but the grobX() and grobY() functions, which are fed by the xDetails()/yDetails() methods should give reasonable coordinates for it to work.

Basically, what one would like these functions to do is to give the coordinates of the bounding box given an angle theta in degrees. For textGrob() this works as follows:

library(grid)
library(marquee)

theta <- seq(0, 315, by = 15)

label <- "Lorem ipsum dolor sit amet, consectetur 
adipiscing elit. In hendrerit metus quam, 
sed rutrum nulla feugiat consequat. Sed eu 
pulvinar purus, vel placerat metus."

txt <- textGrob(label, rot = 45)

grid.newpage()
grid.draw(txt)

x <- grobX(txt, theta)
y <- grobY(txt, theta)

grid.points(x = x, y = y, gp = gpar(col = 'red'))

For marquee_grob(), it just yields central points.

mq <- marquee_grob(
  label, classic_style(), 
  angle = 45, x = 0.5, y = 0.5, hjust = 0.5, vjust = 0.5
)

grid.newpage()
grid.draw(mq)

x <- grobX(mq, theta)
y <- grobY(mq, theta)

grid.points(x = x, y = y, gp = gpar(col = 'red'))

Created on 2024-04-30 with reprex v2.1.0

I imagine the easiest way is to calculate the 4 corner points of the bounding box of the grob and then use something like the following to reuse the xDetails.points method:

xDetails.marquee_grob <- function(x, theta) {

  #...
  # calculate 4 corner bounds of bounding box
  #...

  pts <- structure(
    list(
      x = unit.c(x1, x2, x3, x4), 
      y = unit.c(y1, y2, y3, y4)
    ), 
    class = "points"
  )
  xDetails(pts, theta)
}
thomasp85 commented 5 months ago

sounds good - would you make a PR?

teunbrand commented 5 months ago

Yeah I'll see if I can pull this off