D3.js-动态更新折线图中的轴

时间:2014-10-03 17:11:21

标签: javascript jquery d3.js graph data-visualization

我最近开始研究d3.js.我正在尝试开发交互式多线图。请到目前为止查看我的工作:http://jsfiddle.net/dalapati/cdkn14j3/6/

    data1 = [
                    {"date": 1357717800000,"value": "5.6"}, 
                    {"date": 1357718400000,"value": "5.6"}, 
                    {"date": 1357719000000,"value": "6"}, 
                    {"date": 1357719600000,"value": "5.1"},
                    {"date": 1357720200000,"value": "5.3"},
                    // {"date": 1357720800000,"value": "5.4"}
            ];

    data2 = [
                    {"date": 1357714800000,"value": "5.2"},
                    {"date": 1357715400000,"value": "5.2"},
                    {"date": 1357716000000,"value": "5.2"}, 
                    {"date": 1357716600000,"value": "5.1"},
                    {"date": 1357717200000,"value": "5.5"}, 
            ];

// date manipulation to format UTC to js Date obj           
    data1.forEach(function(d){ d.time = new Date(d.time * 1000);});
    data2.forEach(function(d){ d.time = new Date(d.time * 1000);});

// helpers and constants        
var margin = {"top": 50, "right": 50, "bottom": 50, "left": 100, "axis": 55};
var width = 1500 - margin.left - margin.right;
var height = 580 - margin.top - margin.bottom;
var timeFormat = d3.time.format("%X");

// find data range
var findXMin = function(_data){
    return d3.min(_data, function(d){
        return Math.min(d.date);
    });
}

var findXMax = function(_data){
    return d3.max(_data, function(d){ 
        return Math.max(d.date);
    });
}

var findYMin = function(_data){
    return d3.min(_data, function(d){
        return Math.min(d.value);
    });
}

var findYMax = function(_data){
    return d3.max(_data, function(d){
        return Math.max(d.value);
    });
}

var x1Min = findXMin(data1);
var x1Max = findXMax(data1);

var x2Min = findXMin(data2);
var x2Max = findXMax(data2);

var y1Min = findYMin(data1);
var y1Max = findYMax(data1);

var y2Min = findYMin(data2);
var y2Max = findYMax(data2);

var yMin = (y1Min < y2Min) ? y1Min:y2Min;
var yMax = (y1Max > y2Max) ? y1Max:y2Max;

    // scales
var x1Scale = d3.time.scale()
                    .domain([x1Min,x1Max])
                    .range([0, width]);
var x2Scale = d3.time.scale()
                    .domain([x2Min,x2Max])
                    .range([0, width]);
var yScale = d3.scale.linear()
                    .domain([yMin,yMax]).range([height, 0]); 

var renderXAxis = function(scale, className, tickFormat, index0, index1, orient){
    var axis = d3.svg.axis()
                .scale(scale)
                .orient(orient)
                .ticks(5)
                .tickPadding(5)
                .tickFormat(tickFormat);
        svg.append("g")
                .attr("class", className)
                .attr("transform", function() {                        
                        return "translate(" +index0+", " +index1+ ")";})
                .call(axis);
}

var renderYAxis = function(scale, className, tickFormat, index0, index1, orient){
    var axis = d3.svg.axis()
                .scale(scale)
                .orient(orient)
                .ticks(5)
                .tickPadding(5)
                .tickFormat(tickFormat);
        svg.append("g")
                .attr("class", className)
                .attr("transform", function(){                        
                        return "translate(" +index0+", " +index1+ ")";})
                .call(axis);
// grid plot
    svg.append("g")
        .attr("class", "y grid")
        .call(make_y_axis()
        .tickSize(-width, 0, 0)
        .tickFormat(""));                    
}

var make_y_axis = function () {
                            return d3.svg.axis()
                                .scale(yScale)
                                .orient("left")
                                .ticks(5)
                                .tickPadding(5);
                        };    

// Set up chart type
// create a line function that can convert data into x and y points
var line1 = d3.svg.line().interpolate("basis")
                .x(function (d) {
                    return x1Scale(d.date);
                })
                .y(function (d) {
                    return yScale(d.value);
                });
var line2 = d3.svg.line().interpolate("basis")
                .x(function (d) {
                    return x2Scale(d.date);
                })
                .y(function (d) {
                    return yScale(d.value);
                });

//   Create Zoom feature
var zoomBottom = d3.behavior.zoom()
                    .x(x1Scale)
                    .scaleExtent([1,10]);
var zoom = d3.behavior.zoom()
                    .x(x2Scale)
                    .scaleExtent([1,10])
                    .on("zoom",zoomed);


// Create Drag behaviour
var drag = d3.behavior.drag()
            .origin(function(d){
                var t = d3.select(this);
                return {
                    x: t.attr("x"), 
                    y: t.attr("y")
                };
            })
            .on("dragstart", dragstarted)
            .on("drag", dragged)
            .on("dragend", dragended);


// create svg container
var svg = d3.select('#chart')
                .append("svg:svg")
                .attr('width', width + margin.left + margin.right)
                .attr('height', height + margin.top + margin.bottom)
                .append("svg:g")
                .attr("transform", "translate(" + margin.left + "," + margin.top + ")");


var plot =   svg.append("svg:rect")
                .attr("width", width)
                .attr("height", height)
                .attr("class", "plot")
                .call(zoom);

//Draw Axes   
var x1Axis = renderXAxis(x1Scale, "x1Axis", timeFormat, 0, height, "bottom");

var x2Axis = renderXAxis(x2Scale, "x2Axis", timeFormat, 0, 0, "top");

var yAxis = renderYAxis(yScale, "yAxis", function(d){return d;}, 0, 0, "left");

 // add lines
// do this AFTER the axes above so that the line is above the tick-lines
var clip = svg.append("svg:clipPath")
                    .attr("id", "clip")
                    .append("svg:rect")
                    .attr("x1Scale", 0)
                    .attr("x2Scale", 0)
                    .attr("yScale", 0)
                    .attr("width", width)
                    .attr("height", height);

var chartBody = svg.append("g")
        .attr("clip-path", "url(#clip)");

    chartBody.append("svg:path")
        .datum(data1)
        .attr("class", "data1")
        .attr("d", line1(data1))
        .attr("cursor", "move")
        .call(drag);

    chartBody.append("svg:path")
        .datum(data2)
        .attr("class", "data2")
        .attr("d", line2(data2))
        .attr("cursor", "move")
        .call(drag);

/************************** ADDING ZOOMING FEATURE****************************************/

function zoomed() {
        zoomBottom.scale(zoom.scale()).translate(zoom.translate());
        d3.select(".x1Axis").remove();
        renderXAxis(x1Scale, "x1Axis", timeFormat, 0, height, "bottom");
        d3.select(".x2Axis").remove();
        renderXAxis(x2Scale, "x2Axis", timeFormat, 0, 0, "top");
        d3.select(".yAxis").remove();
        renderYAxis(yScale, "yAxis", function(d){return d;}, 0, 0, "left");
        svg.select(".data1").attr("d",line1(data1));
        svg.select(".data2").attr("d",line2(data2));
    }

/***************** Adding Dragging feature*****************************************************/

function dragstarted(d){
    d3.event.sourceEvent.stopPropagation();
    //d3.event.preventDefault();
    //d3.select(this).attr( 'pointer-events', 'none' );
    d3.select(this).classed("dragging", true);
    console.log(d);

}

function dragged(d){
    var lineToMove = d3.event.x;
    d3.select(this)
        .transition()
        .ease("linear")
        .attr("transform", "translate(" +lineToMove+ ",0)");
    d3.select(".x1Axis").remove();
    renderXAxis(x1Scale, "x1Axis", timeFormat, lineToMove, height, "bottom");
    d3.select(".x2Axis").remove();
    renderXAxis(x2Scale, "x2Axis", timeFormat, lineToMove, 0, "top");
    d3.select(".yAxis").remove();
    renderYAxis(yScale, "yAxis", function(d){return d;}, 0, 0, "left");}

function dragended(d){
    d3.select(this).classed("dragging", false);
}

我正在尝试针对每个线图实现拖动行为。我能够实现拖动行为到特定的线图,但是,我不知道如何动态更新其各自的轴。任何人都可以分享你的想法来解决这个问题。 提前谢谢。

1 个答案:

答案 0 :(得分:1)

这是我为解决问题所作的一般性评论:

我不会使用更新功能完全重新渲染每个轴。而是根据需要更新其现有属性并一次绘制轴。

您只需使用axis.scale(scale).tickFormat(tickFormat)等方法即可访问这些内容。这增加了效率。然后你可以做类似的事情:d3.select(".x.axis").transition().duration(1600).call(axis)