convas demo1

时间:2023-06-26 09:20:56
1 getContext

语法

Canvas.getContext(contextID)

参数

参数 contextID 指定了您想要在画布上绘制的类型。当前唯一的合法值是 "2d",它指定了二维绘图,并且导致这个方法返回一个环境对象,该对象导出一个二维绘图 API。

提示:在未来,如果 <canvas> 标签扩展到支持 3D 绘图,getContext() 方法可能允许传递一个 "3d" 字符串参数。

返回值

一个 CanvasRenderingContext2D 对象,使用它可以绘制到 Canvas 元素中。

2

可以用下面两种方法直接设置变换矩阵:

context.transform(m11, m12, m21, m22, dx, dy)
context.setTransform(m11, m12, m21, m22, dx, dy)
第一个方法直接将当前的变形矩阵乘上下面的矩阵(注意排列的顺序):
m11  m21  dx
m12  m22  dy
0       0       1
第二个方法会重置当前的变形矩阵为单位矩阵,然后以相同的参数调用transform方法。

function draw() {  
  var canvas = document.getElementById("lesson01");  
  var ctx = canvas.getContext("2d");  
  
  var sin = Math.sin(Math.PI/6);  
  var cos = Math.cos(Math.PI/6);  
  ctx.translate(200, 200);  
  var c = 0;  
  for (var i=0; i <= 12; i++) {  
    c = Math.floor(255 / 12 * i);  
    ctx.fillStyle = "rgb(" + c + "," + c + "," + c + ")";  
    ctx.fillRect(0, 0, 100, 10);  
    ctx.transform(cos, sin, -sin, cos, 0, 0);  
  }  
    
  ctx.setTransform(-1, 0, 0, 1, 200, 200);  
  ctx.fillStyle = "rgba(255, 128, 255, 0.5)";  
  ctx.fillRect(0, 50, 100, 100);  
}

  所有的变换起始都是通过变换矩阵实现的,所以上述的平移,旋转,缩放都可以用相应的矩阵代替,精通数学的同学可以自己推导出来:
平移:context.translate(dx,dy)可以使用context.transform (1,0,0,1,dx,dy)或者context.transform(0,1,1,0.dx,dy)代替。
旋转:context.rotate(θ)可以使用context.transform(Math.cos(θ*Math.PI/180),Math.sin(θ*Math.PI/180),-Math.sin(θ*Math.PI/180),Math.cos(θ*Math.PI/180),0,0)或者

context.transform(-Math.sin(θ*Math.PI/180),Math.cos(θ*Math.PI/180),Math.cos(θ*Math.PI/180),Math.sin(θ*Math.PI/180), 0,0)代替。
缩放:context.scale(sx, sy)可以使用context.transform(sx,0,0,sy,0,0)或者context.transform(0,sy,sx,0, 0,0)代替。

<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>