核心代码:
1./**
2. * GCanvas 1.2
3. * @author GreatGhoul
4. * @email: greatghoul@gmail.com
5. * @blog: http://greatghoul.iteye.com
6. */
7.(function() {
8. // 创建GCanvas构造方法的闭包和全局引用
9. var GCanvas = window.GCanvas = function(id, w, h) {
10. return new Canvas(id, w, h);
11. }
12.
13. /**
14. * 用指定的id, 长和宽构造一个画板
15. *
16. * @param id html元素的id
17. * @param w 指定的画板宽度
18. * @param h 指定的画板高度
19. */
20. var Canvas = function(id, w, h) {
21. // 只想Canvas实例,以修正this指针的引用错误.
22. var self = this;
23.
24. // 缓冲器
25. var cache = [];
26.
27. // 画板绑定到的html元素的引用
28. var canvas = document.getElementById(id);
29.
30. // 画板底色, 默认为浅灰色
31. var bgColor = "lightgray";
32.
33. // 笔刷的颜色, 默认为黑色
34. var fgColor = "black";
35.
36. // 原点坐标, 初始为(0, 0)
37. var oX = 0, oY = 0;
38.
39. // 是否允许点画到画板边界以外
40. var allowOutside = false;
41.
42. // 渲染html元素
43. canvas.onselectstart = function() {return false;}
44. canvas.style.overflow = "hidden";
45. canvas.style.background = "lightblue";
46. canvas.style.width = (w ? w : 400) + "px";
47. canvas.style.height = (h ? h : 400) + "px";
48.
49. this.copyright = function() {
50. var c = "# G2W GCanvas [Version 1.2]\n"
51. + "# (C) Copyright 2009-2010 G2W Blog.\n"
52. + "# http://greatghoul.iteye.com \n";
53.
54. return c;
55. }
56.
57. /**
58. * 获取画板左上角的在文档中的绝对坐标
59. *
60. * @return 形如{x, y}的坐标
61. */
62. this.pos = function() {
63. var rect = canvas.getClientRects()[0];
64. return {
65. x: rect.left,
66. y: rect.top
67. };
68. }
69.
70. /**
71. * 清空画板
72. */
73. this.clear = function() {
74. cache = [];
75. canvas.innerHTML = "";
76. }
77.
78. /**
79. * 设置或取得画板的大小, 如果缓存不为空,则设置无效
80. *
81. * @param w 新的宽度
82. * @param h 新的高度
83. * @return 形如{width, height}的尺寸
84. */
85. this.size = function(w, h) {
86. if (w && h) {
87. if (cache.length != 0) return;
88. canvas.style.width = w + "px";
89. canvas.style.height = h + "px";
90. } else {
91. return {
92. parseInt(canvas.style.width),
93. height: parseInt(canvas.style.width)
94. };
95. }
96. }
97.
98. /**
99. * 设置或取得是否允许点显示到画板边界以外
100. *
101. * @param flag true为允许显示,false为不允许,其它为不做改变
102. * @return 是否允许显示
103. */
104. this.allowOutside = function(flag) {
105. if (flag == true || flag == false)
106. allowOutside = flag;
107. return allowOutside;
108. }
109.
110. /**
111. * 设置或取得笔刷颜色
112. * 颜色的格式为:
113. * rgb(r, g, b) 其中r, g, b为0-255的整数
114. * #000000 ~ #FFFFFF
115. * 字符串描述 如: red, blue, black, lightblue
116. *
117. * @param color 新的笔刷颜色
118. * @return 当前笔刷颜色
119. */
120. this.fgColor = function(color) {
121. fgColor = (color ? color: fgColor);
122. return fgColor;
123. }
124.
125. /**
126. * 设置或取得画布颜色
127. * 颜色的格式为:
128. * rgb(r, g, b) 其中r, g, b为0-255的整数
129. * #000000 ~ #FFFFFF
130. * 字符串描述 如: red, blue, black, lightblue
131. *
132. * @param color 新的画布颜色
133. * @return 当前画布颜色
134. */
135. this.bgColor = function(color) {
136. bgColor = (color ? color: bgColor);
137. canvas.style.background = bgColor;
138. return bgColor;
139. }
140.
141. /**
142. * 在给定的坐标出画点
143. *
144. * @param x x坐标
145. * @param y y坐标
146. */
147. this.point = function(x, y) {
148. var pos = self.pos();
149. var size = self.size();
150. x = pos.x + oX + x;
151. y = pos.y + oY + y;
152.
153. // 如果不允许在边界外显示点,则不讲该点推入缓存
154. if (!allowOutside
155. && !((x >= pos.x && x <= pos.x + size.width)
156. && (y >= pos.y && y <= pos.y + size.height)))
157. return;
158. cache.push("<div style='1px;height:1px;position:absolute;left:" + x +"px;top:" + y + "px;background-color:" + fgColor + ";font-size:0px;z-index:999;'></div>");
159. }
160.
161. /**
162. * 数值微分法画直线
163. *
164. * @param x0 起点x坐标
165. * @param y0 起点y坐标
166. * @param x1 终点x坐标
167. * @param y1 终点y坐标
168. */
169. function line_DDA(x0, y0, x1, y1) {
170. var px = x0, py = y0;
171. var dx = x1 - x0;
172. var dy = y1 - y0;
173. var incX = 0, incY = 0;
174. var epsl = Math.abs(dx) > Math.abs(dy) ? Math.abs(dx) : Math.abs(dy);
175. incX = dx / epsl;
176. incY = dy / epsl;
177. for (var i = 0; i < epsl; i++) {
178. self.point(parseInt(px + 0.5), parseInt(py + 0.5));
179. px += incX;
180. py += incY;
181. }
182. }
183.
184. /**
185. * 用给定的起点和终点坐标画直线
186. *
187. * @param x0 起点x坐标
188. * @param y0 起点y坐标
189. * @param x1 终点x坐标
190. * @param y1 终点y坐标
191. */
192. this.line = function(x0, y0, x1, y1) {
193. line_DDA(x0, y0, x1, y1);
194. }
195.
196. /**
197. * 用中点Bresenham法画圆
198. *
199. * @param x 圆心x坐标
200. * @param y 圆心y坐标
201. * @param r 圆的半径
202. */
203. function circle_MidBresenham(x, y, r) {
204. var px, py, d;
205. px = 0; py = r; d = 1 - r;
206. while (px < py) {
207. self.point(x + px, y + py);
208. self.point(x + py, y + px);
209. self.point(x - px, y + py);
210. self.point(x + py, y - px);
211. self.point(x + px, y - py);
212. self.point(x - py, y + px);
213. self.point(x - px, y - py);
214. self.point(x - py, y - px);
215. if (d < 0) d += 2 * px + 3;
216. else {
217. d += 2 * (px - py) + 5;
218. py--;
219. }
220. px++;
221. }
222. }
223.
224. /**
225. * 用给定的圆心坐标和半径画圆
226. *
227. * @param x 圆心x坐标
228. * @param y 圆心y坐标
229. * @param r 圆的半径
230. */
231. this.circle = function(x, y, r) {
232. circle_MidBresenham(x, y, r);
233. }
234.
235. /**
236. * 用中点Bresenham法画椭圆
237. *
238. * @param x 圆心x坐标
239. * @param y 圆心y坐标
240. * @param a 长半轴长度
241. * @param b 短半轴长度
242. */
243. function MidBresenhamEllipse(x, y, a, b) {
244. var px, py;
245. var d1, d2;
246. px = 0;
247. py = b;
248. d1 = b * b + a * a * (-b + 0.25);
249. self.point(x + px, y + py);
250. self.point(x - px, y - py);
251. self.point(x - px, y + py);
252. self.point(x + px, y - py);
253. while (b * b * (px + 1) < a * a * (py - 0.5)) {
254. if (d1 <= 0) {
255. d1 += b * b * (2 * px + 3);
256. px++;
257. } else {
258. d1 += b * b * (2 * px + 3) + a * a * (-2 * py + 2);
259. px++;
260. py--;
261. }
262. self.point(x + px, y + py);
263. self.point(x - px, y - py);
264. self.point(x - px, y + py);
265. self.point(x + px, y - py);
266. }
267. d2 = b * b * (px + 0.5) * (px + 0.5) + a * a * (py - 1) * (py - 1) - a * a * b * b;
268. while (py > 0) {
269. if (d2 <= 0) {
270. d2 += b * b * (2 * px + 2) + a * a * (-2 * py + 3);
271. px++;
272. py--;
273. } else {
274. d2 += a * a * (-2 * py + 3);
275. py--;
276. }
277. self.point(x + px, y + py);
278. self.point(x - px, y - py);
279. self.point(x - px, y + py);
280. self.point(x + px, y - py);
281. }
282. }
283.
284. /**
285. * 用给定的圆心坐标和长短半轴画椭圆
286. *
287. * @param x 圆心x坐标
288. * @param y 圆心y坐标
289. * @param a 长半轴长度
290. * @param b 短半轴长度
291. */
292. this.ellipse = function(x, y, a, b) {
293. MidBresenhamEllipse(x, y, a, b);
294. }
295.
296.
297. /**
298. * 将缓存中的图像显示到画板上,并清空缓存
299. */
300. this.paint = function() {
301. canvas.innerHTML += cache.join("");;
302. cache = [];
303. }
304. }
305.})();