var can1=document.querySelector('#canvas1'); var ctx1=can1.getContext('2d'); var w=can1.width; var h=can1.height; var texts=["明星", "深爱", "小云", "直到", "永远"]; var font="bold 40px arial" //texts=['I','LOVE','XIAO','YUN']; //font="40px arial" var index=0; var num=1500; var z=Math.sqrt(w*h/1500) var points=[]; var length=1500; var can2=document.createElement('canvas'); can2.width=w; can2.height=h; var ctx2=can2.getContext('2d'); //生成圆点 function setpoints(){ for(var i=0;i<num;i++){ points.push(new setcil(i)); } } function setcil(i){ this.r = Math.round(Math.random() * 255 | 0); this.g = Math.round(Math.random() * 255 | 0); this.b = Math.round(Math.random() * 255 | 0); this.a =Math.random()*1; this.a=this.a.toFixed(2); this.x=(i*z)%w; this.y=(i*z)/w*z; this.offset=Math.random()*600; this.radius=Math.random()*8+0.1; this.state=true; /*ctx1.beginPath(); ctx1.fillStyle='#000'; ctx1.arc(this.x,this.y,this.radius,0,Math.PI*2); ctx1.fill();*/ } //获取文字点的xy var textdata=[]; function settextdata(){ var tx=texts[index]; if(index<texts.length-1){ index+=1; }else{ index=0; } //设置背景写字 ctx2.fillStyle="#000"; ctx2.fillRect(0,0,w,h); ctx2.fillStyle="#f00"; ctx2.font=font; //ctx1.textAlign="center"//文字水平居中对齐 ctx2.fillText(tx,20,60); //获取rgba数组值 得到红字的点x y var imgdata=ctx2.getImageData(0,0,w,h).data; textdata=[]; for(var i=0;i<imgdata.length;i+=4){ if(imgdata[i] !=0 ) { var a={ x:i/4%w*8, y:i/4/w*8 } textdata.push(a); /*ctx2.beginPath(); ctx2.fillStyle='#fff'; ctx2.arc(a.x,a.y,1,0,Math.PI*2); ctx2.fill();*/ } } console.log(textdata.length) if(textdata.length<1500){ length=textdata.length; }else{ length=1500; } getdx(); } //计算圆点最终显示的dx dy function getdx(){ for(var i=0;i<points.length;i++){ var pa=points[i]; var txts=[]; var ind=0; if(textdata.length){ for(var n=0;n<textdata.length;n++){ var po=textdata[n]; txts[n]=Math.sqrt( (pa.x-po.x)*(pa.x-po.x) + (pa.y-po.y)*(pa.y-po.y) ); if(n>0){ if(txts[n]<=txts[ind]){ ind=n; } } } points[i].dx=textdata[ind].x; points[i].dy=textdata[ind].y; textdata.splice(ind,1) } } } function draw(){ var now=Date.now(); ctx1.globalCompositeOperation = "source-over"; //设置填充为黑色并绘制全屏矩形 ctx1.fillStyle = '#000'; ctx1.fillRect(0, 0, w, w) //设置重叠样式,重复区域颜色相加 ctx1.globalCompositeOperation = "lighter"; for(var i=0;i<length;i++){ var p=points[i]; if(p.x==0){ continue; } ctx1.beginPath(); //ctx1.fillStyle="#fff"; p.a=1; ctx1.fillStyle='rgba('+p.r+','+p.g+','+p.b+','+p.a+')'; var mod=(p.offset+now)%600/600; mod=Math.sin(mod*Math.PI); ctx1.arc(p.x,p.y,p.radius*mod,0,Math.PI*2); ctx1.fill(); p.x+=(p.dx-p.x)/10; p.y+=(p.dy-p.y)/10; } } window.onload=function(){ setpoints(); settextdata(); //draw(); setInterval(draw,30) setInterval(settextdata,4000) }以上是原码
一、获取文字每个像素的xy:
在canvas上写字,字颜色不要和背景一样。
通过getImageData来获取画板每个点的rgba组成的数组
我们来分析这些数组颜色
I是加4的
可以判断 r g b 也就是i i+1 i+2 它们的颜色。
当条件满足时获取这时x y 并乘以数来放大点。
二、生成圆对象数组
圆 的个数需要固定,循环生成对象并存在数组里。
我们最先把这些圆 点平分在画板上。
需要算出每个点的xy的间隔
canvas的面积/点数 得到某面积内的一个点,开根就是长宽值内的点
圆 对象需要有rgb a 三个255内一个1内的随机数。
还需要8内的半径,和offset 值600内随机数
三、计算圆对象离哪个点最近。得到所有圆显示结果的xy
for 循环圆数组
得到当前圆对象,创建数组,循环所有点,判断这些点哪个和圆最近。
设置dy dx 也就是圆最后显示x y
然后删除这个点。这样一直循环下去。
判断两点的最短距离就是直线。
我们在两点间画直线,两点延长线上会有一个点交接。
三点组成垂直三角形。
最短距离是斜边。
a*a+b*b=c*c
根据这个来得到c的值。
四、每隔30ms渲染一次画板,计算每个点的新x y 和半径
循环圆数组
beginPath()开始画圆
设置fillStyle 也就是rgba
创建mod 它是圆半径
用offset+当前时间 % 600 /600 得到的值 是0-1 0-1
半径不能是小大 再从小到大这样不是闪烁的效果。
需要是0-1 1-0这样的。
这里用到了math.sin(0-3) 结果就是小大大小这样的值。
画圆。
p.x+=(p.dx-p.x)/10;
p.y+=(p.dy-p.y)/10;
算下一次新的xy。