前言

今天分享一个炫酷的碎片式切图效果,这个其实在自己的之前的博客上有实现过,本人觉得这个效果还是挺炫酷的,这次还是用我们的canvas来实现,代码量不多,但有些地方还是需要花点时间去理解的,需要点数学几何理解能力,老规矩,我们还是先看效果再来看实现步骤。

如果这篇文章有帮助到你,️关注+点赞️鼓励一下作者,文章公众号首发,关注 前端南玖 第一时间获取最新文章~

需求分析

从上面我们看到图片在切换的时候其实是一个一个的小碎片慢慢从点击位置往外扩散开来,这一个个小碎片,在页面中其实就是一个个的小方块。这里的难点在于如何将一张完整的图片切割成一个一个的小方块分别进行渲染,还有就是这个棱形图案的位置确定。

  • 切割:这里我们可以以坐标系的形式来进行切割,每一个方块都对应着它们自己在坐标系中的位置(x, y)
  • 绘制:这里的重点在于drawImage方法
  • 棱形扩散:这里需要点数学几何理解能力,后面作图理解

实现过程

坐标系

在实现之前,我们先来理解一个概念:坐标系

注意:这里所说的坐标系不是我们数学中的坐标系,但两者又有些类似,不同点在于两者的原点位置以及y轴的方向不同。

切割

这一步主要是为了确定每一个单元格的大小,单元格的长宽最好不要是最大公约数或最小公约数,因为过大效果不够炫,过小性能会有压力。

我这里画板长宽为 800 * 530 ,选取 16 * 15 为单元尺寸,即整个画布由 50 * 35 共 1750 个单元格组成。切割分完单元格之后我们需要先计算一些基本的参数备用。

this.imgW = 800; // 图片原始宽
this.imgH = 530; // 图片原始高 this.conW = 800; // 画布宽
this.conH = 530; // 画布高 this.dw = 16; // 单元格宽
this.dh = 15; // 单元格高 this.I = this.conH / this.dh; //单元行数
this.J = this.conW / this.dw; // 单元列数 this.DW = this.imgW / this.J; // 原图单元宽
this.DH = this.imgH / this.I; // 原图单元高

行数 = 画布高度 / 单元格高度;列数 = 画面宽度 / 单元格宽度

绘制

本次绘制的重点在于drawImage这个方法,我们可以先来了解一下这个方法的参数及功能

drawImage

drawImage(image, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight)

这个方法一共有9个参数,作用是在画布上绘制图像。看到这么多参数是不是已经被劝退了,哈哈

  • image:绘制到上下文的元素。允许任何的画布图像源,例如:HTMLImageElementSVGImageElementHTMLVideoElementHTMLCanvasElementImageBitmapOffscreenCanvasVideoFrame
  • sx:(可选)需要绘制到目标上下文中的,image 的矩形(裁剪)选择框的左上角 X 轴坐标。可以使用 3 参数或 5 参数语法来省略这个参数。
  • s y:(可选)需要绘制到目标上下文中的,image 的矩形(裁剪)选择框的左上角 Y 轴坐标。可以使用 3 参数或 5 参数语法来省略这个参数。
  • sWidth:(可选)需要绘制到目标上下文中的,image 的矩形(裁剪)选择框的宽度。如果不说明,整个矩形(裁剪)从坐标的 sxsy 开始,到 image 的右下角结束。可以使用 3 参数或 5 参数语法来省略这个参数。使用负值将翻转这个图像。
  • sHeight:(可选)需要绘制到目标上下文中的,image的矩形(裁剪)选择框的高度。使用负值将翻转这个图像。
  • dximage 的左上角在目标画布上 X 轴坐标。
  • dyimage 的左上角在目标画布上 Y 轴坐标。
  • dWidthimage 在目标画布上绘制的宽度。允许对绘制的 image 进行缩放。如果不说明,在绘制时 image 宽度不会缩放。注意,这个参数不包含在 3 参数语法中。
  • dHeightimage 在目标画布上绘制的高度。允许对绘制的 image 进行缩放。如果不说明,在绘制时 image 高度不会缩放。注意,这个参数不包含在 3 参数语法中。

这9个参数我们可以这样来记忆,第一个参数是图像源,接下来的四个参数指的是原图,最后四个参数指的是画布

切割&渲染

这里我们主要是将一张图片切割成一个个的小碎片,是这些碎片拼起来就是一张完整的图片。

class ChipBanner {
constructor() {
this.cvs = document.querySelector("#chip");
this.ctx = this.cvs.getContext("2d");
this.imgList = document.querySelectorAll(".bg");
this.imgIndex = 0;
this.isAnimating = false; this.imgW = 800; //图片原始宽/高
this.imgH = 530; this.conW = 800; //画布宽/高
this.conH = 530; this.dw = 16; //画布单元宽/高
this.dh = 15; this.I = this.conH / this.dh; //单元行/列数
this.J = this.conW / this.dw; this.DW = this.imgW / this.J; //原图单元宽/高
this.DH = this.imgH / this.I;
} init() {
this.ctx.beginPath(); for (let i = 0; i < this.I; i++) {
for (let j = 0; j < this.J; j++) {
this.chipDraw(this.imgList[this.imgIndex], i, j);
}
} this.ctx.closePath();
this.ctx.stroke();
}
drawText() {
this.ctx.font = "150px serif";
this.ctx.strokeStyle = "white";
this.ctx.strokeText("1024", 500, 500);
} chipDraw(img, i, j) {
this.drawText();
//负责绘制,i: 单元行号;j: 单元列号
this.ctx.drawImage(
img,
this.DW * j,
this.DH * i,
this.DW,
this.DH,
this.dw * j,
this.dh * i,
this.dw,
this.dh
);
}
}

这里正确拼出来看到的和正常图片没有任何区别

再来看一张拼错的图

刚开始几何坐标那里没写对,拼出来就成这样了,哈哈,看着就像动画帧卡住的样子。

动画

这里主要是要找出某个点周围棱形范围内的所有点的坐标,然后在清除这些坐标图案的同时,开始绘制下一张图片。

菱形线上的点与坐标的 行号差值的绝对值 + 列号差值的绝对值 = 距离

找出坐标棱形范围内所有的点

countAround(i, j, dst) {
let arr = [];
for (let m = i - dst; m <= i + dst; m++) {
for (let n = j - dst; n <= j + dst; n++) {
if (
Math.abs(m - i) + Math.abs(n - j) == dst &&
m >= 0 &&
n >= 0 &&
m <= this.I - 1 &&
n <= this.J - 1
) {
arr.push({ x: m, y: n });
}
}
}
return arr;
}

清除单元格画布

chipClear(i, j) {
this.ctx.clearRect(this.dw * j, this.dh * i, this.dw, this.dh);
}

合并&动画

start(i, j) {
if (this.isAnimating) return; this.isAnimating = true; this.imgIndex++; if (this.imgIndex > this.imgList.length - 1) this.imgIndex = 0; let _this = this,
dst = 0,
timer = setInterval(() => {
let resArr = _this.countAround(i, j, dst); resArr.forEach((item) => {
_this.chipClear(item.x, item.y); // 清除单元格
_this.chipDraw(_this.imgList[_this.imgIndex], item.x, item.y); // 绘制下一张图片
}); if (!resArr.length) {
clearInterval(timer);
_this.isAnimating = false;
}
dst++;
}, 30);
}

大功告成,这样就实现了一个炫酷的碎片式切图效果了~

最后

喜欢的同学欢迎点个赞呀,想要查看源码的同学快来公众号回复碎片吧~

原文首发地址点这里,欢迎大家关注公众号 「前端南玖」,如果你想进前端交流群一起学习,请点这里

我是南玖,我们下期见!!!

教你用canvas打造一个炫酷的碎片切图效果的更多相关文章

  1. 2019基于Hexo快速搭建个人博客,打造一个炫酷博客(1)-奥怪的小栈

    本文转载于:奥怪的小栈 这篇文章告诉你如何在2019快速上手搭建一个像我一样的博客:基于HEXO+Github搭建.并完成SEO优化,打造一个炫酷博客. 本站基于HEXO+Github搭建.所以你需要 ...

  2. Android一个炫酷的树状图组织架构图开源控件实现过程

    Android一个炫酷的树状图组织架构图开源控件 文章目录 [1 简介] [2 效果展示] [3 使用步骤] [4 实现基本布局流程] [5 实现自由放缩及拖动] [6 实现添加删除及节点动画] [7 ...

  3. 利用UIWebView打造一个炫酷的视频背景视图(OC & Swift)

    http://www.cocoachina.com/ios/20151023/13860.html 2015-10-6更新:适配 Swift2.0 如有需要,可以通过pjin.elvin@gmail. ...

  4. 2019Hexo博客Next主题深度美化 打造一个炫酷博客(2)-奥怪的小栈

    219/8/1 更新 本文转载于:奥怪的小栈 这篇文章告诉你在搭建好博客后,面对网上千篇一律的美化教程怎么才能添加自己独特点,使人眼前一亮. 本站基于HEXO+Github搭建. 所以你需要准备好HE ...

  5. 用Canvas写一个炫酷的时间更新动画玩玩

    正文必须要写点什么...   // '; var WINDOW_WIDTH = 913; var WINDOW_HEIGHT = 400; var RADIUS = 7; //球半径 var NUMB ...

  6. canvas的进阶 - 学习利用canvas做一个炫酷的倒计时功能

    先给大家贴一张图片,因为我不会上传视频( ̄□ ̄||) ,请大家谅解了~  如果有知道怎么上传视频的大神还请指点指点 ^_^ ~ 然后看一下代码: html部分 :  <!DOCTYPE html ...

  7. vue 写一个炫酷的轮播图

    效果如上图: 原理: 1.利用css 的 transform 和一些其他的属性,先选五张将图片位置拍列好,剩余的隐藏 2.利用 js 动态切换类名,达到切换效果 css代码如下 .swiper-cer ...

  8. 使用CoordinatorLayout打造各种炫酷的效果

    使用CoordinatorLayout打造各种炫酷的效果 自定义Behavior -- 仿知乎,FloatActionButton隐藏与展示 NestedScrolling 机制深入解析 一步步带你读 ...

  9. 一个炫酷的flash网站模板

    这是一个炫酷的flash欧美网站模板,它包括首页,公司简介,留言等五个页面,界面转换非常的炫酷!他还有时间.全屏.背景音乐开关的功能!有兴趣的朋友可以看看!贴几张网站图片给大家看看! 下载后直接找到s ...

随机推荐

  1. pat链表专题训练+搜索专题

    本期题目包括: 1074:https://pintia.cn/problem-sets/994805342720868352/problems/994805394512134144 1052:http ...

  2. vue中axios配置代理的俩种方式及优缺点

    概述:Axios 是一个基于 promise 的 HTTP 库,可以用在浏览器和 node.js 中 当我们使用vue向服务器发送AJAX请求时,我们会遇到跨域问题,一般跨域的解决方案有俩种,一种是官 ...

  3. Luogu1655 小朋友的球 (组合数学,第二类斯特林数,高精)

    我bingoyes再高精用STL就饿死,死外边! string真的爽... 斯特林数模板题:\(S(n,m) = S(n-1,m-1)+S(n-1,m)*n\) #include <iostre ...

  4. Spring源码 10 IOC refresh方法5

    本文章基于 Spring 5.3.15 Spring IOC 的核心是 AbstractApplicationContext 的 refresh 方法. 其中一共有 13 个主要方法,这里分析第 5 ...

  5. 在使用amoeba连接数据库时,报错java.lang.Exception: poolName=slaves, no valid pools

    项目场景:Mysql 实现数据库读写分离 搭建3台MySQL服务器,完成主从复制,搭建一台amoeba服务器,完成MySQL的读写分离 问题描述: 问题1. 在服务搭建完毕后,利用客户机连接amoeb ...

  6. 使用 Vue.js 框架后的感想

    前言 用 Vue 已经有段时间了,把自己的所想所悟写下来,每一个想法都是非常宝贵的,记录成为生活,记录成为习惯. 简化开发 Vue 是可以辅助前端工程师开发 Web App 的一种框架,它节省很多时间 ...

  7. STC8H开发(十六): GPIO驱动XL2400无线模块

    目录 STC8H开发(一): 在Keil5中配置和使用FwLib_STC8封装库(图文详解) STC8H开发(二): 在Linux VSCode中配置和使用FwLib_STC8封装库(图文详解) ST ...

  8. 使用Python的selenium库制作脚本,支持后台运行

    本文介绍如何使用Python的selenium库制作脚本.概念:       Selenium是一个用于测试网站的自动化测试工具,支持各种浏览器包括Chrome.Firefox.Safari等主流界面 ...

  9. (已解决)Adobe Creative Cloud 安装 Acrobat PDF 报错 DW071 DW003

    今天安装 Adobe Acrobat pdf 阅读器报错了,错误为 Exit Code: 7 Please see specific errors below for troubleshooting. ...

  10. RTMP播放器开发填坑之道

    好多开发者提到,在目前开源播放器如此泛滥的情况下,为什么还需要做自研框架的RTMP播放器,自研和开源播放器,到底好在哪些方面?以下大概聊聊我们的一点经验,感兴趣的,可以关注 github: 1. 低延 ...