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 相关文章推荐
任意位置显示html菜单
Feb 01 Javascript
JavaScript 利用StringBuffer类提升+=拼接字符串效率
Nov 24 Javascript
JavaScript 闭包在封装函数时的简单分析
Nov 28 Javascript
Jquery遍历节点的方法小集
Jan 22 Javascript
元素绑定click点击事件方法
Jun 08 Javascript
分享jQuery插件的学习笔记
Jan 14 Javascript
JavaScript获取对象在页面中位置坐标的方法
Feb 03 Javascript
微信小程序实现登录页云层漂浮的动画效果
May 05 Javascript
微信小程序如何获取用户信息
Jan 26 Javascript
vue定义全局变量和全局方法的方法示例
Aug 01 Javascript
layui表单验证select下拉框实现验证的方法
Sep 05 Javascript
JavaScript 中判断变量是否为数字的示例代码
Oct 22 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检测移动设备类mobile detection使用实例
2014/04/14 PHP
thinkphp3.2.2前后台公用类架构问题分析
2014/11/25 PHP
mac下多个php版本快速切换的方法
2016/10/09 PHP
HTTP头隐藏PHP版本号实现过程解析
2020/12/09 PHP
window.showModalDialog使用手册
2007/01/11 Javascript
JavaScript中变量提升 Hoisting
2012/07/03 Javascript
JSON.stringify转换JSON时日期时间不准确的解决方法
2014/08/08 Javascript
用js动态添加html元素,以及属性的简单实例
2016/07/19 Javascript
jQuery 全选 全部选 反选 实现代码
2016/08/17 Javascript
JavaScript递归操作实例浅析
2016/10/31 Javascript
基于jQuery插件jqzoom实现的图片放大镜效果示例
2017/01/23 Javascript
JS排序之选择排序详解
2017/04/08 Javascript
解决vue多个路由共用一个页面的问题
2018/03/12 Javascript
HTML+JavaScript实现扫雷小游戏
2019/09/30 Javascript
微信小程序手动添加收货地址省市区联动
2020/05/18 Javascript
微信小程序整个页面的自动适应布局的实现
2020/07/12 Javascript
mapboxgl实现带箭头轨迹线的代码
2021/01/04 Javascript
node.js文件的复制、创建文件夹等相关操作
2021/02/05 Javascript
apache部署python程序出现503错误的解决方法
2017/07/24 Python
python selenium自动上传有赞单号的操作方法
2018/07/05 Python
Python3 使用cookiejar管理cookie的方法
2018/12/28 Python
Python 依赖库太多了该如何管理
2019/11/08 Python
Opencv图像处理:如何判断图片里某个颜色值占的比例
2020/06/03 Python
python suds访问webservice服务实现
2020/06/26 Python
在pycharm中文件取消用 pytest模式打开的操作
2020/09/01 Python
详解html5 postMessage解决跨域通信的问题
2018/08/17 HTML / CSS
新西兰网上购物,折扣店:BestDeals.co.nz
2019/03/20 全球购物
员工年终演讲稿
2014/01/03 职场文书
料理师求职信
2014/01/30 职场文书
房地产营销策划方案
2014/02/08 职场文书
家长会学生演讲稿
2014/04/26 职场文书
感恩节活动策划方案
2014/05/16 职场文书
2014年护士长工作总结
2014/11/11 职场文书
给领导敬酒词
2015/08/12 职场文书
python 利用PyAutoGUI快速构建自动化操作脚本
2021/05/31 Python
Python可视化学习之matplotlib内置单颜色
2022/02/24 Python