2014-03-24 81 views
17

我想從官方文檔中應用"general update pattern"更新鼠標事件(但可能是按鈕或其他)的svg路徑。如何使用d3.js更新svg路徑

但是路徑只能被添加和不更新。我想這就是爲什麼我沒有正確使用enterexit財產,但經過一些各種試驗後,我無法讓它工作。

這是一個jsfiddle

我的js代碼是在這裏:

var shapeCoords = [ 
        [10, 10], [100, 10], [100, 100], [10, 100]     
        ]; 

$(function() { 
    var container = $('#container'); 

    // D3 
    console.log("D3: ", d3); 

    var svg = d3.select('#container') 
       .append('svg:svg') 
       .attr('height', 600) 
       .attr('width', 800); 

    var line = d3.svg.line() 
        .x(function(d) { return d[0]; }) 
        .y(function(d) { return d[1]; }) 
        .interpolate('linear'); 

    function render() { 

      svg.data(shapeCoords) 
       .append('svg:path') 
       .attr('d', line(shapeCoords) + 'Z') 
       .style('stroke-width', 1) 
       .style('stroke', 'steelblue'); 
    } 
    render(); 

    var mouseIsDown = false; 
    container.on('mousedown mouseup mousemove', function(e) { 
     if (e.type == 'mousedown') { 
      mouseIsDown = true; 
      shapeCoords[3] = [e.offsetX, e.offsetY]; 
     } else if (e.type == 'mouseup'){ 
      mouseIsDown = false; 
      shapeCoords[3] = [e.offsetX, e.offsetY]; 
     } else if (e.type == 'mousemove') { 
      if (mouseIsDown) { 
       shapeCoords[3] = [e.offsetX, e.offsetY]; 
       render(); 
      } 
     } 
    }); 


}); 

和HTML:

<!DOCTYPE html> 
<html> 
<head> 
    <title>D3 mousemove</title> 
    <script type="text/javascript" 
      src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"> 
    </script> 
    <script type="text/javascript" 
      src="http://mbostock.github.com/d3/d3.js"> 
    </script> 
    <script type="text/javascript" src="script.js"></script> 
    <style> 
     #container { 
      width: 800px; 
      height: 600px; 
      border: 1px solid silver; } 
     path, line { 
      stroke: steelblue; 
      stroke-width: 1; 
      fill: none; 
     } 
    </style> 
</head> 
<body> 
    <div id="container"></div> 
</body> 
</html> 

回答

14

你的代碼不選擇現有的元素,所以不是更新現有的 「d」 屬性通過update選擇路徑,它每次都附加一條新路徑。此版本的render()產生了預期的行爲。更多關於選擇here

function render() { 
    path = svg.selectAll('path').data([shapeCoords]) 
    path.attr('d', function(d){return line(d) + 'Z'}) 
     .style('stroke-width', 1) 
     .style('stroke', 'steelblue'); 
    path.enter().append('svg:path').attr('d', function(d){return line(d) + 'Z'}) 
     .style('stroke-width', 1) 
     .style('stroke', 'steelblue'); 
    path.exit().remove() 

一旦運行數據通過.data()path加入,操作上path執行只適用於更新選擇。意思是,只有那些在新連接下仍然具有相應數據元素的現有元素。當您調用enter().append()時,它會爲每個數據元添加一個新元素,而不存在預先存在的元素,然後僅將以下操作應用於這些元素。上面的第一個path.attr()只對現有元素有效;在path.enter()之後應用的那些僅適用於新元素。它不在上面的代碼片段中,但enter()將回車選擇添加到更新選擇中:調用enter()path上的任何操作都將應用於現有元素和新元素。

+0

你爲什麼要重複'attr('d')'? – nkint

+0

我的意思是,你爲什麼首先改變路徑上「d」的'attr',然後通過'enter()。append()'增加更多的「d」? – nkint

+1

第一個'attr(「d」)'只適用於已存在的元素,隨後的'attr(「d」)'爲新元素添加一個'd'屬性。 (上面添加了完整的解釋。)乾杯! –

4

請嘗試下面的代碼,我認爲這是你想要的。問題是由於您要更新元素時​​應區分輸入,更新和退出而引起的,否則會一次又一次地添加數據。

$(function() { 
var container = $('#container'); 

// D3 
console.log("D3: ", d3); 

var svg = d3.select('#container') 
      .append('svg:svg') 
      .attr('height', 600) 
      .attr('width', 800); 

var line = d3.svg.line() 
       .x(function(d) { return d[0]; }) 
       .y(function(d) { return d[1]; }) 
       .interpolate('linear'); 

svg.data(shapeCoords) 
    .append('svg:path') 
    .attr('d', line(shapeCoords) + 'Z') 
    .style('stroke-width', 1) 
    .style('stroke', 'steelblue'); 

function render() { 

    var svg = d3.select('#container').select("svg").selectAll('path').data(shapeCoords); 
    svg.enter().append('svg:path') 
      .attr('d', line(shapeCoords) + 'Z') 
      .style('stroke-width', 1) 
      .style('stroke', 'steelblue'); 
    svg.attr('d', line(shapeCoords) + 'Z') 
      .style('stroke-width', 1) 
      .style('stroke', 'steelblue');  
    svg.exit().remove();  

} 
render(); 
+0

對不起爲什麼你綁定數據3次? – nkint

+0

@nkint我只是想顯示結果,並不在乎這一點。當然不需要這樣做3次,我重新編輯它,謝謝。 – linpingta