Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using D3 with Elm

Tags:

d3.js

elm

Is it manageable to using D3 with Elm using ports? I'm trying out Elm but I can't find any examples of using Elm with D3 without a wrapper API. The problem I've run into is that the wrapper and the forks don't work with 0.18. I'm also seeing a lot of statements that suggest building an API around javascript APIs is bad practice and that instead you should use ports. I can't find any examples of this with D3, however. I found this example but the D3 part was all done in plain javascript which doesn't really fit.

I'm probably being too aggressive with taking on D3 right off-the-bat with Elm but that's really what I want to do with it. If it's not really feasible to use D3 with Elm I'll probably not bother with it for now. Is there a fundamental problem with this kind of interaction or is it simply a lack of interest in D3 in the Elm community or am I just missing something?

For example, take this code ripped from the bl.ocks example above:

var t = d3.transition().duration(750);
var g = d3.select("svg g")
// JOIN new data with old elements.
var text = g.selectAll("text")
  .data(data, function(d) { return d; });

// ENTER new elements present in new data.
text.enter().append("text")
  .attr("class", "enter")
  .attr("dy", ".35em")
  .attr("y", -60)
  .attr("x", function(d, i) { return i * 24; })
  .style("fill-opacity", 1e-6)
  .text(function(d) { return d; })
  .transition(t)
  .attr("y", 0)
  .style("fill-opacity", 1);

Is there a straightforward translation into Elm for this kind of thing?

like image 523
JimmyJames Avatar asked Feb 15 '17 15:02

JimmyJames


2 Answers

I know only a little about D3. You will want to put all the data processing in Elm and just pass data out to the js code that controls D3. That will keep your model sane.

You also need to watch out for D3 mutating the DOM because then Elm will struggle to update the parts of the page it is responsible for. Best would be to carve up your page with elm parts and other parts using Elm.embed. But you might be able to have Elm write the whole page and let D3 mutate the DOM if you use Html.keyed to help Elm keep track of what is what in the DOM.

Html.keyed.div "d3node" 
  [ ]
  [ ... ensure that d3 only touches DOM elements inside this node ... ]

You cannot pass functions as such through a port, but you can pass json. so you might use elm to create something like

{ function_type: "f1",
  param1: ... ,
  param2: ...
}

Then you could in JavaScript do a

switch (data.function_type) of 
  case "f1: 
    function1 (data.param1, data.param2);
...


function1(p1, p2) {
  // some sort of D3 manipulation
  var text = g.selectAll(p1)
    .data(data, p2);
like image 86
Simon H Avatar answered Nov 05 '22 15:11

Simon H


Your problem can be solved using a webcomponent like multi-chart.

Import the component inside index.html and create a node with the attributes you want:

Html.node "multi-chart" [ Html.Attributes.attribute "title" "test chart" ] []
like image 34
Lisard Avatar answered Nov 05 '22 15:11

Lisard