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

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

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

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

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

1. 什么是离屏技术?

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

2. 实现水印和中心缩放

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

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

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>Learn Canvas</title>
  6. <style>
  7. canvas {
  8. display: block;
  9. margin: 0 auto;
  10. border: 1px solid #222;
  11. }
  12. input {
  13. display: block;
  14. margin: 20px auto;
  15. width: 800px
  16. }
  17. </style>
  18. </head>
  19. <body>
  20. <div id="app">
  21. <canvas id="my-canvas"></canvas>
  22. <input type="range" value="1.0" min="0.5" max="3.0" step="0.1">
  23. <canvas id="watermark-canvas" style="display: none;"></canvas>
  24. </div>
  25. <script type="text/javascript">
  26. window.onload = function () {
  27. var canvas = document.querySelector("#my-canvas")
  28. var watermarkCanvas = document.querySelector("#watermark-canvas")
  29. var slider = document.querySelector("input")
  30. var scale = slider.value
  31. var ctx = canvas.getContext('2d')
  32. var watermarkCtx = watermarkCanvas.getContext("2d")
  33. /* 给第二个canvas获取的Context对象添加水印 */
  34. watermarkCanvas.width = 300
  35. watermarkCanvas.height = 100
  36. watermarkCtx.font = "bold 20px Arial"
  37. watermarkCtx.lineWidth = "1"
  38. watermarkCtx.fillStyle = "rgba(255 , 255 , 255, 0.5)"
  39. watermarkCtx.fillText("=== yuanxin.me ===", 50, 50)
  40. /****************************************/
  41. var img = new Image()
  42. img.src = "./img/photo.jpg"
  43. /* 加载图片后执行操作 */
  44. img.onload = function () {
  45. canvas.width = img.width;
  46. canvas.height = img.height;
  47. drawImageByScale(canvas, ctx, img, scale, watermarkCanvas);
  48. // 监听input标签的mousemove事件
  49. // 注意:mousemove实时监听值的变化,内存消耗较大
  50. slider.onmousemove = function () {
  51. scale = slider.value
  52. drawImageByScale(canvas, ctx, img, scale, watermarkCanvas);
  53. }
  54. }
  55. /******************/
  56. }
  57. /**
  58. *
  59. * @param {Object} canvas 画布对象
  60. * @param {Object} ctx
  61. * @param {Object} img
  62. * @param {Number} scale 缩放比例
  63. * @param {Object} watermark 水印对象
  64. */
  65. function drawImageByScale(canvas, ctx, img, scale, watermark) {
  66. // 图像按照比例进行缩放
  67. var width = img.width * scale,
  68. height = img.height * scale
  69. // (dx, dy): 画布上绘制img的起始坐标
  70. var dx = canvas.width / 2 - width / 2,
  71. dy = canvas.height / 2 - height / 2
  72. ctx.clearRect(0, 0, canvas.width, canvas.height) // No1 清空画布
  73. ctx.drawImage(img, dx, dy, width, height) // No2 重新绘制图像
  74. if (watermark) {
  75. // No3 判断是否有水印: 有, 绘制水印
  76. ctx.drawImage(watermark, canvas.width - watermark.width, canvas.height - watermark.height)
  77. }
  78. }
  79. </script>
  80. </body>
  81. </html>

实现效果如下图所示:

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

3. 实现放大镜

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

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

代码如下:

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>Document</title>
  6. <style>
  7. canvas {
  8. display: block;
  9. margin: 0 auto;
  10. border: 1px solid #222;
  11. }
  12. </style>
  13. </head>
  14. <body>
  15. <canvas id="my-canvas"></canvas>
  16. <canvas id="off-canvas" style="display: none;"></canvas>
  17. <script>
  18. var isMouseDown = false,
  19. scale = 1.0
  20. var canvas = document.querySelector("#my-canvas")
  21. var offCanvas = document.querySelector("#off-canvas") // 离屏 canvas
  22. var ctx = canvas.getContext("2d")
  23. var offCtx = offCanvas.getContext("2d") // 离屏 canvas 的 Context对象
  24. var img = new Image()
  25. window.onload = function () {
  26. img.src = "./img/photo.jpg"
  27. img.onload = function () {
  28. canvas.width = img.width
  29. canvas.height = img.height
  30. offCanvas.width = img.width
  31. offCanvas.height = img.height
  32. // 计算缩放比例
  33. scale = offCanvas.width / canvas.width
  34. // 初识状态下, 两个canvas均绘制Image
  35. ctx.drawImage(img, 0, 0, canvas.width, canvas.height)
  36. offCtx.drawImage(img, 0, 0, canvas.width, canvas.height)
  37. }
  38. // 鼠标按下
  39. canvas.onmousedown = function (event) {
  40. event.preventDefault() // 禁用默认事件
  41. var point = windowToCanvas(event.clientX, event.clientY) // 获取鼠标相对于 canvas 标签的坐标
  42. isMouseDown = true
  43. drawCanvasWithMagnifier(true, point) // 绘制在离屏canvas上绘制放大后的图像
  44. }
  45. // 鼠标移动
  46. canvas.onmousemove = function (event) {
  47. event.preventDefault() // 禁用默认事件
  48. if (isMouseDown === true) {
  49. var point = windowToCanvas(event.clientX, event.clientY)
  50. drawCanvasWithMagnifier(true, point)
  51. }
  52. }
  53. // 鼠标松开
  54. canvas.onmouseup = function (event) {
  55. event.preventDefault() // 禁用默认事件
  56. isMouseDown = false
  57. drawCanvasWithMagnifier(false) // 不绘制离屏放大镜
  58. }
  59. // 鼠标移出canvas标签
  60. canvas.onmouseout = function (event) {
  61. event.preventDefault() // 禁用默认事件
  62. isMouseDown = false
  63. drawCanvasWithMagnifier(false) // 不绘制离屏放大镜
  64. }
  65. }
  66. /**
  67. * 返回鼠标相对于canvas左上角的坐标
  68. * @param {Number} x 鼠标的屏幕坐标x
  69. * @param {Number} y 鼠标的屏幕坐标y
  70. */
  71. function windowToCanvas(x, y) {
  72. var bbox = canvas.getBoundingClientRect() // bbox中存储的是canvas相对于屏幕的坐标
  73. return {
  74. x: x - bbox.x,
  75. y: y - bbox.y
  76. }
  77. }
  78. function drawCanvasWithMagnifier(isShow, point) {
  79. ctx.clearRect(0, 0, canvas.width, canvas.height) // 清空画布
  80. ctx.drawImage(img, 0, 0, canvas.width, canvas.height) // 在画布上绘制图像
  81. /* 利用离屏,绘制放大镜 */
  82. if (isShow) {
  83. var { x, y } = point
  84. var mr = 50 // 正方形放大镜边长
  85. // (sx, sy): 待放大图像的开始坐标
  86. var sx = x - mr / 2,
  87. sy = y - mr / 2
  88. // (dx, dy): 已放大图像的开始坐标
  89. var dx = x - mr,
  90. dy = y - mr
  91. // 将offCanvas上的(sx,sy)开始的长宽均为mr的正方形区域
  92. // 放大到
  93. // canvas上的(dx,dy)开始的长宽均为 2 * mr 的正方形可视区域
  94. // 由此实现放大效果
  95. ctx.drawImage(offCanvas, sx, sy, mr, mr, dx, dy, 2 * mr, 2 * mr)
  96. }
  97. /*********************/
  98. }
  99. </script>
  100. </body>
  101. </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. tarjan求强连通分量+缩点+割点/割桥(点双/边双)以及一些证明

    “tarjan陪伴强联通分量 生成树完成后思路才闪光 欧拉跑过的七桥古塘 让你 心驰神往”----<膜你抄>   自从听完这首歌,我就对tarjan开始心驰神往了,不过由于之前水平不足,一 ...

  2. ESB结合门户Portlet实现数据分析

    1 背景概述 笔者在公司做集成项目时,通常会涉及ESB与Portal结合实现图表数据分析功能.通过ESB获取数据库信息,然后在门户上采用Portlet接收ESB中的数据URL最后展现到门户上.本文为项 ...

  3. MyBatis 源码分析 - SQL 的执行过程

    * 本文速览 本篇文章较为详细的介绍了 MyBatis 执行 SQL 的过程.该过程本身比较复杂,牵涉到的技术点比较多.包括但不限于 Mapper 接口代理类的生成.接口方法的解析.SQL 语句的解析 ...

  4. Linux下Redis安装使用教程

    https://redis.io/download 第一步:安装redis需要在有c语言的编译环境下,执行命令安装c语言环境: yum install gcc-c++ https://blog.csd ...

  5. HTML和CSS使用注意事项

    HTML 1.button标签 在IE中,button标签默认的type是button,而在其他浏览器和W3C标准中button默认的属性都是submit. 所以,在一个form表单中,如果butto ...

  6. scikit-image 图像处理库介绍

    今天学习图像处理的时候,无意中看到了scikit 软件包,抱着学习的态度,这里做个记录,方便以后翻阅. 概念:scikit-image 是一种开源的用于图像处理的 Python 包.它包括分割,几何变 ...

  7. 机器学习与Tensorflow(4)——卷积神经网络与tensorflow实现

    1.标准卷积神经网络 标准的卷积神经网络由输入层.卷积层(convolutional layer).下采样层(downsampling layer).全连接层(fully—connected laye ...

  8. 【译】使用 ndb 调试 node 应用

    原文链接:Debugging Node.js Application Using ndb Google Chrome 实验室发布了一款新的 node debug 工具来提升开发者体验,本文将会全面介绍 ...

  9. mysql: [ERROR] unknown variable 'datadir=/var/lib/mysql'问题

    环境: Centos7,mysql 5.7 问题: 在使用命令“mysql -u root -p”连接mysql时,报:“mysql: [ERROR] unknown variable 'datadi ...

  10. Gradle中使用SpringBoot插件构建多模块遇到的问题

    通常下,多模块的项目如下: Root project 'demospring' +--- Project ':model' \--- Project ':rest' 那么我们需要在rest模块依赖mo ...