elm-d3 @ nyc d3.js meetup (30 june, 2014)

Post on 10-May-2015

371 Views

Category:

Technology

1 Downloads

Preview:

Click to see full reader

TRANSCRIPT

elm-d3: Front-end Development without

FrameworksSpiros Eliopoulos (@seliopou)

June 30, 2014 NYC D3.js Meetup

What is Elm?• Elm is a functional-reactive programming language for

the web.

• It kind of looks like Haskell or OCaml and is statically-typed like them, but it’s less scary and compiles to JavaScript.

• It models inputs as time-varying values called Signals.!

• You can lift pure functions to Signals to build up complex applications from basic inputs.

What is D3?

• Preaching to the choir.

• Assumed.

Let’s get on the same page about MVC.

Model is Information• The model describes the entire state of the

application, all in one place.

• It has a concrete type: m, i.e, data m = { … }

• While bits of state may be otherwise strewn about the application, the model is the authoritative record of state. In other words, you should never read the random bits.

View is Computation

• To display an interface, you have to produce some representation of the interface that the underlying system can use to render the interface, e.g., HTML.

• The representation has a type r.

• The view is a function from the model to the representation: m -> r.

Controller is Computation• The controller mediates user interactions and

model updates. It handles events by updating the model accordingly.

• Events have a concrete type e.

• An event handler is a function from an event and model to an updated model: e -> m -> m.!

• A controller turns a stream of events into a signal of models: Stream e -> Signal m

A “complete” MVC application.

view m = … handler e m = … controller = … handler … !main : Signal Element main = lift view (controller events)

An even more “complete” MVC application.

view m = … handler e m = … controller = folde initModel handler !main : Signal Element main = lift view (controller events)

An even more “complete” MVC application.

view m = render w h d3_view m handler e m = … controller = folde initModel handler !main : Signal Element main = lift view (controller events)

Goal I: Use Elm to create models, event handlers,

and controllers.

Goal II: Use D3.js to create declarative, compseable views.

Part Ia A Basic Operation

An example operation.

d3.selectAll(“div”)

Shorthand for this.

d3.select(document).selectAll(“div”)

More generally.

context.selectAll(“div”)

Remove free variables so it works in isolation.

function(context) { return context.selectAll(“div”); }

Parameterize by the element name.

var selectAll = function(elt) { return function(context) { return context.selectAll(elt); } }

Using it.

selectAll(“div”)(d3.select(document))

Part Ib Another Basic Operation

Another example operation.

context.attr(“class”, “box”);

Get rid of free variables

var attr = function(name, val) { return function(context) { return context.attr(name, val); } }

Using it.

!attr(“class”,“box”)(d3.select(“div”))

Part Ic Last Basic Operation

Data binding for good measure.

var bind = function(val) { return function(context) { return context.data(val); }; }

Part Id So what?

Part II Combining Operations

How do you write an operation that will set the class string of every <div> to “box”?

Regular D3.js.

d3.selectAll(“div”) .attr(“class”, “box”);

Using basic operations.

var div_op = function(context) { return attr(“class”, “box”) (selectAll(“div”)(context); }

Ugly. What’s happening?

This code has to be read from the inside out.

var div_op = function(context) { return attr(“class”, “box”) (selectAll(“div”)(context); }

Method-chaining operations is now

function application.

Making method chaining explicit.

var chain = function(op1, op2) { return function(context) { return op2(op1(context)); }; }

For good measure, making sequencing explicit.

var seq = function(op1, op2) { return function(context) { op1(context); return op2(context); }; }

Composing operations.

var div_op = chain(selectAll(“div”), attr(“class”, “box”));

Better. Understandable. Also more general.

Still not great to read or write.

Part III Writing D3 in Elm

Wouldn’t this be nice?

div_op : Selection a div_op = selectAll “div” |. str attr “class” “box”

Why Is This Nice?• This is Elm code: it’s type-safe.

• |. is the method chaining operation: concise and no code inversion.

• It’s compositional: take basic operations and combine them to create a “bigger” operation.

• It’s reusable: The new operation is just another value that you can compose with other operations.

div_op : Selection a div_op = selectAll “div” |. str attr “class” “box” !div_op’ : Selection Int div_op’ = div_op |. attr “width” (\d i -> show d)

Selection a• This is the type of a D3 operation in Elm.

• The a is the type of data that the operation expects to be bound to the parent selection it’s applied to.

• If a is a type variable, then the operation does not inspect the data and can be used in all contexts.

• If a is a concrete type, such as Int, that limits the other operations it can be composed with.

• The render function from before is what does the initial data binding of the model to the root of the DOM tree.

Wouldn’t this be nice?

circles : Widget [Point] Point circles = selectAll "circle" |= List.tail |- enter <.> append “circle” |. num attr "r" 1.5 |. str attr "fill" "black" |- update |. fun attr "cx" (\p _ -> show p.x) |. fun attr "cy" (\p _ -> show p.y)

Widget a b• This is the type of a D3 data bind, introduced by

the |= operation.

• The a is the type of operations that the data bind can be composed with.

• The b is the type of operations that can be composed with the data bind.

• You turn a Widget a b into a Selection a using the embed function.

Wouldn’t this be nice too?

voronoi : Widget [Point] [Point] voronoi = selectAll "path" |= Voronoi.cells |- enter <.> append "path" |- update |. fun attr "d" (\d _ -> path d) |. fun attr "class" (\_ i -> "q" ++ (show (mod i 9)) ++ "-9")

Defining the view (svg function elided).

view : Dims -> Margins -> Selection [Point] view dims margins = svg dims margins |. seq (embed voronoi) (embed circles)

Part IV Writing Applications

using elm-d3

https://github.com/seliopou/elm-d3

top related