第一节
1、利用document.getElementById('canvas') 获取指向canvas的引用
2、在canvas对象上调用getContext('2d')方法,获取绘图环境变量
3、font设置字体、fillStyle用来填充fillText设置的字符, strokeStyle用来给strokeText的字符来进行描边。
4、fillStyle,strokeStyle可以是颜色,渐变色,或者图案
code
var canvas = document.getElementById('canvas');
const context = canvas.getContext('2d');
context.font = '38pt Arial';
context.fillStyle = 'cornflowerblue';
context.strokeStyle = 'blue';
context.fillText('Hello Canvas', canvas.width / 2 - 150, canvas.height / 2 + 15);
context.strokeText('Hello Canvas', canvas.width / 2 - 150, canvas.height / 2 + 15);
第二节 canvas状态的保存和恢复
1、canvas API 提供了两个API save() 和 restore()两个方法
2、save 讲当前canvas的状态推送到一个保存canvas状态的堆栈顶部、restore()将原来保存在栈顶的那一组状态,弹出后,就被设置成canvas当前的状态了,在save和restore之间设置状态,只会持续至restore()方法被调用之前。
第三节 基本的绘制操作
demo 绘制一个时钟
code
1、先画一个圆圈
function drawCirCle () {
context.beginPath();
context.arc(canvas.width / 2, canvas.height / 2, RADIUS, 0, Math.PI * 2, true);
context.stroke();
}
其中 beiginPath 是开始一个新路径
arc是描绘一个圆圈 arc里面的参数有
context.arc(x,y,r,sAngle,eAngle,counterclockwise);
参数 描述
x 圆的中心的 x 坐标。
y 圆的中心的 y 坐标。
r 圆的半径。
sAngle 起始角,以弧度计。(弧的圆形的三点钟位置是 0 度)。
eAngle 结束角,以弧度计。
counterclockwise 可选。规定应该逆时针还是顺时针绘图。False = 顺时针,true = 逆时针。
stroke 是对线条进行描绘
2、画一个实心小点
function drawCenter () {
context.beginPath();
context.arc(canvas.width / 2, canvas.height / 2, 5, 0, Math.PI * 2, true);
context.fill();
}
fill 是实心填充,区分stroke
3、将数字时钟渲染至画面
function drawNumerals () {
var numerals = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12];
var angle = 0;
var numeralsWidth = 0;
numerals.forEach(function (numeral) {
angle = Math.PI / 6 * (numeral - 3);
numeralsWidth = context.measureText(numeral).width;
context.fillText(numeral,
canvas.width / 2 + Math.cos(angle) * HAND_RADIUS - numeralsWidth / 2,
canvas.height / 2 + Math.sin(angle) * (HAND_RADIUS) + FONT_HEIGHT / 3
);
});
}
mearsureText 用来获取指定文本的宽度
fillText用来渲染在画面上被填充的文本
context.fillText(text,x,y,maxWidth);
参数 描述
text 规定在画布上输出的文本。
x 开始绘制文本的 x 坐标位置(相对于画布)。
y 开始绘制文本的 y 坐标位置(相对于画布)。
maxWidth 可选。允许的最大文本宽度,以像素计。
回想一下高中数学,我们知道了半径以后,分成四个象限的圆,怎么获取每一个角度的坐标轴 就是用sin 和 cos
第四步,画时钟,分钟,秒钟
function drawHand (loc, isHour) {
var angle = (Math.PI * 2) * (loc / 60) - (Math.PI / 2);
var handRadius = isHour ? RADIUS - HAND_TRUNCATION - HOUR_HAND_TRUNCATION
: RADIUS - HAND_TRUNCATION;
context.moveTo(canvas.width / 2, canvas.height / 2);
context.lineTo(
canvas.width / 2 + Math.cos(angle) * handRadius,
canvas.height / 2 + Math.sin(angle) * handRadius
);
context.stroke();
}
function drawHands () {
var date = new Date;
var hour = date.getHours();
hour = hour > 12 ? hour - 12 : hour;
drawHand(hour * 5 + (date.getMinutes() / 60) * 5, true, 0.5);
drawHand(date.getMinutes(), false, 0.5);
drawHand(date.getSeconds(), false, 0.2);
}
moveTo lineTo 一起用, moveTo 两个参数,表示线开始的起点坐标轴,图中就是以圆心为起点,lineTo是移动到终点的位置的坐标轴
图中区分了一个时针和其他的长度
最后一步 就是设置一个定时器
// initialization
context.font = FONT_HEIGHT + 'px Arial';
loop = setInterval(drawClock, 1000);
第四节 事件处理
鼠标事件 监听鼠标事件可以这样写
canvas.onmousedown = function (e) {
// code
}
也可以这样写
canvas.addEventListener('mousedown', function (e) {
// code
})
将鼠标坐标转换成Canvas坐标
很多时候开发者需要知道鼠标事件的点相对于canvas的位置,而不是在整个窗口中的位置,所以必须进行坐标转换
function windowToCanvas (canvas, x, y) {
var bbox = canvas.getBoundingClientRect();
return {
x: (x - bbox.left) * (canvas.width / bbox.width),
y: (y - bbox.top) * (canvas.height / bbox.height)
}
}
canvas.onmousemove = function (e) {
var loc = windowToCanvas(canvas, e.clientX, e.clientY);
}
code 精灵表坐标查看器
var canvas = document.getElementById('canvas');
var readout = document.getElementById('readout');
var context = canvas.getContext('2d');
var spriteSheet = new Image();
var drawSpriteSheet = function () {
context.drawImage(spriteSheet, 0, 0);
}
var drawBackground = function () {
var VERTICAL_LINE_SPACING = 12;
var i = context.canvas.height;
context.clearRect(0, 0, canvas.width, canvas.height);
context.strokeStyle = 'lightgrey';
context.lineWidth = 0.5;
while (i > VERTICAL_LINE_SPACING * 4) {
context.beginPath();
context.moveTo(0, i);
context.lineTo(context.canvas.width, i);
context.stroke();
i -= VERTICAL_LINE_SPACING;
}
}
function windowToCanvas (canvas, x, y) {
var bbox = canvas.getBoundingClientRect();
return {
x: (x - bbox.left) * (canvas.width / bbox.width),
y: (y - bbox.top) * (canvas.height / bbox.height)
}
}
function drawGuideLines(x, y) {
context.strokeStyle = 'rgba(0, 0, 230, 0.8)';
context.lineWidth = 0.5;
drawVerticalLine(x);
drawHorizontalLine(y);
}
function drawVerticalLine (x) {
context.beginPath();
context.moveTo(x + 0.5, 0);
context.lineTo(x + 0.5, context.canvas.height);
context.stroke();
}
function drawHorizontalLine (y) {
context.beginPath();
context.moveTo(0, y + 0.5);
context.lineTo(context.canvas.width, y + 0.5);
context.stroke();
}
function updateReadout (x, y) {
readout.innerText = '(' + x + ',' + y + ')';
}
// event handlers
canvas.onmousemove = function (e) {
var loc = windowToCanvas(canvas, e.clientX, e.clientY);
drawBackground();
drawSpriteSheet();
drawGuideLines(loc.x, loc.y);
updateReadout(loc.x.toFixed(0), loc.y.toFixed(0));
}
// initial
spriteSheet.src = 'running-sprite-sheet.png';
spriteSheet.onload = function () {
drawSpriteSheet();
}
drawBackground();
代码中通过canvas.onmouseover来监听鼠标滑入滑出的,通过e来传递该鼠标的位置,转换成相对于canvas的位置,context.drawImage 对canvas画布中插入图片
键盘事件
keydown
keyup
keypress
第五节 绘制表面的保存与恢复
canvas绘制环境对象的另外一个关键功能就是可以对绘图表面自身进行保存和恢复,这种绘制表面的保存与恢复功能,可以让开发者在绘图表面上进行一些临时性的绘制动作。
使用getImageData() 和 putImageData() 方法来保存于恢复绘图环境的绘图表面
第二章 绘制
2.1 坐标系统
以canvas的左上角为原点,X坐标向右方增长,Y坐标向下方增长
canvas的坐标系并不固定的,可以对坐标系统进行平移以及旋转:
平移
旋转
缩放
创建自定义的变换方式,比如切变(错切)
2.2 canvas的绘制模型
1)将图形或图像绘制到一个无限大的透明位图中,在绘制时遵从当前的填充模式,描边模式以及线条样式
2)将图形或图像的阴影绘制到另一幅位图中,在绘制时使用当前绘图环境的阴影设定
3)将阴影中每一个像素的alpha分量乘以绘图环境对象的globalAlpha属性值
4)将绘有阴影的位图与经过剪辑区域剪切过的canvas进行图像合成,在操作时使用当前的合成模式参数
5)将图形和图像的每一个像素颜色分量,乘以绘图环境对象的globalAlpha属性值
6)将绘有图形或图像的位图,合成到当前经过剪辑区域剪切过的canvas位图之上,在操作时使用当前的合成操作符
2.3 矩形的绘制
canvas的API提供了如下三个方法,分别用于矩形的清除,描边,以及填充
clearRect(double x, double y, double w, double h)
strokeRect(double x, double y, double w, double h)
fillRect(double x, double y, double w, double h)
strokeRect 要考虑两个属性
context.lineJoin = 'round' // 矩形边的连接处的样式, round表示圆角矩形
context.lineWidth = 30 // 矩形边的宽度
2.4颜色和透明度
通过strokeStyle 和 fillStyle可以设置颜色与透明度
如: context.fillStyle = 'rgba(0, 0, 255, 0.5)'
css3颜色规范中说道,之所以要增加对HSL格式的支持,是因为RGB方式来指定颜色有两个缺陷
1、它以硬件为导向的,这种表述颜色的形式,是基于“阴极射线管”的
2、它不直观
HSL也有三个分量,表示 色相、饱和度、亮度
2.5 渐变色和图案
2.5.1 渐变色
通过调用createLinearGradient()方法来创建线性渐变
通过传入两点坐标x, y后,返回一个CanvasGradient实例,最后应用程序将该渐变色进行填充,知道将填充属性设置成其他值为止。
创建好渐变色后,该段代码通过调用canvasGradient之中唯一的方法addColorStop()来向渐变色中增加5个“颜色停止点”,该方法接受两个参数: 一个是位于0 ~1.0之间的double值,代表颜色停止点在渐变线上的位置,另一个是DOMSTRING类型的CSS颜色字串值
code
var canvas = document.getElementById('canvas');
var context = canvas.getContext('2d');
var gradient = context.createLinearGradient(0, 0, canvas.width, canvas.height);
gradient.addColorStop(0, 'blue');
gradient.addColorStop(0.25, 'white');
gradient.addColorStop(0.5, 'purple');
gradient.addColorStop(0.75, 'red');
gradient.addColorStop(1, 'yellow');
context.fillStyle = gradient;
context.fillRect(0, 0, canvas.width, canvas.height);
var canvas = document.getElementById('canvas');
var context = canvas.getContext('2d');
var gradient = context.createLinearGradient(0, 0, 0, canvas.height);
gradient.addColorStop(0, 'blue');
gradient.addColorStop(0.25, 'white');
gradient.addColorStop(0.5, 'purple');
gradient.addColorStop(0.75, 'red');
gradient.addColorStop(1, 'yellow');
context.fillStyle = gradient;
context.fillRect(0, 0, canvas.width, canvas.height);
var canvas = document.getElementById('canvas');
var context = canvas.getContext('2d');
var gradient = context.createLinearGradient(0, 0, canvas.width, 0);
gradient.addColorStop(0, 'blue');
gradient.addColorStop(0.25, 'white');
gradient.addColorStop(0.5, 'purple');
gradient.addColorStop(0.75, 'red');
gradient.addColorStop(1, 'yellow');
context.fillStyle = gradient;
context.fillRect(0, 0, canvas.width, canvas.height);
2.5.2 放射线
通过createRadialGradient方法生成一个放射线的gradient
context.createRadialGradient(canvas.width / 2, canvas.height, 10
, canvas.width / 2, 0, 100)
渐变色与放射线区别在于
createRadialGradient 要比 createLinearGradient多传入两个参数,代表起始位置和终点位置的半径
2.5.3图案
通过createPattern 创建一个CanvasPattern对象,这个对象是可以生成在canvas中对图形和文本进行描边和填充的图案,他可以是image元素,canvas元素,或者video元素
createPattern(canvas | image | video, DOMString repetition)
DOMString repetition 可以为 repeat, repeat-x, repeat-y, no-repeat
var patten = context.createPattern(image, repeatString);
...
context.fillStyle = pattern;
2.6 阴影
在canvas中可以通过修改绘图环境中的如下4个属性值来指定阴影效果
shadowColor CSS3格式的颜色
shadowOffsetX 从图形或文本到阴影的水平像素偏移
shadowOffsetY 从图形或文本到阴影的垂直像素偏移
shadowBlur 一个与像素无关的值,该值被用于高斯模糊方程之中,以便对阴影进行模糊化处理
2.7 路径填充描边
2.7.1 路径与子路径
用beginPath 开始一段新路径,该方法会清楚上一次调用rect()方法时创建的子路径
绘制多个途径的时候,如果下一个途径不使用beginPath清空,会使上一个途径被重绘
2.7.2 剪纸效果
非零环绕规则:
对于路径中的任意给定区域,从该区域内部画一条足够长的线,使此线段的终点完全落在路径范围之外,先设置一个计时器,先置为0, 如果是与路径顺时针相交,则加1,如果是与路径的逆时针部分相交,则减1,如果计数器最终值不为0,那么此区域就在路径里面,调用fill()时候会对其进行填充,否则,不会进行填充。