Heim > Artikel > Web-Frontend > Detaillierte Erläuterung der Produktionsmethode für den Wechsel fragmentierter HTML5-Bilder
Dieser Artikel stellt hauptsächlich HTML5 vor, um Ihnen beizubringen, wie man coole fragmentierte Bildwechsel (Leinwand) durchführt. Interessierte können mehr erfahren
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 reines CSS zur Implementierung verwendet, 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.
Vorbereitungsarbeiten
1 Bereiten Sie zunächst mehrere Bilder der gleichen Größe vor. In diesem Beispiel beträgt die Bildgröße 1920 * 1080 (Hinweis : Die Größe hier ist die Größe des Originalbildes, 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 HTML mit benutzerdefinierter Größe ein, muss jedoch mit dem Bild übereinstimmen Ressourcen haben das gleiche Seitenverhältnis. 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: Holen Sie sich zuerst das Kontextobjekt der Leinwand die drawImage-Methode.
var ctx = document.querySelector('#myCanvas').getContext('2d'), img = document.querySelector('.img'); ctx.beginPath(); ctx.drawImage(img, 0, 0); ctx.closePath(); ctx.stroke();
Erreichen
Ich glaube, viele Menschen werden nach der Lektüre schnell verstehen, dass mehrere kleine Einheiten verwendet werden, wenn sie miteinander kombiniert werden Jede Einheit ist nur dafür verantwortlich, einen kleinen Teil des Bildes zu zeichnen und ihn schließlich zu einem vollständigen Bild zusammenzusetzen.
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 mit dem Schneiden begonnen werden soll
· sy: Y-Koordinatenposition, an der die Scherung beginnt
· swidth: Breite des zugeschnittenen Bildes
· sheight: Höhe des zugeschnittenen Bildes
· x : Die x-Koordinatenposition des auf der Leinwand platzierten Bildes
· y: Die y-Koordinatenposition des auf der Leinwand platzierten Bildes
· width: 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 kommt. 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 von uns zuvor festgelegt. Bitte beachten Sie, dass bei der Berechnung des vierten Satzes von Zeilen/Spalten Folgendes klar ist: 行数 = 画布高度 / 单元格高度;列数 = 画面宽度 / 单元格宽度
. 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. Wie sollen wir nun die Bilder in Zeile 2 und Spalte 3 schreiben?
var i = 2, j = 3; ctx.drawImage(img, DW*j, DH*i, DW, DH, dw*j, dh*i, dw, dh);
Was hier leicht verwechselt wird, ist: 裁剪或摆放的横坐标为单元格宽度 * 列号,纵坐标为单元格高度 * 行号
.
Der Einfachheit halber ist eine reine Funktion, die für das Rendern verantwortlich ist, gekapselt. Sie nimmt nicht an der Logik teil und zeichnet nur entsprechend dem eingehenden Bildobjekt und den Koordinaten.
function handleDraw(img, i, j) { ctx.drawImage(img, DW*j, DH*i, DW, DH, dw*j, dh*i, dw, dh); }
Nach der Kapselung der Rendering-Methode wird das gesamte Bild durch eine doppelte Schleife aus Zeilen und Spalten gerendert.
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 阶段,有空的话会将该效果插件化,方便有兴趣的朋友使用。
Das obige ist der detaillierte Inhalt vonDetaillierte Erläuterung der Produktionsmethode für den Wechsel fragmentierter HTML5-Bilder. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!