网站地图    收藏   

主页 > canvas引擎 > canvas基础 >

canvas实现剪切蒙层

来源:未知    时间:2022-12-21 14:39 作者:小飞侠 阅读:

[导读] 在某些特殊业务场景下我们需要多图像进行裁剪,或者创建蒙层框选出某个特定的区域,要实现这样的场景其实思路有很多,但是考虑到canvas的性能、实现复杂度的问题来讲,都有各自...

在某些特殊业务场景下我们需要多图像进行裁剪,或者创建蒙层框选出某个特定的区域,要实现这样的场景其实思路有很多,但是考虑到canvas的性能、实现复杂度的问题来讲,都有各自的不足之处。首先来看如下图需求场景。


 image.png


如果我们要实现这样的一个框选效果,对图形或画面框选出某个特定的区域从而对这个区域做某些特定的业务操作。要实现这样一个框选效果常见的解决方案有4种:


第一种方案:

要实现这样的选框效果,我们可以配合div DOM节点来控制选框,并调整其大小。dom效果与源码实现可参考:html5 canvas 截图demo(带半透明遮罩)_Don't lost way-CSDN博客


实现思路分别有以下三个核心步骤。


第一步:在canvas画布下创建一个div元素,这个div元素就是框选的区域。


第二步:这个选框边上8个点的实现分别在这个选框div中添加8个子元素,通过定位的方式分别对这8个子元素定位到相应的位置。


第三步:通过鼠标移动事件对这个div进行缩放调整宽高大小,并获取选框在窗口上的坐标。


这种方式往往的通过div等节点元素来控制的,对dom操作依赖度很高,实现起来源码量也很大,在我看来不利于我们本节内容寻求最优的解决方案的初衷。


第二种方案: 

第二种解决方案是参考我们公司现有方案,其思路是通过在画布的背景图上创建一个矩形图层,并对此图层进行半透明效果处理,在此半透明图层下再实现框选的矩形,并记录选框矩形的坐标,通过ctx.putImageData()方法来获取到背景图对应的区域并绘制到框选矩形中去即可。实现步骤分为以下4个步骤。


第一步:在背景图上创建半透明的矩形图层,


第二步:在半透明图层下再创建一个框选矩形,并记录此矩形的坐标大小,根据此矩形的坐标计算出8个点的坐标并添加8个点定位在框选矩形的边框上。


第三步:通过鼠标移动事件实时对框选矩形的位置和大小进行调整并更新坐标。


第四步:使用记录下来的框选矩形坐标通过getImageData()方法复制一份背景图对应坐标区域图形并通过putImageData()方法绘制到框选矩形相同的坐标上来即可。


这个方案的可用性会比第一种解决方案要高,但从性能提升角度去考虑 对框选矩形会不断的重复渲染,也会造成不必要的计算开销。显然我们还在寻求探索更优的解决方案。


第三种方案:

第三种方案就是我们可以直接通过canvas提供的原生API ctx.globalCompositeOperation = 'xor'对我们创建的半透明矩形进行裁剪出空白区域,并对此区域的坐标添加边上的8个点。实现思路如下:


第一步:在背景图层上创建一个与画布大小相同的矩形,并设置成半透明状态。


第二步:用过globalCompositeOperation = 'xor'对此半透明图层进行裁剪的属性设置。


第三步:定义框选的矩形并记录其坐标,根据裁剪的坐标计算出8个点的定位位置即可。


此方案可快速解决我们简单的一些业务场景,但它存在一个问题,当我们需要同事生成多个框选矩形的时候,在某些矩形坐标出现重叠的情况下,在重叠产生交集处会出现白色区域,不利于绘制多个框选矩形的业务场景。在单个选框矩形的需求下其性能和可用性很高。


第四种方案:

本方案解决思路为创建两个canvas画布,第一个canvas画布主要用户背景图型的绘制,第二个canvas画布主要用于绘制裁剪蒙层和选框标注等操作,在第二个canvas画布中先绘制一个宽高大小与画布相同的矩形并设置半透明效果,在此基础上通过清除ctx.clearRect()方法按照给定的坐标对半透明蒙层指定区域进行清除,再绘制相同给定坐标的矩形即可,在此基础上添加边框上的8个点。具体步骤如下:


第一步:在第一个canvas中绘制背景图。


第二步:在第二个canvas中绘制相当画布大小的矩形并设置成半透明状态,记录其坐标。


第三步:根据记录的坐标绘制对应的矩形选框,在此基础上添加对应的8个点。 


例如:


1. 第一个画布绘制背景图 


let image = new Image();
const canvas = document.getElementById("canvas");
canvas.width = canvas.offsetWidth;
canvas.height = canvas.offsetHeight;
const ctx = canvas.getContext("2d");
image.setAttribute("crossOrigin","anonymous");
image.src = "https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fnimg.ws.126.net%2F%3Furl%3Dhttp%3A%2F%2Fdingyue.ws.126.net%2F2021%2F0128%2F6cd17366j00qnmnle008uc000vk00xcm.jpg%26thumbnail%3D650x2147483647%26quality%3D80%26type%3Djpg&refer=http%3A%2F%2Fnimg.ws.126.net&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=jpeg?sec=1643627661&t=298faa510a1783c1f8413fb8a51e7cf8";
image.onload = (event) => {
   ctx.drawImage(0,0,wdith,height);
};


2. 第二个画布创建蒙层并清除指定区域绘制相遇坐标的矩形框 


ctx.save();
// 在第二个canvas画布中添加半透明蒙层
ctx.fillStyle = "rgba(0,0,0,0.5)";
ctx.fillRect(0,0,canvas.width,canvas.height);
 
// 清空半透明蒙层给定区域
ctx.clearRect(50,50,100,100);
 
// 绘制给定坐标的矩形框
ctx.strokeStyle = "red";
ctx.strokeRect(80,80,100,100);
/****添加对应边框上的8个点*****/
ctx.restore()


       此方案可很好解决我们的业务需求,并可以同事绘制多个矩形选框,不会存在过大的计算量,实现复杂度极其简化。目前视为最优解决方案。



最新评论

添加评论

更多文章推荐

自学PHP网专注网站建设学习,PHP程序学习,平面设计学习,以及操作系统学习

京ICP备14009008号-1@版权所有www.zixuephp.com

网站声明:本站所有视频,教程都由网友上传,站长收集和分享给大家学习使用,如由牵扯版权问题请联系站长邮箱904561283@qq.com

添加评论