2014-10-03 71 views
0

我最近開始研究d3.js.我正在嘗試開發一個交互式多線圖。請看看我的工作至今:http://jsfiddle.net/dalapati/cdkn14j3/6/D3.js-動態更新線圖中的軸

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); 
} 

我試圖實現相對於它的軸拖動行爲各線圖。我可以實現拖動行爲到一個特定的線圖,但是,我不知道如何動態更新其各自的軸。任何人都可以請分享你的想法來解決這個問題。 預先感謝您。

+0

作爲一般性評論,我不會用更新函數完全重新渲染每個軸。相反,根據需要更新其現有屬性並一次繪製軸。您可以通過使用像axis.scale(scale).tickFormat(tickFormat)這樣的方法來訪問它們。這增加了效率。然後,您可以執行如下操作:d3.select(「。x.axis」)。transition()。duration(1600).call(xAxis) – 2014-10-03 18:57:25

+0

嗨,感謝您的回覆。你給出的想法很好。但我在這裏看到了一個錯誤。最初,當我拖動一個特定的圖形時,它可以通過更新其各自的軸來正常工作。稍後當我在整個繪圖上應用變焦時,軸會重置回原來的位置。這裏是更新的Jsfiddle:http://jsfiddle.net/dalapati/cdkn14j3/8/ – Dinesh 2014-10-03 20:12:04

+0

我會爲這個問題開一個新的問題。我不知道這個問題。 – 2014-10-03 20:14:42

回答

1

這是我給瞭解決問題的一般性評論:

我不會完全重新渲染與更新功能各軸。相反,根據需要更新其現有屬性並一次繪製軸。

只需使用像axis.scale(scale).tickFormat(tickFormat)這樣的方法即可訪問這些文件。這增加了效率。然後你可以這樣做:d3.select(".x.axis").transition().duration(1600).call(axis)