html5 canvas绘图-刻度仪表盘的绘制

---恢复内容开始---

圆弧,尤其是圆,通常被用做描绘一些实物。下图所示的应用程序用5个圆形实现了一个仪表盘。仪表盘的刻度代表了圆周上的角度值。用户可以通过它来交互式地旋转多边形物体。

该应用程序使用了本章到目前为止所讲的很多技术。为了绘制这个仪表盘,该应用程序画了许多圆形与线段,使用了各种颜色及透明度,对圆形路径进行了描边与填充。同时为了使盘面上的刻度看起来有深度感,它还运用了阴影效果。该程序还运用了剪纸效果。使得仪表盘外围的那一圈看起来有半透明的效果。

仪表盘的绘制

html代码:


 1 <head>
2 <title>A Dial Showing the Degrees of a Circle</title>
3
4 <style>
5 body {
6 background: #eeeeee;
7 }
8
9 #canvas {
10 background: #ffffff;
11 cursor: crosshair;
12 margin-left: 10px;
13 margin-top: 10px;
14 -webkit-box-shadow: 4px 4px 8px rgba(0,0,0,0.5);
15 -moz-box-shadow: 4px 4px 8px rgba(0,0,0,0.5);
16 box-shadow: 4px 4px 8px rgba(0,0,0,0.5);
17 }
18
19 </style>
20 </head>
21
22 <body>
23 <canvas id=‘canvas‘ width=‘650‘ height=‘450‘>
24 Canvas not supported
25 </canvas>
26
27 <script src = ‘example.js‘></script>
28 </body>
29 </html>

example.js


  1 var canvas = document.getElementById(‘canvas‘),
2 context = canvas.getContext(‘2d‘),
3
4 CENTROID_RADIUS = 10,
5 CENTROID_STROKE_STYLE = ‘rgba(0, 0, 0, 0.5)‘,
6 CENTROID_FILL_STYLE = ‘rgba(80, 190, 240, 0.6)‘,
7
8 RING_INNER_RADIUS = 35,
9 RING_OUTER_RADIUS = 55,
10
11 ANNOTATIONS_FILL_STYLE = ‘rgba(0, 0, 230, 0.9)‘,
12 ANNOTATIONS_TEXT_SIZE = 12,
13
14 TICK_WIDTH = 10,
15 TICK_LONG_STROKE_STYLE = ‘rgba(100, 140, 230, 0.9)‘,
16 TICK_SHORT_STROKE_STYLE = ‘rgba(100, 140, 230, 0.7)‘,
17
18 TRACKING_DIAL_STROKING_STYLE = ‘rgba(100, 140, 230, 0.5)‘,
19
20 GUIDEWIRE_STROKE_STYLE = ‘goldenrod‘,
21 GUIDEWIRE_FILL_STYLE = ‘rgba(250, 250, 0, 0.6)‘,
22
23 circle = { x: canvas.width/2,
24 y: canvas.height/2,
25 radius: 150
26 };
27
28 // Functions..........................................................
29
30 function drawGrid(color, stepx, stepy) {
31 context.save()
32
33 context.shadowColor = undefined;
34 context.shadowOffsetX = 0;
35 context.shadowOffsetY = 0;
36
37 context.strokeStyle = color;
38 context.fillStyle = ‘#ffffff‘;
39 context.lineWidth = 0.5;
40 context.fillRect(0, 0, context.canvas.width,
41 context.canvas.height);
42
43 for (var i = stepx + 0.5;
44 i < context.canvas.width; i += stepx) {
45 context.beginPath();
46 context.moveTo(i, 0);
47 context.lineTo(i, context.canvas.height);
48 context.stroke();
49 }
50
51 for (var i = stepy + 0.5;
52 i < context.canvas.height; i += stepy) {
53 context.beginPath();
54 context.moveTo(0, i);
55 context.lineTo(context.canvas.width, i);
56 context.stroke();
57 }
58
59 context.restore();
60 }
61
62 function drawDial() {
63 var loc = {x: circle.x, y: circle.y};
64
65 drawCentroid();
66 drawCentroidGuidewire(loc);
67
68 drawRing();
69 drawTickInnerCircle();
70 drawTicks();
71 drawAnnotations();
72 }
73
74 function drawCentroid() {
75 context.beginPath();
76 context.save();
77 context.strokeStyle = CENTROID_STROKE_STYLE;
78 context.fillStyle = CENTROID_FILL_STYLE;
79 context.arc(circle.x, circle.y,
80 CENTROID_RADIUS, 0, Math.PI*2, false);
81 context.stroke();
82 context.fill();
83 context.restore();
84 }
85
86 function drawCentroidGuidewire(loc) {
87 var angle = -Math.PI/4,
88 radius, endpt;
89
90 radius = circle.radius + RING_OUTER_RADIUS;
91
92 if (loc.x >= circle.x) {
93 endpt = { x: circle.x + radius * Math.cos(angle),
94 y: circle.y + radius * Math.sin(angle)
95 };
96 }
97 else {
98 endpt = { x: circle.x - radius * Math.cos(angle),
99 y: circle.y - radius * Math.sin(angle)
100 };
101 }
102
103 context.save();
104
105 context.strokeStyle = GUIDEWIRE_STROKE_STYLE;
106 context.fillStyle = GUIDEWIRE_FILL_STYLE;
107
108 context.beginPath();
109 context.moveTo(circle.x, circle.y);
110 context.lineTo(endpt.x, endpt.y);
111 context.stroke();
112
113 context.beginPath();
114 context.strokeStyle = TICK_LONG_STROKE_STYLE;
115 context.arc(endpt.x, endpt.y, 5, 0, Math.PI*2, false);
116 context.fill();
117 context.stroke();
118
119 context.restore();
120 }
121
122 function drawRing() {
123 drawRingOuterCircle();
124
125 context.strokeStyle = ‘rgba(0, 0, 0, 0.1)‘;
126 context.arc(circle.x, circle.y,
127 circle.radius + RING_INNER_RADIUS,
128 0, Math.PI*2, false);
129
130 context.fillStyle = ‘rgba(100, 140, 230, 0.1)‘;
131 context.fill();
132 context.stroke();
133 }
134
135 function drawRingOuterCircle() {
136 context.shadowColor = ‘rgba(0, 0, 0, 0.7)‘;
137 context.shadowOffsetX = 3,
138 context.shadowOffsetY = 3,
139 context.shadowBlur = 6,
140 context.strokeStyle = TRACKING_DIAL_STROKING_STYLE;
141 context.beginPath();
142 context.arc(circle.x, circle.y, circle.radius +
143 RING_OUTER_RADIUS, 0, Math.PI*2, true);
144 context.stroke();
145 }
146
147 function drawTickInnerCircle() {
148 context.save();
149 context.beginPath();
150 context.strokeStyle = ‘rgba(0, 0, 0, 0.1)‘;
151 context.arc(circle.x, circle.y,
152 circle.radius + RING_INNER_RADIUS - TICK_WIDTH,
153 0, Math.PI*2, false);
154 context.stroke();
155 context.restore();
156 }
157
158 function drawTick(angle, radius, cnt) {
159 var tickWidth = cnt % 4 === 0 ? TICK_WIDTH : TICK_WIDTH/2;
160
161 context.beginPath();
162
163 context.moveTo(circle.x + Math.cos(angle) * (radius - tickWidth),
164 circle.y + Math.sin(angle) * (radius - tickWidth));
165
166 context.lineTo(circle.x + Math.cos(angle) * (radius),
167 circle.y + Math.sin(angle) * (radius));
168
169 context.strokeStyle = TICK_SHORT_STROKE_STYLE;
170 context.stroke();
171 }
172
173 function drawTicks() {
174 var radius = circle.radius + RING_INNER_RADIUS,
175 ANGLE_MAX = 2*Math.PI,
176 ANGLE_DELTA = Math.PI/64,
177 tickWidth;
178
179 context.save();
180
181 for (var angle = 0, cnt = 0; angle < ANGLE_MAX;
182 angle += ANGLE_DELTA, cnt++) {
183 drawTick(angle, radius, cnt++);
184 }
185
186 context.restore();
187 }
188
189 function drawAnnotations() {
190 var radius = circle.radius + RING_INNER_RADIUS;
191
192 context.save();
193 context.fillStyle = ANNOTATIONS_FILL_STYLE;
194 context.font = ANNOTATIONS_TEXT_SIZE + ‘px Helvetica‘;
195
196 for (var angle=0; angle < 2*Math.PI; angle += Math.PI/8) {
197 context.beginPath();
198 context.fillText((angle * 180 / Math.PI).toFixed(0),
199 circle.x + Math.cos(angle) * (radius - TICK_WIDTH*2),
200 circle.y - Math.sin(angle) * (radius - TICK_WIDTH*2));
201 }
202 context.restore();
203 }
204
205 // Initialization....................................................
206
207 context.shadowOffsetX = 2;
208 context.shadowOffsetY = 2;
209 context.shadowBlur = 4;
210
211 context.textAlign = ‘center‘;
212 context.textBaseline = ‘middle‘;
213 drawGrid(‘lightgray‘, 10, 10);
214 drawDial();

在上述的javascript代码中,有一些问题值得注意。首先,像往常一样,该应用程序在每次调用ARC()方法之前,几乎都会调用beginpath()方法,以便在创建弧形路径之前先开始一段新的路径。原来说过,arc()方法会将上一条子路径的终点与圆弧路径的起点相连,所以我们调用beginpath(),将当期路径的所有子路径都清除。这样的话,arc()方法就不会画出那些不美观的线段了。

该应用程序使用了绘制剪纸效果的技巧,来让表盘背景看起来有些透明。代码调用了arc()方法,按照顺时针方向来绘制外围的圆形,且按照逆时针方向来绘制里面的圆形。在这种情况下,为了做出剪纸的效果,应用程序并没有在第二次调用arc()方法之前先调用beginPath()方法。

第二个要注意的是,save()方法与restore()方法之间的那段代码,对绘图环境对象的某些属性做了一个临时性的修改,例如strokeStyle与fillStyle()等。通过Canvas绘图环境的save()与restrore()方法,你可以实现各自独立且互不干扰的绘图函数来。

最后,请注意应用程序是如何绘制仪表盘周围文字的。先把绘图环境对象的textAlign与textBaseline属性分别设置为center与middle,这样的话,应用程序就可以很容易地计算出绘制文本的位置了。

---恢复内容结束---

圆弧,尤其是圆,通常被用做描绘一些实物。下图所示的应用程序用5个圆形实现了一个仪表盘。仪表盘的刻度代表了圆周上的角度值。用户可以通过它来交互式地旋转多边形物体。

该应用程序使用了本章到目前为止所讲的很多技术。为了绘制这个仪表盘,该应用程序画了许多圆形与线段,使用了各种颜色及透明度,对圆形路径进行了描边与填充。同时为了使盘面上的刻度看起来有深度感,它还运用了阴影效果。该程序还运用了剪纸效果。使得仪表盘外围的那一圈看起来有半透明的效果。

仪表盘的绘制

html代码:


 1 <head>
2 <title>A Dial Showing the Degrees of a Circle</title>
3
4 <style>
5 body {
6 background: #eeeeee;
7 }
8
9 #canvas {
10 background: #ffffff;
11 cursor: crosshair;
12 margin-left: 10px;
13 margin-top: 10px;
14 -webkit-box-shadow: 4px 4px 8px rgba(0,0,0,0.5);
15 -moz-box-shadow: 4px 4px 8px rgba(0,0,0,0.5);
16 box-shadow: 4px 4px 8px rgba(0,0,0,0.5);
17 }
18
19 </style>
20 </head>
21
22 <body>
23 <canvas id=‘canvas‘ width=‘650‘ height=‘450‘>
24 Canvas not supported
25 </canvas>
26
27 <script src = ‘example.js‘></script>
28 </body>
29 </html>

example.js


  1 var canvas = document.getElementById(‘canvas‘),
2 context = canvas.getContext(‘2d‘),
3
4 CENTROID_RADIUS = 10,
5 CENTROID_STROKE_STYLE = ‘rgba(0, 0, 0, 0.5)‘,
6 CENTROID_FILL_STYLE = ‘rgba(80, 190, 240, 0.6)‘,
7
8 RING_INNER_RADIUS = 35,
9 RING_OUTER_RADIUS = 55,
10
11 ANNOTATIONS_FILL_STYLE = ‘rgba(0, 0, 230, 0.9)‘,
12 ANNOTATIONS_TEXT_SIZE = 12,
13
14 TICK_WIDTH = 10,
15 TICK_LONG_STROKE_STYLE = ‘rgba(100, 140, 230, 0.9)‘,
16 TICK_SHORT_STROKE_STYLE = ‘rgba(100, 140, 230, 0.7)‘,
17
18 TRACKING_DIAL_STROKING_STYLE = ‘rgba(100, 140, 230, 0.5)‘,
19
20 GUIDEWIRE_STROKE_STYLE = ‘goldenrod‘,
21 GUIDEWIRE_FILL_STYLE = ‘rgba(250, 250, 0, 0.6)‘,
22
23 circle = { x: canvas.width/2,
24 y: canvas.height/2,
25 radius: 150
26 };
27
28 // Functions..........................................................
29
30 function drawGrid(color, stepx, stepy) {
31 context.save()
32
33 context.shadowColor = undefined;
34 context.shadowOffsetX = 0;
35 context.shadowOffsetY = 0;
36
37 context.strokeStyle = color;
38 context.fillStyle = ‘#ffffff‘;
39 context.lineWidth = 0.5;
40 context.fillRect(0, 0, context.canvas.width,
41 context.canvas.height);
42
43 for (var i = stepx + 0.5;
44 i < context.canvas.width; i += stepx) {
45 context.beginPath();
46 context.moveTo(i, 0);
47 context.lineTo(i, context.canvas.height);
48 context.stroke();
49 }
50
51 for (var i = stepy + 0.5;
52 i < context.canvas.height; i += stepy) {
53 context.beginPath();
54 context.moveTo(0, i);
55 context.lineTo(context.canvas.width, i);
56 context.stroke();
57 }
58
59 context.restore();
60 }
61
62 function drawDial() {
63 var loc = {x: circle.x, y: circle.y};
64
65 drawCentroid();
66 drawCentroidGuidewire(loc);
67
68 drawRing();
69 drawTickInnerCircle();
70 drawTicks();
71 drawAnnotations();
72 }
73
74 function drawCentroid() {
75 context.beginPath();
76 context.save();
77 context.strokeStyle = CENTROID_STROKE_STYLE;
78 context.fillStyle = CENTROID_FILL_STYLE;
79 context.arc(circle.x, circle.y,
80 CENTROID_RADIUS, 0, Math.PI*2, false);
81 context.stroke();
82 context.fill();
83 context.restore();
84 }
85
86 function drawCentroidGuidewire(loc) {
87 var angle = -Math.PI/4,
88 radius, endpt;
89
90 radius = circle.radius + RING_OUTER_RADIUS;
91
92 if (loc.x >= circle.x) {
93 endpt = { x: circle.x + radius * Math.cos(angle),
94 y: circle.y + radius * Math.sin(angle)
95 };
96 }
97 else {
98 endpt = { x: circle.x - radius * Math.cos(angle),
99 y: circle.y - radius * Math.sin(angle)
100 };
101 }
102
103 context.save();
104
105 context.strokeStyle = GUIDEWIRE_STROKE_STYLE;
106 context.fillStyle = GUIDEWIRE_FILL_STYLE;
107
108 context.beginPath();
109 context.moveTo(circle.x, circle.y);
110 context.lineTo(endpt.x, endpt.y);
111 context.stroke();
112
113 context.beginPath();
114 context.strokeStyle = TICK_LONG_STROKE_STYLE;
115 context.arc(endpt.x, endpt.y, 5, 0, Math.PI*2, false);
116 context.fill();
117 context.stroke();
118
119 context.restore();
120 }
121
122 function drawRing() {
123 drawRingOuterCircle();
124
125 context.strokeStyle = ‘rgba(0, 0, 0, 0.1)‘;
126 context.arc(circle.x, circle.y,
127 circle.radius + RING_INNER_RADIUS,
128 0, Math.PI*2, false);
129
130 context.fillStyle = ‘rgba(100, 140, 230, 0.1)‘;
131 context.fill();
132 context.stroke();
133 }
134
135 function drawRingOuterCircle() {
136 context.shadowColor = ‘rgba(0, 0, 0, 0.7)‘;
137 context.shadowOffsetX = 3,
138 context.shadowOffsetY = 3,
139 context.shadowBlur = 6,
140 context.strokeStyle = TRACKING_DIAL_STROKING_STYLE;
141 context.beginPath();
142 context.arc(circle.x, circle.y, circle.radius +
143 RING_OUTER_RADIUS, 0, Math.PI*2, true);
144 context.stroke();
145 }
146
147 function drawTickInnerCircle() {
148 context.save();
149 context.beginPath();
150 context.strokeStyle = ‘rgba(0, 0, 0, 0.1)‘;
151 context.arc(circle.x, circle.y,
152 circle.radius + RING_INNER_RADIUS - TICK_WIDTH,
153 0, Math.PI*2, false);
154 context.stroke();
155 context.restore();
156 }
157
158 function drawTick(angle, radius, cnt) {
159 var tickWidth = cnt % 4 === 0 ? TICK_WIDTH : TICK_WIDTH/2;
160
161 context.beginPath();
162
163 context.moveTo(circle.x + Math.cos(angle) * (radius - tickWidth),
164 circle.y + Math.sin(angle) * (radius - tickWidth));
165
166 context.lineTo(circle.x + Math.cos(angle) * (radius),
167 circle.y + Math.sin(angle) * (radius));
168
169 context.strokeStyle = TICK_SHORT_STROKE_STYLE;
170 context.stroke();
171 }
172
173 function drawTicks() {
174 var radius = circle.radius + RING_INNER_RADIUS,
175 ANGLE_MAX = 2*Math.PI,
176 ANGLE_DELTA = Math.PI/64,
177 tickWidth;
178
179 context.save();
180
181 for (var angle = 0, cnt = 0; angle < ANGLE_MAX;
182 angle += ANGLE_DELTA, cnt++) {
183 drawTick(angle, radius, cnt++);
184 }
185
186 context.restore();
187 }
188
189 function drawAnnotations() {
190 var radius = circle.radius + RING_INNER_RADIUS;
191
192 context.save();
193 context.fillStyle = ANNOTATIONS_FILL_STYLE;
194 context.font = ANNOTATIONS_TEXT_SIZE + ‘px Helvetica‘;
195
196 for (var angle=0; angle < 2*Math.PI; angle += Math.PI/8) {
197 context.beginPath();
198 context.fillText((angle * 180 / Math.PI).toFixed(0),
199 circle.x + Math.cos(angle) * (radius - TICK_WIDTH*2),
200 circle.y - Math.sin(angle) * (radius - TICK_WIDTH*2));
201 }
202 context.restore();
203 }
204
205 // Initialization....................................................
206
207 context.shadowOffsetX = 2;
208 context.shadowOffsetY = 2;
209 context.shadowBlur = 4;
210
211 context.textAlign = ‘center‘;
212 context.textBaseline = ‘middle‘;
213 drawGrid(‘lightgray‘, 10, 10);
214 drawDial();

在上述的javascript代码中,有一些问题值得注意。首先,像往常一样,该应用程序在每次调用ARC()方法之前,几乎都会调用beginpath()方法,以便在创建弧形路径之前先开始一段新的路径。原来说过,arc()方法会将上一条子路径的终点与圆弧路径的起点相连,所以我们调用beginpath(),将当期路径的所有子路径都清除。这样的话,arc()方法就不会画出那些不美观的线段了。

该应用程序使用了绘制剪纸效果的技巧,来让表盘背景看起来有些透明。代码调用了arc()方法,按照顺时针方向来绘制外围的圆形,且按照逆时针方向来绘制里面的圆形。在这种情况下,为了做出剪纸的效果,应用程序并没有在第二次调用arc()方法之前先调用beginPath()方法。

第二个要注意的是,save()方法与restore()方法之间的那段代码,对绘图环境对象的某些属性做了一个临时性的修改,例如strokeStyle与fillStyle()等。通过Canvas绘图环境的save()与restrore()方法,你可以实现各自独立且互不干扰的绘图函数来。

最后,请注意应用程序是如何绘制仪表盘周围文字的。先把绘图环境对象的textAlign与textBaseline属性分别设置为center与middle,这样的话,应用程序就可以很容易地计算出绘制文本的位置了。

时间: 2024-10-22 23:27:51

html5 canvas绘图-刻度仪表盘的绘制的相关文章

html5 canvas绘图-贝塞尔曲线

贝塞尔曲线(ezier curve)最迟是由法国物理学家与数学家paul de Casteljau发明的.它的广泛运用则要归功于法国工程师皮埃尔 贝塞尔 贝塞尔曲线期初被用在汽车车身的设计上.现在则多用于计算机图形系统中.例如Adobe Illustrator/Apple的Cocoa框架以及在Html5的canvas. 贝塞尔曲线分为两种:平方(quadratic)贝塞尔曲线及立方(cubic)贝塞尔曲线.平方贝塞尔曲线是一种二次曲线(second degree curve),意思就是说,它们是

HTML5 Canvas 绘图入门

HTML5 Canvas 绘图入门 HTML5 Canvas 绘图入门,仅供学习参考 <!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title>HTML5 移动Web开发指南</title> <style type="text/css"> h1, h5 { text-align: center; } canvas {

HTML5 canvas绘图基本使用方法

<canvas></canvas>是HTML5中新增的标签,用于绘制图形,实际上,这个标签和其他的标签一样,其特殊之处在于该标签可以获取一个CanvasRenderingContext2D对象,我们可以通过JavaScript脚本来控制该对象进行绘图. <canvas></canvas>只是一个绘制图形的容器,除了id.class.style等属性外,还有height和width属性.在<canvas>>元素上绘图主要有三步: 获取<

HTML5 canvas绘图

HTML5 canvas画图 示例 ------- <!DOCTYPE html> <head> <meta charset="UTF-8"> <script src="jquery-3.1.1.min.js"></script> <link rel="stylesheet" type="text/css" href="style.css"

HTML5 Canvas绘图详解 drawImage() 方法 有图有真相!

步骤 1 2 3 4 5 简介 是一个新的HTML元素,这个元素可以被Script语言(通常是JavaScript)用来绘制图形.例如可以用它来画图.合成图象.或做简单的(和不那么简单的)动画. 工具/原料 html script 步骤/方法 最常见的在canvas上画图的方法是使用Image对象.所支持的来源图片格式依赖于浏览器的支持,然而,一些典型的图片格式(png,jpg,gif等)基本上都没有问题. 在下面的所有例子中,图片源将会使用这张256×256尺寸的图片. 绘制图片:在最基本的画

HTML5 &lt;canvas&gt; 元素用于图形的绘制,通过脚本(通常是javascript)完成

<canvas> 标签只是图形容器,您必须使用脚本来绘制图形 可以通过多种方法使用canvas绘制路径\盒\圆以及添加图像 创建一个画布(Canvas) 一个画布在网页中是一个矩形框,通过 <canvas> 元素来绘制. 注意: 默认情况下 <canvas> 元素没有边框和内容. <canvas>简单实例如下: <canvas id="myCanvas" width="200" height="100&

HTML5 Canvas绘图系列之一:圆弧等基础图形的实现

之前的一个微信项目已经要结项了,最近整理一下项目中使用较多的canvas画图方面的知识吧,打算写个3,4篇的样子.本篇主要介绍基础操作和弧线画法. 之后再写一下趋势图,直方图,文本图像处理的. 言归正传,canvas元素本身是一个容器元素,提供一块画布,用脚本来实现想要画什么.为了演示使用,我们新增一个空的aspx页. 首先,我们新增一个canvas元素: <canvas id="myConvas" style="display:block; margin: 0 aut

html5 canvas绘图—三次方贝塞尔曲线

我们知道二次方贝塞尔曲线,那些曲线都是二维的,意思就是说,它们都只能向一个方向弯曲.如果需要如图这样,能够向两个方向弯曲的曲线,那么你需要的就是三次贝塞尔曲线. 该图所示应用程序使用bezierCurveTo()方法创建了一条代表三次方贝塞尔曲线的路径.该应用程序的代码列在了下面的程序清单中. 这段代码除了绘制曲线本身,还填充了表示曲线控制点与锚点的小圆圈. html代码: 1 <html> 2 <head> 3 <title>Bezier Curves</tit

HTML5 Canvas核心技术:图形、动画与游戏开发 PDF扫描版?

HTML5 Canvas核心技术:图形.动画与游戏开发 内容简介: <HTML5 Canvas核心技术:图形.动画与游戏开发>中,畅销书作家David Geary(基瑞)先生以实用的范例程序直接切入这套API,全面讲解其功能,以求让读者实现出内容丰富且界面一致的网络应用程序,并将开发好的程序部署在多种设备及操作系统之上. 教程地址:HTML5 Canvas核心技术:图形.动画与游戏开发 PDF扫描版? HTML5 Canvas核心技术:图形.动画与游戏开发 目录: 前言 第1章 基础知识 1.