Junwen's home
  • ES6

    • ES6 Decorator
    • ES6核心特性
    • Promise&Generator
  • js原理

    • 简单实现bind、apply和call
    • 如何遍历一个dom tree
    • 实现函数currying
    • 实现一个event
    • 详解js的继承
    • 详解requestAnimationFrame
    • Canvas api详解
    • DOM事件
    • EventLoop详解
    • JavaScript的内存管理
    • JavaScript的运行机制
    • Math对象
    • new操作符都做了什么
    • create基本实现原理
    • Set、Map、WeakSet和WeakMap
    • web worker原理
    • WebGL教程(MDN)
  • jsInfoSeries

    • 简介
    • JavaScript基础知识
    • 基础知识2
    • 基础知识3
    • 基础知识4
  • 技巧

    • 5个js解构有趣用途
    • 如何使用set提高代码性能
    • cordova构建项目时的问题
    • js中轻松遍历对象属性的几种方式
  • 怎么写出更好的css
  • BFC详解
  • box-shadow详解
  • CSS小技巧
  • Grid布局详解
HTML
  • IP十问
  • http笔试
  • http协议
  • 浏览器原理
  • 浏览器缓存其实就这么一回事儿
  • 浏览器兼容性问题
  • 移动端开发兼容性适配
  • 前端性能优化
  • 前端如何进行seo优化
  • webpack

    • webpack HMR
    • webpack优化基本方法
  • leetcode题解

    • 两数之和
    • 判断整数是否为回文串
    • 无重复字符的最长子串
  • Js链表
  • JavaScript排序
  • React

    • 虚拟DOM原理理解
    • React Hook
    • 组件复用指南
  • Vue

    • Vue举一反三
面试题
读书笔记
GitHub (opens new window)

Syun0216

多读书多种树
  • ES6

    • ES6 Decorator
    • ES6核心特性
    • Promise&Generator
  • js原理

    • 简单实现bind、apply和call
    • 如何遍历一个dom tree
    • 实现函数currying
    • 实现一个event
    • 详解js的继承
    • 详解requestAnimationFrame
    • Canvas api详解
    • DOM事件
    • EventLoop详解
    • JavaScript的内存管理
    • JavaScript的运行机制
    • Math对象
    • new操作符都做了什么
    • create基本实现原理
    • Set、Map、WeakSet和WeakMap
    • web worker原理
    • WebGL教程(MDN)
  • jsInfoSeries

    • 简介
    • JavaScript基础知识
    • 基础知识2
    • 基础知识3
    • 基础知识4
  • 技巧

    • 5个js解构有趣用途
    • 如何使用set提高代码性能
    • cordova构建项目时的问题
    • js中轻松遍历对象属性的几种方式
  • 怎么写出更好的css
  • BFC详解
  • box-shadow详解
  • CSS小技巧
  • Grid布局详解
HTML
  • IP十问
  • http笔试
  • http协议
  • 浏览器原理
  • 浏览器缓存其实就这么一回事儿
  • 浏览器兼容性问题
  • 移动端开发兼容性适配
  • 前端性能优化
  • 前端如何进行seo优化
  • webpack

    • webpack HMR
    • webpack优化基本方法
  • leetcode题解

    • 两数之和
    • 判断整数是否为回文串
    • 无重复字符的最长子串
  • Js链表
  • JavaScript排序
  • React

    • 虚拟DOM原理理解
    • React Hook
    • 组件复用指南
  • Vue

    • Vue举一反三
面试题
读书笔记
GitHub (opens new window)
  • 白帽子讲web安全

    • HTML5安全
    • PHP安全
    • WebServer配置安全
    • Web框架安全
    • 互联网业务安全
    • 加密算法和随机数
    • 安全的开发流程
    • 安全运营
    • 应用层拒绝服攻击
    • 文件上传漏洞
    • 注入攻击
    • 点击劫持
    • 认证与会话管理
    • 访问控制
    • 跨站点请求伪造(CSRF)
    • 跨站脚本攻击
  • 深入react技术栈

    • chapter1
  • 高性能建站
  • 冴羽系列文章链接
  • books
junwen
2020-03-27

第二章 绘制

# 绘制

本章会介绍:

  • 对线条、弧形、圆、曲线及多边形进行描边与填充
  • 通过设置绘图环境的属性来改变所绘图形的外观
  • 绘制圆角矩形
  • 绘制并编辑贝塞尔曲线
  • 对2d绘制环境进行扩展,使之可以绘制虚线
  • 使用纯色、渐变色及图案对图形进行描边及填充
  • 阴影效果
  • 在不影响背景的情况下,使用“剪辑区域”技术来查出图形与文本
  • 在canvas中拖动图形对象
  • 坐标系统的变换

# 坐标系统

canvas坐标系统以左上角为原点,x坐标向右方增长,y坐标向下方延伸,我们也可以对坐标系统进行平移(translate)或者旋转(rotate)和缩放(scale)

# Canvas的绘制模型

在向canvas之上绘制图形或图像时,浏览器将做以下步骤:

  • 将图形或图像绘制到一个无线大的透明位图,在绘制时使用当前绘制的阴影设定
  • 将图形或图像绘制到另外一幅绘图中,绘制时使用当前绘图环境的阴影设定。
  • 将阴影中每一个像素的alpha分量乘以绘图环境对象的globalAlpha属性值
  • 将绘有引用的位图与经过剪辑区域剪切过的canvas进行图像合成。操作时使用当前合成模式参数。
  • 将图形或图像的每一个像素颜色分量,乘以绘图环境对象的globalAlpha属性值
  • 将绘有图形或图像的位图,合成到当前经过剪辑区剪切过的canvas位图上, 在操作时使用当前合成操作符

# 矩形绘制

clearReat(double x,double y, double w, double h) //清除某一部分的矩形
strokeReat(double x,double y, double w, double h) // 绘制空心矩形
fillReat(double x,double y, double w, double h) // 绘制实心矩形
1
2
3

# 颜色与透明度

strokeStyle与fillStyle的属性值可以是任意有效的css字符串

#ffffff;
#642
rgb(255,255,0)
hsl(20,62%,28%)
hsla(40,82%,33%,0.6)
antiquewhite
burlywood
cadetblue
1
2
3
4
5
6
7
8

# 渐变色与图案

Canvas元素支持线性(linear)与放射(radial)渐变

  • 通过调用createLinearGradient()会返回一个CanvasGradient实例,通过它的唯一方法addColorStop来向渐变色中添加颜色停止点(color stop)。该方法接受两个参数:一个是位于0-1.0之间的double值,代表颜色停止点在渐变线上的位置,另一个是DOMString类型的css3颜色字串值
var canvas = document.getElementById('canvas'),
    context = canvas.getContext('2d'),
    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.rect(0,0,canvas.width,canvas.height)
1
2
3
4
5
6
7
8
9
10
11
  • 放射性渐变
var canvas = document.getElementById('canvas'),
    context = canvas.getContext('2d'),
    gradient = context.createRadialGradient(canvas.width/2,canvas.height,10,canvas.width/2,0,100);
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.rect(0,0,canvas.width,canvas.height);
    context.fill()
1
2
3
4
5
6
7
8
9
10
11
12

# 图案

# 阴影

  • shadowColor: css3格式颜色
  • shadowOffsetX: 水平像素偏移
  • shadowOffsetY: 垂直像素偏移
  • shadowBlur: 高斯模糊
context.shadowColor = 'rgba(0,0,0,0.7)';
context.shadowOffsetX = 1;
context.shadowOffsetY = 1;
context.shadowBlur = 2;
1
2
3
4

禁用阴影,将shadowColor设置为undefined

# 内嵌阴影

shadowOffsetX与shadowOffsetY设置负偏移量可以形成内嵌阴影

var drawingContext = document.getElementById('canvas').getContext('2d'),

drawingContext.lineWidth = 1;
drawingContext.shadowColor =  'blue';
drawingContext.shadowOffsetX = -5;
drawingContext.shadowOffsetY = -5;
drawingContext.shadowBlur = 20;
drawingContext.strokeStyle = 'rgba(0,0,255,0.6)'

drawingContext.save();
drawingContext.beginPath();
drawingContext.arc(100,100,60,0,Math.PI*2,false);
drawingContext.clip(); //绘制内容不得超出圆形范围之外
drawingContext.stroke();
drawingContext.restore();
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

效果如下:

# CanvasRenderingContext2D之中与阴影效果相关的属性

# 路径、描边、填充

var context = document.getElementById('drawingCanvas').getContext('2d');

context.font = '48pt Heivetica';
context.strokeStyle = 'blue';
context.fillStyle = 'red';
context.lineWidth = '2';

context.strokeText('Stroke', 60, 110);
context.fillText('Fill',440,110);

context.lineWidth = '5';
context.beginPath();
context.rect(400,150,150,100);
context.fill();

context.beginPath();
context.arc(820,370,60,0,Math.Pi/2);
context.stroke();
context.fill();
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

首先调用beginPath()方法来开始一段新的路径,rect()与arc()方法分别用于创建矩形和弧形路径。然后调用stroke与fill方法,对刚才那些路径进行描边或填充。

# 路径与子路径

在某一时刻,canvas中只能有一条路径存在,canvas称为当前路径。然而这条路径却可以包含许多子路径。而子路径又是由两个或者多个点组成的。

// 绘制连个矩形
context.beginPath();
context.rect(10,10,100,100);
context.stroke();
context.beginPath();
context.rect(50,50,100,100);
context.stroke();
1
2
3
4
5
6
7

# 填充路径所使用的非零环绕规则

# 剪纸效果

let context = document.getElementById('canvas').getContext('2d');

function drawGrid(color, stepx, stepy) {

}

function drawTwoArcs() {
  context.beginPath();
  context.arc(300,190,150,0,Math.PI*2,false);
  context.arc(300,190,150,0,Math.PI*2,true);

  context.fill();
  context.shadowColor = undefined;
  context.shadowOffsetX = 0;
  context.shadowOffsetY = 0;
  context.stroke();
}

function draw() {
  context.clearRect(0,0,context.canvas.width,context.canvas.height);
  drawGrid('lightGray',10,10);
  context.save();
  context.shadowColor='rgba(0,0,0,0)';
  context.shadowOffsetX = 12;
  context.shadowOffsetY = 12;
  context.shadowBlur = 15;
  drawTwoArcs();
  context.restore();
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29

# 线段

let canvas = document.querySelector('#canvas');
let context = canvas.getContext('2d');
context.lineWidth =1;
context.beginPath();
context.moveTo(50,10);
context.lineTo(200,10);
context.stroke();
context.beginPath();
context.moveTo(50,20);
context.lineTo(200,20);
context.stroke();
1
2
3
4
5
6
7
8
9
10
11

在下图中,这条垂直线段绘制在两个像素之间,中线左右两端的那半个像素就不再延伸了,它们合起来恰好占据1个像素宽度。所以说,如果要绘制一条真正1像素宽的线段,你必须将该线段绘制在某两个像素之间的那个像素中,而不是他两的交界处

# 网格绘制

var context = document.getElementById('canvas').getContext('2d')l

function drawGrid(context, color, stepx, stepy) {
  context.strokeStyle = color;
  context.lineWidth = 0.5;
  for(var i = stepx +0.5;i<context.canvas.width;i+=stepx) {
    context.beginPath();
    context.moveTo(i,0);
    context.lineTo(i,context.canvas.height);
    context.stroke();
  }
  for(var i = stepy+0.5;i<context.canvas.height;i+=stepy) {
    context.beginPath();
    context.moveTo(0,i);
    context.lineTo(context.canvas.width,i);
    context.stroke();
  }
}

drawGrid(context,'lightgray',10,10)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

# 橡皮筋式的线条绘制

# 虚线绘制

var context = document.getElementById('canvas').getContext('2d')

function drawDashedLine(context, x1, y1, x2, y2, dashLength) {
  dashLength = dashLength === undefined ? 5 : dashLength;
  var deltaX = x2 - x1;
  var deltaY = y2 - y1;
  var numDashes = Math.floor(Math.sqrt(deltaX*deltaX + deltaY*deltaY)/dashLength);
  for(var i=0;i<numDashes;++i) {
    context[i%2===0?'moveTo':'lineTo'](x1 + (deltaX / numDashes) * i, y1 + (deltaY / numDashes) * i);

    context.stroke()
  }
  drawDashedLine(context,20,20,context.canvas.width-20,20);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14

# 线段断点与连接点的绘制

  • lineCap
  • lineJoin
属性 描述 类型 取值范围 默认值
lineWidth 以像素为单位的线段宽度 double 非零的整数 1.0
lineCap 该值决定浏览器如何绘制线段的端点 DOMString butt、round、square butt
lineJoin 该值决定浏览器如何绘制线段的连接点 DOMString round、bevel、miter bevel
mitterLimit 斜接线长度与二分之一线宽的比值,如果斜线的长度超过了该值,浏览器就会以bevel方式来绘制线段的连接点 double 非零的正数 10.0

# 圆弧形

方法 描述
arc(double x,double y,double radius,double startAngle,double endAngle,boolean counter-clockwise) 创建一条以(x,y)为圆心,radius为半径,以startAngle和endAngle为起止角的圆弧路径,最后一个参数false为顺时针,true为逆时针
arcTo(double x1,double y1,double x2,double y2,double radius) 参考(x1,y1)与(x2,y2)两个点,创建一条radius为半径的圆弧路径,该圆弧与当前点到(x1,y1)到(x2,y2)的连线相切

# 贝塞尔曲线(bezier curve)

贝塞尔曲线分为平方贝塞尔曲线和立方贝塞尔曲线。平方贝塞尔曲线是一种二次曲线,它是由三个点定义的:两个描点一个控制点。立方贝塞尔曲线则是一种三次曲线,室友四个点来控制:两个描点和两个控制点。

# 二次方贝塞尔曲线

context.quadraticCurveTo(150.8,130,160.6,150.5);
context.quadraticCurveTo(190,250.0,210.5,160.5);
context.quadraticCurveTo(240,100.5,290,70.5);
1
2
3

quadraticCurveTo方法绘制二次方贝塞尔曲线,接受四个参数,分别表示两个点的x和y坐标。第一个点是曲线的控制点,用于决定曲线的形状,第二个点是描点。

方法 描述
bezierCurveTo(double cpx, double cpy,double cp2x, double cp2y,double x,double y) 创建一条代表三次方贝塞尔曲线路径,你需要向该方法传入三个点的坐标,前两个点是该曲线的控制点,最后一个是描点

# 多边形绘制

points.push(new Point(centerX + radius*Math.sin(angle), centerY - radius*Math.cos(angle)))
angle += 2*Math.PI /sides
1
2
在Github上编辑此页 (opens new window)
上次更新: 3/22/2021, 3:47:15 AM
最近更新
01
如何打造全链路项目生命周期的统一交付平台
04-10
02
如何建立前端标准化研发流程
04-10
03
如何从0到1一步步成体系地搭建CI
04-10
更多文章>
Theme by Vdoing | Copyright © 2019-2021 Syun
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式