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 相关文章推荐
js对列表中第一个值处理与jsp页面对列表中第一个值处理的区别详解
Nov 05 Javascript
js模仿hover的具体实现代码
Dec 30 Javascript
jQuery+css3实现文字跟随鼠标的上下抖动
Jul 31 Javascript
Jquery中map函数的用法
Jun 03 Javascript
jQuery中可见性过滤器简单用法示例
Mar 31 jQuery
详解vue的diff算法原理
May 20 Javascript
vuejs选中当前样式active的实例
Aug 22 Javascript
微信上传视频文件提示(推荐)
Nov 22 Javascript
Vuejs学习笔记之使用指令v-model完成表单的数据双向绑定
Apr 29 Javascript
javascript实现视频弹幕效果(两个版本)
Nov 28 Javascript
微信小程序实现日历签到
Sep 21 Javascript
vue-cli —— 如何局部修改Element样式
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
mysql5的sql文件导入到mysql4的方法
2008/10/19 PHP
php Rename 更改文件、文件夹名称
2011/05/24 PHP
探讨如何使用SimpleXML函数来加载和解析XML文档
2013/06/07 PHP
解析PHP可变函数的经典用法
2013/06/20 PHP
php session的应用详细介绍
2017/03/22 PHP
php正则表达式基本知识与应用详解【经典教程】
2017/04/17 PHP
JavaScript中的类数组对象介绍
2014/12/30 Javascript
jQuery实现手机自定义弹出输入框
2016/06/13 Javascript
文件上传插件SWFUpload的使用指南
2016/11/29 Javascript
ReactNative Image组件使用详解
2017/08/07 Javascript
JavaScript中EventLoop介绍
2018/01/22 Javascript
node实现生成带参数的小程序二维码并保存到本地功能示例
2018/12/05 Javascript
小程序多图列表实现性能优化的方法步骤
2019/05/28 Javascript
[01:08:29]DOTA2-DPC中国联赛定级赛 RNG vs Aster BO3第一场 1月9日
2021/03/11 DOTA
python3.6的venv模块使用详解
2018/08/01 Python
python3使用pandas获取股票数据的方法
2018/12/22 Python
对Python的多进程锁的使用方法详解
2019/02/18 Python
python爬虫之自制英汉字典
2019/06/24 Python
opencv3/C++ 平面对象识别&amp;透视变换方式
2019/12/11 Python
学会python自动收发邮件 代替你问候女友
2020/05/20 Python
Python实现一个简单的毕业生信息管理系统的示例代码
2020/06/08 Python
利用纯CSS3实现文字向右循环闪过效果实例(可用于移动端)
2017/06/15 HTML / CSS
css3的transition属性详解
2014/12/15 HTML / CSS
您的健身减肥和健康饮食专家:vitafy
2017/06/06 全球购物
给医务人员表扬信
2014/01/12 职场文书
财务会计毕业生个人求职信
2014/02/03 职场文书
电子商务专业学生职业生涯规划
2014/03/07 职场文书
2014年基层党组织公开承诺书
2014/03/29 职场文书
党校培训自我鉴定范文
2014/04/10 职场文书
教师业务培训方案
2014/05/01 职场文书
土建工程师岗位职责
2014/06/10 职场文书
员工教育培训协议书
2014/09/27 职场文书
邀请书模板
2015/02/02 职场文书
2015年财务个人工作总结范文
2015/05/22 职场文书
2019行政前台转正申请书范文3篇
2019/08/15 职场文书
OpenFeign实现远程调用
2022/08/14 Java/Android