如何实现Canvas图像的拖拽、点击等操作

news2024/9/20 22:46:40

上一篇Canvas的博文写完后,有位朋友希望能对Canvas绘制出来的图像进行点击、拖拽等操作,因为Canvas绘制出的图像能很好的美化。好像是想做炉石什么的游戏,我也没玩过。

Canvas在我的理解中就好像在一张画布上绘制图像,它只能看到却“摸”不到,那要如何进行操作呢。我不知道网上是怎么做的,这里用自己的想法做了个DEMO分享给大家。

思路:

虽然Canvas不能拖拽,但div可以拖拽,那怎么把二者结合起来呢。初步想法是将一个与Canvas图像大小差不多的div覆盖在其上,在拖拽div时将获取的光标坐标修正后传给Canvas绘制函数并刷新图像的位置。

既然要覆盖,先做些准备工作:

1.将div与Canvas画布均position:absolute,否则无法重叠。

2.将div的z-index值设置大点,保证其在Canvas画面之上。

准备工作完成后,我们先来看div的拖拽:

   var divObj=document.getElementById("cover");
    var moveFlag=false;
 
        divObj.onmousedown=function(e){
        moveFlag=true;
        var clickEvent=window.event||e;
        var mwidth=clickEvent.clientX-divObj.offsetLeft;
        var mheight=clickEvent.clientY-divObj.offsetTop;
        document.onmousemove=function(e){
            var moveEvent=window.event||e;
            if(moveFlag){
                divObj.style.left=moveEvent.clientX-mwidth+"px";
                divObj.style.top=moveEvent.clientY-mheight+"px";
                divObj.onmouseup=function(){
                    moveFlag=false;
                }
            }
        }
    };

来解读下这段代码:首先获取div对象,设置拖拽标志moveFlage,当onmousedown时为true表示可以拖动,当onmouseup时为false表示不能拖动了。

   var clickEvent=window.event||e;
      var mwidth=clickEvent.clientX-divObj.offsetLeft;
      var mheight=clickEvent.clientY-divObj.offsetTop;

这三行代码是为了修正光标位置。当点击时,记录下光标在div上的位置。mwidth和mheight表示光标落点相对于div左边和上边的距离。如果不加修正:

这就是不加修正的结果,当光标点下时,div的坐标即左上角会与光标坐标一致。

修正后:

点击时光标总会“粘”在div某点上。

接下来绘制图片:

首先定义全局变量X和Y,它们是为了实时更新图像的绘制坐标。

var ctx=document.getElementById("myCanvas").getContext("2d");
 var img=document.getElementById("myImg");
    function drawImg(){
        ctx.clearRect(0,0,1000,500);
        ctx.beginPath();
        ctx.drawImage(img,X,Y);
        ctx.closePath();
        ctx.stroke();
    }
 
    window.onload=function(){
        setInterval(drawImg,1);
    }

获取“画笔”,获取图片对象。这里setInterval循环执行绘制图片的函数,以刷新图片的位置,setInterval的间隔值越小,拖拽起来越“流畅”。

同时别忘了clearRect,当图片移动到下一个位置时,清除上一个位置的图片,参数为Canvas画布的坐标和尺寸。

在拖拽时将修正后的光标坐标传给X、Y:

 X=moveEvent.clientX-mwidth;
 Y=moveEvent.clientY-mheight;

最后加上div和图像的活动范围:

if(moveEvent.clientX<=mwidth){
        divObj.style.left=0+"px";
        X=0;
}
if(parseInt(divObj.style.left)+divObj.offsetWidth >=1000){
        divObj.style.left=1000 - divObj.offsetWidth+"px";
        X=1000 - divObj.offsetWidth;
}
if(moveEvent.clientY<=mheight){
        divObj.style.top=0+"px";
        Y=0;
}
if(parseInt(divObj.style.top)+divObj.offsetHeight>=500){
       divObj.style.top=500-divObj.offsetHeight+"px";
       Y=500-divObj.offsetHeight;
}

 

这个就看个人的要求了,注意是要同时限定div和图片的活动范围。1000与500为本例的画布大小,如果是在整个页面里活动就换成innerWidth或innerHeight。

彻底隐藏div看看效果:

最后说下点击事件,这里要注意的是在拖拽的过程中onmousedown与onmouseup二者就构成了一个click过程,但我们不希望在拖拽结束后触发点击事件。

这里有个比较简单的办法,定义一个clickFlag默认为false,当onmousedown时设为true,若进行了onmousemove事件时设为false。

在最后onmouseup时判断clickFlag的值,为true时才触发点击事件。也就是说当你按下鼠标时,只有不发现移动,松开鼠标时才会触发点击事件。

整理后的JS代码:

//    绘制图片坐标
    var X=0;
    var Y=0;
//    js部分
    var divObj=document.getElementById("cover");
    var moveFlag=false;
//区别moueseup与click的标志
    var clickFlag=false;
//    拖拽函数
    divObj.onmousedown=function(e){
        moveFlag=true;
        clickFlag=true;
        var clickEvent=window.event||e;
        var mwidth=clickEvent.clientX-divObj.offsetLeft;
        var mheight=clickEvent.clientY-divObj.offsetTop;
        document.onmousemove=function(e){
            clickFlag=false;
            var moveEvent=window.event||e;
            if(moveFlag){
                divObj.style.left=moveEvent.clientX-mwidth+"px";
                divObj.style.top=moveEvent.clientY-mheight+"px";
              将鼠标坐标传给Canvas中的图像
                X=moveEvent.clientX-mwidth;
                Y=moveEvent.clientY-mheight;
              下面四个条件为限制div以及图像的活动边界
                if(moveEvent.clientX<=mwidth){
                    divObj.style.left=0+"px";
                    X=0;
                }
                if(parseInt(divObj.style.left)+divObj.offsetWidth >=1000){
                    divObj.style.left=1000 - divObj.offsetWidth+"px";
                    X=1000 - divObj.offsetWidth;
                }
                if(moveEvent.clientY<=mheight){
                    divObj.style.top=0+"px";
                    Y=0;
                }
                if(parseInt(divObj.style.top)+divObj.offsetHeight>=500){
                    divObj.style.top=500-divObj.offsetHeight+"px";
                    Y=500-divObj.offsetHeight;
                }
                divObj.onmouseup=function(){
                    moveFlag=false;
                    if(clickFlag){
                        alert("点击生效");
                    }
                }
            }
        }
    };

 本例到此结束,更多功能大家有兴趣可以自己开发,感谢您的浏览,也感谢每个对我这菜鸟提意见的人。

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/467690.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

MySQL用的在溜,不知道业务如何设计也白搭!!!

MySQL业务设计 作者: 博学谷狂野架构师GitHub&#xff1a;GitHub地址 &#xff08;有我精心准备的130本电子书PDF&#xff09; 只分享干货、不吹水&#xff0c;让我们一起加油&#xff01;&#x1f604; 逻辑设计 范式设计 范式概述 第一范式&#xff1a;当关系模式R的所有属…

浙江省CIO峰会|数据安全+数字化转型,美创特色实践获“年度数字化赋能服务商”

近日&#xff0c;浙江省CIO年度峰会暨数实融合创新发展大会在杭州成功举办。美创科技受邀参加本次峰会&#xff0c;与全省数字化领袖人才共话数字化发展。 对话数字化转型 美创分享能力实践 在本次峰会以“数字化转型的昨天 今天 明天”为主题的论坛对话环节&#xff0c;美创科…

Win11启用docker报错

这里写自定义目录标题 An unexpected error was encountered while executing a WSLcommand. An unexpected error was encountered while executing a WSLcommand. An unexpected error was encountered while executing a WSLcommand. provisioning docker WSL distros: se…

M2M场景之客户端凭证模式|OIDC OAuth2.0 认证协议最佳实践系列 【4】

在前两篇文章中&#xff0c;我们介绍了 OIDC 授权码以及授权码增强的 PKCE 模式&#xff0c;本次我们将重点围绕 &#xff08;Client Credentials&#xff09; 模式进行讲解 &#xff0c;Client Credentials 模式是 OIDC 授权模式之一&#xff0c;它是一种用于客户端&#xff0…

微信小程序开发一个多少钱

小程序开发是当前比较流行的一项技术服务&#xff0c;能够为企业和个人带来巨大的商业价值和社会价值&#xff0c;但是小程序开发费用也是潜在的成本之一。在选择小程序开发服务时&#xff0c;了解开发费用如何计算、影响价格的因素以及如何降低成本等方面的知识&#xff0c;可…

055:cesium两种方法加载天地影像图

第055个 点击查看专栏目录 本示例的目的是介绍如何在vue+cesium中用两种方法加载天地影像图。一种是利用WebMapTileServiceImageryProvider,另一种是利用UrlTemplateImageryProvider. 直接复制下面的 vue+cesium源代码,操作2分钟即可运行实现效果. 文章目录 示例效果配置方…

bug记录:c++ mysql Connector:Lost connection to MySQL server during query

1.背景 使用mysql connector1.1.4版本&#xff0c;代码中有 mysql 连接池&#xff0c;每次执行 sql 时从连接池取出一个连接&#xff0c;先用isClosed()判断为false继续使用&#xff0c;否则创建新连接。     现在升级 mysql connector为1.1.13版本&#xff0c;业务代码未修…

Linux进程概念——其二

目录 环境变量 基本概念 常见环境变量 查看环境变量方法 测试PATH&#xff3b;重点&#xff3d; 测试HOME 和环境变量相关的命令 环境变量的组织方式 通过代码获取环境变量 通过系统调用获取或设置环境变量 环境变量通常是具有全局属性的&#xff3b;重点&#xff3d…

学会笔记本电脑录屏快捷键,轻松实现录屏!

案例&#xff1a;笔记本电脑录屏有快捷键吗&#xff1f; 【我每次打开笔记本电脑录屏都要耗费比较长的时间&#xff0c;这样会影响到我录屏的效率。在这里想问一下&#xff0c;有没有快速打开电脑录屏的方法&#xff1f;】 在日常的工作、学习、娱乐中&#xff0c;我们经常需…

算法训练第一周题解汇总

A - Sort the Subarray 大意&#xff1a;在s1找一个最大的 [l&#xff0c;r] 子区间&#xff0c;使其经过从小到大的排序后 能够变成 s2 题解&#xff1a;先确定最小的区间&#xff0c;然后慢慢扩大。 最小区间的确定&#xff1a;s1和s2第一个不相等的数开始&#xff0c;到最后…

浅谈测试用例设计 | 京东云技术团队

作者&#xff1a;京东物流 王莹莹 一、测试用例为什么存在 1.1 定义 测试用例(Test Case)是指对特定的软件产品进行测试任务的描述&#xff0c;体现测试方案、方法、技术和策略。测试用例内容包括测试目标、测试环境、输入数据、测试步骤、预期结果、测试脚本等&#xff0c;…

pytorch 计算网络模型的计算量FLOPs和参数量parameter之殊途同归

计算网络模型的计算量FLOPs和参数量parameter之殊途同归 参数量方法一&#xff1a;pytorch自带方法&#xff0c;计算模型参数总量参数量方法二&#xff1a; summary的使用&#xff1a;来自于torchinfo第三方库参数量方法三&#xff1a; summary的使用&#xff1a;来自于torchsu…

controlnet1.1预处理器功能详解

ControlNet 1.1 与 ControlNet 1.0 具有完全相同的体系结构,ControlNet 1.1 包括所有以前的模型&#xff0c;具有改进的稳健性和结果质量,但增加并细化了多个模型。 今天太忙了&#xff0c;有时间就把每个模型的测试样稿发出来 2023.4.27 分类预处理器备注模型黑白倒转invert边…

数据库物理存储结构

目录 一、数据库文件和文件组 1、数据库文件 &#xff08;1&#xff09; 主数据库文件&#xff08;Primary Database File&#xff09; &#xff08;2&#xff09; 次数据库文件&#xff08;Secondary Database File&#xff09; &#xff08;3&#xff09; 事务日志文件 …

[Linux]文档搜索和归档备份

​⭐作者介绍&#xff1a;大二本科网络工程专业在读&#xff0c;持续学习Java&#xff0c;输出优质文章 ⭐作者主页&#xff1a;逐梦苍穹 ⭐所属专栏&#xff1a;Linux基础操作。本文主要是分享一些Linux系统常用操作&#xff0c;内容主要来源是学校作业&#xff0c;分享出来的…

配置zabbix自定义监控项

1.需要安装zabbix-agent服务&#xff0c;使用的zabbix版本为5.0版本 参考&#xff1a;zabbix监控linux主机_Apex Predator的博客-CSDN博客 2.创建存放脚本目录并编辑监控服务的脚本(此处监控一下服务是否存活) mkdir /opt/zabbix_jb vi /opt/zabbix_jb/service_status.sh …

【容器化应用程序设计和开发】2.2 Dockerfile 的编写和最佳实践

往期回顾&#xff1a; 第一章&#xff1a;【云原生概念和技术】 第二章&#xff1a;2.1 容器化基础知识和Docker容器 容器化应用程序设计和开发 2.2 Dockerfile 的编写和最佳实践2.2.1 Dockerfile 包含哪些指令2.2.2 Dockerfile 注意事项 在上篇章节中&#xff0c;我们介绍了…

什么是索引?MySQL索引的底层数据结构

索引(index)是帮助MySQL高效获取数据的数据结构(有序)。在数据之外&#xff0c;数据库系统还维护着满足特定查找算法的数据结构(B树)&#xff0c;这些数据结构以某种方式引用(指向)数据&#xff0c;这样就可以在这些数据结构上实现高级查找算法&#xff0c;这种数据结构就是索引…

SAP 生产订单修改记录查询

无论在项目实施过程中还是在运维的项目中,经常会遇到生产订单被修改,导致需求发生变更,这个时候用户经常就会需要要求查询生产订单的修改记录。通过SAP的标准程序是没有办法查询到生产订单修改记录,这个时候就从开发的角度去做增强的方式去实现。 1、肯定是在生产订单保存…

AI(二):初体验(Cursor、Copilot、Bito)

Cursor Cursor官网下载&#xff1a;https://www.cursor.so/ && https://github.com/getcursor/cursor Cursor.so是一款基于GPT的代码生成工具&#xff0c;它可以帮助开发者快速生成代码&#xff0c;提高开发效率。GPT是一种自然语言处理技术&#xff0c;可以根据输入…