Skip to main content

src/svg_path@svg.erl

-module(svg_path@svg).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/svg_path/svg.gleam").
-export([labeled_point/4, document/2, paths/2]).
-export_type([thing_to_draw/0]).

-if(?OTP_RELEASE >= 27).
-define(MODULEDOC(Str), -moduledoc(Str)).
-define(DOC(Str), -doc(Str)).
-else.
-define(MODULEDOC(Str), -compile([])).
-define(DOC(Str), -compile([])).
-endif.

?MODULEDOC(" Small helpers for rendering paths as complete SVG documents.\n").

-type thing_to_draw() :: {styled_path, svg_path:path(), binary()} |
    {rectangle, vec@vec2:vec2(float()), float(), float(), binary()} |
    {circle, vec@vec2:vec2(float()), float(), binary()} |
    {ellipse, vec@vec2:vec2(float()), vec@vec2:vec2(float()), binary()} |
    {text, binary(), binary(), vec@vec2:vec2(float()), integer()}.

-file("src/svg_path/svg.gleam", 52).
-spec labeled_point(binary(), binary(), vec@vec2:vec2(float()), integer()) -> list(thing_to_draw()).
labeled_point(Label, Color, Point, Font_size) ->
    Side = erlang:float(Font_size),
    Half_side = Side / 2.0,
    Left = erlang:element(2, Point) - Half_side,
    Right = erlang:element(2, Point) + Half_side,
    Top = erlang:element(3, Point) - Half_side,
    Bottom = erlang:element(3, Point) + Half_side,
    Top_left = svg_path:point(Left, Top),
    Top_right = svg_path:point(Right, Top),
    Bottom_right = svg_path:point(Right, Bottom),
    Bottom_left = svg_path:point(Left, Bottom),
    Marker = {path,
        [begin
                _pipe = svg_path:assert_subpath(
                    [{line, Top_left, Top_right},
                        {line, Top_right, Bottom_right},
                        {line, Bottom_right, Bottom_left},
                        {line, Bottom_left, Top_left}]
                ),
                svg_path:assert_set_closed(_pipe, true)
            end,
            svg_path:assert_subpath([{line, Top_left, Bottom_right}]),
            svg_path:assert_subpath([{line, Bottom_left, Top_right}])]},
    [{styled_path,
            Marker,
            <<<<"fill: none; stroke: "/utf8, Color/binary>>/binary,
                "; stroke-width: 1; stroke-linecap: square; stroke-linejoin: miter"/utf8>>},
        {text,
            Label,
            <<<<"fill: "/utf8, Color/binary>>/binary,
                "; font-family: system-ui, sans-serif"/utf8>>,
            svg_path:point(
                Right + Half_side,
                erlang:element(3, Point) + Half_side
            ),
            Font_size}].

-file("src/svg_path/svg.gleam", 276).
-spec replace(binary(), binary(), binary()) -> binary().
replace(Value, Pattern, Replacement) ->
    _pipe = Value,
    _pipe@1 = gleam@string:split(_pipe, Pattern),
    gleam@string:join(_pipe@1, Replacement).

-file("src/svg_path/svg.gleam", 269).
-spec text_escape(binary()) -> binary().
text_escape(Value) ->
    _pipe = Value,
    _pipe@1 = replace(_pipe, <<"&"/utf8>>, <<"&amp;"/utf8>>),
    _pipe@2 = replace(_pipe@1, <<"<"/utf8>>, <<"&lt;"/utf8>>),
    replace(_pipe@2, <<">"/utf8>>, <<"&gt;"/utf8>>).

-file("src/svg_path/svg.gleam", 261).
-spec attribute_escape(binary()) -> binary().
attribute_escape(Value) ->
    _pipe = Value,
    _pipe@1 = replace(_pipe, <<"&"/utf8>>, <<"&amp;"/utf8>>),
    _pipe@2 = replace(_pipe@1, <<"\""/utf8>>, <<"&quot;"/utf8>>),
    _pipe@3 = replace(_pipe@2, <<"<"/utf8>>, <<"&lt;"/utf8>>),
    replace(_pipe@3, <<">"/utf8>>, <<"&gt;"/utf8>>).

-file("src/svg_path/svg.gleam", 225).
-spec text_element(
    binary(),
    binary(),
    vec@vec2:vec2(float()),
    integer(),
    svg_path@number_format:number_format()
) -> binary().
text_element(Label, Style, Point, Font_size, Format) ->
    <<<<<<<<<<<<<<<<<<<<"  <text x=\""/utf8,
                                            (svg_path@number_format:number(
                                                erlang:element(2, Point),
                                                Format
                                            ))/binary>>/binary,
                                        "\" y=\""/utf8>>/binary,
                                    (svg_path@number_format:number(
                                        erlang:element(3, Point),
                                        Format
                                    ))/binary>>/binary,
                                "\" font-size=\""/utf8>>/binary,
                            (erlang:integer_to_binary(Font_size))/binary>>/binary,
                        "\" style=\""/utf8>>/binary,
                    (attribute_escape(Style))/binary>>/binary,
                "\">"/utf8>>/binary,
            (text_escape(Label))/binary>>/binary,
        "</text>"/utf8>>.

-file("src/svg_path/svg.gleam", 206).
-spec ellipse_element(
    vec@vec2:vec2(float()),
    vec@vec2:vec2(float()),
    binary(),
    svg_path@number_format:number_format()
) -> binary().
ellipse_element(Center, Radius, Style, Format) ->
    <<<<<<<<<<<<<<<<<<<<"  <ellipse cx=\""/utf8,
                                            (svg_path@number_format:number(
                                                erlang:element(2, Center),
                                                Format
                                            ))/binary>>/binary,
                                        "\" cy=\""/utf8>>/binary,
                                    (svg_path@number_format:number(
                                        erlang:element(3, Center),
                                        Format
                                    ))/binary>>/binary,
                                "\" rx=\""/utf8>>/binary,
                            (svg_path@number_format:number(
                                erlang:element(2, Radius),
                                Format
                            ))/binary>>/binary,
                        "\" ry=\""/utf8>>/binary,
                    (svg_path@number_format:number(
                        erlang:element(3, Radius),
                        Format
                    ))/binary>>/binary,
                "\" style=\""/utf8>>/binary,
            (attribute_escape(Style))/binary>>/binary,
        "\" />"/utf8>>.

-file("src/svg_path/svg.gleam", 189).
-spec circle_element(
    vec@vec2:vec2(float()),
    float(),
    binary(),
    svg_path@number_format:number_format()
) -> binary().
circle_element(Center, Radius, Style, Format) ->
    <<<<<<<<<<<<<<<<"  <circle cx=\""/utf8,
                                    (svg_path@number_format:number(
                                        erlang:element(2, Center),
                                        Format
                                    ))/binary>>/binary,
                                "\" cy=\""/utf8>>/binary,
                            (svg_path@number_format:number(
                                erlang:element(3, Center),
                                Format
                            ))/binary>>/binary,
                        "\" r=\""/utf8>>/binary,
                    (svg_path@number_format:number(Radius, Format))/binary>>/binary,
                "\" style=\""/utf8>>/binary,
            (attribute_escape(Style))/binary>>/binary,
        "\" />"/utf8>>.

-file("src/svg_path/svg.gleam", 169).
-spec rectangle_element(
    vec@vec2:vec2(float()),
    float(),
    float(),
    binary(),
    svg_path@number_format:number_format()
) -> binary().
rectangle_element(Top_left, Width, Height, Style, Format) ->
    <<<<<<<<<<<<<<<<<<<<"  <rect x=\""/utf8,
                                            (svg_path@number_format:number(
                                                erlang:element(2, Top_left),
                                                Format
                                            ))/binary>>/binary,
                                        "\" y=\""/utf8>>/binary,
                                    (svg_path@number_format:number(
                                        erlang:element(3, Top_left),
                                        Format
                                    ))/binary>>/binary,
                                "\" width=\""/utf8>>/binary,
                            (svg_path@number_format:number(Width, Format))/binary>>/binary,
                        "\" height=\""/utf8>>/binary,
                    (svg_path@number_format:number(Height, Format))/binary>>/binary,
                "\" style=\""/utf8>>/binary,
            (attribute_escape(Style))/binary>>/binary,
        "\" />"/utf8>>.

-file("src/svg_path/svg.gleam", 161).
-spec path_element(svg_path:path(), binary()) -> binary().
path_element(Path, Style) ->
    <<<<<<<<"  <path d=\""/utf8,
                    (attribute_escape(svg_path@serialize:path(Path)))/binary>>/binary,
                "\" style=\""/utf8>>/binary,
            (attribute_escape(Style))/binary>>/binary,
        "\" />"/utf8>>.

-file("src/svg_path/svg.gleam", 144).
-spec thing_element(thing_to_draw(), svg_path@number_format:number_format()) -> binary().
thing_element(Thing, Format) ->
    case Thing of
        {styled_path, Path, Style} ->
            path_element(Path, Style);

        {rectangle, Top_left, Width, Height, Style@1} ->
            rectangle_element(Top_left, Width, Height, Style@1, Format);

        {circle, Center, Radius, Style@2} ->
            circle_element(Center, Radius, Style@2, Format);

        {ellipse, Center@1, Radius@1, Style@3} ->
            ellipse_element(Center@1, Radius@1, Style@3, Format);

        {text, Label, Style@4, Point, Font_size} ->
            text_element(Label, Style@4, Point, Font_size, Format)
    end.

-file("src/svg_path/svg.gleam", 245).
-spec view_box_value(
    svg_path:bounding_box(),
    svg_path@number_format:number_format()
) -> binary().
view_box_value(Box, Format) ->
    {bounding_box, Min, _} = Box,
    _pipe = [erlang:element(2, Min),
        erlang:element(3, Min),
        svg_path:bounding_box_width(Box),
        svg_path:bounding_box_height(Box)],
    _pipe@1 = gleam@list:map(
        _pipe,
        fun(_capture) -> svg_path@number_format:number(_capture, Format) end
    ),
    gleam@string:join(_pipe@1, <<" "/utf8>>).

-file("src/svg_path/svg.gleam", 104).
?DOC(
    " Render styled paths and text labels as a complete SVG document.\n"
    "\n"
    " The supplied bounding box is used directly as the document `viewBox`.\n"
).
-spec document(list(thing_to_draw()), svg_path:bounding_box()) -> binary().
document(Things, View_box) ->
    {bounding_box, Min, _} = View_box,
    Format = svg_path@number_format:prepare(
        {options, succinct, {at_most, 5}},
        [erlang:element(2, Min),
            erlang:element(3, Min),
            svg_path:bounding_box_width(View_box),
            svg_path:bounding_box_height(View_box)]
    ),
    <<<<<<<<"<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\""/utf8,
                    (view_box_value(View_box, Format))/binary>>/binary,
                "\">\n"/utf8>>/binary,
            (begin
                _pipe = Things,
                _pipe@1 = gleam@list:map(
                    _pipe,
                    fun(_capture) -> thing_element(_capture, Format) end
                ),
                gleam@string:join(_pipe@1, <<"\n"/utf8>>)
            end)/binary>>/binary,
        "\n</svg>"/utf8>>.

-file("src/svg_path/svg.gleam", 137).
?DOC(
    " Render styled paths and text labels as a complete SVG document.\n"
    "\n"
    " This is an older name for `document`.\n"
).
-spec paths(list(thing_to_draw()), svg_path:bounding_box()) -> binary().
paths(Things, View_box) ->
    document(Things, View_box).