4

Here's what I have:

http://jsfiddle.net/bozdoz/Q6A3L/

rickshaw d3.js graph

Code for the background bars:

maxData = 80000000;
maxHeight = 250;
var yScale = d3.scale.linear().
  domain([0, maxData]). // your data minimum and maximum
  range([0, maxHeight]); // the pixels to map to, e.g., the height of the diagram.

var riskpoints = [62000000,48000000,30000000];
var rectDemo = d3.select("#chart").
    append("svg:svg").
    attr("width", 400).
    attr("height", maxHeight).
    attr('class','risk');

rectDemo.append("svg:rect").
    attr("x",0).
    attr("y", maxHeight - yScale(riskpoints[0])).
    attr("height", yScale(riskpoints[0]) - yScale(riskpoints[1])).
    attr("width", '100%').
    attr("fill", "rgba(0,100,0,.3)");

rectDemo.append("svg:rect").
    attr("x",0).
    attr("y", maxHeight - yScale(riskpoints[1])).
    attr("height", yScale(riskpoints[1]) - yScale(riskpoints[2])).
    attr("width", '100%').
    attr("fill", "rgba(100,100,0,.3)");

rectDemo.append("svg:rect").
    attr("x",0).
    attr("y", maxHeight - yScale(riskpoints[2])).
    attr("height", yScale(riskpoints[2])).
    attr("width", '100%').
    attr("fill", "rgba(100,0,0,.3)");

This is exactly what I want, except that I have made the red, yellow, green background bars a fixed height.

When you use the slider, or, more importantly, when the graph is regenerated (which it will with the actual data), I want the background bars to adjust to the correct height.

For example, in the image, the green bar is somewhere between 300M and 200M. If you remove all the graph data except for the red (vertical) bars, the green bar (horizontal) is just above 40M. This is because the position/height of the background bars are not regenerated, whereas the position/height of the graph data are regenerated, via the rickshaw javascript.

How could I put this data into the rickshaw graph so that it is regenerated?

4

2 回答 2

3

The solution is to setup update function to calculate new heights of the background bars, to get displayed bars you can use graph.series.active(); you also may like to keep vars in same scope....

so the solution itself:

var maxHeight;
var background_update = function(graph) {
    //skip 1st time;
    if (maxHeight === undefined) {return;}
    var series=graph.series.active();
    maxHeight=yScale(get_maximum_all(series));
    //console.log(maxHeight);
    var red_riskpoint=get_maximum("y",series[0]);
    var yellow_riskpoint=get_maximum("y",series[1]);
    var green_riskpoint=get_maximum("y",series[2]);
    //console.log(graph.series.active());
    console.log(yScale(red_riskpoint),yScale(yellow_riskpoint),yScale(green_riskpoint));
    
   // return;
    
    b_red.attr("y", maxHeight - yScale(red_riskpoint)).attr("height", yScale(red_riskpoint));
    b_yellow.attr("y", maxHeight - yScale(yellow_riskpoint)).attr("height", Math.abs(yScale(yellow_riskpoint) - yScale(red_riskpoint)));
    b_green.attr("y", maxHeight - yScale(green_riskpoint)).attr("height", Math.abs(yScale(green_riskpoint) - yScale(yellow_riskpoint)));
    console.log(maxHeight-yScale(green_riskpoint));
};
var get_maximum_all=function(series) {
    var max=0;
    for (var i in series) {
        var stack=series[i].stack;
        for (n in stack) {
            if (stack[n].y>max) {max=stack[n].y;}
            if (stack[n].y0>max) {max=stack[n].y0;}
        }
    }
    return max;
}
    var get_maximum=function(tag,object){
    var max=0;
    for (var i in object.stack) {
        if (object.stack[i][tag]>max) {max=object.stack[i][tag];}
    }
return max;
    }
Rickshaw.Graph.RangeSlider = function(args) {

    var element = this.element = args.element;
    var graph = this.graph = args.graph;


    $(element).slider({

        range: true,
        min: graph.dataDomain()[0],
        max: graph.dataDomain()[1],
        values: [
            graph.dataDomain()[0],
            graph.dataDomain()[1]
            ],
        slide: function(event, ui) {

            graph.window.xMin = ui.values[0];
            graph.window.xMax = ui.values[1];
            graph.update();

            // if we're at an extreme, stick there
            if (graph.dataDomain()[0] == ui.values[0]) {
                graph.window.xMin = undefined;
            }
            if (graph.dataDomain()[1] == ui.values[1]) {
                graph.window.xMax = undefined;
            }
        }
    });


    element.style.width = graph.width + 'px';

    graph.onUpdate(function() {

        var values = $(element).slider('option', 'values');

        $(element).slider('option', 'min', graph.dataDomain()[0]);
        $(element).slider('option', 'max', graph.dataDomain()[1]);

        if (graph.window.xMin == undefined) {
            values[0] = graph.dataDomain()[0];
        }
        if (graph.window.xMax == undefined) {
            values[1] = graph.dataDomain()[1];
        }

        $(element).slider('option', 'values', values);
        background_update(graph);
    });
}

other code is almost same you placed to fiddle,

my fiddle here

please note, that i not sure how calculate riskpoints, i just tried to get a maximums. I sure you can make riskpoint calculations from viewing the console.log(series)

b_red,b_green,b_yellow it is d3 selections of initialised background bars.

于 2012-11-15T00:50:11.500 回答
1

I found somewhat of a solution, with the help of @eicto's answer.

var maxHeight = 250;
var theSVG = d3.select("#chart svg");

//from @eicto: get the maximum value on the current chart
function get_maximum_all(series) { 
    var max=0;
    for (var i in series) {
        var stack=series[i].stack;
        for (n in stack) {
            if (stack[n].y>max) {max=stack[n].y;}
            if (stack[n].y0>max) {max=stack[n].y0;}
        }
    }
    return parseInt(max);
}

//create a function to call on graph update event
function createRiskPoints(riskpoints){
//these variables need to change on each graph update
   var series = graph.series.active();
//this variable should be get_max_y_axis, but I don't know how to do that
   var maxData = get_maximum_all(series);
   var yScale = d3.scale.linear().
  domain([0, maxData]).
  range([0, maxHeight]);

//using dummy values for now
   var riskpoints = (riskpoints) ? riskpoints : [300000000,200000000,100000000];

//insert the bars so they go behind the data values
theSVG.insert("svg:rect", ":first-child").
    attr("x",0).
    attr("y", maxHeight - yScale(riskpoints[0])).
    attr("height", yScale(riskpoints[0]) - yScale(riskpoints[1])).
    attr("width", '100%').
    attr("fill", "rgba(0,100,0,.2)");

theSVG.insert("svg:rect", ":first-child").
    attr("x",0).
    attr("y", maxHeight - yScale(riskpoints[1])).
    attr("height", yScale(riskpoints[1]) - yScale(riskpoints[2])).
    attr("width", '100%').
    attr("fill", "rgba(100,100,0,.2)");

theSVG.insert("svg:rect", ":first-child").
    attr("x",0).
    attr("y", maxHeight - yScale(riskpoints[2])).
    attr("height", yScale(riskpoints[2])).
    attr("width", '100%').
    attr("fill", "rgba(100,0,0,.2)");
}
//call the function
   createRiskPoints();
//call the function on graph update: thanks to @eicto
   graph.onUpdate( createRiskPoints );​

Now the bars change when the graph changes; however, they are not to scale. This will be my next task.

http://jsfiddle.net/bozdoz/Q6A3L/

于 2012-11-15T21:49:48.317 回答