首頁 web前端 H5教程 html5碎片式圖片切換製作方法詳解

html5碎片式圖片切換製作方法詳解

Aug 07, 2017 pm 03:02 PM
h5 html5 製作方法

本篇文章主要介紹了html5教你做酷炫的碎片式圖片切換(canvas) ,具有一定參考價值,有興趣的可以了解一下

前言

老規矩,先上原始碼。圖片區域是可以點擊的,動畫會從點擊的位置開始發生。

本來這個效果是我3年前做的,只是當是用無數個 p 標籤完成的,性能比較成問題,在移動端完全跑不動。最近心血來潮想學習一個做 CSS 效果很厲害的大神用純 CSS 實現,無奈功力不夠只能放棄,最終選擇用 canvas 來完成了。

準備工作

1. 先準備相同尺寸的圖片若干張,本例圖片尺寸皆為1920 * 1080(註:這裡的尺寸是原始圖片的尺寸,不是透過css 顯示在頁面上的尺寸)。為方便之後的使用,將這些圖片加入 HTML 中一隱藏元素裡備用。


<p class=&#39;hide&#39;>
    <img class=&#39;img&#39; src=&#39;./images/a.jpg&#39; />
    <img class=&#39;img&#39; src=&#39;./images/b.jpg&#39; />
    <img class=&#39;img&#39; src=&#39;./images/c.jpg&#39; />
    <img class=&#39;img&#39; src=&#39;./images/d.jpg&#39; />
    <img class=&#39;img&#39; src=&#39;./images/e.jpg&#39; />
</p>
登入後複製


.hide {
    display: none;
}
登入後複製

2. 在HTML 中插入canvas 畫布,尺寸自定,但必須保證與圖片資源寬高比一致。本例中畫布尺寸為 800 * 450。


<canvas id="myCanvas" width="800" height="450">您的浏览器不支持 CANVAS</canvas>
登入後複製

3. 基礎程式碼如下,首先取得畫布的 context 物件;其次取得圖片物件;最後透過 drawImage 方法將圖片繪製出來。


var ctx = document.querySelector(&#39;#myCanvas&#39;).getContext(&#39;2d&#39;),
    img = document.querySelector(&#39;.img&#39;);

ctx.beginPath();
ctx.drawImage(img, 0, 0);
ctx.closePath();
ctx.stroke();
登入後複製

實現

#相信很多人看完很快就能明白,這是用若干個小的單元組合在一起,每個單元只負責繪製圖片的一小部分,最後拼在一起就成了一張完整的圖片。

那麼在具體講解原始碼之前,先讓我們來複習一下 canvas 中 drawImage 函數的用法。由於我們需要用到函數9個參數的情況,參數較多,需要牢記這些參數的意義和參考的物件。


context.drawImage(img, sx, sy, swidth, sheight, x, y, width, height);
登入後複製

· img:規定要使用的圖片、畫布或影片

· sx:開始剪下的x 座標位置

# · sy:開始剪切的y 座標位置

· swidth:被剪切圖像的寬度

· sheight:被剪切圖像的高度

· x:在畫布上放置圖像的x 座標位置

· y:在畫布上放置圖像的y 座標位置

· width:要使用的圖像的寬度

· height:要使用的圖像的高度

我相信即使將上面這些參數羅列出來,在開發的時候還是很容易暈。這裡推薦給大家一個小技巧:除去第一個img 參數以外還有8個參數,其中前4個參數的尺寸參考的物件是原圖,即1920 * 1080;後4個參數的尺寸參考的物件是畫布,即800 * 450。

記住這個口訣,在實際寫作的時候就不容易暈了。

分格

分格是要定下在畫布中一個單元的尺寸,最重要的是單元尺寸可以被畫面的兩條邊長所整除,即單元尺寸應為畫面寬高的公約數。公約數不一定是最大公約數或最小公約數,因為過大效果不夠炫,過小性能會有壓力。

以本例畫板 800 * 450 的尺寸為例,我在此選取 25 * 25 為單元尺寸,即整個畫布由 32 * 18 共 576 個單元格組成。分好格之後我們需要先計算一些基本的參數備用。


var imgW = 1920, //图片原始宽/高
    imgH = 1080;

var conW = 800, //画布宽/高
    conH = 450;

var dw = 25, //画布单元格宽/高
    dh = 25;

var I = conH / dh, //单元行/列数
    J = conW / dw;

var DW = imgW / J, //原图单元格宽/高
    DH =imgH / I;
登入後複製

前三組參數是我們之前設定的,需要注意的,在算第四組行/列數時要清楚:行數=畫布高度/ 儲存格高度;列數= 畫面寬度/ 儲存格寬度。如果這點搞反了,後面就蒙逼了。最後一組 DW/DH 是放大換算到原圖上的儲存格尺寸,用於後面裁切圖片使用。

繪製

循序漸進,我們先畫出最左上角的那個單元格。因為其原圖裁切位置畫布擺放位置都是 (0, 0),所以最簡單。


ctx.drawImage(img, 0, 0, DW, DH, 0, 0, dw, dh);
登入後複製

成功了。那現在要繪製第2行,第3列的圖片該怎麼寫呢。


var i = 2,
    j = 3;
ctx.drawImage(img, DW*j, DH*i, DW, DH, dw*j, dh*i, dw, dh);
登入後複製

這裡容易搞混的是:裁剪或擺放的橫座標為單元格寬度* 列號,縱座標為單元格高度* 行號

為了方便,封裝一個負責渲染的純淨函數,其不參與邏輯,只會根據傳入的圖片物件及座標進行繪製。


function handleDraw(img, i, j) {
    ctx.drawImage(img, DW*j, DH*i, DW, DH, dw*j, dh*i, dw, dh);
}
登入後複製

封裝好渲染方法之後,透過行數和列數的雙重循環把整個圖片渲染出來。


ctx.beginPath();

for (var i = 0; i < I; i ++) {
    for (var j = 0; j < J; j ++) {
        handleDraw(img, i, j);
    }
}

ctx.closePath();
ctx.stroke();
登入後複製

完美~。其实到这一步核心部分就完成了,为什么呢?因为此时这幅图片已经是由几百个单元格拼合而成的,大家可以凭借天马行空的想像赋予其动画效果。

在分享自己的动画算法之前,先给大家看下拼错是什么样的~

还有点炫酷~

动画算法

下面分享下我的动画算法。Demo 里的效果是怎么实现的呢?

由于在画布的网格上,每个单元格都有行列号(i,j)。我希望能给出一个坐标(i,j)后,从近到远依次得出坐标周围所有菱形上的点。具体如下图,懒得做图了~

比如坐标为(3,3)

距离为 1 的点有(2,3)、(3,4)、(4,3)、(3,2)共4个;

距离为 2 的点有(1,3)、(2,4)、(3,5)、(4,4)、(5,3)、(4,2)、(3,1)、(2,2)共8个;

........

求出这一系列点的算法也很容易, 因为菱形线上的点与坐标的 行号差值的绝对值 + 列号差值的绝对值 = 距离,具体如下:


function countAround(i, j, dst) {
    var resArr = [];
    for (var m = (i-dst); m <= (i+dst); m++) {
        for (var n = (j-dst); n <= (j+dst); n++) {
            if ((Math.abs(m-i) + Math.abs(n-j) == dst)) {
                resArr.push({x: m, y: n});
            }
        }
    }
    return resArr;
}
登入後複製

该函数用于给定坐标和距离(dst),求出坐标周围该距离上的所有点,以数组的形式返回。但是上面的算法少了边界限制,完整如下:


countAround(i, j, dst) {
    var resArr = [];
    for (var m = (i-dst); m <= (i+dst); m++) {
        for (var n = (j-dst); n <= (j+dst); n++) {
            if ((Math.abs(m-i) + Math.abs(n-j) == dst) && (m >=0 && n >= 0) && (m <= (I-1) && n <= (J-1))) {
                resArr.push({x: m, y: n});
            }
        }
    }
    return resArr;
}
登入後複製

这样我们就有了一个计算周围固定距离上所有点的纯净函数,接下来就开始完成动画渲染了。

首先编写一个用于清除单元格内容的清除函数,只需要传入坐标,就能清除该坐标单元格上的内容,等待之后绘制新的图案。


handleClear(i, j) {
    ctx.clearRect(dw*j, dh*i, dw, dh);
}
登入後複製

anotherImg 为下一张图,最后通过 setInterval 不断向外层绘制新的图片完成碎片式的渐变效果。


var dst = 0,
intervalObj = setInterval(function() {
    var resArr = countAround(i, j, dst);

    resArr.forEach(function(item, index) {
        handleClear(item.x, item.y);
        handleDraw(anotherImg, item.x, item.y);
    });
        
    if (!resArr.length) {
        clearInterval(intervalObj);
    }
    dst ++;
}, 20);
登入後複製

当 countAround 返回的数组长度为0,即到坐标点该距离上的所有点都在边界之外了,就停止定时器循环。至此所有核心代码已经介绍完毕,具体实现请查看源码。

现在给定画布上任意坐标,就能从该点开始向四周扩散完成碎片式的图片切换效果。

在自动轮播时,每次从预设好的8个点(四个角及四条边的中点)开始动画,8个点坐标如下:


var randomPoint = [{
    x: 0,
    y: 0
}, {
    x: I - 1,
    y: 0
}, {
    x: 0,
    y: J - 1
}, {
    x: I - 1,
    y: J - 1
}, {
    x: 0,
    y: Math.ceil(J / 2)
}, {
    x: I - 1,
    y: Math.ceil(J / 2)
}, {
    x: Math.ceil(I / 2),
    y: 0
}, {
    x: Math.ceil(I / 2),
    y: J - 1
}]
登入後複製

点击时,则算出点击所在单元格坐标,从该点开始动画。


function handleClick(e) {
    var offsetX = e.offsetX,
      offsetY = e.offsetY,
      j = Math.floor(offsetX / dw),
      i = Math.floor(offsetY / dh),
    
    //有了i, j,开始动画...    
},
登入後複製

目前该效果只是 Demo 阶段,有空的话会将该效果插件化,方便有兴趣的朋友使用。

以上是html5碎片式圖片切換製作方法詳解的詳細內容。更多資訊請關注PHP中文網其他相關文章!

本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

HTML 中的表格邊框 HTML 中的表格邊框 Sep 04, 2024 pm 04:49 PM

HTML 表格邊框指南。在這裡,我們以 HTML 中的表格邊框為例,討論定義表格邊框的多種方法。

HTML 中的巢狀表 HTML 中的巢狀表 Sep 04, 2024 pm 04:49 PM

這是 HTML 中巢狀表的指南。這裡我們討論如何在表中建立表格以及對應的範例。

HTML 左邊距 HTML 左邊距 Sep 04, 2024 pm 04:48 PM

HTML 左邊距指南。在這裡,我們討論 HTML margin-left 的簡要概述及其範例及其程式碼實作。

HTML 表格佈局 HTML 表格佈局 Sep 04, 2024 pm 04:54 PM

HTML 表格佈局指南。在這裡,我們詳細討論 HTML 表格佈局的值以及範例和輸出。

HTML 輸入佔位符 HTML 輸入佔位符 Sep 04, 2024 pm 04:54 PM

HTML 輸入佔位符指南。在這裡,我們討論 HTML 輸入佔位符的範例以及程式碼和輸出。

HTML 有序列表 HTML 有序列表 Sep 04, 2024 pm 04:43 PM

HTML 有序列表指南。在這裡我們也分別討論了 HTML 有序列表和類型的介紹以及它們的範例

HTML onclick 按鈕 HTML onclick 按鈕 Sep 04, 2024 pm 04:49 PM

HTML onclick 按鈕指南。這裡我們分別討論它們的介紹、工作原理、範例以及各個事件中的onclick事件。

在 HTML 中移動文字 在 HTML 中移動文字 Sep 04, 2024 pm 04:45 PM

HTML 中的文字移動指南。在這裡我們討論一下marquee標籤如何使用語法和實作範例。

See all articles