1 /* 2 Copyright 2008-2012 3 Matthias Ehmann, 4 Michael Gerhaeuser, 5 Carsten Miller, 6 Bianca Valentin, 7 Alfred Wassermann, 8 Peter Wilfahrt 9 10 This file is part of JSXGraph. 11 12 JSXGraph is free software: you can redistribute it and/or modify 13 it under the terms of the GNU Lesser General Public License as published by 14 the Free Software Foundation, either version 3 of the License, or 15 (at your option) any later version. 16 17 JSXGraph is distributed in the hope that it will be useful, 18 but WITHOUT ANY WARRANTY; without even the implied warranty of 19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20 GNU Lesser General Public License for more details. 21 22 You should have received a copy of the GNU Lesser General Public License 23 along with JSXGraph. If not, see <http://www.gnu.org/licenses/>. 24 */ 25 26 /** 27 * @fileoverview The JSXGraph object is defined in this file. JXG.JSXGraph controls all boards. 28 * It has methods to create, save, load and free boards. Additionally some helper functions are 29 * defined in this file directly in the JXG namespace. 30 * @version 0.83 31 */ 32 33 /** 34 * Constructs a new JSXGraph singleton object. 35 * @class The JXG.JSXGraph singleton stores all properties required 36 * to load, save, create and free a board. 37 */ 38 JXG.JSXGraph = { 39 40 /** 41 * The small gray version indicator in the top left corner of every JSXGraph board (if 42 * showCopyright is not set to false on board creation). 43 * @type String 44 */ 45 licenseText: 'JSXGraph v0.94 Copyright (C) see http://jsxgraph.org', 46 47 /** 48 * Associative array that keeps references to all boards. 49 * @type Object 50 */ 51 boards: {}, 52 53 /** 54 * Associative array that keeps track of all constructable elements registered 55 * via {@link JXG.JSXGraph.registerElement}. 56 * @type Object 57 */ 58 elements: {}, 59 60 /** 61 * Stores the renderer that is used to draw the boards. 62 * @type String 63 */ 64 rendererType: (function() { 65 var i, arr; 66 67 if (JXG.supportsSVG()) { 68 JXG.Options.renderer = 'svg'; 69 } else if (JXG.supportsVML()) { 70 JXG.Options.renderer = 'vml'; 71 // Ok, this is some real magic going on here. IE/VML always was so 72 // terribly slow, except in one place: Examples placed in a moodle course 73 // was almost as fast as in other browsers. So i grabbed all the css and 74 // js scripts from our moodle, added them to a jsxgraph example and it 75 // worked. next step was to strip all the css/js code which didn't affect 76 // the VML update speed. The following five lines are what was left after 77 // the last step and yes - it basically does nothing but reads two 78 // properties of document.body on every mouse move. why? we don't know. if 79 // you know, please let us know. 80 function MouseMove() { 81 document.body.scrollLeft; 82 document.body.scrollTop; 83 } 84 document.onmousemove = MouseMove; 85 } else { 86 JXG.Options.renderer = 'canvas'; 87 } 88 89 // Load the source files for the renderer 90 arr = JXG.rendererFiles[JXG.Options.renderer].split(','); 91 for (i = 0; i < arr.length; i++) ( function(include) { 92 JXG.require(JXG.requirePath + include + '.js'); 93 } )(arr[i]); 94 95 return JXG.Options.renderer; 96 })(), 97 98 /** 99 * Initialise a new board. 100 * @param {String} box Html-ID to the Html-element in which the board is painted. 101 * @returns {JXG.Board} Reference to the created board. 102 */ 103 initBoard: function (box, attributes) { 104 var renderer, 105 originX, originY, unitX, unitY, 106 w, h, dimensions, 107 bbox, 108 zoomfactor, zoomX, zoomY, 109 showCopyright, showNavi, 110 board, 111 wheelzoom, shiftpan; 112 113 dimensions = JXG.getDimensions(box); 114 115 // parse attributes 116 if (typeof attributes == 'undefined') { 117 attributes = {}; 118 } 119 120 if (typeof attributes["boundingbox"] != 'undefined') { 121 bbox = attributes["boundingbox"]; 122 w = parseInt(dimensions.width); 123 h = parseInt(dimensions.height); 124 125 if (attributes["keepaspectratio"]) { 126 /* 127 * If the boundingbox attribute is given and the ratio of height and width of the 128 * sides defined by the bounding box and the ratio of the dimensions of the div tag 129 * which contains the board do not coincide, then the smaller side is chosen. 130 */ 131 unitX = w/(bbox[2]-bbox[0]); 132 unitY = h/(-bbox[3]+bbox[1]); 133 if (Math.abs(unitX)<Math.abs(unitY)) { 134 unitY = Math.abs(unitX)*unitY/Math.abs(unitY); 135 } else { 136 unitX = Math.abs(unitY)*unitX/Math.abs(unitX); 137 } 138 } else { 139 unitX = w/(bbox[2]-bbox[0]); 140 unitY = h/(-bbox[3]+bbox[1]); 141 } 142 originX = -unitX*bbox[0]; 143 originY = unitY*bbox[1]; 144 } else { 145 originX = ( (typeof attributes["originX"]) == 'undefined' ? 150 : attributes["originX"]); 146 originY = ( (typeof attributes["originY"]) == 'undefined' ? 150 : attributes["originY"]); 147 unitX = ( (typeof attributes["unitX"]) == 'undefined' ? 50 : attributes["unitX"]); 148 unitY = ( (typeof attributes["unitY"]) == 'undefined' ? 50 : attributes["unitY"]); 149 } 150 151 zoomfactor = ( (typeof attributes["zoomfactor"]) == 'undefined' ? 1.0 : attributes["zoom"]); 152 zoomX = zoomfactor*( (typeof attributes["zoomX"]) == 'undefined' ? 1.0 : attributes["zoomX"]); 153 zoomY = zoomfactor*( (typeof attributes["zoomY"]) == 'undefined' ? 1.0 : attributes["zoomY"]); 154 155 showCopyright = ( (typeof attributes["showCopyright"]) == 'undefined' ? JXG.Options.showCopyright : attributes["showCopyright"]); 156 157 wheelzoom = ( (typeof attributes["zoom"]) == 'undefined' ? JXG.Options.zoom.wheel : attributes["zoom"]); 158 shiftpan = ( (typeof attributes["pan"]) == 'undefined' ? JXG.Options.pan : attributes["pan"]); 159 160 // create the renderer 161 if(JXG.Options.renderer == 'svg') { 162 renderer = new JXG.SVGRenderer(document.getElementById(box)); 163 } else if(JXG.Options.renderer == 'vml') { 164 renderer = new JXG.VMLRenderer(document.getElementById(box)); 165 } else if(JXG.Options.renderer == 'silverlight') { 166 renderer = new JXG.SilverlightRenderer(document.getElementById(box), dimensions.width, dimensions.height); 167 } else { 168 renderer = new JXG.CanvasRenderer(document.getElementById(box)); 169 } 170 171 // create the board 172 board = new JXG.Board(box, renderer, '', [originX, originY], zoomX, zoomY, unitX, unitY, dimensions.width, dimensions.height, showCopyright); 173 this.boards[board.id] = board; 174 175 board.keepaspectratio = attributes.keepaspectratio; 176 board.options.zoom.wheel = wheelzoom; 177 board.options.pan = shiftpan; 178 179 180 // create elements like axes, grid, navigation, ... 181 board.suspendUpdate(); 182 board.initInfobox(); 183 184 if(attributes["axis"]) { 185 board.defaultAxes = {}; 186 board.defaultAxes.x = board.create('axis', [[0,0], [1,0]], {ticks:{drawZero:true}}); 187 board.defaultAxes.y = board.create('axis', [[0,0], [0,1]], {ticks:{drawZero:board.options.axis.ticks.drawZero}}); 188 } 189 190 if(attributes["grid"]) { 191 board.create('grid', []); 192 } 193 194 if (typeof attributes["shownavigation"] != 'undefined') attributes["showNavigation"] = attributes["shownavigation"]; 195 showNavi = ( (typeof attributes["showNavigation"]) == 'undefined' ? board.options.showNavigation : attributes["showNavigation"]); 196 if (showNavi) { 197 board.renderer.drawZoomBar(board); 198 } 199 board.unsuspendUpdate(); 200 201 return board; 202 }, 203 204 /** 205 * Load a board from a file containing a construction made with either GEONExT, 206 * Intergeo, Geogebra, or Cinderella. 207 * @param {String} box HTML-ID to the HTML-element in which the board is painted. 208 * @param {String} file base64 encoded string. 209 * @param {String} format containing the file format: 'Geonext' or 'Intergeo'. 210 * @returns {JXG.Board} Reference to the created board. 211 * 212 * @see JXG.FileReader 213 * @see JXG.GeonextReader 214 * @see JXG.GeogebraReader 215 * @see JXG.IntergeoReader 216 * @see JXG.CinderellaReader 217 */ 218 loadBoardFromFile: function (box, file, format) { 219 var renderer, board, dimensions; 220 221 if(JXG.Options.renderer == 'svg') { 222 renderer = new JXG.SVGRenderer(document.getElementById(box)); 223 } else if(JXG.Options.renderer == 'vml') { 224 renderer = new JXG.VMLRenderer(document.getElementById(box)); 225 } else if(JXG.Options.renderer == 'silverlight') { 226 renderer = new JXG.SilverlightRenderer(document.getElementById(box), dimensions.width, dimensions.height); 227 } else { 228 renderer = new JXG.CanvasRenderer(document.getElementById(box)); 229 } 230 231 //var dimensions = document.getElementById(box).getDimensions(); 232 dimensions = JXG.getDimensions(box); 233 234 /* User default parameters, in parse* the values in the gxt files are submitted to board */ 235 board = new JXG.Board(box, renderer, '', [150, 150], 1.0, 1.0, 50, 50, dimensions.width, dimensions.height); 236 board.initInfobox(); 237 238 JXG.FileReader.parseFileContent(file, board, format); 239 if(board.options.showNavigation) { 240 board.renderer.drawZoomBar(board); 241 } 242 this.boards[board.id] = board; 243 return board; 244 }, 245 246 /** 247 * Load a board from a base64 encoded string containing a construction made with either GEONExT, 248 * Intergeo, Geogebra, or Cinderella. 249 * @param {String} box HTML-ID to the HTML-element in which the board is painted. 250 * @param {String} string base64 encoded string. 251 * @param {String} format containing the file format: 'Geonext' or 'Intergeo'. 252 * @returns {JXG.Board} Reference to the created board. 253 * 254 * @see JXG.FileReader 255 * @see JXG.GeonextReader 256 * @see JXG.GeogebraReader 257 * @see JXG.IntergeoReader 258 * @see JXG.CinderellaReader 259 */ 260 loadBoardFromString: function(box, string, format) { 261 var renderer, dimensions, board; 262 263 if(JXG.Options.renderer == 'svg') { 264 renderer = new JXG.SVGRenderer(document.getElementById(box)); 265 } else if(JXG.Options.renderer == 'vml') { 266 renderer = new JXG.VMLRenderer(document.getElementById(box)); 267 } else if(JXG.Options.renderer == 'silverlight') { 268 renderer = new JXG.SilverlightRenderer(document.getElementById(box), dimensions.width, dimensions.height); 269 } else { 270 renderer = new JXG.CanvasRenderer(document.getElementById(box)); 271 } 272 //var dimensions = document.getElementById(box).getDimensions(); 273 dimensions = JXG.getDimensions(box); 274 275 /* User default parameters, in parse* the values in the gxt files are submitted to board */ 276 board = new JXG.Board(box, renderer, '', [150, 150], 1.0, 1.0, 50, 50, dimensions.width, dimensions.height); 277 board.initInfobox(); 278 279 JXG.FileReader.parseString(string, board, format, true); 280 if (board.options.showNavigation) { 281 board.renderer.drawZoomBar(board); 282 } 283 284 this.boards[board.id] = board; 285 return board; 286 }, 287 288 /** 289 * Delete a board and all its contents. 290 * @param {String} board HTML-ID to the DOM-element in which the board is drawn. 291 */ 292 freeBoard: function (board) { 293 var el, i; 294 295 if (typeof(board) == 'string') { 296 board = this.boards[board]; 297 } 298 299 board.removeEventHandlers(); 300 301 // Remove all objects from the board. 302 for(el in board.objects) { 303 board.removeObject(board.objects[el]); 304 } 305 306 // Remove all the other things, left on the board, XHTML save 307 while (board.containerObj.firstChild) { 308 board.containerObj.removeChild(board.containerObj.firstChild); 309 } 310 // board.containerObj.innerHTML = ''; 311 312 // Tell the browser the objects aren't needed anymore 313 for(el in board.objects) { 314 delete(board.objects[el]); 315 } 316 317 // Free the renderer and the algebra object 318 delete(board.renderer); 319 delete(board.algebra); 320 321 // clear the creator cache 322 board.jc.creator.clearCache(); 323 delete(board.jc); 324 325 // Finally remove the board itself from the boards array 326 delete(this.boards[board.id]); 327 }, 328 329 /** 330 * This registers a new construction element to JSXGraph for the construction via the {@link JXG.Board.create} 331 * interface. 332 * @param {String} element The elements name. This is case-insensitive, existing elements with the same name 333 * will be overwritten. 334 * @param {Function} creator A reference to a function taking three parameters: First the board, the element is 335 * to be created on, a parent element array, and an attributes object. See {@link JXG.createPoint} or any other 336 * <tt>JXG.create...</tt> function for an example. 337 */ 338 registerElement: function (element, creator) { 339 element = element.toLowerCase(); 340 this.elements[element] = creator; 341 342 if(JXG.Board.prototype['_' + element]) 343 throw new Error("JSXGraph: Can't create wrapper method in JXG.Board because member '_" + element + "' already exists'"); 344 JXG.Board.prototype['_' + element] = function (parents, attributes) { 345 return this.create(element, parents, attributes); 346 }; 347 348 }, 349 350 /** 351 * The opposite of {@link JXG.JSXGraph.registerElement}, it removes a given element from 352 * the element list. You probably don't need this. 353 * @param {String} element The name of the element which is to be removed from the element list. 354 */ 355 unregisterElement: function (element) { 356 delete (this.elements[element.toLowerCase()]); 357 delete (JXG.Board.prototype['_' + element.toLowerCase()]); 358 } 359 }; 360