Forturn’s wheel takes you very high and then throws you very low, and there is nothing you can do but face the turn of it with courage.
Canvas
设置<canvas>
元素的 宽度时,注意不要使用style
属性,直接通过指定 <canvas>
本身的属性即可。像下面这样:
<canvas id="canvas" width=1000 height=600>xxx</canvas>
取得 canvas对象 var canvas = document.getElementById('canvas');
canvas 除了具备基本绘图能力的 2D 上下文,<canvas>
还建议了一个名为 WebGL 的 3D 上下文。
要在这块画布(canvas)上绘图,需要取得绘图上下文(getContext()
)。
有些浏览器会为 HTML 规范之外的元素创建默认的 HTML 元素对象①。在这种情况下,即使 drawing 变量中保存着一个有效的元素引用,也检测不到 getContext()方法。( Firefox 3 中使用<canvas>
元素。虽然浏览器会为该标签创建一个 DOM 对象,而且也可以引用它,但
这个对象中并没有 getContext()
方法。)
var context = canvas.getContext('2d');
使用 toDataURL()
方法,可以导出在<canvas>
元素上绘制的图像。这个方法接受一个参数,即图像的 MIME 类型格式,而且适合用于创建图像的任何上下文。
canvas.toDataURL('image/png')
;
2D上下文
2D 上下文的两种基本绘图操作是填充和描边。填充,就是用指定的样式(颜色、渐变或图像)填充图形;描边,就是只在图形的边缘画线。 通过设置这两个属性:fillStyle
和 strokeStyle
可以 对 填充和描边进行控制。
fillStyle('#cccccc')
:填充颜色;strokeStyle('#333')
:描边颜色;ctx.linewidth=10
:描边宽度;
矩形绘制
- fillRect():填充矩形
- strokeRect():描边矩形
- clearRect(x,y,width, height): 清除绘图区域((x,y)为左上角,宽为width,高为height的大小)的内容;
路径绘制
- arc(x,y,r,start,end):以(x,y)为圆心,r为半径, 画弧线,start为弧线起始位置的角度,end为弧线结束位置的角度;
- moveTo(x,y):将当前光标移动到(x,y);
- lineTo(x,y):从前点画直线到(x,y);
- stroke():描边路径;
绘制文字
- 文字格式:
ctx.font = "bold 16px Arial";
- 文字对齐方式:
ctx.textAlign = "center";
- 文本基线:
ctx.textBaseline = "middle";
- 填充文字:
ctx.fillText("12", 250, 125);
- 描边文字:
ctx.strokeText()
变换
通过上下文的变换,可以把处理后的图像绘制到画布上。2D 绘制上下文支持各种基本的绘制变换。创建绘制上下文时,会以默认值初始化变换矩阵,在默认的变换矩阵下,所有处理都按描述直接绘制。为绘制上下文应用变换,会导致使用不同的变换矩阵应用处理,从而产生不同的结果。 可以通过如下方法来修改变换矩阵。
- rotate(angle):围绕原点旋转图像 angle 弧度。
- scale(scaleX, scaleY):缩放图像,在 x 方向乘以 scaleX,在 y 方向乘以 scaleY。scaleX和 scaleY 的默认值都是 1.0。
- translate(x, y):将坐标原点移动到(x,y)。执行这个变换之后,坐标(0,0)会变成之前由(x,y)表示的点。
transform(m1_1, m1_2, m2_1, m2_2, dx, dy):直接修改变换矩阵,方式是乘以如下 矩阵。
m1_1 m1_2 dx
m2_1 m2_2 dy
0 0 1
setTransform(m1_1, m1_2, m2_1, m2_2, dx, dy):将变换矩阵重置为默认状态,然后再调用 transform()。
变换有可能很简单,但也可能很复杂,这都要视情况而定。
除此以外,我们还可以调用save()
和 restore()
方法,对设置的上下文进行保存和恢复。
PS:save() 方法保存的只是对绘图上下文的设置和变换, 不会保存绘图上下文的内容。
绘制图像
- drawImage():最简单的调用方式 是传入一个 HTML 元素,以及绘制该图像的起点的 x 和 y 坐标。绘制到画布上 的图像大小与原始大小一样。
- drawImage():如果你想改变绘制后图像的大小,可以再多传入两个参数,分别表示目标 宽度和目标高度。通过这种方式来缩放图像并不影响上下文的变换矩阵。
- drawImage():可以选择把图像中的某个区域绘制到上下文中。drawImage()方法的这种调 用方式总共需要传入 9 个参数:要绘制的图像、源图像的 x 坐标、源图像的 y 坐标、源图像的宽度、源 图像的高度、目标图像的 x 坐标、目标图像的 y 坐标、目标图像的宽度、目标图像的高度。这样调用 drawImage()方法可以获得最多的控制。
drawImage()方法除了可以接受一个image作为参数,还可以接受一个<canvas>
对象。
图像不能来自其他域。如果图像来自其他域, 调用 toDataURL() 会抛出一个错误
阴影
2D 上下文会根据以下几个属性的值,自动为形状或路径绘制出阴影。
- shadowColor:用 CSS 颜色格式表示的阴影颜色,默认为黑色。
- shadowOffsetX:形状或路径 x 轴方向的阴影偏移量,默认为 0。
- shadowOffsetY:形状或路径 y 轴方向的阴影偏移量,默认为 0。
- shadowBlur:模糊的像素数,默认 0,即不模糊。
这些属性都可以通过 context 对象来修改。只要在绘制前为它们设置适当的值,就能自动产生阴 影。
渐变
渐变由 CanvasGradient 实例表示,很容易通过 2D 上下文来创建和修改。要创建一个新的线性渐 变,可以调用 createLinearGradient()方法。这个方法接收 4 个参数:起点的 x 坐标、起点的 y 坐 标、终点的 x 坐标、终点的 y 坐标。 调用这个方法后, 它就会创建一个指定大小的渐变, 并返回 CanvasGradient 对象的实例。
创建了渐变对象后,下一步就是使用 addColorStop()方法来指定色标。这个方法接收两个参数: 色标位置和 CSS 颜色值。色标位置是一个 0(开始的颜色)到 1(结束的颜色)之间的数字。例如:
var gradient = context.createLinearGradient(30, 30, 70, 70);
gradient.addColorStop(0, "white");
gradient.addColorStop(1, "black");
此时,gradient 对象表示的是一个从画布上点(30,30)到点(70,70)的渐变。起点的色标是白色,终 点的色标是黑色。然后就可以把 fillStyle 或 strokeStyle 设置为这个对象,从而使用渐变来绘制 形状或描边:
//绘制渐变矩形
context.fillStyle = gradient; context.fillRect(30, 30, 50, 50);
要创建径向渐变(或放射渐变),可以使用 createRadialGradient()方法。这个方法接收 6 个参数,对应着两个圆的圆心和半径。
模式
模式其实就是重复的图像,可以用来填充或描边图形。要创建一个新模式,可以调用createPattern()方法并传入两个参数:一个 HTML 元素和一表示如何重复图像的字符串。其中,第二个参数的值与 CSS 的 background-repeat 属性值相同,包括”repeat”、”repeat-x”、”repeat-y”和”no-repeat”。
获取图像数据
2D 上下文的一个明显的长处就是,可以通过 getImageData()取得原始图像数据。这个方法接收4 个参数:要取得其数据的画面区域的 x 和 y 坐标以及该区域的像素宽度和高度。例如,要取得左上角坐标为(10,5)、大小为 50×50 像素的区域的图像数据,可以使用以下代码:
var imageData = context.getImageData(10, 5, 50, 50);
这里返回的对象是 ImageData 的实例。每个 ImageData 对象都有三个属性:width、height 和data。其中 data 属性是一个数组,保存着图像中每一个像素的数据。在 data 数组中,每一个像素用4 个元素来保存,分别表示红、绿、蓝和透明度值。因此,第一个像素的数据就保存在数组的第 0 到第3 个元素中。
WebGL
WebGL 是针对 Canvas 的 3D 上下文。但它并不是W3C制定的标准。
WebGL(全写Web Graphics Library)是一种3D绘图标准,这种绘图技术标准允许把JavaScript和OpenGL ES 2.0结合在一起,通过增加OpenGL ES 2.0的一个JavaScript绑定,WebGL可以为HTML5 Canvas提供硬件3D加速渲染,这样Web开发人员就可以借助系统显卡来在浏览器里更流畅地展示3D场景和模型了,还能创建复杂的导航和数据视觉化。显然,WebGL技术标准免去了开发网页专用渲染插件的麻烦,可被用于创建具有复杂3D结构的网站页面,甚至可以用来设计3D网页游戏等等。
WebGL 涉及的复杂计算需要提前知道数值的精度,而标准的 JavaScript 数值无法满足需要。为此,WebGL 引入了一个概念,叫类型化数组(typed arrays)。类型化数组也是数组,只不过其元素被设置为特定类型的值。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Canvas</title>
<style>
</style>
</head>
<body>
<img src="images/07.png" alt="">
<div class="box">
<canvas id="canvas" width="500px" height="500px">Your browser's version is too low and please update it to the newest.</canvas>
</div>
<script>
var canvas = document.getElementById('canvas');
var ctx = null;
if (canvas.getContext) {
ctx = canvas.getContext('2d');
// ctx.scale(5, 5);
// ctx.fillStyle = "#ff0000";
// ctx.fillRect(10, 10, 200, 200); // 宽高是200的矩形 填充色:红色
// ctx.fillStyle = "rgba(0, 255, 0, 0.3)";
// ctx.fillRect(110, 110, 200, 200); // 宽高是200的矩形 填充色: 绿色, 透明度 30%
// ctx.strokeStyle = 'rgba(0, 0, 255, 0.3)';
// ctx.lineWidth = 30;
// ctx.strokeRect(109, 109, 202, 202); // 创建描边矩形, 边框宽度是30, 颜色是蓝色
// setTimeout(() => {
// console.log('清掉左上角的宽高为150的区域');
// ctx.clearRect(10, 10, 330, 330);
// startLine();
// }, 3000);
// startLine();
function startLine() {
// start draw line
ctx.lineWidth = 2
ctx.strokeStyle = "black"
ctx.beginPath();
ctx.arc(250, 250, 200, 1, Math.PI - 1);
// ctx.arc(250, 250, 200, Math.PI+1, 2*Math.PI-1);
ctx.moveTo(10, 10);
ctx.lineTo(300, 10);
ctx.moveTo(400, 250); // 表的中心
ctx.arc(250, 250, 150, 0, 360); // 表盘
ctx.moveTo(390, 250);
ctx.arc(250, 250, 140, 0, 360); // 表盘
ctx.moveTo(380, 250);
ctx.lineTo(250, 250); // 分针
ctx.lineTo(250, 350); // 时针
ctx.stroke(); // 对路径描边
}
// drawText();
function drawText() {
ctx.font = "bold 16px Arial";
ctx.textAlign = "center";
ctx.textBaseline = "middle";
ctx.fillText("12", 250, 125);
ctx.lineWidth = 2;
ctx.font = "bold 36px Arial";
ctx.strokeStyle = 'yellow'; // 描边文字颜色
ctx.textBaseline = 'top'; // 基线
ctx.textAlign = 'left'; // 水平对齐方式
ctx.strokeText('This 卜', 10, 10);
}
// transform();
function transform() {
ctx.translate(50, 50);
ctx.rotate(0.5);
ctx.moveTo(0, 0);
ctx.strokeStyle = 'orange';
// ctx.fillRect(0, 0, 120, 120);
}
// setTimeout(() => {
// drawImage();
// }, 1000);
function drawImage() {
var img1 = document.images[0];
ctx.drawImage(img1, 120, 50);
ctx.drawImage(img1, 190, 190, 70, 70);
ctx.drawImage(img1, 0, 0, 100, 100, 0, 0, 50, 50);
}
// ctx.rotate(-0.5);
// ctx.clearRect(0, 0, 500, 500);
// shadow();
function shadow() {
ctx.shadowColor = 'red';
ctx.shadowBlur = 5;
ctx.shadowOffsetX = 10;
ctx.shadowOffsetY = 40;
ctx.fillStyle = "rgba(0, 200, 0, 0.5)";
ctx.fillRect(20, 20, 120, 200);
}
// saveAndRestore();
function saveAndRestore() {
ctx.clearRect(0, 0, 500, 500);
ctx.shadowColor = 'blue';
ctx.beginPath();
ctx.moveTo(50, 50);
ctx.lineTo(100, 100);
ctx.stroke();
ctx.save();
ctx.shadowColor = 'red';
ctx.fillRect(100, 10, 50, 100); // 阴影颜色 虹色
ctx.restore();
ctx.fillRect(200, 200, 50, 100); // 阴影颜色 蓝色
}
ctx.shadowBlur = 0;
ctx.shadowOffsetX = 0;
ctx.shadowOffsetY = 0;
// gradient();
function gradient() {
// 线性渐变
var lineGradient = ctx.createLinearGradient(300, 0, 150, 150);
lineGradient.addColorStop(0, 'white');
lineGradient.addColorStop(1, 'green');
// 应用线性渐变
ctx.fillStyle = lineGradient;
ctx.fillRect(200, 100, 150, 150);
ctx.clearRect(0, 0, 500, 500);
// 径向渐变
var radialGradient = ctx.createRadialGradient(100, 100, 30, 100, 100, 50);
radialGradient.addColorStop(0, "white");
radialGradient.addColorStop(1, "black");
//绘制渐变矩形
ctx.fillStyle = radialGradient;
// 注意矩形坐标 及宽高 与 径向渐变 参数的关系
ctx.fillRect(50, 50, 100, 100);
}
ctx.clearRect(0, 0, 500, 500);
// setTimeout(()=>{pattern();}, 1500);
// 模式
function pattern() {
var ptn = ctx.createPattern(document.images[0], 'repeat');
ctx.fillStyle = ptn;
ctx.fillRect(10, 10, 500, 500);
ctx.clearRect(0, 0, 500, 500);
ptn = ctx.createPattern(document.images[0], 'repeat-x');
ctx.fillStyle = ptn;
ctx.fillRect(10, 10, 500, 500);
}
setTimeout(() => {
getImageData();
}, 2000);
var imageData;
// 获取图像数据
function getImageData() {
var img1 = document.images[0];
ctx.drawImage(img1, 0, 0);
imageData = ctx.getImageData(0, 0, 128, 128);
data = imageData.data;
// 将图像做灰度处理
for (i = 0, len = data.length; i < len; i += 4) {
red = data[i];
green = data[i + 1];
blue = data[i + 2];
alpha = data[i + 3];
//求得 rgb 平均值
average = Math.floor((red + green + blue) / 3);
//设置颜色值,透明度不变
data[i] = average;
data[i + 1] = average;
data[i + 2] = average;
}
//回写图像数据并显示结果
imageData.data = data;
ctx.putImageData(imageData, 0, 0);
}
}
</script>
</body>
</html>