1 /*      Name: Graphics Module
  2         Date: April 2011
  3         Description: Main module for the UniPlay graphics (2D/Sprite) functionality
  4         Dependencies: <none>
  5         Children: <none> */
  6 
  7 /*      Sprite object
  8         Properies: visible, path, origWidth, origHeight, 
  9                    scaleWidth, scaleHeight, angle, alpha
 10         Methods: load, draw, show, hide, scale */
 11 
 12 /**
 13  * Creates an instance of a Sprite
 14  *
 15  * @constructor
 16  * @this {Sprite}
 17  * @param {String} path Path to sprite image file.
 18  * @see graphics.js
 19  */
 20 function Sprite(path) {
 21 	/**
 22 	* Path to sprite image file.
 23 	*
 24 	* @type String
 25 	*/
 26 	this.path = path;
 27 	
 28 	/**
 29 	* Image array for animated sprites.
 30 	*
 31 	* @type Array
 32 	*/
 33 	this.image = [];
 34 	
 35 	/**
 36 	* Sprite visible property.
 37 	*
 38 	* @type Boolean
 39 	*/
 40 	this.visible = true;
 41 	
 42 	/**
 43 	* Starting angle value for rotation.
 44 	*
 45 	* @type Number
 46 	*/
 47 	this.angle = null;
 48 	
 49 	/**
 50 	* Alpha transparency value.
 51 	*
 52 	* @type Number
 53 	*/
 54 	this.alpha = 1.0;
 55 	
 56 	/**
 57 	* Sprite image index.
 58 	*
 59 	* @type Number
 60 	*/
 61 	this.imageindex = 0;
 62 	
 63 	/**
 64 	* Number of sprites in current Sprite object.
 65 	*
 66 	* @type Number
 67 	*/
 68 	this.nsprites = 0;
 69 	
 70 	/**
 71 	* Current sprite X position.
 72 	*
 73 	* @type Number
 74 	*/
 75 	this.x = 0;
 76 	
 77 	/**
 78 	* Current sprite Y position.
 79 	*
 80 	* @type Number
 81 	*/
 82 	this.y = 0;
 83 	
 84 	
 85 	/**
 86 	 * Load sprite image file from the path given in {@link #path}.
 87 	 *
 88 	 * @this {Sprite}
 89 	 */
 90 	this.load = function() {
 91 		this.image[0] = new Image();
 92 		this.image[0].src = this.path;
 93 		
 94 		this.origWidth = this.image[0].width;
 95 		this.origHeight = this.image[0].height;
 96 		
 97 		this.scaleWidth = this.origWidth;
 98 		this.scaleHeight = this.origHeight;
 99 		
100 		this.nsprites++;
101 	};
102 	
103 	/** Load in sprite on instantiation */
104 	this.load();
105 	
106 	/**
107 	 * Add a sprite to the sprite {@link #image} Array.
108 	 * <i>Used to create animated sprites.</i>
109 	 * @param {String} path Path to sprite image file.
110 	 * @this {Sprite}
111 	 */
112 	this.add = function(path) {
113 		this.image[this.nsprites] = new Image();
114 		this.image[this.nsprites].src = path;
115 		this.nsprites++;
116 	};
117 	
118 	/**
119 	 * Cycle through sprites in {@link #image} Array.
120 	 * <i>Used to play animated sprites.</i>
121 	 * @this {Sprite}
122 	 */
123 	this.cycle = function() {
124 		this.imageindex++;
125 		
126 		if (this.imageindex === this.nsprites){
127 			this.imageindex = 0;
128 		}
129 	};
130 	
131 	/**
132 	 * Set a sprites current image.
133 	 * <i>Used to set animated sprite image.</i>
134 	 * @param {Number} i Index of image in {@link #image} Array.
135 	 * @this {Sprite}
136 	 */
137 	this.setSpriteIndex = function(i){
138 		this.imageindex = i;
139 	};
140 	
141 	/**
142 	 * Draw sprite on Canvas 2D context.
143 	 *
144 	 * @param {[object CanvasRenderingContext2D]} ctx Canvas 2D context to draw onto.
145 	 * @this {Sprite}
146 	 */
147 	this.draw = function(ctx){
148 		if (ctx){
149 			if (ctx.drawImage){
150 				if (this.visible === true){
151 					var previousAlpha = ctx.globalAlpha;
152 					ctx.globalAlpha = this.alpha;
153 			
154 					if (this.angle != null){
155 						ctx.save();
156 						ctx.translate(this.x+(this.scaleWidth/2),this.y+(this.scaleHeight/2));
157 						ctx.rotate(this.angle);
158 						ctx.translate(-this.x-(this.scaleWidth/2),-this.y-(this.scaleHeight/2));
159 					}
160  
161 					ctx.drawImage(this.image[this.imageindex],this.x,this.y,this.scaleWidth,this.scaleHeight);
162 					
163 					if (this.angle != null){
164 						ctx.restore();
165 					}
166 					
167 					ctx.globalAlpha = previousAlpha;
168 				}
169 			}
170 		}
171 	};
172 	
173 	/**
174 	 * Set sprite to be visible when drawing.
175 	 *
176 	 * @this {Sprite}
177 	 */
178 	this.show = function(){
179 		this.visible = true;
180 	};
181 	
182 	/**
183 	 * Set sprite to be invisible when drawing.
184 	 *
185 	 * @this {Sprite}
186 	 */
187 	this.hide = function(){
188 		this.visible = false; 
189 	};
190 	
191 	/**
192 	 * Scale sprite when drawing by width and height.
193 	 *
194 	 * @param {Number} width Width to scale sprite by.
195 	 * @param {Number} height Height to scale sprite by.
196 	 * @this {Sprite}
197 	 */
198 	this.scale = function(width,height){
199 		this.scaleWidth = width;
200 		this.scaleHeight = height;
201 	};
202 	
203 	/**
204 	 * Rotate sprite when drawing.
205 	 *
206 	 * @param {Number} angle Angle of rotation in degrees.
207 	 * @this {Sprite}
208 	 */
209 	this.rotate = function(angle) {
210 		this.angle = angle*(Math.PI/180);
211 	};
212 	
213 	/**
214 	 * Set alpha transparency of sprite.
215 	 *
216 	 * @param {Number} value Transparency value from 0.0 to 1.0
217 	 * @this {Sprite}
218 	 */
219 	this.transparency = function(value){
220 		this.alpha = value;
221 	};
222 	
223 	/**
224 	 * Set sprite position using cartesian coordinates.
225 	 *
226 	 * @param {Number} x Set sprite X axis position.
227 	 * @param {Number} y Set sprite Y axis position.
228 	 * @this {Sprite}
229 	 */
230 	this.setPosition = function(x,y){
231 		this.x = x;
232 		this.y = y;
233 	};
234 
235 	/**
236 	 * Return visible property stored in {@link #visible}.
237 	 * @return {Boolean} Boolean denoting visible property.
238 	 * @this {Sprite}
239 	 */
240 	this.getVisible = function(){
241 		return this.visible;
242 	};
243 	
244 	/**
245 	 * Return angle of sprite value stored in {@link #angle}.
246 	 * @return {Number} Number denoting angle of sprite.
247 	 * @this {Sprite}
248 	 */
249 	this.getAngle = function(){
250 		return this.angle;
251 	};
252 	
253 	/**
254 	 * Return alpha transparency value stored in {@link #alpha}.
255 	 * @return {Number} Number denoting alpha transparency value.
256 	 * @this {Sprite}
257 	 */
258 	this.getTransparency = function(){
259 		return this.alpha;
260 	};
261 	
262 	/**
263 	 * Return sprite image index value stored in {@link #imageindex}.
264 	 * @return {Number} Number denoting image index value.
265 	 * @this {Sprite}
266 	 */
267 	this.getImageIndex = function(){
268 		return this.imageindex;
269 	};
270 	
271 	/**
272 	 * Return number of sprites value stored in {@link #nsprites}.
273 	 * @return {Number} Number denoting number of sprites value.
274 	 * @this {Sprite}
275 	 */
276 	this.getNumSprites = function(){
277 		return this.nsprites;
278 	};
279 	
280 	/**
281 	 * Return sprite x axis cartesian co-ordinate value stored in {@link #x}.
282 	 * @return {Number} Number denoting sprite x axis cartesian co-ordinate value.
283 	 * @this {Sprite}
284 	 */
285 	this.getX = function(){
286 		return this.x;
287 	};
288 	
289 	/**
290 	 * Return sprite y axis cartesian co-ordinate value stored in {@link #y}.
291 	 * @return {Number} Number denoting sprite y axis cartesian co-ordinate value.
292 	 * @this {Sprite}
293 	 */
294 	this.getY = function(){
295 		return this.y;
296 	};
297 }
298 
299 /**
300  * Creates an instance of the Drawing object
301  *
302  * @constructor
303  * @this {Drawing}
304  * @see graphics.js
305  */
306  
307 function Drawing() {
308 	/**
309 	* RGB line colour property.
310 	*
311 	* @type Number
312 	*/
313 	this.rgbLine = "rgb(255,255,255)";
314 	
315 	/**
316 	* Line red colour property.
317 	*
318 	* @type Number
319 	*/
320 	this.lineR = 255;
321 	
322 	/**
323 	* Line green colour property.
324 	*
325 	* @type Number
326 	*/
327 	this.lineG = 255;
328 	
329 	/**
330 	* Line blue colour property.
331 	*
332 	* @type Number
333 	*/
334 	this.lineB = 255;
335 	
336 	/**
337 	* RGB fill colour property.
338 	*
339 	* @type Number
340 	*/
341 	this.rgbFill = "rgb(255,255,255)";
342 	
343 	/**
344 	* Fill red colour property.
345 	*
346 	* @type Number
347 	*/
348 	this.fillR = 255;
349 	
350 	/**
351 	* Fill green colour property.
352 	*
353 	* @type Number
354 	*/
355 	this.fillG = 255;
356 	
357 	/**
358 	* Fill blue colour property.
359 	*
360 	* @type Number
361 	*/
362 	this.fillB = 255;
363 	
364 	/**
365 	* Current font face property. e.g "Verdana"
366 	*
367 	* @type String
368 	*/
369 	this.currentFont = "";
370 	
371 	/**
372 	* Current font size property. e.g. 14
373 	*
374 	* @type Number
375 	*/
376 	this.fontSize = 0;
377 	
378 	/**
379 	* Current font style property. e.g. "bold"
380 	*
381 	* @type String
382 	*/
383 	this.fontStyle = "";
384 	
385 	/**
386 	* Previous RGB fill style.
387 	*
388 	* @type String
389 	*/
390 	this.prevFillRGB = "";
391 	
392 	/**
393 	* Drawing transparency (alpha) value.
394 	*
395 	* @type Number
396 	*/
397 	this.alpha = 1.0;
398 	
399 	/**
400 	 * Text drawing function.
401 	 * <i>Note: uses all font property values to draw text.</i>
402 	 * @param {[object CanvasRenderingContext2D]} ctx Canvas drawing context.
403 	 * @param {String} string String for text to draw.
404 	 * @param {Number} x X axis coordinate to draw text at.
405 	 * @param {Number} y Y axis coordinate to draw text at.
406 	 * @this {Drawing}
407 	 */
408 	this.text = function(ctx,string,x,y) {
409 		if (ctx){
410 				var previousAlpha = ctx.globalAlpha;
411 				ctx.globalAlpha = this.alpha;
412 		
413 				this.prevFillRGB = ctx.fillStyle;
414 			
415 				ctx.fillStyle = this.rgbFill;
416 				ctx.font = this.fontStyle + " " + this.fontSize + "px " + this.currentFont;
417 				ctx.fillText(string, x, y);
418 				
419 				ctx.fillStyle = this.prevFillRGB;
420 				
421 				ctx.globalAlpha = previousAlpha;
422 		}
423 	};
424 	
425 	/**
426 	 * Set the font face. e.g "Verdana"
427 	 * 
428 	 * @param {String} string String denoting font face.
429 	 * @this {Drawing}
430 	 */
431 	this.setFontFace = function(string) {
432 		this.currentFont = string;
433 	};
434 	
435 	/**
436 	 * Set the font size. e.g. 11
437 	 * 
438 	 * @param {Number} integer Number denoting font size.
439 	 * @this {Drawing}
440 	 */
441 	this.setFontSize = function(number) {
442 		this.fontSize = number;
443 	};
444 
445 	/**
446 	 * Set the font style. e.g. "bold"
447 	 * 
448 	 * @param {String} string String denoting font style.
449 	 * @this {Drawing}
450 	 */
451 	this.setFontStyle = function(string) {
452 		this.fontStyle = string;
453 	};		
454 	
455 	/**
456 	 * Pixel drawing function.
457 	 * 
458 	 * @param {[object CanvasRenderingContext2D]} ctx Canvas 2D rendering context.
459 	 * @param {ImageData} id Image data object.
460 	 * @param {ImageData.data} pix ImageData.data object.
461 	 * @param {Number} x X axis coordinate to draw pixel at.
462 	 * @param {Number} y Y axis coordinate to draw pixel at.
463 	 * @this {Drawing}
464 	 */
465 	this.pixel = function(ctx,id,pix,x,y) {
466 		if (ctx){
467 			var previousAlpha = ctx.globalAlpha;
468 			ctx.globalAlpha = this.alpha;
469 			
470 			pix[0] = this.fillR;
471 			pix[1] = this.fillG;
472 			pix[2] = this.fillB;
473 			pix[3] = 255;
474 			ctx.putImageData(id,x,y);
475 			
476 			ctx.globalAlpha = previousAlpha;
477 		}
478 	};
479 	
480 	/**
481 	 * Line drawing function.
482 	 * 
483 	 * @param {[object CanvasRenderingContext2D]} ctx Canvas 2D rendering context.
484 	 * @param {Number} x1 X1 axis coordinate to start line at.
485 	 * @param {Number} y1 Y1 axis coordinate to start line at.
486 	 * @param {Number} x2 X2 axis coordinate to end line at.
487 	 * @param {Number} y2 Y2 axis coordinate to end line at.
488 	 * @this {Drawing}
489 	 */
490 	this.line = function(ctx,x1,y1,x2,y2) {
491 		if (ctx){
492 			var previousAlpha = ctx.globalAlpha;
493 			ctx.globalAlpha = this.alpha;
494 				
495 			ctx.strokeStyle = this.rgbLine;
496 			ctx.beginPath();
497 			ctx.moveTo(x1,y1);
498 			ctx.lineTo(x2,y2);
499 			ctx.closePath();
500 			ctx.stroke();
501 			
502 			ctx.globalAlpha = previousAlpha;
503 		}
504 	};
505 	
506 	/**
507 	 * Box (rectangle) drawing function.
508 	 * 
509 	 * @param {[object CanvasRenderingContext2D]} ctx Canvas 2D rendering context.
510 	 * @param {Number} x X axis coordinate to start box drawing at.
511 	 * @param {Number} y Y axis coordinate to start box drawing at.
512 	 * @param {Number} width Width of box.
513 	 * @param {Number} height Height of box.
514 	 * @param {Boolean} fill Boolean denoting if the box should be filled or empty.
515 	 * @this {Drawing}
516 	 */
517 	this.box = function(ctx,x,y,width,height,fill) {
518 		if (ctx){
519 			var previousAlpha = ctx.globalAlpha;
520 			ctx.globalAlpha = this.alpha;
521 		
522 			if (fill){
523 				ctx.fillStyle = this.rgbFill;
524 				ctx.fillRect(x,y,width,height);
525 			} else {
526 				ctx.strokeRect(x,y,width,height);
527 			}
528 			
529 			ctx.globalAlpha = previousAlpha;
530 		}
531 	};
532 	
533 	/**
534 	 * Circle drawing function.
535 	 * 
536 	 * @param {[object CanvasRenderingContext2D]} ctx Canvas 2D rendering context.
537 	 * @param {Number} x X axis coordinate to start circle drawing at.
538 	 * @param {Number} y Y axis coordinate to start circle drawing at.
539 	 * @param {Number} radius Radius of circle.
540 	 * @param {Boolean} fill Boolean denoting if the circle should be filled or empty.
541 	 * @this {Drawing}
542 	 */
543 	this.circle = function(ctx,x,y,radius,fill) {
544 		if (ctx){
545 			var previousAlpha = ctx.globalAlpha;
546 			ctx.globalAlpha = this.alpha;
547 		
548 			ctx.fillStyle = this.rgbFill;
549 			ctx.strokeStyle = this.rgbLine;
550 			ctx.save();
551 			ctx.beginPath();
552 			ctx.arc(x, y, radius, 0, Math.PI*2, true);
553 			ctx.closePath();
554 			ctx.restore();
555 			if (fill){
556 				ctx.fill();
557 			} else {
558 				ctx.stroke();
559 			}
560 			ctx.restore();
561 			
562 			ctx.globalAlpha = previousAlpha;
563 		}
564 	};
565 	
566 	
567 	/**
568 	 * Ellipse drawing function.
569 	 * 
570 	 * @param {[object CanvasRenderingContext2D]} ctx Canvas 2D rendering context.
571 	 * @param {Number} x X axis coordinate to start ellipse drawing at.
572 	 * @param {Number} y Y axis coordinate to start ellipse drawing at.
573 	 * @param {Number} radiusx X axis radius of ellipse.
574 	 * @param {Number} radiusy Y axis radius of ellipse.
575 	 * @param {Boolean} fill Boolean denoting if the ellipse should be filled or empty.
576 	 * @this {Drawing}
577 	 */
578 	this.ellipse = function(ctx,x,y,radiusx,radiusy,fill) {
579 		if (ctx){
580 			var previousAlpha = ctx.globalAlpha;
581 			ctx.globalAlpha = this.alpha;
582 		
583 			ctx.save();
584 			ctx.save();
585 			ctx.beginPath();
586 			ctx.translate(x, y);
587 			ctx.scale(radiusx, radiusy);
588 			ctx.arc(0, 0, 1, 0, 2*Math.PI, false);
589 			ctx.closePath();
590 			ctx.restore();
591 			if (fill)
592 				ctx.fill();
593 			ctx.stroke();
594 			ctx.restore();
595 			
596 			ctx.globalAlpha = previousAlpha;
597 		}
598 	};
599 	
600 	/**
601 	 * Set RGB line colour.
602 	 * 
603 	 * @param {[object CanvasRenderingContext2D]} ctx Canvas 2D rendering context.
604 	 * @param {Number} r Red line colour value.
605 	 * @param {Number} g Green line colour value.
606 	 * @param {Number} b Blue line colour value.
607 	 * @this {Drawing}
608 	 */
609 	this.setRGBLine = function(ctx,r,g,b) {
610 		if (ctx){
611 			this.rgbLine = "rgb(" + r + "," + g + "," + b + ")";
612 			this.lineR = r;
613 			this.lineG = g;
614 			this.lineB = b;
615 		}
616 	};
617 	
618 	/**
619 	 * Set RGB fill colour.
620 	 * 
621 	 * @param {[object CanvasRenderingContext2D]} ctx Canvas 2D rendering context.
622 	 * @param {Number} r Red fill colour value.
623 	 * @param {Number} g Green fill colour value.
624 	 * @param {Number} b Blue fill colour value.
625 	 * @this {Drawing}
626 	 */
627 	this.setRGBFill = function(ctx,r,g,b) {
628 		if (ctx){
629 			this.rgbFill = "rgb(" + r + "," + g + "," + b + ")";
630 			this.fillR = r;
631 			this.fillG = g;
632 			this.fillB = b;
633 		}
634 	};
635 	
636 	/**
637 	 * Clear the Canvas drawing context.
638 	 * 
639 	 * @param {[object CanvasRenderingContext2D]} ctx Canvas 2D rendering context.
640 	 * @this {Drawing}
641 	 */
642 	this.cls = function(ctx) {
643 		if (ctx){
644 			ctx.strokeStyle = this.rgbFill;
645 			ctx.fillStyle = this.rgbFill;
646 			ctx.clearRect(0, 0, ctx.canvas.offsetWidth, ctx.canvas.offsetHeight);
647 		}
648 	};
649 	
650 	/**
651 	 * Set the drawing transparency (alpha) value.
652 	 * 
653 	 * @param {Number} value Transparency (alpha) value.
654 	 * @this {Drawing}
655 	 */
656 	this.transparency = function(value){
657 		this.alpha = value;
658 	};
659 	
660 	/**
661 	 * Return the RGB value of a pixel as a string.
662 	 * @return {String} String denoting pixel RGB value.
663 	 * @this {Drawing}
664 	 */
665 	this.getPixelRGB = function(ctx,x,y) {
666 		if (ctx){
667 			var getImgData = ctx.getImageData(x,y,1,1);
668 			return "rgb(" + getImgData.data[0] + "," + getImgData.data[1] + "," + getImgData.data[2] + ")";
669 		}
670 	};	
671 
672 	/**
673 	 * Return the RGB value of the line colour as a 3 element array.
674 	 * @return {Array} 3 element array with red, green and blue line colours.
675 	 * @this {Drawing}
676 	 */
677 	this.getRGBLine = function(){
678 		return [lineR,lineG,lineB];
679 	};
680 	
681 	/**
682 	 * Return the RGB value of the fill colour as a 3 element array.
683 	 * @return {Array} 3 element array with red, green and blue fill colours.
684 	 * @this {Drawing}
685 	 */
686 	this.getRGBFill = function(){
687 		return [fillR,fillG,fillB];
688 	};
689 	
690 	/**
691 	 * Return the current font face.
692 	 * @return {String} String denoting current font face.
693 	 * @this {Drawing}
694 	 */
695 	this.getCurrentFont = function(){
696 		return this.currentFont;
697 	};
698 	
699 	/**
700 	 * Return the current font size.
701 	 * @return {Number} Number denoting current font size.
702 	 * @this {Drawing}
703 	 */
704 	this.getFontSize = function(){
705 		return this.fontSize;
706 	};
707 	
708 	/**
709 	 * Return the current font style.
710 	 * @return {String} String denoting current font style.
711 	 * @this {Drawing}
712 	 */
713 	this.getFontStyle = function(){
714 		return this.fontStyle;
715 	};
716 	
717 	/**
718 	 * Return the current drawing transparency (alpha) value.
719 	 * @return {Number} Number denoting current drawing transparency (alpha) value.
720 	 * @this {Drawing}
721 	 */
722 	this.getTransparency = function(){
723 		return this.alpha;
724 	};
725 }