1 /* 2 Copyright 2008-2023 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 * @exports jxg as JXG 50 */ 51 var jxg = {}; 52 53 // Make sure JXG.extend is not defined 54 // If jsxgraph is loaded via loadjsxgraph.js, this is required, but JXG.extend will be undefined 55 // If jsxgraph is compiled as an amd module, it is possible that another jsxgraph version is already loaded and we 56 // therefore must not re-use the global JXG variable. But in this case JXG.extend will already be defined. 57 // This is the reason for this check. 58 if (typeof JXG === "object" && !JXG.extend) { 59 jxg = JXG; 60 } 61 62 // We need the following two methods "extend" and "shortcut" to create the JXG object via JXG.extend. 63 64 /** 65 * Copy all properties of the <tt>extension</tt> object to <tt>object</tt>. 66 * @param {Object} object 67 * @param {Object} extension 68 * @param {Boolean} [onlyOwn=false] Only consider properties that belong to extension itself, not any inherited properties. 69 * @param {Boolean} [toLower=false] If true the keys are convert to lower case. This is needed for visProp, see JXG#copyAttributes 70 */ 71 jxg.extend = function (object, extension, onlyOwn, toLower) { 72 var e, e2; 73 74 onlyOwn = onlyOwn || false; 75 toLower = toLower || false; 76 77 // the purpose of this for...in loop is indeed to use hasOwnProperty only if the caller 78 // explicitly wishes so. 79 for (e in extension) { 80 if (!onlyOwn || (onlyOwn && extension.hasOwnProperty(e))) { 81 if (toLower) { 82 e2 = e.toLowerCase(); 83 } else { 84 e2 = e; 85 } 86 87 object[e2] = extension[e]; 88 } 89 } 90 }; 91 92 /** 93 * Set a constant <tt>name</tt> in <tt>object</tt> to <tt>value</tt>. The value can't be changed after declaration. 94 * @param {Object} object 95 * @param {String} name 96 * @param {Number|String|Boolean} value 97 * @param {Boolean} ignoreRedefine This should be left at its default: false. 98 */ 99 jxg.defineConstant = function (object, name, value, ignoreRedefine) { 100 ignoreRedefine = ignoreRedefine || false; 101 102 if (ignoreRedefine && jxg.exists(object[name])) { 103 return; 104 } 105 106 Object.defineProperty(object, name, { 107 value: value, 108 writable: false, 109 enumerable: true, 110 configurable: false 111 }); 112 }; 113 114 /** 115 * Copy all properties of the <tt>constants</tt> object in <tt>object</tt> as a constant. 116 * @param {Object} object 117 * @param {Object} constants 118 * @param {Boolean} [onlyOwn=false] Only consider properties that belong to extension itself, not any inherited properties. 119 * @param {Boolean} [toUpper=false] If true the keys are convert to lower case. This is needed for visProp, see JXG#copyAttributes 120 */ 121 jxg.extendConstants = function (object, constants, onlyOwn, toUpper) { 122 var e, e2; 123 124 onlyOwn = onlyOwn || false; 125 toUpper = toUpper || false; 126 127 // The purpose of this for...in loop is indeed to use hasOwnProperty only if the caller explicitly wishes so. 128 for (e in constants) { 129 if (!onlyOwn || (onlyOwn && constants.hasOwnProperty(e))) { 130 if (toUpper) { 131 e2 = e.toUpperCase(); 132 } else { 133 e2 = e; 134 } 135 136 this.defineConstant(object, e2, constants[e]); 137 } 138 } 139 }; 140 141 jxg.extend( 142 jxg, 143 /** @lends JXG */ { 144 /** 145 * Store a reference to every board in this central list. This will at some point 146 * replace JXG.JSXGraph.boards. 147 * @type Object 148 */ 149 boards: {}, 150 151 /** 152 * Store the available file readers in this structure. 153 * @type Object 154 */ 155 readers: {}, 156 157 /** 158 * Associative array that keeps track of all constructable elements registered 159 * via {@link JXG.registerElement}. 160 * @type Object 161 */ 162 elements: {}, 163 164 /** 165 * This registers a new construction element to JSXGraph for the construction via the {@link JXG.Board.create} 166 * interface. 167 * @param {String} element The elements name. This is case-insensitive, existing elements with the same name 168 * will be overwritten. 169 * @param {Function} creator A reference to a function taking three parameters: First the board, the element is 170 * to be created on, a parent element array, and an attributes object. See {@link JXG.createPoint} or any other 171 * <tt>JXG.create...</tt> function for an example. 172 */ 173 registerElement: function (element, creator) { 174 element = element.toLowerCase(); 175 this.elements[element] = creator; 176 }, 177 178 /** 179 * Register a file reader. 180 * @param {function} reader A file reader. This object has to provide two methods: <tt>prepareString()</tt> 181 * and <tt>read()</tt>. 182 * @param {Array} ext 183 */ 184 registerReader: function (reader, ext) { 185 var i, e; 186 187 for (i = 0; i < ext.length; i++) { 188 e = ext[i].toLowerCase(); 189 190 if (typeof this.readers[e] !== "function") { 191 this.readers[e] = reader; 192 } 193 } 194 }, 195 196 /** 197 * Creates a shortcut to a method, e.g. {@link JXG.Board#createElement} is a shortcut to {@link JXG.Board#create}. 198 * Sometimes the target is undefined by the time you want to define the shortcut so we need this little helper. 199 * @param {Object} object The object the method we want to create a shortcut for belongs to. 200 * @param {String} fun The method we want to create a shortcut for. 201 * @returns {Function} A function that calls the given method. 202 */ 203 shortcut: function (object, fun) { 204 return function () { 205 return object[fun].apply(this, arguments); 206 }; 207 }, 208 209 /** 210 * s may be a string containing the name or id of an element or even a reference 211 * to the element itself. This function returns a reference to the element. Search order: id, name. 212 * @param {JXG.Board} board Reference to the board the element belongs to. 213 * @param {String} s String or reference to a JSXGraph element. 214 * @returns {Object} Reference to the object given in parameter object 215 * @deprecated Use {@link JXG.Board#select} 216 */ 217 getRef: function (board, s) { 218 jxg.deprecated("JXG.getRef()", "Board.select()"); 219 return board.select(s); 220 }, 221 222 /** 223 * This is just a shortcut to {@link JXG.getRef}. 224 * @deprecated Use {@link JXG.Board#select}. 225 */ 226 getReference: function (board, s) { 227 jxg.deprecated("JXG.getReference()", "Board.select()"); 228 return board.select(s); 229 }, 230 231 /** 232 * s may be the string containing the id of an HTML tag that hosts a JSXGraph board. 233 * This function returns the reference to the board. 234 * @param {String} s String of an HTML tag that hosts a JSXGraph board 235 * @returns {Object} Reference to the board or null. 236 */ 237 getBoardByContainerId: function (s) { 238 var b; 239 for (b in JXG.boards) { 240 if (JXG.boards.hasOwnProperty(b) && JXG.boards[b].container === s) { 241 return JXG.boards[b]; 242 } 243 } 244 245 return null; 246 }, 247 248 /** 249 * This method issues a warning to the developer that the given function is deprecated 250 * and, if available, offers an alternative to the deprecated function. 251 * @param {String} what Describes the function that is deprecated 252 * @param {String} [replacement] The replacement that should be used instead. 253 */ 254 deprecated: function (what, replacement) { 255 var warning = what + " is deprecated."; 256 257 if (replacement) { 258 warning += " Please use " + replacement + " instead."; 259 } 260 261 jxg.warn(warning); 262 }, 263 264 /** 265 * Outputs a warning via console.warn(), if available. If console.warn() is 266 * unavailable this function will look for an HTML element with the id 'warning' 267 * and append the warning to this element's innerHTML. 268 * @param {String} warning The warning text 269 */ 270 warn: function (warning) { 271 if (typeof window === "object" && window.console && console.warn) { 272 console.warn("WARNING:", warning); 273 } else if (typeof document === "object" && document.getElementById("warning")) { 274 document.getElementById("debug").innerHTML += "WARNING: " + warning + "<br />"; 275 } 276 }, 277 278 /** 279 * Add something to the debug log. If available a JavaScript debug console is used. Otherwise 280 * we're looking for a HTML div with id "debug". If this doesn't exist, too, the output is omitted. 281 * @param s An arbitrary number of parameters. 282 * @see JXG#debugWST 283 */ 284 debugInt: function (s) { 285 var i, p; 286 287 for (i = 0; i < arguments.length; i++) { 288 p = arguments[i]; 289 if (typeof window === "object" && window.console && console.log) { 290 console.log(p); 291 } else if (typeof document === "object" && document.getElementById("debug")) { 292 document.getElementById("debug").innerHTML += p + "<br/>"; 293 } 294 } 295 }, 296 297 /** 298 * Add something to the debug log. If available a JavaScript debug console is used. Otherwise 299 * we're looking for a HTML div with id "debug". If this doesn't exist, too, the output is omitted. 300 * This method adds a stack trace (if available). 301 * @param s An arbitrary number of parameters. 302 * @see JXG#debug 303 */ 304 debugWST: function (s) { 305 var e = new Error(); 306 307 jxg.debugInt.apply(this, arguments); 308 309 if (e && e.stack) { 310 jxg.debugInt("stacktrace"); 311 jxg.debugInt(e.stack.split("\n").slice(1).join("\n")); 312 } 313 }, 314 315 /** 316 * Add something to the debug log. If available a JavaScript debug console is used. Otherwise 317 * we're looking for a HTML div with id "debug". If this doesn't exist, too, the output is omitted. 318 * This method adds a line of the stack trace (if available). 319 * 320 * @param s An arbitrary number of parameters. 321 * @see JXG#debug 322 */ 323 debugLine: function (s) { 324 var e = new Error(); 325 326 jxg.debugInt.apply(this, arguments); 327 328 if (e && e.stack) { 329 jxg.debugInt("Called from", e.stack.split("\n").slice(2, 3).join("\n")); 330 } 331 }, 332 333 /** 334 * Add something to the debug log. If available a JavaScript debug console is used. Otherwise 335 * we're looking for a HTML div with id "debug". If this doesn't exist, too, the output is omitted. 336 * @param s An arbitrary number of parameters. 337 * @see JXG#debugWST 338 * @see JXG#debugLine 339 * @see JXG#debugInt 340 */ 341 debug: function (s) { 342 jxg.debugInt.apply(this, arguments); 343 } 344 } 345 ); 346 347 export default jxg; 348