Created
March 14, 2012 15:58
-
-
Save flying19880517/2037456 to your computer and use it in GitHub Desktop.
2D图形绘制测试
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!-- | |
http://www.ghost-hack.com/post/jsexperiments/tunneler/tunneler.html | |
--> | |
<html> | |
<head> | |
<style type="text/css"> | |
body | |
{ | |
font-family: Monospace; | |
background-color: #222222; | |
margin: 0px; | |
overflow: hidden; | |
} | |
</style> | |
<script type="text/javascript"> | |
var g; | |
var canvas; | |
var width = window.innerWidth ; | |
var height = window.innerHeight ; | |
var windowHalfX = window.innerWidth / 2; | |
var windowHalfY = window.innerHeight / 2; | |
var mouseX = 0; | |
var mouseY = 0; | |
var pmouseX = 0; | |
var pmouseY = 0; | |
var mousePressed = false; | |
var drawRate = 6; | |
var frameCount = 0; | |
var PI = Math.PI; | |
var TWO_PI = 2*Math.PI; | |
var HALF_PI = Math.PI*0.5; | |
function init(){ | |
canvas = document.getElementById('canvas'); | |
canvas.width = width; | |
canvas.height = height; | |
g = canvas.getContext('2d'); | |
g.setTransform(1, 0, 0, 1, 0,0); | |
document.addEventListener('mousemove', onDocumentMouseMove, false); | |
document.addEventListener('mousedown', onDocumentMouseDown, false); | |
document.addEventListener('mouseup', onDocumentMouseUp, false); | |
document.addEventListener('keydown', onDocumentKeyDown, false); | |
setup(); | |
drawInternal(); | |
} | |
function windowResize(){ | |
// width = window.innerWidth ; | |
// height = window.innerHeight ; | |
// canvas.width = width; | |
// canvas.height = height; | |
g.setTransform(1, 0, 0, 1, 0,0); | |
} | |
function onDocumentMouseMove(event) { | |
mouseX = event.clientX - canvas.offsetLeft; | |
mouseY = event.clientY - canvas.offsetTop; | |
} | |
function onDocumentMouseDown(event) { | |
mousePressed = true; | |
mousePressedEvent(); | |
} | |
function onDocumentMouseUp(event) { | |
mousePressed = false; | |
} | |
function onDocumentKeyDown(event){ | |
//setup(); | |
} | |
function drawInternal(){ | |
draw(); | |
setTimeout('drawInternal()', drawRate); | |
pmouseX = mouseX; | |
pmouseY = mouseY; | |
frameCount++; | |
} | |
function clear(){ | |
g.clearRect(0,0,width,height); | |
} | |
function line(x1, y1, x2, y2){ | |
g.beginPath(); | |
g.moveTo(x1,y1); | |
g.lineTo(x2,y2); | |
g.closePath(); | |
g.stroke(); | |
} | |
function fillStrokeCircle(x,y,radius){ | |
if(radius<=0) | |
radius = 0; | |
g.beginPath(); | |
g.arc(x, y, radius, 0, TWO_PI, true); | |
g.closePath(); | |
g.fill(); | |
g.stroke(); | |
} | |
function fillCircle(x, y, radius){ | |
if(radius<=0) | |
radius = 0; | |
g.beginPath(); | |
g.arc(x, y, radius, 0, TWO_PI, true); | |
g.closePath(); | |
g.fill(); | |
} | |
function strokeCircle(x, y, radius){ | |
if(radius<=0) | |
radius = 0; | |
g.beginPath(); | |
g.arc(x,y, radius, 0, TWO_PI, true); | |
g.stroke(); | |
} | |
function dist(ax, ay, bx, by) { | |
var dx = bx - ax; | |
dy = by - ay; | |
return Math.sqrt(dx * dx + dy * dy + dz * dz); | |
} | |
var currentRandom = Math.random; | |
// Pseudo-random generator | |
function Marsaglia(i1, i2) { | |
// from http://www.math.uni-bielefeld.de/~sillke/ALGORITHMS/random/marsaglia-c | |
var z=i1 || 362436069, w= i2 || 521288629; | |
var nextInt = function() { | |
z=(36969*(z&65535)+(z>>>16)) & 0xFFFFFFFF; | |
w=(18000*(w&65535)+(w>>>16)) & 0xFFFFFFFF; | |
return (((z&0xFFFF)<<16) | (w&0xFFFF)) & 0xFFFFFFFF; | |
}; | |
this.nextDouble = function() { | |
var i = nextInt() / 4294967296; | |
return i < 0 ? 1 + i : i; | |
}; | |
this.nextInt = nextInt; | |
} | |
Marsaglia.createRandomized = function() { | |
var now = new Date(); | |
return new Marsaglia((now / 60000) & 0xFFFFFFFF, now & 0xFFFFFFFF); | |
}; | |
// Noise functions and helpers | |
function PerlinNoise(seed) { | |
var rnd = seed !== undefined ? new Marsaglia(seed) : Marsaglia.createRandomized(); | |
var i, j; | |
// http://www.noisemachine.com/talk1/17b.html | |
// http://mrl.nyu.edu/~perlin/noise/ | |
// generate permutation | |
var p = new Array(512); | |
for(i=0;i<256;++i) { p[i] = i; } | |
for(i=0;i<256;++i) { var t = p[j = rnd.nextInt() & 0xFF]; p[j] = p[i]; p[i] = t; } | |
// copy to avoid taking mod in p[0]; | |
for(i=0;i<256;++i) { p[i + 256] = p[i]; } | |
function grad3d(i,x,y,z) { | |
var h = i & 15; // convert into 12 gradient directions | |
var u = h<8 ? x : y, | |
v = h<4 ? y : h===12||h===14 ? x : z; | |
return ((h&1) === 0 ? u : -u) + ((h&2) === 0 ? v : -v); | |
} | |
function grad2d(i,x,y) { | |
var v = (i & 1) === 0 ? x : y; | |
return (i&2) === 0 ? -v : v; | |
} | |
function grad1d(i,x) { | |
return (i&1) === 0 ? -x : x; | |
} | |
function lerp(t,a,b) { return a + t * (b - a); } | |
this.noise3d = function(x, y, z) { | |
var X = Math.floor(x)&255, Y = Math.floor(y)&255, Z = Math.floor(z)&255; | |
x -= Math.floor(x); y -= Math.floor(y); z -= Math.floor(z); | |
var fx = (3-2*x)*x*x, fy = (3-2*y)*y*y, fz = (3-2*z)*z*z; | |
var p0 = p[X]+Y, p00 = p[p0] + Z, p01 = p[p0 + 1] + Z, p1 = p[X + 1] + Y, p10 = p[p1] + Z, p11 = p[p1 + 1] + Z; | |
return lerp(fz, | |
lerp(fy, lerp(fx, grad3d(p[p00], x, y, z), grad3d(p[p10], x-1, y, z)), | |
lerp(fx, grad3d(p[p01], x, y-1, z), grad3d(p[p11], x-1, y-1,z))), | |
lerp(fy, lerp(fx, grad3d(p[p00 + 1], x, y, z-1), grad3d(p[p10 + 1], x-1, y, z-1)), | |
lerp(fx, grad3d(p[p01 + 1], x, y-1, z-1), grad3d(p[p11 + 1], x-1, y-1,z-1)))); | |
}; | |
this.noise2d = function(x, y) { | |
var X = Math.floor(x)&255, Y = Math.floor(y)&255; | |
x -= Math.floor(x); y -= Math.floor(y); | |
var fx = (3-2*x)*x*x, fy = (3-2*y)*y*y; | |
var p0 = p[X]+Y, p1 = p[X + 1] + Y; | |
return lerp(fy, | |
lerp(fx, grad2d(p[p0], x, y), grad2d(p[p1], x-1, y)), | |
lerp(fx, grad2d(p[p0 + 1], x, y-1), grad2d(p[p1 + 1], x-1, y-1))); | |
}; | |
this.noise1d = function(x) { | |
var X = Math.floor(x)&255; | |
x -= Math.floor(x); | |
var fx = (3-2*x)*x*x; | |
return lerp(fx, grad1d(p[X], x), grad1d(p[X+1], x-1)); | |
}; | |
} | |
// these are lifted from Processing.js | |
// processing defaults | |
var noiseProfile = { generator: undefined, octaves: 4, fallout: 0.5, seed: undefined}; | |
function noise(x, y, z) { | |
if(noiseProfile.generator === undefined) { | |
// caching | |
noiseProfile.generator = new PerlinNoise(noiseProfile.seed); | |
} | |
var generator = noiseProfile.generator; | |
var effect = 1, k = 1, sum = 0; | |
for(var i=0; i<noiseProfile.octaves; ++i) { | |
effect *= noiseProfile.fallout; | |
switch (arguments.length) { | |
case 1: | |
sum += effect * (1 + generator.noise1d(k*x))/2; break; | |
case 2: | |
sum += effect * (1 + generator.noise2d(k*x, k*y))/2; break; | |
case 3: | |
sum += effect * (1 + generator.noise3d(k*x, k*y, k*z))/2; break; | |
} | |
k *= 2; | |
} | |
return sum; | |
}; | |
function Worm(x,y){ | |
this.x = x; | |
this.y = y; | |
this.lx = x; | |
this.ly = y; | |
this.heading = Math.sin(frameCount*0.083) * PI;; | |
this.rotation = Math.random() * (PI / (Math.random() * 70)); | |
this.rate = 0; | |
this.maxLength = 15 + (noise(frameCount * 0.0025, frameCount*0.1) * 15); | |
this.detail = 2; | |
this.thickness = 3; | |
this.thicknessTarget = 5 + Math.random() * 10; | |
var cIndex = parseInt( Math.random() * colors.length ); | |
this.c = colors[cIndex]; | |
this.life = 30 + Math.random() * 120; | |
this.segments = new Array(); | |
this.ooo = true; | |
this.counter = noise(frameCount * 0.1, frameCount*.1); | |
this.update = function(){ | |
this.life--; | |
if(this.life > 0){ | |
this.thickness += (this.thicknessTarget-this.thickness) * 0.1; | |
this.thickness += 0.1; | |
if(this.thickness > this.thicknessTarget) | |
this.thickness = this.thicknessTarget; | |
this.heading += this.rotation; | |
this.rate = Math.cos( this.counter / 200.0) * (10 + noise(frameCount*0.05) * 10); | |
this.rotation = Math.sin(this.counter/this.rate) * (this.segments.length+1) * 0.010; | |
this.counter++; | |
var speedMod = (this.segments.length * this.segments.length * this.segments.length) * 0.0015 * this.thickness / this.thicknessTarget; | |
var totalSpeed = (this.detail + speedMod); | |
var nx = Math.cos(this.heading) * totalSpeed; | |
var ny = Math.sin(this.heading) * totalSpeed; | |
this.walk(nx,ny); | |
} | |
else{ | |
if(this.segments.length > 1){ | |
this.segments.pop(); | |
} | |
else{ | |
this.thickness*=0.95; | |
this.thickness-=0.2; | |
if(this.thickness<0.1) | |
this.ooo = true; | |
return; | |
} | |
} | |
this.ooo = true; | |
for(var i=0; i<this.segments.length; i++){ | |
var segment = this.segments[i]; | |
if(segment.ooo() == false){ | |
this.ooo = false; | |
break; | |
} | |
} | |
} | |
this.walk = function(nx,ny){ | |
this.lx = this.x; | |
this.ly = this.y; | |
this.x += nx; | |
this.y += ny; | |
var newSegment = new Segment(this.lx,this.ly,this.x,this.y,this.thickness); | |
this.segments.unshift(newSegment); | |
if(this.segments.length > 1) | |
this.segments[this.segments.length-1].smoothAgainst(this.segments[this.segments.length-2]); | |
if(this.segments.length >= this.maxLength){ | |
this.segments.pop(); | |
} | |
} | |
} | |
function Segment(x1,y1,x2,y2,thickness){ | |
this.x1 = x1; | |
this.y1 = y1; | |
this.x2 = x2; | |
this.y2 = y2; | |
this.thickness = thickness; | |
var angle = Math.atan2(y2-y1,x2-x1); | |
this.lAngle = angle - HALF_PI; | |
var lDeltaX = Math.cos(this.lAngle) * thickness; | |
var lDeltaY = Math.sin(this.lAngle) * thickness; | |
this.leftX1 = x1 + lDeltaX; | |
this.leftY1 = y1 + lDeltaY; | |
this.leftX2 = x2 + lDeltaX; | |
this.leftY2 = y2 + lDeltaY; | |
this.rAngle = angle + HALF_PI; | |
var rDeltaX = Math.cos(this.rAngle) * thickness; | |
var rDeltaY = Math.sin(this.rAngle) * thickness; | |
this.rightX1 = x1 + rDeltaX; | |
this.rightY1 = y1 + rDeltaY; | |
this.rightX2 = x2 + rDeltaX; | |
this.rightY2 = y2 + rDeltaY; | |
this.smoothAgainst = function(last){ | |
this.leftX1 = last.leftX2 = (last.leftX2 + this.leftX1) * 0.5; | |
this.leftY1 = last.leftY2 = (last.leftY2 + this.leftY1) * 0.5; | |
this.rightX1 = last.rightX2 = (last.rightX2 + this.rightX1) * 0.5; | |
this.rightY1 = last.rightY2 = (last.rightY2 + this.rightY1) * 0.5; | |
} | |
this.ooo = function(){ | |
if(this.x1 < 0 || this.y1 < 0 || this.x1 > width || this.y1>height || | |
this.x2 < 0 || this.y2 < 0 || this.x2 > width || this.y2>height) | |
return true; | |
else | |
return false; | |
} | |
} | |
var worms; | |
var colors = []; | |
colors[0] = '#2cd9fe'; | |
colors[1] = '#2cfecf'; | |
colors[2] = '#373fdf'; | |
colors[3] = '#88fe1f'; | |
colors[4] = '#48d6ff'; | |
colors[5] = '#b3fcff'; | |
colors[6] = '#f76cad'; | |
colors[7] = '#505083'; | |
colors[8] = '#113a7e'; | |
colors[9] = '#014050'; | |
colors[10] = '#ccf3ef'; | |
colors[11] = '#009437'; | |
colors[12] = '#8fb300'; | |
function setup(){ | |
worms = new Array(); | |
} | |
function draw(){ | |
clear(); | |
for(var w=0; w<worms.length; w++){ | |
var worm = worms[w]; | |
worm.update(); | |
g.fillStyle = worm.c; | |
g.lineWidth = 2; | |
g.strokeStyle = '#ffffff'; | |
if(worm.segments.length>1){ | |
g.beginPath(); | |
g.moveTo(worm.segments[0].leftX1, worm.segments[0].leftY1); | |
for(var i=0; i<worm.segments.length; i++){ | |
var segment = worm.segments[i]; | |
g.lineTo(segment.leftX1,segment.leftY1); | |
} | |
g.lineTo(worm.segments[worm.segments.length-1].rightX1, worm.segments[worm.segments.length-1].rightY1); | |
for(var i=worm.segments.length-1; i>=0; i--){ | |
var segment = worm.segments[i]; | |
g.lineTo(segment.rightX1,segment.rightY1); | |
} | |
g.closePath(); | |
// g.stroke(); | |
g.fill(); | |
g.stroke(); | |
} | |
g.strokeStyle = '#ffffff'; | |
if(worm.segments.length>=1){ | |
var x = worm.segments[0].x1; | |
var y = worm.segments[0].y1; | |
var thickness = worm.segments[0].thickness; | |
if(worm.thickness<thickness) | |
thickness = worm.thickness; | |
if(thickness<=0) | |
thickness = 0.000001; | |
g.beginPath(); | |
g.arc(x, y, thickness, worm.segments[0].lAngle, worm.segments[0].rAngle, false); | |
g.closePath(); | |
//g.fill(); | |
g.stroke(); | |
var xEnd = worm.segments[worm.segments.length-1].x1; | |
var yEnd = worm.segments[worm.segments.length-1].y1; | |
thickness = worm.segments[worm.segments.length-1].thickness; | |
if(worm.thickness<thickness) | |
thickness = worm.thickness; | |
if(thickness<=0) | |
thickness = 0.000001; | |
g.beginPath(); | |
g.arc(xEnd, yEnd, thickness, worm.segments[worm.segments.length-1].lAngle, worm.segments[worm.segments.length-1].rAngle, true); | |
g.closePath(); | |
//g.fill(); | |
g.stroke(); | |
thickness = worm.thickness-0.6; | |
if(worm.thickness<thickness) | |
thickness = worm.thickness; | |
fillCircle(worm.segments[0].x1,worm.segments[0].y1,thickness); | |
thickness = worm.segments[worm.segments.length-1].thickness-0.6; | |
if(worm.thickness<thickness) | |
thickness = worm.thickness; | |
fillCircle(worm.segments[worm.segments.length-1].x1,worm.segments[worm.segments.length-1].y1,thickness); | |
if(worm.life>0){ | |
g.fillStyle = "#FFFFFF"; | |
fillCircle(worm.segments[0].x1,worm.segments[0].y1,thickness * 0.72); | |
} | |
} | |
} | |
for(var w=0; w<worms.length; w++){ | |
var worm = worms[w]; | |
if(worm.ooo){ | |
worms.splice(w,1); | |
w--; | |
} | |
} | |
if(frameCount %2 ==0 && mousePressed && worms.length < 50){ | |
var direction = Math.atan2(pmouseY-mouseY, pmouseX-mouseX) + PI; | |
var newWorm = new Worm(mouseX,mouseY); | |
worms.push( newWorm ); | |
if(mouseX!=pmouseX && mouseY!=pmouseY) | |
newWorm.heading = direction; | |
} | |
} | |
function mousePressedEvent(){ | |
} | |
</script> | |
<link rel="stylesheet" type="text/css" href="http://fonts.googleapis.com/css?family=Lobster"> | |
<style> | |
body { | |
font-family: 'Lobster', serif; | |
font-size: 72px; | |
color: #FFFFFF; | |
} | |
</style> | |
</head> | |
<body onload="init()" onresize="windowResize()"> | |
<div style="position:relative;top:250px;z-index:1;-moz-user-select: none;-khtml-user-select: none; | |
user-select: none;"> | |
<center> | |
hold me | |
</center> | |
</div> | |
<div style="z-index:4; position:absolute; top:0; left:0"> | |
<canvas id="canvas"></canvas> | |
</div> | |
</body> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment