您的位置:首页 > 其它

Canvas基础入门

2015-06-05 22:30 344 查看

Canvas学习笔记

标签(空格分隔):HTML5 Canvas

canvas基础知识

canvas元素

<canvas width="500" height="500"> // 默认宽度和高度为350和150像素
</canvas>


坐标系统

2D渲染上下文是一种基于屏幕的标准绘图平台,采用笛卡尔坐标体系,左上角为原点
(0, 0)
,坐标系统的一个单位相当于屏幕的1个像素。可以通过Javascript来访问2D渲染上下文。

绘制基本的图形和线条

矩形,有三个方法:
rect
fillRect
strokeRect
分别绘制矩形,填充矩形和矩形(无填充有边框)

/* rect(x, y, width, height) 4个参数,前两个表示矩形左上角的坐标值,width和height分别表示矩形的宽度和高度*/
context.fillRect(40, 40, 100, 100) // 填充矩形
context.fillRect(40, 40, 100, 100) // 线框矩形


线条,可以通过线条的组合画出很多的图形

/* 画线条*/
context.lineWidth = 2; // 设置线条的宽度,默认为1
context.beginPath(); // 开始路径
context.moveTo(0, 0); // 设置路径原点
context.lineTo(300, 100); // 设置路径终点
context.closePath(); // 结束路径
context.stroke(); // 绘出路径轮廓


圆弧,圆弧最常见的应用就是画圆形,圆弧首位相连就是一个圆形,用方法
arc
context.arc(x, y, radius, startAngle, endAngle, anticlockwise)
, 前三个参数代表圆心的坐标和半径的大小,第四个和第五参数表示开始角度和结束角度,第六个参数是一个布尔值,逆时针则为true,顺时针为false

/* 画圆形*/
context.beginPath();
context.arc(50, 50, 50, 0, Math.PI*3/2, false);
context.closePath();
context.fill(); // 填充整个圆形
context.stroke(); // 绘出圆形轮廓(线框图)


绘制文本,canvas文本以图像形式绘制,无法通过鼠标选取,不能编辑。通过方法
fillText
绘制,还可以修改文本的样式

/* 绘制文本*/
var text = "hello world!";
context.font = " italic 50px serif"; // 修改字号和字体
context.fillText(text, 40, 40);
context.strokeText(text, 40, 40);


修改样式,通过方法
fillStyle
方法可以修改形状和路径的填充颜色,方法
lineWidth
可以修改线宽,默认为1。

context.fillStyle = "rgb(255, 0, 0)";
context.lineWidth = 5; // 加粗线条


擦除canvas,
clearRect(x, y, width, height)
可以部分清除一个矩形大小的区域

context.clearRect(0, 0, canvas.width(), canvas.height()); // 清除全部canvas区域


canvas 高级功能

绘图状态

在画布中,绘图状态指的是描述某一个时刻2D渲染上下文外观的整套属性,从简单的颜色值到变换矩阵。可以通过方法
save
restore
保存和恢复绘图状态

context.fillStyle = "rgb(255, 0, 0)";
context.save(); // 保存画布状态
context.fillRect(50, 50, 100, 100); // 红色正方形

context.fillStyle = "rgb(0, 0, 225)";
context.fillRect(200, 50, 100, 100); // 蓝色正方形

// context.restore(); // 恢复画布状态
context.fillRect(350, 50, 100, 100); // 红色正方形


可以同时保存和恢复多个绘图状态,各个绘图状态以栈的形式储存,先进后出,每恢复一个绘图状态就从栈顶取出,直到栈空

context.fillStyle = "rgb(255, 0, 0)";
context.save(); // 保存画布状态
context.fillRect(50, 50, 100, 100); // 红色正方形

context.fillStyle = "rgb(0, 0, 225)";
context.save(); // 保存画布状态
context.fillRect(200, 50, 100, 100); // 蓝色正方形

// context.restore(); // 恢复画布状态
context.fillRect(350, 50, 100, 100); // 蓝色正方形

context.restore(); // 恢复画布状态
context.fillRect(50, 200, 100, 100); // 红色正方形


变形

平移,移动2D渲染上下文的坐标原点

context.translate(150, 150); // 平移原点的坐标到(150, 150)


缩放,调整2D渲染上下文的尺寸,分别在x方向和y方向上

context.scale(2, 2); // x和y方向都乘以2


旋转,将2D渲染上下文绕其原点进行旋转

context.rotate(0.7854); // 旋转45度(Math.PI/4)


变换矩阵,3X3的矩阵,默认为单位矩阵,可以通过方法
setTransform
transform
修改其值的大小

/* 变换矩阵*/
context.setTransform(1,0,0,1,0,0);
var xScale = Math.cos(0.7845);
var ySkew = -Math.sin(0.7845);
var xSKew = Math.sin(0.7845);
var yScale = Math.cos(0.7845);
var xTrans = 100;
var yTrans = 100;

context.transform(xScale, ySkew, xSKew, yScale, xTrans, yTrans);
context.fillRect(-50, -50, 100, 100);


合成

阿尔法值,可以通过设置
globalAlpha
设置全局阿尔法值也可通过
rgba
设置样式的阿尔法值。
globalAlpha
的值必须在0.0(透明)到1.0(不透明)之间,影响透明度。

合成,设置两个图形层叠时候的处理方式,
globalCompositeOperation
有11种可选方法,但是游览器并不支持所有属性。介绍两种常用的
source-top
默认值,后面的图形盖住前面的,
destination-over
前面的盖住后面的。

高级样式

阴影,通过4个属性进行控制,
shadowBlur
,
shadowOffsetX
,
shadowOffsetY
,
shadowColor


context.shadowBlur = 80; // 模糊值
context.shadowOffsetX = 10; // 阴影长度
context.shadowOffsetY = 10;
context.shadowColor = "rgba(100, 100, 100, 0.5)"; // 阴影颜色
context.fillRect(50, 50, 100, 100);


渐变,分为线性渐变和放射性渐变

/* 线性渐变色*/
var gradient = context.createLinearGradient(0, 0, 0, canvas.height());
gradient.addColorStop(0, "rgb(0, 0, 0)"); // 0,渐变起点
gradient.addColorStop(1, "rgb(255, 255, 255)"); // 1,渐变终点

context.fillStyle = gradient;
context.fillRect(0, 0, canvas.width(), canvas.height());


复杂路径,可以通过线条的组合画出很多比较复杂的图形

/* 画三角形*/
context.beginPath();
context.moveTo(100, 50);
context.lineTo(150, 150);
context.lineTo(50, 150);
context.closePath();
context.stroke();
context.fill();


贝塞尔曲线,二次贝塞尔曲线有一个控制点,三次贝塞尔曲线有两个控制点,可以用来画三角函数图形。

/* 二次贝塞尔曲线*/
context.lineWidth = 5; // 线宽
context.beginPath();
context.moveTo(50, 250); 起点坐标
context.quadraticCurveTo(250, 100, 450, 250); 终点坐标(450, 250),控制点坐标(250, 100)
context.stroke();

/* 三次贝塞尔曲线*/
context.lineWidth = 5;
context.beginPath();
context.moveTo(50, 250);
context.bezierCurveTo(150, 50, 350, 450, 450, 250); // 两个控制点
context.stroke();


处理图像和视频

加载图像

调用函数
drawImage
至少需要3个参数,所绘制的图像,图像绘制位置的(x, y)坐标

var image = new Image();
image.src = "example.jpg";
$(image).load(function(){
context.drawImage(image, 0, 0);
});


函数
drawImage
还可以调整图像的大小和canvas画布的大小相匹配

context.drawImage(image, 0, 0, width, height);

函数
drawImage
将图像裁剪至你想要的大小,并可以做相应的放大和缩小,此时共需要9个参数,源图像,源图像的裁剪区原点坐标(x,y),源图像的裁剪区宽度和高度,在画布上绘制图像的原点坐标(x,y)及在画布上绘制图像的宽度和高度。

context.drawImage(image, sx, sy, sw, sh, dx, dy, dw, dh);

图像变形

对图像的变形如阴影,平移,旋转以及缩放和对整个画布进行的变形使用的方法是一致的。

访问像素值

在画布中访问像素的方法是
getImageData
, 有4个参数,要访问的像素区域的原点坐标(x,y),像素区域的宽度和高度。返回一个ImageData对象,这个对象包含3个属性:width,height,data,最重要的是属性值data,是一个包含了所访问区域全部像素信息的一维数组。

var imageData = context.getImageData(x, y, width, height);
var pixel = imageData.data; // 一维数组 `4*widht*height`, *rgba*


通过对像素值的访问我们可以对图像进行一些处理,如反转图像,灰度化图像,以及像素化。实例代码:

/* 通过访问图像像素值实现基本的图像效果*/
var image = new Image();
image.src = "example.jpg";
$(image).load(function(){
context.drawImage(image, 0, 0, 500, 500);

var imageData = context.getImageData(0, 0, canvas.width(), canvas.height());
var pixels = imageData.data;
var numPixels = pixels.length;

context.clearRect(0, 0, canvas.width(), canvas.height);

//  反转颜色,255 减去当前颜色值所得就是反转后的颜色
for(var i = 0; i < numPixels; i++){
pixels[i*4] = 255 - pixels[i];
pixels[i*4 + 1] = 255 - pixels[i*4 + 1];
pixels[i*4 + 2] = 255 - pixels[i*4 + 2];
}
// 灰度化图像,计算现有颜色的平均值
for(var i =0; i < numPixels; i++){
var average = (pixels[i*4]+pixels[i*4+1]+pixels[i*4+2])/3;
pixels[i*4] = average;
pixels[i*4+1] = average;
pixels[i*4+1] = average;
}
context.putImageData(imageData, 0, 0);
})


像素化图像类似于打马赛克的效果,可以将图像变得不可识别。

// 小方块在每行每列上的数目
var numTileRows = 50;
var numTileCols = 50;

// 每个小方块的宽度和长度
var tileWidth = imageData.width/numTileRows;
var tileHeight = imageData.height/numTileCols;

for(var r = 0; r < numTileRows; r++){
for(var c = 0; c < numTileCols; c++){
// 小方块中心的坐标
var x = (c*tileWidth)+(tileWidth/2);
var y = (r*tileHeight)+(tileHeight/2);
// 小方块中心的像素值
var pos = (Math.floor(y)*(imageData.width*4)) + (Math.floor(x)*4);

var red = pixels[pos];
var green = pixels[pos + 1];
var blue = pixels[pos + 2];

context.fillStyle = "rgb("+red+", "+green+", "+blue+")";

// 马赛克效果
context.fillRect(x-(tileWidth/2), y-(tileHeight/2), tileWidth, tileHeight);
}
}


视频处理

视频处理的原理和处理图像几乎一样,只是处理的是视频当前帧的图像值,不再赘述。

制作动画

更新,清除,绘制

动画的原理就是使得一个动画对象不断的更新,清除和绘制。只要这个循环的速度到一定程度就可产生动画效果

function animate(){

// 消除
context.clearRect(0, 0, canvasWidth, canvasHeigth);

var shapesLength = shapes.length;
for(var i = 0; i < shapesLength; i++){
var tmpShape = shapes[i];

/* 更新*/
// tmpShape.x += 2;
// tmpShape.y++;

// tmpShape.x += Math.random()*4 - 2;
// tmpShape.y += Math.random()*4 - 2;

//圆周运行
tmpShape.x += (tmpShape.radius*Math.cos(tmpShape.angle*(Math.PI/180)));
tmpShape.y += (tmpShape.radius*Math.sin(tmpShape.angle*(Math.PI/180)));

// 增大角度
tmpShape.angle += 5;
if(tmpShape.angle >= 360){
tmpShape.angle = 0;
}

// 绘制
context.fillRect(tmpShape.x, tmpShape.y, tmpShape.width, tmpShape.height);
}

if(playAnimate){
setTimeout(animate, 33);
}
};


反弹效果

$(document).ready(function(){
var canvas = $("#myCanvas");
var context = canvas.get(0).getContext("2d");

var canvasWidth = canvas.width();
var canvasHeight = canvas.height();

var playAnimation = true;

var startButton = $("#startAnimation");
var stopButton = $("#stopAnimation");

// 添加按钮时间处理
startButton.hide();
startButton.click(function() {
$(this).hide();
stopButton.show();

playAnimation = true;
animate();
});

stopButton.click(function() {
$(this).hide();
startButton.show();

playAnimation = false;
});

// 图形类
var Shape = function(x, y, width, height) {
this.x = x;
this.y = y;
this.width = width;
this.height = height;

/* 可以通过修改运动的默认值,来设置运动方式*/
this.reverseX = false;
this.reverseY = true;
};

var shapes = new Array();

// 创造图形
for (var i = 0; i < 10; i++) {
var x = Math.random()*250;
var y = Math.random()*250;
var width = height = Math.random()*30;
shapes.push(new Shape(x, y, width, height));
};

context.clearRect(0, 0, canvasWidth, canvasHeight);

var shapesLength = shapes.length;
for (var i = 0; i < shapesLength; i++) {
var tmpShape = shapes[i];

// 更新
// 检查是否碰壁
if (!tmpShape.reverseX) {
tmpShape.x += 2;
} else {
tmpShape.x -= 2;
};

if (!tmpShape.reverseY) {
tmpShape.y += 2;
} else {
tmpShape.y -= 2;
};

// 绘制
context.fillRect(tmpShape.x, tmpShape.y, tmpShape.width, tmpShape.height);

// 检查碰壁
if (tmpShape.x < 0) {
tmpShape.reverseX = false;
} else if (tmpShape.x + tmpShape.width > canvasWidth) {
tmpShape.reverseX = true;
};

if (tmpShape.y < 0) {
tmpShape.reverseY = false;
} else if (tmpShape.y + tmpShape.height > canvasHeight) {
tmpShape.reverseY = true;
};

};

if (playAnimation) {
setTimeout(animate, 33);
};
};

animate();
});
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: