Dieses Mal zeige ich Ihnen, wie Sie in H5 einen fragmentierten Bildwechsel durchführen. Was sind die Vorsichtsmaßnahmen für den fragmentierten Bildwechsel?
Vorwort
Alte Regel, Quellcode zuerst. Der Bildbereich ist anklickbar und die Animation beginnt an der angeklickten Position.
Ursprünglich habe ich diesen Effekt vor 3 Jahren gemacht, aber ich dachte, er sei mit unzähligen p-Tags gemacht worden. Die Leistung war ein Problem und er konnte auf dem mobilen Endgerät überhaupt nicht ausgeführt werden. Kürzlich wollte ich aus einer Laune heraus lernen, wie man es mit reinem CSS implementiert, und zwar von einem Meister, der sehr gut darin ist, CSS zu erstellen. Ich hatte jedoch keine andere Wahl, als aufzugeben, weil ich nicht über genügend Fähigkeiten verfügte Ich habe mich für die Verwendung von Leinwand entschieden, um es zu vervollständigen.
1. Bereiten Sie zunächst mehrere Bilder in der gleichen Größe vor sind alle 1920 * 1080 (Hinweis: Die Größe hier ist die Größe des Originalbilds, nicht die Größe, die auf der Seite über CSS angezeigt wird). Fügen Sie diese Bilder zur späteren Verwendung zu einem versteckten Element in HTML hinzu, um sie später zu verwenden.
<p class='hide'> <img class='img' src='./images/a.jpg' /> <img class='img' src='./images/b.jpg' /> <img class='img' src='./images/c.jpg' /> <img class='img' src='./images/d.jpg' /> <img class='img' src='./images/e.jpg' /> </p>
.hide { display: none; }
2. Fügen Sie eine Leinwand in benutzerdefinierter Größe in HTML ein, muss jedoch das gleiche Seitenverhältnis wie die Bildressource sicherstellen. In diesem Beispiel beträgt die Leinwandgröße 800 * 450.
<canvas id="myCanvas" width="800" height="450">您的浏览器不支持 CANVAS</canvas>
3. Der Grundcode lautet wie folgt: Rufen Sie zunächst das Kontextobjekt der Leinwand ab und zeichnen Sie schließlich das Bild.
var ctx = document.querySelector('#myCanvas').getContext('2d'), img = document.querySelector('.img'); ctx.beginPath(); ctx.drawImage(img, 0, 0); ctx.closePath(); ctx.stroke();
Erfolg
Ich glaube, viele Leute werden bald verstehen, dass es sich um eine Kombination mehrerer kleiner Einheiten handelt. Jede Einheit ist nur für die kleine Zeichnung verantwortlich Teile eines Bildes, die sich schließlich zu einem Gesamtbild zusammenfügen.
Bevor wir den Quellcode im Detail erklären, schauen wir uns zunächst die Verwendung der Funktion „drawImage“ in Canvas an. Da wir 9 Parameter dieser Funktion verwenden müssen und es viele Parameter gibt, müssen wir die Bedeutung dieser Parameter und der Referenzobjekte im Auge behalten.
context.drawImage(img, sx, sy, swidth, sheight, x, y, width, height);
· img: Gibt das zu verwendende Bild, die Leinwand oder das Video an
· sx: Die x-Koordinatenposition, an der der Schnitt beginnt
· sy: Die Startpunkt des Schnitts Y-Koordinatenposition
· Breite: Breite des Schnittbildes
· Höhe: Höhe des Schnittbildes
· x: x-Koordinate der Platzierung des Position des Bildes auf der Leinwand
· y: die Y-Koordinatenposition des Bildes, das auf der Leinwand platziert werden soll
· Breite: die Breite des zu verwendenden Bildes
· Höhe: Die Höhe des zu verwendenden Bildes
Ich glaube, dass es trotz der Auflistung der oben genannten Parameter immer noch leicht zu Verwirrung während der Entwicklung kommen kann. Hier ist ein kleiner Tipp, der Ihnen empfohlen wird: Zusätzlich zum ersten img-Parameter gibt es 8 Parameter. Das Größenreferenzobjekt der ersten 4 Parameter ist das Originalbild, dh 1920 * 1080 4 Parameter sind Canvas, also 800 * 450.
Bedenken Sie diese Formel und es wird nicht leicht sein, beim Schreiben schwindelig zu werden.
Gitter
Gitter werden verwendet, um die Größe einer Einheit im Canvas zu bestimmen. Das Wichtigste ist, dass die Einheitsgröße sein kann Durch die Länge der beiden Seiten teilbar, d. h. die Einheitsgröße sollte der gemeinsame Teiler der Breite und Höhe des Bildschirms sein. Der gemeinsame Teiler ist nicht unbedingt der größte gemeinsame Teiler oder der kleinste gemeinsame Teiler, denn wenn er zu groß ist, ist der Effekt nicht cool genug, und wenn er zu klein ist, gerät die Leistung unter Druck.
Nehmen Sie die Größe der Zeichenfläche in diesem Beispiel als 800 * 450 an. Ich wähle hier 25 * 25 als Einheitsgröße, das heißt, die gesamte Leinwand besteht aus 32 * 18, also insgesamt 576 Zellen. Nachdem wir das Gitter geteilt haben, müssen wir zunächst einige grundlegende Parameter berechnen.
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;
Die ersten drei Parametersätze wurden bereits von uns festgelegt. Bei der Berechnung des vierten Zeilen-/Spaltensatzes ist Folgendes zu beachten: 行数 = 画布高度 / 单元格高度;列数 = 画面宽度 / 单元格宽度
. Wenn dies umgekehrt ist, werden Sie später in Schwierigkeiten geraten. Die letzte DW/DH-Gruppe wird vergrößert und in die Zellengröße des Originalbilds konvertiert, die später zum Zuschneiden des Bilds verwendet wird.
Zeichnen
Schritt für Schritt zeichnen wir zuerst die Zelle in der oberen linken Ecke. Da sowohl 原图裁切位置
als auch 画布摆放位置
(0, 0) sind, ist es das einfachste.
ctx.drawImage(img, 0, 0, DW, DH, 0, 0, dw, dh);
Erfolgreich. Jetzt müssen wir also die Bilder in Zeile 2 und Spalte 3 zeichnen. Wie sollen wir sie schreiben?
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 阶段,有空的话会将该效果插件化,方便有兴趣的朋友使用。
相信看了本文案例你已经掌握了方法,更多精彩请关注php中文网其它相关文章!
推荐阅读:
H5的多线程(Worker SharedWorker)使用详解
Das obige ist der detaillierte Inhalt vonSo führen Sie den fragmentierten Bildwechsel in H5 durch. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!