在 JavaScript Canvas 中沿线移动点

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/5985072/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-25 19:02:36  来源:igfitidea点击:

Moving a Point Along a Line in JavaScript Canvas

javascriptmathcanvas2dline

提问by Conner Ruhl

Let's say that I have the coordinates of a line (25,35 45,65, 30,85 - It would be a two part line). I need to move a point (car) along that line at a constant distance every frame. How can I do this?

假设我有一条线的坐标(25,35 45,65, 30,85 - 这将是一条两部分的线)。我需要每帧以恒定距离沿该线移动一个点(汽车)。我怎样才能做到这一点?

采纳答案by Beta

Consider the line (25,35 45,65). The vector from the beginning to the end is (20, 30). To move a point (x,y) in that direction, we could just add that vector:

考虑这条线 (25,35 45,65)。从头到尾的向量是 (20, 30)。要沿该方向移动一个点 (x,y),我们可以添加该向量:

V = (20, 30) (x,y) => (x+20, y+30).

V = (20, 30) (x,y) => (x+20, y+30)。

If we start at the beginning of the line, we'll arrive at the end. But that's too big a step. We want something smaller but in the same direction, so we multiply the vector by, say, 0.1:

如果我们从行的开头开始,我们将到达结尾。但这一步太大了。我们想要更小但方向相同的东西,所以我们将向量乘以 0.1:

V = (2, 3) (x,y) => (x+2, y+3) => (x+4, y+6) => ...

V = (2, 3) (x,y) => (x+2, y+3) => (x+4, y+6) => ...

It's convenient to normalize, that is to make its length 1, which we do by dividing by its length:

normalize很方便,也就是让它的长度为 1,我们通过除以它的长度来实现:

V => V/|V| = (2,3)/sqrt(22+ 32) = (7.21, 10.82)

V => V/|V| = (2,3)/sqrt(2 2+ 3 2) = (7.21, 10.82)

Then you can just multiply that by whatever step size you want.

然后你可以将它乘以你想要的任何步长。

回答by Delta

Hey, so you have the coordinates (25,35) (45,65) (30,85) for your 2 lines, The point you want to move is going to be placed at the first of these coordinates (25,35) and you want it to move towards the second coordinate (45,65) (the end of the first line segment).

嘿,所以你有 2 条线的坐标 (25,35) (45,65) (30,85),你想移动的点将被放置在这些坐标中的第一个 (25,35) 和您希望它向第二个坐标 (45,65)(第一条线段的末端)移动。

The first step is to get the orientation in which the point is going to move, the orientation is the angle between the point position and the target position. To find this angle you can use the Math.atan2(), passing in as the first argument the target position Y - the point position Y, and as the second argument the target position X - the point position X.

第一步是获取点将要移动的方向,方向是点位置与目标位置之间的夹角。要找到这个角度,您可以使用Math.atan2(),作为第一个参数传入 ,作为target position Y - the point position Y第二个参数传入target position X - the point position X

var Point = {X: 25, Y: 35};
var Target = {X:45, Y:65};

var Angle = Math.atan2(Target.Y - Point.Y, Target.X - Point.X);

Now get the Sine and Cosine of that angle, the Sine is the value to move along the Y axis, and the Cosine is how much to move on the X axis. Multiply the sine and cosine by the distance you want to move each frame.

现在获取该角度的正弦和余弦,正弦是沿 Y 轴移动的值,余弦是在 X 轴上移动的量。将正弦和余弦乘以每帧要移动的距离。

var Per_Frame_Distance = 2;
var Sin = Math.sin(Angle) * Per_Frame_Distance;
var Cos = Math.cos(Angle) * Per_Frame_Distance;

Ok, what is left do to now is just setup the redraw method where you add the sine to the point's Y position and the cosine to the point's X position at each call. Check if the point has arrived to it's destination then do the same process to move towards the end of the second line segment.

好的,现在剩下要做的就是设置重绘方法,在该方法中,您在每次调用时将正弦添加到点的 Y 位置,将余弦添加到点的 X 位置。检查该点是否已到达其目的地,然后执行相同的过程以移向第二条线段的末端。

回答by John

8 years too late but someone may find this useful. This method is far faster given it doesn't uses stuff like atan, cos, sin and square root of which all are slow.

8 年太晚了,但有人可能会发现这很有用。这种方法要快得多,因为它不使用诸如 atan、cos、sin 和平方根之类的东西,这些东西都很慢。

function getPositionAlongTheLine(x1, y1, x2, y2, percentage) {
    return {x : x1 * (1.0 - percentage) + x2 * percentage, y : y1 * (1.0 - percentage) + y2 * percentage};
}

Pass percentage as value between 0 and 1 where 0 is start of the line and 1 being the end.

将百分比作为 0 和 1 之间的值传递,其中 0 是行的开头,1 是行的结尾。

var xy = getPositionAlongTheLine(100, 200, 500, 666, 0.5);
console.log(xy.x, xy.y);

回答by vbarbarosh

Sometimes it's not so obvious how to translate a mathematical formula into a code. The following is an implementation of a function which moves a point specified distance along a line. It uses vector notation:

有时,如何将数学公式转化为代码并不那么明显。下面是一个函数的实现,它沿着一条线移动一个点指定的距离。它使用向量表示法:

function travel(x, y, dx, x1, y1, x2, y2)
{
    var point = new Vector(x, y),
        begin = new Vector(x1, y1),
        end = new Vector(x2, y2);
    return end.sub(begin).norm().mul(dx).add(point);
}

class Vector
{
    constructor(x = 0, y = 0) {
        this.x = x;
        this.y = y;
    }

    clone() {
        return new this.constructor(this.x, this.y);
    }

    add(v) {
        this.x += v.x;
        this.y += v.y;
        return this;
    }

    sub(v) {
        this.x = this.x - v.x;
        this.y = this.y - v.y;
        return this;
    }

    mul(x) {
        this.x *= x;
        this.y *= x;
        return this;
    }

    div(x) {
        this.x /= x;
        this.y /= x;
        return this;
    }

    get mag() {
        return Math.sqrt(this.x * this.x + this.y * this.y);
    }

    norm() {
        var mag = this.mag;
        if (mag > 0) {
            this.div(mag);
        }
        return this;
    }
}

And a version without Vectorclass:

还有一个没有Vector类的版本:

function travel(x, y, dx, x1, y1, x2, y2)
{
    var a = {x: x2 - x1, y: y2 - y1},
        mag = Math.sqrt(a.x*a.x + a.y*a.y);
    if (mag == 0) {
        a.x = a.y = 0;
    }
    else {
        a.x = a.x/mag*dx;
        a.y = a.y/mag*dx;
    }
    return {x: x + a.x, y: y + a.y};
}