d3.js中的动态svg路径

时间:2014-07-17 07:10:20

标签: javascript d3.js turtle-graphics

我正在研究乌龟图形的d3.js实现。基本上,当我们给出绘制或移动的龟指令时,它会将这些指令转换为svg路径对象可接受的形式,以便它的" d"属性。

我希望用户能够提供乌龟指令(在javascript控制台或最终使用按钮),并让svg画布上的路径动态更新。现在我可以做到这一点,但transition()还没有成功。即无论我为转换设置duration(),它都会立即更新。也许这与我没有将指令作为数据绑定到路径元素这一事实有关?

我有一个Turtle构造函数和一个Vector2D构造函数,定义如下:

<body>
<script src="path_to_D3"></script>
<script>

var svg = d3.select("body").append("svg").attr("width", 800).attr("height", 800);

var xScale = d3.scale.linear().domain(-1000, 1000).range(0, 800)
var yScale = d3.scale.linear().domain(-1000, 1000).range(0, 800)

// Here's where I am having an issue with binding data. 

var path = svg.append("path").attr("stroke", "red").attr("fill", "none");

// Proposed alternative: var path = d3.select(".turtlePath").data("");
//                           path.enter().append("path").attr("class", "turtlePath")
//                             .attr("d", function(d) { return d; });
//           

function Vector2D(x, y) {
  this.x = x
  this.y = y

  this.add = function(other) {
    return new Vector2D(x + other.x, y + other.y)
  }

  this.scaleBy(factor) {
    return new Vector2D(x * factor, y * factor)
  }
}


functionTurtle() {
  var position = new Vector2D(0, 0)
  var angle = 0;
  var pathInstruct = “M” + x(0) + “, “ + y(0) + “ “;
  var moveDist = 100;
  this.penDown = false;



  this.goForward = function() {
    var xAdd = Math.cos(angle);
    var yAdd = Math.sin(angle);
    position = position.add(new Vector2D(xAdd, yAdd).scaleBy(moveDist));

    // Here is the crucial bit. 
    var newInstruct = "";
    if (penDown) {
      newInstruct = "L" + x(position.x) + ", " + y(position.y) + " ";
    } else {
      newInstruct = "m" + x(position.x) + ", " + y(position.y) + " ";
    }
    pathInstruct += newInstruct;

    // Here's where I'd like the transition to occur. 
    path.attr("d", pathInstruct);
    // Proposed: path.data(pathInstruct).transition().duration(500)
    //               .attr("d", function(d) { return d; });
  }

}   
</script>
</body>

然后我可以给出海龟命令并将它们显示在画布上:

var t = new Turtle()
t.penDown = true;
t.goForward();
t.goForward();
t.penDown = false;

乌龟的这些命令产生一条简单的水平线。但我喜欢动态更新的路径,而不是像Mike Bostock的post那样即时更新。我是否需要将路径指令作为数据绑定到路径元素?

1 个答案:

答案 0 :(得分:0)

错误与转换无关 - 它是由初始化和更新步骤中.data()调用引起的。

传递给.data() 的参数必须是一个数据值数组,即使您只有一个元素,因此只有一个数据值。 / p>

要解决此问题,您有两种选择:

  1. 通过在调用方法时将数据值包装在括号中来创建一个ad-hoc数组:

    path.data([pathInstruct]).transition().duration(500)
              .attr("d", function(d) { return d; });
    
  2. 使用.datum()方法,该方法接受单个数据值并将其附加到选择中的每个元素:

    path.datum(pathInstruct).transition().duration(500)
              .attr("d", function(d) { return d; });
    
  3. 请注意,.datum()方法不会创建enter()exit()选项;在使用.datum()设置数据之前,您必须先创建路径元素。