elm-community / elm-webgl

Moved to elm-explorations/webgl
http://package.elm-lang.org/packages/elm-explorations/webgl/latest
BSD 3-Clause "New" or "Revised" License
95 stars 22 forks source link

JS Interop: Direct Access to "draw()"? #25

Closed felixguendling closed 8 years ago

felixguendling commented 8 years ago

I'm currently experimenting using elm-webgl to power a canvas on a Leaflet.js map to render geo data. Basically, this is working great! I think Elm could be a good fit to render big amounts of live geo data.

Unfortunately, the JS Ports feature of Elm seems to be asynchronous which leads to a laggy view. I've created an example to show the behavior: https://github.com/felixguendling/elm-map/tree/master

The rendering works fine, but when you drag/move the map, the canvas contents get displayed at the wrong position for perhaps a few milliseconds. I assume this glitch originates from the ports not being synchronous. There are some plain JS examples that do the same with the slight difference, that the canvas update happens at the same time as the CSS update of the map.

Problem in the code (https://github.com/felixguendling/elm-map/blob/master/index.html):

app.ports.mapUpdate.send

and

var pos = this._map.containerPointToLayerPoint([0, 0]);
L.DomUtil.setPosition(this._el, pos);

are not synchronized.

So, my question is: is there a way to instantly render the changes or are there some kind of "synchronous ports" in Elm? Or is there a totally different solution to this problem?

Edit: The model needs to be updated before the synchronous redraw.

w0rm commented 8 years ago

@felixguendling why do you want to move the canvas element, and not the triangle within it? You could've sent the offset to webgl and use it to offset the triangle.

w0rm commented 8 years ago

@felixguendling, sorry. I see why you need it now, it is moved with the main map and you have to reposition it with the opposite offset.

felixguendling commented 8 years ago

@w0rm thank you for looking into the problem.

Yes. That's the approach other implementations use, too. This way, I don't have to use the "move" callback commented out in the file: https://github.com/felixguendling/elm-map/blob/master/index.html#L24

If I use the "move" callback (and position the canvas outside, not as child DOM of the map), another undesired "effect" appears: the constant rerender is not exactly synchronous with the drag movement of the user. Thus, the triangle is not at the same geographical location which looks weird. Furthermore, the system load increases significantly when dragging the map around (laptop fan makes noise).

I think this is a problem with Elm Ports being asynchronous in general, making real-time JS interop hard. But perhaps there is a way to solve this specific problem without touching the Elm compiler?

Edit: I thought about implementing a simple tile-based map in Elm (which would result in synchronous updates!). But I think that's not an easy problem. So using an existing mature library like Leaflet was my first approach.

nphollon commented 8 years ago

This seems like a great topic to bring up on the elm-dev mailing list.

As for finding a work-around within elm-webgl, I don't see a good way of doing it. You'd have to decouple from Elm's VDOM render loop somehow, right?

felixguendling commented 8 years ago

Thanks for the hint. I opened a discussion: https://groups.google.com/forum/#!topic/elm-dev/lAEnpHQzS5c