d3.compose

d3.compose adds advanced chart layout and composition to d3 and d3.chart. Create rich, data-bound charts by composing charts (like Line and Bars) and components (like Axis, Title, and Legend).

Downloads & Dependencies

d3.compose-all

Includes all charts, components, extensions, and mixins.

d3.compose-all.js 186kb Development: Full source with tons of comments.
d3.compose-all.min.js 15.2kb Production: minified and gzipped (Source Map)
d3.compose.css Base styling for d3.compose charts/components

d3.compose-mixins

Use if you're creating your own charts/components and want to use d3.compose's mixins to help.

d3.compose-mixins.js 114kb Development
d3.compose-mixins.min.js 9.3kb Production (Source Map)

d3.compose

Use if you're using your own charts/components and don't need mixins, charts, or components provided by d3.compose.

d3.compose.js 84kb Development
d3.compose.min.js 7.5kb Production (Source Map)

d3.compose depends on the following libraries:

Introduction

When creating complex charts with D3.js and d3.chart, laying out and sizing parts of the chart are often manual processes and creating composable and reusable components becomes very difficult. d3.compose creates a standard base that charts and components are built on top of that automatically handles layout and sizing and can be composed and layered to created rich, data-bound charts.

Usage

Add d3.compose and its dependencies to your page:

<!doctype html>
<html>
  <head>
    <!-- ... -->

    <link rel="stylesheet" type="text/css" href="d3.compose.css">
  </head>
  <body>
    <!-- ... -->

    <script src="d3.js"></script>
    <script src="d3.chart.js"></script>

    <script src="d3.compose-all.js"></script>

    <!-- Your code -->
  </body>
</html>

Compose

Compose rich, data-bound charts from charts (like Lines and Bars) and components (like Axis, Title, and Legend) with d3 and d3.chart. Using the options property, charts and components can be bound to data and customized to create dynamic charts.

<div id="#chart"></div>
var chart = d3.select('#chart').chart('Compose', function(data) {
  // Process data...

  // Create shared scales
  var scales = {
    x: {data: data.input, key: 'x', adjacent: true},
    y: {data: data.input, key: 'y'},
    y2: {data: data.output, key: 'y'}
  };

  // Setup charts and components
  var charts = [
    d3c.bars('input', {data: data.input, xScale: scales.x, yScale: scales.y}),
    d3c.lines('output', {data: data.output, xScale: scales.x, yScale: scales.y2})
  ];

  var title = d3c.title('d3.compose');
  var xAxis = d3c.axis('xAxis', {scale: scales.x});
  var yAxis = d3c.axis('yAxis', {scale: scales.y});
  var y2Axis = d3c.axis('y2Axis', {scale: scales.y2});

  // Layout charts and components
  return [
    title,
    [yAxis, d3c.layered(charts), y2Axis],
    xAxis
  ];;
});

chart.draw({input: [...], output: [...]});

options {Function|Object}

Get/set the options object/function for the chart that takes data and returns [...layout] for composing child charts and components.

// get
chart.options();

// set (static)
chart.options([
  // ...
]);

// set (dynamic, takes data and returns options)
chart.options(function(data) {
  // process data...

  return [
    // ...
  ];
});

// Set directly from d3.chart creation
d3.select('#chart')
  .chart('Compose', function(data) {
    // ...
  });

margins {Object {top, right, bottom, left}} [{top: 10, right: 10, bottom: 10, left: 10}]

Margins between edge of container and components/chart

chart.margins({top: 10, right: 20, bottom: 10, left: 20});

width {Number}

Get/set overall width of chart

height {Number}

Get/set overall height of chart

responsive {Boolean} [true]

Enable responsive container + viewBox so that chart scales to fill width (only works if selection is not an svg)

charts {Array}

Set charts from options or get chart instances. Each chart should use a unique key so that updates are passed to the existing chart (otherwise they are recreated on update). The type option must be a registered d3.chart and all other options are passed to the chart.

chart.charts([
  {id: 'input', type: 'Bars'}, // options to pass to Bars chart
  {id: 'output', type: 'Lines'} // options to pass to Lines chart
]);

components {Array}

Set components from options or get components instances. Each component should use a unique key so that updates are passed to the existing chart (otherwise they are recreated on update). The type option must be a registered d3.chart and all other options are passed to the component.

chart.components([
  {id: 'axis.y', type: 'Axis'}, // options to pass to Axis component
  {id: 'title', type: 'Title'} // options to pass to Title component
])

delay {Number|Function} [d3 default: 0]

Delay start of transition by specified milliseconds. (applied to all charts and components as default)

duration {Number|Function} [d3 default: 250ms]

Transition duration in milliseconds. (applied to all charts and components as default)

ease {String|Function} [d3 default: 'cubic-in-out']

Transition ease function. (applied to all charts and components as default)

draw draw(data)

  1. data (Any)

Draw chart with given data

var chart = d3.select('#chart')
  .chart('Compose', function(data) {
    // ...
  });

chart.draw([1, 2, 3]);

chart.draw({values: [1, 2, 3]});

chart.draw([
  {values: [1, 2, 3]},
  {values: [4, 5, 6]}
]);

redraw

Redraw chart with current data

Inherits

Chart

Common base for creating charts. Standard d3.chart charts can be used with d3.compose, but extending d3.chart('Chart') includes helpers for properties and "di" functions.

Extending

To take advantage of "di"-binding (automatically injects chart into "di" methods) and automatically setting properties from options, use d3.compose.helpers.di and d3.compose.helpers.property when creating your chart.

var helpers = d3.compose.helpers;

d3.chart('Chart').extend('Pie', {
  initialize: function() {
    // same as d3.chart
  },
  transform: function(data) {
    // same as d3.chart
  },

  color: helpers.di(function(chart, d, i) {
    // "di" function with parent chart injected ("this" = element)
  }),

  centered: helpers.property({
    default_value: true
    // can be automatically set from options object
  })
});

z_index Static

Default z-index for chart (Components are 50 by default, so Chart = 100 is above component by default)

d3.chart('Chart').extend('BelowComponentLayers', {
  // ...
}, {
  z_index: 40
});

Inherits

Component

Common base for creating components that includes helpers for positioning and layout.

Extending

d3.chart('Component') contains intelligent defaults and there are no required overrides. Create a component just like a chart, by creating layers in the initialize method in extend.

  • To adjust layout calculation, use prepareLayout, getLayout, and setLayout.
  • To layout a component within the chart, use skip_layout: true and the static layer_type: 'chart'
d3.chart('Component').extend('Key', {
  initialize: function() {
    this.layer('Key', this.base, {
      dataBind: function(data) {
        return this.selectAll('text')
          .data(data);
      },
      insert: function() {
        return this.append('text');
      },
      events: {
        merge: function() {
          this.text(this.chart().keyText)
        }
      }
    })
  },

  keyText: helpers.di(function(chart, d, i) {
    return d.abbr + ' = ' + d.value;
  })
});

position {String} ['top']

Component's position relative to chart (top, right, bottom, left)

width {Number} [(actual width)]

Get/set the width of the component (in pixels) (used in layout calculations)

height {Number} [(actual height)]

Get/set the height of the component (in pixels) (used in layout calculations)

margins {Object} [{top: 0, right: 0, bottom: 0, left: 0}]

Margins (in pixels) around component

centered {Boolean} [false]

Center the component vertically/horizontally (depending on position)

skip_layout

Skip component during layout calculations and positioning (override in prototype of extension)

d3.chart('Component').extend('NotLaidOut', {
  skip_layout: true
});

prepareLayout prepareLayout(data)

  1. data (Any)

Perform any layout preparation required before getLayout (default is draw) (override in prototype of extension)

Note: By default, components are double-drawn; for every draw, they are drawn once to determine the layout size of the component and a second time for display with the calculated layout. This can cause issues if the component uses transitions. See Axis for an example of a Component with transitions.

d3.chart('Component').extend('Custom', {
  prepareLayout: function(data) {
    // default: this.draw(data);
    // so that getLayout has real dimensions

    // -> custom preparation (if necessary)
  }
})

getLayout getLayout(data)

  1. data (Any)
Returns (Object)

position, width, and height for layout

Get layout details for use when laying out component (override in prototype of extension)

d3.chart('Component').extend('Custom', {
  getLayout: function(data) {
    var calculated_width, calculated_height;

    // Perform custom calculations...

    // Must return position, width, and height
    return {
      position: this.position(),
      width: calculated_width,
      height: calculated_height
    };
  }
});

setLayout setLayout(x, y, options)

  1. x (Number)

    position of base top-left

  2. y (Number)

    position of base top-left

  3. options (Object)
    • [height] (Object)

      height of component in layout

    • [width] (Object)

      width of component in layout

Set layout of underlying base (override in prototype of extension)

d3.chart('Component').extend('Custom', {
  setLayout: function(x, y, options) {
    // Set layout of this.base...
    // (the following is the default implementation)
    var margins = this.margins();

    // (handle this.centered())

    this.base
      .attr('transform', helpers.translate(x + margins.left, y + margins.top));
    this.height(options && options.height);
    this.width(options && options.width);
  }
});

z_index Static

Default z-index for component (Charts are 100 by default, so Component = 50 is below chart by default)

d3.chart('Component').extend('AboveChartLayers', {
  // ...
}, {
  z_index: 150
});

layer_type Static

Set to 'chart' to use chart layer for component. (e.g. Axis uses chart layer to position with charts, but includes layout for ticks)

d3.chart('Component').extend('ChartComponent', {
  // ...
}, {
  layer_type: 'chart'
});

Inherits

Overlay

Common base for creating overlays that includes helpers for positioning and show/hide.

Extending

Create an overlay just like a chart, by creating layers in the initialize method in extend.

  • To adjust positioning, override position
  • To adjust show/hide behavior, override show/hide
d3.chart('Overlay').extend('ClosestPoints', {
  // TODO
});

x {Number} [0]

Overlay's top-left x-position in px from left

y {Number} [0]

Overlay's top-left y-position in px from top

hidden {Boolean} [true]

Whether overlay is currently hidden

style {String} [set from x, y, and hidden]

Overlays base styling (default includes position and hidden)

position position(position, [y])

  1. position (Object|Number)

    {x,y}, {container: {x,y}}, {chart: {x,y}} or x in px from left

  2. [y] (Number)

    in px from top

Position overlay layer at given x,y coordinates

// Absolute, x: 100, y: 50
overlay.position(100, 50);
overlay.position({x: 100, y: 50});

// Relative-to-chart, x: 50, y: 40
overlay.position({chart: {x: 50, y: 40}});

// Relative-to-container, x: 75, y: 50
overlay.position({container: {x: 75, y: 50}});

show

Show overlay (with display: block)

hide

Hide overlay (with display: none)

getAbsolutePosition getAbsolutePosition(container_position)

  1. container_position (Object)

    ({x, y})

Returns (Object)

absolute {x, y} relative to container div

Get absolute position from container position (needed since container position uses viewBox and needs to be scaled to absolute position)

Inherits

Base

Shared functionality between all charts and components.

  • Set properties automatically from options,
  • Store fully transformed data
  • Adds "before:draw" and "draw" events
  • Standard width and height calculations

data {Any}

Store fully-transformed data for direct access from the chart

options {Object}

Overall options for chart/component, automatically setting any matching properties.

var property = d3.compose.helpers.property;

d3.chart('Base').extend('HasProperties', {
  a: property(),
  b: property({
    set: function(value) {
      return {
        override: value + '!'
      };
    }
  })
});

var instance = d3.select('#chart')
  .chart('HasProperties', {
    a: 123,
    b: 'Howdy',
    c: true
  });

// Equivalent to:
// d3.select(...)
//   .chart('HasProperties')
//   .options({...});

console.log(instance.a()); // -> 123
console.log(instance.b()); // -> Howdy!
console.log(instance.options().c); // -> true

width

Returns (Number)

Get width of this.base. (Does not include set for setting width of this.base)

height

Returns (Number)

Get height of this.base. (Does not include set for setting height of this.base)


Lines

Create an XY Lines chart with single or series data.

Extending

Great care has been taken in making the standard charts in d3.compose extensible. To extend the Lines chart, the following methods are available:

  • createLine
  • lineKey
  • lineData
  • onDataBind
  • onInsert
  • onEnter
  • onEnterTransition
  • onUpdate
  • onUpdateTransition
  • onMerge
  • onMergeTransition
  • onExit
  • onExitTransition

View the Lines.js source for the default implementation and more information on these methods.

var chart = d3.select('#chart').chart('Compose', function(data) {
  return {
    charts: {
      input: {
        type: 'Lines'
        data: data.input,
        // xScale: ...,
        // yScale: ...,
        // other properties...
      }
    }
  };
});

// Single y-values
chart.draw([1, 2, 3]);

// Series (x,y) values
chart.draw([
  {values: [{x: 0, y: 1}, {x: 1, y: 2}, {x: 2, y: 3}]}
  {values: [{x: 0, y: 3}, {x: 1, y: 2}, {x: 2, y: 1}]}
]);

interpolate {String} [monotone]

Set interpolation mode for line

Inherits

Bars

Bars chart with centered or adjacent display for single or series data.

To display bars for different series next to each other (adjacent), use the adjacent option when creating the xScale (see example below).

Extending

To extend the Bars chart, the following methods are available:

  • barHeight
  • barWidth
  • barX
  • barY
  • barClass
  • onDataBind
  • onInsert
  • onEnter
  • onEnterTransition
  • onUpdate
  • onUpdateTransition
  • onMerge
  • onMergeTransition
  • onExit
  • onExitTransition
var chart = d3.select('#chart').chart('Compose', function(data) {
  // Display bars for different series next to each other (adjacent: true)
  var xScale = {type: 'ordinal', adjacent: true, domain: [0, 1, 2]};

  return {
    charts: {
      output: {
        type: 'Bars',
        data: data.output,
        xScale: xScale,
        // yScale: ...,
        // other properties...
      }
    }
  };
});

// Single y-values
chart.draw([10, 20, 30]);

// Series (x,y) values
chart.draw([
  {values: [{x: 0, y: 10}, {x: 1, y: 20}, {x: 2, y: 30}]},
  {values: [{x: 0, y: 30}, {x: 1, y: 20}, {x: 2, y: 10}]}
]);

Inherits

StackedBars

Bars chart with values stacked on top of each other

(See Bars for extensibility details)

var chart = d3.select('#chart').chart('Compose', function(data) {
  // Display bars for different series next to each other (adjacent: true)
  var xScale = {type: 'ordinal', adjacent: true, domain: [0, 1, 2]};

  return {
    charts: {
      stacked_output: {
        type: 'StackedBars',
        data: data.output,
        xScale: xScale,
        // yScale: ...,
        // other properties...
      }
    }
  };
});

// Single y-values
chart.draw([10, 20, 30]);

// Series (x,y) values
chart.draw([
  {values: [{x: 0, y: 10}, {x: 1, y: 20}, {x: 2, y: 30}]},
  {values: [{x: 0, y: 30}, {x: 1, y: 20}, {x: 2, y: 10}]}
]);

Inherits

HorizontalBars

Bars chart with bars that group from left-to-right

(See Bars for extensibility details)

var chart = d3.select('#chart').chart('Compose', function(data) {
  // Display bars for different series next to each other (adjacent: true)
  var xScale = {type: 'ordinal', adjacent: true, domain: [0, 1, 2]};

  return {
    charts: {
      output: {
        type: 'HorizontalBars',
        data: data.output,
        xScale: xScale,
        // yScale: ...,
        // other properties...
      }
    }
  };
});

// Single y-values
chart.draw([10, 20, 30]);

// Series (x,y) values
chart.draw([
  {values: [{x: 0, y: 10}, {x: 1, y: 20}, {x: 2, y: 30}]},
  {values: [{x: 0, y: 30}, {x: 1, y: 20}, {x: 2, y: 10}]}
]);

Inherits

HorizontalStackedBars

Horizontal Stacked Bars

(See Bars for extensibility details)

var chart = d3.select('#chart').chart('Compose', function(data) {
  // Display bars for different series next to each other (adjacent: true)
  var xScale = {type: 'ordinal', adjacent: true, domain: [0, 1, 2]};

  return {
    charts: {
      output: {
        type: 'HorizontalStackedBars',
        data: data.output,
        xScale: xScale,
        // yScale: ...,
        // other properties...
      }
    }
  };
});

// Single y-values
chart.draw([10, 20, 30]);

// Series (x,y) values
chart.draw([
  {values: [{x: 0, y: 10}, {x: 1, y: 20}, {x: 2, y: 30}]},
  {values: [{x: 0, y: 30}, {x: 1, y: 20}, {x: 2, y: 10}]}
]);

Inherits

Labels

Standalone or "embeddable" labels (uses mixins.Labels and attachLabels to embed in chart)

Extending

To extend the Labels chart, the following methods are available:

  • insertLabels
  • mergeLabels
  • layoutLabels
  • transitionLabels
  • onDataBind
  • onInsert
  • onEnter
  • onEnterTransition
  • onUpdate
  • onUpdateTransition
  • onMerge
  • onMergeTransition
  • onExit
  • onExitTransition

View the Labels.js source for the default implementation and more information on these methods.

var chart = d3.select('#chart').chart('Compose', function(data) {
  return {
    charts: {
      input: {
        type: 'Lines',
        data: data.input,
        // xScale, yScale, other properties...

        // Show labels with default properties
        labels: true
      },
      output: {
        type: 'Bars',
        data: data.output,
        // xScale, yScale, other properties...

        // Pass options to labels
        labels: {
          offset: 2,
          position: 'top',
          style: {
            'font-size': '14px'
          },
          format: d3.format(',0d')
        }
      },
      labels: {
        type: 'Labels',
        data: data.labels,

        // xScale, yScale, other properties...
      }
    }
  };
});

chart.draw({
  input: [1, 2, 3],
  output: [10, 20, 30],
  labels: [
    {x: 0, y: 0},
    {x: 0, y: 30, label: 'Override (y by default)'},
    {x: 2, y: 0},
    {x: 2, y: 30}
  ]
});

format {String|Function}

Formatting function or string (string is passed to d3.format) for label values

position {String|Function} [top|bottom]

Label position relative to data point (top, right, bottom, or left)

Additionally, (a)|(b) can be used to set position to a if y-value >= 0 and b otherwise, where a and b are top, right, bottom, or left

For more advanced positioning, a "di" function can be specified to set position per label

labels.position('top'); // top for all values
labels.position('top|bottom'); // top for y-value >= 0, bottom otherwise
labels.position(function(d, i) { return d.x >= 0 ? 'right' : 'left'; });

offset {Number|Object} [0]

Offset between data point and label (if Number is given, offset is set based on position)

padding {Number} [1]

Padding between text and label background

anchor {String} [middle]

Define text anchor (start, middle, or end)

(set by default based on label position)

alignment {String} [middle]

Define text-alignment (top, middle, or bottom)

(set by default based on label position)

labelText labelText(d, i)

  1. d (Any)
  2. i (Number)
Returns (String)

Get label text for data-point (uses "label" property or y-value)

labelClass labelClass(d, i)

  1. d (Any)
  2. i (Number)
Returns (String)

Get class for label group

Inherits

Axis

Axis component for XY data (wraps d3.axis).

Available d3.axis extensions:

  • ticks
  • tickValues
  • tickSize
  • innerTickSize
  • outerTickSize
  • tickPadding
  • tickFormat
d3.select('#chart')
  .chart('Compose', function(data) {
    var scales = {
      x: {data: data, key: 'x'},
      y: {data: data, key: 'y'}
    };

    var charts = [];
    var xAxis = d3c.axis({scale: scales.x});
    var yAxis = d3c.axis({scale: scales.y});

    return [
      // Display y-axis to left of charts
      [yAxis, d3c.layered(charts)],

      // Display x-axis below charts
      xAxis
    ];
  });

scale {Object|d3.scale}

Scale to pass to d3.axis

  • If xScale/yScale are given, scale is set automatically based on position.
  • Can be d3.scale or, if Object is given, helpers.createScale is used
// Set with d3.scale directly
axis.scale(d3.scale());

// or with Object passed helpers.createScale
axis.scale({data: data, key: 'x'});

// For x0/y0 position, both xScale and yScale needed
// (scale is automatically set by position)
axis.xScale({domain: [0, 100]});
axis.yScale({domain: [0, 10]});
axis.position('y0');

// -> axis.scale() -> axis.xScale by default

translation {Object} [(set based on position)]

{x,y} translation of axis relative to chart (set by default based on position)

orient {String} [(set based on position)]

Axis orient for ticks (set by default based on position)

orientation {String} [(set based on position)]

Axis orientation (vertical or horizonal)

gridlines {Boolean|Object} [false]

Attach gridlines for axis (true to show with default options, {...} to pass options to Gridlines)

Inherits

Legend

Legend component that can automatically pull chart and series information from d3.compose

Notes:

  • To exclude a chart from the legend, use exclude_from_legend = true in chart prototype or options
  • To exclude a series from the legend, use exclude_from_legend = true in series object
  • To add swatch for custom chart, use Legend.registerSwatch()
d3.select('#chart')
  .chart('Compose', function(data) {
    var input = [{key: 'input', name: 'Input', values: data.input}];
    var output = [
      {key: 'output1', name: 'Output 1', values: data.output1},
      {key: 'output2', name: 'Output 2', values: data.output2}
    ];

    var charts = [
      d3c.lines('a', {data: input}), // ...
      d3c.bars('b', {data: output}) // ...
    ];
    var legend = d3c.legend({charts: ['a', 'b']});

    return [
      [d3c.layered(charts), legend]
    ];
  });

// -> automatically creates legend from series data for 'a' and 'b'
//    (Lines Swatch) Input
//    (Bars Swatch) Output 1
//    (Bars Swatch) Output 2

// or, manually set data for legend
return [
  d3c.legend({
    data: [
      {type: 'Lines', text: 'Input', class: 'series-index-0'},
      {type: 'Bars', text: 'Output 1', class: 'series-index-0'},
      {type: 'Bars', text: 'Output 2', class: 'series-index-1'},
    ]
  })
};

charts {Array}

Array of chart keys from container to display in legend

d3.select('#chart')
.chart('Compose', function(data) {
  var charts = [
    {id: 'a'},
    {id: 'b'},
    {id: 'c'}
  ];
  var legend = d3c.legend({charts: ['a', 'c']});

  return [
    [d3c.layered(charts), legend]
  ];
});

swatchDimensions {Object} [{width: 20, height: 20}]

Dimensions of "swatch" in px

margins {Object} [{top: 8, right: 8, bottom: 8, left: 8}]

Margins (in pixels) around legend

stackDirection {String} [(based on position)]

Direction to "stack" legend, "vertical" or "horizontal". (Default is set based on position: top/bottom = "horizontal", left/right = "vertical")

registerSwatch registerSwatch(types, create) Static

  1. types (Array|String)

    Chart type(s)

  2. create (Function)

    "di" function that inserts swatch

Register a swatch create function for the given chart type

d3.chart('Legend').registerSwatch(['Lines'], function(chart, d, i) {
  var dimensions = chart.swatchDimensions();

  return this.append('line')
    .attr('x1', 0).attr('y1', dimensions.height / 2)
    .attr('x2', dimensions.width).attr('y2', dimensions.height / 2)
    .attr('class', 'chart-line');
});

Inherits

InsetLegend

Legend positioned within chart bounds.

translation {Object {x,y}} [{x: 10, y: 10, relative_to: 'left-top'}]

Position legend within chart layer {x, y, relative_to} Use relative_to to use x,y values relative to x-y origin (e.g. "left-top" is default)

d3.select('#chart')
  .chart('Compose', function(data) {
    return {
      components: {
        legend: {
          type: 'InsetLegend',
          // Position legend 10px away from right-bottom corner of chart
          translation: {x: 10, y: 10, relative_to: 'right-bottom'}
        }
      }
    }
  });

Inherits

Text

Add text to a chart.

d3.select('#chart')
  .chart('Compose', function(data) {
    return {
      components: {
        title: {
          type: 'Text',
          position: 'top'
          text: 'Main Title',
          textAlign: 'left',
          'class': 'title'
        },
        notes: {
          type: 'Text',
          position: 'bottom',
          text: 'Notes',
          'class': 'notes'
        }
      }
    };
  });

text {String}

Text to display

rotation {Number} [0]

Rotation of text

textAlign {String} ["center"]

Horizontal text-alignment of text ("left", "center", or "right")

anchor {String} [(set by `textAlign`)]

text-anchor for text ("start", "middle", or "end")

verticalAlign {String} ["middle"]

Vertical aligment for text ("top", "middle", "bottom")

style {Object} [{}]

Style object containing styles for text

Inherits

Title

Title component that extends Text with defaults (styling, sensible margins, and rotated when positioned left or right)

margins {Object} [(set based on `position`)]

Margins (in pixels) around Title

rotation {Number} [(set based on `position`)]

Rotation of title. (Default is -90 for position = "right", 90 for position = "left", and 0 otherwise).

Inherits

AxisTitle

Axis title component that extends Title with defaults (styling)

margins {Object} [(set based on `position`)]

Margins (in pixels) around axis title

Inherits

Gridlines

Gridlines component that draws major ticks for chart

Uses d3.axis extensions for ticks:

  • ticks
  • tickValues

Extending

To extend the Gridlines component, the following methods are available

  • onInsert
  • onEnter
  • onEnterTransition
  • onUpdate
  • onUpdateTransition
  • onMerge
  • onMergeTransition
  • onExit
  • onExitTransition
d3.select('#chart').chart('Compose', function(data) {
  var scales = {
    x: {data: data, key: 'x'},
    y: {data: data, key: 'y'}
  };

  var vertical = d3c.gridlines({
    scale: scales.x,
    orientation: 'vertical'
  });
  var horizontal = d3c.gridlines({
    scale: scales.y,
    orientation: 'horizontal'
  });

  return [
    vertical,
    horizontal
  ];
});

orientation {String} [horizontal]

Use horizontal, vertical gridlines

scale {Object|d3.scale}

Scale to use for gridlines. Can be d3.scale or, if Object is given, helpers.createScale is used.

// Set with d3.scale directly
gridlines.scale(d3.scale());

// or with Object passed to helpers.createScale
gridlines.scale({data: data, key: 'x'});

helpers

d3.compose.helpers includes general purpose helpers that are used throughout d3.compose. Includes convenience functions for create charts/components (property, di, and mixin), helpful calculations (dimensions, max, and min) and other common behavior.

createScale createScale(options)

  1. options (Object|Function)

    (passing in Function returns original function with no changes)

    • [type = 'linear'] (String)

      Any available d3.scale ("linear", "ordinal", "log", etc.) or "time"

    • [domain] (Array)

      Domain for scale

    • [range] (Array)

      Range for scale

    • [data] (Any)

      Used to dynamically set domain (with given value or key)

    • [value] (Function)

      "di"-function for getting value for data

    • [key] (String)

      Data key to extract value

    • [centered] (Boolean)

      For "ordinal" scales, use centered x-values

    • [adjacent] (Boolean)

      For "ordinal" + centered, set x-values for different series next to each other

      • Requires series-index as second argument to scale, otherwise centered x-value is used
      • Requires "data" or "series" options to determine number of series
    • [series] (Number)

      Used with "adjacent" if no "data" is given to set series count

    • [padding = 0.1] (Number)

      For "ordinal" scales, set padding between different x-values

    • [...] (Array...)

      Set any other scale properties with array of arguments to pass to property

Returns (d3.Scale)

Create scale from options

// Simple type, range, and domain
var scale = createScale({
  type: 'linear',
  domain: [0, 100],
  range: [0, 500]
});

// Calculate domain for data
var scale = createScale({
  type: 'log',
  data: [{y: 1}, {y: 100}, {y: 2000}, {y: 5000}],
  key: 'y'
});

// Scale is passed through
var original = d3.scale.linear();
var scale = createScale(original);
scale === original;

// Set other properties by passing in "arguments" array
var scale = createScale({
  type: 'ordinal',
  domain: ['a', 'b', 'c', 'd', 'e'],
  rangeRoundBands: [[0, 100], 0.1, 0.05] // -> rangeRoundBands([0, 100], 0.1, 0.05)
});

// Use ordinal + adjacent for bar charts
var scale = createScale({
  type: 'ordinal',
  adjacent: true,
  domain: ['a', 'b', 'c'],
  series: 2 // Series count is required for adjacent if data isn't given
})

dimensions dimensions(selection)

  1. selection (d3.Selection)
Returns (Object)

{width, height}

Helper for robustly determining width/height of given selector. Checks dimensions from css, attributes, and bounding box.

mixin mixin(Parent, mixins)

  1. Parent (Function)
  2. mixins (...Object)
Returns (Function)

Combine mixins with Parent super class for extension

var a = {transform: function() {}, a: 1};
var b = {initialize: function() {}, b: 2};
var c = {c: 3};

var Custom = mixin(Chart, a, b, c).extend({
  initialize: function(options) {
    this._super.initialize.call(this, options);
    // d
  },
  transform: function(data) {
    data = this._super.transform.call(this, data);
    // d
  }
});

// initialize: Chart, b, d
// transform: Chart, a, d

property property([options])

  1. [options] (Object)
    • [default_value] (Any)

      default value for property (when set value is undefined). If default value is a function, wrap in another function as default_value is evaluated by default.

    • [get] (Function)

      function(value) {return ...} getter, where value is the stored value and return desired value

    • [set] (Function)

      function(value, previous) {return {override, after}}. Return override to override stored value and after() to run after set

    • [context = this] (Object)

      context to evaluate get/set/after functions

Returns (Function)

(): get, (value): set

Helper for creating properties for charts/components

var Custom = d3.chart('Chart').extend('Custom', {
  // Create property that's stored internally as 'simple'
  simple: property()
});
var custom; // = new Custom(...);

// set
custom.simple('Howdy');

// get
console.log(custom.simple()); // -> 'Howdy'

// Advanced
// --------
// Default values:
Custom.prototype.message = property({
  default_value: 'Howdy!'
});

console.log(custom.message()); // -> 'Howdy!'
custom.message('Goodbye');
console.log(custom.message()); // -> 'Goodbye'

// Set to undefined to reset to default value
custom.message(undefined);
console.log(custom.message()); // -> 'Howdy!'

// Computed default value:
Custom.property.computed = property({
  default_value: function() {
    // "this" = Custom instance
    return this.message();
  }
});

// Function default value:
// For function default_values, wrap in function to differentiate from computed
Custom.property.fn = property({
  default_value: function() {
    return function defaultFn() {};
  }
  // The following would be incorrectly evaluated
  // default_value: function defaultFn() {}
})

// Custom getter:
Custom.prototype.exclaimed = property({
  get: function(value) {
    // Value is the underlying set value
    return value + '!';
  }
});

custom.exclaimed('Howdy');
console.log(custom.exclaimed()); // -> 'Howdy!'

// Custom setter:
Custom.prototype.feeling = property({
  set: function(value, previous) {
    if (value == 'Hate') {
      // To override value, return Object with override specified
      return {
        override: 'Love',

        // To do something after override, use after callback
        after: function() {
          console.log('After: ' + this.feeling()); // -> 'After: Love'
        }
      };
    }
  }

  custom.feeling('Hate'); // -> 'After: Love'
  console.log(custom.feeling()); // -> 'Love'
});

stack stack([options])

  1. [options] (Object)
    • [direction = vertical] (String)

      "vertical" or "horizontal"

    • [origin] (String)

      "top", "right", "bottom", or "left" (by default, "top" for "vertical" and "left" for "horizontal")

    • [padding = 0] (Number)

      padding (in px) between elements

    • [min_height = 0] (Number)

      minimum spacing height (for vertical stacking)

    • [min_width = 0] (Number)

      minimum spacing width (for horizontal stacking)

Returns (Function)

Stack given array of elements vertically or horizontally

// Stack all text elements vertically, from the top, with 0px padding
d3.selectAll('text').call(helpers.stack())

// Stack all text elements horizontally, from the right, with 5px padding
d3.selectAll('text').call(helpers.stack({
  direction: 'horizontal',
  origin: 'right',
  padding: 5
}));

translate translate([x], [y])

  1. [x] (Number|Object)

    value or {x, y}

  2. [y] (Number)
Returns (String)

Translate by (x, y) distance

translate(10, 15) == 'translate(10, 15)'
translate({x: 10, y: 15}) == 'translate(10, 15)'

rotate rotate(degrees, [center = {x: 0, y: 0}])

  1. degrees (Number)
  2. [center = {x: 0, y: 0}] (Object)
Returns (String)

Rotate by degrees, with optional center

alignText alignText(element, [line_height])

  1. element (Element)
  2. [line_height] (Number)
Returns (Number)

offset

Find vertical offset to vertically align text (needed due to lack of alignment-baseline support in Firefox)

var label = d3.select('text');

// Place label vertically so that origin is top-left
var offset = alignText(label);
label.attr('transform', translate(0, offset));

// Center label for line-height of 20px
var offset = alignText(label, 20);
label.attr('transform', translate(0, offset));

isSeriesData isSeriesData(data)

  1. data (Array)
Returns (Boolean)

Determine if given data is likely series data

max max(data, getValue)

  1. data (Array)
  2. getValue (Function)

    di function that returns value for given (d, i)

Returns (Number)

Get max for array/series by value di

var data = [
  {values: [{y: 1}, {y: 2}, {y: 3}]},
  {values: [{y: 4}, {y: 2}, {y: 0}]}
];
max(data, function(d, i) { return d.y; }); // -> 4

min min(data, getValue)

  1. data (Array)
  2. getValue (Function)

    di function that returns value for given (d, i)

Returns (Number)

Get min for array/series by value di

var data = [
  {values: [{x: 1}, {x: 2}, {x: 3}]},
  {values: [{x: 4}, {x: 2}, {x: 0}]}
];
min(data, function(d, i) { return d.x; }); // -> 0

getMargins getMargins(margins, default_margins)

  1. margins (Number|Object)
  2. default_margins (Object)
Returns (Object)

Get formatted margins for varying input

getMargins(4);
// -> {top: 4, right: 4, bottom: 4, left: 4}

getMargins({top: 20}, {top: 8, bottom: 8});
// -> {top: 20, right: 0, bottom: 8, left: 0}

di di(callback)

  1. callback (Function)

    with (chart, d, i) arguments

Returns (Function)

Create wrapped (d, i) function that adds chart instance as first argument. Wrapped function uses standard d3 arguments and context.

Note: in order to pass proper context to di-functions called within di-function use .call(this, d, i) (where "this" is d3 context)

d3.chart('Base').extend('Custom', {
  initialize: function() {
    this.base.select('point')
      .attr('cx', this.x);
    // -> (d, i) and "this" used from d3, "chart" injected automatically
  },

  x: di(function(chart, d, i) {
    // "this" is standard d3 context: node
    return chart.xScale()(chart.xValue.call(this, d, i));
  })

  // xScale, xValue...
});

getParentData getParentData(element)

  1. element (Element)
Returns (Any)

Get parent data for element (used to get parent series for data point)

var data = [{
  name: 'Input',
  values: [1, 2, 3]
}];

d3.selectAll('g')
  .data(data)
  .enter().append('g')
    .selectAll('text')
      .data(function(d) { return d.values; })
      .enter().append('text')
        .text(function(d) {
          var series_data = getParentData(this);
          return series_data.name + ': ' + d;
        });

// Input: 1, Input: 2, Input: 3

mixins

mixins.Series

Mixin for handling series data

seriesKey seriesKey(d)

  1. d (Any)

    Series object with key

Returns (Any)

Get key for given series data

seriesValues seriesValues(d)

  1. d (Any)

    Series object with values array

Returns (Array)

Get values for given series data

seriesClass seriesClass(d, i)

  1. d (Any)
  2. i (Number)
Returns (String)

Get class for given series data

seriesIndex seriesIndex(d, i)

  1. d (Any)
  2. i (Number)

Get index for given data-point of series

seriesData

Returns (Any)

Get parent series data for given data-point

itemStyle itemStyle(d, [i], [j])

  1. d (Any)
  2. [i] (Number)
  3. [j] (Number)
Returns (String)

(di) Get style given series data or data-point (Uses "style" object on d, if defined)

seriesCount

Returns (Number)

Get series count for chart

seriesLayer seriesLayer(name, selection, options)

  1. name (String)
  2. selection (Selection)
  3. options (Object)

    (dataBind and insert required)

Returns (d3.chart.layer)

Extension of layer() that handles data-binding and layering for series data.

  • Updates dataBind method to access underlying series values
  • Creates group layer for each series in chart
  • Should be used just like layer()
d3.chart('Chart').extend('Custom', helpers.mixin(mixins.Series, {
  initialize: function() {
    this.seriesLayer('Circles', this.base, {
      // Create group for each series on this.base
      // and calls the following for each series item
      // (entire layer is called twice: series-1 and series-2)

      dataBind: function(data) {
        // 1. data = [1, 2, 3]
        // 2. data = [4, 5, 6]
      },
      insert: function() {
        // Same as chart.layer
        // (where "this" is series group layer)
      },
      events: {
        // Same as chart.layer
      }
    });
  }
}));

// ...

chart.draw([
  {key: 'series-1', values: [1, 2, 3]},
  {key: 'series-2', values: [4, 5, 6]}
]);

mixins.XY

Mixin for handling XY data

xScale {Object|d3.scale}

Get/set x-scale with d3.scale or with object (uses helpers.createScale)

xScale {Object|d3.scale}

Get/set yscale with d3.scale or with object (uses helpers.createScale)

xKey {String} ['x']

Key on data object for x-value

yKey {String} ['y']

Key on data object for y-value

x x(d, i)

  1. d (Any)
  2. i (Number)
Returns (Number)

Get scaled x-value for given data-point

y y(d, i)

  1. d (Any)
  2. i (Number)
Returns (Number)

Get scaled y-value for given data-point

key key(d, i)

  1. d (Any)
  2. i (Number)
Returns (Any)

Get key for data-point. Looks for "key" on d first, otherwise uses x-value.

x0

Returns (Number)

Get scaled x = 0 value

x0

Returns (Number)

Get scaled y = 0 value

xValue xValue(d)

  1. d (Any)
Returns (Any)

Get x-value for data-point. Checks for xKey() on d first, otherwise uses d[0].

xValue({x: 10, y: 20}); // -> 10
xValue([10, 20]); // -> 10

yValue yValue(d)

  1. d (Any)
Returns (Any)

Get y-value for data-point. Checks for yKey() on d first, otherwise uses d[1].

yValue({x: 10, y: 20}); // -> 20
yValue([10, 20]); // -> 20

setScales

Set x- and y-scale ranges (using setXScaleRange and setYScaleRange)

setXScaleRange setXScaleRange(x_scale)

  1. x_scale (d3.scale)

Set range (0, width) for given x-scale

setYScaleRange setYScaleRange(y_scale)

  1. y_scale (d3.scale)

Set range(height, 0) for given y-scale

getDefaultXScale

Returns (d3.scale)

Get default x-scale: {data: this.data(), key: 'x'}

getDefaultYScale

Returns (d3.scale)

Get default y-scale: {data: this.data(), key: 'y'}

mixins.XYValues

Mixin for charts of centered key,value data (x: index, y: value, key)

adjacentWidth

Returns (Number)

Determine width of data-point when displayed adjacent

layeredWidth

Returns (Number)

Determine layered width (width of group for adjacent)

itemWidth

Returns (Number)

Determine item width based on series display type (adjacent or layered)

getDefaultYScale

Returns (d3.scale)

Override default x-scale to use ordinal type: {type: 'ordinal', data: this.data(), key: 'y', centered: true}

mixins.XYInverted

Mixin for inverting XY calculations with x vertical, increasing bottom-to-top and y horizontal, increasing left-to-right

x x(d, i)

  1. d (Any)
  2. i (Number)
Returns (Number)

Get x-value for plotting (scaled y-value)

y y(d, i)

  1. d (Any)
  2. i (Number)
Returns (Number)

Get y-value for plotting (scaled x-value)

x0

Returns (Number)

Get scaled y = 0 value (along x-axis)

x0

Returns (Number)

Get scaled x = 0 value (along y-axis)

setXScaleRange setXScaleRange(x_scale)

  1. x_scale (d3.scale)

Set range (height, 0) for given x-scale

setYScaleRange setYScaleRange(y_scale)

  1. y_scale (d3.scale)

Set range (0, width) for given y-scale

mixins.Labels

Mixin for handling labels in charts

attachLabels

Call during chart initialization to add labels to chart

d3.chart('Chart').extend('Custom', helpers.mixin(Labels, {
  initialize: function() {
    // this.layer()...

    // Attach labels layer
    this.attachLabels();
  }
}));

labels {Object}

Options passed to labels chart

d3.chart('Chart').extend('Custom', helpers.mixin(Labels, {
  // ...
}));

// ...

chart.labels(true); // -> display labels with defaults
chart.labels(false); // -> hide labels
chart.labels({offset: 10}); // -> pass options to labels chart

d3.select('#chart')
  .chart('Compose', function(data) {
    return {
      charts: {
        custom: {labels: {offset: 10}}
      }
    };
  });

mixins.LabelsXY

Mixin for handling labels in XY charts (proxies x and y to properly place labels for XY charts)

Inherits

mixins.Hover

Mixin for handling common hover behavior that adds standard onMouseEnter, onMouseMove, and onMouseLeave handlers and getPoint helper for adding helpful meta information to raw data point.

getPoint getPoint(d, i, j)

  1. d (Any)
  2. i (Number)
  3. j (Number)
Returns (Key, series, d, meta chart, i, j, x, y)

}

Get point information for given data-point

mouseEnterPoint mouseEnterPoint(d, i, j)

  1. d (Any)
  2. i (Number)
  3. j (Number)

Call to trigger mouseenter:point when mouse enters data-point

d3.chart('Chart').extend('Bars', helpers.mixin(Hover, {
  initialize: function() {
    this.layer('bars', this.base, {
      // dataBind...
      insert: function() {
        // Want to trigger enter/leave point
        // when mouse enter/leaves bar (rect)
        var chart = this.chart();
        return this.append('rect')
          .on('mouseenter', chart.mouseEnterPoint)
          .on('mouseleave', chart.mouseLeavePoint);
      }
      // events...
    })
  }
}));

mouseleavePoint mouseleavePoint(d, i, j)

  1. d (Any)
  2. i (Number)
  3. j (Number)

Call to trigger mouseleave:point when mouse leaves data-point

d3.chart('Chart').extend('Bars', helpers.mixin(Hover, {
  initialize: function() {
    this.layer('bars', this.base, {
      // dataBind...
      insert: function() {
        // Want to trigger enter/leave point
        // when mouse enter/leaves bar (rect)
        var chart = this.chart();
        return this.append('rect')
          .on('mouseenter', chart.mouseEnterPoint)
          .on('mouseleave', chart.mouseLeavePoint);
      }
      // events...
    })
  }
}));

onMouseEnter onMouseEnter(position)

  1. position (Object)

    (chart and container {x,y} position of mouse)

    • chart (Object)

      {x, y} position relative to chart origin

    • container (Object)

      {x, y} position relative to container origin

(Override) Called when mouse enters container

onMouseMove onMouseMove(position)

  1. position (Object)

    (chart and container {x,y} position of mouse)

    • chart (Object)

      {x, y} position relative to chart origin

    • container (Object)

      {x, y} position relative to container origin

(Override) Called when mouse moves within container

onMouseLeave

(Override) Called when mouse leaves container

mixins.HoverPoints

Mixin for automatically triggering "mouseenter:point"/"mouseleave:point" for chart data points that are within given hoverTolerance.

hoverTolerance {Number} [Infinity]

Hover tolerance (in px) for calculating close points

mixins.Transition

Mixin for handling common transition behaviors

delay {Number|Function} [(use container value, if available)]

Delay start of transition by specified milliseconds.

duration {Number|Function} [(use container value, if available)]

Transition duration in milliseconds.

ease {String|Function} [(use container value, if available)]

Transition ease function

setupTransition setupTransition(selection)

  1. selection (d3.selection)

Setup delay, duration, and ease for transition

d3.chart('Chart').extend('Custom', helpers.mixin(Transition, {
  initialize: function() {
    this.layer('circles', this.base, {
      // ...
      events: {
        'merge:transition': function() {
          // Set delay, duration, and ease from properties
          this.chart().setupTransition(this);
        }
      }
    });
  }
}));

mixins.StandardLayer

Mixin to create standard layer to make extending charts straightforward.

d3.chart('Chart').extend('Custom', helpers.mixin(StandardLayer, {
  initialize: function() {
    this.standardLayer('main', this.base.append('g'))
    // dataBind, insert, events are defined on prototype
  },

  onDataBind: function(selection, data) {
    // ...
  },
  onInsert: function(selection) {
    // ...
  },
  onEnter: function(selection) {
    // ...
  },
  onUpdateTransition: function(selection) {
    // ...
  },
  // all d3.chart events are available: onMerge, onExit, ...
}));

standardLayer standardLayer(name, selection)

  1. name (String)
  2. selection (d3.selection)

extension of layer() that uses standard methods on prototype for extensibility.

d3.chart('Chart').extend('Custom', helpers.mixin(StandardLayer, {
  initialize: function() {
    this.standardLayer('circles', this.base.append('g'));
  }

  // onDataBind, onInsert, etc. work with "circles" layer
}));

standardSeriesLayer standardSeriesLayer(name, selection)

  1. name (String)
  2. selection (d3.selection)

extension of seriesLayer() that uses standard methods on prototype for extensibility.

d3.chart('Chart').extend('Custom', helpers.mixin(StandardLayer, {
  initialize: function() {
    this.standardSeriesLayer('circles', this.base.append('g'));
  },

  // onDataBind, onInsert, etc. work with "circles" seriesLayer
}));

onDataBind onDataBind(selection, data)

  1. selection (d3.selection)
  2. data (Any)
Returns (d3.selection)

Called for standard layer's dataBind

onInsert onInsert(selection)

  1. selection (d3.selection)
Returns (d3.selection)

Called for standard layer's insert

onEnter onEnter(selection)

  1. selection (d3.selection)

Call for standard layer's events['enter']

onEnterTransition onEnterTransition(selection)

  1. selection (d3.selection)

Call for standard layer's events['enter:transition']

onUpdate onUpdate(selection)

  1. selection (d3.selection)

Call for standard layer's events['update']

onUpdateTransition onUpdateTransition(selection)

  1. selection (d3.selection)

Call for standard layer's events['update']

onMerge onMerge(selection)

  1. selection (d3.selection)

Call for standard layer's events['merge']

onMergeTransition onMergeTransition(selection)

  1. selection (d3.selection)

Call for standard layer's events['merge:transition']

onExit onExit(selection)

  1. selection (d3.selection)

Call for standard layer's events['exit']

onExitTransition onExitTransition(selection)

  1. selection (d3.selection)

Call for standard layer's events['exit:transition']

Change Log

0.15.0

  • Add Gridlines component
  • Update and simplify property
  • Update label positioning
  • Update class system to remove implicit initialize and transform cascade
  • Remove deprecated xy extension and Object-style layout
  • 0.15.1 Fix Overlay.position and labels with stacked bars bugs
  • 0.15.2 Fix Gridlines onExit bug and slide down Bars on exit
  • 0.15.3 Fix layout calculation and axis transition bugs
  • 0.15.4 Fix component centering and mousemove in IE bugs
  • 0.15.5 Fix __proto__ and Overlay transform issues
  • 0.15.6 Fix Legend type not updating bug
  • 0.15.7 Add banner to dist css and tweak label defaults
  • 0.15.8 Fix margins issue for centered components
  • 0.15.9 Fix delayed gridlines attachment bug and fix undefined config issue
  • 0.15.10 Fix legend expanding on redraw issue
  • 0.15.11 Update build (remove grunt), start new draw architecture, convert tests to mocha + jsdom
  • 0.15.12 Include license/version in minified dist
  • 0.15.13 Improve backwards compatibility with new architecture

0.14.0

  • New layout system
  • Remove dependency on Underscore
  • Only set charts and components from options function
  • Convert Compose.charts and Compose.components to arrays
  • Add helpers for charts and components
  • Update mouse listening
  • Update overlay positioning
  • New module system
  • 0.14.1 Fix undefined XYInverted bug
  • 0.14.2 Expose d3c global
  • 0.14.3 Add Text and AxisTitle components, update default margins, add centered component property
  • 0.14.4 Set transitions on Compose, update stack, and add hover listeners to Legend
  • 0.14.5 Disable x0 and y0 position for axes until tested more thoroughly, refactor layout
  • 0.14.6 Fix vertical Axis bug, absolute positioning Compose bug, unknown position bug, and property.previous bug
  • 0.14.7 (Temporarily) Re-instantiate component on position change to avoid nasty side effects

0.13.0

  • Add responsive support for div selections, with width and height used for viewBox
  • Add StandardLayer to improve extensibility in standard charts and components
  • Add Transition mixin for standard approach to adding duration, delay, and ease to charts/layers
  • 0.13.1 Add Overlay component and layer type
  • 0.13.2 Add xKey and yKey to mixins.XY and lots of docs updates
  • 0.13.3 For xy, add given components after generated
  • 0.13.4 Clear unset options on set and fix axis layout issue for inverted
  • 0.13.5 Fix bars axis offset issue
  • 0.13.6 Additional bar offset tweaks

0.12.0

  • Add centered and adjacent options for createScale
  • Move x calculations for Values to createScale
  • Remove LineValues and AxisValues to use scale instead
  • Rename Line to Lines
  • Bugfixes in Legend, Axis, and Multi
  • Refactor Lines chart
  • Add hover to labels
  • Move hover points into separate HoverPoints mixin
  • Refactor mouse events
  • 0.12.1 Complete rename to d3.compose
  • 0.12.2 Move xy to d3.compose namespace
  • 0.12.3 Fix version number
  • 0.12.4 Fix data handling bug in Compose.draw, fix examples, and move stack back to helpers
  • 0.12.5 Handle line-height: normal in alignText
  • 0.12.6 Split merge and layout in labels for better override
  • 0.12.7 Fix cached config bug
  • 0.12.8 Fix improperly updating series class/style bug
  • 0.12.9 Fix Lines indexing bug and set class/style for charts on merge instead of insert
  • 0.12.10 Allow 0/null for transition (delay, duration, ease) values
  • 0.12.11 Use utils instead of underscore
  • 0.12.12 Fix label collisions bug
  • 0.12.13 Add HorizontalBar and HorizontalStackedBars; make Bars, Lines, and Title more extensible; fix undefined data bug; namespace charts
  • 0.12.14 Add horizontal bars swatch to legend

0.11.0

  • New legend data format
  • Fix creating legend from xy extension
  • New registerSwatch method (move method out of charts)
  • More options
  • Split build into three parts: core, core + mixins, core + mixins + charts/components
  • Simplify and cleanup
  • 0.11.1 Labels extension bugfix and Bars offset bugfix

0.10.0

  • Simplify charts and components
  • Simplify draw/redraw
  • Simplify attach/detach
  • Simplify properties
  • Merge Container and Multi
  • Move axes, title, and legend out of Multi and into xy extension
  • Move z-index out of helpers
  • Isolate underscore in utils