递归函数和此D3.JS

时间:2018-10-19 11:38:19

标签: javascript d3.js recursion

我的point={x,y,nextPoint}点数组。目的是在每个点之间画一条线并在其上移动一个圆。数组中最后一个点的nextPoint为空。

我可以通过在该点调用[number of points]-1方法来移动圆。那一点都不灵活,我想递归地做。我正在创建一个这样的圆圈:

function addCercle() {
  var ret = svg.append("circle") //svg is declared before
    .attr("cx", points[0].x) // points = the array of points
    .attr("cy", points[0].y)
    .attr("r", "3%");
  return ret;
}

不起作用的功能是这样的:

function move(p) {
  for (var i = 0; i < points.length-1; i++) {
    p = d3.select(this)
      .transition()
      .duration(speed) //
      .attr("cx", points[i].x)
      .attr("cy", points[i].y);
  }
}

我想这样称呼它,使圆在所有直线上运行:

var test = addCercle();
console.log(test);
move(test);

有人可以向我解释一下我的功能变动时需要做什么吗?还是在通话中?

1 个答案:

答案 0 :(得分:1)

如果要使move函数具有递归性,则需要从内部调用它。与往常一样,有很多方法可以执行此操作,但是如果您有一个点数组,则可以传递点数组或传递点数组中的当前位置。这是一个传递点数组的示例:

// p is the element being moved, points is the array of points
function move(p, points) {
  if (points.length > 0) { // one point or more in the array => move the element
    p.transition()
      .duration(speed) //
      .attr("cx", points[0].x)
      .attr("cy", points[0].y)
      // when the transition ends, call this function with the array of points minus the first point
      .on('end', () => move(p, points.slice(1)));
  }
}

const arrayOfPoints = [{x: 100, y: 200},{x: 200, y: 200}, {x: 300, y: 300}]
// call the function
move(circle, arrayOfPoints);

工作示例,其中我生成了一个点数组,然后沿着这些点所描述的路径移动了一个圆:

var svg = d3.select('svg'),
radius = 100,
pts = d3.range(0, 2 * Math.PI, 0.01 * Math.PI) // NOTE: this produces an array
        .map( d => d3.pointRadial(d, radius) ),// of arrays; slightly different
                                               // to your data structure
speed = 50

function addCercle(points) {
  var ret = svg
    .append('g')
    .attr('transform', 'translate(150,150)')
    .append("circle") //svg is declared before
    .attr("cx", points[0][0]) // points = the array of points
    .attr("cy", points[0][1])
    .attr("r", "3%");
  return ret;
}

function move(p, points) {
  if (points.length > 0) {
    p.transition()
      .duration(speed) //
      .attr("cx", points[0][0])
      .attr("cy", points[0][1])
      .on('end', () => move(p, points.slice(1)));
  }
}

var test = addCercle(pts);
move(test, pts);
<script type="text/javascript" src="http://d3js.org/d3.v5.js"></script>
<svg width="960" height="960"></svg>

您可以通过补间过渡来产生更平滑的路径和动画。

这是一个稍作改动的示例,该示例遵循相同的原理,但使用的是您在问题中描述的数据结构;唯一改变的是该函数设置cxcy值的方式,以及如何确定是否要显示更多点。

var svg = d3.select('svg'),
radius = 300,
pts = d3.range(0, 2 * Math.PI, 0.01 * Math.PI).map( d => d3.pointRadial(d, radius) ),
speed = 50

function makeWeirdDataStructure ( pts ) {
  return {
    x: pts[0][0],
    y: pts[0][1],
    nextPt: pts.length > 1 ? makeWeirdDataStructure( pts.slice(1) ) : null
  }
}

function addCercle(points) {
  var ret = svg
    .append('g')
    .attr('transform', 'translate(400,400)')
    .append("circle") //svg is declared before
    .attr("cx", points.x) // points = the array of points
    .attr("cy", points.y)
    .attr("r", "3%");
  return ret;
}

function move(p, points) {
  if ( points !== null ) {
    p.transition()
      .duration(speed) //
      .attr("cx", points.x)
      .attr("cy", points.y)
      .on('end', () => move(p, points.nextPt));
  }
}

var wds = makeWeirdDataStructure(pts)
var test = addCercle(wds);
move(test, wds);
<script type="text/javascript" src="http://d3js.org/d3.v5.js"></script>
<svg width="960" height="960"></svg>