d3 / d3-transition

Animated transitions for D3 selections.
https://d3js.org/d3-transition
ISC License
224 stars 65 forks source link

Help Passing down Transitions #52

Closed lukekentwell closed 8 years ago

lukekentwell commented 8 years ago

Hi Mike,

I am attempting to make a simple plugin that renders a column plot using a set of given scales and some data bound to a selection. I am up to the point of getting the columns to animate but cannot get my transition times to work.

I have used your axis as a starting point (for the general pattern) however when the transition for the columns is applied it always has a time of '250'.

This is my first adventure with the new ES6 module approach and I am not sure what im doing wrong.

Any advice would be much appreciated.

Below is the plugin code..

import { getBaseLine } from "./utils/scale";
import { select } from "d3-selection";
/* eslint-disable no-unused-vars */
import transition from "d3-transition"; 
/* eslint-enable no-unused-vars */

export function columnPlot() {
    var categoryScale = null,
        seriesScale = null,
        valueScale = null,
        colorScale = null;

    function columnPlot(context) {
        var selection = context.selection ? context.selection() : context;

        selection.each(function(data) {
            var columns = select(this).selectAll(".column").data(data, function(d) { return d.key; }),
                columnsEnter = columns.enter().append("rect").classed("column", true),
                columnsExit = columns.exit(),
                baseLine = getBaseLine(valueScale);

            // merge entering and existing to reduce update code.
            columns = columns.merge(columnsEnter);

            // wire up transition
            if(context !== selection) {
                columns = columns.transition(context);

                // set initial location of the entering rectangles.
                columnsEnter.attr("x", function(d) {
                    return categoryScale(d.category) + seriesScale(d.series);
                })
                .attr("y", baseLine)
                .attr("width", seriesScale.bandwidth())
                .attr("height", 0)
                .attr("fill", function(d) {
                    return colorScale(d.series);
                });
            }

            columnsExit.remove();

            // set rectangle attributes
            columns.attr("x", function(d) {
                return categoryScale(d.category) + seriesScale(d.series);
            })
            .attr("y", function(d) {
                if(d.value < 0) {
                    return baseLine;
                }

                return valueScale(d.value);
            })
            .attr("width", seriesScale.bandwidth())
            .attr("height", function(d) {
                return Math.abs(baseLine - valueScale(d.value));
            })      
            .attr("fill", function(d) {
                return colorScale(d.series);
            });
        });

    }

// Properties
columnPlot.categoryScale = function(value) {
    return arguments.length ? (categoryScale = value, columnPlot) : categoryScale;
};

columnPlot.seriesScale = function(value) {
    return arguments.length ? (seriesScale = value, columnPlot) : seriesScale;
};

columnPlot.valueScale = function(value) {
    return arguments.length ? (valueScale = value, columnPlot) : valueScale;
};

columnPlot.colorScale = function(value) {
    return arguments.length ? (colorScale = value, columnPlot) : colorScale;
};

return columnPlot;
}

code thats calling this..

d3.select("#test-group-plots").datum(data).transition().duration(5000).call(columnPlot);
mbostock commented 8 years ago

I’m not sure what’s going wrong here. It’s hard to tell just from looking at a snippet rather than being able to run a live example, but then, I probably don’t have time to debug a large amount of code anyway. (Sorry.) I see two things that are suspicious:

  1. Your import from d3-transition is invalid because d3-transition has no default export. If you just want to import d3-transition to define selection.transition (i.e., to import with side-effects) then you can say import "d3-transition";. If you want to import a specific symbol from d3-transition for use, such as d3.transition, then you should say import {transition} from "d3-transition";.
  2. You’ve nested your code in a call to selection.each so that it runs separately for each selected element. This is probably okay, but it’s preferable to avoid such iteration if possible, since usually it’s more efficient and slightly simpler if you can write your code without it. (d3-axis does not use selection.each; see axis.js

Here’s a trivial example I just made so you can see a minimal example of how to implement a transitionable component:

http://bl.ocks.org/mbostock/b6fbf8119a10bb8cc3fa730e61d27240

If you’re able to reduce this down to something smaller that I can run in my browser, I’d be happy to take another look.