程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> 關於JAVA >> Web Chart入門(7) 物理動畫效果(如撕扯效果)

Web Chart入門(7) 物理動畫效果(如撕扯效果)

編輯:關於JAVA

物理動畫

這裡物理動畫說的是,圖形的動畫效果和實際生活中的物理效果類似,比如說重力影響的效果。

其實動畫的實現就是把一個動作拆分成間隔連續的去完成, 視覺上就感覺是在動的了。

比如把一個圖從左邊移到右邊, 設總距離100的話, 每隔 1/40秒 移到 1 的話,效果就會有了。

這個時間間隔和距離間隔設置多少為最佳,美學上是有一些定義的,這裡就不探討了。

一個拽動和撕扯窗布的例子

三個文件

tearCloth.html ;  tearCloth.css ; tearCloth.js

tearCloth.html

<!--Add by oscar999-->
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">  
<HTML>  
<HEAD>  
<TITLE> New Document </TITLE>  
<META NAME="Author" CONTENT="oscar999">  
<link rel="stylesheet" type="text/css" href="tearCloth.css"  />  
</HEAD>  
      
<BODY>  
<canvas id = "c" > </canvas>    
<center id="info">  
  <center id="top">  
  <a id="close" href="">close</a>  
  </center>  
  <p>  
    <br>  
    - Tear the cloth with your mouse.<br><br>  
    - Right click and drag to cut the cloth<br><br>  
    - Reduce physics_accuracy if it's laggy.<br><br>  
  </p>  
</center>  
      
<script src="tearCloth.js"></script>  
</BODY>  
</HTML>

tearCloth.css

* {  
     margin: 0;  
  overflow:hidden;  
  -webkit-user-select: none;  
  -moz-user-select: none;  
  -ms-user-select: none;  
  -o-user-select: none;  
  user-select: none;    
}  
      
body {  
  background:#333;  
}  
      
canvas {  
  background:#333;  
  width:100%;  
  height:376px;  
  margin:0 auto;  
  display:block;  
}  
      
#info {  
  position:absolute;  
  left:-1px;  
  top:-1px;  
  width:auto;  
  max-width:380px;  
  height:auto;  
  background:#f2f2f2;  
  border-bottom-right-radius:10px;  
}  
      
#top {  
  background:#fff;  
  width:100%;  
  height:auto;  
  position:relative;  
  border-bottom:1px solid #eee;  
}  
      
p {  
  font-family:Arial, sans-serif;  
  color:#666;  
  text-align:justify;  
  font-size: 16px;  
  margin:10px;  
}  
      
a {  
  font-family:sans-serif;  
  color:#444;  
  text-decoration:none;  
  font-size: 20px;  
}  
      
#site {  
  float:left;  
  margin: 10px;  
  color: #38a;  
  border-bottom:1px dashed #888;  
}  
      
#site:hover {  
  color: #7af;  
}  
      
#close {  
  float:right;  
  margin: 10px;  
}  
      
#p {  
  font-family: Verdana, sans-serif;  
  position:absolute;  
  right:10px;  
  bottom:10px;  
  color:#adf;  
  border: 1px dashed #555;  
  padding:4px 8px;  
}

tearCloth.js

document.getElementById('close').onmousedown = function(e) {  
  e.preventDefault();  
  document.getElementById('info').style.display = 'none';  
  return false;  
};  
      
// settings  
      
var physics_accuracy = 6,  
mouse_influence      = 20,   
mouse_cut            = 5,  
gravity              = 900,   
cloth_height         = 30,  
cloth_width          = 50,  
start_y              = 20,  
spacing              = 7,  
tear_distance        = 60;  
      
      
window.requestAnimFrame =  
window.requestAnimationFrame       ||  
window.webkitRequestAnimationFrame ||  
window.mozRequestAnimationFrame    ||  
window.oRequestAnimationFrame      ||  
window.msRequestAnimationFrame     ||  
function(callback) {  
    window.setTimeout(callback, 1000 / 60);  
};  
      
var canvas,  
    ctx,  
    cloth,  
    boundsx,  
    boundsy,  
    mouse = {  
        down: false,  
        button: 1,  
        x: 0,  
        y: 0,  
        px: 0,  
        py: 0  
    };  
      
window.onload = function() {  
      
    canvas = document.getElementById('c');  
    ctx    = canvas.getContext('2d');  
      
    canvas.width = canvas.clientWidth;  
    canvas.height = 376;  
      
    canvas.onmousedown = function(e) {  
        mouse.button = e.which;  
        mouse.px = mouse.x;  
        mouse.py = mouse.y;  
  var rect = canvas.getBoundingClientRect();  
  mouse.x = e.clientX - rect.left,  
  mouse.y = e.clientY - rect.top,  
        mouse.down = true;  
        e.preventDefault();  
    };  
      
    canvas.onmouseup = function(e) {  
        mouse.down = false;  
        e.preventDefault();  
    };  
      
    canvas.onmousemove = function(e) {  
        mouse.px = mouse.x;  
        mouse.py = mouse.y;  
        var rect = canvas.getBoundingClientRect();  
  mouse.x = e.clientX - rect.left,  
  mouse.y = e.clientY - rect.top,  
        e.preventDefault();  
    };  
      
    canvas.oncontextmenu = function(e) {  
        e.preventDefault();   
    };  
      
    boundsx = canvas.width - 1;  
    boundsy = canvas.height - 1;  
      
    ctx.strokeStyle = 'rgba(222,222,222,0.6)';  
    cloth = new Cloth();  
    update();  
};  
      
var Point = function(x, y) {  
      
    this.x = x;  
    this.y = y;  
    this.px = x;  
    this.py = y;  
    this.vx = 0;  
    this.vy = 0;  
    this.pin_x = null;  
    this.pin_y = null;  
    this.constraints = [];  
};  
      
Point.prototype.update = function(delta) {  
      
    if (mouse.down) {  
      
        var diff_x = this.x - mouse.x,  
            diff_y = this.y - mouse.y,  
            dist   = Math.sqrt(diff_x * diff_x + diff_y * diff_y);  
      
        if (mouse.button == 1) {  
      
            if(dist < mouse_influence) {  
                this.px = this.x - (mouse.x - mouse.px) * 1.8;  
                this.py = this.y - (mouse.y - mouse.py) * 1.8;  
            }  
      
        } else if (dist < mouse_cut) this.constraints = [];  
    }  
      
    this.add_force(0, gravity);  
      
    delta *= delta;  
    nx = this.x + ((this.x - this.px) * .99) + ((this.vx / 2) * delta);  
    ny = this.y + ((this.y - this.py) * .99) + ((this.vy / 2) * delta);  
      
    this.px = this.x;  
    this.py = this.y;  
      
    this.x = nx;  
    this.y = ny;  
      
    this.vy = this.vx = 0  
};  
      
Point.prototype.draw = function() {  
      
    if (this.constraints.length <= 0) return;  
          
    var i = this.constraints.length;  
    while(i--) this.constraints[i].draw();  
};  
      
Point.prototype.resolve_constraints = function() {  
      
    if (this.pin_x != null && this.pin_y != null) {  
          
        this.x = this.pin_x;  
        this.y = this.pin_y;  
        return;  
    }  
      
    var i = this.constraints.length;  
    while(i--) this.constraints[i].resolve();  
      
    this.x > boundsx ? this.x = 2 * boundsx - this.x : 1 > this.x && (this.x = 2 - this.x);  
    this.y < 1 ? this.y = 2 - this.y : this.y > boundsy && (this.y = 2 * boundsy - this.y);  
};  
      
Point.prototype.attach = function(point) {  
      
    this.constraints.push(  
        new Constraint(this, point)  
    );  
};  
      
Point.prototype.remove_constraint = function(lnk) {  
      
    var i = this.constraints.length;  
    while(i--) if(this.constraints[i] == lnk) this.constraints.splice(i, 1);  
};  
      
Point.prototype.add_force = function(x, y )  {  
      
    this.vx += x;  
    this.vy += y;  
};  
      
Point.prototype.pin = function(pinx, piny) {  
    this.pin_x = pinx;  
    this.pin_y = piny;  
};  
      
var Constraint = function(p1, p2) {  
      
    this.p1 = p1;  
    this.p2 = p2;  
    this.length = spacing;  
};  
      
Constraint.prototype.resolve = function() {  
      
    var diff_x = this.p1.x - this.p2.x,  
        diff_y = this.p1.y - this.p2.y,  
        dist = Math.sqrt(diff_x * diff_x + diff_y * diff_y),  
        diff = (this.length - dist) / dist;  
      
    if (dist > tear_distance) this.p1.remove_constraint(this);  
      
    var px = diff_x * diff * 0.5;  
    var py = diff_y * diff * 0.5;  
      
    this.p1.x += px;  
    this.p1.y += py;  
    this.p2.x -= px;  
    this.p2.y -= py;  
};  
      
Constraint.prototype.draw = function() {  
      
    ctx.moveTo(this.p1.x, this.p1.y);  
    ctx.lineTo(this.p2.x, this.p2.y);  
};  
      
var Cloth = function() {  
      
    this.points = [];  
      
    var start_x = canvas.width / 2 - cloth_width * spacing / 2;  
      
    for(var y = 0; y <= cloth_height; y++) {  
      
        for(var x = 0; x <= cloth_width; x++) {  
      
            var p = new Point(start_x + x * spacing, start_y + y * spacing);  
      
   x != 0 && p.attach(this.points[this.points.length - 1]);  
            y == 0 && p.pin(p.x, p.y);  
            y != 0 && p.attach(this.points[x + (y - 1) * (cloth_width + 1)])  
      
            this.points.push(p);  
        }  
    }  
};  
      
Cloth.prototype.update = function() {  
      
    var i = physics_accuracy;  
      
    while(i--) {  
        var p = this.points.length;  
        while(p--) this.points[p].resolve_constraints();  
    }  
      
    i = this.points.length;  
    while(i--) this.points[i].update(.016);  
};  
      
Cloth.prototype.draw = function() {  
      
    ctx.beginPath();  
      
    var i = cloth.points.length;  
    while(i--) cloth.points[i].draw();  
      
    ctx.stroke();  
};  
      
function update() {  
      
    ctx.clearRect(0, 0, canvas.width, canvas.height);  
      
    cloth.update();  
    cloth.draw();  
      
    requestAnimFrame(update);  
}

打開html 文件就可以看到效果了,最好是在Chrome和Firefox 下查看效果。

也可以通過以下link 在線看效果:

http://lonely-pixel.com/lab/cloth/

 

其他的例子

除了以上撕扯窗布的效果,還可以看一些更多的類似效果

http://lonely-pixel.com/

框架

在這個JS框架橫行的年代,你有可能會問,有沒有一個JS框架,讓讓我很容易的實現這些效果。

答案是肯定的: 有,

verlet-js  就是比較好一個。

verlet-js的定位就是一個簡單的使用javascript實現的物理引擎。

官方的網址是:http://subprotocol.com/verlet-js/

可以看的例子有。

Examples

Shapes (Hello world):http://subprotocol.com/verlet-js/examples/shapes.html

Fractal Trees:http://subprotocol.com/verlet-js/examples/tree.html

Cloth:http://subprotocol.com/verlet-js/examples/cloth.html

Spiderweb:http://subprotocol.com/verlet-js/examples/spiderweb.html

那個蜘蛛在網上爬行的例子很炫。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved