教程所示圖片使用的是 github 倉庫圖片,網速過慢的朋友請移步>>> (原文)canvas 離屏技術與放大鏡實現。
更多討論或者錯誤提交,也請移步。
利用
除了可以實現濾鏡,還可以利用離屏技術放大鏡功能。canvas
為了方便講解,本文分為 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.valuevar ctx = canvas.getContext('2d')var watermarkCtx = watermarkCanvas.getContext("2d")/* 給第二個canvas獲取的Context對象添加水印 */watermarkCanvas.width = 300watermarkCanvas.height = 100watermarkCtx.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.valuedrawImageByScale(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 / 2ctx.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 個部分:
- 細化處理
的鼠標響應事件:滑入、滑出、點擊和松開canvas
- 重新計算離屏坐標(詳細公式計算思路請見代碼注釋)
- 重新計算鼠標相對于 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.0var canvas = document.querySelector("#my-canvas")var offCanvas = document.querySelector("#off-canvas") // 離屏 canvasvar 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.widthcanvas.height = img.heightoffCanvas.width = img.widthoffCanvas.height = img.height// 計算縮放比例scale = offCanvas.width / canvas.width// 初識狀態下, 兩個canvas均繪制Imagectx.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 = truedrawCanvasWithMagnifier(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 = falsedrawCanvasWithMagnifier(false) // 不繪制離屏放大鏡}// 鼠標移出canvas標簽canvas.onmouseout = function (event) {event.preventDefault() // 禁用默認事件isMouseDown = falsedrawCanvasWithMagnifier(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 } = pointvar 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 設計、算法分析、大數據、人工智能等。本群主打有深度、有態度的技術交流,歡迎熱衷記錄知識的您的加入。
本文轉載于:猿2048https://www.mk2048.com/blog/blog.php?id=k2ihkj&title=canvas離屏技術與放大鏡實現