• 【转】随便谈谈用canvas来实现文字图片粒子化


    看了岑安大大的教程http://www.cnblogs.com/hongru/archive/2012/03/28/2420415.html后,让我见识到了canvas操控像素能力的强大,也就自己试着做了一下。发现如此好玩的效果也正如岑安大大所说的一样,事情没有想象中那么难。

      先看个DEMO吧,先从文字下手:文字粒子化

      要做出这样的效果,只需要懂的使用canvas的getImgData()就行了。该方法能够复制画布上指定矩形的像素数据,用法很简单:

    1
    var imgData=context.getImageData(x,y,width,height);

    就酱紫就可以获取到imgData。imgData是获取到的像素信息,具体如下

    对于 ImageData 对象中的每个像素,都存在着四方面的信息,即 RGBA 值:

    • R - 红色 (0-255)
    • G - 绿色 (0-255)
    • B - 蓝色 (0-255)
    • A - alpha 通道 (0-255; 0 是透明的,255 是完全可见的)

    只要是有前端编程经验的,都肯定知道rgba了,而获取到的imgData就是一个存放着制定矩形中所有像素数组的数组,第一个像素的R是imgData[0],G是imgData[1],B是imgData[2],A则是imgData[3],第二个像素的R是imgData[4],G是imgData[5],B是imgData[6],A则是imgData[7]。。。以此类推。然后,既然我们已经获取到了所有像素里的rgba参数了,我们也就可以很简单的对这些参数进行更改,然后再将更改后的imgData通过putImageData()方法贴到画布上。像素处理完毕。就是如此简单。

      知道如何获取像素数据后,接下来就可以开搞了~~~关键代码就下面这些:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    function getimgData(text){
        drawText(text);
        var imgData = context.getImageData(0,0,canvas.width , canvas.height);
        context.clearRect(0,0,canvas.width , canvas.height);
        var dots = [];
        for(var x=0;x<imgData.width;x+=6){
            for(var y=0;y<imgData.height;y+=6){
                var i = (y*imgData.width + x)*4;
                if(imgData.data[i+3] >= 128){
                    var dot = new Dot(x-3 , y-3 , 0 , 3);
                    dots.push(dot);
                }
            }
        }
        return dots;
    }

    获取到imgData后,通过两个循环,获得透明度大于128的,也就是有颜色的像素,然后实例化一个粒子对象,存入一个粒子数组中保存,以下是粒子对象代码:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    var Dot = function(centerX , centerY , centerZ , radius){
                this.dx = centerX;  //保存原来的位置
                this.dy = centerY;
                this.dz = centerZ;
                this.tx = 0;     //保存粒子聚合后又飞散开的位置
                this.ty = 0;
                this.tz = 0;
                this.z = centerZ;
                this.x = centerX;
                this.y = centerY;
                this.radius = radius;
            }
     
            Dot.prototype = {
                paint:function(){
                    context.save();
                    context.beginPath();
                    var scale = focallength/(focallength + this.z);
                    context.arc(canvas.width/2 + (this.x-canvas.width/2)*scale , canvas.height/2 + (this.y-canvas.height/2) * scale, this.radius*scale , 0 , 2*Math.PI);
                    context.fillStyle = "rgba(50,50,50,"+ scale +")";
                    context.fill()
                    context.restore();
                }
            }

    为了让小圆扩散有3D的空间感,所以还引入了Z轴,也就是把3维平面化成二维,具体我就不多说了。可以直接戳http://www.cnblogs.com/hongru/archive/2011/09/12/2174187.html   我就是看着岑安大大的教程学的。3D效果也做好后,就做动画,随机出一个坐标,让粒子先呆在那个坐标,然后通过保存的位置再聚合,然后再随机出坐标再分散,就是这个动画的原理了。

      下面贴出所有代码:

    复制代码
      1 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
      2 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
      3 <head>
      4     <meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
      5     <style>
      6         #cas{
      7             display: block;
      8             border:1px solid;
      9             margin:auto;
     10         }
     11     </style>
     12     <script>
     13         window.onload = function(){
     14             canvas = document.getElementById("cas");
     15             context = canvas.getContext('2d');
     16             focallength = 250;
     17 
     18             var dots = getimgData(document.getElementById('name').value);;
     19             var pause = false;
     20             initAnimate();
     21             function initAnimate(){
     22                 dots.forEach(function(){
     23                     this.x = Math.random()*canvas.width;
     24                     this.y = Math.random()*canvas.height;
     25                     this.z = Math.random()*focallength*2 - focallength;
     26 
     27                     this.tx = Math.random()*canvas.width;
     28                     this.ty = Math.random()*canvas.height;
     29                     this.tz = Math.random()*focallength*2 - focallength;
     30                     this.paint();
     31                 });
     32                 animate();
     33             }
     34 
     35             //计算帧速率
     36             var lastTime;
     37             var derection = true;
     38             function animate(){
     39                 animateRunning = true;
     40                 var thisTime = +new Date();
     41                 context.clearRect(0,0,canvas.width , canvas.height);
     42                 dots.forEach(function(){
     43                     var dot = this;
     44                     if(derection){
     45                         if (Math.abs(dot.dx - dot.x) < 0.1 && Math.abs(dot.dy - dot.y) < 0.1 && Math.abs(dot.dz - dot.z)<0.1) {
     46                             dot.x = dot.dx;
     47                             dot.y = dot.dy;
     48                             dot.z = dot.dz;
     49                             if(thisTime - lastTime > 300) derection = false;
     50                         } else {
     51                             dot.x = dot.x + (dot.dx - dot.x) * 0.1;
     52                             dot.y = dot.y + (dot.dy - dot.y) * 0.1;
     53                             dot.z = dot.z + (dot.dz - dot.z) * 0.1;
     54                             lastTime = +new Date()
     55                         }
     56                     }
     57                     else {
     58                         if (Math.abs(dot.tx - dot.x) < 0.1 && Math.abs(dot.ty - dot.y) < 0.1 && Math.abs(dot.tz - dot.z)<0.1) {
     59                             dot.x = dot.tx;
     60                             dot.y = dot.ty;
     61                             dot.z = dot.tz;
     62                             pause = true;
     63                         } else {
     64                             dot.x = dot.x + (dot.tx - dot.x) * 0.1;
     65                             dot.y = dot.y + (dot.ty - dot.y) * 0.1;
     66                             dot.z = dot.z + (dot.tz - dot.z) * 0.1;
     67                             pause = false;
     68                         }
     69                     }
     70                     dot.paint();
     71                 });
     72                 if(!pause) {
     73                     if("requestAnimationFrame" in window){
     74                         requestAnimationFrame(animate);
     75                     }
     76                     else if("webkitRequestAnimationFrame" in window){
     77                         webkitRequestAnimationFrame(animate);
     78                     }
     79                     else if("msRequestAnimationFrame" in window){
     80                         msRequestAnimationFrame(animate);
     81                     }
     82                     else if("mozRequestAnimationFrame" in window){
     83                         mozRequestAnimationFrame(animate);
     84                     }
     85                 }
     86             }
     87 
     88             document.getElementById('startBtn').onclick = function(){
     89                 if(!pause) return;
     90                 dots = getimgData(document.getElementById('name').value);
     91                 derection=true;
     92                 pause = false;
     93                 initAnimate();
     94             }
     95         }
     96 
     97         Array.prototype.forEach = function(callback){
     98             for(var i=0;i<this.length;i++){
     99                 callback.call(this[i]);
    100             }
    101         }
    102 
    103         function getimgData(text){
    104             drawText(text);
    105             var imgData = context.getImageData(0,0,canvas.width , canvas.height);
    106             context.clearRect(0,0,canvas.width , canvas.height);
    107             var dots = [];
    108             for(var x=0;x<imgData.width;x+=6){
    109                 for(var y=0;y<imgData.height;y+=6){
    110                     var i = (y*imgData.width + x)*4;
    111                     if(imgData.data[i] >= 128){
    112                         var dot = new Dot(x-3 , y-3 , 0 , 3);
    113                         dots.push(dot);
    114                     }
    115                 }
    116             }
    117             return dots;
    118         }
    119 
    120         function drawText(text){
    121             context.save()
    122             context.font = "200px 微软雅黑 bold";
    123             context.fillStyle = "rgba(168,168,168,1)";
    124             context.textAlign = "center";
    125             context.textBaseline = "middle";
    126             context.fillText(text , canvas.width/2 , canvas.height/2);
    127             context.restore();
    128         }
    129 
    130 
    131         var Dot = function(centerX , centerY , centerZ , radius){
    132             this.dx = centerX;
    133             this.dy = centerY;
    134             this.dz = centerZ;
    135             this.tx = 0;
    136             this.ty = 0;
    137             this.tz = 0;
    138             this.z = centerZ;
    139             this.x = centerX;
    140             this.y = centerY;
    141             this.radius = radius;
    142         }
    143 
    144         Dot.prototype = {
    145             paint:function(){
    146                 context.save();
    147                 context.beginPath();
    148                 var scale = focallength/(focallength + this.z);
    149                 context.arc(canvas.width/2 + (this.x-canvas.width/2)*scale , canvas.height/2 + (this.y-canvas.height/2) * scale, this.radius*scale , 0 , 2*Math.PI);
    150                 context.fillStyle = "rgba(50,50,50,"+ scale +")";
    151                 context.fill()
    152                 context.restore();
    153             }
    154         }
    155     </script>
    156     <title>操控字体的数据</title>
    157 </head>
    158 <body>
    159     <div >
    160         <canvas id='cas' width="1000" height="500">浏览器不支持canvas</canvas>
    161         <div style="150px;margin:10px auto">
    162             <input type="text" name="" id="name" style="80px;" value="王鸿兴"><button id="startBtn">开始</button>
    163         </div>
    164     </div>
    165 </body>
    166 </html>
    复制代码

    技术不是很好,代码写的不好请见谅。不过应该不难理解。

      知道文字如何粒子化后,图片也就一样的做法了。这里也有几个DEMO:粒子化Demo1 , 粒子化Demo2。代码就不贴了,通过控制台一样可以看的到代码,毕竟就一个html文件。

      补充一点:过于复杂的图片不适合粒子化,因为对象过多时,对浏览器的造成很大的负荷,动画效果也就会变得很卡很卡了。一般一千个粒子左右比较合适,自己就根据图片复杂度调整粒子的大小,减少粒子数量就行了。

  • 相关阅读:
    Laravel 项目架构 弹性、可维护性
    QT信号槽详解
    linux常用命令
    程序莫名其妙的崩溃,加断点刚进入函数就崩溃,断点不往下走,读取图片数据到程序并保存到一个HBITMAP 中
    C++ 实现sqilte创建数据库插入、更新、查询、删除
    dump、libeay32.dll、gsoap、webserver多线程调用gsoap产生崩溃
    bat自动打包压缩实现
    linux 文件名称前后缀操作函数----取目录函数dir、取文件名称函数notdir、取后缀函数suffix、取前缀basename、加后缀函数addsuffix、加前缀addprefix、连接函数join
    linux makefile字符串操作函数 替换subst、模式替换patsubst、去首尾空格strip、查找字符串findstring、过滤filter、反过滤filter-out、排序函数sort、取单词word、取单词串wordlist、个数统计words
    makefile编写--引用
  • 原文地址:https://www.cnblogs.com/weikai/p/3531875.html
Copyright © 2020-2023  润新知