最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

JavaScript?Canvas實現(xiàn)圖片局部放大鏡效果

 更新時間:2024年03月28日 14:52:52   作者:beckyye  
這篇文章主要為大家詳細介紹了如何使用JavaScript?Canvas實現(xiàn)圖片局部放大鏡效果,文中的示例代碼講解詳細,感興趣的小伙伴可以跟隨小編一起學習一下

前言

最近我在可視化課程中學習了如何在Canvas中利用像素處理來實現(xiàn)濾鏡效果,在這節(jié)課程的結(jié)尾留了一道局部放大鏡的題目,提示我們用像素處理的方式去實現(xiàn)這個效果,最終實現(xiàn)隨著鼠標移動將圖片局部放大,本著把學到的內(nèi)容落地實踐的想法,我就去思考了一番,但很不幸,我思考了好幾天也沒思考出結(jié)果,因為剛開始我想的一直是在一個Canvas上來操作,但是一來我對Canvas API還并不是很熟悉,二來我對像素處理還不夠熟練,然后第三是如果原圖的部分像素被處理了,那下一次放大就會有問題,因此我最終放棄了這個思路,選擇了再增加一個Canvas來完成最終的效果,以下就是利用這種方式實現(xiàn)圖片局部放大的效果。

像素處理

在實現(xiàn)這個效果之前,我們先來了解一下如何處理像素,有些小伙伴可能不太清楚,所以這里簡單說一下,在屏幕上我們知道所有顯示的內(nèi)容都是由像素點組成的,那么在處理像素之前,我們需要先獲取到像素信息,那么Canvas就是提供了一個API叫做getImageData讓我們可以獲取到畫布上的像素信息,最終這個API返回的是一個ImageData類型的值,關(guān)于這個API的具體描述可以參考對應的MDN頁面。

ImageData類型的數(shù)據(jù)包含三個屬性,包括data、width、height。width和height簡單來說,就是被提取像素信息的區(qū)域的寬高,最主要的像素信息是在這個data屬性中。data屬性指向一個數(shù)組類型的值,準確來說是Uint8ClampedArray的實例,Uint8ClampedArray表示8 位無符號整型固定數(shù)組,也就是說其中的元素是0到255之間的整數(shù),我們知道一個像素的顏色信息可以使用rgba四個分量表示,那么我們就得出在data數(shù)組中每四個元素就能表示一個像素點的信息,因此data數(shù)組的長度就是width * height * 4。

了解完像素處理,我們就可以開始進行具體的實現(xiàn)了。

具體實現(xiàn)

<canvas ref="canvasRef" width="0" height="0"></canvas>
<canvas ref="magnifier" width="0" height="0"></canvas><!-- 放大鏡 -->

1. 準備工作

在實現(xiàn)放大效果之前,我們需要先把圖片加載到Canvas上:

(async function() {
  const img = await loadImage('src/assets/girl1.jpg');
  canvasRef.value.width = img.width;
  canvasRef.value.height = img.height;
  context.drawImage(img, 0, 0);
}());

這里loadImage方法是通過Image對象來異步加載圖片,然后通過drawImage方法將圖片繪制到畫布上。

接著設(shè)置一個要放大的區(qū)域,也就是以鼠標坐標為中心,多少半徑以內(nèi)的內(nèi)容要被放大,這里我設(shè)置一個變量originSize用于存儲原圖大小,并設(shè)置一個5倍的放大倍數(shù)。

let originSize = 40; // 原圖大小
let zoom = 5; // 放大倍數(shù)

(async function() {
  // ...
  magnifier.value.width = originSize * zoom;
  magnifier.value.height = originSize * zoom;
}());

用作于放大鏡的magnifier,我們使用originSize * zoom來設(shè)置它的寬高。

2. 鼠標移動事件監(jiān)聽

接下來就是主要的代碼實現(xiàn)。

首先是添加鼠標移動事件的監(jiān)聽:

const addEvent = () => {
  canvasRef.value.addEventListener('mousemove', mouseDownHandler);
};

addEvent();

然后我們就來實現(xiàn)mouseDownHandler函數(shù)。

首先我們獲取鼠標坐標在Canvas中的相對坐標,并通過Math.floor取整

const mouseDownHandler = e => {
  // 相對于畫布的坐標
  const center = {
    x: Math.floor(e.pageX - left),
    y: Math.floor(e.pageY - top)
  };
};

然后利用getImageData方法獲取指定區(qū)域的像素信息,這里我們用到了OffscreenCanvas,它提供了一個可以脫離屏幕渲染的 canvas 對象,可以提升渲染性能;這樣我們就得到了待放大區(qū)域的像素信息。

const mouseDownHandler = e => {
  // 相對于畫布的坐標
  // ...
  // 待放大區(qū)域的imageData
  const originImageData = getImageData(img, [center.x - originSize / 2, center.y - originSize / 2, originSize, originSize]);
};

現(xiàn)在我們需要一個ImageData類型的變量,用于存儲放大后的像素信息,因為最終要渲染到magnifier這個Canvas上,我們就使用magnifier的2d上下文對象調(diào)用createImageData方法來創(chuàng)建一個ImageData對象,關(guān)于這個方法的使用具體可查看MDN文檔。

const mouseDownHandler = e => {
  // 相對于畫布的坐標
  // ...
  // 待放大區(qū)域的imageData
  // ...
  // 構(gòu)建一個imageData
  const areaImageData = mContext.createImageData(magnifier.value.width, magnifier.value.height);
};

接下來就是具體的像素遍歷和處理,按照areaImageData的寬高來進行遍歷,這里迭代的增量使用+zoom是因為,當我們放大zoom倍數(shù)之后,原圖1個像素的信息在magnifier使用zoom*zoom個像素來放大,也就是zoom*zoom個像素點的色值和原圖中對應的那個像素的色值是一樣的。在我們這段代碼中設(shè)置zoom為5,也就是放大后使用5*5=25個像素點表示之前的一個像素點。

const mouseDownHandler = e => {
  // 相對于畫布的坐標
  // ...
  // 待放大區(qū)域的imageData
  // ...
  // 構(gòu)建一個imageData
  // ...
  let count = 0;
  for (let j = 0; j < originSize * zoom; j += zoom) {
    for (let i = 0; i < originSize * zoom; i += zoom) {

      // ...

    }
  }
};

所以我們繼續(xù)使用兩個for循環(huán)k和m,把areaImageData的data數(shù)組中的對應元素賦值為原圖對應像素的色值,完成賦值后我們就可以通過putImageData方法將像素信息渲染到magnifier畫布上。

const mouseDownHandler = e => {
  // 相對于畫布的坐標
  // ...
  // 待放大區(qū)域的imageData
  // ...
  // 構(gòu)建一個imageData
  // ...
  let count = 0;
  for (let j = 0; j < originSize * zoom; j += zoom) {
    for (let i = 0; i < originSize * zoom; i += zoom) {

      for (let k = j; k < j + zoom; k ++) {
        for (let m = i; m < i + zoom; m ++) {
          const index = (k * originSize * zoom + m) * 4;
          areaImageData.data[index] = originImageData.data[count];
          areaImageData.data[index + 1] = originImageData.data[count + 1];
          areaImageData.data[index + 2] = originImageData.data[count + 2];
          areaImageData.data[index + 3] = originImageData.data[count + 3];

        }
      }
      count += 4;

    }
  }
  mContext.putImageData(areaImageData, 0, 0);
};

至此我們就實現(xiàn)了基本的局部放大,但現(xiàn)在放大鏡不在原圖Canvas的上方,并且放大鏡是一個正方形,我們繼續(xù)簡單優(yōu)化一下。

3. 簡單優(yōu)化

首先因為我對Canvas API還不太熟悉,所以我現(xiàn)在通過css把放大鏡改為圓形,并加上一個陰影box-shadow來優(yōu)化視覺效果。

#magnifier {
  position: absolute;
  box-shadow: 0 0 10px 4px rgba(12, 12, 12, .5);
  border-radius: 50%;
}

然后給兩個Canvas外層加一個div容器,把放大鏡設(shè)置絕對定位,把它放到鼠標坐標的位置,在鼠標移動過程中更新放大鏡的位置。

<div class="canvas-container" ref="containerRef" :style="{width: containerWidth + 'px'}">
  <canvas ref="canvasRef" width="0" height="0"></canvas>
  <canvas ref="magnifier" width="0" height="0" id="magnifier" :style="position"></canvas>
</div>
const position = reactive({
  left: 0,
  top: 0
});
const containerWidth = ref(0);

containerWidth.value = img.width;
// 在鼠標移動過程中更新放大鏡的位置
position.top = (center.y - originSize * zoom / 2) + 'px';
position.left = (center.x - originSize * zoom / 2) + 'px';
.canvas-container {
  position: relative;
  overflow: hidden;
}

這個時候放大鏡的位置就和我們預想的一致了,但是現(xiàn)在還有一個問題,就是放大鏡在原圖的上方,在移動的過程中會看到放大鏡的渲染有點卡頓,這是因為鼠標移動事件是加在原圖Canvas上的,當鼠標懸浮在放大鏡上時,這個移動事件的監(jiān)聽就不連貫了,此時我們可以考慮把鼠標移動監(jiān)聽加改為加在外層容器上,這樣就能看到移動過程中放大鏡的渲染是比較流暢了。

const addEvent = () => {
  containerRef.value.addEventListener('mousemove', mouseDownHandler);
};

至此就完成了簡單的局部放大效果,雖然還存在一些問題吧。

到此這篇關(guān)于JavaScript Canvas實現(xiàn)圖片局部放大鏡效果的文章就介紹到這了,更多相關(guān)JavaScript Canvas圖片局部放大內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 淺析Bootstrap組件之面板組件

    淺析Bootstrap組件之面板組件

    這篇文章主要介紹了淺析Bootstrap組件之面板組件 的相關(guān)資料,需要的朋友可以參考下
    2016-05-05
  • 微信小程序?qū)崿F(xiàn)折疊展開效果

    微信小程序?qū)崿F(xiàn)折疊展開效果

    這篇文章主要為大家詳細介紹了微信小程序?qū)崿F(xiàn)折疊展開效果,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2018-07-07
  • javascript常用代碼段搜集

    javascript常用代碼段搜集

    這篇文章主要記錄了本人搜集的幾段javascript常用代碼段,都是平時項目中需要用到的,需要的朋友可以參考下
    2014-12-12
  • 原生javascript實現(xiàn)的ajax異步封裝功能示例

    原生javascript實現(xiàn)的ajax異步封裝功能示例

    這篇文章主要介紹了原生javascript實現(xiàn)的ajax異步封裝功能,結(jié)合完整實例形式分析了原生javascript實現(xiàn)的ajax異步交互函數(shù)與相應的使用方法,需要的朋友可以參考下
    2016-11-11
  • javascript數(shù)組元素刪除方法delete和splice解析

    javascript數(shù)組元素刪除方法delete和splice解析

    這篇文章主要介紹了javascaipt數(shù)組元素刪除方法delete和splice解析,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2019-12-12
  • js中點擊空白區(qū)域時文本框與隱藏層的顯示與影藏問題

    js中點擊空白區(qū)域時文本框與隱藏層的顯示與影藏問題

    文本框獲得焦點的時在文本框的下方顯示一個浮動層,點擊文本框隱藏浮動層,下面為大家介紹下鼠標點擊時文本框與隱藏層處理問題,感興趣的朋友可以參考下
    2013-08-08
  • 詳解JavaScript中的類型判斷與類型轉(zhuǎn)換

    詳解JavaScript中的類型判斷與類型轉(zhuǎn)換

    這篇文章主要給大家講解一下JavaScript中的類型判斷與類型轉(zhuǎn)換的基本概念和使用方法,對我們的學習JavaScript的類型判斷與轉(zhuǎn)換有一定的幫助,需要的朋友可以參考下
    2023-07-07
  • 基于Javascript倒計時效果

    基于Javascript倒計時效果

    這篇文章主要為大家詳細介紹了基于Javascript倒計時效果,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2016-12-12
  • javascript生成隨機數(shù)方法匯總

    javascript生成隨機數(shù)方法匯總

    實現(xiàn)隨機數(shù)是各種編程語言都很常見的一個編程任務(wù),下面介紹一下在JavaScript如何實現(xiàn)隨機數(shù)。非常的簡單實用的例子奉獻給大家,希望大家能夠喜歡。
    2015-11-11
  • 微信小程序input框中加入小圖標的實現(xiàn)方法

    微信小程序input框中加入小圖標的實現(xiàn)方法

    這篇文章主要介紹了微信小程序input框中加入小圖標的實現(xiàn)方法,非常不錯,具有一定的參考借鑒價值,需要的朋友可以參考下
    2018-06-06

最新評論

建湖县| 东阿县| 崇信县| 南召县| 通榆县| 田东县| 晋宁县| 中牟县| 紫金县| 揭西县| 建瓯市| 孙吴县| 桐庐县| 工布江达县| 大名县| 会泽县| 明光市| 东宁县| 平塘县| 侯马市| 宁强县| 临颍县| 富锦市| 沅陵县| 安图县| 宜都市| 两当县| 重庆市| 留坝县| 龙岩市| 益阳市| 鸡西市| 黔西县| 景宁| 肇州县| 琼结县| 探索| 上犹县| 岳阳市| 嘉祥县| 武鸣县|