Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
20 | reyssat | 1 | // 2D Graphics Package |
2 | // Drawing routines for DynLayer |
||
3 | // Copyright (C) 2000-2001 Dan Steinman, Guoyi Chao, Rob Breeds |
||
4 | |||
5 | // Guoyi Chao: drawing routines for line, circle, ellipse |
||
6 | // Dan Steinman: DynAPI2 support, object wrappers, VML support, improved routines for line, rect, and fills() |
||
7 | // Rob Breeds: improve performance on ellipse and circle algorithms, and added line thicknesses support |
||
8 | |||
9 | // Distributed under the terms of the GNU Library General Public License |
||
10 | |||
11 | function Graphics(dlyr) { |
||
12 | this._dlyr = dlyr; |
||
13 | this._s = "yellow"; |
||
14 | this._w = 1; |
||
15 | this._f = "white"; |
||
16 | } |
||
17 | Graphics.prototype.setStrokeColor = function(v) {this._s = v}; |
||
18 | Graphics.prototype.setStrokeWeight = function(v) {this._w = v}; |
||
19 | Graphics.prototype.setFillColor = function(v) {this._f = v}; |
||
20 | Graphics.prototype.drawPixel = function(x,y) { |
||
21 | drawPixel(x,y,this._s,this._w,this); |
||
22 | }; |
||
23 | Graphics.prototype.drawLine = function(x1,y1,x2,y2) { |
||
24 | var shape; |
||
25 | if (Graphics.useVML) { |
||
26 | shape = new VML_Line(x1,y1,x2,y2,this._w,this._s); |
||
27 | this._dlyr.elm.appendChild(shape.elm); |
||
28 | } |
||
29 | else { |
||
30 | shape = new Line(x1,y1,x2,y2,this._w,this._s); |
||
31 | this._dlyr.addChild(shape); |
||
32 | } |
||
33 | return shape; |
||
34 | }; |
||
35 | Graphics.prototype.drawCircle = function(x,y,radius) { |
||
36 | var shape; |
||
37 | if (Graphics.useVML) { |
||
38 | // bug in IE, always fills anyway |
||
39 | shape = new VML_Oval(x,y,2*radius,2*radius,this._w,this._s, dynapi.ua.ie5?this._dlyr.bgColor:false); |
||
40 | this._dlyr.elm.appendChild(shape.elm); |
||
41 | } |
||
42 | else { |
||
43 | shape = new Circle(x,y,radius,this._w,this._s); |
||
44 | this._dlyr.addChild(shape); |
||
45 | } |
||
46 | return shape; |
||
47 | }; |
||
48 | Graphics.prototype.fillCircle = function(x,y,r) { |
||
49 | fillCircle(x+r,y+r,r,this.color,this._dlyr); |
||
50 | }; |
||
51 | Graphics.prototype.drawOval = function(x,y,w,h) { |
||
52 | drawEllipse(x+w/2,y+h/2,w,h,this.color,false,this.thickness,this._dlyr); |
||
53 | }; |
||
54 | Graphics.prototype.fillEllipse = function(x,y,w,h) { |
||
55 | drawEllipse(x+w/2,y+h/2,w,h,this.color,true,this.thickness,this._dlyr); |
||
56 | }; |
||
57 | Graphics.prototype.drawRect = function(x,y,w,h) { |
||
58 | drawRect(x,y,w,h,this.color,this.thickness,this._dlyr); |
||
59 | }; |
||
60 | Graphics.prototype.fillRect = function(x,y,w,h) { |
||
61 | fillRect(x,y,w,h,this.color,this._dlyr); |
||
62 | }; |
||
63 | Graphics.prototype.clear = function() { |
||
64 | this.deleteAllChildren(); |
||
65 | this.setHTML(''); |
||
66 | }; |
||
67 | |||
68 | Graphics.useVML = false; |
||
69 | if (dynapi.ua.ie && dynapi.ua.v>=5) { // include active-x component for IE5+ |
||
70 | Graphics.useVML = true; |
||
71 | var str = '<xml:namespace ns="urn:schemas-microsoft-com:vml" prefix="v"/>'+ |
||
72 | '<object id="VMLRender" codebase="vgx.dll" classid="CLSID:10072CEC-8CC1-11D1-986E-00A0C955B42E"></object>'+ |
||
73 | '<style>'+ |
||
74 | '<!--'+ |
||
75 | 'v\\:* { behavior: url(#VMLRender); }'+ |
||
76 | '-->'+ |
||
77 | '</style>'; |
||
78 | |||
79 | if (dynapi.loaded) { |
||
80 | dynapi.frame.document.body.appendChild('beforeEnd',str); |
||
81 | } |
||
82 | else { |
||
83 | document.write(str); |
||
84 | } |
||
85 | } |
||
86 | |||
87 | // Drawing Routines |
||
88 | |||
89 | function Pixel(x,y,color,t) { // not really needed |
||
90 | this.DynLayer = DynLayer; |
||
91 | this.DynLayer(); |
||
92 | this.setLocation(x,y); |
||
93 | this.setSize(t||1,t||1); |
||
94 | this.setBgColor(color||"black"); |
||
95 | } |
||
96 | Pixel.prototype = new DynLayer(); |
||
97 | |||
98 | function drawPixel(x,y,color,t,lyr) { |
||
99 | lyr.addChild( new DynLayer('',Math.round(x),Math.round(y),t,t,color) ) |
||
100 | } |
||
101 | |||
102 | function Shape() { |
||
103 | this.DynLayer = DynLayer; |
||
104 | this.DynLayer(); |
||
105 | |||
106 | this.setStrokeColor("black"); |
||
107 | this.setStrokeWeight(1); |
||
108 | } |
||
109 | Shape.prototype = new DynLayer(); |
||
110 | Shape.prototype.setStrokeColor = function(v) {this._s = v}; |
||
111 | Shape.prototype.setStrokeWeight = function(v) {this._w = v}; |
||
112 | |||
113 | function Line(x1,y1,x2,y2,w,s) { |
||
114 | this.Shape = Shape; |
||
115 | this.Shape(); |
||
116 | this.setStrokeWeight(w); |
||
117 | this.setStrokeColor(s); |
||
118 | |||
119 | var dx = Math.min(x1,x2); |
||
120 | var dy = Math.min(y1,y2); |
||
121 | var width = Math.abs(x2-x1); |
||
122 | var height = Math.abs(y2-y1); |
||
123 | this.setLocation(dx, dy); |
||
124 | |||
125 | if(x1==x2||y1==y2) { // straight line |
||
126 | this.setBgColor(s); |
||
127 | if(x1==x2) this.setSize(w,height); // vertical |
||
128 | else this.setSize(width,w); //horizontal |
||
129 | } |
||
130 | else { // diagonal |
||
131 | this.setSize(width,height); |
||
132 | var nx1 = x1-dx; |
||
133 | var ny1 = y1-dy; |
||
134 | var nx2 = x2-dx; |
||
135 | var ny2 = y2-dy; |
||
136 | drawLine(nx1,ny1,nx2,ny2,s,w,this); |
||
137 | } |
||
138 | } |
||
139 | Line.prototype = new Shape(); |
||
140 | |||
141 | function VMLElement() { |
||
142 | this.elm = null |
||
143 | }; |
||
144 | VMLElement.prototype.createShape = function(type) { |
||
145 | this.elm = document.createElement('v:'+type); |
||
146 | } |
||
147 | VMLElement.prototype.setLocation = function() {}; |
||
148 | |||
149 | function VML_Line(x1,y1,x2,y2,w,s) { |
||
150 | this.VMLElement = VMLElement; |
||
151 | this.VMLElement(); |
||
152 | |||
153 | this.createShape("line"); |
||
154 | this.elm.from = x1+'px ,'+y1+'px'; |
||
155 | this.elm.to = x2+'px ,'+y2+'px'; |
||
156 | this.elm.strokeColor = s; |
||
157 | this.elm.innerHTML = '<v:stroke weight="'+w+'px">'; |
||
158 | |||
159 | //this.elm.innerHTML = '<v:stroke weight="'+this.thickness+'px" color="'+this.color+'">'; |
||
160 | //"<v:line id='line" + nnode + "' from=" + x1 + "," + y1 +"' to='" + x2 + "," + y2 +"'><v:stroke weight='2px' color='black'/></v:line>"; |
||
161 | }; |
||
162 | VML_Line.prototype = new VMLElement(); |
||
163 | |||
164 | function VML_Oval(x,y,width,height,w,s,fc) { |
||
165 | this.VMLElement = VMLElement; |
||
166 | this.VMLElement(); |
||
167 | |||
168 | this.elm = document.createElement('v:oval'); |
||
169 | this.elm.style.position = "absolute"; |
||
170 | this.elm.style.left = x+"px"; |
||
171 | this.elm.style.top = y+"px"; |
||
172 | this.elm.style.width = width+"px"; |
||
173 | this.elm.style.height = height+"px"; |
||
174 | |||
175 | this.elm.strokeColor = s; |
||
176 | |||
177 | if (fc) { |
||
178 | this.elm.fillColor = fc; |
||
179 | this.elm.fill = true; |
||
180 | } |
||
181 | else this.elm.fill = false; |
||
182 | |||
183 | this.elm.innerHTML = '<v:stroke weight="'+w+'px">'; |
||
184 | }; |
||
185 | VML_Oval.prototype = new VMLElement(); |
||
186 | |||
187 | function drawLine(x1,y1,x2,y2,color,t,lyr) { |
||
188 | var flag = (Math.abs(y2-y1) > Math.abs(x2-x1)) |
||
189 | var dx,dy,x,y,e,xstep,ystep |
||
190 | if (flag) dx=Math.abs(y2-y1),dy=Math.abs(x2-x1),x=y1,y=x1 |
||
191 | else dx=Math.abs(x2-x1),dy=Math.abs(y2-y1),x=x1,y=y1 |
||
192 | xstep=x1>x2?-1:1 |
||
193 | ystep=y1>y2?-1:1 |
||
194 | if(x1==x2||y1==y2) { |
||
195 | if(x1==x2) { |
||
196 | var ny1 = Math.min(y1,y2) |
||
197 | var ny2 = Math.max(y1,y2) |
||
198 | lyr.addChild( new DynLayer('',x1,ny1,t,(ny2-ny1)*t,color) ) |
||
199 | return |
||
200 | } |
||
201 | else { |
||
202 | var nx1 = Math.min(x1,x2) |
||
203 | var nx2 = Math.max(x1,x2) |
||
204 | lyr.addChild( new DynLayer('',nx1,y1,(nx2-nx1)*t,t,color) ) |
||
205 | return |
||
206 | } |
||
207 | } |
||
208 | // Bresenham Method Begin |
||
209 | var e=-dx |
||
210 | for(var count=0;count<=dx;count++) { |
||
211 | if (flag) drawPixel(y,x,color,t,lyr) |
||
212 | else drawPixel(x,y,color,t,lyr) |
||
213 | if (flag) x+=ystep |
||
214 | else x+=xstep |
||
215 | e+=dy<<1 |
||
216 | if(e>=0) { |
||
217 | if(flag) y+=xstep |
||
218 | else y+=ystep |
||
219 | e-=dx<<1 |
||
220 | } |
||
221 | } |
||
222 | return |
||
223 | } |
||
224 | |||
225 | function Circle(x,y,radius,w,s) { |
||
226 | this.Shape = Shape; |
||
227 | this.Shape(); |
||
228 | this.setStrokeWeight(w); |
||
229 | this.setStrokeColor(s); |
||
230 | |||
231 | this.setLocation(x,y); |
||
232 | this.setSize(2*radius, 2*radius); |
||
233 | |||
234 | drawCircle(0+radius,0+radius,radius-1,this._s,this._w,this); |
||
235 | } |
||
236 | Circle.prototype = new Shape(); |
||
237 | |||
238 | function drawCircle(centerX,centerY,radius,color,t,lyr) { |
||
239 | var x = centerX; |
||
240 | var y = centerY; |
||
241 | var cx = 0 |
||
242 | var cy = radius |
||
243 | var df = 1 - radius |
||
244 | var d_e = 3 |
||
245 | var d_se = -(radius<<1) + 5 |
||
246 | do { |
||
247 | drawPixel(x+cx, y+cy, color,t,lyr) |
||
248 | if (cx) drawPixel(x-cx, y+cy, color,t,lyr) |
||
249 | if (cy) drawPixel(x+cx, y-cy, color,t,lyr) |
||
250 | if ((cx) && (cy)) drawPixel(x-cx, y-cy, color,t,lyr) |
||
251 | if (cx != cy) { |
||
252 | drawPixel(x+cy, y+cx, color,t,lyr) |
||
253 | if (cx) drawPixel(x+cy, y-cx, color,t,lyr) |
||
254 | if (cy) drawPixel(x-cy, y+cx, color,t,lyr) |
||
255 | if (cx && cy) drawPixel(x-cy, y-cx, color,t,lyr) |
||
256 | } |
||
257 | if (df < 0) { |
||
258 | df += d_e |
||
259 | d_e += 2 |
||
260 | d_se += 2 |
||
261 | } |
||
262 | else { |
||
263 | df += d_se |
||
264 | d_e += 2 |
||
265 | d_se += 4 |
||
266 | cy-- |
||
267 | } |
||
268 | cx++ |
||
269 | } while (cx <= cy) |
||
270 | } |
||
271 | |||
272 | function fillCircle(x,y,radius,color,lyr) { |
||
273 | var cx = 0 |
||
274 | var cy = radius |
||
275 | var df = 1 - radius |
||
276 | var d_e = 3 |
||
277 | var d_se = -(radius<<1) + 5 |
||
278 | do { |
||
279 | fillRect(x-cy, y-cx, cy<<1, cx<<1, color,lyr) |
||
280 | if (df < 0) { |
||
281 | df += d_e |
||
282 | d_e += 2 |
||
283 | d_se += 2 |
||
284 | } |
||
285 | else { |
||
286 | if (cx != cy) fillRect(x-cx, y-cy, cx<<1, cy<<1, color,lyr) |
||
287 | df += d_se |
||
288 | d_e += 2 |
||
289 | d_se += 4 |
||
290 | cy-- |
||
291 | } |
||
292 | cx++ |
||
293 | } while (cx <= cy) |
||
294 | } |
||
295 | |||
296 | function drawEllipse(cx,cy,rx,ry,color,filled,t,lyr) { |
||
297 | var x,y,a2,b2, S, T |
||
298 | a2 = rx*rx |
||
299 | b2 = ry*ry |
||
300 | x = 0 |
||
301 | y = ry |
||
302 | S = a2*(1-2*ry) + 2*b2 |
||
303 | T = b2 - 2*a2*(2*ry-1) |
||
304 | symmPaint(cx,cy,x,y,color,filled,t,lyr) |
||
305 | do { |
||
306 | if (S<0) { |
||
307 | S += 2*b2*(2*x+3) |
||
308 | T += 4*b2*(x+1) |
||
309 | x++ |
||
310 | } else if (T<0) { |
||
311 | S += 2*b2*(2*x+3) - 4*a2*(y-1) |
||
312 | T += 4*b2*(x+1) - 2*a2*(2*y-3) |
||
313 | x++ |
||
314 | y-- |
||
315 | } else { |
||
316 | S -= 4*a2*(y-1) |
||
317 | T -= 2*a2*(2*y-3) |
||
318 | y-- |
||
319 | } |
||
320 | symmPaint(cx,cy,x,y,color,filled,t,lyr) |
||
321 | } while (y>0) |
||
322 | } |
||
323 | |||
324 | //Bresenham's algorithm for ellipses |
||
325 | function symmPaint(cx,cy, x, y, color, filled, t, lyr){ |
||
326 | if (filled) { |
||
327 | fillRect ( cx-x, cy-y, x<<1, y<<1, color, lyr ) |
||
328 | } else { |
||
329 | drawPixel ( cx-x, cy-y, color, t,lyr ) |
||
330 | drawPixel ( cx+x, cy-y, color, t,lyr ) |
||
331 | drawPixel ( cx-x, cy+y, color, t,lyr ) |
||
332 | drawPixel ( cx+x, cy+y, color, t,lyr ) |
||
333 | } |
||
334 | } |
||
335 | |||
336 | function drawRect(x,y,w,h,color,t,lyr) { |
||
337 | lyr.addChild( new DynLayer('',x,y,w,t,color) ) |
||
338 | lyr.addChild( new DynLayer('',x,y,t,h,color) ) |
||
339 | lyr.addChild( new DynLayer('',x+w-t,y,t,h,color) ) |
||
340 | lyr.addChild( new DynLayer('',x,y+h-t,w,t,color) ) |
||
341 | } |
||
342 | |||
343 | function fillRect(x,y,w,h,color,lyr) { |
||
344 | lyr.addChild( new DynLayer('',x,y,w,h,color) ) |
||
345 | } |