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

Boundingbox poly behind text #4874

Open
SimonDanisch opened this issue Mar 18, 2025 · 1 comment
Open

Boundingbox poly behind text #4874

SimonDanisch opened this issue Mar 18, 2025 · 1 comment
Labels
enhancement Feature requests and enhancements

Comments

@SimonDanisch
Copy link
Member

@alanedelman reminded me, that Makie still has no easy way to draw a boundingbox behind some text.
I took the chance to make a simple prototype, which wasn't as simple as I expected.
But this should work fairly well:

function rounded_rect(bbox, r)
    if r == 0
        return BezierPath([
            MoveTo(Makie.topright(bbox)),
            LineTo(Makie.topleft(bbox)),
            LineTo(Makie.bottomleft(bbox)),
            LineTo(Makie.bottomright(bbox)),
            ClosePath()
        ])
    else
        w, h = widths(bbox)
        _max = min(w/2, h/2)
        r1, r2, r3, r4 = r isa NTuple{4, Real} ? r : r isa Real ? (r, r, r, r) : throw(ArgumentError("Invalid cornerradius value $r. Must be a `Real` or a tuple with 4 `Real`s."))
        r1, r2, r3, r4 = min.(_max, (r1, r2, r3, r4))
        return BezierPath([
            MoveTo(bbox.origin + Point(w, h/2)),
            EllipticalArc(Makie.topright(bbox) - Point2f(r1, r1), r1, r1, 0.0, 0, pi / 2),
            EllipticalArc(Makie.topleft(bbox) + Point2f(r4, -r4), r4, r4, 0.0, pi / 2, pi),
            EllipticalArc(Makie.bottomleft(bbox) + Point2f(r3, r3), r3, r3, 0.0, pi, 3 / 2 * pi),
            EllipticalArc(Makie.bottomright(bbox) + Point2f(-r2, r2), r2, r2, 0.0, 3 / 2 * pi, 2pi),
            ClosePath(),
        ])
    end
end

function text_bb!(ax, position, text; padding=4, border_radius=0, backgroundcolor=:white, strokecolor=:black, strokewidth=0, text_kw...)
    textscene = Scene(ax.blockscene) # needs own scene to not be obstructed by other plots
    pos_pix = Observable(Point2f(0, 0))
    t = text!(textscene, pos_pix, text=text, space=:pixel, text_kw...)
    translate!(t, 0, 0, 10000) # move in front of everything
    w, h = widths(boundingbox(t))
    rect = Rect2f(-padding/2, -padding/2, w + padding, h + padding)
    rrect = rounded_rect(rect, border_radius)
    bb = poly!(textscene, rrect, color=backgroundcolor, strokecolor=strokecolor, space=:pixel, strokewidth=strokewidth)
    map(ax.scene.camera.projectionview) do mvp
        pix = Makie.project(ax.scene, pos)
        translate!(bb, pix..., 10000-1)
        pos_pix[] = pix
        return pix
    end
    return t 
end

begin 
    f, ax, pl = scatter(rand(Point3f, 10), axis=(; type=Axis3))
    pos = Point3f(0.5)
    text_bb!(ax, pos, "MatrixSpace", strokecolor=:black, border_radius=10, padding=10, strokewidth=01)
    f
end

Image

The question is, how do we want to integrate this into Makie?
@jkrumbiegel, @ffreyer, any API preferences?

I think we can make this a helper function almost like the above, a recipe (although I wonder how we do the thing with the subscene, or if we can get around that), or integrate it into text (I dont like that, this should work with any boundingbox).

@SimonDanisch SimonDanisch added the enhancement Feature requests and enhancements label Mar 18, 2025
@ffreyer
Copy link
Collaborator

ffreyer commented Mar 19, 2025

Just a note - there is Makie.roundedrectvertices and Makie.roundedrectpath

@ffreyer ffreyer mentioned this issue Mar 19, 2025
17 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement Feature requests and enhancements
Projects
None yet
Development

No branches or pull requests

2 participants