I’m researching if Elm will be a good choice here for a canvas heavy web application.
It involves the following:
Creating “object” on the canvas that can handle clicks, drag and drop, double-click.
Object, say a rectangle, can be drop onto another rectangle and they would merge. Will Elm be able to receive any message on the drop event in the update function?
I find this library: elm-canvas 4.2.1 it seems it want to repaint the entire canvas, I’m not sure my scenario (allow drag and drop) would work there.
Another aspect is maybe I’m approaching the problem in a wrong way. Maybe the canvas element is not the proper choice here.
My 2nd idea would be to use a div container with “object” being drawn from SVG and have the position being absolute.
The second solution seems to be more Elm friendly I think, where the drag and drop would occur on the SVG elements.
I know it’s not much, but I’d like to know earlier than later that Elm would be more painful that not, even though I’d highly prefer using Elm.
Any thoughts, anyone created an app with dynamically positioned elements that can be drag and drop on top of each other.
Hi @dstpierre quite some time ago (the app is elm 0.18) I’ve been experimenting with drawing thing in canvas-like environments, see https://elm-image-annotation.pizenberg.fr/. There was no editing of objects though and no drag and drop behavior. It was based on SVG.
Regarding drag and drop, one advice would be to avoid anything directly based on html5 drag-and-drop. It is full of problems, and for this reason, libraries usually create their own way of drag and dropping with object detection and all. In elm this almost certainly means that you’ll have to wire some message passing in your update.
Regarding Canvas. The canvas drawing API cannot be easily used in elm because it is based on side effects (draw this, draw that, clear, change color, etc.). SVG is a declarative API and thus better suited for everything vector drawing in elm. You can also visualize raster images as shown in the linked app but its not handled as well as in canvas, where every thing is rasterized. I believe joakin/elm-canvas is using a nice trick consisting in setting up a custom element web component, needed in addition to the elm package, and communicating with it through the element attributes. I don’t know how much “drawing bandwidth” it can sustain, so you’d have to benchmark it. You could also add your own attributes and events to the custom element to handle the clicking and drag-and-drop behavior in JavaScript land.
Another option is to use elm-explorations/webgl which can be paired with ianmackenzie/elm-3d-scene. But then, you’ll want to be very careful with how you “pack” you object to minimize draw calls.
So lot’s of options but for each one, probably more work than you were hoping I think.
If you compare how well the canvas API is supported between different solutions (Elm/React/Vanilla), IMO Elm doesn’t give you much.
Nevertheless, any time I could I reached for Elm, just because of the benefits from the language itself.
I’d suggest using joakin’s elm-canvas. It worked quite well.
One limitation with always bit me when I tried to do canvas-based stuff was text rendering with text metrics: If you plan on having text as one of the elements on your canvas, you’ll likely want to have some information about what size your text is. This information is really hard to obtain with the canvas api in general (so this is not related to the question whether to use Elm or not).
In these cases, I find it’s hard to find solutions. If the text metrics API that vanilla JS gives you is enough (keep in mind this API is not easily accessible from Elm, even with elm-canvas), you’re lucky and I’d suggest using canvas.
Otherwise, try to go native, or - if you’re really ambitious - you can try something like canaskit (but keep in mind that it’s not mature yet).
Good luck with your canvas heavy web application! I love these kinds of web apps.
I’m tempted to say that Elm isn’t well suited for working with canvas, but I have had a nice time when I have. I made this paint app years ago in Elm 0.18 and canvas: www.ctpaint.org/app
joakin/elm-canvas is great. If for some reason that doesnt suit your needs, I have had a nice time writing something in JS called a CanvasManager that receives port messages from Elm about what canvas operations to apply to what canvas.
So, I imagine an api like:
type CanvasOperation
= PutPixel Position Color
| Fill Color
msgToCanvasManager : { htmlId : String } -> List CanvasOperation -> Cmd msg
Then on the JS side, something like
const canvas = document.getElementById(msg.htmlId);
const ctx = canvas.getContext('2d');
switch (msg.operation.type) {
case "fill":
ctx.fill();
break;
case "put pixel":
ctx.getImageData();
// ..
// I cant remember the canvas api right now
// but hopefully you can see the idea
break;
}