1 /* 2 * © 2009 ROBO Design 3 * http://www.robodesign.ro 4 * 5 * $Date: 2009-04-21 14:30:39 +0300 $ 6 */ 7 8 /** 9 * @author <a lang="ro" href="http://www.robodesign.ro/mihai">Mihai Şucan</a> 10 * @fileOverview The paint application core code. 11 */ 12 13 /** 14 * @class The paint tool application object. 15 */ 16 function Painter () { 17 var _self = this; 18 19 /** 20 * Holds the buffer canvas and context references. 21 * @type Object 22 */ 23 this.buffer = {canvas: null, context: null}; 24 25 /** 26 * Holds the current layer ID, canvas and context references. 27 * @type Object 28 */ 29 this.layer = {id: null, canvas: null, context: null}; 30 31 /** 32 * The instance of the active tool object. 33 * 34 * @type Object 35 * @see PainterConfig.tool_default holds the ID of the tool which is activated 36 * when the application loads. 37 */ 38 this.tool = null; 39 40 /** 41 * Holds references to important DOM elements. 42 * 43 * @private 44 * @type Object 45 */ 46 this.elems = {}; 47 48 /** 49 * Holds the keyboard event listener object. 50 * 51 * @private 52 * @type lib.dom.KeyboardEventListener 53 * @see lib.dom.KeyboardEventListener The class dealing with the cross-browser 54 * differences in the DOM keyboard events. 55 */ 56 var kbListener_; 57 58 /** 59 * Initialize the paint application. 60 * @private 61 */ 62 function init () { 63 if (!window.lang) { 64 alert('Error: The language object is not available!'); 65 return; 66 } 67 68 if (!window.PaintTools) { 69 alert(lang.PaintToolsNotFound); 70 return; 71 } 72 73 if (!window.PainterConfig) { 74 alert(lang.PainterConfigNotFound); 75 return; 76 } 77 78 // This application does not yet implement layers support. 79 // However, there's only little additional work to be done for layers 80 // support. 81 _self.layer.id = 1; 82 83 // Find the canvas element. 84 _self.layer.canvas = document.getElementById('imageLayer'); 85 if (!_self.layer.canvas) { 86 alert(lang.errorCanvasNotFound); 87 return; 88 } 89 90 if (!_self.layer.canvas.getContext) { 91 alert(lang.errorGetContext); 92 return; 93 } 94 95 // Get the 2D canvas context. 96 _self.layer.context = _self.layer.canvas.getContext('2d'); 97 if (!_self.layer.context) { 98 alert(lang.errorGetContext); 99 return; 100 } 101 102 // Add the buffer canvas. 103 var container = _self.layer.canvas.parentNode; 104 _self.buffer.canvas = document.createElement('canvas'); 105 if (!_self.buffer.canvas) { 106 alert(lang.errorCanvasCreate); 107 return; 108 } 109 110 _self.buffer.canvas.id = 'imageBuffer'; 111 _self.buffer.canvas.width = _self.layer.canvas.width; 112 _self.buffer.canvas.height = _self.layer.canvas.height; 113 container.appendChild(_self.buffer.canvas); 114 115 _self.buffer.context = _self.buffer.canvas.getContext('2d'); 116 117 // Get the tools drop-down. 118 _self.elems.tool_select = document.getElementById('tool'); 119 if (!_self.elems.tool_select) { 120 alert(lang.errorToolSelect); 121 return; 122 } 123 _self.elems.tool_select.addEventListener('change', ev_tool_change, false); 124 125 // Activate the default tool. 126 _self.toolActivate(PainterConfig.tool_default); 127 128 // Attach the mousedown, mousemove and mouseup event listeners. 129 _self.buffer.canvas.addEventListener('mousedown', ev_canvas, false); 130 _self.buffer.canvas.addEventListener('mousemove', ev_canvas, false); 131 _self.buffer.canvas.addEventListener('mouseup', ev_canvas, false); 132 133 // Add the keydown event listener. 134 kbListener_ = new lib.dom.KeyboardEventListener(window, 135 {keydown: ev_keydown}); 136 }; 137 138 /** 139 * The Canvas event handler. 140 * 141 * <p>This method determines the mouse position relative to the canvas 142 * element, after which it invokes the method of the currently active tool 143 * with the same name as the current event type. For example, for the 144 * <code>mousedown</code> event the <code><var>tool</var>.mousedown()</code> 145 * method is invoked. 146 * 147 * <p>The mouse coordinates are added to the <var>ev</var> DOM Event object: 148 * <var>ev.x_</var> and <var>ev.y_</var>. 149 * 150 * @private 151 * @param {Event} ev The DOM Event object. 152 */ 153 function ev_canvas (ev) { 154 if (typeof ev.layerX != 'undefined') { // Firefox 155 ev.x_ = ev.layerX; 156 ev.y_ = ev.layerY; 157 } else if (typeof ev.offsetX != 'undefined') { // Opera 158 ev.x_ = ev.offsetX; 159 ev.y_ = ev.offsetY; 160 } 161 162 // Call the event handler of the active tool. 163 var func = _self.tool[ev.type]; 164 if (typeof func == 'function') { 165 func(ev); 166 } 167 }; 168 169 /** 170 * The event handler for any changes made to the tool selector. 171 * 172 * @private 173 * @see Painter#toolActivate The method which does the actual drawing tool 174 * activation. 175 */ 176 function ev_tool_change () { 177 _self.toolActivate(this.value); 178 }; 179 180 /** 181 * Activate a drawing tool by ID. 182 * 183 * <p>The <var>id</var> provided must be available in the global {@link 184 * PaintTools} object. 185 * 186 * @param {String} id The ID of the drawing tool to be activated. 187 * 188 * @returns {Boolean} True if the tool has been activated, or false if not. 189 * 190 * @see PaintTools The object holding all the drawing tools. 191 */ 192 this.toolActivate = function (id) { 193 if (!id) { 194 return false; 195 } 196 197 // Find the tool object. 198 var tool = PaintTools[id]; 199 if (!tool) { 200 return false; 201 } 202 203 // Check if the current tool is the same as the desired one. 204 if (_self.tool && _self.tool instanceof tool) { 205 return true; 206 } 207 208 // Construct the new tool object. 209 var tool_obj = new tool(_self); 210 if (!tool_obj) { 211 alert(lang.errorToolActivate); 212 return false; 213 } 214 215 _self.tool = tool_obj; 216 217 // Update the tool drop-down. 218 _self.elems.tool_select.value = id; 219 220 return true; 221 }; 222 223 /** 224 * The global <code>keydown</code> event handler. This makes all the keyboard 225 * shortcuts work in the web application. 226 * 227 * <p>This method determines the key the user pressed, based on the 228 * <var>ev</var> DOM Event object, taking into consideration any browser 229 * differences. 230 * 231 * <p>In {@link PainterConfig.keys} one can setup the keyboard shortcuts. If 232 * the keyboard combination is found in that list, then the associated tool is 233 * activated. 234 * 235 * @private 236 * 237 * @param {Event} ev The DOM Event object. 238 * 239 * @see PainterConfig.keys The keyboard shortcuts configuration. 240 * @see lib.dom.KeyboardEventListener The class dealing with the cross-browser 241 * differences in the DOM keyboard events. 242 */ 243 function ev_keydown (ev) { 244 if (!ev || !ev.key_) { 245 return; 246 } 247 248 // Do not continue if the event target is some form input. 249 if (ev.target && ev.target.nodeName) { 250 switch (ev.target.nodeName.toLowerCase()) { 251 case 'input': 252 case 'select': 253 return; 254 } 255 } 256 257 // Determine the key ID. 258 var i, kid = '', 259 kmods = {altKey: 'Alt', ctrlKey: 'Control', shiftKey: 'Shift'}; 260 for (i in kmods) { 261 if (ev[i] && ev.key_ != kmods[i]) { 262 kid += kmods[i] + ' '; 263 } 264 } 265 kid += ev.key_; 266 267 // If there's no event handler within the active tool, or if the event 268 // handler does otherwise return false, then continue with the global 269 // keyboard shortcuts. 270 271 var gkey = PainterConfig.keys[kid]; 272 if (!gkey) { 273 return; 274 } 275 276 // Activate the tool associated with the current keyboard shortcut. 277 if (gkey.tool) { 278 _self.toolActivate(gkey.tool); 279 } 280 281 if (ev.preventDefault) { 282 ev.preventDefault(); 283 } 284 }; 285 286 /** 287 * This method draws the buffer canvas on top of the current image layer, 288 * after which the buffer is cleared. This function is called each time when 289 * the user completes a drawing operation. 290 */ 291 this.layerUpdate = function () { 292 _self.layer.context.drawImage(_self.buffer.canvas, 0, 0); 293 _self.buffer.context.clearRect(0, 0, _self.buffer.canvas.width, _self.buffer.canvas.height); 294 }; 295 296 init(); 297 }; 298 299 if(window.addEventListener) { 300 window.addEventListener('load', function () { 301 if (window.Painter) { 302 // Create a Painter object instance. 303 window.PainterInstance = new Painter(); 304 } 305 }, false); } 306 307 // vim:set spell spl=en fo=wan1croql tw=80 ts=2 sw=2 sts=2 sta et ai cin fenc=utf-8 ff=unix: 308