通过 HTML5 Canvas 上的一组坐标移动对象

2023-12-01

我想移动一个物体(在这种情况下画圈)通过坐标数组(例如:{(300,400),(200,300),(300,200),(400,400)})在 HTML5 Canvas 上。我可以将对象移动到一个坐标,如下所示。以下代码在 (100,100) 处绘制一个圆并将其移动到 (300,400)。当我试图扩展它以使圆一个接一个地穿过一组坐标时,我陷入了困境。

const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');

//circle object

let circle ={
x:100, 
y:100,
radius:10,
dx:1,
dy:1,
color:'blue'
}

//function to draw above circle on canvas 
function drawCircle(){

        ctx.beginPath();
        ctx.arc(circle.x,circle.y,circle.radius,0,Math.PI*2);
        ctx.fillStyle=circle.color;
        ctx.fill();
        ctx.closePath();
}

//Moving to a target coordinate (targetX,targetY)

function goTo(targetX,targetY){

        if(Math.abs(circel.x-targetX)<circle.dx && Math.abs(circel.y-targetY)<circle.dy){

            circle.dx=0;
            circle.dy=0;
            circel.x = targetX;
            circle.y = targetY;
        }

        else{

        const opp = targetY - circle.y;
        const adj = targetX - circle.x;

        const angle = Math.atan2(opp,adj)

        circel.x += Math.cos(angle)*circle.dx
        circle.y += Math.sin(angle)*circle.dy

        }

}


function update(){
         ctx.clearRect(0,0,canvas.width,canvas.height);
         
         drawCircle()
         goTo(300,400)
         requestAnimationFrame(update);

}

update()

随机访问关键帧

为了最好地控制动画,您需要创建可以按时间随机访问的路径点(关键帧)。这意味着您只需设置时间即可获得动画中的任何位置。

然后,您可以播放和暂停、设置速度、倒退以及寻找动画中的任何位置。

Example

下面的示例使用一组点并添加在请求的时间快速定位关键帧并插入位置所需的数据。

蓝点将在设定的时间内在路径上以恒定速度移动pathTime在本例中为 4 秒。

红点的位置由滑块设置。这是为了说明动画位置的随机访问。

const ctx = canvas.getContext('2d');
const pathTime = 4; // Total time to travel path from start to end in seconds
var startTime, animTime = 0, paused = false;
requestAnimationFrame(update);
const P2 = (x, y) => ({x, y, dx: 0,dy: 0,dist: 0, start: 0, end: 0});
const pathCoords = [
  P2(20, 20), P2(100, 50),P2(180, 20), P2(150, 100), P2(180, 180),   
  P2(100, 150), P2(20, 180), P2(50, 100), P2(20, 20),
];
createAnimationPath(pathCoords);
const circle ={
    draw(rad = 10, color = "blue") {
        ctx.fillStyle = color;
        ctx.beginPath();
        ctx.arc(this.x, this.y, rad, 0, Math.PI * 2);
        ctx.fill();
    }
};
function createAnimationPath(points) { // Set up path for easy random position lookup
    const segment = (prev, next) => {
        [prev.dx, prev.dy] = [next.x - prev.x, next.y - prev.y];
        prev.dist = Math.hypot(prev.dx, prev.dy);
        next.end = next.start = prev.end = prev.start + prev.dist;
    }
    var i = 1;
    while (i < points.length) { segment(points[i - 1], points[i++]) }
}
function getPos(path, pos, res = {}) {
    pos = (pos % 1) * path[path.length - 1].end;       // loop & scale to total length 
    const pathSeg = path.find(p => pos >= p.start && pos <= p.end);
    const unit = (pos - pathSeg.start) / pathSeg.dist; // unit distance on segment
    res.x = pathSeg.x + pathSeg.dx * unit;             // x, y position on segment
    res.y = pathSeg.y + pathSeg.dy * unit;
    return res;
}
function update(time){
    // startTime ??= time;         // Throws syntax on iOS
    startTime = startTime ?? time; // Fix for above
    ctx.clearRect(0, 0, canvas.width, canvas.height);
    if (paused) { startTime = time - animTime }
    else { animTime = time - startTime }
    getPos(pathCoords, (animTime / 1000) / pathTime, circle).draw(); 
    getPos(pathCoords, timeSlide.value, circle).draw(5, "red"); 
    requestAnimationFrame(update);
}
pause.addEventListener("click", ()=> { paused = true; pause.classList.add("pause") });
play.addEventListener("click", ()=> { paused = false; pause.classList.remove("pause") });
rewind.addEventListener("click", ()=> { startTime = undefined; animTime = 0 });
div {
    position:absolute;
    top: 5px;
    left: 20px;
}
#timeSlide {width: 360px}
.pause {color:blue}
button {height: 30px}
<div><input id="timeSlide" type="range" min="0" max="1" step="0.001" value="0" width= "200"><button id="rewind">Start</button><button id="pause">Pause</button><button id="play">Play</button></div>
<canvas id="canvas" width="200" height="200"></canvas>
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

通过 HTML5 Canvas 上的一组坐标移动对象 的相关文章

随机推荐

  • 结果的 var_dump 给出空值。但更深入的检查返回一个整数[重复]

    这个问题在这里已经有答案了 可能的重复 新的 Mysqli 对象为 Null 我刚刚开始为 MVC 框架构建数据库类 在构建这个时 我正在尝试简单的查询和表 以使其正常工作 我试图查询以下内容 从 mvc test 选择 这应该返回 3 行
  • HTML5 页脚 - 我无法删除的边距

    我已经创建了一个基于 HTML 5 Boilerplate 的网站 我想要一个基本上全白色的网站 但页脚的背景为灰色 问题是页脚下方有一个边距 并且很确定它是一个边距 而不是填充或白色边框 在我的灰色页脚下方留下了一条白色条带 为了在此处发
  • 两个线程可以同时读取同一个QList吗?

    对于线程来说相当陌生 我有一个线程在它们之间共享的 QList 它们都有自己可以工作的空间 并且 GUI 模型 视图 不断访问该列表 然后我得到了指向 QDataList size 的崩溃 调试并没有真正帮助我 因为如果我单步执行代码 并且
  • 如何在 Spring MVC 中正确配置 Stomp 和 SockJS 端点?

    这是 可能是以下内容的重复 Websocket InvalidStateError 连接尚未建立 我正在实施通知系统 并希望在用户登录时初始化套接字连接 并向他显示他的通知 以及如果发生某些事件 我的代码片段如下 websocket js
  • 在 LINQ to Entities 中使用 GLOB 函数

    我需要 SQLiteglob C 方法中必须返回的函数Expression
  • 如何在 C++ 中将字符串向量转换为整数向量?

    我有一个字符串向量 需要帮助弄清楚如何将其转换为整数向量 以便能够进行算术处理 谢谢 include
  • Youtube 请求无法完成,因为您已超出配额 [关闭]

    Closed 这个问题不符合堆栈溢出指南 目前不接受答案 我的应用程序显示 Youtube V3 API 超出配额限制错误 我在 Google 控制台中的每日限制是 0 我无法更改该值 如何解决这个问题 单击旁边的小铅笔图标0并将其增加到1
  • $("#id") 仅选​​择第一个元素,但 $("div#id") 选择两个元素? [关闭]

    这个问题不太可能对任何未来的访客有帮助 它只与一个较小的地理区域 一个特定的时间点或一个非常狭窄的情况相关 通常不适用于全世界的互联网受众 为了帮助使这个问题更广泛地适用 访问帮助中心 div Hello buddy div div Hel
  • 跳过Delphi中的默认参数

    有没有办法跳过默认参数 假设我的方法声明是这样的 procedure MyProc1 var isAttr1 Boolean FALSE var isAttr2 Boolean FALSE var isAttr3 Boolean FALSE
  • 油漆组件不工作

    这可能是一个愚蠢的问题 但是我如何调用paintComponent 它根本不显示该对象 在其内部 公共类 Ball 扩展了 JPanel 实现了 Runnable public class Balls public static void
  • .htaccess 重定向域别名/停放域

    我有一个与 htaccess 相关的问题 例如 如果我有两个域 a com 和 b com 全部引用一台主机 b com 是 a com 的域别名 我希望访问 a com 的访问者将被引用到带有 www 的 url http www a c
  • Firebase JS API 身份验证 - 具有不同凭据的帐户存在

    我们在尝试解决此问题时遇到了实际问题 因此希望获得一些 Firebase 帮助 那些已经解决了相同问题的人 该应用程序是 React Native 0 43 2 并使用 Firebase JS API 最新 我们提供 Facebook 和
  • 为什么不鼓励 setAnimationDidStopSelector ?

    我在苹果关于 setAnimationDidStopSelector 的文档中看到以下内容 在 iOS 4 0 及更高版本中不鼓励使用此方法 如果您使用基于块的动画方法 则可以将委托的结束代码直接包含在块内 我尝试添加要放入动画块内的动画停
  • 将对象数组转换为单个对象

    例如 我有以下数组 name abc value 1 name xyz value 2 name abc value 3 name abc value 4 name xyz value 5 现在 我想通过分组将该数组减少为单个对象value
  • SPOJ 你能回答这些问题吗?

    我正在尝试解决这个问题SPOJ 我在线段树部分发现了这个问题 所以我很确定可能有一些使用线段树的可能解决方案 但我无法想出应该存储在树节点中的元数据 最大总和可以使用以下公式计算卡丹算法 但是如何使用线段树来计算它 如果我们只存储某个范围的
  • 找不到颤振命令

    这个问题的答案是社区努力 编辑现有答案以改进这篇文章 目前不接受新的答案或互动 显然 所有 Flutter 命令都无法在 Android Studio 的终端中运行 我相信我正在尝试在项目的根目录下运行它 Output bash flutt
  • R:将一个(大)数据帧的坐标匹配到另一个(大)数据帧的网格单元

    我有一个包含 X Y 坐标的大型数据框 约 200 000 行 例如 points lt data frame X c 1 3 2 5 4 Y c 4 3 2 2 1 另一个大型数据框 约 1 000 000 行 包含空间 矩形 网格的角单
  • LINQtoSQL 中的多重继承?

    伙计们 我一直在网上冲浪 寻找一种可以在 LINQ To SQL 中使用多表继承的方法 但看起来它只支持单表继承 这不是在 ORM 框架中实现继承的最佳方式 我了解到这个问题将在下一个 LINQ 和实体框架实现中得到解决 但我们谈论的停留时
  • android中如何过滤Json数据?

    我正在获取数据json形式就像 Users category id 1 user email email protected category id 5 user email email protected category id 1 us
  • 通过 HTML5 Canvas 上的一组坐标移动对象

    我想移动一个物体 在这种情况下画圈 通过坐标数组 例如 300 400 200 300 300 200 400 400 在 HTML5 Canvas 上 我可以将对象移动到一个坐标 如下所示 以下代码在 100 100 处绘制一个圆并将其移