Project

General

Profile

canvas_drawing_example_20150723.html

Greg Shah, 07/23/2015 06:08 PM

Download (13.2 KB)

 
1
<!DOCTYPE html>
2
<html lang="en">
3
   <head>
4
      <meta charset="utf-8" />
5
      <title>Canvas Drawing Example</title>
6
      
7
      <script>
8
         var canvas;
9
         
10
         var ctx;
11
         
12
         function drawLine(x1, y1, x2, y2)
13
         {
14
            ctx.beginPath();
15
            ctx.moveTo(x1, y1);
16
            ctx.lineTo(x2, y2);
17
            ctx.stroke();         
18
         }
19
         
20
         function renderClosedPath(ctx, fill)
21
         {
22
            ctx.save();
23
            ctx.clip();
24
            
25
            if (fill)
26
            {
27
               ctx.fill();
28
            }
29
            else
30
            {
31
               ctx.stroke();
32
            }
33
            
34
            ctx.restore();
35
         }
36
         
37
         // 
38
         // Draw a rounded rectangle with the given context, dimensions and fill.
39
         // 
40
         // @param    {CanvasRenderingContext2D} ctx
41
         //           The canvas 2D graphics context.
42
         // @param    {Number} x
43
         //           X coordinate of the top left of the rectangle (if a square corner was placed
44
         //           there).
45
         // @param    {Number} y
46
         //           Y coordinate of the top left of the rectangle (if a square corner was placed
47
         //           there).
48
         // @param    {Number} width
49
         //           Width of the rectangle.
50
         // @param    {Number} height
51
         //           Height of the rectangle.
52
         // @param    {Number} diameter
53
         //           Diameter of the arc that defines the rounded corner.
54
         // @param    {Boolean} fill
55
         //           <code>true</code> to fill the rectangle with the current color, otherwise just
56
         //           stroke the rectangle.
57
         // 
58
         function createRoundRect(ctx, x, y, width, height, diameter, fill)
59
         {
60
            var radius = diameter / 2;
61
            
62
            // arc control points
63
            var northWestX = x;
64
            var northWestY = y;
65
            var northEastX = x + width;
66
            var northEastY = y;
67
            var southWestX = x;
68
            var southWestY = y + height;
69
            var southEastX = x + width;
70
            var southEastY = y + height;
71
            
72
            // line end points
73
            var topLeftX     = northWestX + radius;
74
            var topLeftY     = northWestY;
75
            var topRightX    = northEastX - radius;
76
            var topRightY    = northEastY;
77
            var rightUpX     = northEastX;
78
            var rightUpY     = northEastY + radius;
79
            var rightDownX   = southEastX;
80
            var rightDownY   = southEastY - radius;
81
            var bottomRightX = southEastX - radius;
82
            var bottomRightY = southEastY;
83
            var bottomLeftX  = southWestX + radius;
84
            var bottomLeftY  = southWestY;
85
            var leftDownX    = southWestX;
86
            var leftDownY    = southWestY - radius;
87
            var leftUpX      = northWestX;
88
            var leftUpY      = northWestY + radius;
89
            
90
            ctx.beginPath();
91
            ctx.moveTo(topRightX, topRightY);
92
            ctx.quadraticCurveTo(northEastX, northEastY, rightUpX, rightUpY);
93
            ctx.lineTo(rightDownX, rightDownY);
94
            ctx.quadraticCurveTo(southEastX, southEastY, bottomRightX, bottomRightY);
95
            ctx.lineTo(bottomLeftX, bottomLeftY);
96
            ctx.quadraticCurveTo(southWestX, southWestY, leftDownX, leftDownY);
97
            ctx.lineTo(leftUpX, leftUpY);
98
            ctx.quadraticCurveTo(northWestX, northWestY, topLeftX, topLeftY);
99
            ctx.closePath();
100
            
101
            renderClosedPath(ctx, fill);
102
         }
103
         
104
         function parseColor(spec)
105
         {
106
            if (typeof spec !== "string")
107
            {
108
               return null;
109
            }
110
            
111
            if (spec.length !== 7)
112
            {
113
               return null;
114
            }
115
            
116
            if (spec.charAt(0) !== "#")
117
            {
118
               return null;
119
            }
120
            
121
            var r = parseInt(spec.substr(1, 2), 16);
122
            var g = parseInt(spec.substr(3, 2), 16);
123
            var b = parseInt(spec.substr(5, 2), 16);
124
         
125
            if (r === NaN || g === NaN || b === NaN)
126
            {
127
               return null;
128
            }
129
            
130
            return [ r, g, b ];
131
         }
132
         
133
         function validateColor(color)
134
         {
135
            if (!(color instanceof Array))
136
            {
137
               return false;
138
            }
139
            
140
            if (color.length !== 3)
141
            {
142
               return false;
143
            }
144
            
145
            if (typeof color[0] !== "number" ||
146
                typeof color[1] !== "number" ||
147
                typeof color[2] !== "number")
148
            {
149
               return false;
150
            }
151
            
152
            if (color[0] < 0 || color[0] > 255 ||
153
                color[1] < 0 || color[1] > 255 ||
154
                color[2] < 0 || color[2] > 255)
155
            {
156
               return false;
157
            }
158
            
159
            return true;
160
         }
161
         
162
         function createColorString(color)
163
         {
164
            if (!validateColor(color))
165
            {
166
               return null;
167
            }
168
            
169
            return "rgb(" + color[0].toString() + ", "
170
                          + color[1].toString() + ", "
171
                          + color[2].toString() + ")";
172
         }
173
         
174
         function setColor(ctx, color)
175
         {
176
            var colorSpec;
177
         
178
            if (color instanceof Array)
179
            {
180
               if (validateColor(color))
181
               {
182
                  colorSpec = createColorString(color);     
183
               }
184
               else
185
               {
186
                  // error
187
               }
188
            }
189
            else
190
            {
191
               if (typeof color === "string")
192
               {
193
                  colorSpec = color;
194
               }
195
               else
196
               {
197
                  // error
198
               }
199
            }
200
            
201
            ctx.fillStyle   = colorSpec;
202
            ctx.strokeStyle = colorSpec;
203
         }
204
         
205
         var SCALE_FACTOR = 0.7;
206
         var MIN_COLOR_VALUE = Math.floor(1.0 / (1.0 - SCALE_FACTOR));
207
         
208
         function lightenColor(color)
209
         {
210
            if (!validateColor(color))
211
            {
212
               return null;
213
            }
214
            
215
            // handle black directly, the result is NOT very much different but this is how it is
216
            // done in Java
217
            if (color[0] == 0 && color[1] == 0 && color[2] == 0)
218
               return [ MIN_COLOR_VALUE, MIN_COLOR_VALUE, MIN_COLOR_VALUE ];
219
            
220
            // force inputs to a minimim color value if between 0 and that minimum color value
221
            // (yes, this is how Java does it)
222
            var rIn = (color[0] > 0 && color[0] < MIN_COLOR_VALUE) ? MIN_COLOR_VALUE : color[0];
223
            var gIn = (color[1] > 0 && color[1] < MIN_COLOR_VALUE) ? MIN_COLOR_VALUE : color[1];
224
            var bIn = (color[2] > 0 && color[2] < MIN_COLOR_VALUE) ? MIN_COLOR_VALUE : color[2];
225
            
226
            // scale it
227
            var r = Math.min(Math.floor(rIn / SCALE_FACTOR), 255);
228
            var g = Math.min(Math.floor(gIn / SCALE_FACTOR), 255);
229
            var b = Math.min(Math.floor(bIn / SCALE_FACTOR), 255);
230
            
231
            return [ r, g, b ];
232
         }
233
         
234
         function darkenColor(color)
235
         {
236
            if (!validateColor(color))
237
            {
238
               return null;
239
            }
240
            
241
            var r = Math.max(0, Math.floor(color[0] * SCALE_FACTOR));
242
            var g = Math.max(0, Math.floor(color[1] * SCALE_FACTOR));
243
            var b = Math.max(0, Math.floor(color[2] * SCALE_FACTOR));
244
            
245
            return [ r, g, b ];
246
         }
247
         
248
         function create3DRect(ctx, x, y, width, height, fill, raised)
249
         {
250
            // save off our colors
251
            var oriFillColor   = ctx.fillStyle;
252
            var oriStrokeColor = ctx.strokeStyle;
253
            
254
            // both colors should always be assigned the same value on entry to any drawing op
255
            // so it should be safe to use just the fill color
256
            var color = parseColor(oriFillColor);
257
            
258
            if (color === null)
259
            {
260
               return;
261
            }
262
            
263
            var darker  = darkenColor(color);
264
            var lighter = lightenColor(color);
265
            
266
            // save off our state so that we can clear our clipping region on exit
267
            ctx.save();
268
            
269
            // the Java implementation draws 1 pixel larger in each dimension
270
            width  = width + 1;
271
            height = height + 1;
272
            
273
            // setup our clipping region, this is needed because the line width (1 pixel wide) is
274
            // drawn half on one side of hte path and half on the other side; this makes paths a
275
            // half pixel bigger than the caller would expect; by defining the same path as a
276
            // clipping region, the half pixel width that is outside the path is never output
277
            ctx.beginPath();
278
            ctx.rect(x, y, width, height);
279
            ctx.clip();
280
            
281
            // now begin a new path for the rectangle itself
282
            ctx.beginPath();
283
            
284
            // create the path
285
            ctx.rect(x, y, width, height);
286
            
287
            // set the color and fill or stroke as needed
288
            if (fill)                                       
289
            {
290
               ctx.fillStyle = createColorString(raised ? lighter : darker);
291
               ctx.fill();
292
            }
293
            else
294
            {
295
               ctx.strokeStyle = createColorString(raised ? lighter : darker);
296
               ctx.stroke();
297
            }
298
            
299
            // draw the bottom and right sides in the contrasting color
300
            ctx.strokeStyle = createColorString(raised ? darker : lighter);
301
            drawLine(x + 1, y + height, x + width, y + height);
302
            drawLine(x + width, y, x + width, y + height - 1);
303
            
304
            // clear the clipping region
305
            ctx.restore();
306
            
307
            // reset our colors
308
            ctx.fillStyle   = oriFillColor;
309
            ctx.strokeStyle = oriStrokeColor;
310
         }                         
311
         
312
         function createRect(ctx, x, y, width, height, fill)
313
         {
314
            ctx.beginPath();
315
            ctx.rect(x, y, width, height);
316
            renderClosedPath(ctx, fill);
317
         }                         
318
         
319
         window.onload=function()
320
         {
321
            canvas = document.getElementById("bogus");
322
            ctx = canvas.getContext('2d');
323
            
324
            canvas.top = 150;
325
            canvas.left = 150;
326
            canvas.width = 600;
327
            canvas.height = 600;
328
            
329
            ctx.lineWidth = 1;
330
            drawLine(10, 10, 590, 30);
331
         
332
            createRect(ctx, 40, 40, 55, 30, false);
333
            createRect(ctx, 150, 40, 55, 30, true);
334
            
335
            createRoundRect(ctx, 40, 90, 55, 30, 5, false);
336
            createRoundRect(ctx, 40, 130, 55, 30, 5, true);
337
            createRoundRect(ctx, 110, 90, 55, 30, 8, false);
338
            createRoundRect(ctx, 110, 130, 55, 30, 8, true);
339
            createRoundRect(ctx, 180, 90, 55, 30, 10, false);
340
            createRoundRect(ctx, 180, 130, 55, 30, 10, true);
341
            createRoundRect(ctx, 250, 90, 55, 30, 15, false);
342
            createRoundRect(ctx, 250, 130, 55, 30, 15, true);
343
            createRoundRect(ctx, 320, 90, 55, 30, 20, false);
344
            createRoundRect(ctx, 320, 130, 55, 30, 20, true);
345
            createRoundRect(ctx, 390, 90, 55, 30, 25, false);
346
            createRoundRect(ctx, 390, 130, 55, 30, 25, true);
347
            createRoundRect(ctx, 460, 90, 55, 30, 30, false);
348
            createRoundRect(ctx, 460, 130, 55, 30, 30, true);
349
            
350
            setColor(ctx, "#00FF00");
351
            create3DRect(ctx, 40, 175, 75, 30, false, true);
352
            create3DRect(ctx, 130, 175, 150, 60, false, true);
353
            create3DRect(ctx, 295, 175, 75, 30, true, true);
354
            create3DRect(ctx, 395, 175, 150, 60, true, true);
355
            create3DRect(ctx, 40, 250, 75, 30, false, false);
356
            create3DRect(ctx, 130, 250, 150, 60, false, false);
357
            create3DRect(ctx, 295, 250, 75, 30, true, false);
358
            create3DRect(ctx, 395, 250, 150, 60, true, false);
359
            setColor(ctx, "#000000");
360
            create3DRect(ctx, 40, 325, 75, 30, false, false);
361
            create3DRect(ctx, 130, 325, 150, 60, false, false);
362
            create3DRect(ctx, 295, 325, 75, 30, true, false);
363
            create3DRect(ctx, 395, 325, 150, 60, true, false);
364
         };
365
      </script>
366
   </head>
367
   <body>
368
      <canvas id="bogus" style="position:'absolute';background-color:#EEEEEE">No HTML5 support in your browser!</canvas>
369
   </body>
370
</html>