Responsive SVG with elm?

I’m trying to make a responsive svg with elm that fills the screen.

I’ve managed to do this using elm-playground and computer.screen.width and computer.screen.height, but I don’t understand how its fetched in the source code so that I can extract just this functionality without having to import the entire elm-playground just to get the dimensions of the screen.

Is there a way using core elm package that I can get screen width and height so I don’t have to import elm-playground to do this?

1 Like

this ellie gets me one step closer
https://ellie-app.com/3nw5FhVJYL4a1

using Browser.Dom exposing (Viewport) seems to be what I’m after, but it’s a task that has to be performed each time I want to get the viewport, such as every time I render because the window size can change. Not very intuitive or nice I must say, wish there was just a primitive that always told you these very useful values

See here.

Depending on your needs, you can make SVG fill the screen (or parent element) without query of the viewport. Just with HTML / SVG attributes and some CSS properties. Basically set the width and height of your svg element to 100% so it fills the parent element and then use viewbox property to position the elements inside. The viewbox is tricky to understand (at least I had trouble with it at first), but very powerful once you get it. Check out MDN docs for it at https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/viewBox. You may be also interested in the preseveAspectRation attribute, also discussed there.

There is an extensive discussion on using it with Elm at day 1 of Software Garden. I hope it helps.

2 Likes

For the record: you can subscribe to a “resize” event and pass the initial window size via flags so you can spare that Maybe Viewport which is indeed quite awkward to work with.

See this example: https://ellie-app.com/cp8fMcKgss6a1

Here is Ellie demonstrating the viewbox technique: https://ellie-app.com/cp8m289xjgQa1

Note how I set the style on html and body elements.

2 Likes

I have some code that might help you here. What I tend to do is query for the window size on application init and also create a subscription to Browser.Events.onResize. Assuming its a fullscreen SVG app, this size is converted into the SVG viewport. If the SVG part was not fullscreen, its more complicated because although you can query for the viewport of anything in the DOM, there is no ResizeObserver like thing in Elm. You can opt to set that up with ports, or if you know that something is only going to change size if the window is resized, just re-query it after the Browser.Events.onResize subscription is invoked.

Initial sizing request from Browser.Dom.getViewport is here:

https://github.com/the-sett/tea-tree/blob/master/example/src/elm/Main.elm#L139

The subscription for ongoing window resize events is here:

https://github.com/the-sett/tea-tree/blob/master/example/src/elm/Main.elm#L120

The reason that I query for the window size, rather than just letting the SVG fill the window with its CSS styling, is that I want to set up the SVG viewBox to exactly match its on screen size in pixels. This is done here:

https://github.com/the-sett/tea-tree/blob/master/example/src/elm/Main.elm#L258

I find having the SVG exactly match the window size 1:1, makes rendering sharp looking SVG much easier.

For example, when rendering a line 1px wide, if it is a vertical line, its x coordinate needs to be offset by 0.5 px, so that the line is drawn right down the middle of the pixels, if you see what I mean? Another way you can do this is to offset the SVG viewport origin by 0.5, to make the math ‘easier’. Of course, its not always easier that way, as now a 2px wide line needs adjustment.

One thing I have not done in this application is to take into account the device scaling ratio. For example, on my current screen it is 1.5, so each SVG unit is 1.5 physical pixels, which can lead to blurry edges - It matters less on a high DPI device though.

2 Likes

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