Search code examples
javascriptd3.jsdc.jscrossfilter

How to rescale x axis using the crossfilter?


First, sorry for my English.

I'm learning dc.js.

I have 3 charts(1 composite chart, 1 line chart and 1 bar chart).

When I control the brush of the bar chart, I want to rescale the X axis of the other 2 charts.

Use event trigger?

Image here

var temperatureChart;
var windSpeedChart;
var dateChart;

var init = function() {
temperatureChart = dc.compositeChart("#temperature-chart");
windSpeedChart = dc.lineChart("#windspeed-chart");
dateChart = dc.barChart("#date-chart");

d3.json(jsonUrl, function(error, result) {
    var dateFormat = d3.time.format("%Y-%m-%d %H:%M");
    var numberFormat = d3.format(".2f");
    var data = result.result.data[0];

    data.forEach(function(e) {
        e.observeDate = dateFormat.parse(e.observeDate);
    });

    var ndx = crossfilter(data),
    all = ndx.groupAll();
    dimension1 = ndx.dimension(function(d) {return d.observeDate;}),
    dimension2 = ndx.dimension(function(d) {return d.observeDate;}),
    dimension3 = ndx.dimension(function(d) {return d.observeDate;}),
    temperatureGroup = dimension1.group().reduceSum(function(d) {return d.temperature;}),
    windSpeedGroup = dimension2.group().reduceSum(function(d) {return d.windSpeed;}),
    dateGroup = dimension3.group();

    var scaleMin = d3.min(data, function(d){
        return d.observeDate;
    });
    var scaleMax = d3.max(data, function(d){
        return d.observeDate;
    });

    var width = 1000, height = 300;
    var margin = {top: 30, right: 50, bottom: 25, left: 40};

    temperatureChart
    .width(width)
    .height(height)
    .transitionDuration(1000)
    .margins(margin)
    .dimension(dimension1)
    .xUnits(d3.time.hours)
    .elasticY(true)
    .elasticX(true)
    .mouseZoomable(true)
    .renderHorizontalGridLines(true)
    .x(d3.time.scale().domain([scaleMin, scaleMax]))
    .brushOn(false)
    .renderlet(function(c) {
        var canvas = (c.g()).append("g").attr("transform", "translate("+margin.left+","+margin.top+")").attr("pointer-events", "all");
        var crossHair = canvas.append("g").attr("class", "crosshair");

        crossHair.append("line").attr("id", "h_crosshair")
            .attr("x1", 0)
            .attr("y1", 0)
            .attr("x2", 0)
            .attr("y2", 0)
            .style("stroke", "gray")
            .style("stroke-width", "1px")
            .style("stroke-dasharray", "5,5")
            .style("display", "none");

        crossHair.append("line").attr("id", "v_crosshair")
            .attr("x1", 0)
            .attr("y1", 0)
            .attr("x2", 0)
            .attr("y2", 0)
            .style("stroke", "gray")
            .style("stroke-width", "1px")
            .style("stroke-dasharray", "5,5")
            .style("display", "none");

        crossHair.append("text").attr("id", "crosshair_text")
            .style("font-size", "10px")
            .style("stroke", "gray")
            .style("stroke-width", "0.5px");

        canvas.on("mousemove", function() {
            addCrossHair(d3.mouse(this)[0], d3.mouse(this)[1]);
        }).on("mouseover", function() {
            d3.selectAll("#v_crosshair").style("display", "block");
            c.selectAll("#h_crosshair").style("display", "block");
        }).on("mouseout", function() {
            d3.selectAll("#v_crosshair").style("display", "none");
            c.selectAll("#h_crosshair").style("display", "none");
        }).append("rect")
          .style("visibility", "hidden")
          .attr("x", 0)
          .attr("y", 0)
          .attr("width", width - margin.left - margin.right)
          .attr("height", height - margin.top - margin.bottom);

        function addCrossHair(x, y) {
            c.selectAll("#h_crosshair")
                .attr("x1", 0)
                .attr("y1", y)
                .attr("x2", c.xAxisLength())
                .attr("y2", y)
                .style("display", "block");

            d3.selectAll("#v_crosshair")
                .attr("x1", x)
                .attr("y1", 0)
                .attr("x2", x)
                .attr("y2", c.yAxisHeight())
                .style("display", "block");

        }
    })
    .compose([
        dc.lineChart(temperatureChart)
                .dotRadius(5)
                .group(temperatureGroup)
    ]);

    windSpeedChart
    .width(width)
    .height(height)
    .transitionDuration(1000)
    .margins(margin)
    .dimension(dimension2)
    .xUnits(d3.time.hours)
    .elasticY(true)
    .elasticX(true)
    .mouseZoomable(true)
    .renderHorizontalGridLines(true)
    .x(d3.time.scale().domain([scaleMin, scaleMax]))
    .brushOn(false)
    .group(windSpeedGroup)
    .renderlet(function(c) {
        var canvas = (c.g()).append("g").attr("transform", "translate("+margin.left+","+margin.top+")").attr("pointer-events", "all");
        var crossHair = canvas.append("g").attr("class", "crosshair");

        crossHair.append("line").attr("id", "h_crosshair")
            .attr("x1", 0)
            .attr("y1", 0)
            .attr("x2", 0)
            .attr("y2", 0)
            .style("stroke", "gray")
            .style("stroke-width", "1px")
            .style("stroke-dasharray", "5,5")
            .style("display", "none");

        crossHair.append("line").attr("id", "v_crosshair")
            .attr("x1", 0)
            .attr("y1", 0)
            .attr("x2", 0)
            .attr("y2", 0)
            .style("stroke", "gray")
            .style("stroke-width", "1px")
            .style("stroke-dasharray", "5,5")
            .style("display", "none");

        crossHair.append("text").attr("id", "crosshair_text")
            .style("font-size", "10px")
            .style("stroke", "gray")
            .style("stroke-width", "0.5px");

        var bisectDate = d3.bisector(function(d) {
            return d.observeDate;
        }).right;

        canvas.on("mousemove", function() {
            addCrossHair(d3.mouse(this)[0], d3.mouse(this)[1]);
        }).on("mouseover", function() {
            d3.selectAll("#v_crosshair").style("display", "block");
            c.selectAll("#h_crosshair").style("display", "block");
        }).on("mouseout", function() {
            d3.selectAll("#v_crosshair").style("display", "none");
            c.selectAll("#h_crosshair").style("display", "none");
        }).append("rect")
          .style("visibility", "hidden")
          .attr("x", 0)
          .attr("y", 0)
          .attr("width", width - margin.left - margin.right)
          .attr("height", height - margin.top - margin.bottom);

        c.xAxis().scale();

        function addCrossHair(x, y) {
            c.select("#h_crosshair")
                .attr("x1", 0)
                .attr("y1", y)
                .attr("x2", c.xAxisLength())
                .attr("y2", y)
                .style("display", "block");

            d3.selectAll("#v_crosshair")
                .attr("x1", x)
                .attr("y1", 0)
                .attr("x2", x)
                .attr("y2", c.yAxisHeight())
                .style("display", "block");

        }
    });

    dateChart
     .width(width)
     .height(50)
     .margins({top: 0, right: 50, bottom: 20, left: 40})
     .xUnits(d3.time.hours)
     .x(d3.time.scale().domain([scaleMin, scaleMax]))
     .centerBar(true)
     .brushOn(true)
     .dimension(dimension3)
     .group(dateGroup).yAxis().ticks(0);

    dateChart.on("filtered", function(c) {
        if(c.filter())
            dc.events.trigger(function() {
                        // Any code here?
            });
    });
    dc.renderAll(); 
});

Solution

  • Do you mean the "range / focus chart" functionality that can be seen in the last "monthly abs volume & move" chart on the main dc.js page?

    If so, here is the documentation: https://github.com/dc-js/dc.js/blob/develop/web/docs/api-latest.md#dc.coordinateGridMixin+rangeChart

    It is a very simple feature and not fully documented, so please ask if you have any questions.

    EDIT: noticed that you are talking about multiple "focus charts" for one "range chart". That's not built-in, but it's covered in this Q/A: https://stackoverflow.com/a/27725811/676195