• 关于canvas的缩放和位移实战的一点点总结


    关于canvas的缩放和位移,这里做一些总结。

    变量定义

    defuaultScale:canvas画布的精度,也是缩放的初始值

    offsetX:x方向的偏移量

    offsetY:y方向的偏移量

    scale:画布缩放比例,默认值:defaultScale

    realScale:真实缩放比例,默认值为1,公式为realScale = scale / defaultScale

    centerX:缩放中心点x坐标

    centerY:缩放中心点y坐标

    lastX:记录最后移动canvas的点的x坐标

    lastY:记录最后移动canvas的点的y坐标

    lastD:记录两指间最后的距离

    使用

    初始化:

    如果canvas处于隐藏状态将获取不到宽高

    设置画布的精度,将影响画布的清晰程度。

    canvas.width = canvas.offsetWidth * defaultScale;
    canvas.height = canvas.offsetHeight * defaultScale;
    context = canvas.getContext('2d'); 
    
    • 1
    • 2
    • 3

    通过context.save - context.restore来重置每次的位移和缩放属性,从而达到不影响其他数据的目的。

    当保留缩放中心点时,真实偏移量需要将中心点考虑进来。

    function draw(){context.save();clear(); // 清除上次的绘制// 真实偏移量const offsetX0 = offsetX - centerX + centerX / realScale;const offsetY0 = offsetY - centerY + centerY / realScale;context.scale(scale, scale);context.translate(offsetX0, offsetY0);drawOther(); // 绘制其他物体context.restore();drawDebug(); // 绘制debug面板
    } 
    
    • 1
    • 2

    缩放和位移的步长计算

    开始触屏:

    开始缩放时,中心点位置可能发生变化,需要补齐其偏差。

    public handleTouchStart(e: TouchEvent) {const { clientX, clientY } = e.touches[0];// 记录起始点lastX = clientX;lastY = clientY; // 双指视为缩放 if (e.touches.length === 2) {// 记录两指间的距离lastD = Math.sqrt((clientX - e.touches[1].clientX) * (clientX - e.touches[1].clientX) +(clientY - e.touches[1].clientY) * (clientY - e.touches[1].clientY),); const _centerX = (clientX + e.touches[1].clientX) / 2;const _centerY = (clientY + e.touches[1].clientY) / 2;offsetX +=((1 - realScale) * (centerX - _centerX)) / realScale;offsetY +=((1 - realScale) * (centerY - _centerY)) / realScale;centerX = _centerX;centerY = _centerY; }
    } 
    
    • 1
    • 2

    触屏移动:

    偏移步长 = 位移量 / 真实缩放

    缩放步长 = 两指间距位移量 * 精度,(精度用于调节缩放幅度)

    public handleTouchMove(e: TouchEvent) {const { clientX, clientY } = e.touches[0];if (e.touches.length === 1) {offsetX += (clientX - lastX) / realScale;offsetY += (clientY - lastY) / realScale;}else{const distance = Math.sqrt((clientX - e.touches[1].clientX) * (clientX - e.touches[1].clientX) +(clientY - e.touches[1].clientY) * (clientY - e.touches[1].clientY),);// 0.01为每次缩放的幅度,可以视情况进行调节const tmpScale = scale + (distance - lastD) * 0.01;if (tmpScale <= 0) { // 防止缩放造成物体反向return;}if (lastD) {scale = tmpScale;}// 保留最后两指间的距离lastD = distance;}// 保留最后移动的点lastX = clientX;lastY = clientY;
    } 
    
    • 1
    • 2

    坐标点映射

    有时候点击canvas,需要将点击坐标映射到绘制的物体上,这里给出坐标的映射关系:

    映射坐标 = 真实坐标 / 真实缩放值 - 真实偏移量

     public transorm(x: number,y: number,reverse = false,) {const offsetX0 = offsetX - centerX + centerX / realScale;const offsetY0 = offsetY - centerY + centerY / realScale;if (reverse) {// 逆映射return {x: (x + offsetX0) * realScale,y: (y + offsetY0) * realScale,};}return {x: x / realScale - offsetX0,y: y / realScale - offsetY0,};
    } 
    
    • 1
    • 2
  • 相关阅读:
    FlexPro软件:生产、研究和开发中的测量数据分析
    淘宝天猫京东商品详情一键铺货到拼多多平台店铺接口代码对接教程
    Git学习笔记
    刷题日记【第十三篇】-笔试必刷题【数根+星际密码+跳台阶扩展问题+快到碗里来】
    论文速览 | IEEE Signal Processing Letters, 2024 | 基于时空上下文学习的事件相机立体深度估计
    springboot时间管理系统springboot47
    赢麻了!smardaten闷声干大事,竟然用无代码开发了复杂小程序!
    构建SatelliteRpc:基于Kestrel的RPC框架(整体设计篇)
    问题2:为什么4级中断处理完成之后会经过用户程序之后再回到1中断处理程序处理呢
    Python:二进制文件实现等间隔取相同数据量并合并
  • 原文地址:https://blog.csdn.net/weixin_53312997/article/details/126840697