使用JS實現任意位置縮放圖片功能
前言
本文將用一個簡單的例子詳細講解如何用原生JS一步步實現完整的任意位置縮放圖片功能,無任何第三方依賴,指針事件 進行多端統(tǒng)一的事件監(jiān)聽,干貨滿滿。
完整代碼
HTML:
<div class="wrapper"> <img id="image" alt="" src="https://images.pexels.com/photos/459203/pexels-photo-459203.jpeg"/> </div>
CSS:
html, body { margin: 0; padding: 0; overflow: hidden; } .wrapper { width: 100vw; height: 100vh; display: flex; justify-content: center; align-items: center; background: #000; } img { max-height: 80vh; touch-action: none; }
JavaScript:
window.onload = () => { // 獲取dom const wrapper = document.querySelector(".wrapper"); const image = document.getElementById("image"); // 全局變量 let rect, x = 0, y = 0, scale = 1, minScale = 0.2, maxScale = 16, isPointerdown = false, // 按下標識 lastPointermove = { x: 0, y: 0 }; // 用于計算diff rect = image.getBoundingClientRect() // 拖拽查看 drag(); // 滾輪縮放 wheelZoom(); // 拖拽查看 function drag() { // 綁定 pointerdown image.addEventListener("pointerdown", function (e) { isPointerdown = true; lastPointermove = { x: e.clientX, y: e.clientY }; }); // 綁定 pointermove image.addEventListener("pointermove", function (e) { if (isPointerdown) { const current = { x: e.clientX, y: e.clientY }; x += current.x - lastPointermove.x; y += current.y - lastPointermove.y; lastPointermove = current; image.style.transform = "translate3d(" + x + "px, " + y + "px, 0) scale(" + scale + ")"; } e.preventDefault(); }); // 綁定 pointerup image.addEventListener("pointerup", function (e) { if (isPointerdown) { isPointerdown = false; } }); } // 滾輪縮放 function wheelZoom() { wrapper.addEventListener("wheel", function (e) { let d = e.deltaY < 0 ? 0.1 : -0.1; let ratio = 1 + d; let temp_scale = scale * ratio; if (temp_scale > maxScale) return if (temp_scale < minScale) return scale = temp_scale if (e.target.tagName === "IMG") { const max = { x: (d * rect.width) / 2, y: (d * rect.height) / 2, }; const mouseOffset = { x: e.clientX - rect.x, y: e.clientY - rect.y } // 計算每次的偏移量 x -= d * (mouseOffset.x - x) - max.x; y -= d * (mouseOffset.y - y) - max.y; image.style.transform = "translate3d(" + x + "px, " + y + "px, 0) scale(" + scale + ")"; } e.preventDefault(); }); } }
實現原理
實現圖片放大的關鍵點在于 CSS3 中的 transform
變換,該屬性應用于元素在2D或3D上的旋轉,縮放,移動,傾斜等等變換,通過設置 translate(x,y)
即可偏移元素位置,設置 scale
即可縮放元素,當然你也可以只設置 matrix
來完成上述所有操作,這涉及到矩陣變換的知識,本文使用的均是CSS提供的語法糖進行變換操作。
PC上的點擊、移動,H5的手勢操作,都離不開DOM事件監(jiān)聽。例如鼠標移動事件對應 mousemove
,移動端因為沒有鼠標則對應 touchmove
,而本文將介紹如何僅通過指針事件來進行多端統(tǒng)一 的事件監(jiān)聽。在監(jiān)聽事件中我們可以通過 event
對象獲取各種屬性,例如常用的 offsetX
、offsetY
相對偏移量,clientX
、clientY
距離窗口的橫坐標和縱坐標等。
理解transform-origin值
官方文檔解釋為:**transform-origin
**CSS 屬性讓你更改一個元素變形的原點。 https://developer.mozilla.org/zh-CN/docs/Web/CSS/transform-origin
我們可以簡單的理解為圖片縮放起點,這個值默認為圖片的正中心,所以我們進行放大或縮小都是依圖片中心來縮放。
css縮放圖片有兩種方法
一、修改transform-origin值進行縮放
優(yōu)點:簡單快捷,容易理解
缺點:頻繁修改
transform-origin
值會抖動,需要計算修正量
將鼠標當前的偏移量即 offsetX、offsetY
的值改變 transform-origin
來動態(tài)設置縮放的原點,再進行縮放,那么最終效果就是依照最新的transform-origin
值來進行縮放。
比如修改transform-origin
值為90% 90%。再設置放大倍數scale
為1.1。效果就是下圖的樣子
二、不修改transform-origin值,設置偏移量translate(x,y)進行縮放
我們利用滾輪事件監(jiān)聽并改變 scale
值。重點是利用 deltaY
值的正負來判斷滾輪是朝上還是朝下:
let scale = 1; image.addEventListener("wheel", function (e) { //d值永遠是正的0.1或者負的0.1,代表每次縮放的倍數 let d = e.deltaY < 0 ? 0.1 : -0.1; scale = scale * (1 + d); ... });
如上圖,怎么樣從左圖變成右圖呢?由于我們未修改transform-origin
,所以縮放始終都以圖片中心 為原點進行縮放,這顯然不符合我們的操作習慣,我們需要的是以鼠標點為中心對圖片進行縮放。
可以清晰的看到,我們先將圖片放大0.1倍,再設置偏移量translate(x,y)
就可以實現任意位置縮放
需要計算的translate(x,y)
值,實際上就是放大后的圖片中心點與原始圖片中心點的差值
每次可偏移translate(x,y)
的最大值
= 長寬 * 放大倍數 / 2
例如:長400,寬為800的圖片。放大0.1倍之后,圖片的長為440,寬為880。如果是在中心點放大,那么不需要移動圖片,xy等于0。如果在左上角放大,那么圖片整體向右下角偏移 x = (440 - 400) / 2 = 20,y = (880 - 800) / 2 = 40.
let d = e.deltaY < 0 ? 0.1 : -0.1; const max = { x: (d * rect.width) / 2, y: (d * rect.height) / 2, };
用鼠標點的座標
減去圖片的在頁面中的位置
可以得到鼠標在圖片中的位置
rect = image.getBoundingClientRect() const mouseOffset = { x: e.clientX - rect.x, y: e.clientY - rect.y }
最后用mouseOffset
減去已偏移的xy,再剩以放大倍數d
,再減去max
,就是當前的translate(x,y)
值
- 因為
mouseOffset
的值,基本可以看作為一個常量,如果鼠標不移動位置,那么mouseOffset
的值不會變,所以需要減去已偏移的xy,才能累計偏移量 - 再剩以放大倍數,得到的值,還不能用于偏移
- 第二步得到的這個值已經超過我們的最大偏移值
max
,所以需要減去max
,最終就是當前的偏移量
// 計算每次的偏移量 x -= d * (mouseOffset.x - x) - max.x; y -= d * (mouseOffset.y - y) - max.y; image.style.transform = "translate3d(" + x + "px, " + y + "px, 0) scale(" + scale + ")";
移動圖片
移動圖片的實現是比較簡單的,在每次指針按下時我們記錄 clientX
、clientY
為初始值,移動時計算當前的值與初始點位的差值加到 translate
偏移量中即可另外當抬起動作結束時,會觸發(fā) click
事件,所以注意加入全局變量標記以及定時器進行一些判斷處理。
image.addEventListener("pointerdown", function (e) { isPointerdown = true; lastPointermove = {x: e.clientX, y: e.clientY}; }); image.addEventListener("pointermove", function (e) { if (isPointerdown) { const current = {x: e.clientX, y: e.clientY}; x += current.x - lastPointermove.x; y += current.y - lastPointermove.y; lastPointermove = current; image.style.transform = "translate3d(" + x + "px, " + y + "px, 0) scale(" + scale + ")"; } e.preventDefault(); }); image.addEventListener("pointerup", function (e) { isPointerdown = false; });
結束
到此這篇關于使用JS實現任意位置縮放圖片功能的文章就介紹到這了,更多相關JS任意位置縮放圖片內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
JavaScript CollectGarbage函數案例詳解
這篇文章主要介紹了JavaScript CollectGarbage函數案例詳解,本篇文章通過簡要的案例,講解了該項技術的了解與使用,以下就是詳細內容,需要的朋友可以參考下2021-08-08