跟踪路径与DOM对象 [英] Trace path with DOM object

查看:153
本文介绍了跟踪路径与DOM对象的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我是javascript和d3js的新手。我想一个DOM对象跟踪由参数化曲线(x(t),y(t))指定的路径。下面是这种参数化的一个例子:

I'm new to javascript and d3js. I would like a DOM object to trace out a path specified by a parametrized curve (x(t),y(t)). Here is an example of such a parametrization:

var theta = [];
        for(var i = 0; i <= N; i++){
        theta.push(2*Math.PI*i/N);
    }
var points = [];
    for(var i = 0; i <= N; i++){
        points.push([Math.cos(theta[i]),Math.sin(theta[i])]);
    }

上面是曲线的参数化 - 在这种情况下,圆 - 我想我的DOM对象遵循这条曲线的轨迹。 [Aside:是否有更好的方法来定义 points ?运行一个for循环似乎是可笑的。]

The above is the parametrization of a curve -- in this case, also a circle -- and I would like my DOM object to follow the trajectory of this curve. [Aside: is there any better way to define points? It seems ridiculous to run a for loop.]

一个粗略的方式来实现我想找的是在update()运行一个for循环, d3的一部分。首先,我只是在svg变量中添加一个圆,这样它就不需要链接到任何数据。然后选择和更新,无需进入/退出。

A crude way to achieve the sort of effect I'm looking for is to run a for loop in the update() part of d3. First, I simply append a circle to the svg variable, so that it need not be linked to any data. It is then selected and updated without required enter/exit.

        for (var i = 0; i <= N; i++){
        svg.selectAll("circle")
                .transition()
                .attr("cx",points[i][0]+w/2) // w: width
                .attr("cy",points[i][1]+h/2) // h: height
                .duration(dt) // 
                .delay(dt*i);
            }

[Aside:我听说过queue以计算总延迟。评论?]然而,过渡的缓和属性使它运行在一个波纹的方式。我想我可以指定没有缓解,但我确信必须有一个更好的方式来实现我想要的,这是简单的初始DOM对象(圆)沿着一个特定的轨迹平稳地移动。

[Aside: I've heard queue() would be better, as opposed to calculating the total delay. Comments?] However, the easing property of the transition makes it run in a choppy fashion. I imagine I could specify no easing, but I'm sure there must be a better way to achieve what I want, which is simply for the initial DOM object (the circle) to move smoothly along a specific trajectory.

最后,我想为多个DOM对象执行此操作,最终将链接到数据,每个对象都有一个特定的曲线。关于我如何做这个的任何提示?

In the end, I would want to do this for multiple DOM objects which will eventually be linked to data, each with a specific curve to follow. Any tips on how I would do this?

感谢提供任何帮助,我会很乐意采取任何建议,包括参考。

Thanks in advance for any help, and I will gladly take any advice, including references.

推荐答案

有趣但不太实用的方法



有多个动画选项,包括沿路径移动对象的能力。该路径以与< path> 元素相同的形式定义,因此您可以使用 d3.svg.arc 函数创建路径。

Interesting but not terribly practical approach

The SVG spec actually has a number of animation options, including the ability to move an object along a path. The path is defined in the same form as for a <path> element, so you could use the d3.svg.arc functions to create the path.

一旦你定义了一个路径,很容易使用d3来添加动画:

http://fiddle.jshell.net/RnNsE/1/

虽然您会想要阅读 SVG动画元素和属性

Once you have a path defined, it is easy to use d3 to add in the animation:
http://fiddle.jshell.net/RnNsE/1/
although you'll want to read up on SVG animation elements and attributes.

但是,这个奇妙的动画有一个限制:浏览器支持不佳。所以如果这是一个网站,你将需要用d3和Javascript做动画。

However, there is a limitation to this wonderful animation: poor browser support. So if this is for a website, you're going to need to do the animation with d3 and Javascript.

让d3为您创建流畅的动画的关键是使用自定义补间功能

The key to getting d3 to create smooth animations for you is to use a custom "tween" function on a transition.

执行转换时,d3会为每个元素的每个更改初始化补间函数,并启动定时器函数以触发更新。在定时器的每个tick处,d3调用适当的补间函数,其中包含关于沿着过渡有多远的信息。因此,如果刻度在2000ms转换中发生500ms,则补间函数将给出值0.25(假设线性宽松函数,其他宽松函数使经过的时间和沿着转换的预期距离之间的关系复杂化)。

When you do a transition, d3 initializes a tween function for each change on each element, and starts up timer functions to trigger the updates. At each "tick" of the timer, d3 calls the appropriate "tween" function with the information about how far along the transition it is. So if the tick occurs 500ms into a 2000ms transition, the tween function will given the value 0.25 (assuming a linear easing function, other easing functions complicate the relationship between time elapsed and the expected "distance" along the transition).

现在,对于大多数更改,补间函数是相当简单的,而d3将自动为你。如果将cx值从100更改为200,则当转换值为25%时,补间函数将返回125,当转换为50%时,补间函数将返回125,以此类推。如果将填充值从红色更改为黄色,它将计算这些颜色的数值并在它们之间进行转换。

Now, for most changes the tween function is fairly straightforward, and d3 will figure one out for you automatically. If you change a "cx" value from 100 to 200, then the tween function is going to return 125 when the transition value 25%, 150 when the transition is 50%, and so on. If you change a "fill" value from red to yellow, it will calculate the numerical values of those colours and convert between them.

然后使用补间函数在每个tick处返回的值来更新元素的属性或样式。由于更新每秒发生很多次,它通常会产生平滑的动画。对于更改圆的cx值的简单示例,圆以直线从起点移动到结束点。

The value returned by the tween function at each tick is then used to update the attribute or style of the element. Since the updates happen many times a second, it usually results in a smooth animation. For the simple example of changing the "cx" value of a circle, the circle moves in a straight line from the starting point to the end point.

希望它在一条直线上移动。你想要它在一个圆圈(或沿你选择的任何路径)移动。因此,您需要创建一个自定义函数,告诉圆形应该在过渡的25%处,以及在过渡处应该有50%的位置。

But you don't want it to move in a straight line. You want it to move in a circle (or along any path you choose). So you're going to need to create a custom function that tells the circle where it should be 25% of the way through the transition, and where it should be 50% through the transition, and so on.

如果你担心你必须自己决定,不要害怕。像这样,很多与D3, Mike Bostock为你做了艰苦的工作。但即使他不必做艰苦的工作。他的方法为SVG路径使用两个内置的JavaScript函数, getTotalLength() getPointAtLength()。第一个告诉你路径的总长度,第二个告诉你点的坐标从路径的开始一定距离。

And if you're worried you have to figure that out on your own, never fear. Like so, so much with D3, Mike Bostock has done the hard work for you. But even he didn't have to do the hard hard work. His approach uses two built-in Javascript functions for SVG paths, getTotalLength() and getPointAtLength(). The first tells you the total length of the path, the second gives you the coordinates of the point a certain distance from the start of the path.

对于这两个值,可以直接找出你应该在的坐标,如果你想成为路径的一定百分比:在25% ,你想要在 path.getPointAtLength(0.25 * path.getTotalLength())

With those two values, it is straightforward to figure out the coordinates you should be at if you want to be a certain percent of the way along the path: at 25%, you want to be at path.getPointAtLength(0.25*path.getTotalLength() ).

这会发生:

// Returns an attrTween for translating along the specified path element.
function translateAlong(path) {
  var l = path.getTotalLength();

  return function(d, i, a) {
    return function(t) {
      var p = path.getPointAtLength(t * l);
      return "translate(" + p.x + "," + p.y + ")";
    };
  };
}

有点混乱,不是?返回一个函数返回一个函数的函数。

A little confusing, no? A function that returns a function that returns a function.

这是因为当你为一个过渡指定一个补间,你实际要指定的是一个 - 将为选择中的每个元素返回适当的补间函数的函数。

That's because when you specify a "tween" for a transition, what you actually have to specify is a "tween factory" -- the function that will return an appropriate tween function for each element in your selection.

现在,在他的例子中,他只有一个路径和一个对象沿着它移动,所以这些额外的图层不会被使用。但在一般情况下,你的补间工厂函数将接受参数 d (选择中该元素的数据对象), i (该元素的索引)和 a (您要更改的属性或样式的初始值)。使用这些值,您必须返回自定义补间函数,其采用过渡状态值 t (某个缓动函数的0或1之间的数字,或者可能超过1的数字)并计算该状态下的属性值。

Now, in his example he only has one path and one object moving along it, so those extra layers don't get used. But in the general case, your tween factory function would take the arguments d (the data object for that element in the selection), i (the index of that element) and a (the initial value of the attribute or style that you're changing). With those values, you have to return the custom tween function which take a transition state value t (a number between 0 or 1, or possibly a bit beyond 1 for certain easing functions) and computes the attribute value at that state in the transition.

你会注意到这个函数返回一个翻译指令。与使用 cx cy 相比,这通常是一个更简单的移动对象的方法,因为你可以在一个变换属性调用中指定水平和垂直运动,所以你只需要一个补间函数来做这两个。

You'll note that this function returns a translation instruction. That's generally going to be an easier way to move an object around, compared to using cx and cy, since you can specify both horizontal and vertical movement in one transform attribute call, so you only need the one tween function to do both.

这是我上面的例子,更新使用d3补间以沿路径移动圈子:

http://fiddle.jshell.net/RnNsE/2 /

Here's my example from above, updated to use a d3 tween to move the circles along the path:
http://fiddle.jshell.net/RnNsE/2/

键码:

circles.transition().ease("linear")
    .duration(5000)
    .delay(function(d,i){return i*5000;})
    .attrTween("transform", createPathTween);

//creates a tween function to translate an element
//along the path that is a sibling to the element
function createPathTween(d, i, a) {
  var path = this.parentNode.getElementsByTagName("path")[0];
  //i.e., go from this <circle> -> parent <g> -> array of child <path> elements 
               -> first (and only) element in that array

  var l = path.getTotalLength();

  return function(t) {
      var p = path.getPointAtLength(t * l);
      return "translate(" + p.x + "," + p.y + ")";
    };    
}

我的版本从Mike的版本中去除了最外层的嵌套函数,添加一些Javascript以为每个圆形元素找到正确的< path> 元素。

My version strips out the outermost layer of nested functions from Mike's version, but it adds in a bit of Javascript to find the correct <path> element for each circle element.

请注意,您需要一个SVG路径元素才能使用 getTotalLength() getPointAtLength()函数;然而,如果你不想让它显示在屏幕上,这个路径可以是不可见的( fill:none; stroke:none; 再次,虽然我的路径定义是硬编码,但您可以使用d3的 arc line 生成器为您构建。

Note that you need an SVG path element in order to use the getTotalLength() and getPointAtLength() functions; however, this path can be invisible (fill:none; stroke:none; in CSS) if you don't want it to show on the screen. And again, while my path definitions are hard-coded, you could use one of d3's arc or line generators to construct it for you.

只是为了好玩,以下是我使用不同缓动功能的示例:

http://fiddle.jshell.net/RnNsE/3/

请注意,我没有改变任何关于补间函数 - 所有改变的是 t 值,d3传递到该函数作为过渡进展。

And just for fun, here's my example with a different easing function:
http://fiddle.jshell.net/RnNsE/3/
Note that I didn't change anything about the tweening function -- all that's changed is the t values that d3 passes in to that function as the transition progresses.

PS这是d3自定义补间函数的另一个好的资源:
http://blog.safaribooksonline.com/2013/07/11/reusable-d3-js-using-attrtween-transitions-and-mv/

P.S. Here's another good resource on d3 custom tween functions: http://blog.safaribooksonline.com/2013/07/11/reusable-d3-js-using-attrtween-transitions-and-mv/

这篇关于跟踪路径与DOM对象的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆