playground:test_3js

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revision Previous revision
Next revision
Previous revision
playground:test_3js [2020/04/23 12:45] hnagelplayground:test_3js [2020/08/20 10:17] (current) hnagel
Line 1: Line 1:
 +<code perl>
 +> cube(3)->VISUAL;
 +</code>
 +<HTML>
 +<!--
 +polymake for knusper
 +Thu Aug 20 14:10:19 2020
 +unnamed
 +-->
 +
  
 <html> <html>
-<div name="output_subarea" style="overflow-x: auto; 
-padding: 0.4em; 
--webkit-box-flex: 1; 
--moz-box-flex: 1; 
-box-flex: 1; 
-flex: 1; 
-max-width: calc(100% - 14ex);"> 
    <head>    <head>
 +      <meta charset=utf-8>
       <title>unnamed</title>       <title>unnamed</title>
       <style>       <style>
Line 14: Line 18:
 // COMMON_CODE_BLOCK_BEGIN // COMMON_CODE_BLOCK_BEGIN
 */ */
-         html{overflow: scroll;+         html {overflow: scroll;}
-         body { font-family: Arial, Helvetica, sans-serif}+
          strong{font-size: 18px;}          strong{font-size: 18px;}
          canvas { z-index: 8; }          canvas { z-index: 8; }
-         input[type='range'] {} 
          input[type='radio'] {margin-left:0;}          input[type='radio'] {margin-left:0;}
          input[type='checkbox'] {margin-right:7px; margin-left: 0px; padding-left:0px;}          input[type='checkbox'] {margin-right:7px; margin-left: 0px; padding-left:0px;}
-         .group{padding-bottom: 40px;}+         .group{padding-bottom: 15px;}
          .settings * {z-index: 11; }          .settings * {z-index: 11; }
-         .settings{z-index: 10; margin-left: 30px; displaynone; width: 14em; height: 90%; border: solid 1px silver; padding: 2px; overflow-y: scroll; background-color: white } +         .settings{z-index: 10; font-family: Arial, Helvetica, sans-serif; margin-left: 30px; visibilityhidden; width: 14em; height: 96%; border: solid 1px silver; padding: 2px; overflow-y: scroll; box-sizing: border-box; background-color: white; position: absolute;
-         .indented{margin-left: 20px; margin-top: 15px; padding-bottom: 0px;} +         .indented{margin-left: 20px; margin-top: 10px; padding-bottom: 0px;} 
          .shownObjectsList{overflow: auto; max-width: 150px; max-height: 150px;}          .shownObjectsList{overflow: auto; max-width: 150px; max-height: 150px;}
-         .showSettingsButton{displayblock; z-index: 12; position: absolute } +         .showSettingsButton{visibilityvisible; z-index: 12; position: absolute } 
-         .hideSettingsButton{displaynone; z-index: 12; position: absolute; opacity: 0.5} +         .hideSettingsButton{visibilityhidden; z-index: 12; position: absolute; opacity: 0.5} 
-         .resetButton{margin-top20px;+         button{margin-left0; margin-top10px}
-         button{margin-left0;}+
          img{cursor: pointer;}          img{cursor: pointer;}
-         .suboption{padding-top: 30px;} +         .suboption{padding-top: 15px;} 
-         .transparency{displaynone;} +         #model47529851256 width100%; height: 100%; } 
-         .labelsCheckbox{margin-top10px;} +         .threejs_container width100%; height: 75vh;} 
- +         .settings{max-height: 74vh} 
          input[type=range] {          input[type=range] {
            -webkit-appearance: none;            -webkit-appearance: none;
Line 42: Line 42:
            margin-left: auto;            margin-left: auto;
            margin-right: auto;            margin-right: auto;
-           margin-top: 20px;+           margin-top: 15px; 
 +           margin-bottom: 15px;
            display: block;             display: block;
          }          }
Line 129: Line 130:
  </style>  </style>
    </head>    </head>
- 
 <body> <body>
 +   <div class='threejs_container'>
  <div id='settings_0' class='settings'>  <div id='settings_0' class='settings'>
  <div class=group id='transparency_0' class='transparency'>  <div class=group id='transparency_0' class='transparency'>
Line 144: Line 144:
  <div><input type='checkbox' id='changeRotationY_0'> y-axis</div>  <div><input type='checkbox' id='changeRotationY_0'> y-axis</div>
  <div><input type='checkbox' id='changeRotationZ_0'> z-axis</div>  <div><input type='checkbox' id='changeRotationZ_0'> z-axis</div>
- <button id='resetButton_0' class='resetButton' >Reset</button>+ <button id='resetButton_0'>Reset</button>
  </div>  </div>
  
Line 155: Line 155:
  <div class=group id='display_0'>  <div class=group id='display_0'>
  <strong>Display</strong>  <strong>Display</strong>
 + <div class=indented>
 + <div id='shownObjectTypesList_0' class='shownObjectsList'></div>
 + </div>
 + <div class=suboption>Objects</div>
  <div class=indented>  <div class=indented>
  <div id='shownObjectsList_0' class='shownObjectsList'></div>  <div id='shownObjectsList_0' class='shownObjectsList'></div>
- <div class='labelsCheckbox'><input type='checkbox' id='labelsCheckboxInput_0' checked>Labels</div> 
  </div>  </div>
  </div>  </div>
Line 174: Line 177:
  
  </div> <!-- end of settings -->  </div> <!-- end of settings -->
- <img id='hideSettingsButton_0' style="display: none" class='hideSettingsButton' src='/kernelspecs/polymake/close.svg' width=20px"> + <img id='hideSettingsButton_0' class='hideSettingsButton' src='/kernelspecs/r118/polymake/close.svg' width=20px"> 
- <img id='showSettingsButton_0' class='showSettingsButton' src='/kernelspecs/polymake/menu.svg' width=20px"> + <img id='showSettingsButton_0' class='showSettingsButton' src='/kernelspecs/r118/polymake/menu.svg' width=20px"> 
-<div id="model39814440028"></div> +<div id="model47529851256"></div> 
- +</div> 
-<script> +   <script> 
-requirejs.config({ +    requirejs.config({ 
-  paths: { +      paths: { 
-    three: '/kernelspecs/polymake/three', +        three: '/kernelspecs/r118/polymake/three', 
-    Detector: '/kernelspecs/polymake/Detector', +        TrackballControls: '/kernelspecs/r118/polymake/TrackballControls', 
-    SVGRenderer: '/kernelspecs/polymake/SVGRenderer', +        Projector: '/kernelspecs/r118/polymake/Projector', 
-    CanvasRenderer: '/kernelspecs/polymake/CanvasRenderer', +        SVGRenderer: '/kernelspecs/r118/polymake/SVGRenderer', 
-    Projector: '/kernelspecs/polymake/Projector', +        WEBGL: '/kernelspecs/r118/polymake/WebGL', 
-    TrackballControls: '/kernelspecs/polymake/TrackballControls' +      }, 
-  }, +      shim: { 
-  shim: { +        'three': { exports: 'THREE'}, 
-    'three': +        'SVGRenderer': { deps: [ 'three' ], exports: 'THREE.SVGRenderer' }, 
-    { +        'WEBGL': { deps: [ 'three' ], exports: 'THREE.WEBGL' }, 
-      exports: 'THREE' +        'Projector': { deps: [ 'three' ], exports: 'THREE.Projector' }, 
-    }, +        'TrackballControls': { deps: [ 'three' ], exports: 'THREE.TrackballControls'
-    'Detector': +      
-    { +    }); 
-      deps: [ 'three' ], +     
-      exports: 'Detector' +    require(['three'],function(THREE){ 
-    }, +        window.THREE = THREE; 
-    'SVGRenderer': +      require(['TrackballControls','Projector','SVGRenderer','WEBGL'],function(TrackballControls,Projector,SVGRenderer,WEBGL) { 
-    { +    THREE.TrackballControls TrackballControls
-      deps: [ 'three' ], +    THREE.Projector Projector
-      exports: 'THREE.SVGRenderer' +    THREE.SVGRenderer SVGRenderer
-    }, +    THREE.WEBGL WEBGL;
-    'CanvasRenderer': +
-    { +
-      deps: [ 'three' ], +
-      exports: 'THREE.CanvasRenderer' +
-    }, +
-    'Projector': +
-    { +
-      deps: [ 'three' ], +
-      exports: 'THREE.Projector' +
-    }, +
-    'TrackballControls': +
-    { +
-      deps: [ 'three' ], +
-      exports: 'THREE.TrackballControls' +
-    +
-  +
-}); +
-require(['three'],function(THREE){ +
-    window.THREE = THREE; +
-  require(['Detector','SVGRenderer','CanvasRenderer','Projector','TrackballControls'],function(Detector,SVGRenderer,CanvasRenderer,Projector,TrackballControls){ +
-      THREE.SVGRenderer SVGRenderer+
-      THREE.CanvasRenderer CanvasRenderer+
-      THREE.Projector Projector+
-      THREE.TrackballControls TrackballControls;+
  
 // COMMON_CODE_BLOCK_BEGIN // COMMON_CODE_BLOCK_BEGIN
- var foldable = false; 
-   var container = document.getElementById( 'model39814440028' ); 
-   var renderer = Detector.webgl? new THREE.WebGLRenderer({antialias: true}): new THREE.CanvasRenderer({antialias: true}); 
- var svgRenderer = new THREE.SVGRenderer({antialias: true}); 
-            var box = document.getElementsByName( 'output_subarea' )[0]; 
-         var notebook = document.getElementById( 'notebook_panel' ); 
  
-   var width box.clientWidth - 25; +const intervalLength = 25; // for automatic animations 
-   var height = width/2; //this needs sth more reasonable +const explodableModel false;  
-   //var height notebook.clientHeight * 0.8+const modelContains = { points: falsepointlabels: falselines: falseedgelabels: false, faces: false, arrowheads: false }
-   renderer.setSize(widthheight); +const foldables = [];
-   svgRenderer.setSize(widthheight); +
-   renderer.setClearColor(0xFFFFFF1)+
-   svgRenderer.setClearColor(0xFFFFFF, 1);+
  
-   container.appendChild(renderer.domElement);+var three = document.getElementById("model47529851256"); 
 +var scene = new THREE.Scene();
  
-   var scene = new THREE.Scene(); +var camera = new THREE.PerspectiveCamera(75, 1, 0.1, 1000); 
-   var camera = new THREE.PerspectiveCamera(75width/height, 0.1, 1000);+camera.position.set(005); 
 +camera.lookAt(0, 0, 0); 
 +camera.up.set(0, 1, 0);
  
-   var renderid;+var renderer = new THREE.WebGLRenderer( { antialias: true } ); 
 +var svgRenderer = new THREE.SVGRenderer({antialias: true}); 
 +renderer.setPixelRatio( window.devicePixelRatio ); 
 +renderer.setClearColor(0xFFFFFF, 1); 
 +svgRenderer.setClearColor(0xFFFFFF, 1); 
 +three.appendChild(renderer.domElement);
  
-   camera.position.set(00, 5); +var control = new THREE.TrackballControls(camerathree); 
-   camera.lookAt(0, 0, 0)+control.zoomSpeed = 0.2
-   camera.up.set(0, 1, 0);+control.rotateSpeed = 4;
  
-   // class to allow move points together with labels and spheres +function onWindowResize() { 
-   var PMPoint = function (x,y,z) { +    var width = three.clientWidth; 
-      this.vector = new THREE.Vector3(x,y,z); +    var height = three.clientHeight; 
-      this.sprite = null; +    renderer.setSize( width, height ); 
-      this.sphere = null; +    svgRenderer.setSize( width, height ); 
-   +    camera.aspect = width / height; 
-   PMPoint.prototype.makelabel = function(label) { +    camera.updateProjectionMatrix(); 
-      this.sprite = textSpritelabel );+
 + 
 +onWindowResize(); 
 +window.addEventListener('resize', onWindowResize);  
 + 
 +// class to allow move points together with labels and spheres 
 +var PMPoint = function (x,y,z) { 
 +   this.vector = new THREE.Vector3(x,y,z); 
 +   this.sprite = null; 
 +   this.sphere = null; 
 +
 +PMPoint.prototype.addLabel = function(labelsprite) { 
 +   this.sprite = labelsprite; 
 +   this.sprite.position.copy(this.vector); 
 +
 +PMPoint.prototype.addSphere = function(spheremesh) { 
 +   this.sphere = spheremesh; 
 +   this.sphere.position.copy(this.vector); 
 +
 +PMPoint.prototype.set = function(x,y,z) { 
 +   this.vector.set(x,y,z); 
 +   if (this.sprite) {
       this.sprite.position.copy(this.vector);       this.sprite.position.copy(this.vector);
    }    }
-   PMPoint.prototype.makesphere = function(radius,material) { +   if (this.sphere) {
-      this.sphere = new THREE.Mesh(new THREE.SphereGeometry(radius), material);+
       this.sphere.position.copy(this.vector);       this.sphere.position.copy(this.vector);
    }    }
 +}
 +PMPoint.prototype.radius = function() {
 +   if (this.sphere) {
 +      return this.sphere.geometry.parameters.radius;
 +   } else {
 +      return 0;
 +   }
 +};
 +// select the target node
 +var target = document.querySelector('#model47529851256');
  
-   PMPoint.prototype.setX = function(x) { +// create an observer instance 
-      this.vector.setX(x); +var observer new MutationObserver(function(mutations) { 
-      if (this.sprite) { +   mutations.forEach(function(mutation{ 
-         this.sprite.position.setX(x);+      if (mutation.removedNodes && mutation.removedNodes.length > 0) { 
 +         cancelAnimationFrame(renderId); 
 +         observer.disconnect(); 
 +         console.log("cancelled frame "+renderId);
       }       }
-      if (this.sphere) { +   }); 
-         this.sphere.position.setX(x);+}); 
 + 
 +// configuration of the observer: 
 +var config = { childList: true, characterData: true } 
 + 
 +// pass in the target node, as well as the observer options 
 +while (target) { 
 +   if (target.className=="output") { 
 +      observer.observe(target, config); 
 +      break; 
 +   } 
 +   target = target.parentNode; 
 +
 + 
 +// COMMON_CODE_BLOCK_END 
 + 
 +var obj0 = new THREE.Object3D(); 
 +obj0.name = "unnamed__1"; 
 +obj0.userData.explodable = 1; 
 +obj0.userData.points = []; 
 +obj0.userData.points.push(new PMPoint(-1, -1, -1)); 
 +obj0.userData.points.push(new PMPoint(1, -1, -1)); 
 +obj0.userData.points.push(new PMPoint(-1, 1, -1)); 
 +obj0.userData.points.push(new PMPoint(1, 1, -1)); 
 +obj0.userData.points.push(new PMPoint(-1, -1, 1)); 
 +obj0.userData.points.push(new PMPoint(1, -1, 1)); 
 +obj0.userData.points.push(new PMPoint(-1, 1, 1)); 
 +obj0.userData.points.push(new PMPoint(1, 1, 1)); 
 + 
 +obj0.userData.pointradii = 0.02; 
 +   <!-- Vertex style --> 
 +obj0.userData.pointmaterial = new THREE.MeshBasicMaterial( { color: 0xFF0000, side: THREE.DoubleSide, transparent: false } ); 
 +obj0.userData.pointlabels = ["0", "1", "2", "3", "4", "5", "6", "7"]; 
 +obj0.userData.edgeindices = [0, 1, 0, 2, 1, 3, 2, 3, 0, 4, 1, 5, 4, 5, 2, 6, 4, 6, 3, 7, 5, 7, 6, 7]; 
 +   <!-- Edge style --> 
 +obj0.userData.edgematerial = new THREE.LineBasicMaterial( { color: 0x000000, depthTest: true, linewidth: 1.5, transparent: false } ); 
 +obj0.userData.facets = [[0, 4, 6, 2], [7, 5, 1, 3], [5, 4, 0, 1], [2, 6, 7, 3], [0, 2, 3, 1], [6, 4, 5, 7]]; 
 +   <!-- Facet style --> 
 +obj0.userData.facetmaterial = new THREE.MeshBasicMaterial( { color: 0x77EC9E, depthFunc: THREE.LessDepth, depthWrite: true, opacity: 1, polygonOffset: true, polygonOffsetFactor: 1, polygonOffsetUnits: 1, side: THREE.DoubleSide, transparent: true } ); 
 +init_object(obj0); 
 +scene.add(obj0); 
 +// COMMON_CODE_BLOCK_BEGIN 
 +function textSpriteMaterial(message, parameters) { 
 +    if ( parameters === undefined ) parameters = {}; 
 +    var fontface = "Helvetica"; 
 +    var fontsize = parameters.hasOwnProperty("fontsize") ? parameters["fontsize"] : 18; 
 +    fontsize = fontsize*10; 
 +    var lines = message.split('\\n'); 
 +    var size = 512; 
 +    for(var i = 0; i<lines.length; i++){ 
 +        var tmp = lines[i].length; 
 +        while(tmp*fontsize > size){ 
 +           fontsize--; 
 +        } 
 +    } 
 +     
 +    var canvas = document.createElement('canvas'); 
 +    canvas.width = size; 
 +    canvas.height = size; 
 +    var context = canvas.getContext('2d'); 
 +    context.fillStyle = "rgba(255, 255, 255, 0)"; 
 +    context.fill(); 
 +    context.font = fontsize + "px " + fontface; 
 +     
 +    // text color 
 +    context.fillStyle = "rgba(0, 0, 0, 1.0)"; 
 +     for(var i = 0; i<lines.length; i++){ 
 +        context.fillText(lines[i], size/2, size/2+i*fontsize); 
 +     } 
 +     
 +    // canvas contents will be used for a texture 
 +    var texture = new THREE.Texture(canvas); 
 +    texture.needsUpdate = true; 
 +     
 +    var spriteMaterial = new THREE.SpriteMaterial({map: texture, depthTest: true, depthWrite: false, depthFunc: THREE.LessEqualDepth}); 
 +    return spriteMaterial; 
 +
 + 
 + 
 +// ---------------------- INITIALIZING OBJECTS-------------------------------------- 
 +// --------------------------------------------------------------------------------- 
 + 
 +function init_object(obj) { 
 +    if (obj.userData.hasOwnProperty("pointmaterial")) { 
 +        init_points(obj); 
 +        modelContains.points = true; 
 +    } 
 +    if (obj.userData.hasOwnProperty("pointlabels")) { 
 +        init_pointlabels(obj); 
 +        modelContains.pointlabels = true; 
 +    } 
 +    if (obj.userData.hasOwnProperty("edgematerial")) { 
 +        init_lines(obj); 
 +        modelContains.lines = true; 
 +    } 
 +    if (obj.userData.hasOwnProperty("edgelabels")) { 
 +        init_edgelabels(obj); 
 +        modelContains.edgelabels = true; 
 +    } 
 +    if (obj.userData.hasOwnProperty("arrowstyle")) { 
 +        init_arrowheads(obj); 
 +        modelContains.arrowheads = true; 
 +    } 
 +    if (obj.userData.hasOwnProperty("facetmaterial")) { 
 +        init_faces(obj); 
 +        modelContains.faces = true; 
 +    } 
 +
 + 
 +function init_points(obj) { 
 +   var pointgroup = new THREE.Group(); 
 +   pointgroup.name = "points"; 
 +   var points = obj.userData.points; 
 +   var radii = obj.userData.pointradii; 
 +   var materials = obj.userData.pointmaterial; 
 +   var geometry,material; 
 +   if (!Array.isArray(radii)) { 
 +      geometry = new THREE.SphereBufferGeometry(radii);   
 +   } 
 +   if (!Array.isArray(materials)) { 
 +      material = materials; 
 +   } 
 +   for (var i=0; i<points.length; i++) { 
 +      var point = points[i]; 
 +      if (Array.isArray(radii)) { 
 +         if (radii[i] == 0) { 
 +            continue; 
 +         } 
 +         geometry = new THREE.SphereBufferGeometry(radii[i]);   
 +      }  
 +      if (Array.isArray(materials)) { 
 +         material = materials[i];     
 +      }  
 +      var sphere = new THREE.Mesh(geometry, material); 
 +      point.addSphere(sphere); 
 +      pointgroup.add(sphere); 
 +   } 
 +   obj.add(pointgroup); 
 +
 + 
 +function init_pointlabels(obj) { 
 +   var points = obj.userData.points; 
 +   var labels = obj.userData.pointlabels; 
 +   var pointlabels = new THREE.Group(); 
 +   pointlabels.name = "pointlabels"; 
 +   if (Array.isArray(labels)) { 
 +      for (var i=0; i<points.length; i++) { 
 +         var point = points[i]; 
 +         var spriteMaterial = textSpriteMaterial( labels[i] ); 
 +       var sprite = new THREE.Sprite(spriteMaterial); 
 +         point.addLabel(sprite); 
 +         pointlabels.add(sprite);
       }       }
-   }; +   else { 
-   PMPoint.prototype.setY function(y{ +      var spriteMaterial textSpriteMateriallabels ); 
-      this.vector.setY(y); +      for (var i=0; i<points.length; i++) { 
-      if (this.sprite) { +         var point = points[i]; 
-         this.sprite.position.setY(y);+       var sprite = new THREE.Sprite(spriteMaterial); 
 +         point.addLabel(sprite); 
 +         pointlabels.add(sprite);
       }       }
-      if (this.sphere) { +   } 
-         this.sphere.position.setY(y);+   obj.add(pointlabels); 
 +
 + 
 +function init_lines(obj) { 
 +   var edgeindices = obj.userData.edgeindices; 
 +   var points = obj.userData.points; 
 +   var materials = obj.userData.edgematerial; 
 +   var geometry = new THREE.BufferGeometry(); 
 +   var bufarr = new Float32Array( obj.userData.edgeindices.length * 3 ); 
 +   var bufattr = new THREE.Float32BufferAttribute( bufarr, 3 ); 
 +   var geometry = new THREE.BufferGeometry(); 
 +   geometry.setAttribute('position', bufattr); 
 +   if (Array.isArray(materials)) {      
 +      for (var i=0; i<materials.length; i++) { 
 +         geometry.addGroup(2*i,2,i);
       }       }
-   }; +   } 
-   PMPoint.prototype.setZ = function(z) { +   var lines = new THREE.LineSegments(geometry, materials); 
-      this.vector.setZ(z); +   lines.name "lines"; 
-      if (this.sprite) { +   obj.add(lines); 
-         this.sprite.position.setZ(z);+   updateEdgesPosition(obj); 
 +
 + 
 +function init_edgelabels(obj) { 
 +   var points = obj.userData.points; 
 +   var edgeindices = obj.userData.edgeindices; 
 +   var labels = obj.userData.edgelabels; 
 +   var edgelabels = new THREE.Group(); 
 +   edgelabels.name = "edgelabels"; 
 +   if (Array.isArray(labels)) { 
 +      for (var i=0; i<edgeindices.length; i=i+2) { 
 +         var point = points[i]; 
 +         var spriteMaterial = textSpriteMaterial( labels[i] ); 
 +      var sprite = new THREE.Sprite(spriteMaterial); 
 +         sprite.position.copy(new THREE.Vector3().addVectors(points[edgeindices[i]].vector,points[edgeindices[i+1]].vector).multiplyScalar(0.5)); 
 +         edgelabels.add(sprite);
       }       }
-      if (this.sphere) { +   } else { 
-         this.sphere.position.setZ(z);+      var spriteMaterial = textSpriteMaterial( labels ); 
 +      for (var i=0; i<points.length; i++) { 
 +         var point = points[i]; 
 +      var sprite = new THREE.Sprite(spriteMaterial); 
 +         sprite.position.copy(new THREE.Vector3().addVectors(points[edgeindices[i]].vector,points[edgeindices[i+1]].vector).multiplyScalar(0.5)); 
 +         pointlabels.add(sprite);
       }       }
-   }; +   } 
-   PMPoint.prototype.set function(x,y,z) { +   obj.add(edgelabels); 
-      this.vector.set(x,y,z); +
-      if (this.sprite) { + 
-         this.sprite.position.set(x,y,z);+function init_arrowheads(obj) { 
 +    var arrowheads = new THREE.Group(); 
 +    arrowheads.name "arrowheads"; 
 +    var arrowstyle = obj.userData.arrowstyle; 
 +    var edgeindices = obj.userData.edgeindices; 
 +    var edgematerials = obj.userData.edgematerial; 
 +    var points = obj.userData.points; 
 +    var material; 
 +    if (!Array.isArray(edgematerials)) { 
 +        material = new THREE.MeshBasicMaterial( {color: edgematerials.color} ); 
 +    } 
 + 
 +    for (var i=0; i<edgeindices.length; i=i+2) { 
 +        var start = points[edgeindices[i]]; 
 +        var end = points[edgeindices[i+1]]; 
 +        var dist = start.vector.distanceTo( end.vector ) - start.radius() - end.radius(); 
 +        if (dist <= 0) { 
 +            continue; 
 +        } 
 +        var dir = new THREE.Vector3().subVectors(end.vector,start.vector); 
 +        dir.normalize(); 
 +        var axis = new THREE.Vector3().set(dir.z,0,-dir.x); 
 +        axis.normalize(); 
 +        var radians = Math.acos( dir.); 
 +        var radius = dist/25; 
 +        var height = dist/5; 
 +        var geometry = new THREE.ConeBufferGeometry(radius,height); 
 +        var position = new THREE.Vector3().addVectors(start.vector,dir.clone().multiplyScalar(start.radius()+dist-height/2)); 
 +        if (Array.isArray(edgematerials)) { 
 +            material = new THREE.MeshBasicMaterial( {color: edgematerials[i].color} ); 
 +        } 
 +        var cone = new THREE.Mesh( geometry, material ); 
 +        cone.quaternion.setFromAxisAngle(axis,radians);; 
 +        cone.position.copy(position);; 
 +        arrowheads.add(cone); 
 +    } 
 +    obj.add(arrowheads); 
 +
 + 
 +function init_faces(obj) { 
 +   var points = obj.userData.points; 
 +   var facets = obj.userData.facets; 
 +   obj.userData.triangleindices = []; 
 +   for (var i=0; i<facets.length; i++) { 
 +      facet = facets[i]; 
 +      for (var t=0; t<facet.length-2; t++) { 
 +         obj.userData.triangleindices.push(facet[0],facet[t+1],facet[t+2]);  
       }       }
-      if (this.sphere{ +   } 
-         this.sphere.position.set(x,y,z); +   var bufarr = new Float32Arrayobj.userData.triangleindices.length * 3 ); 
-      } +   var bufattr = new THREE.Float32BufferAttribute(bufarr,3); 
-   }+    
-   PMPoint.prototype.add = function(o{ +   var materials = obj.userData.facetmaterial
-      if (this.sprite) { +   var geometry = new THREE.BufferGeometry(); 
-         o.add(this.sprite)+   geometry.setAttribute('position',bufattr); 
-      } +   if (Array.isArray(materials)) { 
-      if (this.sphere) { +      var tricount = 0
-         o.add(this.sphere);+      var facet; 
 +      for (var i=0; i<facets.length; i++) { 
 +         facet = facets[i]; 
 +         geometry.addGroup(tricount,(facet.length-2)*3,i); 
 +         tricount += (facet.length-2)*3;
       }       }
-   };+   } 
 +   var mesh = new THREE.Mesh(geometry, materials); 
 +   mesh.name = "faces"; 
 +   obj.add(mesh);  
 +   updateFacesPosition(obj); 
 +
 +// //INITIALIZING
  
  
-   var controls new THREE.TrackballControls(camera, container); +function updateFacesPosition(obj) { 
- controls.zoomSpeed = 0.2+   var points obj.userData.points; 
- controls.rotateSpeed 4;+   var indices = obj.userData.triangleindices; 
 +   var faces = obj.getObjectByName("faces"); 
 +   var ba = faces.geometry.getAttribute("position"); 
 +   for (var i=0; i<indices.lengthi++) { 
 +      ba.setXYZ(i, points[indices[i]].vector.x, points[indices[i]].vector.y ,points[indices[i]].vector.z);  
 +   } 
 +   faces.geometry.attributes.position.needsUpdate true; 
 +    
 +}
  
-   var all_objects []+function updateEdgesPosition(obj) { 
-   var centroids []+   var points obj.userData.points
-   // select the target node +   var indices obj.userData.edgeindices
-   var target document.querySelector('#model39814440028');+   var lines = obj.getObjectByName("lines"); 
 +   var ba lines.geometry.getAttribute("position");  
 +   for (var i=0; i<indices.length; i++) { 
 +      ba.setXYZ(i, points[indices[i]].vector.x, points[indices[i]].vector.y ,points[indices[i]].vector.z);  
 +   } 
 +   lines.geometry.attributes.position.needsUpdate = true; 
 +}
  
-   // create an observer instance 
-   var observer = new MutationObserver(function(mutations) { 
-      mutations.forEach(function(mutation) { 
-         if (mutation.removedNodes && mutation.removedNodes.length > 0) { 
-            cancelAnimationFrame(renderId); 
-            observer.disconnect(); 
-            console.log("cancelled frame "+renderId); 
-         } 
-      }); 
-   }); 
  
-   // configuration of the observer: 
-   var config = { childList: true, characterData: true } 
  
-   // pass in the target node, as well as the observer options +var xRotationEnabled = false; 
-   while (target) { +var yRotationEnabled = false; 
-      if (target.className=="output") { +var zRotationEnabled = false; 
-         observer.observe(target, config); +var rotationSpeedFactor = 1; 
-         break;+var settingsShown = false; 
 +var labelsShown = true; 
 +var intervals = []; 
 +var timeouts = []; 
 +var explodingSpeed = 0.05; 
 +var explodeScale = 0; 
 +var XMLS = new XMLSerializer(); 
 +var svgElement; 
 +var renderId; 
 + 
 +var render = function () { 
 + 
 + renderId = requestAnimationFrame(render); 
 + 
 +// comment in for automatic explosion 
 +// explode(updateFactor()); 
 + 
 +    var phi = 0.02 * rotationSpeedFactor; 
 + 
 +    if (xRotationEnabled) { 
 +        scene.rotation.x += phi; 
 +    } 
 +    if (yRotationEnabled) { 
 +        scene.rotation.y +phi; 
 +    } 
 +    if (zRotationEnabled) { 
 +        scene.rotation.z +phi; 
 +    } 
 + 
 +    control.update(); 
 +    renderer.render(scene, camera); 
 +}; 
 + 
 +if ( THREE.WEBGL.isWebGLAvailable() ) { 
 + render(); 
 +} else { 
 + var warning = WEBGL.getWebGLErrorMessage(); 
 + three.appendChild( warning ); 
 +
 +     
 +function changeTransparency() { 
 +    var opacity = 1-Number(event.currentTarget.value); 
 +    for (var i=0; i<scene.children.length; i++) { 
 +        child = scene.children[i]; 
 +        if ( child.userData.hasOwnProperty("facetmaterial") { 
 +            if (Array.isArray(child.userData.facetmaterial)) { 
 +                for (var j=0; j<child.userData.facetmaterial.length; j++) { 
 +                    child.userData.facetmaterial[j].opacity = opacity; 
 +                } 
 +            } else { 
 +                child.userData.facetmaterial.opacity = opacity; 
 +            }     
 +        } 
 +    } 
 +
 + 
 +function changeRotationX(event){ 
 +    xRotationEnabled = event.currentTarget.checked; 
 +}  
 + 
 +function changeRotationY(event){ 
 +    yRotationEnabled = event.currentTarget.checked; 
 +}  
 + 
 +function changeRotationZ(event){ 
 +    zRotationEnabled = event.currentTarget.checked; 
 +}  
 + 
 + 
 +function changeRotationSpeedFactor(event){ 
 +    rotationSpeedFactor = Number(event.currentTarget.value); 
 +
 + 
 +function resetScene(){ 
 +    scene.rotation.set(0,0,0); 
 +    camera.position.set(0,0,5); 
 +    camera.up.set(0,1,0); 
 +
 + 
 +function showSettings(event){ 
 +    document.getElementById('settings_0').style.visibility = 'visible'; 
 +    document.getElementById('showSettingsButton_0').style.visibility = 'hidden'; 
 +    document.getElementById('hideSettingsButton_0').style.visibility = 'visible'; 
 +    settingsShown = true; 
 +
 + 
 +function hideSettings(event){ 
 +    document.getElementById('settings_0').style.visibility = 'hidden'; 
 +    document.getElementById('showSettingsButton_0').style.visibility = 'visible'; 
 +    document.getElementById('hideSettingsButton_0').style.visibility = 'hidden'; 
 +    settingsShown = false; 
 +
 + 
 + 
 + 
 +var pos = 150* Math.PI; 
 + 
 +function updateFactor() { 
 +    pos++; 
 +    return Math.sin(.01*pos)+1; 
 +
 + 
 +// ------------------------ FOLDING ------------------------------------------------ 
 +// --------------------------------------------------------------------------------- 
 +// rotate point p around axis defined by points p1 and p2 by given angle 
 +function rotate(p, p1, p2, angle ){    
 +   angle = -angle; 
 +   var x = p.x, y = p.y, z = p.z,  
 +   a = p1.x, b = p1.y, c = p1.z,  
 +   u = p2.x-p1.x, v = p2.y-p1.y, w = p2.z-p1.z; 
 +   var result = []; 
 +   var L = u*u + v*v + w*w; 
 +   var sqrt = Math.sqrt; 
 +   var cos = Math.cos; 
 +   var sin = Math.sin; 
 + 
 +   result[0] = ((a*(v*v+w*w)-u*(b*v+c*w-u*x-v*y-w*z))*(1-cos(angle))+L*x*cos(angle)+sqrt(L)*(-c*v+b*w-w*y+v*z)*sin(angle))/L; 
 +   result[1] = ((b*(u*u+w*w)-v*(a*u+c*w-u*x-v*y-w*z))*(1-cos(angle))+L*y*cos(angle)+sqrt(L)*(c*u-a*w+w*x-u*z)*sin(angle))/L; 
 +   result[2] = ((c*(u*u+v*v)-w*(a*u+b*v-u*x-v*y-w*z))*(1-cos(angle))+L*z*cos(angle)+sqrt(L)*(-b*u+a*v-v*x+u*y)*sin(angle))/L; 
 + 
 +   return result; 
 +
 + 
 +var fold = function(event){ 
 +    var obj = foldables[Number(event.currentTarget.name)]; 
 +    var foldvalue = Number(event.currentTarget.value); 
 +    var scale = foldvalue - obj.userData.oldscale; 
 + 
 +    for (var j=0; j<obj.userData.axes.length; j++) { 
 +        rotateVertices(obj, j, scale); 
 +    } 
 +    update(obj); 
 +    obj.userData.oldscale += scale; 
 +    lookAtBarycenter(obj); 
 +
 + 
 +function lookAtBarycenter(obj){ 
 +    control.target = barycenter(obj); 
 +
 + 
 +function barycenter(obj) { 
 +   var center = new THREE.Vector3(0,0,0); 
 +   var points = obj.userData.points; 
 +   for (var i=0; i<points.length; i++){ 
 +      center.add(points[i].vector); 
 +   } 
 +   center.divideScalar(points.length); 
 +   return center; 
 +
 + 
 +function rotateVertices(obj, edge, scale) { 
 +   var axes = obj.userData.axes; 
 +   var subtrees = obj.userData.subtrees; 
 +   var points = obj.userData.points; 
 +   var angles = obj.userData.angles; 
 +   if (edge < axes.length){ 
 +      for (var j=0; j<subtrees[edge].length; j++){ 
 +         var rotP = rotate(points[subtrees[edge][j]].vector, points[axes[edge][0]].vector,points[axes[edge][1]].vector, scale * (Math.PI - angles[edge])); 
 +         points[subtrees[edge][j]].set(rotP[0],rotP[1],rotP[2]);
       }       }
-      target = target.parentNode; 
    }    }
 +}
 +
 +function update(obj) {
 +   updateFacesPosition(obj);
 +   updateEdgesPosition(obj);
 +}
 +
 +if (foldables.length) {
 +    var settings = document.getElementById('settings_0');
 +    var foldDiv = document.createElement('div');
 +    foldDiv.id = 'fold_0';
 +    var title = document.createElement('strong');
 +    title.innerHTML = 'Fold';
 +    foldDiv.appendChild(title);
 +    foldDiv.className = 'group';
 +    for (var i=0; i<foldables.length; i++) {
 +        var range = document.createElement('input');
 +        range.type = 'range';
 +        range.min = 0;
 +        range.max = 1;
 +        range.value = 0;
 +        range.step = 0.001;
 +        range.name = String(i);
 +        range.oninput = fold;
 +        foldDiv.appendChild(range);
 +    }
 +    lookAtBarycenter(foldables[0]);
 +    settings.insertBefore(foldDiv,settings.childNodes[0]);
 +}
 +
 +    
 +// ---------------------- EXPLOSION ------------------------------------------------
 +// ---------------------------------------------------------------------------------
 +
 +if (explodableModel) {
 +    for (var i=0; i<scene.children.length; i++) {
 +        obj = scene.children[i];
 +        if ( obj.userData.explodable ) {
 +            computeCentroid(obj);
 +        }
 +    }
 +    document.getElementById('explodeRange_0').oninput = triggerExplode;
 +    document.getElementById('explodeCheckbox_0').onchange = triggerAutomaticExplode;
 +    document.getElementById('explodingSpeedRange_0').oninput = setExplodingSpeed;
 +}
 +
 +function computeCentroid(obj) {
 +    centroid = new THREE.Vector3();
 +    obj.userData.points.forEach(function(pmpoint) {
 +        centroid.add(pmpoint.vector);
 +    });
 +    centroid.divideScalar(obj.userData.points.length);
 +    obj.userData.centroid = centroid;
 +}
 +
 +function explode(factor) {
 +    for (var i=0; i<scene.children.length; i++) {
 +        var obj = scene.children[i];
 +        if (obj.userData.hasOwnProperty("centroid")) { 
 +            var c = obj.userData.centroid;
 +            obj.position.set(c.x*factor, c.y*factor, c.z*factor);
 +        }
 +    }
 +}
 +
 +function triggerExplode(event){
 +    explodeScale = Number(event.currentTarget.value);
 +    explode(explodeScale);
 +}
 +
 +function setExplodingSpeed(event){
 +    explodingSpeed = Number(event.currentTarget.value);
 +}
 +
 +function triggerAutomaticExplode(event){
 +    if (event.currentTarget.checked){
 +        startExploding();
 +    } else {
 +        clearIntervals();
 +    }
 +}
 +
 +function startExploding(){
 +    intervals.push(setInterval(explodingInterval, 25));
 +}
 +
 +
 +function explodingInterval(){
 +    explodeScale += explodingSpeed;
 +    if (explodeScale <= 6){ 
 +        explode(explodeScale);
 +    }
 +    else{
 +        explode(6);
 +        explodeScale = 6;
 +        clearIntervals();
 +        timeouts.push(setTimeout(startUnexploding, 3000));
 +    }
 +    document.getElementById('explodeRange_0').value = explodeScale;
 +}
 +
 +
 +function startUnexploding(){
 +    intervals.push(setInterval(unexplodingInterval, 25));
 +}
 +
 +function unexplodingInterval(){
 +    explodeScale -= explodingSpeed;
 +    if (explodeScale >= 0){
 +        explode(explodeScale);
 +    }
 +    else {
 +        explode(0);
 +        explodeScale = 0;
 +        clearIntervals();
 +        timeouts.push(setTimeout(startExploding, 3000));
 +    }
 +    document.getElementById('explodeRange_0').value = explodeScale;
 +}
 +
 +function clearIntervals(){
 +    intervals.forEach(function(interval){
 +        clearInterval(interval);
 +    });
 +    intervals = [];
 +    timeouts.forEach(function(timeout){
 +        clearTimeout(timeout);
 +    });
 +    timeouts = [];
 +}
 +
 +// ---------------------- DISPLAY --------------------------------------------------
 +// ---------------------------------------------------------------------------------
 +
 +const objectTypeInnerHTMLs = { points: "Points", pointlabels: "Point labels", lines: "Edges", edgelabels: "Edge labels", faces: "Faces", arrowheads: "Arrow heads" };
 +const objectTypeVisible = {};
 +Object.assign(objectTypeVisible,modelContains);
 +const sortedObjectTypeKeys = Object.keys(objectTypeInnerHTMLs).sort();
 +const shownObjectTypesList = document.getElementById('shownObjectTypesList_0');
 +
 +function setVisibility(bool,objname) {
 +    for (var i=0; i<scene.children.length; i++){
 +        var obj = scene.children[i].getObjectByName(objname);
 +        if (obj) {
 +            obj.visible = bool;
 +        }
 +    }
 +}
 +
 +function toggleObjectTypeVisibility(event){
 +    var name = event.currentTarget.name;
 +    var checked = event.currentTarget.checked;
 +    objectTypeVisible[name] = checked;
 +    setVisibility(checked,name);
 +}
 +
 +for (var i=0; i<sortedObjectTypeKeys.length; i++){
 +    var key = sortedObjectTypeKeys[i];
 +    if (modelContains[key]) {
 +        var objTypeNode = document.createElement('span');
 +        objTypeNode.innerHTML = objectTypeInnerHTMLs[key] + '<br>';
 +        var checkbox = document.createElement('input');
 +        checkbox.type = 'checkbox';
 +        checkbox.checked = true;
 +        checkbox.name = key;
 +        checkbox.onchange = toggleObjectTypeVisibility;
 +        shownObjectTypesList.appendChild(checkbox);
 +        shownObjectTypesList.appendChild(objTypeNode);
 +    }
 +}
 +
 +// ------------------------------------------------------
 +
 +function toggleObjectVisibility(event){
 +    var nr = Number(event.currentTarget.name);
 +    scene.children[nr].visible = event.currentTarget.checked;
 +}
 +
 +// append checkboxes for displaying or hiding objects
 +var shownObjectsList = document.getElementById('shownObjectsList_0');
 +for (var i=0; i<scene.children.length; i++){
 +    obj = scene.children[i];
 +    var objNode = document.createElement('span');
 +    objNode.innerHTML = obj.name + '<br>';
 +    var checkbox = document.createElement('input');
 +    checkbox.type = 'checkbox';
 +    checkbox.checked = true;
 +    checkbox.name = String(i);
 +    checkbox.onchange = toggleObjectVisibility;
 +    shownObjectsList.appendChild(checkbox);
 +    shownObjectsList.appendChild(objNode);
 +}
 +
 +// ---------------------- SVG ------------------------------------------------------
 +// ---------------------------------------------------------------------------------
 +
 +function takeSvgScreenshot() {
 +    if (objectTypeVisible["pointlabels"]) {
 +        setVisibility(false,"pointlabels");
 +    }
 +    if (objectTypeVisible["edgelabels"]) {
 +        setVisibility(false,"edgelabels");
 +    }
 +    svgRenderer.render(scene,camera);
 +    svgElement = XMLS.serializeToString(svgRenderer.domElement);
 +    
 +    if (objectTypeVisible["pointlabels"]) {
 +        setVisibility(true,"pointlabels");
 +    }
 +    if (objectTypeVisible["edgelabels"]) {
 +        setVisibility(true,"edgelabels");
 +    }
 +
 +    if (document.getElementById('tab_0').checked){
 +        //show in new tab
 +        var myWindow = window.open("","");
 +        myWindow.document.body.innerHTML = svgElement;
 +    } else{
 +        // download svg file 
 +        download("screenshot.svg", svgElement);
 +    }
 +}
 +
 +function download(filename, text) {
 +  var element = document.createElement('a');
 +  element.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(text));
 +  element.setAttribute('download', filename);
 +
 +  element.style.display = 'none';
 +  document.body.appendChild(element);
 +
 +  element.click();
 +
 +  document.body.removeChild(element);
 +}
 +
 +
 +document.getElementById('transparencyRange_0').oninput = changeTransparency;
 +document.getElementById('changeRotationX_0').onchange = changeRotationX;
 +document.getElementById('changeRotationY_0').onchange = changeRotationY;
 +document.getElementById('changeRotationZ_0').onchange = changeRotationZ;
 +document.getElementById('resetButton_0').onclick = resetScene;
 +document.getElementById('rotationSpeedRange_0').oninput = changeRotationSpeedFactor;
 +document.getElementById('takeScreenshot_0').onclick = takeSvgScreenshot;
 +document.getElementById('showSettingsButton_0').onclick = showSettings;
 +document.getElementById('hideSettingsButton_0').onclick = hideSettings;
 +
 +
 +// ------------------ SHORTCUTS --------------------------------------------
 +// -------------------------------------------------------------------------
 +
 +/**
 + * http://www.openjs.com/scripts/events/keyboard_shortcuts/
 + * Version : 2.01.B
 + * By Binny V A
 + * License : BSD
 + */
 +shortcut = {
 + 'all_shortcuts':{},//All the shortcuts are stored in this array
 + 'add': function(shortcut_combination,callback,opt) {
 + //Provide a set of default options
 + var default_options = {
 + 'type':'keydown',
 + 'propagate':false,
 + 'disable_in_input':false,
 + 'target':document,
 + 'keycode':false
 + }
 + if(!opt) opt = default_options;
 + else {
 + for(var dfo in default_options) {
 + if(typeof opt[dfo] == 'undefined') opt[dfo] = default_options[dfo];
 + }
 + }
 +
 + var ele = opt.target;
 + if(typeof opt.target == 'string') ele = document.getElementById(opt.target);
 + var ths = this;
 + shortcut_combination = shortcut_combination.toLowerCase();
 +
 + //The function to be called at keypress
 + var func = function(e) {
 + e = e || window.event;
 +
 + if(opt['disable_in_input']) { //Don't enable shortcut keys in Input, Textarea fields
 + var element;
 + if(e.target) element=e.target;
 + else if(e.srcElement) element=e.srcElement;
 + if(element.nodeType==3) element=element.parentNode;
 +
 + if(element.tagName == 'INPUT' || element.tagName == 'TEXTAREA') return;
 + }
 +
 + //Find Which key is pressed
 + if (e.keyCode) code = e.keyCode;
 + else if (e.which) code = e.which;
 + var character = String.fromCharCode(code).toLowerCase();
 +
 + if(code == 188) character=","; //If the user presses , when the type is onkeydown
 + if(code == 190) character="."; //If the user presses , when the type is onkeydown
 +
 + var keys = shortcut_combination.split("+");
 + //Key Pressed - counts the number of valid keypresses - if it is same as the number of keys, the shortcut function is invoked
 + var kp = 0;
 +
 + //Work around for stupid Shift key bug created by using lowercase - as a result the shift+num combination was broken
 + var shift_nums = {
 + "`":"~",
 + "1":"!",
 + "2":"@",
 + "3":"#",
 + "4":"$",
 + "5":"%",
 + "6":"^",
 + "7":"&",
 + "8":"*",
 + "9":"(",
 + "0":")",
 + "-":"_",
 + "=":"+",
 + ";":":",
 + "'":"\"",
 + ",":"<",
 + ".":">",
 + "/":"?",
 + "\\":"|"
 + }
 + //Special Keys - and their codes
 + var special_keys = {
 + 'esc':27,
 + 'escape':27,
 + 'tab':9,
 + 'space':32,
 + 'return':13,
 + 'enter':13,
 + 'backspace':8,
 +
 + 'scrolllock':145,
 + 'scroll_lock':145,
 + 'scroll':145,
 + 'capslock':20,
 + 'caps_lock':20,
 + 'caps':20,
 + 'numlock':144,
 + 'num_lock':144,
 + 'num':144,
 +
 + 'pause':19,
 + 'break':19,
 +
 + 'insert':45,
 + 'home':36,
 + 'delete':46,
 + 'end':35,
 +
 + 'pageup':33,
 + 'page_up':33,
 + 'pu':33,
 +
 + 'pagedown':34,
 + 'page_down':34,
 + 'pd':34,
 +
 + 'left':37,
 + 'up':38,
 + 'right':39,
 + 'down':40,
 +
 + 'f1':112,
 + 'f2':113,
 + 'f3':114,
 + 'f4':115,
 + 'f5':116,
 + 'f6':117,
 + 'f7':118,
 + 'f8':119,
 + 'f9':120,
 + 'f10':121,
 + 'f11':122,
 + 'f12':123
 + }
 +
 + var modifiers = { 
 + shift: { wanted:false, pressed:false},
 + ctrl : { wanted:false, pressed:false},
 + alt  : { wanted:false, pressed:false},
 + meta : { wanted:false, pressed:false} //Meta is Mac specific
 + };
 +                        
 + if(e.ctrlKey) modifiers.ctrl.pressed = true;
 + if(e.shiftKey) modifiers.shift.pressed = true;
 + if(e.altKey) modifiers.alt.pressed = true;
 + if(e.metaKey)   modifiers.meta.pressed = true;
 +                        
 + for(var i=0; k=keys[i],i<keys.length; i++) {
 + //Modifiers
 + if(k == 'ctrl' || k == 'control') {
 + kp++;
 + modifiers.ctrl.wanted = true;
 +
 + } else if(k == 'shift') {
 + kp++;
 + modifiers.shift.wanted = true;
 +
 + } else if(k == 'alt') {
 + kp++;
 + modifiers.alt.wanted = true;
 + } else if(k == 'meta') {
 + kp++;
 + modifiers.meta.wanted = true;
 + } else if(k.length > 1) { //If it is a special key
 + if(special_keys[k] == code) kp++;
 +
 + } else if(opt['keycode']) {
 + if(opt['keycode'] == code) kp++;
 +
 + } else { //The special keys did not match
 + if(character == k) kp++;
 + else {
 + if(shift_nums[character] && e.shiftKey) { //Stupid Shift key bug created by using lowercase
 + character = shift_nums[character]; 
 + if(character == k) kp++;
 + }
 + }
 + }
 + }
 +
 + if(kp == keys.length && 
 + modifiers.ctrl.pressed == modifiers.ctrl.wanted &&
 + modifiers.shift.pressed == modifiers.shift.wanted &&
 + modifiers.alt.pressed == modifiers.alt.wanted &&
 + modifiers.meta.pressed == modifiers.meta.wanted) {
 + callback(e);
 +
 + if(!opt['propagate']) { //Stop the event
 + //e.cancelBubble is supported by IE - this will kill the bubbling process.
 + e.cancelBubble = true;
 + e.returnValue = false;
 +
 + //e.stopPropagation works in Firefox.
 + if (e.stopPropagation) {
 + e.stopPropagation();
 + e.preventDefault();
 + }
 + return false;
 + }
 + }
 + }
 + this.all_shortcuts[shortcut_combination] = {
 + 'callback':func, 
 + 'target':ele, 
 + 'event': opt['type']
 + };
 + //Attach the function with the event
 + if(ele.addEventListener) ele.addEventListener(opt['type'], func, false);
 + else if(ele.attachEvent) ele.attachEvent('on'+opt['type'], func);
 + else ele['on'+opt['type']] = func;
 + },
 +
 + //Remove the shortcut - just specify the shortcut and I will remove the binding
 + 'remove':function(shortcut_combination) {
 + shortcut_combination = shortcut_combination.toLowerCase();
 + var binding = this.all_shortcuts[shortcut_combination];
 + delete(this.all_shortcuts[shortcut_combination])
 + if(!binding) return;
 + var type = binding['event'];
 + var ele = binding['target'];
 + var callback = binding['callback'];
 +
 + if(ele.detachEvent) ele.detachEvent('on'+type, callback);
 + else if(ele.removeEventListener) ele.removeEventListener(type, callback, false);
 + else ele['on'+type] = false;
 + }
 +}
 +
 +shortcut.add("Alt+Left",function() {
 + var event = new Event('click');
 + if (settingsShown){
 + document.getElementById('hideSettingsButton_0').dispatchEvent(event);
 + } else {
 + document.getElementById('showSettingsButton_0').dispatchEvent(event);
 + }
 +});
 +
  
 // COMMON_CODE_BLOCK_END // COMMON_CODE_BLOCK_END
  
-   var objectnames = ["unnamed__1"]; +});}); 
-   var obj = new THREE.Object3D(); +      </script> 
-   var allpoints = []; +   </body> 
-   allpoints.push(new PMPoint(0, 0, 0)); +</html> 
-   allpoints.push(new PMPoint(1, 0, 0)); +</HTML> 
-   allpoints.push(new PMPoint(0, 1, 0)); +<code perl> 
-   allpoints.push(new PMPoint(0, 0, 1));+> fan::planar_net(cube(3))->VISUAL
 +</code> 
 +<HTML> 
 +<!-- 
 +polymake for knusper 
 +Thu Aug 20 14:10:19 2020 
 +planar_net_ 
 +-->
  
-   <!-- Vertex style --> 
-   var points_material = new THREE.MeshBasicMaterial ( {color: 0xFF0000, } ); 
  
-   points_material.side THREE.DoubleSide+<html> 
-   points_material.transparent = true;+   <head> 
 +      <meta charset=utf-8> 
 +      <title>planar_net_</title> 
 +      <style> 
 +/* 
 +// COMMON_CODE_BLOCK_BEGIN 
 +*/ 
 +         html {overflow: scroll;} 
 +         strong{font-size: 18px;} 
 +         canvas { z-index: 8; } 
 +         input[type='radio'] {margin-left:0;
 +         input[type='checkbox'] {margin-right:7px; margin-left: 0px; padding-left:0px;
 +         .group{padding-bottom: 15px;} 
 +         .settings * {z-index: 11; } 
 +         .settings{z-index: 10; font-family: Arial, Helvetica, sans-serif; margin-left: 30px; visibility: hidden; width: 14em; height: 96%; border: solid 1px silver; padding: 2px; overflow-y: scroll; box-sizing: border-box; background-color: white; position: absolute;
 +         .indented{margin-left: 20px; margin-top: 10px; padding-bottom: 0px;}  
 +         .shownObjectsList{overflow: auto; max-width: 150px; max-height: 150px;} 
 +         .showSettingsButton{visibility: visible; z-index: 12; position: absolute } 
 +         .hideSettingsButton{visibility: hidden; z-index: 12; position: absolute; opacity: 0.5} 
 +         button{margin-left: 0; margin-top: 10px} 
 +         img{cursor: pointer;} 
 +         .suboption{padding-top: 15px;} 
 +         #model29171150745 { width: 100%; height: 100%; } 
 +         .threejs_container { width: 100%; height: 75vh;} 
 +         .settings{max-height: 74vh}  
 +         input[type=range] { 
 +           -webkit-appearance: none; 
 +           padding:0;  
 +           width:90%;  
 +           margin-left: auto; 
 +           margin-right: auto; 
 +           margin-top: 15px; 
 +           margin-bottom: 15px; 
 +           display: block;  
 +         } 
 +         input[type=range]:focus { 
 +           outline: none; 
 +         } 
 +         input[type=range]::-webkit-slider-runnable-track { 
 +           height: 4px; 
 +           cursor: pointer; 
 +           animate: 0.2s
 +           box-shadow: 0px 0px 0px #000000; 
 +           background: #E3E3E3; 
 +           border-radius: 0px; 
 +           border: 0px solid #000000; 
 +         } 
 +         input[type=range]::-webkit-slider-thumb { 
 +           box-shadow: 1px 1px 2px #B8B8B8; 
 +           border: 1px solid #ABABAB; 
 +           height: 13px; 
 +           width: 25px; 
 +           border-radius: 20px; 
 +           background: #E0E0E0; 
 +           cursor: pointer; 
 +           -webkit-appearance: none; 
 +           margin-top: -5px; 
 +         } 
 +         input[type=range]:focus::-webkit-slider-runnable-track { 
 +           background: #E3E3E3; 
 +         } 
 +         input[type=range]::-moz-range-track { 
 +           height: 4px; 
 +           cursor: pointer; 
 +           animate: 0.2s; 
 +           box-shadow: 0px 0px 0px #000000; 
 +           background: #E3E3E3; 
 +           border-radius: 0px; 
 +           border: 0px solid #000000; 
 +         } 
 +         input[type=range]::-moz-range-thumb { 
 +           box-shadow: 1px 1px 2px #B8B8B8; 
 +           border: 1px solid #ABABAB; 
 +           height: 13px; 
 +           width: 25px; 
 +           border-radius: 20px; 
 +           background: #E0E0E0; 
 +           cursor: pointer; 
 +         } 
 +         input[type=range]::-ms-track { 
 +           height: 4px; 
 +           cursor: pointer; 
 +           animate: 0.2s; 
 +           background: transparent
 +           border-color: transparent; 
 +           color: transparent; 
 +         } 
 +         input[type=range]::-ms-fill-lower { 
 +           background: #E3E3E3; 
 +           border: 0px solid #000000; 
 +           border-radius: 0px; 
 +           box-shadow: 0px 0px 0px #000000; 
 +         } 
 +         input[type=range]::-ms-fill-upper { 
 +           background: #E3E3E3; 
 +           border: 0px solid #000000; 
 +           border-radius: 0px; 
 +           box-shadow: 0px 0px 0px #000000; 
 +         } 
 +         input[type=range]::-ms-thumb { 
 +           box-shadow: 1px 1px 2px #B8B8B8; 
 +           border: 1px solid #ABABAB; 
 +           height: 13px; 
 +           width: 25px; 
 +           border-radius: 20px; 
 +           background: #E0E0E0; 
 +           cursor: pointer; 
 +         } 
 +         input[type=range]:focus::-ms-fill-lower { 
 +           background: #E3E3E3; 
 +         } 
 +         input[type=range]:focus::-ms-fill-upper { 
 +           background: #E3E3E3; 
 +         } 
 +/* 
 +// COMMON_CODE_BLOCK_END 
 +*/ 
 + </style> 
 +   </head> 
 +<body> 
 +   <div class='threejs_container'> 
 + <div id='settings_1' class='settings'> 
 + <div class=group id='transparency_1' class='transparency'> 
 + <strong>Transparency</strong> 
 + <input id='transparencyRange_1' type='range' min=0 max=1 step=0.01 value=0> 
 + </div> 
 +  
 + <div class=group id='rotation_1'> 
 + <strong>Rotation</strong> 
 + <div class=indented> 
 + <div><input type='checkbox' id='changeRotationX_1'> x-axis</div> 
 + <div><input type='checkbox' id='changeRotationY_1'> y-axis</div> 
 + <div><input type='checkbox' id='changeRotationZ_1'> z-axis</div> 
 + <button id='resetButton_1'>Reset</button> 
 + </div>
  
-   <!-- POINTS --+ <div class=suboption>Rotation speed</div
-   allpoints[0].makesphere(0.02,points_material); + <input id='rotationSpeedRange_1' type='range' min=max=5 step=0.01 value=2>
-   allpoints[1].makesphere(0.02,points_material); +
-   allpoints[2].makesphere(0.02,points_material); +
-   allpoints[3].makesphere(0.02,points_material); +
-   allpoints[0].makelabel("0"); +
-   allpoints[1].makelabel("1"); +
-   allpoints[2].makelabel("2"); +
-   allpoints[3].makelabel("3");+
  
-   for (index = 0; index < allpoints.length++index) { + </div> 
-      allpoints[index].add(obj);+ 
 + 
 + <div class=group id='display_1'> 
 + <strong>Display</strong> 
 + <div class=indented> 
 + <div id='shownObjectTypesList_1' class='shownObjectsList'></div> 
 + </div> 
 + <div class=suboption>Objects</div> 
 + <div class=indented> 
 + <div id='shownObjectsList_1' class='shownObjectsList'></div> 
 + </div> 
 + </div> 
 + 
 + 
 + <div class=group id='svg_1'> 
 + <strong>SVG</strong> 
 + <div class=indented> 
 + <form> 
 + <input type="radio" name='screenshotMode' value='download' id='download_1' checked> Download<br> 
 + <input type="radio" name='screenshotMode' value='tab' id='tab_1' > New tab<br> 
 + </form> 
 + <button id='takeScreenshot_1'>Screenshot</button> 
 + </div> 
 + </div> 
 + 
 + </div> <!-- end of settings --> 
 + <img id='hideSettingsButton_1' class='hideSettingsButton' src='/kernelspecs/r118/polymake/close.svg' width=20px"> 
 + <img id='showSettingsButton_1' class='showSettingsButton' src='/kernelspecs/r118/polymake/menu.svg' width=20px"> 
 +<div id="model29171150745"></div> 
 +</div> 
 +   <script> 
 +    requirejs.config({ 
 +      paths: { 
 +        three: '/kernelspecs/r118/polymake/three', 
 +        TrackballControls: '/kernelspecs/r118/polymake/TrackballControls', 
 +        Projector: '/kernelspecs/r118/polymake/Projector', 
 +        SVGRenderer: '/kernelspecs/r118/polymake/SVGRenderer', 
 +        WEBGL: '/kernelspecs/r118/polymake/WebGL', 
 +      }, 
 +      shim: { 
 +        'three': { exports: 'THREE'}, 
 +        'SVGRenderer': { deps: [ 'three' ], exports: 'THREE.SVGRenderer' }, 
 +        'WEBGL': { deps: [ 'three' ], exports: 'THREE.WEBGL' }, 
 +        'Projector': { deps: [ 'three' ], exports: 'THREE.Projector' }, 
 +        'TrackballControls': { deps: [ 'three' ], exports: 'THREE.TrackballControls'
 +      } 
 +    }); 
 +     
 +    require(['three'],function(THREE){ 
 +        window.THREE = THREE; 
 +      require(['TrackballControls','Projector','SVGRenderer','WEBGL'],function(TrackballControls,Projector,SVGRenderer,WEBGL) { 
 +    THREE.TrackballControls = TrackballControls; 
 +    THREE.Projector = Projector; 
 +    THREE.SVGRenderer = SVGRenderer; 
 +    THREE.WEBGL = WEBGL; 
 + 
 +// COMMON_CODE_BLOCK_BEGIN 
 + 
 +const intervalLength = 25; // for automatic animations 
 +const explodableModel = false;  
 +const modelContains = { points: false, pointlabels: false, lines: false, edgelabels: false, faces: false, arrowheads: false }; 
 +const foldables = []; 
 + 
 +var three = document.getElementById("model29171150745"); 
 +var scene new THREE.Scene(); 
 + 
 +var camera = new THREE.PerspectiveCamera(75, 1, 0.1, 1000); 
 +camera.position.set(0, 0, 5); 
 +camera.lookAt(0, 0, 0); 
 +camera.up.set(0, 1, 0); 
 + 
 +var renderer = new THREE.WebGLRenderer( { antialias: true } ); 
 +var svgRenderer = new THREE.SVGRenderer({antialias: true}); 
 +renderer.setPixelRatio( window.devicePixelRatio ); 
 +renderer.setClearColor(0xFFFFFF, 1); 
 +svgRenderer.setClearColor(0xFFFFFF, 1); 
 +three.appendChild(renderer.domElement); 
 + 
 +var control = new THREE.TrackballControls(camera, three); 
 +control.zoomSpeed = 0.2; 
 +control.rotateSpeed = 4; 
 + 
 +function onWindowResize() { 
 +    var width = three.clientWidth; 
 +    var height = three.clientHeight; 
 +    renderer.setSize( width, height ); 
 +    svgRenderer.setSize( width, height ); 
 +    camera.aspect = width / height; 
 +    camera.updateProjectionMatrix(); 
 +
 + 
 +onWindowResize(); 
 +window.addEventListener('resize', onWindowResize);  
 + 
 +// class to allow move points together with labels and spheres 
 +var PMPoint = function (x,y,z) { 
 +   this.vector = new THREE.Vector3(x,y,z); 
 +   this.sprite = null; 
 +   this.sphere = null; 
 +
 +PMPoint.prototype.addLabel = function(labelsprite) { 
 +   this.sprite = labelsprite; 
 +   this.sprite.position.copy(this.vector); 
 +
 +PMPoint.prototype.addSphere = function(spheremesh) { 
 +   this.sphere = spheremesh; 
 +   this.sphere.position.copy(this.vector); 
 +
 +PMPoint.prototype.set = function(x,y,z) { 
 +   this.vector.set(x,y,z); 
 +   if (this.sprite) { 
 +      this.sprite.position.copy(this.vector);
    }    }
-   var faces new THREE.Geometry();+   if (this.sphere) { 
 +      this.sphere.position.copy(this.vector); 
 +   } 
 +
 +PMPoint.prototype.radius = function() { 
 +   if (this.sphere) { 
 +      return this.sphere.geometry.parameters.radius; 
 +   } else { 
 +      return 0; 
 +   } 
 +}; 
 +// select the target node 
 +var target document.querySelector('#model29171150745');
  
-   <!-- VERTICES --> +// create an observer instance 
-   faces.vertices.push(allpoints[0].vector); +var observer = new MutationObserver(function(mutations) { 
-   faces.vertices.push(allpoints[1].vector); +   mutations.forEach(function(mutation{ 
-   faces.vertices.push(allpoints[2].vector); +      if (mutation.removedNodes && mutation.removedNodes.length > 0) { 
-   faces.vertices.push(allpoints[3].vector);+         cancelAnimationFrame(renderId); 
 +         observer.disconnect(); 
 +         console.log("cancelled frame "+renderId); 
 +      } 
 +   }); 
 +});
  
-   centroids.push(computeCentroid(faces));+// configuration of the observer: 
 +var config = { childList: true, characterData: true }
  
 +// pass in the target node, as well as the observer options
 +while (target) {
 +   if (target.className=="output") {
 +      observer.observe(target, config);
 +      break;
 +   }
 +   target = target.parentNode;
 +}
 +
 +// COMMON_CODE_BLOCK_END
 +
 +var obj0 = new THREE.Object3D();
 +obj0.name = "planar_net_";
 +obj0.userData.explodable = 1;
 +obj0.userData.points = [];
 +obj0.userData.points.push(new PMPoint(0, 0, 0));
 +obj0.userData.points.push(new PMPoint(2, 0, 0));
 +obj0.userData.points.push(new PMPoint(2, 2, 0));
 +obj0.userData.points.push(new PMPoint(0, 2, 0));
 +obj0.userData.points.push(new PMPoint(0, -2, 0));
 +obj0.userData.points.push(new PMPoint(2, -2, 0));
 +obj0.userData.points.push(new PMPoint(2, 4, 0));
 +obj0.userData.points.push(new PMPoint(0, 4, 0));
 +obj0.userData.points.push(new PMPoint(-2, 2, 0));
 +obj0.userData.points.push(new PMPoint(-2, 0, 0));
 +obj0.userData.points.push(new PMPoint(4, 0, 0));
 +obj0.userData.points.push(new PMPoint(4, 2, 0));
 +obj0.userData.points.push(new PMPoint(0, -4, 0));
 +obj0.userData.points.push(new PMPoint(2, -4, 0));
 +
 +obj0.userData.pointradii = 0.02;
 +   <!-- Vertex style -->
 +obj0.userData.pointmaterial = new THREE.MeshBasicMaterial( { color: 0xFF0000, side: THREE.DoubleSide, transparent: false } );
 +obj0.userData.pointlabels = ["0", "4", "6", "2", "1", "5", "7", "3", "3", "1", "5", "7", "3", "7"];
 +obj0.userData.edgeindices = [0, 1, 1, 2, 0, 3, 2, 3, 0, 4, 1, 5, 4, 5, 2, 6, 3, 7, 6, 7, 3, 8, 0, 9, 8, 9, 1, 10, 2, 11, 10, 11, 4, 12, 5, 13, 12, 13];
 +   <!-- Edge style -->
 +obj0.userData.edgematerial = new THREE.LineBasicMaterial( { color: 0x000000, depthTest: true, linewidth: 1.5, transparent: false } );
 +obj0.userData.facets = [[0, 1, 2, 3], [13, 5, 4, 12], [5, 1, 0, 4], [3, 2, 6, 7], [0, 3, 8, 9], [2, 1, 10, 11]];
    <!-- Facet style -->    <!-- Facet style -->
-   var faces_material = new THREE.MeshBasicMaterial ( {color: 0x77EC9E, transparent: true, opacity: 1, side: THREE.DoubleSide , depthWrite: true, depthTest: true, } );+obj0.userData.facetmaterial = new THREE.MeshBasicMaterial( { color: 0x77EC9E, depthFunc: THREE.LessDepth, depthWrite: true, opacity: 1, polygonOffset: true, polygonOffsetFactor: 1, polygonOffsetUnits: 1, side: THREE.DoubleSide, transparent: true } )
 +obj0.userData.axes = [[5,4], 
 +      [2,1], 
 +      [0,3], 
 +      [3,2], 
 +      [1,0]];
  
-   faces_material.side THREE.DoubleSide; +obj0.userData.angles [1.5707963267949, 
-   faces_material.transparent = true;+      1.5707963267949, 
 +      1.5707963267949, 
 +      1.5707963267949, 
 +      1.5707963267949];
  
-   <!-- FACETS -->  +obj0.userData.subtrees = [[12,13], 
-   faces.faces.push(new THREE.Face3(231undefinedundefined0));+      [10,11], 
 +      [8,9], 
 +      [6,7], 
 +      [4,5,12,13]];
  
-   faces.faces.push(new THREE.Face3(032undefinedundefined, 0));+obj0.userData.polytoperoot = [[-1,-1,-1], 
 +      [-1,0,0], 
 +      [0,2,0]];
  
-   faces.faces.push(new THREE.Face3(13, 0, undefinedundefined, 0));+obj0.userData.oldscale = 0; 
 +foldables.push(obj0); 
 +init_object(obj0); 
 +scene.add(obj0); 
 +// COMMON_CODE_BLOCK_BEGIN 
 +function textSpriteMaterial(messageparameters) { 
 +    if ( parameters === undefined ) parameters = {}; 
 +    var fontface = "Helvetica"; 
 +    var fontsize = parameters.hasOwnProperty("fontsize") ? parameters["fontsize"] : 18; 
 +    fontsize = fontsize*10; 
 +    var lines = message.split('\\n'); 
 +    var size = 512; 
 +    for(var i = 0; i<lines.length; i++){ 
 +        var tmp = lines[i].length; 
 +        while(tmp*fontsize > size){ 
 +           fontsize--; 
 +        } 
 +    } 
 +     
 +    var canvas = document.createElement('canvas'); 
 +    canvas.width = size; 
 +    canvas.height = size; 
 +    var context = canvas.getContext('2d'); 
 +    context.fillStyle = "rgba(255255, 255, 0)"; 
 +    context.fill(); 
 +    context.font = fontsize + "px " + fontface; 
 +     
 +    // text color 
 +    context.fillStyle = "rgba(0, 001.0)"; 
 +     for(var i = 0; i<lines.length; i++)
 +        context.fillText(lines[i], size/2, size/2+i*fontsize); 
 +     } 
 +     
 +    // canvas contents will be used for a texture 
 +    var texture = new THREE.Texture(canvas); 
 +    texture.needsUpdate = true; 
 +     
 +    var spriteMaterial = new THREE.SpriteMaterial({map: texture, depthTest: true, depthWrite: false, depthFunc: THREE.LessEqualDepth}); 
 +    return spriteMaterial; 
 +}
  
-   faces.faces.push(new THREE.Face3(2, 1, 0, undefined, undefined, 0)); 
  
 +// ---------------------- INITIALIZING OBJECTS--------------------------------------
 +// ---------------------------------------------------------------------------------
  
-   faces.computeFaceNormals(); +function init_object(obj) { 
-   faces.computeVertexNormals();+    if (obj.userData.hasOwnProperty("pointmaterial")) { 
 +        init_points(obj); 
 +        modelContains.points = true; 
 +    } 
 +    if (obj.userData.hasOwnProperty("pointlabels")) { 
 +        init_pointlabels(obj); 
 +        modelContains.pointlabels = true; 
 +    } 
 +    if (obj.userData.hasOwnProperty("edgematerial")) { 
 +        init_lines(obj); 
 +        modelContains.lines = true; 
 +    } 
 +    if (obj.userData.hasOwnProperty("edgelabels")) { 
 +        init_edgelabels(obj); 
 +        modelContains.edgelabels = true; 
 +    } 
 +    if (obj.userData.hasOwnProperty("arrowstyle")) { 
 +        init_arrowheads(obj); 
 +        modelContains.arrowheads = true; 
 +    } 
 +    if (obj.userData.hasOwnProperty("facetmaterial")) { 
 +        init_faces(obj); 
 +        modelContains.faces = true; 
 +    } 
 +}
  
-   var object = new THREE.Mesh(facesfaces_material); +function init_points(obj) { 
-   obj.add(object);+   var pointgroup = new THREE.Group(); 
 +   pointgroup.name = "points"; 
 +   var points = obj.userData.points; 
 +   var radii = obj.userData.pointradii; 
 +   var materials = obj.userData.pointmaterial; 
 +   var geometry,material; 
 +   if (!Array.isArray(radii)) { 
 +      geometry = new THREE.SphereBufferGeometry(radii);   
 +   } 
 +   if (!Array.isArray(materials)) { 
 +      material = materials; 
 +   } 
 +   for (var i=0; i<points.length; i++) { 
 +      var point = points[i]; 
 +      if (Array.isArray(radii)) { 
 +         if (radii[i] == 0) { 
 +            continue; 
 +         } 
 +         geometry = new THREE.SphereBufferGeometry(radii[i]);   
 +      }  
 +      if (Array.isArray(materials)) { 
 +         material = materials[i];     
 +      }  
 +      var sphere = new THREE.Mesh(geometrymaterial); 
 +      point.addSphere(sphere); 
 +      pointgroup.add(sphere); 
 +   } 
 +   obj.add(pointgroup); 
 +}
  
-   <!-- Edge style --> +function init_pointlabels(obj) { 
-   var line_material = new THREE.LineBasicMaterial ( {color: 0x000000, linewidth: 1.5, } );+   var points = obj.userData.points; 
 +   var labels = obj.userData.pointlabels; 
 +   var pointlabels = new THREE.Group(); 
 +   pointlabels.name = "pointlabels"; 
 +   if (Array.isArray(labels)) { 
 +      for (var i=0; i<points.length; i++) { 
 +         var point = points[i]; 
 +         var spriteMaterial = textSpriteMaterial( labels[i] ); 
 +       var sprite = new THREE.Sprite(spriteMaterial); 
 +         point.addLabel(sprite); 
 +         pointlabels.add(sprite); 
 +      } 
 +   } else { 
 +      var spriteMaterial = textSpriteMaterial( labels ); 
 +      for (var i=0; i<points.length; i++) { 
 +         var point = points[i]; 
 +       var sprite = new THREE.Sprite(spriteMaterial); 
 +         point.addLabel(sprite); 
 +         pointlabels.add(sprite); 
 +      } 
 +   } 
 +   obj.add(pointlabels); 
 +}
  
-   line_material.side = THREE.DoubleSide+function init_lines(obj) { 
-   line_material.transparent true;+   var edgeindices = obj.userData.edgeindices; 
 +   var points obj.userData.points; 
 +   var materials = obj.userData.edgematerial; 
 +   var geometry = new THREE.BufferGeometry()
 +   var bufarr = new Float32Array( obj.userData.edgeindices.length * 3 ); 
 +   var bufattr new THREE.Float32BufferAttribute( bufarr, 3 ); 
 +   var geometry = new THREE.BufferGeometry(); 
 +   geometry.setAttribute('position', bufattr); 
 +   if (Array.isArray(materials)) {      
 +      for (var i=0; i<materials.length; i++) { 
 +         geometry.addGroup(2*i,2,i); 
 +      } 
 +   } 
 +   var lines = new THREE.LineSegments(geometry, materials); 
 +   lines.name = "lines"; 
 +   obj.add(lines); 
 +   updateEdgesPosition(obj); 
 +}
  
-   <!-- EDGES -->  +function init_edgelabels(obj) { 
-   var line = new THREE.Geometry(); +   var points = obj.userData.points; 
-   line.vertices.push(allpoints[2].vector); +   var edgeindices = obj.userData.edgeindices; 
-   line.vertices.push(allpoints[3].vector); +   var labels = obj.userData.edgelabels; 
-   line.vertices.push(allpoints[1].vector); +   var edgelabels = new THREE.Group(); 
-   line.vertices.push(allpoints[2].vector); +   edgelabels.name = "edgelabels"; 
-   obj.add(new THREE.Line(line, line_material));+   if (Array.isArray(labels)) { 
 +      for (var i=0; i<edgeindices.length; i=i+2) { 
 +         var point = points[i]
 +         var spriteMaterial = textSpriteMaterial( labels[i] ); 
 +      var sprite = new THREE.Sprite(spriteMaterial); 
 +         sprite.position.copy(new THREE.Vector3().addVectors(points[edgeindices[i]].vector,points[edgeindices[i+1]].vector).multiplyScalar(0.5)); 
 +         edgelabels.add(sprite); 
 +      } 
 +   } else { 
 +      var spriteMaterial = textSpriteMaterial( labels ); 
 +      for (var i=0; i<points.length; i++) { 
 +         var point = points[i]
 +      var sprite = new THREE.Sprite(spriteMaterial); 
 +         sprite.position.copy(new THREE.Vector3().addVectors(points[edgeindices[i]].vector,points[edgeindices[i+1]].vector).multiplyScalar(0.5)); 
 +         pointlabels.add(sprite); 
 +      } 
 +   } 
 +   obj.add(edgelabels); 
 +}
  
-   var line = new THREE.Geometry(); +function init_arrowheads(obj) { 
-   line.vertices.push(allpoints[0].vector)+    var arrowheads = new THREE.Group(); 
-   line.vertices.push(allpoints[3].vector)+    arrowheads.name = "arrowheads"; 
-   line.vertices.push(allpoints[2].vector)+    var arrowstyle = obj.userData.arrowstyle
-   line.vertices.push(allpoints[0].vector)+    var edgeindices = obj.userData.edgeindices
-   obj.add(new THREE.Line(line, line_material));+    var edgematerials = obj.userData.edgematerial
 +    var points = obj.userData.points
 +    var material; 
 +    if (!Array.isArray(edgematerials)) { 
 +        material = new THREE.MeshBasicMaterial{color: edgematerials.color} ); 
 +    }
  
-   var line = new THREE.Geometry(); +    for (var i=0; i<edgeindices.length; i=i+2) { 
-   line.vertices.push(allpoints[1].vector); +        var start = points[edgeindices[i]]; 
-   line.vertices.push(allpoints[3].vector); +        var end = points[edgeindices[i+1]]; 
-   line.vertices.push(allpoints[0].vector); +        var dist = start.vector.distanceTo( end.vector ) - start.radius() - end.radius(); 
-   line.vertices.push(allpoints[1].vector); +        if (dist <= 0) { 
-   obj.add(new THREE.Line(lineline_material));+            continue; 
 +        } 
 +        var dir = new THREE.Vector3().subVectors(end.vector,start.vector); 
 +        dir.normalize(); 
 +        var axis = new THREE.Vector3().set(dir.z,0,-dir.x); 
 +        axis.normalize(); 
 +        var radians = Math.acos( dir.y ); 
 +        var radius = dist/25; 
 +        var height = dist/5; 
 +        var geometry = new THREE.ConeBufferGeometry(radius,height); 
 +        var position = new THREE.Vector3().addVectors(start.vector,dir.clone().multiplyScalar(start.radius()+dist-height/2)); 
 +        if (Array.isArray(edgematerials)) { 
 +            material = new THREE.MeshBasicMaterial{color: edgematerials[i].color} ); 
 +        } 
 +        var cone = new THREE.Mesh( geometry, material ); 
 +        cone.quaternion.setFromAxisAngle(axis,radians);; 
 +        cone.position.copy(position);; 
 +        arrowheads.add(cone); 
 +    } 
 +    obj.add(arrowheads); 
 +
 + 
 +function init_faces(obj) { 
 +   var points = obj.userData.points; 
 +   var facets = obj.userData.facets; 
 +   obj.userData.triangleindices = []; 
 +   for (var i=0; i<facets.length; i++) { 
 +      facet = facets[i]; 
 +      for (var t=0; t<facet.length-2; t++) { 
 +         obj.userData.triangleindices.push(facet[0],facet[t+1],facet[t+2]);   
 +      } 
 +   } 
 +   var bufarr = new Float32Array( obj.userData.triangleindices.length * 3 ); 
 +   var bufattr = new THREE.Float32BufferAttribute(bufarr,3); 
 +    
 +   var materials = obj.userData.facetmaterial; 
 +   var geometry = new THREE.BufferGeometry(); 
 +   geometry.setAttribute('position',bufattr); 
 +   if (Array.isArray(materials)) { 
 +      var tricount = 0; 
 +      var facet; 
 +      for (var i=0; i<facets.length; i++) { 
 +         facet = facets[i]
 +         geometry.addGroup(tricount,(facet.length-2)*3,i); 
 +         tricount += (facet.length-2)*3; 
 +      } 
 +   } 
 +   var mesh = new THREE.Mesh(geometry, materials); 
 +   mesh.name = "faces"
 +   obj.add(mesh);  
 +   updateFacesPosition(obj); 
 +
 +// //INITIALIZING 
 + 
 + 
 +function updateFacesPosition(obj) { 
 +   var points = obj.userData.points; 
 +   var indices = obj.userData.triangleindices; 
 +   var faces = obj.getObjectByName("faces"); 
 +   var ba = faces.geometry.getAttribute("position"); 
 +   for (var i=0; i<indices.length; i++) { 
 +      ba.setXYZ(ipoints[indices[i]].vector.x, points[indices[i]].vector.y ,points[indices[i]].vector.z);  
 +   } 
 +   faces.geometry.attributes.position.needsUpdate = true; 
 +    
 +
 + 
 +function updateEdgesPosition(obj
 +   var points = obj.userData.points; 
 +   var indices = obj.userData.edgeindices; 
 +   var lines = obj.getObjectByName("lines"); 
 +   var ba = lines.geometry.getAttribute("position");  
 +   for (var i=0; i<indices.length; i++) { 
 +      ba.setXYZ(i, points[indices[i]].vector.x, points[indices[i]].vector.y ,points[indices[i]].vector.z);  
 +   } 
 +   lines.geometry.attributes.position.needsUpdate = true; 
 +}
  
-   var line = new THREE.Geometry(); 
-   line.vertices.push(allpoints[2].vector); 
-   line.vertices.push(allpoints[1].vector); 
-   line.vertices.push(allpoints[0].vector); 
-   line.vertices.push(allpoints[2].vector); 
-   obj.add(new THREE.Line(line, line_material)); 
  
-   scene.add(obj); 
-   all_objects.push(obj); 
  
-// COMMON_CODE_BLOCK_BEGIN 
 var xRotationEnabled = false; var xRotationEnabled = false;
 var yRotationEnabled = false; var yRotationEnabled = false;
Line 462: Line 1892:
 var renderId; var renderId;
  
- var render = function () {+var render = function () {
  
- renderId = requestAnimationFrame(render);+ renderId = requestAnimationFrame(render);
  
-// comment in for automatic explosion +// comment in for automatic explosion 
-// explode(updateFactor());+// explode(updateFactor());
  
- var phi = 0.02 * rotationSpeedFactor;+    var phi = 0.02 * rotationSpeedFactor;
  
- if (xRotationEnabled){ +    if (xRotationEnabled) { 
- scene.rotation.x += phi; +        scene.rotation.x += phi; 
- +    
- if(yRotationEnabled){ +    if (yRotationEnabled) { 
- scene.rotation.y += phi; +        scene.rotation.y += phi; 
- +    
- if(zRotationEnabled){ +    if (zRotationEnabled) { 
- scene.rotation.z += phi; +        scene.rotation.z += phi; 
- }+    }
  
- controls.update(); +    control.update(); 
- renderer.render(scene, camera); +    renderer.render(scene, camera); 
- };+};
  
 +if ( THREE.WEBGL.isWebGLAvailable() ) {
  render();  render();
 +} else {
 + var warning = WEBGL.getWebGLErrorMessage();
 + three.appendChild( warning );
 +}
 +    
 +function changeTransparency() {
 +    var opacity = 1-Number(event.currentTarget.value);
 +    for (var i=0; i<scene.children.length; i++) {
 +        child = scene.children[i];
 +        if ( child.userData.hasOwnProperty("facetmaterial") ) {
 +            if (Array.isArray(child.userData.facetmaterial)) {
 +                for (var j=0; j<child.userData.facetmaterial.length; j++) {
 +                    child.userData.facetmaterial[j].opacity = opacity;
 +                }
 +            } else {
 +                child.userData.facetmaterial.opacity = opacity;
 +            }    
 +        }
 +    }
 +}
  
- function computeCentroid(geom) { +function changeRotationX(event){ 
- centroid new THREE.Vector3(); +    xRotationEnabled event.currentTarget.checked
- geom.vertices.forEach(function(v) { +}
- centroid.add(v);  +
- }); +
- centroid.divideScalar(geom.vertices.length); +
- return centroid+
- }+
  
- function changeTransparency(event){ +function changeRotationY(event){ 
- var opacity 1-Number(event.currentTarget.value); +    yRotationEnabled = event.currentTarget.checked
- for (var i=0; i<all_objects.length; i++){ +}
- for (var j=0; j<all_objects[i].children.length; j++){ +
- if (all_objects[i].children[j].material.type == "MultiMaterial") { +
- for (var k=0; k<all_objects[i].children[j].material.materials.length; k++){ +
- all_objects[i].children[j].material.materials[k].opacity = opacity; +
- all_objects[i].children[j].material.materials[k].depthWrite = opacity < 0.5 ? false : true; +
- all_objects[i].children[j].material.materials[k].depthTest = opacity < 0.5 ? false : true; +
-+
- } else if (all_objects[i].children[j].material.transparent &&  +
-   all_objects[i].children[j].material.type == "MeshBasicMaterial" && +
-   all_objects[i].children[j].geometry.type == "Geometry"){ +
- all_objects[i].children[j].material.opacity = opacity; +
- all_objects[i].children[j].material.depthWrite = opacity < 0.5 ? false : true; +
- all_objects[i].children[j].material.depthTest = opacity < 0.5 ? false : true; +
-+
-+
- } +
- }+
  
- function changeRotationX(event){ +function changeRotationZ(event){ 
- xRotationEnabled = event.currentTarget.checked; +    zRotationEnabled = event.currentTarget.checked; 
- } +}
  
- function changeRotationY(event){ 
- yRotationEnabled = event.currentTarget.checked; 
- }  
  
- function changeRotationZ(event){ +function changeRotationSpeedFactor(event){ 
- zRotationEnabled = event.currentTarget.checked+    rotationSpeedFactor Number(event.currentTarget.value)
- } +}
  
 +function resetScene(){
 +    scene.rotation.set(0,0,0);
 +    camera.position.set(0,0,5);
 +    camera.up.set(0,1,0);
 +}
  
- function changeRotationSpeedFactor(event){ +function showSettings(event){ 
- rotationSpeedFactor Number(event.currentTarget.value); +    document.getElementById('settings_1').style.visibility 'visible'; 
- }+    document.getElementById('showSettingsButton_1').style.visibility = 'hidden'; 
 +    document.getElementById('hideSettingsButton_1').style.visibility = 'visible'; 
 +    settingsShown = true
 +}
  
- function resetScene(){ +function hideSettings(event){ 
- scene.rotation.set(0,0,0); +    document.getElementById('settings_1').style.visibility = 'hidden'
- camera.position.set(0,0,5); +    document.getElementById('showSettingsButton_1').style.visibility = 'visible'
- camera.up.set(0,1,0); +    document.getElementById('hideSettingsButton_1').style.visibility = 'hidden'; 
- }+    settingsShown = false
 +}
  
- function showSettings(event){ 
- event.currentTarget.style.display = 'none'; 
- document.getElementById('settings_0').style.position = 'absolute'; 
- document.getElementById('settings_0').style.display = 'block'; 
- document.getElementById('showSettingsButton_0').style.display = 'none'; 
- document.getElementById('hideSettingsButton_0').style.display = 'block'; 
- settingsShown = true; 
- } 
  
- function hideSettings(event){ 
- event.currentTarget.style.display = 'none'; 
- document.getElementById('settings_0').style.display = 'none'; 
- document.getElementById('hideSettingsButton_0').style.display = 'none'; 
- document.getElementById('showSettingsButton_0').style.display = 'block'; 
- settingsShown = false; 
- } 
  
 +var pos = 150* Math.PI;
  
 +function updateFactor() {
 +    pos++;
 +    return Math.sin(.01*pos)+1;
 +}
  
- var pos 150* Math.PI;+// ------------------------ FOLDING ------------------------------------------------ 
 +// --------------------------------------------------------------------------------- 
 +// rotate point p around axis defined by points p1 and p2 by given angle 
 +function rotate(p, p1, p2, angle ){    
 +   angle = -angle; 
 +   var p.x, y = p.y, z = p.z,  
 +   a = p1.x, b = p1.y, c = p1.z,  
 +   u = p2.x-p1.x, v = p2.y-p1.y, w = p2.z-p1.z; 
 +   var result = []; 
 +   var L = u*u + v*v + w*w; 
 +   var sqrt = Math.sqrt; 
 +   var cos = Math.cos; 
 +   var sin = Math.sin;
  
- function updateFactor() +   result[0] = ((a*(v*v+w*w)-u*(b*v+c*w-u*x-v*y-w*z))*(1-cos(angle))+L*x*cos(angle)+sqrt(L)*(-c*v+b*w-w*y+v*z)*sin(angle))/L
- pos++; +   result[1] = ((b*(u*u+w*w)-v*(a*u+c*w-u*x-v*y-w*z))*(1-cos(angle))+L*y*cos(angle)+sqrt(L)*(c*u-a*w+w*x-u*z)*sin(angle))/L
- return Math.sin(.01*pos)+1; +   result[2] = ((c*(u*u+v*v)-w*(a*u+b*v-u*x-v*y-w*z))*(1-cos(angle))+L*z*cos(angle)+sqrt(L)*(-b*u+a*v-v*x+u*y)*sin(angle))/L;
- }+
  
- function makelabel(message, x, y, z, params) { +   return result
- var spritey = textSprite( message, params ); +}
- spritey.position.set(x, y, z); +
- obj.add(spritey)+
- }+
  
- function textSprite(message, parameters) +var fold = function(event){ 
- +    var obj = foldables[Number(event.currentTarget.name)]; 
- if parameters === undefined parameters {};+    var foldvalue Number(event.currentTarget.value)
 +    var scale foldvalue - obj.userData.oldscale;
  
- var fontface "Helvetica";+    for (var j=0j<obj.userData.axes.length; j++) { 
 +        rotateVertices(obj, j, scale); 
 +    } 
 +    update(obj); 
 +    obj.userData.oldscale += scale; 
 +    lookAtBarycenter(obj); 
 +}
  
- var fontsize = parameters.hasOwnProperty("fontsize" +function lookAtBarycenter(obj){ 
- parameters["fontsize"] : 18; +    control.target barycenter(obj); 
- fontsize fontsize*10;+}
  
- var canvas document.createElement('canvas'); +function barycenter(obj) { 
- var size 1024+   var center new THREE.Vector3(0,0,0); 
- canvas.width size; +   var points obj.userData.points
- canvas.height = size+   for (var i=0i<points.lengthi++){ 
- var context = canvas.getContext('2d'); +      center.add(points[i].vector); 
- context.font = fontsize + "px " + fontface;+   } 
 +   center.divideScalar(points.length); 
 +   return center; 
 +}
  
- // text color +function rotateVertices(obj, edge, scale) { 
- context.fillStyle "rgba(0, 0, 0, 1.0)";+   var axes = obj.userData.axes; 
 +   var subtrees obj.userData.subtrees; 
 +   var points = obj.userData.points; 
 +   var angles = obj.userData.angles; 
 +   if (edge < axes.length){ 
 +      for (var j=0; j<subtrees[edge].length; j++){ 
 +         var rotP = rotate(points[subtrees[edge][j]].vectorpoints[axes[edge][0]].vector,points[axes[edge][1]].vector, scale * (Math.PI - angles[edge])); 
 +         points[subtrees[edge][j]].set(rotP[0],rotP[1],rotP[2]); 
 +      } 
 +   } 
 +}
  
- context.fillText(message, size/2, size/2);+function update(obj) { 
 +   updateFacesPosition(obj); 
 +   updateEdgesPosition(obj); 
 +}
  
- // canvas contents will be used for a texture +if (foldables.length) { 
- var texture new THREE.Texture(canvas); +    var settings = document.getElementById('settings_1'); 
- texture.needsUpdate true;+    var foldDiv = document.createElement('div'); 
 +    foldDiv.id = 'fold_1'; 
 +    var title = document.createElement('strong'); 
 +    title.innerHTML = 'Fold'; 
 +    foldDiv.appendChild(title); 
 +    foldDiv.className = 'group'; 
 +    for (var i=0; i<foldables.length; i++) { 
 +        var range document.createElement('input'); 
 +        range.type 'range'; 
 +        range.min = 0; 
 +        range.max = 1; 
 +        range.value = 0; 
 +        range.step = 0.001; 
 +        range.name = String(i); 
 +        range.oninput = fold; 
 +        foldDiv.appendChild(range); 
 +    } 
 +    lookAtBarycenter(foldables[0]); 
 +    settings.insertBefore(foldDiv,settings.childNodes[0]); 
 +}
  
- var spriteMaterial = new THREE.SpriteMaterial( +     
- {map: texture, useScreenCoordinates: false}); +// ---------------------- EXPLOSION ------------------------------------------------ 
- var sprite = new THREE.Sprite(spriteMaterial); +// ---------------------------------------------------------------------------------
- return sprite; +
- }+
  
- function takeSvgScreenshot(){ +if (explodableModel) { 
- if (labelsShown){ +    for (var i=0; i<scene.children.length; i++) { 
- hideLabels(); +        obj = scene.children[i]; 
- +        if ( obj.userData.explodable ) { 
- svgRenderer.render(scene,camera); +            computeCentroid(obj); 
- svgElement = XMLS.serializeToString(svgRenderer.domElement); +        
-  +    } 
- if (labelsShown){ +    document.getElementById('explodeRange_1').oninput = triggerExplode
- displayLabels(); +    document.getElementById('explodeCheckbox_1').onchange = triggerAutomaticExplode
- }+    document.getElementById('explodingSpeedRange_1').oninput = setExplodingSpeed
 +}
  
- if (document.getElementById('tab_0').checked){ +function computeCentroid(obj) { 
- //show in new tab +    centroid new THREE.Vector3(); 
- var myWindow window.open("",""); +    obj.userData.points.forEach(function(pmpoint) 
- myWindow.document.body.innerHTML = svgElement; +        centroid.add(pmpoint.vector);  
- } else+    }); 
- // download svg file  +    centroid.divideScalar(obj.userData.points.length); 
- download("screenshot.svg", svgElement); +    obj.userData.centroid = centroid; 
- } +}
- } +
- +
  
- function showOrHideObject(event){ +function explode(factor) { 
- var nr Number(event.currentTarget.name)+    for (var i=0; i<scene.children.lengthi++) { 
- all_objects[nr].visible event.currentTarget.checked+        var obj = scene.children[i]
- }+        if (obj.userData.hasOwnProperty("centroid")) {  
 +            var c obj.userData.centroid; 
 +            obj.position.set(c.x*factor, c.y*factor, c.z*factor); 
 +        } 
 +    }  
 +}
  
- function displayOrHideOptionsRecursiveobj ) { +function triggerExplode(event){ 
- for (var j=0; j<obj.children.length; j++) { +    explodeScale Number(event.currentTarget.value); 
- var child = obj.children[j]; +    explode(explodeScale); 
- if (child.material===undefined && child) { +}
- displayOrHideOptionsRecursive( child ); +
- } else { +
- if (child.material.type == "MultiMaterial"+
- for (var k=0k<child.material.materials.length; k++) { +
- if (child.material.materials[k].transparent+
- document.getElementById('transparency_0').style.display = 'block'; +
- document.getElementById('transparencyRange_0').value = 1 -  +
- child.material.materials[k].opacity; +
- return; +
-+
-+
- } else if ( child.material.transparent &&  +
- child.material.type == "MeshBasicMaterial" && +
- child.geometry.type == "Geometry"){ +
- document.getElementById('transparency_0').style.display = 'block'; +
- return; +
-+
-+
- } +
- }+
  
- function displayOrHideOptions() { +function setExplodingSpeed(event){ 
- for (var i=0; i<all_objects.length; i+++    explodingSpeed = Number(event.currentTarget.value); 
- var obj = all_objects[i]; +}
- displayOrHideOptionsRecursive( obj ); +
- } +
- }+
  
- displayOrHideOptions()+function triggerAutomaticExplode(event)
 +    if (event.currentTarget.checked){ 
 +        startExploding(); 
 +    } else { 
 +        clearIntervals(); 
 +    }  
 +}
  
 +function startExploding(){
 +    intervals.push(setInterval(explodingInterval, 25));
 +}
  
  
 +function explodingInterval(){
 +    explodeScale += explodingSpeed;
 +    if (explodeScale <= 6){ 
 +        explode(explodeScale);
 +    }
 +    else{
 +        explode(6);
 +        explodeScale = 6;
 +        clearIntervals();
 +        timeouts.push(setTimeout(startUnexploding, 3000));
 +    }
 +    document.getElementById('explodeRange_1').value = explodeScale;
 +}
  
-// ---------------------- EXPLOSION ------------------------------------------------ 
-// --------------------------------------------------------------------------------- 
  
- function explode(factor) { +function startUnexploding(){ 
- var obj, c; +    intervals.push(setInterval(unexplodingInterval25)); 
- var c0 = centroids[0]; +}
- for (var i = 0; i<centroids.length; ++i) { +
- c = centroids[i]; +
- obj = all_objects[all_objects.length - centroids.length + i]; +
- obj.position.set(c.x*factorc.y*factor, c.z*factor); +
- }  +
- }+
  
- function triggerExplode(event){ +function unexplodingInterval(){ 
- explodeScale = Number(event.currentTarget.value); +    explodeScale -explodingSpeed; 
- explode(explodeScale); +    if (explodeScale >= 0){  
- }+        explode(explodeScale); 
 +    } 
 +    else { 
 +        explode(0); 
 +        explodeScale = 0; 
 +        clearIntervals()
 +        timeouts.push(setTimeout(startExploding, 3000)); 
 +    } 
 +    document.getElementById('explodeRange_1').value = explodeScale
 +}
  
- function setExplodingSpeed(event){ +function clearIntervals(){ 
- explodingSpeed = Number(event.currentTarget.value); +    intervals.forEach(function(interval){ 
- }+        clearInterval(interval); 
 +    }); 
 +    intervals = []; 
 +    timeouts.forEach(function(timeout)
 +        clearTimeout(timeout); 
 +    }); 
 +    timeouts = []
 +}
  
- function triggerAutomaticExplode(event){ +// ---------------------- DISPLAY -------------------------------------------------- 
- if (event.currentTarget.checked){ +// ---------------------------------------------------------------------------------
- startExploding(); +
- } else { +
- clearIntervals(); +
- }  +
- }+
  
- function startExploding()+const objectTypeInnerHTMLs = points: "Points", pointlabels: "Point labels", lines: "Edges", edgelabels: "Edge labels", faces: "Faces", arrowheads: "Arrow heads" }; 
- intervals.push(setInterval(explodingInterval25)); +const objectTypeVisible = {}; 
- }+Object.assign(objectTypeVisible,modelContains)
 +const sortedObjectTypeKeys = Object.keys(objectTypeInnerHTMLs).sort(); 
 +const shownObjectTypesList = document.getElementById('shownObjectTypesList_1');
  
 +function setVisibility(bool,objname) {
 +    for (var i=0; i<scene.children.length; i++){
 +        var obj = scene.children[i].getObjectByName(objname);
 +        if (obj) {
 +            obj.visible = bool;
 +        }
 +    }
 +}
  
- function explodingInterval(){ +function toggleObjectTypeVisibility(event){ 
- explodeScale +explodingSpeed+    var name event.currentTarget.name
- if (explodeScale <6){  +    var checked event.currentTarget.checked
- explode(explodeScale)+    objectTypeVisible[name] checked
- +    setVisibility(checked,name); 
- else{ +}
- explode(6); +
- explodeScale 6+
- clearIntervals(); +
- timeouts.push(setTimeout(startUnexploding3000)); +
-+
- document.getElementById('explodeRange_0').value = explodeScale+
- }+
  
 +for (var i=0; i<sortedObjectTypeKeys.length; i++){
 +    var key = sortedObjectTypeKeys[i];
 +    if (modelContains[key]) {
 +        var objTypeNode = document.createElement('span');
 +        objTypeNode.innerHTML = objectTypeInnerHTMLs[key] + '<br>';
 +        var checkbox = document.createElement('input');
 +        checkbox.type = 'checkbox';
 +        checkbox.checked = true;
 +        checkbox.name = key;
 +        checkbox.onchange = toggleObjectTypeVisibility;
 +        shownObjectTypesList.appendChild(checkbox);
 +        shownObjectTypesList.appendChild(objTypeNode);
 +    }
 +}
  
- function startUnexploding(){ +// ------------------------------------------------------
- intervals.push(setInterval(unexplodingInterval, 25)); +
- }+
  
- function unexplodingInterval(){ +function toggleObjectVisibility(event){ 
- explodeScale -explodingSpeed; +    var nr Number(event.currentTarget.name); 
- if (explodeScale >= 0){  +    scene.children[nr].visible event.currentTarget.checked
- explode(explodeScale); +}
-+
- else { +
- explode(0); +
- explodeScale = 0; +
- clearIntervals(); +
- timeouts.push(setTimeout(startExploding, 3000)); +
- +
- document.getElementById('explodeRange_0').value explodeScale+
- }+
  
- function clearIntervals(){ +// append checkboxes for displaying or hiding objects 
- intervals.forEach(function(interval){ +var shownObjectsList = document.getElementById('shownObjectsList_1'); 
- clearInterval(interval); +for (var i=0i<scene.children.lengthi++){ 
- })+    obj scene.children[i]; 
- intervals = []; +    var objNode = document.createElement('span'); 
- timeouts.forEach(function(timeout){ +    objNode.innerHTML = obj.name + '<br>'; 
- clearTimeout(timeout); +    var checkbox = document.createElement('input'); 
- }); +    checkbox.type = 'checkbox'; 
- timeouts []+    checkbox.checked = true; 
- }+    checkbox.name = String(i); 
 +    checkbox.onchange toggleObjectVisibility; 
 +    shownObjectsList.appendChild(checkbox); 
 +    shownObjectsList.appendChild(objNode)
 +}
  
- +// ---------------------- SVG ------------------------------------------------------ 
 +// ---------------------------------------------------------------------------------
  
- // append checkboxes for displaying or hiding objects +function takeSvgScreenshot() { 
- var shownObjectsList = document.getElementById('shownObjectsList_0'); +    if (objectTypeVisible["pointlabels"]) { 
- for (var i=0; i<all_objects.length; i++){ +        setVisibility(false,"pointlabels"); 
- var objNode = document.createElement('span'); +    } 
- objNode.innerHTML = objectnames[i+ '<br>'; +    if (objectTypeVisible["edgelabels"]) { 
- var checkbox = document.createElement('input'); +        setVisibility(false,"edgelabels"); 
- checkbox.type = 'checkbox'; +    } 
- checkbox.checked = true+    svgRenderer.render(scene,camera)
- checkbox.name String(i); +    svgElement XMLS.serializeToString(svgRenderer.domElement); 
- checkbox.onchange = showOrHideObject; +     
- shownObjectsList.appendChild(checkbox); +    if (objectTypeVisible["pointlabels"]) { 
- shownObjectsList.appendChild(objNode); +        setVisibility(true,"pointlabels"); 
- }+    } 
 +    if (objectTypeVisible["edgelabels"]) { 
 +        setVisibility(true,"edgelabels"); 
 +    }
  
- function displayLabels(){ +    if (document.getElementById('tab_1').checked){ 
- for (var i=0; i<all_objects.lengthi++){ +        //show in new tab 
- for (var j=0; j<all_objects[i].children.lengthj++)+        var myWindow window.open("","")
- var child = all_objects[i].children[j]; +        myWindow.document.body.innerHTML = svgElement; 
- if (child.type == 'Sprite')+    } else
- child.visible = true+        // download svg file  
- +        download("screenshot.svg", svgElement); 
-+    
- +}
- }+
  
- function hideLabels(){ +function download(filename, text) { 
- for (var i=0; i<all_objects.lengthi++){ +  var element document.createElement('a')
- for (var j=0; j<all_objects[i].children.length; j++){ +  element.setAttribute('href', 'data:text/plain;charset=utf-8,' encodeURIComponent(text)); 
- var child = all_objects[i].children[j]; +  element.setAttribute('download', filename);
- if (child.type == 'Sprite')+
- child.visible = false; +
-+
-+
-+
- }+
  
- function displayOrHideLabels(event){ +  element.style.display 'none'
- if (event.currentTarget.checked){ +  document.body.appendChild(element);
- displayLabels(); +
- labelsShown true+
- } else { +
- hideLabels(); +
- labelsShown = false; +
-+
- }+
  
- function download(filename, text) { +  element.click();
-   var element = document.createElement('a'); +
-   element.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(text)); +
-   element.setAttribute('download', filename);+
  
-   element.style.display = 'none'; +  document.body.removeChild(element); 
-   document.body.appendChild(element);+}
  
-   element.click(); 
  
-   document.body.removeChild(element); +document.getElementById('transparencyRange_1').oninput = changeTransparency; 
- }+document.getElementById('changeRotationX_1').onchange = changeRotationX
 +document.getElementById('changeRotationY_1').onchange = changeRotationY; 
 +document.getElementById('changeRotationZ_1').onchange = changeRotationZ; 
 +document.getElementById('resetButton_1').onclick = resetScene; 
 +document.getElementById('rotationSpeedRange_1').oninput = changeRotationSpeedFactor; 
 +document.getElementById('takeScreenshot_1').onclick = takeSvgScreenshot; 
 +document.getElementById('showSettingsButton_1').onclick = showSettings; 
 +document.getElementById('hideSettingsButton_1').onclick = hideSettings;
  
-var tempobj; 
-tempobj = document.getElementById('explodeRange_0'); 
-if (tempobj) { 
-   tempobj.oninput = triggerExplode; 
-   document.getElementById('explodeCheckbox_0').onchange = triggerAutomaticExplode; 
-   document.getElementById('explodingSpeedRange_0').oninput = setExplodingSpeed; 
-} 
-tempobj = document.getElementById('foldRange_0'); 
-if (tempobj) { 
-   tempobj.oninput = fold; 
-} 
-document.getElementById('transparencyRange_0').oninput = changeTransparency; 
-document.getElementById('changeRotationX_0').onchange = changeRotationX; 
-document.getElementById('changeRotationY_0').onchange = changeRotationY; 
-document.getElementById('changeRotationZ_0').onchange = changeRotationZ; 
-document.getElementById('resetButton_0').onclick = resetScene; 
-document.getElementById('rotationSpeedRange_0').oninput = changeRotationSpeedFactor; 
-document.getElementById('labelsCheckboxInput_0').onchange = displayOrHideLabels; 
-document.getElementById('takeScreenshot_0').onclick = takeSvgScreenshot; 
-document.getElementById('showSettingsButton_0').onclick = showSettings; 
-document.getElementById('hideSettingsButton_0').onclick = hideSettings; 
- 
-  
  
 // ------------------ SHORTCUTS -------------------------------------------- // ------------------ SHORTCUTS --------------------------------------------
Line 1062: Line 2521:
  var event = new Event('click');  var event = new Event('click');
  if (settingsShown){  if (settingsShown){
- document.getElementById('hideSettingsButton_0').dispatchEvent(event); + document.getElementById('hideSettingsButton_1').dispatchEvent(event); 
- } else{ + } else { 
- document.getElementById('showSettingsButton_0').dispatchEvent(event);+ document.getElementById('showSettingsButton_1').dispatchEvent(event);
  }  }
 }); });
  
-if (foldable) moveToBaryCenter(); 
  
 +// COMMON_CODE_BLOCK_END
  
 });}); });});
-// COMMON_CODE_BLOCK_END +      </script> 
-</script>+   </body> 
 +</html> 
 +</HTML>
  
-</body> 
-</div> 
-</html> 
  
  • playground/test_3js.1587645956.txt.gz
  • Last modified: 2020/04/23 12:45
  • by hnagel