点击渔网拖动可以移动渔网,渔网上方的三个点点击后拖动可以将他放下。贴上部分源码,其他的自己去看demo,js已经合并到一起..
附上源码效果: 挂着的渔网</script>
<script type="text/javascript">
var FastVector = function(x,y){
this.x = x;
this.y = y;
};FastVector.prototype = {
add: function (B,internal) {
var nx, ny;
if (typeof(B)=='number'){
nx = this.x+B;
ny = this.y+B;
}else{
nx = this.x+B.x;
ny = this.y+B.y;
}
return new FastVector(nx,ny);
},
add_: function(B) {
if (typeof(B)=='number'){
this.x+=B; this.y+=B;
}else{
this.x+=B.x; this.y+=B.y;
}
return this;
},
dot: function(B) {
return ((this.x*B.x)+(this.y*B.y));
},
length: function() {
return Math.sqrt((this.x*this.x)+(this.y*this.y));
},
multiply: function(B) {
var nx, ny;
if (typeof(B)=='number'){
nx = this.x*B; ny = this.y*B;
}else{
nx = this.x*B.x; ny = this.y*B.y;
}
return new FastVector(nx,ny);
},
multiply_: function(B) {
if (typeof(B)=='number'){
this.x*=B; this.y*=B;
}else{
this.x*=B.x; this.y*=B.y;
}
return this;
},
squaredLength: function(args) {
return (this.x*this.x)+(this.y*this.y);
},
sum: function(){
return this.x+this.y;
},
subtract: function(B) {
var nx, ny;
if (typeof(B) == 'number'){
nx = this.x-B; ny = this.y-B;
}else{
nx = this.x-B.x; ny = this.y-B.y;
}
return new FastVector(nx,ny);
},
subtract_: function(B) {
if (typeof(B) == 'number'){
this.x-=B; this.y-=B;
}else{
this.x-=B.x; this.y-=B.y;
}
return this;
},
toString: function() {
return "["+this.x+","+this.y+"]";
}};
</script>
<script type="text/javascript">
(function(){var two_pi = Math.PI * 2;
var Canvas = this.Canvas = function(canvas){
this.canvas = canvas;
this.ctx = this.canvas.getContext('2d');
this.ctx.fillStyle = this.ctx.strokeStyle = 'black';
this.width = this.canvas.width;
this.height = this.canvas.height;
};Canvas.prototype={
adjust: function(pos) {
var location = this.canvas.getPosition(),
lx = location.x,
ly = location.y,
px = pos.x,
py = pos.y;
var inside = (px > lx && px < lx + this.width && py > ly && py < ly + this.height);
return inside ? new FastVector((pos.x - lx) / this.canvas.width, (pos.y - ly) / this.canvas.height) : null;
},
clear: function(){
this.ctx.clearRect(0, 0, this.width, this.height);
},
circle: function(p, r){
x = p.x * this.width;
y = p.y * this.height;
this.ctx.beginPath();
this.ctx.moveTo(x + r, y);
this.ctx.arc(x, y, r, 0, two_pi, false);
this.ctx.fill();
},
line: function(x1, x2){
this.ctx.beginPath();
this.ctx.moveTo(x1.x * this.width, x1.y * this.height);
this.ctx.lineTo(x2.x * this.width, x2.y * this.height);
this.ctx.stroke();
}
};
})();
</script>
<script type="text/javascript">
var Point = function(canvas, x, y){
this.canvas = canvas;
this.current = this.previous = new FastVector(x, y);
this.mass = this.inv_mass = 1;
this.force = new FastVector(0.0,0.5).multiply(0.05 * 0.05);
this.radius = 3;
};Point.prototype = {
setCurrent: function(p) {
this.current = p;
},
setPrevious: function(p) {
this.previous = p;
},
getCurrent: function() {
return this.current;
},
getPrevious: function() {
return this.previous;
},
move: function() {
if (this.inv_mass!=0){
var new_pos = this.current.multiply(1.99).subtract(this.previous.multiply(0.99)).add(this.force);
new_pos.x = (new_pos.x < 0) ? 0 : ((new_pos.x > 1) ? 1 : new_pos.x);
new_pos.y = (new_pos.y < 0) ? 0 : ((new_pos.y > 1) ? 1 : new_pos.y);
this.previous = this.current;
this.current = new_pos;
}
},
draw: function() {
this.canvas.circle(this.current, this.radius);
}
};
</script>
<script type="text/javascript">
var Constraint = function(canvas, p1, p2, rl){
this.canvas = canvas;
this.p1 = p1;
this.p2 = p2;
this.rest_length = rl || p1.getCurrent().subtract(p2.getCurrent()).length();
this.squared_rest_length = this.rest_length * this.rest_length;
};Constraint.prototype = {
draw: function(){
this.canvas.line(this.p1.getCurrent(), this.p2.getCurrent());
},
satisfy: function(){
var p1 = this.p1.getCurrent();
var p2 = this.p2.getCurrent();
var delta = p2.subtract(p1);
var p1_im = this.p1.inv_mass;
var p2_im = this.p2.inv_mass;
var d = delta.squaredLength();
var diff = (d - this.squared_rest_length) / ((this.squared_rest_length + d) * (p1_im + p2_im));
if (p1_im != 0){
this.p1.setCurrent(p1.add(delta.multiply(p1_im * diff)));
}
if (p2_im != 0){
this.p2.setCurrent( p2.subtract(delta.multiply(p2_im*diff)) );
}
}
};
</script>
<script type="text/javascript">
document.addEvent('domready', function(){
var canvas = new Canvas(document.getElement('canvas')),
cloth = new Cloth(canvas),
inputs = {}, point,
key_down, mouse_down, mouse;
var position = function(event){
return canvas.adjust({
x: event.page.x,
y: event.page.y
});
};
var setPoint = function(inv_mass){
if (!point) return;
if (mouse) {
point.setCurrent(mouse);
point.setPrevious(mouse);
}
point.inv_mass = inv_mass;
};
document.addEvents({
'keydown': function(event){
key_down = true;
},
'keyup': function(){
key_down = false;
},
'mousedown': function(event){
mouse_down = true;
mouse = position(event);
if (!mouse) return;
point = cloth.getClosestPoint(mouse);
setPoint(0);
},
'mouseup': function(event){
mouse_down = false;
if (mouse) setPoint( key_down ? 0 : 1);
},
'mousemove': function(event){
if (!mouse_down) return;
mouse = position(event);
setPoint(mouse ? 0 : 1);
}
});
document.getElements('input').each(function(input){
inputs[input.getProperty('id')] = input;
});
inputs.points.addEvent('click', cloth.togglePoints.bind(cloth));
inputs.constraints.addEvent('click', cloth.toggleConstraints.bind(cloth));
cloth.draw_points = inputs.points.checked;
cloth.draw_constraints = inputs.constraints.checked;
setInterval(cloth.update.bind(cloth), 35);
});var Cloth = function(canvas){
var max_points = 15,
width = canvas.width,
height = canvas.height,
max_dim = Math.max(width, height),
min_dim = Math.min(width, height),
x_offset = width * 0.2,
y_offset = height * 0.2,
spacing = (max_dim - (Math.max(x_offset, y_offset) * 2)) / max_points;
this.num_iterations = 2;
this.canvas = canvas;
this.points = [];
this.constraints = [];
var num_x_points = this.num_x_points = (max_points * (width / max_dim)).round();
var num_y_points = this.num_y_points = (max_points * (height / max_dim)).round();
var constraint;
for (var i = 0, y = y_offset; i < num_y_points; i++, y += spacing){
this.points[i] = [];
for (var j = 0, x = x_offset; j < num_x_points; j++, x += spacing){
var point = new Point(canvas, x / width, y / height);
this.points[i][j] = point;
if (i > 0){
constraint = new Constraint(canvas, this.points[i - 1][j], this.points[i][j]);
this.constraints.push(constraint);
}
if (j > 0){
constraint = new Constraint(canvas, this.points[i][j - 1], this.points[i][j]);
this.constraints.push(constraint);
}
}
}
this.points[0][0].inv_mass = 0;
this.points[0][(num_x_points / 2).floor()].inv_mass = 0;
this.points[0][num_x_points - 1].inv_mass = 0;this.num_constraints = this.constraints.length;
for (i = 0; i < this.num_constraints; i++)
this.constraints[i].draw();
};Cloth.prototype = {
update: function() {
this.canvas.clear();
var num_x = this.num_x_points,
num_y = this.num_y_points,
num_c = this.num_constraints,
num_i = this.num_iterations,
i, j;
for (i = 0; i < num_y; i++)
for (j = 0; j < num_x; j++)
this.points[i][j].move();
for (j = 0; j < num_i; j++)
for (i = 0; i < num_c; i++)
this.constraints[i].satisfy();
if (this.draw_constraints)
for (i = 0; i < this.num_constraints; i++)
this.constraints[i].draw();
if (this.draw_points)
for (i = 0; i < this.num_y_points; i++)
for (j = 0; j < this.num_x_points; j++)
this.points[i][j].draw();
},
getClosestPoint: function(pos) {
var min_dist = 1,
min_point = null,
num_x = this.num_x_points,
num_y = this.num_y_points,
dist, i, j;
for (i = 0; i < num_y; i++){
for (j = 0; j < num_x; j++){
dist = pos.subtract(this.points[i][j].getCurrent()).length();
if (dist < min_dist){
min_dist = dist;
min_point = this.points[i][j];
}
}
}
return min_point;
},
toggleConstraints: function(){
this.draw_constraints = !this.draw_constraints;
},
togglePoints: function(){
this.draw_points = !this.draw_points;
}
};
</script>