Subversion Repositories wimsdev

Rev

Blame | Last modification | View Log | RSS feed

  1. /*
  2.     Copyright 2008 - 2011
  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: you can redistribute it and/or modify
  13.     it under the terms of the GNU Lesser General Public License as published by
  14.     the Free Software Foundation, either version 3 of the License, or
  15.     (at your option) any later version.
  16.  
  17.     JSXGraph is distributed in the hope that it will be useful,
  18.     but WITHOUT ANY WARRANTY; without even the implied warranty of
  19.     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  20.     GNU Lesser General Public License for more details.
  21.  
  22.     You should have received a copy of the GNU Lesser General Public License
  23.     along with JSXGraph.  If not, see <http://www.gnu.org/licenses/>.
  24. */
  25. JXG.GeonextReader = {
  26.  
  27.     changeOriginIds: function (board, id) {
  28.         if ((id == 'gOOe0') || (id == 'gXOe0') || (id == 'gYOe0') || (id == 'gXLe0') || (id == 'gYLe0')) {
  29.             return board.id + id;
  30.         } else {
  31.             return id;
  32.         }
  33.     },
  34.  
  35.     /**
  36.      * Retrieves data by TagName from an XML node.
  37.      * @param {Node} node The Node that contains the data we want to get.
  38.      * @param {String} tag The Name of the tag we are looking for.
  39.      * @param {Number} [idx=0] getElementsByTagName returns an array; This parameter decides which element to use.
  40.      * @param {Boolean} [fc=true] If True, the result will be the <tt>data</tt> of <tt>firstChild</tt> instead of the result node.
  41.      * @returns {String} The gathered data
  42.      */
  43.     gEBTN: function (node, tag, idx, fc) {
  44.         var tmp;
  45.  
  46.         if (!JXG.exists(node || !node.getElementsByTagName )/* || !JXG.exists(node.getElementsByTagName)*/) {
  47.             return '';
  48.         }
  49.         // Default values for optional parameters idx and fc
  50.         if (!JXG.exists(fc)) {
  51.             fc = true;
  52.         }
  53.         idx = idx || 0;
  54.         tmp = node.getElementsByTagName(tag);
  55.         if (tmp.length > 0) {
  56.             tmp = tmp[idx];
  57.             if (fc && tmp.firstChild) {
  58.                 tmp = tmp.firstChild.data;
  59.             }
  60.         }
  61.         return tmp;
  62.     },
  63.  
  64.     /**
  65.      * Set color properties of a geonext element.
  66.      * Set stroke, fill, lighting, label and draft color attributes.
  67.      * @param {Object} gxtEl element of which attributes are to set
  68.      */
  69.     colorProperties: function (gxtEl, Data) {
  70.         var color = this.gEBTN(Data, 'color', 0, false),
  71.             rgbo;
  72.  
  73.         //gxtEl.strokewidth = Data.getElementsByTagName('strokewidth')[0].firstChild.data;
  74.         // colorStroke = strokeColor etc. is here for downwards compatibility:
  75.         // once upon a time we used to create elements in here using the "new JXG.Element" constructor mechanism
  76.         // then we changed to board.create + setProperty afterwords
  77.         // now i want to use the board.create method with an appropriate attributes object to avoid setProperty calls
  78.         // and as gxtEl happens to be somewhat like an attributes object it's  just slightly different so we adjust it
  79.         // for downwards compatibility during the transformation of this reader we use both properties
  80.  
  81.         rgbo = JXG.rgba2rgbo(this.gEBTN(color, 'stroke'));
  82.         gxtEl.strokeColor = rgbo[0];
  83.         gxtEl.strokeOpacity = rgbo[1];
  84.  
  85.         rgbo = JXG.rgba2rgbo(this.gEBTN(color, 'lighting'));
  86.         gxtEl.highlightStrokeColor = rgbo[0];
  87.         gxtEl.highlightStrokeOpacity = rgbo[1];
  88.  
  89.         rgbo = JXG.rgba2rgbo(this.gEBTN(color, 'fill'));
  90.         gxtEl.fillColor = rgbo[0];
  91.         gxtEl.fillOpacity = rgbo[1];
  92.  
  93.         gxtEl.highlightFillColor = gxtEl.fillColor;
  94.         gxtEl.highlightFillOpacity = gxtEl.fillOpacity;
  95.  
  96.         gxtEl.labelColor = JXG.rgba2rgbo(this.gEBTN(color, 'label'))[0];
  97.         gxtEl.colorDraft = JXG.rgba2rgbo(this.gEBTN(color, 'draft'))[0];
  98.  
  99.         // GEONExT hides labels by setting opacity to 0.
  100.         if (JXG.rgba2rgbo(this.gEBTN(color, 'label'))[1]==0) {
  101.             gxtEl.withLabel = false;
  102.         }
  103.        
  104.         // backwards compatibility
  105.         gxtEl.colorStroke = gxtEl.strokeColor;
  106.         gxtEl.colorFill = gxtEl.fillColor;
  107.         gxtEl.colorLabel = gxtEl.labelColor;
  108.  
  109.         return gxtEl;
  110.     },
  111.  
  112.     firstLevelProperties: function (gxtEl, Data) {
  113.         if (!JXG.exists(Data) || !JXG.exists(Data.childNodes))
  114.             return gxtEl;
  115.        
  116.         var arr = Data.childNodes, n, key;
  117.  
  118.         for (n = 0; n < arr.length; n++) {
  119.             if (JXG.exists(arr[n].firstChild) && arr[n].nodeName !== 'data' && arr[n].nodeName !== 'straight') {
  120.                 key = arr[n].nodeName;
  121.                 gxtEl[key] = arr[n].firstChild.data;
  122.             }
  123.         }
  124.        
  125.         return gxtEl;
  126.     },
  127.  
  128.     /**
  129.      * Set the defining properties of a geonext element.
  130.      * Writing the nodeName to ident; setting the name attribute and defining the element id.
  131.      * @param {Object} gxtEl element of which attributes are to set
  132.      */
  133.     defProperties: function (gxtEl, Data) {
  134.         // 3==TEXT_NODE, 8==COMMENT_NODE
  135.         if (Data.nodeType==3 || Data.nodeType==8 ) {
  136.             return null;
  137.         }
  138.  
  139.         gxtEl.ident = Data.nodeName;
  140.        
  141.         if(gxtEl.ident == "text" || gxtEl.ident == "intersection" || gxtEl.ident == "composition") {
  142.             gxtEl.name = '';
  143.         } else {
  144.             gxtEl.name = this.gEBTN(Data, 'name');
  145.         }
  146.        
  147.         gxtEl.id = this.gEBTN(Data, 'id');
  148.  
  149.         return gxtEl;
  150.     },
  151.  
  152.     visualProperties: function (gxtEl, Data) {
  153.         gxtEl.visible = JXG.str2Bool(this.gEBTN(Data, 'visible'));
  154.         gxtEl.trace = JXG.str2Bool(this.gEBTN(Data, 'trace'));
  155.        
  156.         return gxtEl;
  157.     },
  158.  
  159.     transformProperties: function (gxtEl, type) {
  160.         var facemap = [
  161.                 // 0-2
  162.                 'cross', 'cross', 'cross',
  163.                 // 3-6
  164.                 'circle', 'circle', 'circle', 'circle',
  165.                 // 7-9
  166.                 'square', 'square', 'square',
  167.                 // 10-12
  168.                 'plus', 'plus', 'plus'
  169.             ], sizemap = [
  170.                 // 0-2
  171.                 2, 3, 4,
  172.                 // 3-6
  173.                 1, 2, 3, 4,
  174.                 // 7-9
  175.                 2, 3, 4,
  176.                 // 10-12
  177.                 2, 3, 4
  178.             ];
  179.  
  180.         gxtEl.strokeWidth = gxtEl.strokewidth;
  181.         gxtEl.face = facemap[parseInt(gxtEl.style, 10)] || 'cross';
  182.         gxtEl.size = sizemap[parseInt(gxtEl.style, 10)] || 3;
  183.  
  184.         gxtEl.straightFirst = JXG.str2Bool(gxtEl.straightFirst);
  185.         gxtEl.straightLast = JXG.str2Bool(gxtEl.straightLast);
  186.  
  187.         gxtEl.visible = JXG.str2Bool(gxtEl.visible);
  188.         //gxtEl.withLabel = gxtEl.visible;           // withLabel is set in colorProperties()
  189.         gxtEl.draft = JXG.str2Bool(gxtEl.draft);
  190.         gxtEl.trace = JXG.str2Bool(gxtEl.trace);
  191.        
  192.         if (type==='point') {
  193.             // Fill properties are ignored by GEONExT
  194.             gxtEl.fillColor = gxtEl.strokeColor;
  195.             gxtEl.highlightFillColor = gxtEl.highlightStrokeColor;
  196.             gxtEl.fillOpacity = gxtEl.strokeOpacity;
  197.             gxtEl.highlightFillOpacity = gxtEl.highlightStrokeOpacity;
  198.         }
  199.  
  200.         delete gxtEl.color;
  201.         return gxtEl;
  202.     },
  203.  
  204.     readNodes: function (gxtEl, Data, nodeType, prefix) {
  205.         var arr = this.gEBTN(Data, nodeType, 0, false).childNodes,
  206.             key, n;
  207.  
  208.         for (n = 0; n < arr.length; n++) {
  209.             if (arr[n].firstChild != null) {
  210.                 if (prefix != null) {
  211.                     key = prefix + JXG.capitalize(arr[n].nodeName);
  212.                 } else {
  213.                     key = arr[n].nodeName;
  214.                 }
  215.                 gxtEl[key] = arr[n].firstChild.data;
  216.             }
  217.         }
  218.         return gxtEl;
  219.     },
  220.  
  221.     subtreeToString: function (root) {
  222.         try {
  223.             // firefox
  224.             return (new XMLSerializer()).serializeToString(root);
  225.         } catch (e) {
  226.             // IE
  227.             return root.xml;
  228.         }
  229.     },
  230.  
  231.     readImage: function (node) {
  232.         var pic = '',
  233.             nod = node;
  234.  
  235.         if (nod != null) {
  236.             pic = nod.data;
  237.             while (nod.nextSibling != null) {
  238.                 nod = nod.nextSibling;
  239.                 pic += nod.data;
  240.             }
  241.         }
  242.         return pic;
  243.     },
  244.  
  245.     parseImage: function (board, fileNode, level, x, y, w, h, el) {
  246.         var tag, id, im, picStr, tmpImg;
  247.  
  248.         if (fileNode == null) {
  249.             return null;
  250.         }
  251.  
  252.         if (fileNode.getElementsByTagName('src')[0] != null) {  // Background image
  253.             tag = 'src';
  254.         } else if (fileNode.getElementsByTagName('image')[0] != null) {
  255.             tag = 'image';
  256.         } else {
  257.             return null;
  258.         }
  259.  
  260.         picStr = this.readImage(this.gEBTN(fileNode, tag, 0, false).firstChild);
  261.         if (picStr!='') {
  262.             picStr = 'data:image/png;base64,' + picStr;
  263.             if (tag=='src') {  // Background image
  264.                 x = this.gEBTN(fileNode, 'x');
  265.                 y = this.gEBTN(fileNode, 'y');
  266.                 w = this.gEBTN(fileNode, 'width');
  267.                 h = this.gEBTN(fileNode, 'height');
  268.                 im = board.create('image', [picStr,[x, y],[w, h]], {
  269.                         anchor: el, layer: level
  270.                         });
  271.                 return im;
  272.             } else {
  273.                 // Image bound to an element
  274.                 // Read the original dimensions, i.e. the ratio h/w with the help of a temporary image.
  275.                 // We have to wait until the image is loaded, therefore
  276.                 // we need "onload".
  277.                 tmpImg = new Image();
  278.                 tmpImg.src = picStr;
  279.                 id = el.id + '_image';
  280.                 tmpImg.onload = function(){
  281.                     // Now, we can read the original dimensions of the image.
  282.                     var wOrg = this.width,
  283.                         hOrg = this.height,
  284.                         xf, yf, wf, hf, im, tRot;
  285.                        
  286.                     if (el.elementClass == JXG.OBJECT_CLASS_LINE) {
  287.                         // A line containing an image, runs through the horizontal middle
  288.                         // of the image.
  289.                         xf = function(){ return el.point1.X(); };
  290.                         wf = function(){ return el.point1.Dist(el.point2); };
  291.                         hf = function(){ return wf() * hOrg / wOrg; };
  292.                         yf = function(){ return el.point1.Y() - hf() * 0.5; };
  293.                         im = board.create('image', [picStr, [xf,yf], [wf,hf]], {
  294.                                 layer: level,
  295.                                 id: id,
  296.                                 anchor: el
  297.                             });
  298.                         tRot = board.create('transform', [
  299.                                 function () {
  300.                                     return Math.atan2(el.point2.Y()-el.point1.Y(), el.point2.X()-el.point1.X())
  301.                                 },
  302.                                 el.point1
  303.                             ], {
  304.                                 type:'rotate'
  305.                             });
  306.                         tRot.bindTo(im);
  307.                         el.image = im;
  308.                     } else if (el.elementClass == JXG.OBJECT_CLASS_POINT) {
  309.                         wf = function(){ return wOrg / board.unitX; };
  310.                         hf = function(){ return hOrg / board.unitY; };
  311.                         xf = function(){ return el.X() - wf() * 0.5; };
  312.                         yf = function(){ return el.Y() - hf() * 0.5; };
  313.  
  314.                         im = board.create('image', [picStr, [xf,yf], [wf,hf]], {
  315.                                 layer: level,
  316.                                 id: id,
  317.                                 anchor: el
  318.                             });
  319.                         board.renderer.hide(el.label.content);
  320.                         el.image = im;
  321.                     } else if (el.elementClass == JXG.OBJECT_CLASS_CIRCLE) {
  322.                         // A circle containing an image
  323.                         wf = function(){ return 2.0 * el.Radius(); };
  324.                         hf = function(){ return wf() * hOrg / wOrg; };
  325.                         xf = function(){ return el.midpoint.X() - wf() * 0.5; };
  326.                         yf = function(){ return el.midpoint.Y() - hf() * 0.5; };
  327.                         im = board.create('image', [picStr, [xf,yf], [wf,hf]], {
  328.                             layer: level,
  329.                             id: id,
  330.                             anchor: el
  331.                         });
  332.                         el.image = im;
  333.                     } else {
  334.                         im = board.create('image', [picStr, [x, y], [w, h]], {
  335.                             layer: level,
  336.                             id: id,
  337.                             anchor: el
  338.                         });
  339.                         el.image = im;
  340.                     }
  341.                 };
  342.             }
  343.             return im;
  344.         }
  345.     },
  346.  
  347.     readConditions: function(node) {
  348.         var i, s, ob,
  349.             conditions = '';
  350.  
  351.         if (JXG.exists(node)) {
  352.             for(i = 0; i < node.getElementsByTagName('data').length; i++) {
  353.                 ob = node.getElementsByTagName('data')[i];
  354.                 s = this.subtreeToString(ob);
  355.                 conditions += s;
  356.             }
  357.         }
  358.  
  359.         return conditions;
  360.     },
  361.  
  362.     printDebugMessage: function(outputEl,gxtEl,nodetyp,success) {
  363.         JXG.debug("* " + success + ":  " + nodetyp + " " + gxtEl.name + " " + gxtEl.id + "<br>\n");
  364.     },
  365.  
  366.     /**
  367.      * Reading the elements of a geonext file
  368.      * @param {XMLTree} tree expects the content of the parsed geonext file returned by function parseFF/parseIE
  369.      * @param {Object} board board object
  370.      */
  371.     readGeonext: function(tree, board) {
  372.         var xmlNode, elChildNodes,
  373.             s, Data, inter, boardData, el,
  374.             conditions, tmp, strTrue = 'true', gxtReader = this;
  375.  
  376.         // maybe this is not necessary as we already provide layer options for sectors and circles via JXG.Options but
  377.         // maybe these have to be the same for geonext.
  378.         board.options.layer.sector = board.options.layer.angle;
  379.         board.options.layer.circle = board.options.layer.angle;
  380.  
  381.         boardData = this.gEBTN(tree, 'board', 0, false);
  382.         conditions = this.readConditions(boardData.getElementsByTagName('conditions')[0]);
  383.  
  384.         // set the origin
  385.         xmlNode = this.gEBTN(boardData, 'coordinates', 0, false);
  386.         tmp = this.gEBTN(xmlNode, 'origin', 0, false);
  387.         board.origin = {
  388.             usrCoords: [1, 0, 0],
  389.             scrCoords: [1, parseFloat(this.gEBTN(tmp, 'x')), parseFloat(this.gEBTN(tmp, 'y'))]
  390.         };
  391.  
  392.         // zoom level
  393.         tmp = this.gEBTN(xmlNode, 'zoom', 0, false);
  394.         board.zoomX = parseFloat(this.gEBTN(tmp, 'x'));
  395.         board.zoomY = parseFloat(this.gEBTN(tmp, 'y'));
  396.  
  397.         // screen to user coordinates conversion
  398.         tmp = this.gEBTN(xmlNode, 'unit', 0, false);
  399.         board.unitX = parseFloat(this.gEBTN(tmp, 'x'));
  400.         board.unitY = parseFloat(this.gEBTN(tmp, 'y'));
  401.  
  402.         // resize board
  403.         if (board.options.takeSizeFromFile) {
  404.             board.resizeContainer(this.gEBTN(boardData, 'width'), this.gEBTN(boardData, 'height'));
  405.         }
  406.  
  407.         // check and set fontSize
  408.         if (!(parseFloat(board.options.text.fontSize) > 0)) {
  409.             board.options.text.fontSize = 12;
  410.         }
  411.  
  412.         board.geonextCompatibilityMode = true;
  413.  
  414.         // jsxgraph chooses an id for the board but we don't want to use it, we want to use
  415.         // the id stored in the geonext file. if you know why this is required, please note it here.
  416.         delete(JXG.JSXGraph.boards[board.id]);
  417.         board.id = this.gEBTN(boardData, 'id');
  418.         JXG.JSXGraph.boards[board.id] = board;
  419.  
  420.         // this creates some basic elements present in every geonext construction but not explicitly present in the file
  421.         board.initGeonextBoard();
  422.        
  423.         // Update of properties during update() is not necessary in GEONExT files
  424.         // But it maybe necessary if we construct with JavaScript afterwards
  425.         board.renderer.enhancedRendering = true;
  426.  
  427.         // Read background image
  428.         this.parseImage(board, this.gEBTN(boardData, 'file', 0, false), board.options.layer['image']);
  429.  
  430.         board.options.grid.snapToGrid = (this.gEBTN(this.gEBTN(boardData, 'coordinates', 0, false), 'snap') == strTrue);
  431.         //
  432.         // TODO: Missing jsxgraph feature snapToPoint
  433.         // If snapToGrid and snapToPoint are both true, point snapping is enabled
  434.         if (board.options.grid.snapToGrid && this.gEBTN(this.gEBTN(boardData, 'grid', 1, false), 'pointsnap') == strTrue) {
  435.             board.options.grid.snapToGrid = false;
  436.         }
  437. //board.options.grid.snapToGrid = false;
  438.  
  439.         xmlNode = this.gEBTN(boardData, 'grid', 1, false);
  440.         tmp = this.gEBTN(xmlNode,  'x');
  441.         if (tmp) {
  442.             board.options.grid.gridX = 1 / parseFloat(tmp);
  443.             board.options.grid.snapSizeX = parseFloat(tmp);
  444.         }
  445.         tmp = this.gEBTN(xmlNode,  'y');
  446.         if (tmp) {
  447.             board.options.grid.gridY = 1 / parseFloat(tmp);
  448.             board.options.grid.snapSizeY = parseFloat(tmp);
  449.         }
  450.         //board.calculateSnapSizes();             // Seems not to be correct
  451.         board.options.grid.gridDash = JXG.str2Bool(this.gEBTN(xmlNode, 'dash'));
  452.  
  453.         tmp = JXG.rgba2rgbo(this.gEBTN(xmlNode, 'color'));
  454.         board.options.grid.gridColor = tmp[0];
  455.         board.options.grid.gridOpacity = tmp[1];
  456.  
  457.         xmlNode = this.gEBTN(boardData, 'coordinates', 0, false);
  458.         if (this.gEBTN(xmlNode, 'grid') == strTrue) {
  459.             board.create('grid', []);
  460.         }
  461.  
  462.         if (this.gEBTN(xmlNode, 'coord') == strTrue) {
  463.             board.options.axis.ticks.majorHeight = 10;        // Hard coded default option
  464.             board.options.axis.ticks.minorHeight = 4;         // Hard coded default option
  465.             board.create('axis', [[0, 0], [1, 0]]);
  466.             board.create('axis', [[0, 0], [0, 1]]);
  467.         }
  468.  
  469.         board.containerObj.style.backgroundColor = JXG.rgba2rgbo(this.gEBTN(this.gEBTN(boardData, 'background', 0, false), 'color'))[0];
  470.  
  471.         elChildNodes = tree.getElementsByTagName("elements")[0].childNodes;
  472.         for (s = 0; s < elChildNodes.length; s++) {
  473.             (function (s) {
  474.                 var i, gxtEl = {},
  475.                     l, x, y, w, h, c, numberDefEls,
  476.                     el, p, inter, rgbo, tmp;
  477.  
  478.                 Data = elChildNodes[s];
  479.                 gxtEl = gxtReader.defProperties(gxtEl, Data);
  480.  
  481.                 // Skip text nodes
  482.                 if (!JXG.exists(gxtEl)) {
  483.                     return;
  484.                 }
  485.  
  486.                 gxtReader.printDebugMessage('debug', gxtEl, Data.nodeName.toLowerCase, 'READ:');
  487.                 switch (Data.nodeName.toLowerCase()) {
  488.                     case "point":
  489.                         gxtEl = gxtReader.colorProperties(gxtEl, Data);
  490.                         gxtEl = gxtReader.visualProperties(gxtEl, Data);
  491.                         gxtEl = gxtReader.firstLevelProperties(gxtEl, Data);
  492.                         gxtEl = gxtReader.readNodes(gxtEl, Data, 'data');
  493.                         gxtEl.fixed = JXG.str2Bool(gxtReader.gEBTN(Data, 'fix'));
  494.                         gxtEl = gxtReader.transformProperties(gxtEl, 'point');
  495.                        
  496.                         //try {
  497.                             p = board.create('point', [parseFloat(gxtEl.x), parseFloat(gxtEl.y)], gxtEl);
  498.  
  499.                             var v = function(){ return p.visProp.visible; };
  500.                             el = gxtReader.parseImage(board, Data, board.options.layer['image'], 0, 0, 0, 0, p);
  501.                             gxtReader.printDebugMessage('debug', gxtEl, Data.nodeName, 'OK');
  502.                         /*
  503.                         if (JXG.exists(el)) {
  504.                             el.visProp.visible = function() { return p.visProp.visible; };
  505.                             alert(p.visProp.visible);
  506.                             if (el.visProp.visible()) {el.showElement();} else {el.hideElement();}
  507.                         }
  508.                         */
  509.                         //} catch(e) {
  510.                         //    JXG.debug(e);
  511.                         //}
  512.                         break;
  513.                     case "line":
  514.                         gxtEl = gxtReader.colorProperties(gxtEl, Data);
  515.                         gxtEl = gxtReader.visualProperties(gxtEl, Data);
  516.                         gxtEl = gxtReader.firstLevelProperties(gxtEl, Data);
  517.                         gxtEl = gxtReader.readNodes(gxtEl, Data, 'data');
  518.                         gxtEl = gxtReader.readNodes(gxtEl, Data, 'straight', 'straight');
  519.                         gxtEl = gxtReader.transformProperties(gxtEl);
  520.  
  521.                         gxtEl.first = gxtReader.changeOriginIds(board, gxtEl.first);
  522.                         gxtEl.last = gxtReader.changeOriginIds(board, gxtEl.last);
  523.  
  524.                         l = board.create('line', [gxtEl.first, gxtEl.last], gxtEl);
  525.  
  526.                         gxtReader.parseImage(board, Data, board.options.layer['image'], 0, 0, 0, 0, l);
  527.                         gxtReader.printDebugMessage('debug', gxtEl, Data.nodeName, 'OK');
  528.                         break;
  529.                     case "circle":
  530.                         gxtEl = gxtReader.colorProperties(gxtEl, Data);
  531.                         gxtEl = gxtReader.visualProperties(gxtEl, Data);
  532.                         gxtEl = gxtReader.firstLevelProperties(gxtEl, Data);
  533.  
  534.                         tmp = gxtReader.gEBTN(Data, 'data', 0, false);
  535.                         gxtEl.midpoint = gxtReader.changeOriginIds(board, gxtReader.gEBTN(tmp, 'midpoint'));
  536.  
  537.                         if (tmp.getElementsByTagName('radius').length > 0) {
  538.                             gxtEl.radius = gxtReader.changeOriginIds(board, gxtReader.gEBTN(tmp, 'radius'));
  539.                         } else if (tmp.getElementsByTagName('radiusvalue').length > 0) {
  540.                             gxtEl.radius = gxtReader.gEBTN(tmp, 'radiusvalue');
  541.                         }
  542.                         gxtEl = gxtReader.transformProperties(gxtEl);
  543.                         c = board.create('circle', [gxtEl.midpoint, gxtEl.radius], gxtEl);
  544.  
  545.                         gxtReader.parseImage(board, Data, board.options.layer['image'], 0, 0, 0, 0, c);
  546.                         gxtReader.printDebugMessage('debug', gxtEl, Data.nodeName, 'OK');
  547.                         break;
  548.                     case "slider":
  549.                         gxtEl = gxtReader.colorProperties(gxtEl, Data);
  550.                         gxtEl = gxtReader.visualProperties(gxtEl, Data);
  551.                         gxtEl = gxtReader.firstLevelProperties(gxtEl, Data);
  552.  
  553.                         gxtEl = gxtReader.readNodes(gxtEl, Data, 'data');
  554.                         gxtEl.fixed = JXG.str2Bool(gxtReader.gEBTN(Data, 'fix'));
  555.                         gxtEl = gxtReader.readNodes(gxtEl, Data, 'animate', 'animate');
  556.                         gxtEl = gxtReader.transformProperties(gxtEl, 'point');
  557.                         try {
  558.                             gxtEl.parent = gxtReader.changeOriginIds(board, gxtEl.parent);
  559.  
  560.                             // if (board.isSuspendedUpdate) { board.unsuspendUpdate().suspendUpdate(); }
  561.                             p = board.create('glider', [parseFloat(gxtEl.x), parseFloat(gxtEl.y), gxtEl.parent], gxtEl);
  562.                             p.onPolygon = JXG.exists(gxtEl.onpolygon) && JXG.str2Bool(gxtEl.onpolygon);
  563.                            
  564.                             gxtReader.parseImage(board, Data, board.options.layer['point'], 0, 0, 0, 0, p);
  565.                            
  566.                             //if (board.isSuspendedUpdate) { board.unsuspendUpdate().suspendUpdate(); }
  567.                            
  568.                             gxtReader.printDebugMessage('debug', gxtEl, Data.nodeName, 'OK');
  569.                         } catch(e) {
  570.                             JXG.debug("* <b>Err:</b>  Slider " + gxtEl.name + " " + gxtEl.id + ': '+ gxtEl.parent +"<br>\n");
  571.                         }
  572.                         break;
  573.                     case "cas":
  574.                         gxtEl = gxtReader.colorProperties(gxtEl, Data);
  575.                         gxtEl = gxtReader.visualProperties(gxtEl, Data);
  576.                         gxtEl = gxtReader.firstLevelProperties(gxtEl, Data);
  577.                         gxtEl.fixed = JXG.str2Bool(Data.getElementsByTagName('fix')[0].firstChild.data);
  578.                         gxtEl = gxtReader.readNodes(gxtEl, Data, 'data');
  579.                         gxtEl = gxtReader.transformProperties(gxtEl, 'point');
  580.  
  581.                         p = board.create('point', [parseFloat(gxtEl.xval), parseFloat(gxtEl.yval)], gxtEl);
  582.                         gxtReader.parseImage(board, Data, board.options.layer['point'], 0, 0, 0, 0, p);
  583.                         p.addConstraint([gxtEl.x, gxtEl.y]);
  584.                         gxtReader.printDebugMessage('debug', gxtEl, Data.nodeName, 'OK');
  585.                         break;
  586.                     case "intersection":
  587.                         gxtEl = gxtReader.readNodes(gxtEl, Data, 'data');
  588.                         xmlNode = Data.getElementsByTagName('first')[1];
  589.  
  590.                         gxtEl.outFirst = {};
  591.                         gxtEl.outFirst = gxtReader.colorProperties(gxtEl.outFirst, xmlNode);
  592.                         gxtEl.outFirst = gxtReader.visualProperties(gxtEl.outFirst, xmlNode);
  593.                         gxtEl.outFirst = gxtReader.firstLevelProperties(gxtEl.outFirst, xmlNode);
  594.                         gxtEl.outFirst.fixed = JXG.str2Bool(xmlNode.getElementsByTagName('fix')[0].firstChild.data);
  595.                         gxtEl.outFirst = gxtReader.transformProperties(gxtEl.outFirst, 'point');
  596.                         gxtEl.first = gxtReader.changeOriginIds(board, gxtEl.first);
  597.                         gxtEl.last = gxtReader.changeOriginIds(board, gxtEl.last);
  598.  
  599.                         //if ((board.objects[gxtEl.first].type == JXG.OBJECT_TYPE_LINE || board.objects[gxtEl.first].type == JXG.OBJECT_TYPE_ARROW)
  600.                         // && (board.objects[gxtEl.last].type == JXG.OBJECT_TYPE_LINE || board.objects[gxtEl.last].type == JXG.OBJECT_TYPE_ARROW)) {
  601.                         if ((JXG.getReference(board, gxtEl.first).elementClass == JXG.OBJECT_CLASS_LINE)
  602.                          && (JXG.getReference(board, gxtEl.last).elementClass == JXG.OBJECT_CLASS_LINE)) {
  603.                             /*
  604.                             inter = new JXG.Intersection(board, gxtEl.id, board.objects[gxtEl.first],
  605.                                     board.objects[gxtEl.last], gxtEl.outFirst.id, '',
  606.                                     gxtEl.outFirst.name, '');
  607.                             inter.p.setProperty(gxtEl.outFirst);
  608.                             */
  609.                             inter = board.create('intersection', [board.objects[gxtEl.first], board.objects[gxtEl.last], 0], gxtEl.outFirst);
  610.                             /* offensichtlich braucht man dieses if doch */
  611.                             if (gxtEl.outFirst.visible == "false") {
  612.                                 inter.hideElement();
  613.                             }
  614.                         } else {
  615.                             xmlNode = Data.getElementsByTagName('last')[1];
  616.                             if (JXG.exists(xmlNode)) {
  617.                                 gxtEl.outLast = {};
  618.                                 gxtEl.outLast = gxtReader.colorProperties(gxtEl.outLast, xmlNode);
  619.                                 gxtEl.outLast = gxtReader.visualProperties(gxtEl.outLast, xmlNode);
  620.                                 gxtEl.outLast = gxtReader.firstLevelProperties(gxtEl.outLast, xmlNode);
  621.                                 gxtEl.outLast.fixed = JXG.str2Bool(xmlNode.getElementsByTagName('fix')[0].firstChild.data);
  622.                                 gxtEl.outLast = gxtReader.transformProperties(gxtEl.outLast, 'point');
  623.                             /*
  624.                                 inter = new JXG.Intersection(board, gxtEl.id, board.objects[gxtEl.first],
  625.                                     board.objects[gxtEl.last], gxtEl.outFirst.id, gxtEl.outLast.id,
  626.                                     gxtEl.outFirst.name, gxtEl.outLast.name);
  627.                                 inter.p1.setProperty(gxtEl.outFirst);
  628.                                 inter.p2.setProperty(gxtEl.outLast);
  629.                             */
  630.                                 inter = board.create('intersection', [board.objects[gxtEl.first], board.objects[gxtEl.last], 0], gxtEl.outFirst);
  631.                                 inter = board.create('intersection', [board.objects[gxtEl.first], board.objects[gxtEl.last], 1], gxtEl.outLast);
  632.                             }
  633.                         }
  634.                         gxtReader.printDebugMessage('debug', gxtEl, Data.nodeName, 'OK');
  635.                         break;
  636.                     case "composition":
  637.                         gxtEl = gxtReader.readNodes(gxtEl, Data, 'data');
  638.                         gxtEl = gxtReader.firstLevelProperties(gxtEl, Data);
  639.                         gxtEl.defEl = [];
  640.                         numberDefEls = 0;
  641.                         xmlNode = Data.getElementsByTagName('data')[0].getElementsByTagName('input');
  642.                         for (i = 0; i < xmlNode.length; i++) {
  643.                             gxtEl.defEl[i] = xmlNode[i].firstChild.data;
  644.                             numberDefEls = i + 1;
  645.                         }
  646.  
  647.                         // every composition produces at least one element and the data for this element is stored
  648.                         // in gxtEl.out. if additional elements are created their data is read in the according case.
  649.                         xmlNode = Data.getElementsByTagName('output')[0];
  650.                         gxtEl.out = {};
  651.                         gxtEl.out = gxtReader.colorProperties(gxtEl.out, xmlNode);
  652.                         gxtEl.out = gxtReader.visualProperties(gxtEl.out, xmlNode);
  653.                         gxtEl.out = gxtReader.firstLevelProperties(gxtEl.out, xmlNode);
  654.                         gxtEl.out = gxtReader.transformProperties(gxtEl.out);
  655.  
  656.                         gxtEl.defEl[0] = gxtReader.changeOriginIds(board, gxtEl.defEl[0]);
  657.                         gxtEl.defEl[1] = gxtReader.changeOriginIds(board, gxtEl.defEl[1]);
  658.                         gxtEl.defEl[2] = gxtReader.changeOriginIds(board, gxtEl.defEl[2]);
  659.  
  660.                         // if (board.isSuspendedUpdate) { board.unsuspendUpdate().suspendUpdate(); }
  661.                         switch (gxtEl.type) {
  662.                             // ARROW_PARALLEL
  663.                             case "210070":
  664.                                 gxtEl.out.fixed = gxtReader.gEBTN(xmlNode, 'fix');
  665.  
  666.                                 xmlNode = Data.getElementsByTagName('output')[1];
  667.                                 gxtEl.outPoint = {};
  668.                                 gxtEl.outPoint = gxtReader.defProperties(gxtEl.outPoint, xmlNode);
  669.                                 gxtEl.outPoint = gxtReader.colorProperties(gxtEl.outPoint, xmlNode);
  670.                                 gxtEl.outPoint = gxtReader.visualProperties(gxtEl.outPoint, xmlNode);
  671.                                 gxtEl.outPoint = gxtReader.firstLevelProperties(gxtEl.outPoint, xmlNode);
  672.                                 gxtEl.outPoint = gxtReader.transformProperties(gxtEl.outPoint);
  673.                                 gxtEl.out.point = gxtEl.outPoint;
  674.  
  675.                                 board.create('arrowparallel', [gxtEl.defEl[1], gxtEl.defEl[0]], gxtEl.out);
  676.                                 break;
  677.  
  678.                             // BISECTOR
  679.                             case "210080":
  680.                                 gxtEl.out.straightFirst = false;
  681.                                 board.create('bisector', [gxtEl.defEl[0], gxtEl.defEl[1], gxtEl.defEl[2]], gxtEl.out);
  682.                                 break;
  683.  
  684.                             // CIRCUMCIRCLE
  685.                             case "210090":
  686.                                 xmlNode = Data.getElementsByTagName('output')[1];
  687.                                 gxtEl.outCircle = {};
  688.                                 gxtEl.outCircle = gxtReader.defProperties(gxtEl.outCircle, xmlNode);
  689.                                 gxtEl.outCircle = gxtReader.colorProperties(gxtEl.outCircle, xmlNode);
  690.                                 gxtEl.outCircle = gxtReader.visualProperties(gxtEl.outCircle, xmlNode);
  691.                                 gxtEl.outCircle = gxtReader.firstLevelProperties(gxtEl.outCircle, xmlNode);
  692.                                 gxtEl.outCircle = gxtReader.transformProperties(gxtEl.outCircle);
  693.                                 gxtEl.outCircle.point = gxtEl.out;
  694.                                 board.create('circumcircle', [gxtEl.defEl[0], gxtEl.defEl[1], gxtEl.defEl[2]], gxtEl.outCircle);
  695.                                 break;
  696.  
  697.                             // CIRCUMCIRCLE_CENTER
  698.                             case "210100":
  699.                                 board.create('circumcirclemidpoint', [gxtEl.defEl[0], gxtEl.defEl[1], gxtEl.defEl[2]], gxtEl.out);
  700.                                 break;
  701.  
  702.                             // MIDPOINT
  703.                             case "210110":
  704.                                 board.create('midpoint', gxtEl.defEl.slice(0, numberDefEls), gxtEl.out);
  705.                                 break;
  706.  
  707.                              // MIRRORLINE
  708.                             case "210120":
  709.                                 board.create('reflection', [gxtEl.defEl[1], gxtEl.defEl[0]], gxtEl.out);
  710.                                 break;
  711.  
  712.                             // MIRROR_POINT
  713.                             case "210125":
  714.                                 board.create('mirrorpoint', [gxtEl.defEl[0], gxtEl.defEl[1]], gxtEl.out);
  715.                                 break;
  716.  
  717.                             // NORMAL
  718.                             case "210130":
  719.                                 board.create('normal', [gxtEl.defEl[1], gxtEl.defEl[0]], gxtEl.out);
  720.                                 break;
  721.  
  722.                             // PARALLEL
  723.                             case "210140":
  724.                                 board.create('parallel', [gxtEl.defEl[1], gxtEl.defEl[0]], gxtEl.out);
  725.                                 break;
  726.  
  727.                             // PARALLELOGRAM_POINT
  728.                             case "210150":
  729.                                 board.create('parallelpoint', gxtEl.defEl.slice(0, numberDefEls), gxtEl.out);
  730.                                 break;
  731.  
  732.                             // PERPENDICULAR
  733.                             case "210160":
  734.                                 // output[0] was already read and is stored in gxtEl.out
  735.                                 gxtEl.out.fixed = gxtReader.gEBTN(xmlNode, 'fix');
  736.  
  737.                                 xmlNode = Data.getElementsByTagName('output')[1];
  738.                                 gxtEl.outLine = {};
  739.                                 gxtEl.outLine = gxtReader.defProperties(gxtEl.outLine, xmlNode);
  740.                                 gxtEl.outLine = gxtReader.colorProperties(gxtEl.outLine, xmlNode);
  741.                                 gxtEl.outLine = gxtReader.visualProperties(gxtEl.outLine, xmlNode);
  742.                                 gxtEl.outLine = gxtReader.firstLevelProperties(gxtEl.outLine, xmlNode);
  743.                                 gxtEl.outLine = gxtReader.readNodes(gxtEl.outLine, xmlNode, 'straight', 'straight');
  744.                                 gxtEl.outLine = gxtReader.transformProperties(gxtEl.outLine);
  745.                                 gxtEl.outLine.point = gxtEl.out;
  746.  
  747.                                 board.create('perpendicularsegment', [gxtEl.defEl[1], gxtEl.defEl[0]], gxtEl.outLine);
  748.                                 break;
  749.  
  750.                             // PERPENDICULAR_POINT
  751.                             case "210170":
  752.                                 board.create('perpendicularpoint', [gxtEl.defEl[1], gxtEl.defEl[0]], gxtEl.out);
  753.                                 break;
  754.  
  755.                             // ROTATION
  756.                             case "210180":
  757.                                 throw new Error('JSXGraph: Element ROTATION not yet implemented.');
  758.                                 break;
  759.  
  760.                             // SECTOR
  761.                             case "210190":
  762.                                 // sectors usually provide more than one output element but JSXGraph is not fully compatible
  763.                                 // to GEONExT sector elements. GEONExT sectors consist of two lines, a point, and a sector,
  764.                                 // JSXGraph uses a curve to display the sector incl. the borders, and
  765.                                 // a point and two lines.
  766.                                 // Gliders on sectors also run through the borders.
  767.                                 gxtEl.out = gxtReader.defProperties(gxtEl.out, xmlNode);
  768.                                 gxtEl.out.firstArrow = JXG.str2Bool(gxtReader.gEBTN(xmlNode, 'firstarrow'));
  769.                                 gxtEl.out.lastArrow = JXG.str2Bool(gxtReader.gEBTN(xmlNode, 'lastarrow'));
  770.  
  771.                                 // el = board.create('sector', gxtEl.defEl, gxtEl.out);
  772.                                 for (i=0; i<4;i++) {
  773.                                     xmlNode = Data.getElementsByTagName('output')[i];
  774.                                     gxtEl.out = gxtReader.defProperties(gxtEl.out, xmlNode);
  775.                                     gxtEl.out = gxtReader.colorProperties(gxtEl.out, xmlNode);
  776.                                     gxtEl.out = gxtReader.visualProperties(gxtEl.out, xmlNode);
  777.                                     gxtEl.out = gxtReader.firstLevelProperties(gxtEl.out, xmlNode);
  778.                                     gxtEl.out = gxtReader.transformProperties(gxtEl.out);
  779.                                    
  780.                                     if (i==0) {
  781.                                         el = board.create('sector', gxtEl.defEl, gxtEl.out);
  782.                                     } else if (i==1) {
  783.                                         p = board.create('point', [
  784.                                             function(){
  785.                                                 var p1 = JXG.getRef(board,gxtEl.defEl[1]), p2 = JXG.getRef(board,gxtEl.defEl[2]);
  786.                                                 return p1.X() + (p2.X()-p1.X())*el.Radius/p1.Dist(p2);
  787.                                             },
  788.                                             function(){
  789.                                                 var p1 = JXG.getRef(board,gxtEl.defEl[1]), p2 = JXG.getRef(board,gxtEl.defEl[2]);
  790.                                                 return p1.Y() + (p2.Y()-p1.Y())*el.Radius/p1.Dist(p2);
  791.                                             }], gxtEl.out);
  792.                                         //p = JXG.getReference(board,gxtEl.defEl[2]);
  793.                                     } else if (i==2) {
  794.                                         el = board.create('segment', [gxtEl.defEl[1], gxtEl.defEl[0]], gxtEl.out);
  795.                                     } else if (i==3) {
  796.                                         el = board.create('segment', [gxtEl.defEl[1], p], gxtEl.out);
  797.                                     }
  798.                                 }
  799.                                 break;
  800.                             default:
  801.                                 throw new Error("JSXGraph: GEONExT-Element " + gxtEl.type + ' not implemented.');
  802.                                 break;
  803.                         }
  804.  
  805.                         // if (board.isSuspendedUpdate) { board.unsuspendUpdate().suspendUpdate(); }
  806.                         gxtReader.printDebugMessage('debug', gxtEl, Data.nodeName, 'OK');
  807.                         break;
  808.                     case "polygon":
  809.                         gxtEl = gxtReader.colorProperties(gxtEl, Data);
  810.                         gxtEl = gxtReader.firstLevelProperties(gxtEl, Data);
  811.                         gxtEl.dataVertex = [];
  812.                         // In Geonext file format the first vertex is equal to the last vertex:
  813.                         for (i = 0; i < Data.getElementsByTagName('data')[0].getElementsByTagName('vertex').length-1; i++) {
  814.                             gxtEl.dataVertex[i] = Data.getElementsByTagName('data')[0].getElementsByTagName('vertex')[i].firstChild.data;
  815.                             gxtEl.dataVertex[i] = gxtReader.changeOriginIds(board, gxtEl.dataVertex[i]);
  816.                         }
  817.                         gxtEl.border = [];
  818.                         gxtEl.lines = {
  819.                             ids: []
  820.                         };
  821.                         for (i = 0; i < Data.getElementsByTagName('border').length; i++) {
  822.                             gxtEl.border[i] = {};
  823.                             xmlNode = Data.getElementsByTagName('border')[i];
  824.                             gxtEl.border[i].id = xmlNode.getElementsByTagName('id')[0].firstChild.data;
  825.                             gxtEl.lines.ids.push(gxtEl.border[i].id);
  826.                             gxtEl.border[i].name = xmlNode.getElementsByTagName('name')[0].firstChild.data;
  827.                             gxtEl.border[i].straightFirst = JXG.str2Bool(xmlNode.getElementsByTagName('straight')[0].getElementsByTagName('first')[0].firstChild.data);
  828.                             gxtEl.border[i].straightLast = JXG.str2Bool(xmlNode.getElementsByTagName('straight')[0].getElementsByTagName('last')[0].firstChild.data);
  829.                             gxtEl.border[i].strokeWidth = xmlNode.getElementsByTagName('strokewidth')[0].firstChild.data;
  830.                             gxtEl.border[i].dash = JXG.str2Bool(xmlNode.getElementsByTagName('dash')[0].firstChild.data);
  831.                             gxtEl.border[i].visible = JXG.str2Bool(xmlNode.getElementsByTagName('visible')[0].firstChild.data);
  832.                             gxtEl.border[i].draft = JXG.str2Bool(xmlNode.getElementsByTagName('draft')[0].firstChild.data);
  833.                             gxtEl.border[i].trace = JXG.str2Bool(xmlNode.getElementsByTagName('trace')[0].firstChild.data);
  834.  
  835.                             xmlNode = Data.getElementsByTagName('border')[i].getElementsByTagName('color')[0];
  836.                             rgbo = JXG.rgba2rgbo(xmlNode.getElementsByTagName('stroke')[0].firstChild.data);
  837.                             gxtEl.border[i].strokeColor = rgbo[0];
  838.                             gxtEl.border[i].strokeOpacity = rgbo[1];
  839.  
  840.                             rgbo = JXG.rgba2rgbo(xmlNode.getElementsByTagName('lighting')[0].firstChild.data);
  841.                             gxtEl.border[i].highlightStrokeColor = rgbo[0];
  842.                             gxtEl.border[i].highlightStrokeOpacity = rgbo[1];
  843.  
  844.                             rgbo = JXG.rgba2rgbo(xmlNode.getElementsByTagName('fill')[0].firstChild.data);
  845.                             gxtEl.border[i].fillColor = rgbo[0];
  846.                             gxtEl.border[i].fillOpacity = rgbo[1];
  847.  
  848.                             gxtEl.border[i].highlightFillColor = gxtEl.border[i].fillColor;
  849.                             gxtEl.border[i].highlightFillOpacity = gxtEl.border[i].fillOpacity;
  850.  
  851.                             gxtEl.border[i].labelColor = xmlNode.getElementsByTagName('label')[0].firstChild.data;
  852.                             gxtEl.border[i].colorDraft = xmlNode.getElementsByTagName('draft')[0].firstChild.data;
  853.                         }
  854.                         gxtEl = gxtReader.transformProperties(gxtEl);
  855.                         p = board.create('polygon', gxtEl.dataVertex, gxtEl);
  856.  
  857.                         // to emulate the geonext behaviour on invisible polygons
  858.                         // A.W.: Why do we need this?
  859. /*                        
  860.                         if (!gxtEl.visible) {
  861.                             p.setProperty({
  862.                                 fillColor: 'none',
  863.                                 highlightFillColor: 'none'
  864.                             });
  865.                         }
  866. */
  867.                         for (i = 0; i < p.borders.length; i++) {
  868.                             p.borders[i].setProperty(gxtEl.border[i]);
  869.                         }
  870.                            
  871.                         gxtReader.printDebugMessage('debug', gxtEl, Data.nodeName, 'OK');
  872.                         break;
  873.                     case "graph":
  874.                         gxtEl = gxtReader.colorProperties(gxtEl, Data);
  875.                         gxtEl = gxtReader.firstLevelProperties(gxtEl, Data);
  876.                         gxtEl.funct = Data.getElementsByTagName('data')[0].getElementsByTagName('function')[0].firstChild.data;
  877.  
  878.                         c = board.create('curve', ['x',gxtEl.funct], {
  879.                                 id: gxtEl.id,
  880.                                 name: gxtEl.name,
  881.                                 strokeColor: gxtEl.strokeColor,
  882.                                 strokeWidth: gxtEl.strokeWidth,
  883.                                 fillColor: 'none',
  884.                                 highlightFillColor: 'none',
  885.                                 highlightStrokeColor: gxtEl.highlightStrokeColor,
  886.                                 visible: JXG.str2Bool(gxtEl.visible)
  887.                             });
  888.  
  889.                         gxtReader.printDebugMessage('debug', gxtEl, Data.nodeName, 'OK');
  890.                         break;
  891.                     case "arrow":
  892.                         gxtEl = gxtReader.colorProperties(gxtEl, Data);
  893.                         gxtEl = gxtReader.visualProperties(gxtEl, Data);
  894.                         gxtEl = gxtReader.firstLevelProperties(gxtEl, Data);
  895.                         gxtEl = gxtReader.readNodes(gxtEl, Data, 'data');
  896.                         gxtEl = gxtReader.readNodes(gxtEl, Data, 'straight', 'straight');
  897.  
  898.                         gxtEl = gxtReader.transformProperties(gxtEl);
  899.                         gxtEl.first = gxtReader.changeOriginIds(board, gxtEl.first);
  900.                         gxtEl.last = gxtReader.changeOriginIds(board, gxtEl.last);
  901.  
  902.                         l = board.create('arrow', [gxtEl.first, gxtEl.last], gxtEl);
  903.  
  904.                         gxtReader.printDebugMessage('debug', l, Data.nodeName, 'OK');
  905.                         break;
  906.                     case "arc":
  907.                         gxtEl = gxtReader.colorProperties(gxtEl, Data);
  908.                         gxtEl = gxtReader.visualProperties(gxtEl, Data);
  909.                         gxtEl = gxtReader.firstLevelProperties(gxtEl, Data);
  910.                         gxtEl = gxtReader.readNodes(gxtEl, Data, 'data');
  911.  
  912.                         gxtEl.firstArrow = JXG.str2Bool(Data.getElementsByTagName('lastarrow')[0].firstChild.data);   // It seems that JSXGraph and GEONExT
  913.                         gxtEl.lastArrow = JXG.str2Bool(Data.getElementsByTagName('firstarrow')[0].firstChild.data);   // use opposite directions.
  914.  
  915.                         gxtEl = gxtReader.transformProperties(gxtEl);
  916.  
  917.                         gxtEl.midpoint = gxtReader.changeOriginIds(board, gxtEl.midpoint);
  918.                         gxtEl.angle = gxtReader.changeOriginIds(board, gxtEl.angle);
  919.                         gxtEl.radius = gxtReader.changeOriginIds(board, gxtEl.radius);
  920.  
  921.                         c = board.create('arc', [gxtEl.midpoint, gxtEl.radius, gxtEl.angle], gxtEl);
  922.  
  923.                         gxtReader.printDebugMessage('debug', c, Data.nodeName, 'OK');
  924.                         break;
  925.                     case "angle":
  926.                         gxtEl = gxtReader.colorProperties(gxtEl, Data);
  927.                         gxtEl = gxtReader.visualProperties(gxtEl, Data);
  928.                         gxtEl = gxtReader.firstLevelProperties(gxtEl, Data);
  929.                         gxtEl = gxtReader.readNodes(gxtEl, Data, 'data');
  930.                         gxtEl = gxtReader.transformProperties(gxtEl);
  931.  
  932.                         try {
  933.                             gxtEl.text = Data.getElementsByTagName('text')[0].firstChild.data;
  934.                         } catch (e) {
  935.                             gxtEl.text = '';
  936.                         }
  937.  
  938.                         c = board.create('angle', [gxtEl.first, gxtEl.middle, gxtEl.last], gxtEl);
  939.                         gxtReader.printDebugMessage('debug', gxtEl, Data.nodeName, 'OK');
  940.                         break;
  941.                     case "text":
  942.                         if (gxtEl.id.match(/oldVersion/)) {
  943.                             break;
  944.                         }
  945.                         gxtEl = gxtReader.colorProperties(gxtEl, Data);
  946.                         gxtEl = gxtReader.visualProperties(gxtEl, Data);
  947.                         gxtEl = gxtReader.firstLevelProperties(gxtEl, Data);
  948.  
  949.                         gxtEl = gxtReader.readNodes(gxtEl, Data, 'data');
  950.                         gxtEl.mpStr = gxtReader.subtreeToString(Data.getElementsByTagName('data')[0].getElementsByTagName('mp')[0]);
  951.                         gxtEl.mpStr = gxtEl.mpStr.replace(/<\/?mp>/g, '');
  952.                         try {
  953.                             if (Data.getElementsByTagName('data')[0].getElementsByTagName('parent')[0].firstChild) {
  954.                                 gxtEl.parent = Data.getElementsByTagName('data')[0].getElementsByTagName('parent')[0].firstChild.data;
  955.                             }
  956.                         } catch (e) {
  957.                         }
  958.                        
  959.                         gxtEl.condition = Data.getElementsByTagName('condition')[0].firstChild.data;
  960.                         gxtEl.content = Data.getElementsByTagName('content')[0].firstChild.data;
  961.                         gxtEl.fix = Data.getElementsByTagName('fix')[0].firstChild.data;
  962.                         // not used gxtEl.digits = Data.getElementsByTagName('cs')[0].firstChild.data;
  963.                         gxtEl.autodigits = Data.getElementsByTagName('digits')[0].firstChild.data;
  964.                         gxtEl.parent = gxtReader.changeOriginIds(board, gxtEl.parent);
  965.                        
  966.                         /*
  967.                          * Not necessary: is handled by getTextAnchor() in parent element
  968.                         // TODO: Polygons
  969.                         // Handle parent elements of texts
  970.                         if (JXG.exists(gxtEl.parent)) {
  971.                             if (JXG.isPoint(gxtEl.parent)) {
  972.                                 gxtEl.x = (function (x, y, p) { return function() { return x + p.X(); }; })
  973.                                         (gxtEl.x, gxtEl.y, JXG.getReference(board, gxtEl.parent));
  974.                                 gxtEl.y = (function (x, y, p) { return function() { return y + p.Y(); }; })
  975.                                         (gxtEl.x, gxtEl.y, JXG.getReference(board, gxtEl.parent));
  976.                             } else if (JXG.getReference(board, gxtEl.parent).elementClass == JXG.OBJECT_CLASS_CIRCLE) {  
  977.                                 gxtEl.x = (function (x, y, p) { return function() { return x + p.midpoint.X(); }; })
  978.                                         (gxtEl.x, gxtEl.y, JXG.getReference(board, gxtEl.parent));
  979.                                 gxtEl.y = (function (x, y, p) { return function() { return y + p.midpoint.Y(); }; })
  980.                                         (gxtEl.x, gxtEl.y, JXG.getReference(board, gxtEl.parent));
  981.                             } else if (JXG.getReference(board, gxtEl.parent).elementClass == JXG.OBJECT_CLASS_LINE) {  
  982.                                 gxtEl.x = (function (x, y, p) { return function() { return x + (p.point1.X()+p.point2.X())*0.5; }; })
  983.                                         (gxtEl.x, gxtEl.y, JXG.getReference(board, gxtEl.parent));
  984.                                 gxtEl.y = (function (x, y, p) { return function() { return y + (p.point1.Y()+p.point2.Y())*0.5; }; })
  985.                                         (gxtEl.x, gxtEl.y, JXG.getReference(board, gxtEl.parent));
  986.                             }
  987.                         }
  988.                         */
  989.                         c = board.create('text', [gxtEl.x, gxtEl.y, gxtEl.mpStr], {
  990.                                 anchor: gxtEl.parent,
  991.                                 id: gxtEl.id,
  992.                                 name: gxtEl.name,
  993.                                 digits: gxtEl.autodigits,
  994.                                 isLabel: false,
  995.                                 strokeColor: gxtEl.colorLabel,
  996.                                 visible: JXG.str2Bool(gxtEl.visible)
  997.                             });
  998.                         break;
  999.                     case 'parametercurve':
  1000.                         gxtEl = gxtReader.colorProperties(gxtEl, Data);
  1001.                         gxtEl = gxtReader.visualProperties(gxtEl, Data);
  1002.                         gxtEl = gxtReader.firstLevelProperties(gxtEl, Data);
  1003.                         gxtEl = gxtReader.transformProperties(gxtEl);                        
  1004.                         gxtEl.functionx = Data.getElementsByTagName('functionx')[0].firstChild.data;
  1005.                         gxtEl.functiony = Data.getElementsByTagName('functiony')[0].firstChild.data;
  1006.                         gxtEl.min = Data.getElementsByTagName('min')[0].firstChild.data;
  1007.                         gxtEl.max = Data.getElementsByTagName('max')[0].firstChild.data;
  1008.  
  1009.                         gxtEl.fillColor = 'none';
  1010.                         gxtEl.highlightFillColor = 'none';
  1011.                        
  1012.                         board.create('curve',
  1013.                                     [ new Function('t', 'return ' + JXG.GeonextParser.geonext2JS(gxtEl.functionx, board) + ';' ),
  1014.                                       new Function('t', 'return ' + JXG.GeonextParser.geonext2JS(gxtEl.functiony, board) + ';' ),
  1015.                                       new Function('return ' + JXG.GeonextParser.geonext2JS(gxtEl.min, board) + ';' ),
  1016.                                       new Function('return ' + JXG.GeonextParser.geonext2JS(gxtEl.max, board) + ';' )
  1017.                                     ], gxtEl);
  1018.                         /*
  1019.                         c = new JXG.Curve(board, [
  1020.                             't',gxtEl.functionx,gxtEl.functiony,gxtEl.min,gxtEl.max
  1021.                         ], gxtEl.id, gxtEl.name);
  1022.                         c.setProperty('strokeColor:' + gxtEl.colorStroke, 'strokeWidth:' + gxtEl.strokewidth, 'fillColor:none',
  1023.                                 'highlightStrokeColor:' + gxtEl.highlightStrokeColor);
  1024.                         */
  1025.                         gxtReader.printDebugMessage('debug', gxtEl, Data.nodeName, 'OK');
  1026.                         break;
  1027.                     case 'tracecurve':
  1028.                         //try {
  1029.                         gxtEl.tracepoint = Data.getElementsByTagName('tracepoint')[0].firstChild.data;
  1030.                         gxtEl.traceslider = Data.getElementsByTagName('traceslider')[0].firstChild.data;
  1031.                         JXG.getRef(board, gxtEl.tracepoint).setProperty({trace:true});
  1032.                         //} catch(e) {}
  1033.                         gxtReader.printDebugMessage('debug', gxtEl, Data.nodeName, '<b>ERR</b>');
  1034.                         break;
  1035.                     case 'group':
  1036.                         gxtEl = gxtReader.colorProperties(gxtEl, Data);
  1037.                         gxtEl = gxtReader.firstLevelProperties(gxtEl, Data);
  1038.                         gxtEl.members = [
  1039.                         ];
  1040.                         for (i = 0; i < Data.getElementsByTagName('data')[0].getElementsByTagName('member').length; i++) {
  1041.                             gxtEl.members[i] = Data.getElementsByTagName('data')[0].getElementsByTagName('member')[i].firstChild.data;
  1042.                             gxtEl.members[i] = gxtReader.changeOriginIds(board, gxtEl.members[i]);
  1043.                         }
  1044.                         c = new JXG.Group(board, gxtEl.id, gxtEl.name, gxtEl.members);
  1045.                         gxtReader.printDebugMessage('debug', gxtEl, Data.nodeName, 'OK');
  1046.                         break;
  1047.                     default:
  1048.                         JXG.debug("* <b>Err:</b> " + Data.nodeName + " not yet implemented <br>\n");
  1049.                 }
  1050.                 delete(gxtEl);
  1051.             })(s);
  1052.         }
  1053.         board.addConditions(conditions);
  1054.     },
  1055.  
  1056.     decodeString: function(str) {
  1057.         var unz;
  1058.         if (str.indexOf("<GEONEXT>")<0){
  1059.             unz = (new JXG.Util.Unzip(JXG.Util.Base64.decodeAsArray(str))).unzip(); // war Gunzip ME
  1060.             if (unz=="")
  1061.                 return str;
  1062.             else
  1063.                 return unz;
  1064.         } else {
  1065.             return str;
  1066.         }
  1067.     },
  1068.  
  1069.     prepareString: function(fileStr){
  1070.         try {
  1071.             if (fileStr.indexOf('GEONEXT')<0) {
  1072.                 fileStr = (this.decodeString(fileStr))[0][0];  // Base64 decoding
  1073.             }
  1074.             // Hacks to enable not well formed XML. Will be redone in Algebra.geonext2JS and Board.addConditions
  1075.             fileStr = this.fixXML(fileStr);
  1076.         } catch(e) {
  1077.             fileStr = '';
  1078.         }
  1079.         return fileStr;
  1080.     },
  1081.  
  1082.     fixXML: function(str) {
  1083.         var arr = ["active", "angle", "animate", "animated", "arc", "area", "arrow", "author", "autodigits", "axis", "back", "background", "board", "border", "bottom", "buttonsize", "cas", "circle", "color", "comment", "composition", "condition", "conditions", "content", "continuous", "control", "coord", "coordinates", "cross", "cs", "dash", "data", "description", "digits", "direction", "draft", "editable", "elements", "event", "file", "fill", "first", "firstarrow", "fix", "fontsize", "free", "full", "function", "functionx", "functiony", "GEONEXT", "graph", "grid", "group", "height", "id", "image", "info", "information", "input", "intersection", "item", "jsf", "label", "last", "lastarrow", "left", "lefttoolbar", "lighting", "line", "loop", "max", "maximized", "member", "middle", "midpoint", "min", "modifier", "modus", "mp", "mpx", "multi", "name", "onpolygon", "order", "origin", "output", "overline", "parametercurve", "parent", "point", "pointsnap", "polygon", "position", "radius", "radiusnum", "radiusvalue", "right", "section", "selectedlefttoolbar", "showconstruction", "showcoord", "showinfo", "showunit", "showx", "showy", "size", "slider", "snap", "speed", "src", "start", "stop", "straight", "stroke", "strokewidth", "style", "term", "text", "top", "trace", "tracecurve", "tracepoint", "traceslider", "type", "unit", "value", "VERSION", "vertex", "viewport", "visible", "width", "wot", "x", "xooy", "xval", "y", "yval", "zoom"],
  1084.                 list = arr.join('|'),
  1085.                 regex = '\&lt;(/?('+list+'))\&gt;',
  1086.                 expr = new RegExp(regex,'g');
  1087.  
  1088.         // First, we convert all < to &lt; and > to &gt;
  1089.         str = JXG.escapeHTML(str);
  1090.         // Second, we convert all GEONExT tags of the form &lt;tag&gt; back to <tag>
  1091.         str = str.replace(expr,'<$1>');
  1092.  
  1093.         str = str.replace(/(<content>.*)<arc>(.*<\/content>)/g,'$1&lt;arc&gt;$2');
  1094.         str = str.replace(/(<mp>.*)<arc>(.*<\/mpx>)/g,'$1&lt;arc&gt;$2');
  1095.         str = str.replace(/(<mpx>.*)<arc>(.*<\/mpx>)/g,'$1&lt;arc&gt;$2');
  1096.         return str;
  1097.     }
  1098.  
  1099. }; // end: GeonextReader
  1100.