Projet WAVE

ANR | ContInt 2013/2015

Segment components

on

!!!!!!!!!!!!!!!!!!
The code in this post is out of date! please refer to this post for the new APIs
!!!!!!!!!!!!!!!!!!

For those of you that our last post on the visual tools I’m happy to announce that we just released on our github account preliminary versions of some of the mentioned tools!

We published the base-timeline module, and a couple of other modules that go along with it, one segment visualiser and a segment editor.

In this post I will try to explain how to use them altogether.

Act 1. The data

Even though we plan to normalise our data into a specific container, for the sake of this demo I’m going to be using Backbone Models and Collections.

1
2
3
4
5
6
7
8
var collection = new Backbone.Collection([{
    "begin": "0",
    "duration": "16121",
    "end": "16121",
    "color": "#A9d"
  }, { "begin": "1" },
  }, { "begin": "3" },
]);

Act 2. The layout

baseTimeline

Once the we have the data in place we can instantiate the visualisers. As explained in the mentioned post, we will be representing all the visualisations as layers inside a shared timeline, this timeline can handle one or more layers.

1
var graph = createBaseTimeline();

createBaseTimeline give us in return a configurable graph object, with the means to modify the necessary properties of our visualisation. baseTimeline is designed after d3js reusable pattern except we use objects instead of plain functions, and use a draw method as the main entry point to our visualisation. What that means is that instead of just passing the created graph as a function to a d3 selection, we have to feed it the graph.draw method of our object.

1
d3.select('.somediv').call(graph.draw)

You can alliteratively chain up your configurations and leave the draw method at the end of the chain, which will then be assigned to our graph variable, allowing us to use it transparently as you would the usual reusable charts:

1
2
3
4
5
6
7
8
9
10
11
12
// we calculate the max as the limit of our horizontal axis
var max = d3.max(collection.models, function(d){ return parseInt(d.get('end'), 10);});

// then we can configure the visualisation
  graph
    .xDomain([0, max])
    .width(500)
    .height(80)
    .margin({top: 60, right: 60, bottom: 20, left: 0})
    .draw; // entry point

  d3.select('.somediv').call(graph);

If you followed until now, nothing should have happen on your page, that’s just normal since we still need to add some actual layers to the layout. If you inspect your document, however, you’ll see that an SVG and a layout group appeared, and are indeed waiting for your layers to be drawn.

Act 3. The layers

Segment visualiser

With the layout in place is time to create a layer and add it.
For segmented data we can now choose if we want an editor layer or just a visualiser. The modules are based on the same core, and the editing is basically added functionality on top of the visualiser.
First let’s see how we would create a simple segment visualiser layer:

1
var seg = createSegVis({name: 'segments', data: collection.models});

createSegVis will return a layer object. These layers objects won’t follow strictly the aforementioned reusable charts pattern and are – again – just plain objects with a shared API. That will allow in the future for anyone to program their own layer/component types and add them into the same timeline.

As we can see, the layer takes in a name, and it’s own data. (in upcoming versions a global data will be possible to be passed into the base timeline, but from the beginning we want to be able to render separate datasets in different layers).

To add the layer we just use the graph.layer() method and we should be good to go! Here is all the code together:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

  // data here is an array of objects containing our segments
  var collection = new Backbone.Collection(data);
  // compute the maximum value for the x domain
  var max = d3.max(collection.models, function(d){ return parseInt(d.get('end'), 10);});
  // create the segment layer
  var seg = createSegVis({name: 'segments', data: collection.models});

  var graph = createBaseTimeline()
    .xDomain([0, max])
    .width(500)
    .height(80)
    .margin({top: 0, right: 60, bottom: 20, left: 0})
    .layer(seg) // segment visualisier layer
    .draw;

  d3.select('.timeline').call(graph);

Segment editor

In the case we would want to edit, the difference for the user would be minimal, all you have to do is, instead of including seg-vis.min.js in you page, include seg-edit.min.js call createSegEdit instead of createSegVis and voilà:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

  // data.js is loaded exposing an array of objects called data
  var collection = new Backbone.Collection(data);
  var max = d3.max(collection.models, function(d){ return parseInt(d.get('end'), 10);});
  // create the segment layer
  var edit = createSegEdit({name: 'segments', data: collection.models});

  var editor = createBaseTimeline()
    .xDomain([0, max])
    .width(500)
    .height(80)
    .model(collection.models)
    .margin({top: 0, right: 60, bottom: 20, left: 0})
    .layer(edit) // segment editor layer
    .draw;

  d3.select('.editTimeline').call(editor);

The editor has built-in interactions such as move and resize. Multiple segments can be selected and edited together by selecting them while holding the shift key.

In order to add or remove items to the visualisation you just would act on the data (in this case our backbone models) and collection.remove(item) or collection.add({modelitem}). The visualisation will react accordingly through d3js enters and updates phases.

The end

This is till work in progress and we will keep on implementing features, but hopefully with this post you get an idea of where this is going and how we intend it to work.

Please fill free to submit your issues, feedback and pull requests!