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