Maison > interface Web > Tutoriel H5 > Comment effectuer un changement d'image fragmentée dans H5

Comment effectuer un changement d'image fragmentée dans H5

php中世界最好的语言
Libérer: 2018-03-26 17:36:07
original
3114 Les gens l'ont consulté

Cette fois, je vais vous montrer comment effectuer un changement d'image fragmentée en H5. Quelles sont les précautions pour effectuer un changement d'image fragmentée en H5. Voici un cas pratique, jetons un coup d'œil.

Avant-propos

Ancienne règle, le code source d'abord. La zone de l'image est cliquable et l'animation démarrera à partir de la position cliquée.

À l'origine, j'ai créé cet effet il y a 3 ans, mais je pensais que c'était fait avec d'innombrables balises p. Les performances étaient un problème et il ne pouvait pas du tout fonctionner sur le terminal mobile. Récemment, sur un coup de tête, j'ai voulu apprendre à utiliser du CSS pur pour l'implémenter auprès d'un maître très doué en création de CSS. Cependant, je n'ai eu d'autre choix que d'abandonner car je n'avais pas assez de compétences, et finalement. a choisi d'utiliser une toile pour le compléter.

Travail de préparation

1. Préparez d'abord plusieurs images de même taille. Dans cet exemple, les tailles d'image. sont tous 1920 * 1080 (Remarque : la taille ici est la taille de l'image originale, pas la taille affichée sur la page via CSS). Pour une utilisation ultérieure, ajoutez ces images à un élément masqué en HTML pour une utilisation ultérieure.

<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>
Copier après la connexion
.hide {
    display: none;
}
Copier après la connexion

2. Insérez le canevas dans HTML, avec une taille personnalisée, mais doit garantir le même rapport hauteur/largeur que la ressource image. Dans cet exemple, la taille du canevas est de 800 * 450.

<canvas id="myCanvas" width="800" height="450">您的浏览器不支持 CANVAS</canvas>
Copier après la connexion

3. Le code de base est le suivant. Tout d'abord, récupérez l'objet contextuel du canevas ; deuxièmement, récupérez l'objet image et enfin dessinez l'image via la méthode drawImage.

var ctx = document.querySelector('#myCanvas').getContext('2d'),
    img = document.querySelector('.img');
ctx.beginPath();
ctx.drawImage(img, 0, 0);
ctx.closePath();
ctx.stroke();
Copier après la connexion

Réussite

Je pense que beaucoup de gens comprendront peu de temps après avoir lu ceci. Il s'agit d'une combinaison de plusieurs petites unités, chaque unité est uniquement responsable du dessin des petits. parties d’une image qui finissent par s’assembler pour créer une image complète.

Alors avant d'expliquer le code source en détail, passons en revue l'utilisation de la fonction drawImage dans Canvas. Puisque nous devons utiliser 9 paramètres de cette fonction et qu’il existe de nombreux paramètres, nous devons garder à l’esprit la signification de ces paramètres et des objets de référence.

context.drawImage(img, sx, sy, swidth, sheight, x, y, width, height);
Copier après la connexion

· img : Spécifie l'image, la toile ou la vidéo à utiliser

· sx : La position de coordonnée x où commence la découpe

· sy : La point de départ de la position de coordonnée y de découpe

· swidth : largeur de l'image découpée

· sheight : hauteur de l'image découpée

· x : coordonnée x de placement du position de l'image sur la toile

· y : la position de coordonnée y de l'image à placer sur la toile

· width : la largeur de l'image à utiliser

· hauteur : la hauteur de l'image à utiliser

Je crois que même si les paramètres ci-dessus sont listés, il est toujours facile de se tromper lors du développement. Voici une petite astuce qui vous est recommandée : en plus du premier paramètre img, il y a 8 paramètres. L'objet de référence de taille des 4 premiers paramètres est l'image originale, soit 1920 * 1080 l'objet de référence de taille du dernier ; 4 paramètres sont Canvas, soit 800 * 450.

N'oubliez pas cette formule et il ne sera pas facile d'avoir le vertige en écrivant.

Grilles

Les grilles sont utilisées pour déterminer la taille d'une unité dans le canevas. Le plus important est que la taille de l'unité puisse être. modifié par l'écran. Divisible par la longueur des deux côtés, c'est-à-dire que la taille de l'unité doit être le diviseur commun de la largeur et de la hauteur de l'écran. Le diviseur commun n'est pas nécessairement le plus grand diviseur commun ou le plus petit diviseur commun, car s'il est trop grand, l'effet ne sera pas assez cool, et s'il est trop petit, les performances seront sous pression.

Prenons la taille du plan de travail dans cet exemple comme 800 * 450. Je choisis ici 25 * 25 comme taille unitaire, c'est-à-dire que la toile entière est composée de 32 * 18, soit un total de 576 cellules. Après avoir divisé la grille, nous devons d’abord calculer certains paramètres de base.

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;
Copier après la connexion

Les trois premiers ensembles de paramètres ont été définis par nos soins auparavant. Il convient de noter que lors du calcul du quatrième ensemble de lignes/colonnes, soyez clair : 行数 = 画布高度 / 单元格高度;列数 = 画面宽度 / 单元格宽度. Si cette situation est inversée, vous aurez des ennuis plus tard. Le dernier groupe de DW/DH est agrandi et converti à la taille de cellule de l'image d'origine, qui est utilisée ultérieurement pour recadrer l'image.

Dessiner

Étape par étape, nous dessinons d'abord la cellule du coin supérieur gauche. Parce que 原图裁切位置 et 画布摆放位置 sont tous deux (0, 0), c'est le plus simple.

ctx.drawImage(img, 0, 0, DW, DH, 0, 0, dw, dh);
Copier après la connexion

Réussi. Nous devons maintenant dessiner les images de la ligne 2 et de la colonne 3. Comment devons-nous les écrire ?

var i = 2,
    j = 3;
ctx.drawImage(img, DW*j, DH*i, DW, DH, dw*j, dh*i, dw, dh);
Copier après la connexion

这里容易搞混的是:裁剪或摆放的横坐标为单元格宽度 * 列号,纵坐标为单元格高度 * 行号

为了方便,封装一个负责渲染的纯净函数,其不参与逻辑,只会根据传入的图片对象及坐标进行绘制。

function handleDraw(img, i, j) {
    ctx.drawImage(img, DW*j, DH*i, DW, DH, dw*j, dh*i, dw, dh);
}
Copier après la connexion

封装好渲染方法之后,通过行数和列数的双重循环把整张图片渲染出来。

ctx.beginPath();
for (var i = 0; i < I; i ++) {
    for (var j = 0; j < J; j ++) {
        handleDraw(img, i, j);
    }
}
ctx.closePath();
ctx.stroke();
Copier après la connexion

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

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

还有点炫酷~

动画算法

下面分享下我的动画算法。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;
}
Copier après la connexion

该函数用于给定坐标和距离(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;
}
Copier après la connexion

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

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

handleClear(i, j) {
    ctx.clearRect(dw*j, dh*i, dw, dh);
}
Copier après la connexion

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);
Copier après la connexion

当 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
}]
Copier après la connexion

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

function handleClick(e) {
    var offsetX = e.offsetX,
      offsetY = e.offsetY,
      j = Math.floor(offsetX / dw),
      i = Math.floor(offsetY / dh),
    
    //有了i, j,开始动画...    
},
Copier après la connexion

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

相信看了本文案例你已经掌握了方法,更多精彩请关注php中文网其它相关文章!

推荐阅读:

H5的window.postMessage与跨域

H5的多线程(Worker SharedWorker)使用详解

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Étiquettes associées:
source:php.cn
Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal