1 /* 2 Copyright 2008-2024 3 Matthias Ehmann, 4 Michael Gerhaeuser, 5 Carsten Miller, 6 Bianca Valentin, 7 Andreas Walter, 8 Alfred Wassermann, 9 Peter Wilfahrt 10 11 This file is part of JSXGraph and JSXCompressor. 12 13 JSXGraph is free software dual licensed under the GNU LGPL or MIT License. 14 JSXCompressor is free software dual licensed under the GNU LGPL or Apache License. 15 16 You can redistribute it and/or modify it under the terms of the 17 18 * GNU Lesser General Public License as published by 19 the Free Software Foundation, either version 3 of the License, or 20 (at your option) any later version 21 OR 22 * MIT License: https://github.com/jsxgraph/jsxgraph/blob/master/LICENSE.MIT 23 OR 24 * Apache License Version 2.0 25 26 JSXGraph is distributed in the hope that it will be useful, 27 but WITHOUT ANY WARRANTY; without even the implied warranty of 28 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 29 GNU Lesser General Public License for more details. 30 31 You should have received a copy of the GNU Lesser General Public License, Apache 32 License, and the MIT License along with JSXGraph. If not, see 33 <https://www.gnu.org/licenses/>, <https://www.apache.org/licenses/LICENSE-2.0.html>, 34 and <https://opensource.org/licenses/MIT/>. 35 36 */ 37 38 /*global JXG: true, define: true, jQuery: true, window: true, document: true, navigator: true, require: true, module: true, console: true */ 39 /*jslint nomen:true, plusplus:true, forin:true*/ 40 41 /** 42 * @fileoverview The JSXGraph object is defined in this file. JXG.JSXGraph controls all boards. 43 * It has methods to create, save, load and free boards. Additionally some helper functions are 44 * defined in this file directly in the JXG namespace. 45 */ 46 47 /** 48 * JXG is the top object of JSXGraph and defines the namespace 49 * 50 * @name JXG 51 * @exports jxg as JXG 52 * @namespace 53 */ 54 var jxg = {}; 55 56 // Make sure JXG.extend is not defined. 57 // If JSXGraph is compiled as an amd module, it is possible that another JSXGraph version is already loaded and we 58 // therefore must not re-use the global JXG variable. But in this case JXG.extend will already be defined. 59 // This is the reason for this check. 60 // The try-statement is necessary, otherwise an error is thrown in certain imports, e.g. in deno. 61 try { 62 if (typeof JXG === "object" && !JXG.extend) { 63 jxg = JXG; 64 } 65 } catch (e) {} 66 67 // We need the following two methods "extend" and "shortcut" to create the JXG object via JXG.extend. 68 69 /** 70 * Copy all properties of the <tt>extension</tt> object to <tt>object</tt>. 71 * @param {Object} object 72 * @param {Object} extension 73 * @param {Boolean} [onlyOwn=false] Only consider properties that belong to extension itself, not any inherited properties. 74 * @param {Boolean} [toLower=false] If true the keys are convert to lower case. This is needed for visProp, see JXG#copyAttributes 75 */ 76 jxg.extend = function (object, extension, onlyOwn, toLower) { 77 var e, e2; 78 79 onlyOwn = onlyOwn || false; 80 toLower = toLower || false; 81 82 // the purpose of this for...in loop is indeed to use hasOwnProperty only if the caller 83 // explicitly wishes so. 84 for (e in extension) { 85 if (!onlyOwn || (onlyOwn && extension.hasOwnProperty(e))) { 86 if (toLower) { 87 e2 = e.toLowerCase(); 88 } else { 89 e2 = e; 90 } 91 92 object[e2] = extension[e]; 93 } 94 } 95 }; 96 97 /** 98 * Set a constant <tt>name</tt> in <tt>object</tt> to <tt>value</tt>. The value can't be changed after declaration. 99 * @param {Object} object 100 * @param {String} name 101 * @param {Number|String|Boolean} value 102 * @param {Boolean} ignoreRedefine This should be left at its default: false. 103 */ 104 jxg.defineConstant = function (object, name, value, ignoreRedefine) { 105 ignoreRedefine = ignoreRedefine || false; 106 107 if (ignoreRedefine && jxg.exists(object[name])) { 108 return; 109 } 110 111 Object.defineProperty(object, name, { 112 value: value, 113 writable: false, 114 enumerable: true, 115 configurable: false 116 }); 117 }; 118 119 /** 120 * Copy all properties of the <tt>constants</tt> object in <tt>object</tt> as a constant. 121 * @param {Object} object 122 * @param {Object} constants 123 * @param {Boolean} [onlyOwn=false] Only consider properties that belong to extension itself, not any inherited properties. 124 * @param {Boolean} [toUpper=false] If true the keys are convert to lower case. This is needed for visProp, see JXG#copyAttributes 125 */ 126 jxg.extendConstants = function (object, constants, onlyOwn, toUpper) { 127 var e, e2; 128 129 onlyOwn = onlyOwn || false; 130 toUpper = toUpper || false; 131 132 // The purpose of this for...in loop is indeed to use hasOwnProperty only if the caller explicitly wishes so. 133 for (e in constants) { 134 if (!onlyOwn || (onlyOwn && constants.hasOwnProperty(e))) { 135 if (toUpper) { 136 e2 = e.toUpperCase(); 137 } else { 138 e2 = e; 139 } 140 141 this.defineConstant(object, e2, constants[e]); 142 } 143 } 144 }; 145 146 jxg.extend( 147 jxg, 148 /** @lends JXG */ { 149 /** 150 * Store a reference to every board in this central list. This will at some point 151 * replace JXG.JSXGraph.boards. 152 * @type Object 153 */ 154 boards: {}, 155 156 /** 157 * Store the available file readers in this structure. 158 * @type Object 159 */ 160 readers: {}, 161 162 /** 163 * Associative array that keeps track of all constructable elements registered 164 * via {@link JXG.registerElement}. 165 * @type Object 166 */ 167 elements: {}, 168 169 /** 170 * This registers a new construction element to JSXGraph for the construction via the {@link JXG.Board.create} 171 * interface. 172 * @param {String} element The elements name. This is case-insensitive, existing elements with the same name 173 * will be overwritten. 174 * @param {Function} creator A reference to a function taking three parameters: First the board, the element is 175 * to be created on, a parent element array, and an attributes object. See {@link JXG.createPoint} or any other 176 * <tt>JXG.create...</tt> function for an example. 177 */ 178 registerElement: function (element, creator) { 179 element = element.toLowerCase(); 180 this.elements[element] = creator; 181 }, 182 183 /** 184 * Register a file reader. 185 * @param {function} reader A file reader. This object has to provide two methods: <tt>prepareString()</tt> 186 * and <tt>read()</tt>. 187 * @param {Array} ext 188 */ 189 registerReader: function (reader, ext) { 190 var i, e; 191 192 for (i = 0; i < ext.length; i++) { 193 e = ext[i].toLowerCase(); 194 195 if (typeof this.readers[e] !== "function") { 196 this.readers[e] = reader; 197 } 198 } 199 }, 200 201 /** 202 * Creates a shortcut to a method, e.g. {@link JXG.Board#createElement} is a shortcut to {@link JXG.Board#create}. 203 * Sometimes the target is undefined by the time you want to define the shortcut so we need this little helper. 204 * @param {Object} object The object the method we want to create a shortcut for belongs to. 205 * @param {String} fun The method we want to create a shortcut for. 206 * @returns {Function} A function that calls the given method. 207 */ 208 shortcut: function (object, fun) { 209 return function () { 210 return object[fun].apply(this, arguments); 211 }; 212 }, 213 214 /** 215 * s may be a string containing the name or id of an element or even a reference 216 * to the element itself. This function returns a reference to the element. Search order: id, name. 217 * @param {JXG.Board} board Reference to the board the element belongs to. 218 * @param {String} s String or reference to a JSXGraph element. 219 * @returns {Object} Reference to the object given in parameter object 220 * @deprecated Use {@link JXG.Board#select} 221 */ 222 getRef: function (board, s) { 223 jxg.deprecated("JXG.getRef()", "Board.select()"); 224 return board.select(s); 225 }, 226 227 /** 228 * This is just a shortcut to {@link JXG.getRef}. 229 * @deprecated Use {@link JXG.Board#select}. 230 */ 231 getReference: function (board, s) { 232 jxg.deprecated("JXG.getReference()", "Board.select()"); 233 return board.select(s); 234 }, 235 236 /** 237 * s may be the string containing the id of an HTML tag that hosts a JSXGraph board. 238 * This function returns the reference to the board. 239 * @param {String} s String of an HTML tag that hosts a JSXGraph board 240 * @returns {Object} Reference to the board or null. 241 */ 242 getBoardByContainerId: function (s) { 243 var b; 244 for (b in JXG.boards) { 245 if (JXG.boards.hasOwnProperty(b) && JXG.boards[b].container === s) { 246 return JXG.boards[b]; 247 } 248 } 249 250 return null; 251 }, 252 253 /** 254 * This method issues a warning to the developer that the given function is deprecated 255 * and, if available, offers an alternative to the deprecated function. 256 * @param {String} what Describes the function that is deprecated 257 * @param {String} [replacement] The replacement that should be used instead. 258 */ 259 deprecated: function (what, replacement) { 260 var warning = what + " is deprecated."; 261 262 if (replacement) { 263 warning += " Please use " + replacement + " instead."; 264 } 265 266 jxg.warn(warning); 267 }, 268 269 /** 270 * Outputs a warning via console.warn(), if available. If console.warn() is 271 * unavailable this function will look for an HTML element with the id 'warning' 272 * and append the warning to this element's innerHTML. 273 * @param {String} warning The warning text 274 */ 275 warn: function (warning) { 276 if (typeof window === "object" && window.console && console.warn) { 277 console.warn("WARNING:", warning); 278 } else if (typeof document === "object" && document.getElementById("warning")) { 279 document.getElementById("debug").innerHTML += "WARNING: " + warning + "<br />"; 280 } 281 }, 282 283 /** 284 * Add something to the debug log. If available a JavaScript debug console is used. Otherwise 285 * we're looking for a HTML div with id "debug". If this doesn't exist, too, the output is omitted. 286 * @param s An arbitrary number of parameters. 287 * @see JXG.debugWST 288 */ 289 debugInt: function (s) { 290 var i, p; 291 292 for (i = 0; i < arguments.length; i++) { 293 p = arguments[i]; 294 if (typeof window === "object" && window.console && console.log) { 295 console.log(p); 296 } else if (typeof document === "object" && document.getElementById("debug")) { 297 document.getElementById("debug").innerHTML += p + "<br/>"; 298 } 299 } 300 }, 301 302 /** 303 * Add something to the debug log. If available a JavaScript debug console is used. Otherwise 304 * we're looking for a HTML div with id "debug". If this doesn't exist, too, the output is omitted. 305 * This method adds a stack trace (if available). 306 * @param s An arbitrary number of parameters. 307 * @see JXG.debug 308 */ 309 debugWST: function (s) { 310 var e = new Error(); 311 312 jxg.debugInt.apply(this, arguments); 313 314 if (e && e.stack) { 315 jxg.debugInt("stacktrace"); 316 jxg.debugInt(e.stack.split("\n").slice(1).join("\n")); 317 } 318 }, 319 320 /** 321 * Add something to the debug log. If available a JavaScript debug console is used. Otherwise 322 * we're looking for a HTML div with id "debug". If this doesn't exist, too, the output is omitted. 323 * This method adds a line of the stack trace (if available). 324 * 325 * @param s An arbitrary number of parameters. 326 * @see JXG.debug 327 */ 328 debugLine: function (s) { 329 var e = new Error(); 330 331 jxg.debugInt.apply(this, arguments); 332 333 if (e && e.stack) { 334 jxg.debugInt("Called from", e.stack.split("\n").slice(2, 3).join("\n")); 335 } 336 }, 337 338 /** 339 * Add something to the debug log. If available a JavaScript debug console is used. Otherwise 340 * we're looking for a HTML div with id "debug". If this doesn't exist, too, the output is omitted. 341 * @param s An arbitrary number of parameters. 342 * @see JXG.debugWST 343 * @see JXG.debugLine 344 * @see JXG.debugInt 345 */ 346 debug: function (s) { 347 jxg.debugInt.apply(this, arguments); 348 }, 349 350 themes: {} 351 } 352 ); 353 354 export default jxg; 355