My favorites | Sign in
Project Logo
                
Search
for
Updated Oct 06, 2009 by mbostock
Labels: Concept
PropertyChaining  
Properties can refer to computed properties on other marks.

Property Chaining

Using parent

The most common way marks may refer to previously-computed properties is by looking at their parent.

Using proto

Description forthcoming. Note: requires that proto is visible and rendered. Also, if a property function that references this.proto is inherited, the reference changes!

Using globals

A stacked area chart can be produced using property chaining, where a new mark's properties are defined in terms of an existing one:

var vis = new pv.Panel()
    .width(150)
    .height(150);

var area = vis.add(pv.Area)
    .data([1, 1.2, 1.7, 1.5, .7, .5, .2])
    .bottom(0)
    .height(function(d) d * 40)
    .left(function() this.index * 25)
    .fillStyle("steelblue");

area.add(pv.Area)
    .data([.4, .2, .8, 1.2, 1.5, 1.1, .8])
    .bottom(function() area.bottom() + area.height())
    .fillStyle("lightsteelblue");

vis.render();

This example actually combines inheritance with property chaining. Another example:

var vis = new pv.Panel()
    .width(150)
    .height(150);

var area = vis.add(pv.Area)
    .data([1, 1.2, 1.7, 1.5, .7, .5, .2])
    .left(0)
    .width(function(d) d * 40)
    .bottom(function() this.index * 25);

area.add(pv.Area)
    .data([.4, .2, .8, 1.2, 1.5, 1.1, .8])
    .left(function() area.left() + area.width())
  .add(pv.Line)
    .strokeStyle("white");

vis.render();

Although straightforward, property chaining can be verbose.

Using the scene graph

Stacked area charts can also be specified using panels. As above, the panel data is a two-dimensional array, each element an array of values for the area. To offset the bottom of the area, we refer to the cousin, which is the corresponding area instance in the previous instance of the parent panel:

new pv.Panel()
    .width(150)
    .height(150)
  .add(pv.Panel)
    .data([[1, 1.2, 1.7, 1.5, .7, .5, .2],
           [.4, .2, .8, 1.2, 1.5, 1.1, .8],
           [.4, .6, .8, .7, .6, .5, .8]])
  .add(pv.Area)
    .data(function(d) d)
    .bottom(function() {
        var c = this.cousin();
        return c ? c.bottom + c.height : 0;
      })
    .height(function(d) d * 40)
    .left(function() this.index * 25)
  .root.render();

Of course, this is a bit convoluted. The convenient stack layout presents an automatic alternative, but it would be nice to design something a bit more robust (for instance, that calculates the offset in data space rather than pixel space). The technique of using the cousin can break if some of the panel instances are invisible, or in conjunction with inheritance.


Sign in to add a comment
Hosted by Google Code