1 /* 2 Copyright 2008-2013 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 <http://www.gnu.org/licenses/> 29 and <http://opensource.org/licenses/MIT/>. 30 */ 31 32 33 /*global JXG: true, define: true, AMprocessNode: true, MathJax: true, document: true, window: true */ 34 35 /* 36 nomen: Allow underscores to indicate private class members. Might be replaced by local variables. 37 plusplus: Only allowed in for-loops 38 newcap: AsciiMathMl exposes non-constructor functions beginning with upper case letters 39 */ 40 /*jslint nomen: true, plusplus: true, newcap:true*/ 41 42 /* depends: 43 jxg 44 options 45 base/coords 46 base/constants 47 math/math 48 math/geometry 49 utils/type 50 utils/env 51 */ 52 53 /** 54 * @fileoverview JSXGraph can use various technologies to render the contents of a construction, e.g. 55 * SVG, VML, and HTML5 Canvas. To accomplish this, The rendering and the logic and control mechanisms 56 * are completely separated from each other. Every rendering technology has it's own class, called 57 * Renderer, e.g. SVGRenderer for SVG, the same for VML and Canvas. The common base for all available 58 * renderers is the class AbstractRenderer defined in this file. 59 */ 60 61 define([ 62 'jxg', 'options', 'base/coords', 'base/constants', 'math/math', 'math/geometry', 'utils/type', 'utils/env' 63 ], function (JXG, Options, Coords, Const, Mat, Geometry, Type, Env) { 64 65 "use strict"; 66 67 /** 68 * <p>This class defines the interface to the graphics part of JSXGraph. This class is an abstract class, it 69 * actually does not render anything. This is up to the {@link JXG.SVGRenderer}, {@link JXG.VMLRenderer}, 70 * and {@link JXG.CanvasRenderer} classes. We strongly discourage you from using the methods in these classes 71 * directly. Only the methods which are defined in this class and are not marked as private are guaranteed 72 * to exist in any renderer instance you can access via {@link JXG.Board#renderer}. But not all methods may 73 * work as expected.</p> 74 * <p>The methods of this renderer can be divided into different categories: 75 * <dl> 76 * <dt>Draw basic elements</dt> 77 * <dd>In this category we find methods to draw basic elements like {@link JXG.Point}, {@link JXG.Line}, 78 * and {@link JXG.Curve} as well as assisting methods tightly bound to these basic painters. You do not 79 * need to implement these methods in a descendant renderer but instead implement the primitive drawing 80 * methods described below. This approach is encouraged when you're using a XML based rendering engine 81 * like VML and SVG. If you want to use a bitmap based rendering technique you are supposed to override 82 * these methods instead of the primitive drawing methods.</dd> 83 * <dt>Draw primitives</dt> 84 * <dd>This category summarizes methods to handle primitive nodes. As creation and management of these nodes 85 * is different among different the rendering techniques most of these methods are purely virtual and need 86 * proper implementation if you choose to not overwrite the basic element drawing methods.</dd> 87 * <dt>Attribute manipulation</dt> 88 * <dd>In XML based renders you have to manipulate XML nodes and their attributes to change the graphics. 89 * For that purpose attribute manipulation methods are defined to set the color, opacity, and other things. 90 * Please note that some of these methods are required in bitmap based renderers, too, because some elements 91 * like {@link JXG.Text} can be HTML nodes floating over the construction.</dd> 92 * <dt>Renderer control</dt> 93 * <dd>Methods to clear the drawing board or to stop and to resume the rendering engine.</dd> 94 * </dl></p> 95 * @class JXG.AbstractRenderer 96 * @constructor 97 * @see JXG.SVGRenderer 98 * @see JXG.VMLRenderer 99 * @see JXG.CanvasRenderer 100 */ 101 JXG.AbstractRenderer = function () { 102 103 // WHY THIS IS A CLASS INSTEAD OF A SINGLETON OBJECT: 104 // 105 // The renderers need to keep track of some stuff which is not always the same on different boards, 106 // like enhancedRendering, reference to the container object, and resolution in VML. Sure, those 107 // things could be stored in board. But they are rendering related and JXG.Board is already very 108 // very big. 109 // 110 // And we can't save the rendering related data in {SVG,VML,Canvas}Renderer and make only the 111 // JXG.AbstractRenderer a singleton because of that: 112 // 113 // Given an object o with property a set to true 114 // var o = {a: true}; 115 // and a class c doing nothing 116 // c = function() {}; 117 // Set c's prototype to o 118 // c.prototype = o; 119 // and create an instance of c we get i.a to be true 120 // i = new c(); 121 // i.a; 122 // > true 123 // But we can overwrite this property via 124 // c.prototype.a = false; 125 // i.a; 126 // > false 127 128 /** 129 * The vertical offset for {@link Text} elements. Every {@link Text} element will 130 * be placed this amount of pixels below the user given coordinates. 131 * @type number 132 * @default 8 133 */ 134 this.vOffsetText = 0; 135 136 /** 137 * If this property is set to <tt>true</tt> the visual properties of the elements are updated 138 * on every update. Visual properties means: All the stuff stored in the 139 * {@link JXG.GeometryElement#visProp} property won't be set if enhancedRendering is <tt>false</tt> 140 * @type Boolean 141 * @default true 142 */ 143 this.enhancedRendering = true; 144 145 /** 146 * The HTML element that stores the JSXGraph board in it. 147 * @type Node 148 */ 149 this.container = null; 150 151 /** 152 * This is used to easily determine which renderer we are using 153 * @example if (board.renderer.type === 'vml') { 154 * // do something 155 * } 156 * @type String 157 */ 158 this.type = ''; 159 }; 160 161 JXG.extend(JXG.AbstractRenderer.prototype, /** @lends JXG.AbstractRenderer.prototype */ { 162 163 /* ******************************** * 164 * private methods * 165 * should not be called from * 166 * outside AbstractRenderer * 167 * ******************************** */ 168 169 /** 170 * Update visual properties, but only if {@link JXG.AbstractRenderer#enhancedRendering} or <tt>enhanced</tt> is set to true. 171 * @param {JXG.GeometryElement} element The element to update 172 * @param {Object} [not={}] Select properties you don't want to be updated: <tt>{fill: true, dash: true}</tt> updates 173 * everything except for fill and dash. Possible values are <tt>stroke, fill, dash, shadow, gradient</tt>. 174 * @param {Boolean} [enhanced=false] If true, {@link JXG.AbstractRenderer#enhancedRendering} is assumed to be true. 175 * @private 176 */ 177 _updateVisual: function (element, not, enhanced) { 178 var rgbo; 179 180 if (enhanced || this.enhancedRendering) { 181 not = not || {}; 182 183 if (!element.visProp.draft) { 184 if (!not.stroke) { 185 this.setObjectStrokeWidth(element, element.visProp.strokewidth); 186 this.setObjectStrokeColor(element, element.visProp.strokecolor, element.visProp.strokeopacity); 187 } 188 189 if (!not.fill) { 190 this.setObjectFillColor(element, element.visProp.fillcolor, element.visProp.fillopacity); 191 } 192 193 if (!not.dash) { 194 this.setDashStyle(element, element.visProp); 195 } 196 197 if (!not.shadow) { 198 this.setShadow(element); 199 } 200 201 if (!not.gradient) { 202 this.setShadow(element); 203 } 204 } else { 205 this.setDraft(element); 206 } 207 } 208 }, 209 210 211 /* ******************************** * 212 * Point drawing and updating * 213 * ******************************** */ 214 215 /** 216 * Draws a point on the {@link JXG.Board}. 217 * @param {JXG.Point} element Reference to a {@link JXG.Point} object that has to be drawn. 218 * @see Point 219 * @see JXG.Point 220 * @see JXG.AbstractRenderer#updatePoint 221 * @see JXG.AbstractRenderer#changePointStyle 222 */ 223 drawPoint: function (element) { 224 var prim, 225 // sometimes element is not a real point and lacks the methods of a JXG.Point instance, 226 // in these cases to not use element directly. 227 face = Options.normalizePointFace(element.visProp.face); 228 229 // determine how the point looks like 230 if (face === 'o') { 231 prim = 'ellipse'; 232 } else if (face === '[]') { 233 prim = 'rect'; 234 } else { 235 // cross/x, diamond/<>, triangleup/a/^, triangledown/v, triangleleft/<, 236 // triangleright/>, plus/+, 237 prim = 'path'; 238 } 239 240 element.rendNode = this.appendChildPrim(this.createPrim(prim, element.id), element.visProp.layer); 241 this.appendNodesToElement(element, prim); 242 243 // adjust visual propertys 244 this._updateVisual(element, {dash: true, shadow: true}, true); 245 246 247 // By now we only created the xml nodes and set some styles, in updatePoint 248 // the attributes are filled with data. 249 this.updatePoint(element); 250 }, 251 252 /** 253 * Updates visual appearance of the renderer element assigned to the given {@link JXG.Point}. 254 * @param {JXG.Point} element Reference to a {@link JXG.Point} object, that has to be updated. 255 * @see Point 256 * @see JXG.Point 257 * @see JXG.AbstractRenderer#drawPoint 258 * @see JXG.AbstractRenderer#changePointStyle 259 */ 260 updatePoint: function (element) { 261 var size = element.visProp.size, 262 // sometimes element is not a real point and lacks the methods of a JXG.Point instance, 263 // in these cases to not use element directly. 264 face = Options.normalizePointFace(element.visProp.face); 265 266 if (!isNaN(element.coords.scrCoords[2] + element.coords.scrCoords[1])) { 267 this._updateVisual(element, {dash: false, shadow: false}); 268 size *= ((!element.board || !element.board.options.point.zoom) ? 1.0 : Math.sqrt(element.board.zoomX * element.board.zoomY)); 269 270 if (face === 'o') { // circle 271 this.updateEllipsePrim(element.rendNode, element.coords.scrCoords[1], element.coords.scrCoords[2], size + 1, size + 1); 272 } else if (face === '[]') { // rectangle 273 this.updateRectPrim(element.rendNode, element.coords.scrCoords[1] - size, element.coords.scrCoords[2] - size, size * 2, size * 2); 274 } else { // x, +, <>, ^, v, <, > 275 this.updatePathPrim(element.rendNode, this.updatePathStringPoint(element, size, face), element.board); 276 } 277 this.setShadow(element); 278 } 279 }, 280 281 /** 282 * Changes the style of a {@link JXG.Point}. This is required because the point styles differ in what 283 * elements have to be drawn, e.g. if the point is marked by a "x" or a "+" two lines are drawn, if 284 * it's marked by spot a circle is drawn. This method removes the old renderer element(s) and creates 285 * the new one(s). 286 * @param {JXG.Point} element Reference to a {@link JXG.Point} object, that's style is changed. 287 * @see Point 288 * @see JXG.Point 289 * @see JXG.AbstractRenderer#updatePoint 290 * @see JXG.AbstractRenderer#drawPoint 291 */ 292 changePointStyle: function (element) { 293 var node = this.getElementById(element.id); 294 295 // remove the existing point rendering node 296 if (Type.exists(node)) { 297 this.remove(node); 298 } 299 300 // and make a new one 301 this.drawPoint(element); 302 Type.clearVisPropOld(element); 303 304 if (!element.visProp.visible) { 305 this.hide(element); 306 } 307 308 if (element.visProp.draft) { 309 this.setDraft(element); 310 } 311 }, 312 313 /* ******************************** * 314 * Lines * 315 * ******************************** */ 316 317 /** 318 * Draws a line on the {@link JXG.Board}. 319 * @param {JXG.Line} element Reference to a line object, that has to be drawn. 320 * @see Line 321 * @see JXG.Line 322 * @see JXG.AbstractRenderer#updateLine 323 */ 324 drawLine: function (element) { 325 element.rendNode = this.appendChildPrim(this.createPrim('line', element.id), element.visProp.layer); 326 this.appendNodesToElement(element, 'lines'); 327 this.updateLine(element); 328 }, 329 330 /** 331 * Updates visual appearance of the renderer element assigned to the given {@link JXG.Line}. 332 * @param {JXG.Line} element Reference to the {@link JXG.Line} object that has to be updated. 333 * @see Line 334 * @see JXG.Line 335 * @see JXG.AbstractRenderer#drawLine 336 */ 337 updateLine: function (element) { 338 var s, d, d1x, d1y, d2x, d2y, 339 c1 = new Coords(Const.COORDS_BY_USER, element.point1.coords.usrCoords, element.board), 340 c2 = new Coords(Const.COORDS_BY_USER, element.point2.coords.usrCoords, element.board), 341 margin = null; 342 343 if (element.visProp.firstarrow || element.visProp.lastarrow) { 344 margin = -4; 345 } 346 Geometry.calcStraight(element, c1, c2, margin); 347 348 d1x = d1y = d2x = d2y = 0.0; 349 /* 350 Handle arrow heads. 351 352 The arrow head is an equilateral triangle with base length 10 and height 10. 353 These 10 units are scaled to strokeWidth*3 pixels or minimum 10 pixels. 354 */ 355 s = Math.max(parseInt(element.visProp.strokewidth, 10) * 3, 10); 356 if (element.visProp.lastarrow && element.board.renderer.type !== 'vml') { 357 d = c1.distance(Const.COORDS_BY_SCREEN, c2); 358 if (d > Mat.eps) { 359 d2x = (c2.scrCoords[1] - c1.scrCoords[1]) * s / d; 360 d2y = (c2.scrCoords[2] - c1.scrCoords[2]) * s / d; 361 } 362 } 363 if (element.visProp.firstarrow && element.board.renderer.type !== 'vml') { 364 d = c1.distance(Const.COORDS_BY_SCREEN, c2); 365 if (d > Mat.eps) { 366 d1x = (c2.scrCoords[1] - c1.scrCoords[1]) * s / d; 367 d1y = (c2.scrCoords[2] - c1.scrCoords[2]) * s / d; 368 } 369 } 370 371 this.updateLinePrim(element.rendNode, 372 c1.scrCoords[1] + d1x, c1.scrCoords[2] + d1y, 373 c2.scrCoords[1] - d2x, c2.scrCoords[2] - d2y, element.board); 374 375 this.makeArrows(element); 376 this._updateVisual(element, {fill: true}); 377 }, 378 379 /** 380 * Creates a rendering node for ticks added to a line. 381 * @param {JXG.Line} element A arbitrary line. 382 * @see Line 383 * @see Ticks 384 * @see JXG.Line 385 * @see JXG.Ticks 386 * @see JXG.AbstractRenderer#updateTicks 387 */ 388 drawTicks: function (element) { 389 element.rendNode = this.appendChildPrim(this.createPrim('path', element.id), element.visProp.layer); 390 this.appendNodesToElement(element, 'path'); 391 }, 392 393 /** 394 * Update {@link Ticks} on a {@link JXG.Line}. This method is only a stub and has to be implemented 395 * in any descendant renderer class. 396 * @param {JXG.Ticks} element Reference of a ticks object that has to be updated. 397 * @param {Number} dxMaj Number of pixels a major tick counts in x direction. 398 * @param {Number} dyMaj Number of pixels a major tick counts in y direction. 399 * @param {Number} dxMin Number of pixels a minor tick counts in x direction. 400 * @param {Number} dyMin Number of pixels a minor tick counts in y direction. 401 * @see Line 402 * @see Ticks 403 * @see JXG.Line 404 * @see JXG.Ticks 405 * @see JXG.AbstractRenderer#drawTicks 406 */ 407 updateTicks: function (element, dxMaj, dyMaj, dxMin, dyMin) { /* stub */ }, 408 409 /* ************************** 410 * Curves 411 * **************************/ 412 413 /** 414 * Draws a {@link JXG.Curve} on the {@link JXG.Board}. 415 * @param {JXG.Curve} element Reference to a graph object, that has to be plotted. 416 * @see Curve 417 * @see JXG.Curve 418 * @see JXG.AbstractRenderer#updateCurve 419 */ 420 drawCurve: function (element) { 421 element.rendNode = this.appendChildPrim(this.createPrim('path', element.id), element.visProp.layer); 422 this.appendNodesToElement(element, 'path'); 423 this._updateVisual(element, {shadow: true}, true); 424 this.updateCurve(element); 425 }, 426 427 /** 428 * Updates visual appearance of the renderer element assigned to the given {@link JXG.Curve}. 429 * @param {JXG.Curve} element Reference to a {@link JXG.Curve} object, that has to be updated. 430 * @see Curve 431 * @see JXG.Curve 432 * @see JXG.AbstractRenderer#drawCurve 433 */ 434 updateCurve: function (element) { 435 this._updateVisual(element); 436 if (element.visProp.handdrawing) { 437 this.updatePathPrim(element.rendNode, this.updatePathStringBezierPrim(element), element.board); 438 } else { 439 this.updatePathPrim(element.rendNode, this.updatePathStringPrim(element), element.board); 440 } 441 if (element.numberPoints > 1) { 442 this.makeArrows(element); 443 } 444 }, 445 446 /* ************************** 447 * Circle related stuff 448 * **************************/ 449 450 /** 451 * Draws a {@link JXG.Circle} 452 * @param {JXG.Circle} element Reference to a {@link JXG.Circle} object that has to be drawn. 453 * @see Circle 454 * @see JXG.Circle 455 * @see JXG.AbstractRenderer#updateEllipse 456 */ 457 drawEllipse: function (element) { 458 element.rendNode = this.appendChildPrim(this.createPrim('ellipse', element.id), element.visProp.layer); 459 this.appendNodesToElement(element, 'ellipse'); 460 this.updateEllipse(element); 461 }, 462 463 /** 464 * Updates visual appearance of a given {@link JXG.Circle} on the {@link JXG.Board}. 465 * @param {JXG.Circle} element Reference to a {@link JXG.Circle} object, that has to be updated. 466 * @see Circle 467 * @see JXG.Circle 468 * @see JXG.AbstractRenderer#drawEllipse 469 */ 470 updateEllipse: function (element) { 471 this._updateVisual(element); 472 473 var radius = element.Radius(); 474 475 if (radius > 0.0 && 476 Math.abs(element.center.coords.usrCoords[0]) > Mat.eps && 477 !isNaN(radius + element.center.coords.scrCoords[1] + element.center.coords.scrCoords[2]) && 478 radius * element.board.unitX < 2000000) { 479 this.updateEllipsePrim(element.rendNode, element.center.coords.scrCoords[1], 480 element.center.coords.scrCoords[2], (radius * element.board.unitX), (radius * element.board.unitY)); 481 } 482 }, 483 484 485 /* ************************** 486 * Polygon related stuff 487 * **************************/ 488 489 /** 490 * Draws a {@link JXG.Polygon} on the {@link JXG.Board}. 491 * @param {JXG.Polygon} element Reference to a Polygon object, that is to be drawn. 492 * @see Polygon 493 * @see JXG.Polygon 494 * @see JXG.AbstractRenderer#updatePolygon 495 */ 496 drawPolygon: function (element) { 497 element.rendNode = this.appendChildPrim(this.createPrim('polygon', element.id), element.visProp.layer); 498 this.appendNodesToElement(element, 'polygon'); 499 this.updatePolygon(element); 500 }, 501 502 /** 503 * Updates properties of a {@link JXG.Polygon}'s rendering node. 504 * @param {JXG.Polygon} element Reference to a {@link JXG.Polygon} object, that has to be updated. 505 * @see Polygon 506 * @see JXG.Polygon 507 * @see JXG.AbstractRenderer#drawPolygon 508 */ 509 updatePolygon: function (element) { 510 // here originally strokecolor wasn't updated but strokewidth was 511 // but if there's no strokecolor i don't see why we should update strokewidth. 512 this._updateVisual(element, {stroke: true, dash: true}); 513 this.updatePolygonPrim(element.rendNode, element); 514 }, 515 516 /* ************************** 517 * Text related stuff 518 * **************************/ 519 520 /** 521 * Shows a small copyright notice in the top left corner of the board. 522 * @param {String} str The copyright notice itself 523 * @param {Number} fontsize Size of the font the copyright notice is written in 524 */ 525 displayCopyright: function (str, fontsize) { /* stub */ }, 526 527 /** 528 * An internal text is a {@link JXG.Text} element which is drawn using only 529 * the given renderer but no HTML. This method is only a stub, the drawing 530 * is done in the special renderers. 531 * @param {JXG.Text} element Reference to a {@link JXG.Text} object 532 * @see Text 533 * @see JXG.Text 534 * @see JXG.AbstractRenderer#updateInternalText 535 * @see JXG.AbstractRenderer#drawText 536 * @see JXG.AbstractRenderer#updateText 537 * @see JXG.AbstractRenderer#updateTextStyle 538 */ 539 drawInternalText: function (element) { /* stub */ }, 540 541 /** 542 * Updates visual properties of an already existing {@link JXG.Text} element. 543 * @param {JXG.Text} element Reference to an {@link JXG.Text} object, that has to be updated. 544 * @see Text 545 * @see JXG.Text 546 * @see JXG.AbstractRenderer#drawInternalText 547 * @see JXG.AbstractRenderer#drawText 548 * @see JXG.AbstractRenderer#updateText 549 * @see JXG.AbstractRenderer#updateTextStyle 550 */ 551 updateInternalText: function (element) { /* stub */ }, 552 553 /** 554 * Displays a {@link JXG.Text} on the {@link JXG.Board} by putting a HTML div over it. 555 * @param {JXG.Text} element Reference to an {@link JXG.Text} object, that has to be displayed 556 * @see Text 557 * @see JXG.Text 558 * @see JXG.AbstractRenderer#drawInternalText 559 * @see JXG.AbstractRenderer#updateText 560 * @see JXG.AbstractRenderer#updateInternalText 561 * @see JXG.AbstractRenderer#updateTextStyle 562 */ 563 drawText: function (element) { 564 var node, z; 565 566 if (element.visProp.display === 'html' && Env.isBrowser) { 567 node = this.container.ownerDocument.createElement('div'); 568 node.style.position = 'absolute'; 569 570 node.className = element.visProp.cssclass; 571 if (this.container.style.zIndex === '') { 572 z = 0; 573 } else { 574 z = parseInt(this.container.style.zIndex, 10); 575 } 576 577 node.style.zIndex = z + element.board.options.layer.text; 578 this.container.appendChild(node); 579 node.setAttribute('id', this.container.id + '_' + element.id); 580 } else { 581 node = this.drawInternalText(element); 582 } 583 584 element.rendNode = node; 585 element.htmlStr = ''; 586 this.updateText(element); 587 }, 588 589 /** 590 * Updates visual properties of an already existing {@link JXG.Text} element. 591 * @param {JXG.Text} el Reference to an {@link JXG.Text} object, that has to be updated. 592 * @see Text 593 * @see JXG.Text 594 * @see JXG.AbstractRenderer#drawText 595 * @see JXG.AbstractRenderer#drawInternalText 596 * @see JXG.AbstractRenderer#updateInternalText 597 * @see JXG.AbstractRenderer#updateTextStyle 598 */ 599 updateText: function (el) { 600 var content = el.plaintext, v, c; 601 602 if (el.visProp.visible) { 603 this.updateTextStyle(el, false); 604 605 if (el.visProp.display === 'html') { 606 // Set the position 607 if (!isNaN(el.coords.scrCoords[1] + el.coords.scrCoords[2])) { 608 c = el.coords.scrCoords[1]; 609 // webkit seems to fail for extremely large values for c. 610 c = Math.abs(c) < 1000000 ? c : 1000000; 611 if (el.visProp.anchorx === 'right') { 612 v = Math.floor(el.board.canvasWidth - c); 613 if (el.visPropOld.right !== v) { 614 el.rendNode.style.right = v + 'px'; 615 el.rendNode.style.left = 'auto'; 616 el.visPropOld.right = v; 617 } 618 } else if (el.visProp.anchorx === 'middle') { 619 v = Math.floor(c - 0.5 * el.size[0]); 620 if (el.visPropOld.left !== v) { 621 el.rendNode.style.left = v + 'px'; 622 el.rendNode.style.right = 'auto'; 623 el.visPropOld.left = v; 624 } 625 // 'left' 626 } else { 627 v = Math.floor(c); 628 if (el.visPropOld.left !== v) { 629 el.rendNode.style.left = v + 'px'; 630 el.rendNode.style.right = 'auto'; 631 el.visPropOld.left = v; 632 } 633 } 634 635 c = el.coords.scrCoords[2]; 636 c = Math.abs(c) < 1000000 ? c : 1000000; 637 if (el.visProp.anchory === 'top') { 638 v = Math.floor(c + this.vOffsetText); 639 } else if (el.visProp.anchory === 'middle') { 640 v = Math.floor(c - 0.5 * el.size[1] + this.vOffsetText); 641 } else { 642 v = Math.floor(c - el.size[1] + this.vOffsetText); 643 } 644 if (el.visPropOld.top !== v) { 645 el.rendNode.style.top = v + 'px'; 646 el.visPropOld.top = v; 647 } 648 } 649 650 // Set the content 651 if (el.htmlStr !== content) { 652 el.rendNode.innerHTML = content; 653 el.htmlStr = content; 654 655 if (el.visProp.usemathjax) { 656 // typesetting directly might not work because mathjax was not loaded completely 657 // see http://www.mathjax.org/docs/1.1/typeset.html 658 MathJax.Hub.Queue(['Typeset', MathJax.Hub, el.rendNode]); 659 } else if (el.visProp.useasciimathml) { 660 // This is not a constructor. 661 // See http://www1.chapman.edu/~jipsen/mathml/asciimath.html for more information 662 // about AsciiMathML and the project's source code. 663 AMprocessNode(el.rendNode, false); 664 } 665 } 666 this.transformImage(el, el.transformations); 667 } else { 668 this.updateInternalText(el); 669 } 670 } 671 }, 672 673 /** 674 * Updates font-size, color and opacity propertiey and CSS style properties of a {@link JXG.Text} node. 675 * This function is also called by highlight() and nohighlight(). 676 * @param {JXG.Text} element Reference to the {@link JXG.Text} object, that has to be updated. 677 * @param {Boolean} doHighlight 678 * @see Text 679 * @see JXG.Text 680 * @see JXG.AbstractRenderer#drawText 681 * @see JXG.AbstractRenderer#drawInternalText 682 * @see JXG.AbstractRenderer#updateText 683 * @see JXG.AbstractRenderer#updateInternalText 684 * @see JXG.AbstractRenderer#updateInternalTextStyle 685 */ 686 updateTextStyle: function (element, doHighlight) { 687 var fs, so, sc, css, 688 ev = element.visProp, 689 display = Env.isBrowser ? ev.display : 'internal'; 690 691 if (doHighlight) { 692 sc = ev.highlightstrokecolor; 693 so = ev.highlightstrokeopacity; 694 css = ev.highlightcssclass; 695 } else { 696 sc = ev.strokecolor; 697 so = ev.strokeopacity; 698 css = ev.cssclass; 699 } 700 701 // This part is executed for all text elements except internal texts in canvas. 702 if (display === 'html' || (this.type !== 'canvas' && this.type !== 'no')) { 703 fs = Type.evaluate(element.visProp.fontsize); 704 if (element.visPropOld.fontsize !== fs) { 705 try { 706 element.rendNode.style.fontSize = fs + 'px'; 707 } catch (e) { 708 // IE needs special treatment. 709 element.rendNode.style.fontSize = fs; 710 } 711 element.visPropOld.fontsize = fs; 712 } 713 714 } 715 716 if (display === 'html') { 717 if (element.visPropOld.cssclass !== css) { 718 element.rendNode.className = css; 719 element.visPropOld.cssclass = css; 720 } 721 this.setObjectStrokeColor(element, sc, so); 722 } else { 723 this.updateInternalTextStyle(element, sc, so); 724 } 725 return this; 726 }, 727 728 /** 729 * Set color and opacity of internal texts. 730 * This method is used for Canvas and VML. 731 * SVG needs its own version. 732 * @private 733 * @see JXG.AbstractRenderer#updateTextStyle 734 * @see JXG.SVGRenderer#updateInternalTextStyle 735 */ 736 updateInternalTextStyle: function (element, strokeColor, strokeOpacity) { 737 this.setObjectStrokeColor(element, strokeColor, strokeOpacity); 738 }, 739 740 /* ************************** 741 * Image related stuff 742 * **************************/ 743 744 /** 745 * Draws an {@link JXG.Image} on a board; This is just a template that has to be implemented by special 746 * renderers. 747 * @param {JXG.Image} element Reference to the image object that is to be drawn 748 * @see Image 749 * @see JXG.Image 750 * @see JXG.AbstractRenderer#updateImage 751 */ 752 drawImage: function (element) { /* stub */ }, 753 754 /** 755 * Updates the properties of an {@link JXG.Image} element. 756 * @param {JXG.Image} element Reference to an {@link JXG.Image} object, that has to be updated. 757 * @see Image 758 * @see JXG.Image 759 * @see JXG.AbstractRenderer#drawImage 760 */ 761 updateImage: function (element) { 762 this.updateRectPrim(element.rendNode, element.coords.scrCoords[1], 763 element.coords.scrCoords[2] - element.size[1], element.size[0], element.size[1]); 764 765 this.updateImageURL(element); 766 this.transformImage(element, element.transformations); 767 this._updateVisual(element, {stroke: true, dash: true}, true); 768 }, 769 770 /** 771 * Multiplication of transformations without updating. That means, at that point it is expected that the 772 * matrices contain numbers only. First, the origin in user coords is translated to <tt>(0,0)</tt> in screen 773 * coords. Then, the stretch factors are divided out. After the transformations in user coords, the stretch 774 * factors are multiplied in again, and the origin in user coords is translated back to its position. This 775 * method does not have to be implemented in a new renderer. 776 * @param {JXG.GeometryElement} element A JSXGraph element. We only need its board property. 777 * @param {Array} transformations An array of JXG.Transformations. 778 * @returns {Array} A matrix represented by a two dimensional array of numbers. 779 * @see JXG.AbstractRenderer#transformImage 780 */ 781 joinTransforms: function (element, transformations) { 782 var i, 783 m = [[1, 0, 0], [0, 1, 0], [0, 0, 1]], 784 ox = element.board.origin.scrCoords[1], 785 oy = element.board.origin.scrCoords[2], 786 ux = element.board.unitX, 787 uy = element.board.unitY, 788 // Translate to 0,0 in screen coords 789 mpre1 = [[1, 0, 0], 790 [-ox, 1, 0], 791 [-oy, 0, 1]], 792 // Scale 793 mpre2 = [[1, 0, 0], 794 [0, 1 / ux, 0], 795 [0, 0, -1 / uy]], 796 // Scale back 797 mpost2 = [[1, 0, 0], 798 [0, ux, 0], 799 [0, 0, -uy]], 800 // Translate back 801 mpost1 = [[1, 0, 0], 802 [ox, 1, 0], 803 [oy, 0, 1]], 804 len = transformations.length; 805 806 for (i = 0; i < len; i++) { 807 m = Mat.matMatMult(mpre1, m); 808 m = Mat.matMatMult(mpre2, m); 809 m = Mat.matMatMult(transformations[i].matrix, m); 810 m = Mat.matMatMult(mpost2, m); 811 m = Mat.matMatMult(mpost1, m); 812 } 813 return m; 814 }, 815 816 /** 817 * Applies transformations on images and text elements. This method is just a stub and has to be implemented in 818 * all descendant classes where text and image transformations are to be supported. 819 * @param {JXG.Image|JXG.Text} element A {@link JXG.Image} or {@link JXG.Text} object. 820 * @param {Array} transformations An array of {@link JXG.Transformation} objects. This is usually the 821 * transformations property of the given element <tt>el</tt>. 822 */ 823 transformImage: function (element, transformations) { /* stub */ }, 824 825 /** 826 * If the URL of the image is provided by a function the URL has to be updated during updateImage() 827 * @param {JXG.Image} element Reference to an image object. 828 * @see JXG.AbstractRenderer#updateImage 829 */ 830 updateImageURL: function (element) { /* stub */ }, 831 832 /** 833 * Updates CSS style properties of a {@link JXG.Image} node. 834 * In SVGRenderer opacity is the only available style element. 835 * This function is called by highlight() and nohighlight(). 836 * This function works for VML. 837 * It does not work for Canvas. 838 * SVGRenderer overwrites this method. 839 * @param {JXG.Text} el Reference to the {@link JXG.Image} object, that has to be updated. 840 * @param {Boolean} doHighlight 841 * @see Image 842 * @see JXG.Image 843 * @see JXG.AbstractRenderer#highlight 844 * @see JXG.AbstractRenderer#noHighlight 845 */ 846 updateImageStyle: function (el, doHighlight) { 847 el.rendNode.className = (doHighlight) ? el.visProp.highlightcssclass : el.visProp.cssclass; 848 }, 849 850 851 /* ************************** 852 * Render primitive objects 853 * **************************/ 854 855 /** 856 * Appends a node to a specific layer level. This is just an abstract method and has to be implemented 857 * in all renderers that want to use the <tt>createPrim</tt> model to draw. 858 * @param {Node} node A DOM tree node. 859 * @param {Number} level The layer the node is attached to. This is the index of the layer in 860 * {@link JXG.SVGRenderer#layer} or the <tt>z-index</tt> style property of the node in VMLRenderer. 861 */ 862 appendChildPrim: function (node, level) { /* stub */ }, 863 864 /** 865 * Stores the rendering nodes. This is an abstract method which has to be implemented in all renderers that use 866 * the <tt>createPrim</tt> method. 867 * @param {JXG.GeometryElement} element A JSXGraph element. 868 * @param {String} type The XML node name. Only used in VMLRenderer. 869 */ 870 appendNodesToElement: function (element, type) { /* stub */ }, 871 872 /** 873 * Creates a node of a given type with a given id. 874 * @param {String} type The type of the node to create. 875 * @param {String} id Set the id attribute to this. 876 * @returns {Node} Reference to the created node. 877 */ 878 createPrim: function (type, id) { 879 /* stub */ 880 return null; 881 }, 882 883 /** 884 * Removes an element node. Just a stub. 885 * @param {Node} node The node to remove. 886 */ 887 remove: function (node) { /* stub */ }, 888 889 /** 890 * Can be used to create the nodes to display arrows. This is an abstract method which has to be implemented 891 * in any descendant renderer. 892 * @param {JXG.GeometryElement} element The element the arrows are to be attached to. 893 */ 894 makeArrows: function (element) { /* stub */ }, 895 896 /** 897 * Updates an ellipse node primitive. This is an abstract method which has to be implemented in all renderers 898 * that use the <tt>createPrim</tt> method. 899 * @param {Node} node Reference to the node. 900 * @param {Number} x Centre X coordinate 901 * @param {Number} y Centre Y coordinate 902 * @param {Number} rx The x-axis radius. 903 * @param {Number} ry The y-axis radius. 904 */ 905 updateEllipsePrim: function (node, x, y, rx, ry) { /* stub */ }, 906 907 /** 908 * Refreshes a line node. This is an abstract method which has to be implemented in all renderers that use 909 * the <tt>createPrim</tt> method. 910 * @param {Node} node The node to be refreshed. 911 * @param {Number} p1x The first point's x coordinate. 912 * @param {Number} p1y The first point's y coordinate. 913 * @param {Number} p2x The second point's x coordinate. 914 * @param {Number} p2y The second point's y coordinate. 915 * @param {JXG.Board} board 916 */ 917 updateLinePrim: function (node, p1x, p1y, p2x, p2y, board) { /* stub */ }, 918 919 /** 920 * Updates a path element. This is an abstract method which has to be implemented in all renderers that use 921 * the <tt>createPrim</tt> method. 922 * @param {Node} node The path node. 923 * @param {String} pathString A string formatted like e.g. <em>'M 1,2 L 3,1 L5,5'</em>. The format of the string 924 * depends on the rendering engine. 925 * @param {JXG.Board} board Reference to the element's board. 926 */ 927 updatePathPrim: function (node, pathString, board) { /* stub */ }, 928 929 /** 930 * Builds a path data string to draw a point with a face other than <em>rect</em> and <em>circle</em>. Since 931 * the format of such a string usually depends on the renderer this method 932 * is only an abstract method. Therefore, it has to be implemented in the descendant renderer itself unless 933 * the renderer does not use the createPrim interface but the draw* interfaces to paint. 934 * @param {JXG.Point} element The point element 935 * @param {Number} size A positive number describing the size. Usually the half of the width and height of 936 * the drawn point. 937 * @param {String} type A string describing the point's face. This method only accepts the shortcut version of 938 * each possible face: <tt>x, +, <>, ^, v, >, < 939 */ 940 updatePathStringPoint: function (element, size, type) { /* stub */ }, 941 942 /** 943 * Builds a path data string from a {@link JXG.Curve} element. Since the path data strings heavily depend on the 944 * underlying rendering technique this method is just a stub. Although such a path string is of no use for the 945 * CanvasRenderer, this method is used there to draw a path directly. 946 * @param element 947 */ 948 updatePathStringPrim: function (element) { /* stub */ }, 949 950 /** 951 * Builds a path data string from a {@link JXG.Curve} element such that the curve looks like hand drawn. Since 952 * the path data strings heavily depend on the underlying rendering technique this method is just a stub. 953 * Although such a path string is of no use for the CanvasRenderer, this method is used there to draw a path 954 * directly. 955 * @param element 956 */ 957 updatePathStringBezierPrim: function (element) { /* stub */ }, 958 959 960 /** 961 * Update a polygon primitive. 962 * @param {Node} node 963 * @param {JXG.Polygon} element A JSXGraph element of type {@link JXG.Polygon} 964 */ 965 updatePolygonPrim: function (node, element) { /* stub */ }, 966 967 /** 968 * Update a rectangle primitive. This is used only for points with face of type 'rect'. 969 * @param {Node} node The node yearning to be updated. 970 * @param {Number} x x coordinate of the top left vertex. 971 * @param {Number} y y coordinate of the top left vertex. 972 * @param {Number} w Width of the rectangle. 973 * @param {Number} h The rectangle's height. 974 */ 975 updateRectPrim: function (node, x, y, w, h) { /* stub */ }, 976 977 /* ************************** 978 * Set Attributes 979 * **************************/ 980 981 /** 982 * Sets a node's attribute. 983 * @param {Node} node The node that is to be updated. 984 * @param {String} key Name of the attribute. 985 * @param {String} val New value for the attribute. 986 */ 987 setPropertyPrim: function (node, key, val) { /* stub */ }, 988 989 /** 990 * Shows a hidden element on the canvas; Only a stub, requires implementation in the derived renderer. 991 * @param {JXG.GeometryElement} element Reference to the object that has to appear. 992 * @see JXG.AbstractRenderer#hide 993 */ 994 show: function (element) { /* stub */ }, 995 996 /** 997 * Hides an element on the canvas; Only a stub, requires implementation in the derived renderer. 998 * @param {JXG.GeometryElement} element Reference to the geometry element that has to disappear. 999 * @see JXG.AbstractRenderer#show 1000 */ 1001 hide: function (element) { /* stub */ }, 1002 1003 /** 1004 * Sets the buffering as recommended by SVGWG. Until now only Opera supports this and will be ignored by other 1005 * browsers. Although this feature is only supported by SVG we have this method in {@link JXG.AbstractRenderer} 1006 * because it is called from outside the renderer. 1007 * @param {Node} node The SVG DOM Node which buffering type to update. 1008 * @param {String} type Either 'auto', 'dynamic', or 'static'. For an explanation see 1009 * {@link http://www.w3.org/TR/SVGTiny12/painting.html#BufferedRenderingProperty}. 1010 */ 1011 setBuffering: function (node, type) { /* stub */ }, 1012 1013 /** 1014 * Sets an element's dash style. 1015 * @param {JXG.GeometryElement} element An JSXGraph element. 1016 */ 1017 setDashStyle: function (element) { /* stub */ }, 1018 1019 /** 1020 * Puts an object into draft mode, i.e. it's visual appearance will be changed. For GEONE<sub>x</sub>T backwards 1021 * compatibility. 1022 * @param {JXG.GeometryElement} element Reference of the object that is in draft mode. 1023 */ 1024 setDraft: function (element) { 1025 if (!element.visProp.draft) { 1026 return; 1027 } 1028 var draftColor = element.board.options.elements.draft.color, 1029 draftOpacity = element.board.options.elements.draft.opacity; 1030 1031 if (element.type === Const.OBJECT_TYPE_POLYGON) { 1032 this.setObjectFillColor(element, draftColor, draftOpacity); 1033 } else { 1034 if (element.elementClass === Const.OBJECT_CLASS_POINT) { 1035 this.setObjectFillColor(element, draftColor, draftOpacity); 1036 } else { 1037 this.setObjectFillColor(element, 'none', 0); 1038 } 1039 this.setObjectStrokeColor(element, draftColor, draftOpacity); 1040 this.setObjectStrokeWidth(element, element.board.options.elements.draft.strokeWidth); 1041 } 1042 }, 1043 1044 /** 1045 * Puts an object from draft mode back into normal mode. 1046 * @param {JXG.GeometryElement} element Reference of the object that no longer is in draft mode. 1047 */ 1048 removeDraft: function (element) { 1049 if (element.type === Const.OBJECT_TYPE_POLYGON) { 1050 this.setObjectFillColor(element, element.visProp.fillcolor, element.visProp.fillopacity); 1051 } else { 1052 if (element.type === Const.OBJECT_CLASS_POINT) { 1053 this.setObjectFillColor(element, element.visProp.fillcolor, element.visProp.fillopacity); 1054 } 1055 this.setObjectStrokeColor(element, element.visProp.strokecolor, element.visProp.strokeopacity); 1056 this.setObjectStrokeWidth(element, element.visProp.strokewidth); 1057 } 1058 }, 1059 1060 /** 1061 * Sets up nodes for rendering a gradient fill. 1062 * @param element 1063 */ 1064 setGradient: function (element) { /* stub */ }, 1065 1066 /** 1067 * Updates the gradient fill. 1068 * @param {JXG.GeometryElement} element An JSXGraph element with an area that can be filled. 1069 */ 1070 updateGradient: function (element) { /* stub */ }, 1071 1072 /** 1073 * Sets an objects fill color. 1074 * @param {JXG.GeometryElement} element Reference of the object that wants a new fill color. 1075 * @param {String} color Color in a HTML/CSS compatible format. If you don't want any fill color at all, choose 1076 * 'none'. 1077 * @param {Number} opacity Opacity of the fill color. Must be between 0 and 1. 1078 */ 1079 setObjectFillColor: function (element, color, opacity) { /* stub */ }, 1080 1081 /** 1082 * Changes an objects stroke color to the given color. 1083 * @param {JXG.GeometryElement} element Reference of the {@link JXG.GeometryElement} that gets a new stroke 1084 * color. 1085 * @param {String} color Color value in a HTML compatible format, e.g. <strong>#00ff00</strong> or 1086 * <strong>green</strong> for green. 1087 * @param {Number} opacity Opacity of the fill color. Must be between 0 and 1. 1088 */ 1089 setObjectStrokeColor: function (element, color, opacity) { /* stub */ }, 1090 1091 /** 1092 * Sets an element's stroke width. 1093 * @param {JXG.GeometryElement} element Reference to the geometry element. 1094 * @param {Number} width The new stroke width to be assigned to the element. 1095 */ 1096 setObjectStrokeWidth: function (element, width) { /* stub */ }, 1097 1098 /** 1099 * Sets the shadow properties to a geometry element. This method is only a stub, it is implemented in the actual 1100 * renderers. 1101 * @param {JXG.GeometryElement} element Reference to a geometry object, that should get a shadow 1102 */ 1103 setShadow: function (element) { /* stub */ }, 1104 1105 /** 1106 * Highlights an object, i.e. changes the current colors of the object to its highlighting colors 1107 * @param {JXG.GeometryElement} element Reference of the object that will be highlighted. 1108 * @returns {JXG.AbstractRenderer} Reference to the renderer 1109 * @see JXG.AbstractRenderer#updateTextStyle 1110 */ 1111 highlight: function (element) { 1112 var i, ev = element.visProp; 1113 1114 if (!ev.draft) { 1115 if (element.type === Const.OBJECT_TYPE_POLYGON) { 1116 this.setObjectFillColor(element, ev.highlightfillcolor, ev.highlightfillopacity); 1117 for (i = 0; i < element.borders.length; i++) { 1118 this.setObjectStrokeColor(element.borders[i], element.borders[i].visProp.highlightstrokecolor, 1119 element.borders[i].visProp.highlightstrokeopacity); 1120 } 1121 } else { 1122 if (element.type === Const.OBJECT_TYPE_TEXT) { 1123 this.updateTextStyle(element, true); 1124 } else if (element.type === Const.OBJECT_TYPE_IMAGE) { 1125 this.updateImageStyle(element, true); 1126 } else { 1127 this.setObjectStrokeColor(element, ev.highlightstrokecolor, ev.highlightstrokeopacity); 1128 this.setObjectFillColor(element, ev.highlightfillcolor, ev.highlightfillopacity); 1129 } 1130 } 1131 if (ev.highlightstrokewidth) { 1132 this.setObjectStrokeWidth(element, Math.max(ev.highlightstrokewidth, ev.strokewidth)); 1133 } 1134 } 1135 1136 return this; 1137 }, 1138 1139 /** 1140 * Uses the normal colors of an object, i.e. the opposite of {@link JXG.AbstractRenderer#highlight}. 1141 * @param {JXG.GeometryElement} element Reference of the object that will get its normal colors. 1142 * @returns {JXG.AbstractRenderer} Reference to the renderer 1143 * @see JXG.AbstractRenderer#updateTextStyle 1144 */ 1145 noHighlight: function (element) { 1146 var i, ev = element.visProp; 1147 1148 if (!element.visProp.draft) { 1149 if (element.type === Const.OBJECT_TYPE_POLYGON) { 1150 this.setObjectFillColor(element, ev.fillcolor, ev.fillopacity); 1151 for (i = 0; i < element.borders.length; i++) { 1152 this.setObjectStrokeColor(element.borders[i], element.borders[i].visProp.strokecolor, 1153 element.borders[i].visProp.strokeopacity); 1154 } 1155 } else { 1156 if (element.type === Const.OBJECT_TYPE_TEXT) { 1157 this.updateTextStyle(element, false); 1158 } else if (element.type === Const.OBJECT_TYPE_IMAGE) { 1159 this.updateImageStyle(element, false); 1160 } else { 1161 this.setObjectStrokeColor(element, ev.strokecolor, ev.strokeopacity); 1162 this.setObjectFillColor(element, ev.fillcolor, ev.fillopacity); 1163 } 1164 } 1165 this.setObjectStrokeWidth(element, ev.strokewidth); 1166 } 1167 1168 return this; 1169 }, 1170 1171 /* ************************** 1172 * renderer control 1173 * **************************/ 1174 1175 /** 1176 * Stop redraw. This method is called before every update, so a non-vector-graphics based renderer can use this 1177 * method to delete the contents of the drawing panel. This is an abstract method every descendant renderer 1178 * should implement, if appropriate. 1179 * @see JXG.AbstractRenderer#unsuspendRedraw 1180 */ 1181 suspendRedraw: function () { /* stub */ }, 1182 1183 /** 1184 * Restart redraw. This method is called after updating all the rendering node attributes. 1185 * @see JXG.AbstractRenderer#suspendRedraw 1186 */ 1187 unsuspendRedraw: function () { /* stub */ }, 1188 1189 /** 1190 * The tiny zoom bar shown on the bottom of a board (if showNavigation on board creation is true). 1191 * @param {JXG.Board} board Reference to a JSXGraph board. 1192 */ 1193 drawZoomBar: function (board) { 1194 var doc, 1195 node, 1196 cancelbubble = function (e) { 1197 if (!e) { 1198 e = window.event; 1199 } 1200 1201 if (e.stopPropagation) { 1202 // Non IE<=8 1203 e.stopPropagation(); 1204 } else { 1205 e.cancelBubble = true; 1206 } 1207 }, 1208 createButton = function (label, handler) { 1209 var button; 1210 1211 button = doc.createElement('span'); 1212 node.appendChild(button); 1213 button.appendChild(document.createTextNode(label)); 1214 Env.addEvent(button, 'click', handler, board); 1215 1216 // prevent the click from bubbling down to the board 1217 Env.addEvent(button, 'mouseup', cancelbubble, board); 1218 Env.addEvent(button, 'mousedown', cancelbubble, board); 1219 Env.addEvent(button, 'touchend', cancelbubble, board); 1220 Env.addEvent(button, 'touchstart', cancelbubble, board); 1221 }; 1222 1223 if (Env.isBrowser) { 1224 doc = board.containerObj.ownerDocument; 1225 node = doc.createElement('div'); 1226 1227 node.setAttribute('id', board.containerObj.id + '_navigationbar'); 1228 1229 node.style.color = board.options.navbar.strokeColor; 1230 node.style.backgroundColor = board.options.navbar.fillColor; 1231 node.style.padding = board.options.navbar.padding; 1232 node.style.position = board.options.navbar.position; 1233 node.style.fontSize = board.options.navbar.fontSize; 1234 node.style.cursor = board.options.navbar.cursor; 1235 node.style.zIndex = board.options.navbar.zIndex; 1236 board.containerObj.appendChild(node); 1237 node.style.right = board.options.navbar.right; 1238 node.style.bottom = board.options.navbar.bottom; 1239 1240 // For XHTML we need unicode instead of HTML entities 1241 1242 if (board.attr.showreload) { 1243 // full reload circle: \u27F2 1244 // the board.reload() method does not exist during the creation 1245 // of this button. That's why this anonymous function wrapper is required. 1246 createButton('\u00A0\u21BB\u00A0', function () { 1247 board.reload(); 1248 }); 1249 } 1250 1251 createButton('\u00A0\u2013\u00A0', board.zoomOut); 1252 createButton('\u00A0o\u00A0', board.zoom100); 1253 createButton('\u00A0+\u00A0', board.zoomIn); 1254 createButton('\u00A0\u2190\u00A0', board.clickLeftArrow); 1255 createButton('\u00A0\u2193\u00A0', board.clickUpArrow); 1256 createButton('\u00A0\u2191\u00A0', board.clickDownArrow); 1257 createButton('\u00A0\u2192\u00A0', board.clickRightArrow); 1258 } 1259 }, 1260 1261 /** 1262 * Wrapper for getElementById for maybe other renderers which elements are not directly accessible by DOM 1263 * methods like document.getElementById(). 1264 * @param {String} id Unique identifier for element. 1265 * @returns {Object} Reference to a JavaScript object. In case of SVG/VMLRenderer it's a reference to a SVG/VML 1266 * node. 1267 */ 1268 getElementById: function (id) { 1269 return document.getElementById(this.container.id + '_' + id); 1270 }, 1271 1272 /** 1273 * Remove an element and provide a function that inserts it into its original position. This method 1274 * is taken from this article {@link https://developers.google.com/speed/articles/javascript-dom}. 1275 * @author KeeKim Heng, Google Web Developer 1276 * @param {Element} element The element to be temporarily removed 1277 * @returns {Function} A function that inserts the element into its original position 1278 */ 1279 removeToInsertLater: function (element) { 1280 var parentNode = element.parentNode, 1281 nextSibling = element.nextSibling; 1282 1283 parentNode.removeChild(element); 1284 1285 return function () { 1286 if (nextSibling) { 1287 parentNode.insertBefore(element, nextSibling); 1288 } else { 1289 parentNode.appendChild(element); 1290 } 1291 }; 1292 }, 1293 1294 /** 1295 * Resizes the rendering element 1296 * @param {Number} w New width 1297 * @param {Number} h New height 1298 */ 1299 resize: function (w, h) { /* stub */}, 1300 1301 /** 1302 * Create crosshair elements (Fadenkreuz) for presentations. 1303 * @param {Number} n Number of crosshairs. 1304 */ 1305 createTouchpoints: function (n) {}, 1306 1307 /** 1308 * Show a specific crosshair. 1309 * @param {Number} i Number of the crosshair to show 1310 */ 1311 showTouchpoint: function (i) {}, 1312 1313 /** 1314 * Hide a specific crosshair. 1315 * @param {Number} i Number of the crosshair to show 1316 */ 1317 hideTouchpoint: function (i) {}, 1318 1319 /** 1320 * Move a specific crosshair. 1321 * @param {Number} i Number of the crosshair to show 1322 * @param {Array} pos New positon in screen coordinates 1323 */ 1324 updateTouchpoint: function (i, pos) {} 1325 }); 1326 1327 return JXG.AbstractRenderer; 1328 }); 1329