1 /* 2 Copyright 2008-2023 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 dual licensed under the GNU LGPL or MIT License. 13 14 You can redistribute it and/or modify it under the terms of the 15 16 * GNU Lesser General Public License as published by 17 the Free Software Foundation, either version 3 of the License, or 18 (at your option) any later version 19 OR 20 * MIT License: https://github.com/jsxgraph/jsxgraph/blob/master/LICENSE.MIT 21 22 JSXGraph is distributed in the hope that it will be useful, 23 but WITHOUT ANY WARRANTY; without even the implied warranty of 24 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 25 GNU Lesser General Public License for more details. 26 27 You should have received a copy of the GNU Lesser General Public License and 28 the MIT License along with JSXGraph. If not, see <https://www.gnu.org/licenses/> 29 and <https://opensource.org/licenses/MIT/>. 30 */ 31 32 /*global JXG: true, document:true, jQuery:true, define: true, window: true*/ 33 /*jslint nomen: true, plusplus: true*/ 34 35 /** 36 * @fileoverview The JSXGraph object is defined in this file. JXG.JSXGraph controls all boards. 37 * It has methods to create, save, load and free boards. Additionally some helper functions are 38 * defined in this file directly in the JXG namespace. 39 * @version 0.99 40 */ 41 42 import JXG from "./jxg"; 43 import Env from "./utils/env"; 44 import Type from "./utils/type"; 45 import Board from "./base/board"; 46 import FileReader from "./reader/file"; 47 import Options from "./options"; 48 import SVGRenderer from "./renderer/svg"; 49 import VMLRenderer from "./renderer/vml"; 50 import CanvasRenderer from "./renderer/canvas"; 51 import NoRenderer from "./renderer/no"; 52 53 /** 54 * Constructs a new JSXGraph singleton object. 55 * @class The JXG.JSXGraph singleton stores all properties required 56 * to load, save, create and free a board. 57 */ 58 JXG.JSXGraph = { 59 /** 60 * Stores the renderer that is used to draw the boards. 61 * @type String 62 */ 63 rendererType: (function () { 64 Options.board.renderer = "no"; 65 66 if (Env.supportsVML()) { 67 Options.board.renderer = "vml"; 68 // Ok, this is some real magic going on here. IE/VML always was so 69 // terribly slow, except in one place: Examples placed in a moodle course 70 // was almost as fast as in other browsers. So i grabbed all the css and 71 // lib scripts from our moodle, added them to a jsxgraph example and it 72 // worked. next step was to strip all the css/lib code which didn't affect 73 // the VML update speed. The following five lines are what was left after 74 // the last step and yes - it basically does nothing but reads two 75 // properties of document.body on every mouse move. why? we don't know. if 76 // you know, please let us know. 77 // 78 // If we want to use the strict mode we have to refactor this a little bit. Let's 79 // hope the magic isn't gone now. Anywho... it's only useful in old versions of IE 80 // which should not be used anymore. 81 document.onmousemove = function () { 82 var t; 83 84 if (document.body) { 85 t = document.body.scrollLeft; 86 t += document.body.scrollTop; 87 } 88 89 return t; 90 }; 91 } 92 93 if (Env.supportsCanvas()) { 94 Options.board.renderer = "canvas"; 95 } 96 97 if (Env.supportsSVG()) { 98 Options.board.renderer = "svg"; 99 } 100 101 // we are inside node 102 if (Env.isNode() && Env.supportsCanvas()) { 103 Options.board.renderer = "canvas"; 104 } 105 106 if (Env.isNode() || Options.renderer === "no") { 107 Options.text.display = "internal"; 108 Options.infobox.display = "internal"; 109 } 110 111 return Options.board.renderer; 112 })(), 113 114 /** 115 * Initialize the rendering engine 116 * 117 * @param {String} box HTML id of the div-element which hosts the JSXGraph construction 118 * @param {Object} dim The dimensions of the board 119 * @param {Object} doc Usually, this is document object of the browser window. If false or null, this defaults 120 * to the document object of the browser. 121 * @param {Object} attrRenderer Attribute 'renderer', speficies the rendering engine. Possible values are 'auto', 'svg', 122 * 'canvas', 'no', and 'vml'. 123 * @returns {Object} Reference to the rendering engine object. 124 * @private 125 */ 126 initRenderer: function (box, dim, doc, attrRenderer) { 127 var boxid, renderer; 128 129 // Former version: 130 // doc = doc || document 131 if ((!Type.exists(doc) || doc === false) && typeof document === "object") { 132 doc = document; 133 } 134 135 if (typeof doc === "object" && box !== null) { 136 boxid = doc.getElementById(box); 137 138 // Remove everything from the container before initializing the renderer and the board 139 while (boxid.firstChild) { 140 boxid.removeChild(boxid.firstChild); 141 } 142 } else { 143 boxid = box; 144 } 145 146 // If attrRenderer is not supplied take the first available renderer 147 if (attrRenderer === undefined || attrRenderer === "auto") { 148 attrRenderer = this.rendererType; 149 } 150 // create the renderer 151 if (attrRenderer === "svg") { 152 renderer = new SVGRenderer(boxid, dim); 153 } else if (attrRenderer === "vml") { 154 renderer = new VMLRenderer(boxid); 155 } else if (attrRenderer === "canvas") { 156 renderer = new CanvasRenderer(boxid, dim); 157 } else { 158 renderer = new NoRenderer(); 159 } 160 161 return renderer; 162 }, 163 164 /** 165 * Merge the user supplied attributes with the attributes in options.js 166 * 167 * @param {Object} attributes User supplied attributes 168 * @returns {Object} Merged attributes for the board 169 * 170 * @private 171 */ 172 _setAttributes: function (attributes) { 173 // merge attributes 174 var attr = Type.copyAttributes(attributes, Options, "board"); 175 176 // The attributes which are objects have to be copied separately 177 attr.zoom = Type.copyAttributes(attr, Options, "board", "zoom"); 178 attr.pan = Type.copyAttributes(attr, Options, "board", "pan"); 179 attr.drag = Type.copyAttributes(attr, Options, "board", "drag"); 180 attr.keyboard = Type.copyAttributes(attr, Options, "board", "keyboard"); 181 attr.selection = Type.copyAttributes(attr, Options, "board", "selection"); 182 attr.navbar = Type.copyAttributes(attr.navbar, Options, "navbar"); 183 attr.screenshot = Type.copyAttributes(attr, Options, "board", "screenshot"); 184 attr.resize = Type.copyAttributes(attr, Options, "board", "resize"); 185 attr.fullscreen = Type.copyAttributes(attr, Options, "board", "fullscreen"); 186 attr.logging = Type.copyAttributes(attr, Options, 'board', 'logging'); 187 188 // Treat moveTarget separately, because deepCopy will not work here. 189 // Reason: moveTarget will be an HTML node and it is prevented that Type.deepCopy will copy it. 190 attr.movetarget = 191 attributes.moveTarget || attributes.movetarget || Options.board.moveTarget; 192 193 return attr; 194 }, 195 196 /** 197 * Further initialization of the board. Set some properties from attribute values. 198 * 199 * @param {JXG.Board} board 200 * @param {Object} attr attributes object 201 * @param {Object} dimensions Object containing dimensions of the canvas 202 * 203 * @private 204 */ 205 _fillBoard: function (board, attr, dimensions) { 206 board.initInfobox(); 207 board.maxboundingbox = attr.maxboundingbox; 208 board.resizeContainer(dimensions.width, dimensions.height, true, true); 209 board._createSelectionPolygon(attr); 210 board.renderer.drawZoomBar(board, attr.navbar); 211 JXG.boards[board.id] = board; 212 }, 213 214 /** 215 * 216 * @param {String} container HTML-ID to the HTML-element in which the board is painted. 217 * @param {*} attr An object that sets some of the board properties. 218 * 219 * @private 220 */ 221 _setARIA: function (container, attr) { 222 var doc = attr.document, 223 doc_glob, 224 node_jsx, 225 newNode, 226 parent, 227 id_label, 228 id_description; 229 230 if (typeof doc !== 'object') { 231 if (!Env.isBrowser) { 232 return; 233 } 234 doc = document; 235 } 236 237 node_jsx = doc.getElementById(container); 238 doc_glob = node_jsx.ownerDocument; // This is the window.document element, needed below. 239 parent = node_jsx.parentNode; 240 241 id_label = container + "_ARIAlabel"; 242 id_description = container + "_ARIAdescription"; 243 244 newNode = doc_glob.createElement("div"); 245 newNode.innerHTML = attr.title; 246 newNode.setAttribute("id", id_label); 247 newNode.style.display = "none"; 248 parent.insertBefore(newNode, node_jsx); 249 250 newNode = doc_glob.createElement("div"); 251 newNode.innerHTML = attr.description; 252 newNode.setAttribute("id", id_description); 253 newNode.style.display = "none"; 254 parent.insertBefore(newNode, node_jsx); 255 256 node_jsx.setAttribute("aria-labelledby", id_label); 257 node_jsx.setAttribute("aria-describedby", id_description); 258 }, 259 260 /** 261 * Remove the two corresponding ARIA divs when freeing a board 262 * 263 * @param {JXG.Board} board 264 * 265 * @private 266 */ 267 _removeARIANodes: function (board) { 268 var node, id, doc; 269 270 doc = board.document || document; 271 if (typeof doc !== "object") { 272 return; 273 } 274 275 id = board.containerObj.getAttribute("aria-labelledby"); 276 node = doc.getElementById(id); 277 if (node && node.parentNode) { 278 node.parentNode.removeChild(node); 279 } 280 id = board.containerObj.getAttribute("aria-describedby"); 281 node = doc.getElementById(id); 282 if (node && node.parentNode) { 283 node.parentNode.removeChild(node); 284 } 285 }, 286 287 /** 288 * Initialise a new board. 289 * @param {String} box HTML-ID to the HTML-element in which the board is painted. 290 * @param {Object} attributes An object that sets some of the board properties. Most of these properties can be set via JXG.Options. 291 * @param {Array} [attributes.boundingbox=[-5, 5, 5, -5]] An array containing four numbers describing the left, top, right and bottom boundary of the board in user coordinates 292 * @param {Boolean} [attributes.keepaspectratio=false] If <tt>true</tt>, the bounding box is adjusted to the same aspect ratio as the aspect ratio of the div containing the board. 293 * @param {Boolean} [attributes.showCopyright=false] Show the copyright string in the top left corner. 294 * @param {Boolean} [attributes.showNavigation=false] Show the navigation buttons in the bottom right corner. 295 * @param {Object} [attributes.zoom] Allow the user to zoom with the mouse wheel or the two-fingers-zoom gesture. 296 * @param {Object} [attributes.pan] Allow the user to pan with shift+drag mouse or two-fingers-pan gesture. 297 * @param {Object} [attributes.drag] Allow the user to drag objects with a pointer device. 298 * @param {Object} [attributes.keyboard] Allow the user to drag objects with arrow keys on keyboard. 299 * @param {Boolean} [attributes.axis=false] If set to true, show the axis. Can also be set to an object that is given to both axes as an attribute object. 300 * @param {Boolean|Object} [attributes.grid] If set to true, shows the grid. Can also be set to an object that is given to the grid as its attribute object. 301 * @param {Boolean} [attributes.registerEvents=true] Register mouse / touch events. 302 * @returns {JXG.Board} Reference to the created board. 303 * 304 * @see JXG.AbstractRenderer#drawZoomBar 305 */ 306 initBoard: function (box, attributes) { 307 var originX, 308 originY, 309 unitX, 310 unitY, 311 renderer, 312 offX = 0, 313 offY = 0, 314 w, 315 h, 316 dimensions, 317 bbox, 318 attr, 319 axattr, 320 axattr_x, 321 axattr_y, 322 board; 323 324 attributes = attributes || {}; 325 attr = this._setAttributes(attributes); 326 327 dimensions = Env.getDimensions(box, attr.document); 328 329 if (attr.unitx || attr.unity) { 330 originX = Type.def(attr.originx, 150); 331 originY = Type.def(attr.originy, 150); 332 unitX = Type.def(attr.unitx, 50); 333 unitY = Type.def(attr.unity, 50); 334 } else { 335 bbox = attr.boundingbox; 336 if (bbox[0] < attr.maxboundingbox[0]) { 337 bbox[0] = attr.maxboundingbox[0]; 338 } 339 if (bbox[1] > attr.maxboundingbox[1]) { 340 bbox[1] = attr.maxboundingbox[1]; 341 } 342 if (bbox[2] > attr.maxboundingbox[2]) { 343 bbox[2] = attr.maxboundingbox[2]; 344 } 345 if (bbox[3] < attr.maxboundingbox[3]) { 346 bbox[3] = attr.maxboundingbox[3]; 347 } 348 349 w = parseInt(dimensions.width, 10); 350 h = parseInt(dimensions.height, 10); 351 352 if (Type.exists(bbox) && attr.keepaspectratio) { 353 /* 354 * If the boundingbox attribute is given and the ratio of height and width of the 355 * sides defined by the bounding box and the ratio of the dimensions of the div tag 356 * which contains the board do not coincide, then the smaller side is chosen. 357 */ 358 unitX = w / (bbox[2] - bbox[0]); 359 unitY = h / (bbox[1] - bbox[3]); 360 361 if (Math.abs(unitX) < Math.abs(unitY)) { 362 unitY = (Math.abs(unitX) * unitY) / Math.abs(unitY); 363 // Add the additional units in equal portions above and below 364 offY = (h / unitY - (bbox[1] - bbox[3])) * 0.5; 365 } else { 366 unitX = (Math.abs(unitY) * unitX) / Math.abs(unitX); 367 // Add the additional units in equal portions left and right 368 offX = (w / unitX - (bbox[2] - bbox[0])) * 0.5; 369 } 370 } else { 371 unitX = w / (bbox[2] - bbox[0]); 372 unitY = h / (bbox[1] - bbox[3]); 373 } 374 originX = -unitX * (bbox[0] - offX); 375 originY = unitY * (bbox[1] + offY); 376 } 377 378 renderer = this.initRenderer(box, dimensions, attr.document, attr.renderer); 379 this._setARIA(box, attr); 380 381 // create the board 382 board = new Board( 383 box, 384 renderer, 385 attr.id, 386 [originX, originY], 387 attr.zoomfactor * attr.zoomx, 388 attr.zoomfactor * attr.zoomy, 389 unitX, 390 unitY, 391 dimensions.width, 392 dimensions.height, 393 attr 394 ); 395 396 board.keepaspectratio = attr.keepaspectratio; 397 398 this._fillBoard(board, attr, dimensions); 399 400 // create elements like axes, grid, navigation, ... 401 board.suspendUpdate(); 402 if (attr.axis) { 403 axattr = typeof attr.axis === "object" ? attr.axis : {}; 404 405 // The defaultAxes attributes are overwritten by user supplied axis object. 406 axattr_x = Type.deepCopy(Options.board.defaultAxes.x, axattr); 407 axattr_y = Type.deepCopy(Options.board.defaultAxes.y, axattr); 408 // The user supplied defaultAxes attributes are merged in. 409 if (attr.defaultaxes.x) { 410 axattr_x = Type.deepCopy(axattr_x, attr.defaultaxes.x); 411 } 412 if (attr.defaultaxes.y) { 413 axattr_y = Type.deepCopy(axattr_y, attr.defaultaxes.y); 414 } 415 416 board.defaultAxes = {}; 417 board.defaultAxes.x = board.create( 418 "axis", 419 [ 420 [0, 0], 421 [1, 0] 422 ], 423 axattr_x 424 ); 425 board.defaultAxes.y = board.create( 426 "axis", 427 [ 428 [0, 0], 429 [0, 1] 430 ], 431 axattr_y 432 ); 433 } 434 if (attr.grid) { 435 board.create("grid", [], typeof attr.grid === "object" ? attr.grid : {}); 436 } 437 board.unsuspendUpdate(); 438 439 return board; 440 }, 441 442 /** 443 * Load a board from a file containing a construction made with either GEONExT, 444 * Intergeo, Geogebra, or Cinderella. 445 * @param {String} box HTML-ID to the HTML-element in which the board is painted. 446 * @param {String} file base64 encoded string. 447 * @param {String} format containing the file format: 'Geonext' or 'Intergeo'. 448 * @param {Object} attributes Attributes for the board and 'encoding'. 449 * Compressed files need encoding 'iso-8859-1'. Otherwise it probably is 'utf-8'. 450 * @param {Function} callback 451 * @returns {JXG.Board} Reference to the created board. 452 * @see JXG.FileReader 453 * @see JXG.GeonextReader 454 * @see JXG.GeogebraReader 455 * @see JXG.IntergeoReader 456 * @see JXG.CinderellaReader 457 * 458 * @example 459 * // Uncompressed file 460 * var board = JXG.JSXGraph.loadBoardFromFile('jxgbox', 'filename', 'geonext', 461 * {encoding: 'utf-8'}, 462 * function (board) { console.log("Done loading"); } 463 * ); 464 * // Compressed file 465 * var board = JXG.JSXGraph.loadBoardFromFile('jxgbox', 'filename', 'geonext', 466 * {encoding: 'iso-8859-1'}, 467 * function (board) { console.log("Done loading"); } 468 * ); 469 * 470 * @example 471 * // From <input type="file" id="localfile" /> 472 * var file = document.getElementById('localfile').files[0]; 473 * JXG.JSXGraph.loadBoardFromFile('jxgbox', file, 'geonext', 474 * {encoding: 'utf-8'}, 475 * function (board) { console.log("Done loading"); } 476 * ); 477 */ 478 loadBoardFromFile: function (box, file, format, attributes, callback) { 479 var attr, renderer, board, dimensions, encoding; 480 481 attributes = attributes || {}; 482 attr = this._setAttributes(attributes); 483 484 dimensions = Env.getDimensions(box, attr.document); 485 renderer = this.initRenderer(box, dimensions, attr.document, attr.renderer); 486 this._setARIA(box, attr); 487 488 /* User default parameters, in parse* the values in the gxt files are submitted to board */ 489 board = new Board( 490 box, 491 renderer, 492 "", 493 [150, 150], 494 1, 495 1, 496 50, 497 50, 498 dimensions.width, 499 dimensions.height, 500 attr 501 ); 502 this._fillBoard(board, attr, dimensions); 503 encoding = attr.encoding || "iso-8859-1"; 504 FileReader.parseFileContent(file, board, format, true, encoding, callback); 505 506 return board; 507 }, 508 509 /** 510 * Load a board from a base64 encoded string containing a construction made with either GEONExT, 511 * Intergeo, Geogebra, or Cinderella. 512 * @param {String} box HTML-ID to the HTML-element in which the board is painted. 513 * @param {String} string base64 encoded string. 514 * @param {String} format containing the file format: 'Geonext', 'Intergeo', 'Geogebra'. 515 * @param {Object} attributes Attributes for the board and 'encoding'. 516 * Compressed files need encoding 'iso-8859-1'. Otherwise it probably is 'utf-8'. 517 * @param {Function} callback 518 * @returns {JXG.Board} Reference to the created board. 519 * @see JXG.FileReader 520 * @see JXG.GeonextReader 521 * @see JXG.GeogebraReader 522 * @see JXG.IntergeoReader 523 * @see JXG.CinderellaReader 524 */ 525 loadBoardFromString: function (box, string, format, attributes, callback) { 526 var attr, renderer, board, dimensions; 527 528 attributes = attributes || {}; 529 attr = this._setAttributes(attributes); 530 531 dimensions = Env.getDimensions(box, attr.document); 532 renderer = this.initRenderer(box, dimensions, attr.document, attr.renderer); 533 this._setARIA(box, attr); 534 535 /* User default parameters, in parse* the values in the gxt files are submitted to board */ 536 board = new Board( 537 box, 538 renderer, 539 "", 540 [150, 150], 541 1.0, 542 1.0, 543 50, 544 50, 545 dimensions.width, 546 dimensions.height, 547 attr 548 ); 549 this._fillBoard(board, attr, dimensions); 550 FileReader.parseString(string, board, format, true, callback); 551 552 return board; 553 }, 554 555 /** 556 * Delete a board and all its contents. 557 * @param {JXG.Board,String} board HTML-ID to the DOM-element in which the board is drawn. 558 */ 559 freeBoard: function (board) { 560 var el; 561 562 if (typeof board === "string") { 563 board = JXG.boards[board]; 564 } 565 566 this._removeARIANodes(board); 567 board.removeEventHandlers(); 568 board.suspendUpdate(); 569 570 // Remove all objects from the board. 571 for (el in board.objects) { 572 if (board.objects.hasOwnProperty(el)) { 573 board.objects[el].remove(); 574 } 575 } 576 577 // Remove all the other things, left on the board, XHTML save 578 while (board.containerObj.firstChild) { 579 board.containerObj.removeChild(board.containerObj.firstChild); 580 } 581 582 // Tell the browser the objects aren't needed anymore 583 for (el in board.objects) { 584 if (board.objects.hasOwnProperty(el)) { 585 delete board.objects[el]; 586 } 587 } 588 589 // Free the renderer and the algebra object 590 delete board.renderer; 591 592 // clear the creator cache 593 board.jc.creator.clearCache(); 594 delete board.jc; 595 596 // Finally remove the board itself from the boards array 597 delete JXG.boards[board.id]; 598 }, 599 600 /** 601 * @deprecated Use JXG#registerElement 602 * @param element 603 * @param creator 604 */ 605 registerElement: function (element, creator) { 606 JXG.deprecated("JXG.JSXGraph.registerElement()", "JXG.registerElement()"); 607 JXG.registerElement(element, creator); 608 } 609 }; 610 611 // JessieScript/JessieCode startup: 612 // Search for script tags of type text/jessiescript and interprete them. 613 if (Env.isBrowser && typeof window === "object" && typeof document === "object") { 614 Env.addEvent( 615 window, 616 "load", 617 function () { 618 var type, 619 i, 620 j, 621 div, 622 id, 623 board, 624 txt, 625 width, 626 height, 627 maxWidth, 628 aspectRatio, 629 cssClasses, 630 bbox, 631 axis, 632 grid, 633 code, 634 src, 635 request, 636 postpone = false, 637 scripts = document.getElementsByTagName("script"), 638 init = function (code, type, bbox) { 639 var board = JXG.JSXGraph.initBoard(id, { 640 boundingbox: bbox, 641 keepaspectratio: true, 642 grid: grid, 643 axis: axis, 644 showReload: true 645 }); 646 647 if (type.toLowerCase().indexOf("script") > -1) { 648 board.construct(code); 649 } else { 650 try { 651 board.jc.parse(code); 652 } catch (e2) { 653 JXG.debug(e2); 654 } 655 } 656 657 return board; 658 }, 659 makeReload = function (board, code, type, bbox) { 660 return function () { 661 var newBoard; 662 663 JXG.JSXGraph.freeBoard(board); 664 newBoard = init(code, type, bbox); 665 newBoard.reload = makeReload(newBoard, code, type, bbox); 666 }; 667 }; 668 669 for (i = 0; i < scripts.length; i++) { 670 type = scripts[i].getAttribute("type", false); 671 672 if ( 673 Type.exists(type) && 674 (type.toLowerCase() === "text/jessiescript" || 675 type.toLowerCase() === "jessiescript" || 676 type.toLowerCase() === "text/jessiecode" || 677 type.toLowerCase() === "jessiecode") 678 ) { 679 cssClasses = scripts[i].getAttribute("class", false) || ""; 680 width = scripts[i].getAttribute("width", false) || ""; 681 height = scripts[i].getAttribute("height", false) || ""; 682 maxWidth = scripts[i].getAttribute("maxwidth", false) || "100%"; 683 aspectRatio = scripts[i].getAttribute("aspectratio", false) || "1/1"; 684 bbox = scripts[i].getAttribute("boundingbox", false) || "-5, 5, 5, -5"; 685 id = scripts[i].getAttribute("container", false); 686 src = scripts[i].getAttribute("src", false); 687 688 bbox = bbox.split(","); 689 if (bbox.length !== 4) { 690 bbox = [-5, 5, 5, -5]; 691 } else { 692 for (j = 0; j < bbox.length; j++) { 693 bbox[j] = parseFloat(bbox[j]); 694 } 695 } 696 axis = Type.str2Bool(scripts[i].getAttribute("axis", false) || "false"); 697 grid = Type.str2Bool(scripts[i].getAttribute("grid", false) || "false"); 698 699 if (!Type.exists(id)) { 700 id = "jessiescript_autgen_jxg_" + i; 701 div = document.createElement("div"); 702 div.setAttribute("id", id); 703 704 txt = width !== "" ? "width:" + width + ";" : ""; 705 txt += height !== "" ? "height:" + height + ";" : ""; 706 txt += maxWidth !== "" ? "max-width:" + maxWidth + ";" : ""; 707 txt += aspectRatio !== "" ? "aspect-ratio:" + aspectRatio + ";" : ""; 708 709 div.setAttribute("style", txt); 710 div.setAttribute("class", "jxgbox " + cssClasses); 711 try { 712 document.body.insertBefore(div, scripts[i]); 713 } catch (e) { 714 // there's probably jquery involved... 715 if (typeof jQuery === "object") { 716 jQuery(div).insertBefore(scripts[i]); 717 } 718 } 719 } else { 720 div = document.getElementById(id); 721 } 722 723 code = ""; 724 725 if (Type.exists(src)) { 726 postpone = true; 727 request = new XMLHttpRequest(); 728 request.open("GET", src); 729 request.overrideMimeType("text/plain; charset=x-user-defined"); 730 /* jshint ignore:start */ 731 request.addEventListener("load", function () { 732 if (this.status < 400) { 733 code = this.responseText + "\n" + code; 734 board = init(code, type, bbox); 735 board.reload = makeReload(board, code, type, bbox); 736 } else { 737 throw new Error( 738 "\nJSXGraph: failed to load file", 739 src, 740 ":", 741 this.responseText 742 ); 743 } 744 }); 745 request.addEventListener("error", function (e) { 746 throw new Error("\nJSXGraph: failed to load file", src, ":", e); 747 }); 748 /* jshint ignore:end */ 749 request.send(); 750 } else { 751 postpone = false; 752 } 753 754 if (document.getElementById(id)) { 755 code = scripts[i].innerHTML; 756 code = code.replace(/<!\[CDATA\[/g, "").replace(/\]\]>/g, ""); 757 scripts[i].innerHTML = code; 758 759 if (!postpone) { 760 // Do no wait for data from "src" attribute 761 board = init(code, type, bbox); 762 board.reload = makeReload(board, code, type, bbox); 763 } 764 } else { 765 JXG.debug( 766 "JSXGraph: Apparently the div injection failed. Can't create a board, sorry." 767 ); 768 } 769 } 770 } 771 }, 772 window 773 ); 774 } 775 776 export default JXG.JSXGraph; 777