教程所示图片使用的是 github 仓库图片,网速过慢的朋友请移步>>> (原文)canvas 离屏技术与放大镜实现

更多讨论或者错误提交,也请移步。

利用canvas除了可以实现滤镜,还可以利用离屏技术放大镜功能。

为了方便讲解,本文分为 2 个应用部分:

  1. 实现水印和中心缩放
  2. 实现放大镜

1. 什么是离屏技术?

canvas 学习和滤镜实现介绍过drawImage接口。除了绘制图像,这个接口还可以:将一个canvas对象绘制到另一个canvas对象上。这就是离屏技术。

2. 实现水印和中心缩放

在代码中,有两个 canvas 标签。分别是可见与不可见。不可见的 canvas 对象上的 Context 对象,就是我们放置图像水印的地方。

更多详解,请看代码注释:

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Learn Canvas</title>
<style>
canvas {
display: block;
margin: 0 auto;
border: 1px solid #222;
} input {
display: block;
margin: 20px auto;
width: 800px
}
</style>
</head>
<body>
<div id="app">
<canvas id="my-canvas"></canvas>
<input type="range" value="1.0" min="0.5" max="3.0" step="0.1">
<canvas id="watermark-canvas" style="display: none;"></canvas>
</div>
<script type="text/javascript">
window.onload = function () {
var canvas = document.querySelector("#my-canvas")
var watermarkCanvas = document.querySelector("#watermark-canvas")
var slider = document.querySelector("input") var scale = slider.value var ctx = canvas.getContext('2d')
var watermarkCtx = watermarkCanvas.getContext("2d") /* 给第二个canvas获取的Context对象添加水印 */
watermarkCanvas.width = 300
watermarkCanvas.height = 100
watermarkCtx.font = "bold 20px Arial"
watermarkCtx.lineWidth = "1"
watermarkCtx.fillStyle = "rgba(255 , 255 , 255, 0.5)"
watermarkCtx.fillText("=== yuanxin.me ===", 50, 50)
/****************************************/ var img = new Image()
img.src = "./img/photo.jpg" /* 加载图片后执行操作 */
img.onload = function () {
canvas.width = img.width;
canvas.height = img.height;
drawImageByScale(canvas, ctx, img, scale, watermarkCanvas);
// 监听input标签的mousemove事件
// 注意:mousemove实时监听值的变化,内存消耗较大
slider.onmousemove = function () {
scale = slider.value
drawImageByScale(canvas, ctx, img, scale, watermarkCanvas);
}
}
/******************/
}
/**
*
* @param {Object} canvas 画布对象
* @param {Object} ctx
* @param {Object} img
* @param {Number} scale 缩放比例
* @param {Object} watermark 水印对象
*/
function drawImageByScale(canvas, ctx, img, scale, watermark) {
// 图像按照比例进行缩放
var width = img.width * scale,
height = img.height * scale
// (dx, dy): 画布上绘制img的起始坐标
var dx = canvas.width / 2 - width / 2,
dy = canvas.height / 2 - height / 2
ctx.clearRect(0, 0, canvas.width, canvas.height) // No1 清空画布
ctx.drawImage(img, dx, dy, width, height) // No2 重新绘制图像
if (watermark) {
// No3 判断是否有水印: 有, 绘制水印
ctx.drawImage(watermark, canvas.width - watermark.width, canvas.height - watermark.height)
}
}
</script>
</body>
</html>

实现效果如下图所示:

拖动滑竿,即可放大和缩小图像。然后右键保存图像。保存后的图像,就有已经有了水印,如下图所示:

3. 实现放大镜

在上述中心缩放的基础上,实现放大镜主需要注意以下 2 个部分:

  1. 细化处理canvas的鼠标响应事件:滑入、滑出、点击和松开
  2. 重新计算离屏坐标(详细公式计算思路请见代码注释)
  3. 重新计算鼠标相对于 canvas 标签的坐标(详细公式计算思路请见代码注释)

代码如下:

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<style>
canvas {
display: block;
margin: 0 auto;
border: 1px solid #222;
}
</style>
</head>
<body>
<canvas id="my-canvas"></canvas>
<canvas id="off-canvas" style="display: none;"></canvas>
<script>
var isMouseDown = false,
scale = 1.0
var canvas = document.querySelector("#my-canvas")
var offCanvas = document.querySelector("#off-canvas") // 离屏 canvas
var ctx = canvas.getContext("2d")
var offCtx = offCanvas.getContext("2d") // 离屏 canvas 的 Context对象
var img = new Image() window.onload = function () {
img.src = "./img/photo.jpg" img.onload = function () {
canvas.width = img.width
canvas.height = img.height offCanvas.width = img.width
offCanvas.height = img.height // 计算缩放比例
scale = offCanvas.width / canvas.width // 初识状态下, 两个canvas均绘制Image
ctx.drawImage(img, 0, 0, canvas.width, canvas.height)
offCtx.drawImage(img, 0, 0, canvas.width, canvas.height) } // 鼠标按下
canvas.onmousedown = function (event) {
event.preventDefault() // 禁用默认事件
var point = windowToCanvas(event.clientX, event.clientY) // 获取鼠标相对于 canvas 标签的坐标
isMouseDown = true
drawCanvasWithMagnifier(true, point) // 绘制在离屏canvas上绘制放大后的图像
} // 鼠标移动
canvas.onmousemove = function (event) {
event.preventDefault() // 禁用默认事件
if (isMouseDown === true) {
var point = windowToCanvas(event.clientX, event.clientY)
drawCanvasWithMagnifier(true, point)
}
} // 鼠标松开
canvas.onmouseup = function (event) {
event.preventDefault() // 禁用默认事件
isMouseDown = false
drawCanvasWithMagnifier(false) // 不绘制离屏放大镜
} // 鼠标移出canvas标签
canvas.onmouseout = function (event) {
event.preventDefault() // 禁用默认事件
isMouseDown = false
drawCanvasWithMagnifier(false) // 不绘制离屏放大镜
}
} /**
* 返回鼠标相对于canvas左上角的坐标
* @param {Number} x 鼠标的屏幕坐标x
* @param {Number} y 鼠标的屏幕坐标y
*/
function windowToCanvas(x, y) {
var bbox = canvas.getBoundingClientRect() // bbox中存储的是canvas相对于屏幕的坐标
return {
x: x - bbox.x,
y: y - bbox.y
}
} function drawCanvasWithMagnifier(isShow, point) {
ctx.clearRect(0, 0, canvas.width, canvas.height) // 清空画布
ctx.drawImage(img, 0, 0, canvas.width, canvas.height) // 在画布上绘制图像 /* 利用离屏,绘制放大镜 */
if (isShow) {
var { x, y } = point var mr = 50 // 正方形放大镜边长 // (sx, sy): 待放大图像的开始坐标
var sx = x - mr / 2,
sy = y - mr / 2 // (dx, dy): 已放大图像的开始坐标
var dx = x - mr,
dy = y - mr // 将offCanvas上的(sx,sy)开始的长宽均为mr的正方形区域
// 放大到
// canvas上的(dx,dy)开始的长宽均为 2 * mr 的正方形可视区域
// 由此实现放大效果
ctx.drawImage(offCanvas, sx, sy, mr, mr, dx, dy, 2 * mr, 2 * mr)
}
/*********************/
}
</script>
</body>
</html>

放大镜效果如下图所示(被红笔标出的区域就是我们的正方形放大镜):

欢迎入群:857989948 。IT 技术深度交流和分享,涉及方面包括但不限于:网站制作、运营、UI 设计、算法分析、大数据、人工智能等。本群主打有深度、有态度的技术交流,欢迎热衷记录知识的您的加入。

canvas离屏技术与放大镜实现的更多相关文章

  1. Windows桌面共享中一些常见的抓屏技术

    1. BitBlt 我想做Windows开发应该都知道这个API, 它能实现DC间的内容拷贝, 如果我们把源DC指定成Monitor DC或是桌面DC, 它就能实现抓屏功能. 对于通过这种方式的抓屏, ...

  2. Windows抓屏技术

    Windows桌面共享中一些常见的抓屏技术 1. BitBlt   我想做Windows开发应该都知道这个API, 它能实现DC间的内容拷贝, 如果我们把源DC指定成Monitor DC或是桌面DC, ...

  3. canvas知识02:图片放大镜效果

    效果截图: JS代码: <script> // 初始化canvas01和上下文环境 var cav01 = document.getElementById('cav01'); var cx ...

  4. html5 canvas首屏自适应背景动画循环效果代码

    模板描述:html5 canvas首屏自适应背景动画循环效果代码 由于动态图太大,怕以后服务器受不了,所以现在都改为静态图了,大家点击演示地址一样的,希望大家喜欢,你们的支持就是小海的动力!! 欢迎大 ...

  5. DXGI快速截屏录屏技术

    DXGI快速截屏录屏技术 概述   很多地方都需要用到截屏/录屏技术,比如桌面直播,桌面录制等等.在微软Windows平台,有很多截屏的接口,不过大多数性能并不理想,Windows8以后微软引入了一套 ...

  6. 解析电子墨水屏技术(工作原理与LCD的区别)【转】

    转自:https://blog.csdn.net/weixin_42509369/article/details/84646808 阅读电子书早已成为大家生活中一部分,方便轻巧的电子版书籍更便于携带, ...

  7. Canvas清屏的实现

    /** * Canvas清屏的操作 * * 參考资料: http://blog.csdn.net/lfdfhl/article/details/9076001 * */ private void cl ...

  8. QQ群排名霸屏技术居然是这样简单

    最近做了一些收费的QQ群,收多少钱,一块钱的入门费,也就是说进入我的QQ群必须要1块钱的会费. 我的QQ群主要是干嘛呢,放些电影,比如说市面上电影院,正在播放的,最新最热门的,火爆的一些电影. 先前呢 ...

  9. 方别《QQ群霸屏技术》,又见《QQ群建群细则》

    规则,时刻变动;QQ群系列,咱们再来一轮. QQ群霸屏技术,你说建群貌似很菜,大家仿佛都知道,其实只知其一不知其二. QQ群类别 群分类,常规的就以下几种. 普通群. 建群随意,偏个性化,一言不合就拉 ...

随机推荐

  1. 桌面应用开发之WPF页面导航

    先看效果图 Get Start   为了项目解耦,使用mvvmlight框架.MVVM设计模式请自行了解. 1 新建项目   新建一个MvvmLight(WPF)项目,删除其中无关文件夹:Design ...

  2. Maven的多mirrors的配置

    repo1 central Human Readable Name for this Mirror. http://repo1.maven.org/maven2/ repo2 central Huma ...

  3. Nginx+Tomcat反向代理利用certbot实现https

    一.利用Let's Encrypt 免费生成HTTPS证书 1.下载安装certbot(Let's Encrypt ) 2.利用certbot生成证书 3.配置nginx的https证书 安装cerb ...

  4. 833. Find And Replace in String

    To some string S, we will perform some replacement operations that replace groups of letters with ne ...

  5. Maven 项目中的 pom.xml 文件内容说明

    下面是一个比较全面的 POM 文件的结构,当然常用的并不需要这么多配置,视自己的项目需求而定. <project xmlns="http://maven.apache.org/POM/ ...

  6. Win10手记-为应用集成SQLite(二)

    接上篇内容,这里给大家分享我的辅助访问类,采用了异步方法,封装了常用的访问操作,一些操作还是纯CLI的. SQLiteDBManager using System; using System.Coll ...

  7. Ehcache3开发入门简介

    在高并发应用中缓存就是核心机制.最近在研究Ehcache,发现这是一个更加灵活易用的缓存框架(相对于Redis.Memcache),Ehcache更加小巧轻便.而且都有持久化机制,不用担心JVM和服务 ...

  8. 外媒:比特币大陆将于9月IPO 规模或高达180亿美元

    看看你们坚持买的比特币是否值得? 北京时间8月13日上午消息,据CoinDesk获得的文件,比特币大陆将于今年9月申请首次公开募股(IPO),其规模可能高达180亿美元,市值预计在400亿美元到500 ...

  9. __getattr__()

    定义了__getattr__(),当访问object不存在的属性时会调用该方法 不定义访问不存在的属性时会报 AttributeError eg: class Cat(object): def __i ...

  10. php几种常见排序算法

    <?php //从时间上来看,快速排序和归并排序在时间上比较有优势,//但是也比不上sort排序,归并排序比较占用内存! $arr = [4,6,1,2,3,89,56,34,56,23,65] ...