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

51
elm-d3: Front-end Development without Frameworks Spiros Eliopoulos (@seliopou) June 30, 2014 NYC D3.js Meetup

Upload: spiros

Post on 10-May-2015

371 views

Category:

Technology


1 download

TRANSCRIPT

Page 1: elm-d3 @ NYC D3.js Meetup (30 June, 2014)

elm-d3: Front-end Development without

FrameworksSpiros Eliopoulos (@seliopou)

June 30, 2014 NYC D3.js Meetup

Page 2: elm-d3 @ NYC D3.js Meetup (30 June, 2014)

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.

Page 3: elm-d3 @ NYC D3.js Meetup (30 June, 2014)

What is D3?

• Preaching to the choir.

• Assumed.

Page 4: elm-d3 @ NYC D3.js Meetup (30 June, 2014)

Let’s get on the same page about MVC.

Page 5: elm-d3 @ NYC D3.js Meetup (30 June, 2014)

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.

Page 6: elm-d3 @ NYC D3.js Meetup (30 June, 2014)

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.

Page 7: elm-d3 @ NYC D3.js Meetup (30 June, 2014)

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

Page 8: elm-d3 @ NYC D3.js Meetup (30 June, 2014)

A “complete” MVC application.

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

Page 9: elm-d3 @ NYC D3.js Meetup (30 June, 2014)

An even more “complete” MVC application.

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

Page 10: elm-d3 @ NYC D3.js Meetup (30 June, 2014)

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)

Page 11: elm-d3 @ NYC D3.js Meetup (30 June, 2014)

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

and controllers.

Page 12: elm-d3 @ NYC D3.js Meetup (30 June, 2014)

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

Page 13: elm-d3 @ NYC D3.js Meetup (30 June, 2014)

Part Ia A Basic Operation

Page 14: elm-d3 @ NYC D3.js Meetup (30 June, 2014)

An example operation.

d3.selectAll(“div”)

Page 15: elm-d3 @ NYC D3.js Meetup (30 June, 2014)

Shorthand for this.

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

Page 16: elm-d3 @ NYC D3.js Meetup (30 June, 2014)

More generally.

context.selectAll(“div”)

Page 17: elm-d3 @ NYC D3.js Meetup (30 June, 2014)

Remove free variables so it works in isolation.

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

Page 18: elm-d3 @ NYC D3.js Meetup (30 June, 2014)

Parameterize by the element name.

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

Page 19: elm-d3 @ NYC D3.js Meetup (30 June, 2014)

Using it.

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

Page 20: elm-d3 @ NYC D3.js Meetup (30 June, 2014)

Part Ib Another Basic Operation

Page 21: elm-d3 @ NYC D3.js Meetup (30 June, 2014)

Another example operation.

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

Page 22: elm-d3 @ NYC D3.js Meetup (30 June, 2014)

Get rid of free variables

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

Page 23: elm-d3 @ NYC D3.js Meetup (30 June, 2014)

Using it.

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

Page 24: elm-d3 @ NYC D3.js Meetup (30 June, 2014)

Part Ic Last Basic Operation

Page 25: elm-d3 @ NYC D3.js Meetup (30 June, 2014)

Data binding for good measure.

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

Page 26: elm-d3 @ NYC D3.js Meetup (30 June, 2014)

Part Id So what?

Page 27: elm-d3 @ NYC D3.js Meetup (30 June, 2014)

Page 28: elm-d3 @ NYC D3.js Meetup (30 June, 2014)

Part II Combining Operations

Page 29: elm-d3 @ NYC D3.js Meetup (30 June, 2014)

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

Page 30: elm-d3 @ NYC D3.js Meetup (30 June, 2014)

Regular D3.js.

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

Page 31: elm-d3 @ NYC D3.js Meetup (30 June, 2014)

Using basic operations.

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

Page 32: elm-d3 @ NYC D3.js Meetup (30 June, 2014)

Ugly. What’s happening?

Page 33: elm-d3 @ NYC D3.js Meetup (30 June, 2014)

This code has to be read from the inside out.

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

Page 34: elm-d3 @ NYC D3.js Meetup (30 June, 2014)

Method-chaining operations is now

function application.

Page 35: elm-d3 @ NYC D3.js Meetup (30 June, 2014)

Making method chaining explicit.

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

Page 36: elm-d3 @ NYC D3.js Meetup (30 June, 2014)

For good measure, making sequencing explicit.

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

Page 37: elm-d3 @ NYC D3.js Meetup (30 June, 2014)

Composing operations.

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

Page 38: elm-d3 @ NYC D3.js Meetup (30 June, 2014)

Better. Understandable. Also more general.

Page 39: elm-d3 @ NYC D3.js Meetup (30 June, 2014)

Still not great to read or write.

Page 40: elm-d3 @ NYC D3.js Meetup (30 June, 2014)

Part III Writing D3 in Elm

Page 41: elm-d3 @ NYC D3.js Meetup (30 June, 2014)

Wouldn’t this be nice?

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

Page 42: elm-d3 @ NYC D3.js Meetup (30 June, 2014)

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)

Page 43: elm-d3 @ NYC D3.js Meetup (30 June, 2014)

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.

Page 44: elm-d3 @ NYC D3.js Meetup (30 June, 2014)

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)

Page 45: elm-d3 @ NYC D3.js Meetup (30 June, 2014)
Page 46: elm-d3 @ NYC D3.js Meetup (30 June, 2014)

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.

Page 47: elm-d3 @ NYC D3.js Meetup (30 June, 2014)

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")

Page 48: elm-d3 @ NYC D3.js Meetup (30 June, 2014)

Defining the view (svg function elided).

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

Page 49: elm-d3 @ NYC D3.js Meetup (30 June, 2014)

Part IV Writing Applications

using elm-d3

Page 50: elm-d3 @ NYC D3.js Meetup (30 June, 2014)
Page 51: elm-d3 @ NYC D3.js Meetup (30 June, 2014)

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