javascript转换静态图片,增加粒子动画效果


Posted in Javascript onMay 28, 2015

使用getImageData接口获取图片的像素点,然后基于像素点实现动画效果,封装成一个简单的lib

<!DOCTYPE html>
<html>
  <head>
    <title>particle image</title>
    <meta charset="utf-8" />
    <style>
      #logo {
        margin-left:20px;
        margin-top:20px;
        width:160px;
        height:48px;
        background:url('./images/logo.png');
        /*border: 1px solid red;*/
      }
    </style>
    <script type="text/javascript" src="ParticleImage.js"></script>
    <script>
      window.onload = function() {
        ParticleImage.create("logo", "./images/logo.png", "fast");
      };
    </script>
  </head>
  <body>
    <div id="logo"></div>
  </body>
</html>

ParticleImage.js

/*
The MIT License (MIT)
 
Copyright (c) 2015 arest
 
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
 
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
 
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
 
/**
 * Add particle animation for image
 * usage:
    <script type="text/javascript" src="ParticleImage.js"></script>
    <script>
      window.onload = function() {
        // be sure to use image file in your own server (prevent CORS issue)
        ParticleImage.create("logo", "logo_s2.png", "fast");
      };
    </script>
    // in html file
    <div id="logo"></div>
    // you can set default background image as usual
    #logo {
      margin-left:20px;
      margin-top:20px;
      width:160px;
      height:48px;
      background:url('logo_s2.png');
    }
 *
 * @author tianx.qin (rushi_wowen@163.com)
 * @file ParticleImage.js
 * @version 0.9
 */
var ParticleImage = (function(window) {
  var container = null, canvas = null;
  var ctx = null, _spirit = [], timer = null,
    cw = 0, ch = 0, // container width/height
    iw = 0, ih = 0, // image width/height
    mx = 0, my = 0, // mouse position
    bMove = true,
    MOVE_SPAN = 4, DEFAULT_ALPHA = 100,
    speed = 100, S = {"fast":10, "mid":100, "low":300},
    ALPHA = 255 * 255;
 
  // spirit class
  var Spirit = function(data) {
    this.orginal = {
      pos: data.pos,
      x : data.x, y : data.y,
      r : data.r, g : data.g, b : data.b, a : data.a
    };
    // change state, for animation
    this.current = {
      x : data.x,
      y : data.y,
      a : data.a
    };
  };
 
  /**
   * move spirit to original position
   */
  Spirit.prototype.move = function() {
    var cur = this.current, orig = this.orginal;
    if ((cur.x === orig.x) && (cur.y === orig.y)) {
      //console.log("don't move:" + cur.y);
      return false;
    }
    //console.log("move:" + cur.y);
    var rand = 1 + Math.round(MOVE_SPAN * Math.random());
    var offsetX = cur.x - orig.x,
      offsetY = cur.y - orig.y;
    var rad = offsetX == 0 ? 0 : offsetY / offsetX;
    var xSpan = cur.x < orig.x ? rand : cur.x > orig.x ? -rand : 0;
    cur.x += xSpan;
    var tempY = xSpan == 0 ? Math.abs(rand) : Math.abs(Math.round(rad * xSpan));
    var ySpan = offsetY < 0 ? tempY : offsetY > 0 ? -tempY : 0;
    cur.y += ySpan;
    cur.a = ((cur.x === orig.x) && (cur.y === orig.y)) ? orig.a : DEFAULT_ALPHA;
    return true;
  };
 
  /**
   * set random position
   */
  Spirit.prototype.random = function(width, height) {
    var cur = this.current;
    cur.x = width + Math.round(width * 2 * Math.random());
    this.current.y = height + Math.round(height * 2 * Math.random());
  };
 
  /**
   * set random positions for all spirits
   */
  var _disorder = function() {
    var len = _spirit.length;
    for (var i = 0; i < len; i++) {
      _spirit[i].random(cw, ch);
    }
  };
 
  /**
   * start to move spirit
   */
  var _move = function() {
    var sprt = _spirit;
    var len = sprt.length;
    var isMove = false; // whether need to move
    for (var i = 0; i < len; i++) {
      if (sprt[i].move()) {
        isMove = true;
      }
    }
    isMove ? _redraw() : _stopTimer();
  };
 
  /**
   * redraw all spirits while animating
   */
  var _redraw = function() {
    var imgDataObj = ctx.createImageData(iw, ih);
    var imgData = imgDataObj.data;
    var sprt = _spirit;
    var len = sprt.length;
    //console.log("redraw image : " + len);
    for (var i = 0; i < len; i++) {
      var temp = sprt[i];
      //console.log("item : " + JSON.stringify(temp));
      var orig = temp.orginal;
      var cur = temp.current;
      var pos = (cur.y * iw + cur.x) * 4;
      imgData[pos] = orig.r;
      imgData[pos + 1] = orig.g;
      imgData[pos + 2] = orig.b;
      imgData[pos + 3] = cur.a;
    }
    ctx.putImageData(imgDataObj, 0, 0);
  };
 
  /**
   * add mousemove/mouseclick event
   */
  var _addMouseEvent = function(c) {
    c.addEventListener("mouseenter", function(e) {
      //console.log("e.y:" + e.clientY + ", " + container.offsetTop);
      _startTimer();
    });
    c.addEventListener("click", function() {
      // disorder all spirits and start animation
      _startTimer();
    });
  };
 
  /**
   * calculate all pixels of the logo image
   */
  var _checkImage = function(imgUrl, callback) {
    // var tempCanvas = document.getElementById("temp");
    //canvas.width = width;
    //canvas.height = height;
 
    var proc = function(image) {
      var w = image.width, h = image.height;
      iw = w, ih = h;
      //console.log("proc image " + image + "," + w + "," + h);
      canvas = _createCanvas();
      // hide container background
      container.style.backgroundPosition = (-w) + "px";
      container.style.backgroundRepeat = "no-repeat";
      ctx.drawImage(image, 0, 0);
      // this may cause security error for CORS issue
      try {
        var imgData = ctx.getImageData(0, 0, w, h);
        var arrData = imgData.data;
        for (var i = 0; i < arrData.length; i += 4) {
          var r = arrData[i], g = arrData[i + 1], b = arrData[i + 2], a = arrData[i + 3];
          if (r > 0 || g > 0 || b > 0 || a > 0) {
            var pos = i / 4;
            _spirit.push(new Spirit({
              x : pos % w, y : Math.floor(pos / w), 
              r : r, g : g, b : b, a : a
            }));
          }
        }
        return true;
      } catch (e) {
        // do nothing
        return false;
      }
      //return out;
    };
 
    var img = new Image();
    img.src = imgUrl;
    if (img.complete || img.complete === undefined) {
      proc(img) && callback && callback();
    } else {
      img.onload = function() {
        proc(img) && callback && callback();
      };
    }
  };
 
  // use "requestAnimationFrame" to create a timer, need browser support
  var _timer = function(func, dur) {
    //console.log("speed is " + dur);
    var timeLast = null;
    var bStop = false;
    var bRunning = false; // prevent running more than once
    var _start = function() {
      if (func) {
        if (! timeLast) {
          timeLast = Date.now();
          func();
        } else {
          var current = Date.now();
          if (current - timeLast >= dur) {
            timeLast = current;
            func();
          }
        }
      }
 
      if (bStop) {
        return;
      }
      requestAnimationFrame(_start);
    };
 
    var _stop = function() {
      bStop = true;
    };
 
    return {
      start : function() {
        if (bRunning) {
          //console.log("already running..");
          return;
        }
        //console.log("start running..");
        bRunning = true;
        bStop = false;
        _disorder();
        _start();
      },
      stop : function() {
        _stop();
        bRunning = false;
      }
    };
  };
 
  var _startTimer = function() {
    if (! timer) {
      timer = _timer(function() {
        bMove && _move();
      }, speed);
    }
    timer.start();
  };
 
  var _stopTimer = function() {
    timer && timer.stop();
  };
 
  /**
   * start process
   */
  var _create = function(imgUrl) {
    _checkImage(imgUrl, function() {
      //_createSpirits();
      _addMouseEvent(canvas);
      //_startTimer();
    });
  };
 
  var _setSpeed = function(s) {
    S[s] && (speed = S[s]);
  };
 
  /**
   * check whether browser supports canvas
   */
  var _support = function() {
    try {
      document.createElement("canvas").getContext("2d");
      return true;
    } catch (e) {
      return false;
    }
  };
 
  /**
   * create a canvas element
   */
  var _createCanvas = function() {
    var cav = document.createElement("canvas");
    cav.width = iw;
    cav.height = ih;
    container.appendChild(cav);
    ctx = cav.getContext("2d");
    return cav;
  };
 
  /**
   * initialize container params
   */
  var _init = function(c, s) {
    if ((! c) || (! _support())) { // DIV id doesn't exist
      return false;
    }
    container = c;
    cw = c.clientWidth;
    ch = c.clientHeight;
    s && _setSpeed(s);
    return true;
  };
 
  /**
   * export
   */
  return {
    "create" : function(cId, imgUrl, s) { // user can set move speed by 's'['fast','mid','low']
      _init(document.getElementById(cId), s) && _create(imgUrl);
    }
  };
})(window);

以上所述就是本文的全部内容了,希望大家能够喜欢。

Javascript 相关文章推荐
javascript中的array数组使用技巧
Jan 31 Javascript
js动态在form上插入enctype=multipart/form-data的问题
May 24 Javascript
js实现正方形颜色从下往上升的效果
Aug 04 Javascript
Bootstrap 附加导航(Affix)插件实例详解
Jun 01 Javascript
javascript宿主对象之window.navigator详解
Sep 07 Javascript
微信小程序 picker-view 组件详解及简单实例
Jan 10 Javascript
node.JS md5加密中文与php结果不一致的解决方法
May 05 Javascript
Mac系统下Webstorm快捷键整理大全
May 28 Javascript
详解vue+vueRouter+webpack的简单实例
Jun 17 Javascript
基于Node.js模板引擎教程-jade速学与实战1
Sep 17 Javascript
JavaScript求一个数组中重复出现次数最多的元素及其下标位置示例
Jul 23 Javascript
javascript跳转与返回和刷新页面的实例代码
Nov 20 Javascript
jQuery实现限制textarea文本框输入字符数量的方法
May 28 #Javascript
javascript实现行拖动的方法
May 27 #Javascript
JavaScript操作Cookie方法实例分析
May 27 #Javascript
JavaScript通过事件代理高亮显示表格行的方法
May 27 #Javascript
jquery预加载图片的方法
May 27 #Javascript
jQuery仿gmail实现fixed布局的方法
May 27 #Javascript
js实现键盘Enter键提交表单的方法
May 27 #Javascript
You might like
上海无线电三厂简史修改版
2021/03/01 无线电
判“新”函数:得到今天与明天的秒数
2006/10/09 PHP
php AJAX实例根据邮编自动完成地址信息
2008/11/23 PHP
zf框架的数据库追踪器使用示例
2014/03/13 PHP
php快递单号查询接口使用示例
2014/05/05 PHP
php+mysqli事务控制实现银行转账实例
2015/01/29 PHP
PHP面向对象学习之parent::关键字
2017/01/18 PHP
php+layui数据表格实现数据分页渲染代码
2019/10/26 PHP
jquery表格内容筛选实现思路及代码
2013/04/16 Javascript
浅谈JavaScript字符串与数组
2015/06/03 Javascript
jQuery实现按钮只点击一次后就取消点击事件绑定的方法
2015/06/26 Javascript
js实现无限级树形导航列表效果代码
2015/09/23 Javascript
基于javascript简单实现对身份证校验
2021/01/25 Javascript
js面向对象的写法
2016/02/19 Javascript
老司机带你解读jQuery插件开发流程
2016/05/16 Javascript
深入浅析search 搜索框的写法
2016/08/02 Javascript
webstorm添加*.vue文件支持
2018/05/08 Javascript
浅谈vux之x-input使用以及源码解读
2018/11/04 Javascript
vue 动态添加class,三个以上的条件做判断方式
2020/11/02 Javascript
[55:32]2018DOTA2亚洲邀请赛 4.4 淘汰赛 EG vs LGD 第二场
2018/04/05 DOTA
[53:13]DOTA2-DPC中国联赛 正赛 DLG vs PHOENIX BO3 第三场 1月18日
2021/03/11 DOTA
Python实现子类调用父类的方法
2014/11/10 Python
详谈Python3 操作系统与路径 模块(os / os.path / pathlib)
2018/04/26 Python
使用matplotlib中scatter方法画散点图
2019/03/19 Python
如何使用Python进行OCR识别图片中的文字
2019/04/01 Python
Python Web框架之Django框架Form组件用法详解
2019/08/16 Python
Python 中由 yield 实现异步操作
2020/05/04 Python
Python基于opencv的简单图像轮廓形状识别(全网最简单最少代码)
2021/01/28 Python
美国礼品卡交易网站:Cardpool
2018/08/27 全球购物
Linux机考试题
2015/07/17 面试题
市场营销专业个人自荐信格式
2013/09/21 职场文书
红旗方阵解说词
2014/02/12 职场文书
产品推广策划方案
2014/05/10 职场文书
师范生见习报告
2014/10/31 职场文书
css实现文章分割线样式的多种方法总结
2021/04/21 HTML / CSS
MySQL对数据表已有表进行分区表的实现
2021/11/01 MySQL