Load SVG externally and wire to elm model

Hello everyone, coming from Vue, I have been learning elm for the past 4 months and having a great time so far! But I am stuck on achieving one idea I have in elm.

The idea is:

  1. Load an SVG file externally and append it inline.
  2. Collect SVG elements by querying id names within.
  3. Attach onClick listeners to those element collection.

Basically it tries to turn any SVG drawing into clickable checkboxes (if it has the correct ID names).

Before this, I was experimenting around using predefined div elements. The model being a tuple of List & Set
https://ellie-app.com/cgjnTJ2XfmRa1

I have zero idea on how it works and I have yet to experiment this with vanilla JS.

Thanks!

I have never tried it with SVG, but this might help:

https://package.elm-lang.org/packages/hecrj/html-parser/latest/

3 Likes

Thanks rupert! It is said it doesn’t support svg in the parser, but tried it out anyway. It failed to render even though the inner HTML shows the SVG inside the browser’s inspector.

I’ve come across to this package SvgParser - elm-svg-parser 1.0.0

It has this toAttribute endpoint which I can see myself wiring the color attribute to the model. Still has left me wondering around how to attach onClick messages. I’ll figure it out eventually.

Thanks for the package recommendation. It helped me see how to proceed solving this problem!

You can write a custom onClick listener that passes the target’s id to the event.

Yes @shiningflint elm-svg-parser is definitely the way to go. I’ve done almost exactly the same thing as you’re asking for. A false start that made things miserable for a little while was to use img tags and use ports with something like GitHub - iconic/SVGInjector: Fast, caching, dynamic inline SVG DOM injection library. Although this makes loading images nearly trivial, this plays poorly with the virtual DOM.

Instead I would recommend loading the SVG as a string through Http and biting the bullet for the additional record-keeping that will entail then passing it through the SvgParser. Don’t use SvgParser.parse, because you’ll end up directly with Html which cannot be inspected and therefore you can’t traverse over the SVG nodes and add click handlers as necessary.

Instead you want to use SvgParser.parseToNode, which gives you SvgNodes that you can then play with. Unfortunately SvgParser doesn’t expose a function to go from SvgNode to Html a, so you’ll want to copy part of SvgParser.parse in particular

            case svgNode of
                SvgElement element ->
                    if element.name == "svg" then
                        Ok <|
                            svg (List.map toAttribute element.attributes)
                                (List.map nodeToSvg element.children)

                    else
                        Err "Top element is not svg"

                _ ->
                    Err "Top element is not svg"

and put that in a separate function to get SvgNode -> Html msg.

To add the onclick handler you can modify the above snippet of code to inspect certain attribute strings and translate them to actual onClick MyCustomType Html.Attributes (e.g. you could have have the SvgAttribute ("myOnClick", "onClickValue") and then wrap toAttribute with something that checks for "myOnClick" and "onClickValue" and calls onClick OnClickValue.

1 Like

Thank you for the suggestions everybody. After spending some days with it, I found the solution I need. I wrote an oversimplified version of the solution in this Ellie snippet. Hopefully it can be some reference for future people including future me.
https://ellie-app.com/ckpfYCRq7k7a1

Some points noted:

  1. I’m glad the SvgParser package exposes the custom type, because I need to override the nodeToSvg & elementToSvg functions.
  2. Looking in the source code, the nodeToSvg recursion parsing logic is not as scary as I thought.
  3. As @yosteden mentioned, the svg is going to be loaded through Http. And the mapping between id configurations will come from the flags configuration for the initial model.

So, yay! Making this work in elm feels so good!

3 Likes

This topic was automatically closed 10 days after the last reply. New replies are no longer allowed.