JavaScript高级程序设计-第三版(使用Canvas绘图)

十五、使用Canvas绘图

15.1 基本用法

  • 初始化
    • 设置width和height属性
      • <canvas width=‘200’ height=‘200’>…</canvas>
    • 开始和结束标签中的内容是后备信息
      • 在不支持<canvas>元素时显示
  • 绘图上下文
    • 进行绘图的必备操作
    • 方式
      • 在<canvas>对象上调用getContext()
        • 接收参数
          • 上下文名称,例如"2d"
  • 导出<canvas>绘制的图像
    • <canvas>对象上调用toDataURL()
      • 接收参数
        • 图像的MIME类型格式

15.2 2D上下文

  • 使用2D上下文提供的方法,可以绘制简单的2D图像,例如矩形、弧线和路径

15.2.1 填充和描边

  • 2D上下文绘图的基本操作
    • 填充
      • 上下文对象的fillStyle属性
    • 描边
      • 上下文对象的strokeStyle属性
        • 属性值
          • 字符串
            • 表示颜色
          • 渐变对象
          • 模式对象

15.2.2 绘制矩形

  • fillRect(x,y,width,height)
  • strokeRect(x,y,width,height)
  • clearRect(x,y,width,height)
    • 清除画布上的矩形区域
<html>
	<head>
		<script>
		window.onload=function(){
				var drawing = document.getElementById('drawing');
				if(drawing.getContext){
					var context = drawing.getContext('2d');
					
					//填充
					context.fillStyle='red';
					context.fillRect(10,10,50,50);
					//描边
					context.strokeStyle='blue';
					context.strokeRect(30,30,50,50);
					
					context.clearRect(20,20,10,10);
				}
			};
		</script>
	</head>
	<body>
		<canvas id='drawing' width='200' height='200'>不支持canvas</canvas>
	</body>
</html>

15.2.3 绘制路径

  • beginPath()
    • 在绘制路径前必须调用
  • arc(x, y, radius, startAngle, endAngle, counterclockwise)
    • 以圆心坐标绘制弧线
    • 是否逆时针
  • arcTo(x1, y1, x2, y2, radius)
  • bezierCurveTo(c1x, c1y, c2x, c2y, x, y)
    • 起始点:当前位置
    • 终点:(x, y)
    • 控制点:(c1x, c1y)、(c2x, c2y)
  • lineTo(x, y)
  • moveTo(x, y)
    • 移动到(x, y)不画线
  • quadraticCurveTo(cx, cy, x, y)
    • 起始点:当前位置
    • 终点:(x, y)
    • 控制点:(cx, cy)
    • 曲线类型:二次曲线
  • rect(x, y, width, height)
  • closePath()
    • 绘制一条从终点到起点的连线
  • 路径只是路径
    • fill()
    • stroke()
    • clip()
      • 创建剪切区域
  • isPointInPath(x, y)

15.2.4 绘制文本

  • fillText(text, x, y, maxWidth)
  • strokeText(text, x, y, maxWidth)
  • 通过上下文设置文本属性
    • font
    • textAlign:x坐标指代的文本的位置
      • center
      • start
      • end
    • textBaseline:y坐标的位置
  • measureText()
    • 利用font、textAlign、textBaseline计算当前文本大小
    • 返回值
      • TextMetrics对象
        • 具有width属性

15.2.5 变换

  • rotate(angle):旋转弧度
  • scale(scaleX, scaleY):缩放
  • translate(x, y):将(x, y)设置为坐标原点
  • transform(m1_1, m1_2, m2_1, m2_2, dx, dy):修改变换矩阵
  • setTransform(m1_1, m1_2, m2_1, m2_2, dx, dy)
    • 将变化矩阵设置为默认状态,再执行transfrom()
  • save()
    • 将上下文的设置和变换保存进栈中,可以多次调用
  • restore()
    • 逐级恢复至之前保存的设置

15.2.6 绘制图像

  • drawImage( image, x, y, width, height)
    • image可以是<image>也可以是<canvas>
  • drawImage( image, initialX, initialY, initialWidth, initialHeight, destX, destY, destWidth, destHeigth)
    • 取原始图像中的某个区域进行绘制

15.2.7 阴影

  • 上下文属性
    • shadowColor
    • shadowOffsetX
    • shadowOffsetY
    • shadowBlur

15.2.8 渐变

  • createLinearGradient(x1, y1, x2, y2)
  • addColorStop()
    • 给渐变对象指定色标
    • 接收参数
      • 色标位置
        • 0(开始的颜色)到1(结束的颜色)
      • CSS颜色值
var gradient=context.createLinearGradient(30,30,70,70);
gradient.addColorStop(0,'white');
gradient.addColorStop(1,'black');

context.fillStyle=gradient;
//渐变位置与矩形位置必须匹配
context.fillRect(30,30,50,50);
  • createRadialGradient(x1, y1, radius1, x2, y2, radius2)

15.2.9 模式

  • createPattern()
    • 接收参数
      • <img>或<video>或<canvas>
      • ‘repeat’、‘repeat-x’、‘repeat-y’、‘no-repeat’
var image=document.images[0];
pattern=conext.createPattern(image, 'repeat');

context.fillStyle=pattern;
context.fillRect(10,10,150,150);
  • 重复图形从画布原点开始,指定区域只控制显示范围

15.2.10 使用图像数据

  • context.getImageData(x, y, width, height)
    • 返回值为ImageData的实例
      • 具有三个属性
        • width
        • height
        • data
          • 数组
          • 每个像素用数组中的4个元素保存,即r、g、b和透明度
          • 可以操作原始像素值实现灰阶过滤
  • context.putImageData(imageData, x, y)

15.2.11 合成

  • context.globalAlpha
    • 全局透明度
  • context.globalCompositionOperation
    • 表示后绘制的图形怎样与先绘制的图形结合
    • 取值
      • source-over:后绘制的图形位于先绘制的图形上方
      • source-in:后绘制的图形与先绘制的图形重叠的部分可见,两者其他部分完全透明

15.3 WebGL

  • 基于OpenGL ES2.0

15.3.1 类型化数组

  • 复杂计算涉及数值精度
  • ArrayBuffer
    • ArrayBuffer对象表示的只是内存中指定的字节数
    • 为将来使用而分配一定数量的字节
    • 通过该对象获得的信息只有它包含的字节数
      • buffer.byteLength
15.3.1.1 视图
  • DataView
    • 通过它可以选择ArrayBuffer中一小段字节
    • 构造函数接收参数
      • ArrayBuffer
      • byteOffset 字节偏移量
      • byteLength 字节数
    • 实例属性
      • byteOffset
      • byteLength
      • buffer 取得数组缓冲器ArrayBuffer
  • 数据类型及读写方法
数据类型gettersetter
有符号8位整数getInt8(byteOffset)setInt8(byteOffset, value)
有符号16位整数getInt8(byteOffset, littleEndian)setInt8(byteOffset, value, littleEndian)
var buffer = new ArrayBuffer(20),
	view = new DataView(buffer),
	value;
view.setUint16(0,25);
view.setUint16(2,50);
value=view.getUint16(0);
15.3.1.2 类型化视图
  • 又称为类型化数组,继承DataView,不需要记忆每个类型占用的字节数
  • Int8Array
  • Uint8Array
  • Float64Array
  • 构造函数属性 BYTES_PER_ELEMENT属性表示每个元素占用的字节数
var int8s = new Int8Array(buffer, 0, 10 * Int8Array.BYTES_PER_ELEMENT);
var uint16s = new Uint16Array(buffer, int8.byteOffset + int8.byteLength, 5* Uint16Array.BYTES_PER_ELEMENT);
  • 也可以不用首先创建ArrayBuffer对象,直接传入希望保存的元素数,会自动创建ArrayBuffer对象
  • 可以像访问数组一样访问类型化视图中的元素
  • 类型化视图的实例方法 subarray( startElementIndex, endElementIndex )
    • 基于底层数组缓冲器的子集创建一个新视图,相当于取数组的一部分生成新数组
    • 基于同一个ArrayBuffer
    • 操作大数组中的一部分元素时,无需担心意味修改了其他元素

15.3.2 WebGL上下文

  • getContext()
    • 上下文名称 webgl
    • 设置,本身是一个对象,即 { alpha:true }
      • alpha
15.3.2.1 常量
  • OpenGL中的类似常量GL_COLOR_BUFFER_BIT在WebGL中为gl.COLOR_BUFFER_BIT
15.3.2.2 方法命名
  • 通过方法名传达关于数据类型和参数数量的信息
15.3.2.3 准备绘图
  • 操作WebGL上下文之前用某种实色清除<canvas>
gl.clearColor(0,0,0,1);
gl.clear(gl.COLOR_BUFFER_BIT);
15.3.2.4 视口与坐标
  • viewport(x, y, width, height)
  • 坐标
    • 左下角为坐标原点
    • 向右向上为x轴和y轴的正方向
15.3.2.5 缓冲区
  • createBuffer() 创建WebGL缓冲区
  • bindBuffer() 将缓冲区绑定到上下文
  • bufferData() 写入缓冲区
  • drawElements() 输出缓冲区内容
  • deleteBuffer() 清空缓冲区
//创建WebGL缓冲区
var buffer = gl.createBuffer();
//将缓冲区绑定到上下文
gl.bindBuffer(gl.ARRAY_BUFFER,buffer);
//javascript类型化数组Float32Array保存顶点信息
//将顶点信息写入缓冲区
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([0, 0.5, 1]), gl.STATIC_DRAW);
15.3.2.6 错误
  • WebGL不会抛出错误
  • 必须在可能出错的地方手动调用gl.getError()
15.3.2.7 着色器
  • 着色器分类
    • 顶点着色器
    • 片段(像素)着色器
  • 着色器语言GLSL(OpenGL Shading Language)
15.3.2.8 编写着色器
  • GLSL为类C语言
  • 每个着色器都有一个main()方法
  • 为着色器传递数据的方式
    • Attribute 向顶点着色器传入顶点信息
    • Uniform 向任何着色器传入常量值
//接收两个元素
attribute vec2 aVertexPosition;

void main(){
	//创建包含四个元素的数据,填补缺失坐标,将2D转换为3D
	//将顶点信息赋值给gl_Position
	gl_Position = vec4(aVertexPosition, 0.0 1.0);
}
uniform vec4 uColor;

void main(){
	gl_FragColor = uColor;
}
15.3.2.9 编写着色器程序
  • 浏览器无法解析GLSL程序,必须准备好字符串形式的GLSL以便编译并链接到着色器程序
  • 将GLSL包含在<script>中,并设置自定义的type属性
    • 通过元素的text属性获得GLSL字符串
  • 创建着色器对象 gl.createShader()
  • 编译着色器 gl.compileShader()
<script type="x-webgl/x-vertex-shader" id ="vertexShader">
attribute vec2 aVertexPosition;
void main(){
	//创建包含四个元素的数据,填补缺失坐标,将2D转换为3D
	//将顶点信息赋值给gl_Position
	gl_Position = vec4(aVertexPosition, 0.0 1.0);
}
</script>
<script type="x-webgl/x-vertex-shader" id ="fragmentShader">
uniform vec4 uColor;
void main(){
	gl_FragColor = uColor;
}
</script>
var vertexGlsl = document.getElementById('vertexShader').text,
	fragmentGlsl = document.getElementById('fragmentShader').text;

var vertexShader = gl.createShader(gl.VERTEX_SHADER);
gl.shaderSource(vertexShader, vertexGlsl);
gl.compileShader(vertexShader);

var program=gl.createProgram();
gl.attachShader(program, vertexShader);
gl.attachShader(program, fragmentShader);
gl.linkProgram(program);

gl.useProgram(program);
15.3.2.10 为着色器传入值
//获取变量位置
var uColor = gl.getUniformLocation(program, "uColor");
//写入值
gl.uniform4fv(uColor, [0, 0, 0, 1]);

//获取变量位置
var aVertexPosition= gl.getAttributeLocation(program, "aVertexPosition");
gl.enableVertexAttribArray(aVertexPosition);
//创建指针,指向缓冲区
gl.vertexAttribPointer(aVertexPosition,itemSize,gl.FLOAT,false, 0, 0);
15.3.2.11 调试着色器和程序
if(!gl.getShaderParameter(vertexShader,gl.COMPLE_STATUS)){
	alert(gl.getShaderInfoLog(vertexShader);
}

if(!gl.getProgramParameter(program,gl.LINK_STATUS)){
	alert(gl.getProgramInfoLog(program);
}
15.3.2.12 绘图
  • 只能绘制点、线和三角
  • gl.drawArrays() 数组缓冲区
  • gl.drawElemnts() 元素数组缓冲区
    • 接收参数
      • 常量,表征绘制形状
      • 缓冲区起始索引
      • 缓冲区包含的点的集合数
var vertices = new Float32Array([0, 1, 1, -1, -1, -1]),
	buffer=gl.createBuffer(),
	vertexSetSize=2,
	vertexSetCount=vertices.length/vertexSetsize,
	uColor,aVertexPosition;

//把数据放到缓冲区
gl.bindBuffer(gl.ARRAY_BUFFER,buffer);
gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);
//为片段着色器传入颜色值
var uColor = gl.getUniformLocation(program, "uColor");
gl.uniform4fv(uColor, [0, 0, 0, 1]);
//为着色器传入顶点信息
var aVertexPosition= gl.getAttributeLocation(program, "aVertexPosition");
gl.enableVertexAttribArray(aVertexPosition);
gl.vertexAttribPointer(aVertexPosition,vertexSetSize,gl.FLOAT,false, 0, 0);
//绘制三角形
gl.drawArray(gl.TRIANGLES,0,vertexSetCount);
15.3.2.13 纹理
var image=new Image(),
	texture;
image.src='smile.gif';
image.onload=function(){
	//创建纹理
	texture=gl.createTexture();
	gl.bindTexture(gl.TEXTURE_2D,texture);
	//设置像素存储格式
	gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL,true);

	gl.texImage2D(gl.TEXTURE_2D,0,gl.RGBA,gl.RGBA,gl.UNSIGNED_BYTE,image);
	gl.texParameteri(gl.TEXTURE_2D,gl.TEXTURE_MAG_FILTER,gl.NEAREST);
	gl.texParameteri(gl.TEXTURE_2D,gl.TEXTURE_MIN_FILTER,gl.NEAREST);
	
	//清除纹理
	gl.bindTexture(gl.TEXTURE_2D,null);
15.3.2.14 读取像素
  • gl.readPixels(x, y, width, height, imageFormat, dataType, ArrayBuffer)
    • 从帧缓冲区读取像素并保存到类型化数组中
    • 图像格式为gl.RGBA
    • 数据类型与ArrayBuffer匹配
  • 绘制图像后帧缓冲区会恢复其原始的干净状态

15.3.3 支持

  • 需要浏览器和驱动程序都支持WebGL
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值