canvas 简单直线轨迹运动与线性插值计算

canvas 简单直线轨迹运动与线性插值计算

一、canvas 直线轨迹运行

添加 canvas 语法提示

通过/** @type {HTMLCanvasElement} */代码块 来添加canvas的语法提示

<body>
  <canvas id="canvas"></canvas>
</body>
<script>
  /** @type {HTMLCanvasElement} */ 
</script>
获取 canvas,模拟demo数据
/** @type {HTMLCanvasElement} */
const canvas = document.getElementById("canvas");
// 建议设置宽高的方式
canvas.width = 600;
canvas.height = 600;
const coords = [
  [100, 100],
  [200, 200],
  [400, 200],
  [500, 300],
  [500, 500],
];
const img = new Image();
img.src = "img/arrow2.png";
let t = 0; // 图片移动步进
let index = 0; // 图片轨迹分段索引
const imgW = 242 / 10;
const imgH = 166 / 10;
// 图片运动轨迹分段
const animationCoords = [
  [coords[0], coords[1]],
  [coords[1], coords[2]],
  [coords[2], coords[3]],
  [coords[3], coords[4]],
];

// 获取canvas 的上下文
const ctx = canvas.getContext("2d");
根据模拟点位数据 coords,画轨迹
// 轨迹
function drawLine() {
  ctx.beginPath();
  ctx.moveTo(coords[0][0], coords[0][1]);
  ctx.lineTo(coords[1][0], coords[1][1]);
  ctx.lineTo(coords[2][0], coords[2][1]);
  ctx.lineTo(coords[3][0], coords[3][1]);
  ctx.lineTo(coords[4][0], coords[4][1]);
  ctx.strokeStyle = "gray";
  ctx.stroke();
}
drawLine();

在这里插入图片描述

运动中计算图片当前所在位置坐标与角度
/**
 * @desc 根据t切割line坐标,计算当前点的角度值,用于动画
 * @parmas start 轨迹线段开始坐标
 * @parmas end 轨迹线段结束坐标
 */
function computed(start, end, t) {
  const dx = end[0] - start[0];
  const dy = end[1] - start[1];
  const angle = Math.atan2(dy, dx);

  if (t > 1) return {};

  const x = start[0] + (end[0] - start[0]) * t;
  const y = start[1] + (end[1] - start[1]) * t;
  return {
    x,
    y,
    angle,
  };
}
绘制图片
function drawImage() {
  if (t >= 1) {
    t = 0; // 重置
    index++; // 进行下一分段的轨迹运动
    if (index === animationCoords.length) {
      index = 0; // 反复运动
    }
  }
  t += 0.01; // 控制动画速度
  const start = animationCoords[index][0];
  const end = animationCoords[index][1];
  const { x, y, angle } = computed(start, end, t);
  if (x === undefined) return;
  ctx.beginPath();
  ctx.translate(x, y); // 改变画布原点
  ctx.rotate(angle); // 旋转画布
  ctx.drawImage(img, -imgW / 2, -imgH / 2, imgW, imgH);
  // setTransform设置默认矩阵 恢复画布原点 避免后续画图坐标偏离。也可以通过save和restore的方式来恢复画布原点,save可以保存变换矩阵,在translate之前调用save
  ctx.setTransform(1, 0, 0, 1, 0, 0); 
}
编写动画函数
function animation() {
  // 清空画布 动画每一帧之前都需要清空画布,除非动画下一帧是全屏覆盖
  ctx.clearRect(0, 0, 600, 600); 
  requestAnimationFrame(animation); // 浏览器下一次渲染时执行动画函数
  drawImage();
  drawLine();
}
animation()

在这里插入图片描述

二、canvas 中的线性插值

已知 A,B 两点坐标,计算已知 x 或 y 的 C 点坐标,且 C 点在 AB 连线上

线性插值计算方法
/**
 * @desc 线性插值
 * @params coord1
 * @params coord2
 */
function TDLI(coord1, coord2) {
  const scale = (coord1[0] - coord2[0]) / (coord1[1] - coord2[1]);

  return {
    getY: (x) => (x - coord1[0]) / scale + coord1[1],
    getX: (y) => (y - coord1[1]) * scale + coord1[0],
  };
}
demo
const A = [90, 100];
const B = [205, 110];
const tdli = TDLI(A, B);

// 计算AB连线上 x坐标为 320的点
const Cx = 320;
const Cy = tdli.getY(Cx);

ctx.beginPath();
ctx.moveTo(A[0], A[1]);
ctx.lineTo(B[0], B[1]);
ctx.stroke();
ctx.beginPath();
ctx.moveTo(B[0], B[1]);
ctx.lineTo(x, y);
ctx.setLineDash([4, 16]);
ctx.strokeStyle = "red";
ctx.stroke();

在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值