demo实现:线上效果
——————————————————————————
↑↑↑以上正文 = v = ↑↑↑
——————————————————————————
↓↓↓以下废话 =。= ↓↓↓
——————————————————————————
组里一个中台项目,参考阿里云腾讯云那种,
组长看了腾讯云首页觉得它的banner有流光效果(或者叫飞线)非常之高大上,
让我也给整一个。
可能是我之前硬着头皮从无到有做了一个数据大屏的缘故,组长对我有着盲目的期待,
作为一个小小的前端实习生,我——
以下正文:
首先,f12观察banner,发现一个图片地址。
输入地址得到一张图片:
我原本以为整个banner都是用canvas画的,没想到是由一张底图+一个canvas组成的。
这样难度就低了很多。
然后尝试能不能自己做。
我的思考是这个流光轨迹像一条透明度从1到0的线段。
改变线段的坐标使线段发生移动,看起来就像是需求那样。
根据想法动手开始做。
操作过程中发现一条透明度从1到0的线段=一条线段+一个透明度从1到0的渐变覆盖,
所以改变线段坐标的同时也要改变渐变覆盖的坐标。
做出来的结果是这样的,有点像,但是有些时候会一卡一卡的,还不能自如拐弯。
附上代码:
drawCanvas() {
let c = document.getElementById("myCanvas");
let ctx = c.getContext("2d");
let start = 450;
function f() {
ctx.clearRect(0, 0, 900, 500);
ctx.beginPath();
ctx.moveTo(start - 50, start - 50);
ctx.lineTo(start, start);
let gradient = ctx.createLinearGradient(start - 50, 0, start, 0);
gradient.addColorStop(0, "rgba(0, 243, 226,1)");
gradient.addColorStop(1, "rgba(0, 243, 226,0)");
ctx.lineWidth = 4;
ctx.lineCap = "round";
ctx.strokeStyle = gradient;
ctx.stroke();
ctx.closePath();
if (start <= 0) {
start = 450;
} else {
start -= 10;
}
setTimeout(function () {
f();
}, 100);
}
f();
},
这个样子肯定不行的。
但是我也想不出别的办法了。
对canvas所知甚少,就大二的时候学过前端html/css,老师教的以静态展示页面为主,没有什么业务逻辑,js都没写过几句。
就以上这么简单的代码也是边看w3c的canvas参考手册边写的。
(7月份实习以来才学的js,学的同时还要立马付诸应用,赶鸭子上架,太不容易了TTvTT)
百度大法——启动,搜索“canvas 流光”、"canvas 特效"关键字,看到了很多别人做的很炫酷的特效。
沉迷。(幻想以后我也能云淡风轻的做出这些东西!!!)
浏览了很多页面和文章,终于找到一个跟需求有点像的。
关键页面1:https://www.jianshu.com/p/3241494c7207?utm_campaign=maleskine&utm_content=note&utm_medium=seo_notes&utm_source=recommendation
文章底部有个参考页面,点进去
获得关键页面2:https://segmentfault.com/a/1190000008664249
这个教程的代码用的typescript,我还没接触过,语法看起来跟以前学的c#有点像。
这两个关键页面主要让我知道了我之前思考的方向有错,移动的是应该是点而不是线。
点移动所经过的路径变成了一条“线”或者说是"轨迹"。
继续搜索,得到关键页面3:
https://segmentfault.com/a/1190000008560571
!!!
这个好像我数据大屏中间的地图上代表各地市的小圆点!
是拿echarts做的没错!然鹅我并不知道它的实现原理…
部分数据大屏:
。
。
。
原来我要找的东西近在眼前
。
。
。
这个流光效果不就是地图上的飞线吗?!
关键页面3参考代码:
终于有头绪了,不用东找找西找找了。
在讨论区看到大佬之前的回复里有git地址,
打开大佬的git地址,
找到相关文件
↓
看到一个熟悉的字段——requestAnimationFrame(划重点)
↓
其实这个字段或者说是方法在关键页面1、关键页面2中都出现过,但是并没有引起我的深入了解
↓
但是三个关键页面都出现了这个方法,说明它真的是关键!!
↓
继续搜索requestAnimationFrame
↓
关键页面4出现!
http://www.cnblogs.com/onepixel/p/7078617.html
终于知道了requestAnimationFrame是什么有什么用处优点在哪了!
(埋头野区一顿刷,苟发育苟到如今,终于可以出来gank了!!)
结合关键页面3,4、canvas参考手册和需求(仔细观察腾讯云首页banner),
我最终的实现代码如下:
<div class="sciBg">
<div style="margin: 0 auto;width: 900px">
<canvas id="myCanvas4" width="900" height="500" style="border:1px solid #fff;"></canvas>
</div>
</div>
<style>
.sciBg {
background: url(../../assets/cttest/sciBg1.jpg) center no-repeat;
background-size: 1920px 500px;
width: 100%;
height: 500px;
}
</style>
drawCanvas4() {
let c = document.getElementById("myCanvas4");
let context = c.getContext("2d");
let width = 900;//画布宽度
let height = 500;//画布高度
let fPoints = [{x: 452, y: 410,r:1.5}, {x: 452, y: 410,r:1.5},{x:368,y:0,r:2},{x:536,y:0,r:2}];//初始点坐标
function drawCircle() {
for (let i = 0; i < fPoints.length; i++) {
context.lineWidth = 0; //线条宽度-空心圆
// context.strokeStyle = 'rgba(2, 179, 253,0.02)'; //颜色
context.shadowBlur = 0;// 设置或返回用于阴影的颜色
context.shadowColor = 'rgba(2, 179, 253,1)'; // 设置或返回用于阴影的模糊级别
context.fillStyle = 'rgba(2, 179, 253,1)';//填充颜色-实心圆
context.fill();//画实心圆
context.beginPath();
context.arc(fPoints[i].x, fPoints[i].y, fPoints[i].r, 0, Math.PI * 2);
context.closePath();
}
if (fPoints[0].y > 265) {
fPoints[0].x -= 2;
fPoints[0].y -= 1.15;
fPoints[1].x += 2;
fPoints[1].y -= 1.15;
} else if (fPoints[0].y > 0) {
fPoints[0].y -= 2.5;
fPoints[1].y -= 2.5;
} else if (fPoints[0].y < 0) {
fPoints = [{x: 452, y: 410,r:1.5}, {x: 452, y: 410,r:1.5},{x:368,y:0,r:2},{x:536,y:0,r:2}];//初始点坐标
}
if(fPoints[2].y < 264){
fPoints[2].y += 2;
fPoints[3].y += 2;
}else if(fPoints[2].y<310){
fPoints[2].x += 2;
fPoints[2].y += 1.15;
fPoints[3].x -= 2;
fPoints[3].y += 1.15;
}
}
function render() {
//默认值为source-over
let prev = context.globalCompositeOperation;
//只显示canvas上原图像的重叠部分
context.globalCompositeOperation = 'destination-in';
//设置主canvas的绘制透明度
context.globalAlpha = 0.9;
//这一步目的是将canvas上的图像变的透明
context.fillRect(0, 0, width, height);
//在原图像上重叠新图像
context.globalCompositeOperation = prev;
//在主canvas上画新圆
drawCircle();
if (width !== 0) {
//在动画没有结束前,递归渲染
window.requestAnimationFrame(render);
}
}
window.requestAnimationFrame(render);
}
最终实现效果:
(白色框框是用来标注canvas位置大小的)
项目内应用效果:查看更多效果
知识点:在窗口大小改变时,banner大小不发生改变,窗口展示banner最中间的内容。
所以我在计算点的运动时都是固定数字(不用管自适应!方便很多!)
ps:偷偷说一句,我觉得腾讯云首页也是这样固定像素移动的,因为观察到在窗口小于某个固定值时动效会消失不见,而背景图会变成自适应窗口大小。
为了写这篇文章,严谨如我又去调整窗口大小看了下,发现这个固定值是770(为什么不是777呢!)
正文完毕
以下是总结反思:
当天做出来的时候很开心,让组长夸我,但是觉得自己还是有很多不足。
做这样一个看起来很简单的需求做了一天,期间浪费了很多时间在找资料上面,过滤了很多无效页面。
这都是因为自己是js零基础的缘故,
对那些系统学习过js和canvas,其中各种参数方法都信手拈来的人而言,花这么久时间才完成这个需求应该是不可思议的吧。
当天晚上失眠了,放下了看小说打游戏的手,在知乎上百度上找前端的书单。
找到很多,这里就不一一列举了。
原来前端有这么多书!
原来有这么多知识都是我不了解的!
原来requestAnimationFrame这种方法书里都有详细介绍!
我要是早看了书,就不会开始这么漫长且漫无目的的搜索了。
真的要多读书!!!
虽然为了实现各种各样的需求我也会接触到很多自己原本不会的东西,但是耗费的时间和精力真的不值当。
“要多读书。”
“北海,我只能告诉你那以前要多读书。”
↓
↓
↓
↓
↓
↓
↓
题外话:
实习5月份结束,算一算时间,全职实习也快一年了,整个大四都泡在杭州了。
都说金三银四招聘月,可是群里的小伙伴投简历找工作也是困难重重,可能是因为今年行业不景气,也可能是因为我们学校不好叭。
叹气。
跟我同公司同组同班同学java岗的,2月份走了,说要去追逐技术和梦想。
现在他有点疲惫:
大小公司都在招2020年的实习生了。
何去何从鸭,
我也有点迷茫了。