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 数组的 uniq 方法
Jan 23 Javascript
JS Array对象入门分析
Oct 30 Javascript
jQuery 判断页面元素是否存在的代码
Aug 14 Javascript
js RuntimeObject() 获取ie里面自定义函数或者属性的集合
Nov 23 Javascript
常见的原始JS选择器使用方法总结
Apr 09 Javascript
Bootstrap基本插件学习笔记之折叠(22)
Dec 08 Javascript
BootStrap daterangepicker 双日历控件
Jun 02 Javascript
Vuejs 2.0 子组件访问/调用父组件的方法(示例代码)
Feb 08 Javascript
AjaxFileUpload.js实现异步上传文件功能
Apr 19 Javascript
详解vue-cli项目开发/生产环境代理实现跨域请求
Jul 23 Javascript
在layui中layer弹出层点击事件无效的解决方法
Sep 05 Javascript
Ant-design-vue Table组件customRow属性的使用说明
Oct 28 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
创建配置文件 用PHP写出自己的BLOG系统 2
2010/04/12 PHP
tp5.1 框架join方法用法实例分析
2020/05/26 PHP
JS实现浏览器菜单命令
2006/09/05 Javascript
再次更新!MSClass (Class Of Marquee Scroll通用不间断滚动JS封装类 Ver 1.6)
2007/02/05 Javascript
图标线性回归斜着移动到指定的位置
2013/08/16 Javascript
jquery模拟SELECT下拉框取值效果
2013/10/23 Javascript
javascript 实现 原路返回
2015/01/21 Javascript
WEB前端开发都应知道的jquery小技巧及jquery三个简写
2015/11/15 Javascript
理解Angular数据双向绑定
2016/01/10 Javascript
webpack+vue.js快速入门教程
2016/10/12 Javascript
详解springmvc 接收json对象的两种方式
2016/12/06 Javascript
BOM之navigator对象和用户代理检测
2017/02/10 Javascript
ECMAscript 变量作用域总结概括
2017/08/18 Javascript
详解Vue2 SSR 缓存 Api 数据
2017/11/20 Javascript
微信小程序实现单选选项卡切换效果
2020/06/19 Javascript
JS中实现一个下载进度条及播放进度条的代码
2019/06/10 Javascript
layui 实现二级弹窗弹出之后 关闭一级弹窗的方法
2019/09/18 Javascript
基于VUE的v-charts的曲线显示功能
2019/10/01 Javascript
jquery实现掷骰子小游戏
2019/10/24 jQuery
node运行js获得输出的三种方式示例详解
2020/07/02 Javascript
浅述python中argsort()函数的实例用法
2017/03/30 Python
Python下简易的单例模式详解
2019/04/08 Python
numpy concatenate数组拼接方法示例介绍
2019/05/27 Python
详解Numpy数组转置的三种方法T、transpose、swapaxes
2019/05/27 Python
Django生成PDF文档显示在网页上以及解决PDF中文显示乱码的问题
2019/07/04 Python
python模拟点击网页按钮实现方法
2020/02/25 Python
python GUI库图形界面开发之PyQt5 Qt Designer工具(Qt设计师)详细使用方法及Designer ui文件转py文件方法
2020/02/26 Python
使用HTML5 Canvas绘制圆角矩形及相关的一些应用举例
2016/03/22 HTML / CSS
GetYourGuide台湾:预订旅游活动、景点和旅游项目
2019/06/10 全球购物
在加拿大在线租赁和购买电子游戏:Game Access
2019/09/02 全球购物
中专毕业生自荐信范文
2013/11/28 职场文书
用人单位终止解除劳动合同证明书
2014/10/06 职场文书
2015年电话销售工作总结范文
2015/04/20 职场文书
《有余数的除法》教学反思
2016/02/22 职场文书
Oracle 数据仓库ETL技术之多表插入语句的示例详解
2021/04/12 Oracle
springboot读取nacos配置文件
2022/05/20 Java/Android