/*---------------------------------------------------------------------------- * Webtronics 1.0 * SVG schematic drawing Script * ----------------------------------------------------------------------------- * Created by an electronics hobbyist * Based on Richdraw by Mark Finkle * ----------------------------------------------------------------------------- * Copyright (c) 2006 Mark Finkle * * This program is free software; you can redistribute it and/or modify it * under the terms of the MIT License. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. * ----------------------------------------------------------------------------- * History: * 2006-04-05 | Created * --------------------------------------------------------------------------*/ function Schematic(elem) { this.svgNs = 'http://www.w3.org/2000/svg'; this.wtxNs="http://code.google.com/p/webtronics"; this.container = elem; this.grid = 10; this.width=640; this.height=480; this.maxwidth=2000; this.maxheight=2000; this.fontsize=12; /*main svg element*/ this.svgRoot = null; /* group to hold drawing*/ this.drawing=null; /* group to hold background*/ this.background=null; /*svg layer for zoom tools*/ this.zoomtools=null; /*element for selection*/ this.selection=null; /*group to display information*/ this.info=null; this.graph=false; this.connections=false; this.inv=false; this.mode = 'select'; /*array of nodes*/ this.selected = []; /* parts to delete*/ this.garbage = []; //this.wirenodes=[]; this.undolist=[]; this.redolist=[]; this.drag=false; /*selecting rectangle*/ this.selectionRect = { x:0, y:0, width:0, height: 0 }; this.mouseDown={x:0,y:0}; // this.viewoffset={x:0,y:0}; this.onconnector=false; this.connector=null; this.init(this.container); this.onMouseDownListener = this.onMouseDown.bindAsEventListener(this); this.onMouseUpListener = this.onMouseUp.bindAsEventListener(this); this.onMouseMove = this.onMouseMove.bindAsEventListener(this); this.onWheelListener = this.onWheel.bindAsEventListener(this); Event.observe(this.svgRoot, "mousewheel",this.onWheelListener); Event.observe(this.svgRoot, "DOMMouseScroll",this.onWheelListener); Event.observe(this.svgRoot, "dragover", this.onMouseMove); Event.observe(this.svgRoot, "mousemove", this.onMouseMove); Event.observe(this.svgRoot, "mousedown", this.onMouseDownListener); Event.observe(this.svgRoot, "mouseup", this.onMouseUpListener); /*this might get the ipad working*/ Event.observe(this.svgRoot, "onclick", void(0)); } //****************************************************** ///container functions Schematic.prototype.getwithselector=function(selector){ return $$(selector); } Schematic.prototype.getnextid=function(elem,count){ var type=this.readwtx(elem,"type"); if(type=="gnd")return "gnd";// to make universal id gnd for ground if(!count)count=1; var newid=type+count var parts=this.drawing.getElementsByTagName("g"); for(var i=0;i 1){ this.changeobserver.disconnect(); this.clearinfo(); this.unselect(); this.redolist.push(this.undolist.pop()); this.remove(this.drawing); this.drawing=this.undolist[this.undolist.length-1].cloneNode(true); this.svgRoot.insertBefore(this.drawing,this.zoomtools); if(this.background.getAttribute('class')=='inv')this.drawing.setAttribute('class','inv'); else if(this.drawing.getAttribute('class')=='inv')this.drawing.removeAttribute('class'); this.drawing.setAttribute('transform',this.background.getAttribute('transform')); this.addconnects(); // configuration of the observer: // pass in the target node, as well as the observer options this.changeobserver.observe(this.drawing, { attributes: true, childList: true, characterData: true ,subtree:true}); } } Schematic.prototype.addhistory=function(){ if(this.undolist.length>=40)this.undolist.shift(); this.redolist=[]; this.changeobserver.disconnect(); this.undolist.push(this.drawing.cloneNode(true)); // configuration of the observer: this.changeobserver.observe(this.drawing, { attributes: true, childList: true, characterData: true ,subtree:true}); } Schematic.prototype.redo=function(){ if(this.redolist.length){ this.changeobserver.disconnect(); this.clearinfo() this.unselect() this.undolist.push(this.redolist.pop()); this.remove(this.drawing); this.drawing=this.undolist[this.undolist.length-1].cloneNode(true); this.svgRoot.insertBefore(this.drawing,this.zoomtools); if(this.background.getAttribute('class')=='inv')this.drawing.setAttribute('class','inv'); else if(this.drawing.getAttribute('class')=='inv')this.drawing.removeAttribute('class'); this.drawing.setAttribute('transform',this.background.getAttribute('transform')); // configuration of the observer: var config = { attributes: true, childList: true, characterData: true ,subtree:true}; // pass in the target node, as well as the observer options this.addconnects(); this.changeobserver.observe(this.drawing, config); } } Schematic.prototype.init = function(elem) { this.container = elem; this.container.style.MozUserSelect = 'none'; this.svgRoot = document.createElementNS(this.svgNs, "svg"); this.svgRoot.setAttribute('xmlns',this.svgNs); // this.svgRoot.setAttribute('xmlns:wtx',this.wtxNs); this.svgRoot.setAttribute('width',2000); this.svgRoot.setAttribute('height',2000); this.container.appendChild(this.svgRoot); /*set colors*/ this.svgRoot.style.backgroundColor="inherit"; this.container.style.backgroundColor="inherit"; /*create main group for pan/zoom*/ this.drawing=document.createElementNS(this.svgNs,'g'); this.drawing.id='webtronics_drawing'; this.svgRoot.appendChild(this.drawing); /* create group for user info such as selection boxes */ this.info=document.createElementNS(this.svgNs,'g'); this.info.id="information"; this.svgRoot.appendChild(this.info); /*add the background*/ this.graph=false this.showbackground(); /*add the toolbar*/ this.addtools(); // create an observer instance if(window.MutationObserver)this.changeobserver = new MutationObserver(this.updateinfo.bind(this)); else this.changeobserver = new WebKitMutationObserver(this.updateinfo.bind(this)); // configuration of the observer: var config = { attributes: true, childList: true, characterData: true ,subtree:true}; // pass in the target node, as well as the observer options this.changeobserver.observe(this.drawing, config); } Schematic.prototype.updateinfo=function(mutations){ //filter the events var update= false mutations.forEach(function(mutation){if(mutation.target!=this.drawing)update=true}); if(update){ // console.log("updating"); if(!this.drag)this.addhistory(); this.addconnects(); } } Schematic.prototype.addtools=function(){ if($(this.zoomtools))this.remove(this.zoomtools); this.zoomtools=document.createElementNS(this.svgNs,'svg'); this.zoomtools.setAttribute('xmlns:svg',this.svgNs); //this.zoomtools.setAttribute('xmlns:xlink',"http://www.w3.org/1999/xlink"); this.zoomtools.id='webtronics_zoomtools'; this.zoomtools.setAttribute('width',this.container.offsetWidth); this.zoomtools.setAttribute('height',this.container.offsetHeight); /*add the image tools*/ var normal=document.createElementNS(this.svgNs,'image'); normal.setAttribute('x',0); normal.setAttribute('y',0); normal.setAttribute('width',32); normal.setAttribute('height',32); normal.setAttributeNS("http://www.w3.org/1999/xlink",'xlink:href','./buttons/normal.png'); /* make sure the mouse events don't go through the image*/ Event.observe(normal,"mousedown", function(e){e.stopPropagation();}.bind(this)); Event.observe(normal,"mouseup", function(e){e.stopPropagation();}.bind(this)); Event.observe(normal,"click", function(e){ this.drawing.setAttribute('transform','matrix(1,0,0,1,0,0)'); this.background.setAttribute('transform','matrix(1,0,0,1,0,0)'); this.info.setAttribute('transform','matrix(1,0,0,1,0,0)'); e.stopPropagation();}.bind(this)); this.zoomtools.appendChild(normal); var grow=document.createElementNS(this.svgNs,'image'); grow.setAttribute('x',(this.container.offsetWidth)-32); grow.setAttribute('y',(this.container.offsetHeight)-32); grow.setAttribute('width',32); grow.setAttribute('height',32); grow.setAttributeNS("http://www.w3.org/1999/xlink",'xlink:href','buttons/grow.png'); Event.observe(grow,"mousedown", function(e){e.stopPropagation();}.bind(this)); Event.observe(grow,"mouseup", function(e){e.stopPropagation();}.bind(this)); Event.observe(grow,"click", function(e){ if(this.svgRoot.getAttribute('width')deltaY){ shape.setAttributeNS(null, 'x2', toX); shape.setAttributeNS(null, 'y2', fromY); } else { shape.setAttributeNS(null, 'x2', fromX); shape.setAttributeNS(null, 'y2', toY); } } } Schematic.prototype.tracker = function(elem) { var rect={}; if(elem&&(elem.nodeType==1)){ try{ var bbox=elem.getBBox(); } catch(e){ return {x:0,y:0,width:0,height:0}; } var box={x:0,y:0,width:0,height:0}; if(bbox){ box.x=bbox.x; box.y=bbox.y; box.width=bbox.width; box.height=bbox.height; } if(elem.tagName=='g'||elem.tagName=='svg'){ /*newer versions of firefox need this recursive part to get the right bounding box for some reason *otherwise the box width and height are zero if it only contains lines*/ for(var i= elem.childNodes.length;i>0;i--){ if(elem.childNodes[i-1].nodeType==1){ var chbox=this.tracker(elem.childNodes[i-1]); box.x=Math.min(box.x,chbox.x); box.y=Math.min(box.y,chbox.y); box.width=Math.max(chbox.x+chbox.width,box.width); box.height=Math.max(chbox.y+chbox.height,box.height); } } /*gets corrected bounding box*/ var matrix=this.parseMatrix(elem); var tleft=this.svgRoot.createSVGPoint(); var bright=this.svgRoot.createSVGPoint(); tleft.x=box.x; tleft.y=box.y; tleft=tleft.matrixTransform(matrix); bright.x=box.x+box.width; bright.y=box.y+box.height; bright=bright.matrixTransform(matrix); rect.x=Math.min(tleft.x,bright.x); rect.y=Math.min(tleft.y,bright.y); rect.width=Math.max(tleft.x,bright.x)-rect.x; rect.height=Math.max(tleft.y,bright.y)-rect.y; } else if (elem.tagName=='line'){ rect.x=box.x-1; rect.y=box.y-1; rect.width=box.width+2; rect.height=box.height+2; } else { rect.x=box.x; rect.y=box.y; rect.width=box.width; rect.height=box.height; } //elem.rect=rect; //return rect; return rect; } } Schematic.prototype.showTracker = function(elem) { var rect=this.tracker(elem); var tracked = elem.ownerDocument.createElementNS(this.svgNs, 'g'); tracked.setAttributeNS(null, 'class', 'schematic_tracker'); var svg=this.createrect('blue',0.35,rect.x,rect.y,rect.width,rect.height); tracked.appendChild(svg) /*add gadgets*/ if(elem.tagName=='g'){ svg=this.createtext('rotate','blue',rect.x+rect.width,rect.y); // svg.rotatorfor=elem; Event.observe(svg,"mousedown", function(e){ var data = $A(arguments); data.shift(); this.mode='rotate'; this.rotate(data[0]); e.stopPropagation();}.bindAsEventListener(this,elem)); tracked.appendChild(svg); } if (this.readwtx(elem,"flip")=="true"){ svg=this.createtext('flip','blue',rect.x,rect.y+rect.height+10); svg.rotatorfor=elem; Event.observe(svg,"mousedown", function(e){ var data = $A(arguments); data.shift(); this.mode='rotate'; this.flip(data[0]); e.stopPropagation();}.bindAsEventListener(this,elem)); tracked.appendChild(svg); } this.info.appendChild(tracked); /* * if(this.selected.length===1&&this.selected[0].tagName==='g'){ * parent.document.getElementById('webtronics_context_menu').select('[Title=Properties]')[0].setAttribute('class','enabled'); * } else{ parent.document.select('#webtronics_context_menu [Title=Properties]')[0].setAttribute('class','disabled'); } */ } Schematic.prototype.clearinfo=function(){ this.remove(this.info); this.info=document.createElementNS(this.svgNs,'g'); this.info.id="information"; if(this.drawing.getAttribute('class')=='inv')this.info.setAttribute('class','inv'); this.svgRoot.appendChild(this.info); var matrix=this.parseMatrix(this.drawing); this.info.setAttributeNS(null,'transform','matrix('+matrix.a+','+matrix.b+','+matrix.c+','+matrix.d+','+matrix.e+','+matrix.f+')'); this.info } /*find all tracking boxes and delete them*/ Schematic.prototype.removeTracker=function(){ var tracker=$$('.schematic_tracker'); for(var i=0;i0;i--){ if(this.selected[i-1].tagName=='g'&&$(this.readwtx(this.selected[i-1],"label"))) this.remove($(this.readwtx(this.selected[i-1],"label"))); this.remove(this.selected[i-1]); this.selected.pop(); } /*delete all trackers*/ this.removeTracker(); } Schematic.prototype.createvalue=function(elem){ /*create value text if attribute exists*/ /*the value contains * id - the part id *value -the part model or value *label -the id of the label text */ try{ var id=this.readwtx(elem,"id"); var value=this.readwtx(elem,"value"); var label=this.readwtx(elem,"label"); } catch(e){console.log(e);} if(label.length && $(label)){ /*remove all chilnodes*/ while ($(label).firstChild) { $(label).removeChild($(label).firstChild); } if(id){ var idspan=this.createtspan(id,0,0); $(label).appendChild(idspan); } if(value){ var box=this.tracker($(label)); var valuespan=this.createtspan(value,-box.width,box.height); $(label).appendChild(valuespan); } $(label).appendChild(idspan); //$(label).appendChild(valuespan); } else{ var text=this.createtext("",'black',0,0-this.fontsize); this.drawing.appendChild(text); var box=this.tracker(text); if(id||value){ if(id){ var idspan=this.createtspan(id,0,0); text.appendChild(idspan); } if(value){ var box=this.tracker(text); var valuespan=this.createtspan(value,-box.width,box.height); text.appendChild(valuespan); } text.id='value-'+id+"-"+createUUID(); this.writewtx(elem,"label",text.id); text.setAttribute('x',this.parseXY(elem).x-box.width); text.setAttribute('y',this.parseXY(elem).y-box.height); } } } Schematic.prototype.select = function(elem) { this.selected.push(elem); if(elem.tagName=='g'){ try{ var label=this.readwtx(elem,"label"); } catch(e){ var label=null; } if(label){ if(!$(label))this.createvalue(elem); } } this.showTracker(this.selected[this.selected.length-1]); } Schematic.prototype.unselect = function() { for(var i=this.selected.length;i>0;i--){ this.selected[i-1]=null; this.selected.pop(); } this.removeTracker(); } Schematic.prototype.getpins=function(part){ var pins=[]; var nodes = this.getwtxtagname(part,"node"); var matrix=this.parseMatrix(part); for(var j=0;j line'); lines.forEach(function(l){ var p1={x:l.getAttribute('x1')-0,y:l.getAttribute('y1')-0}; var p2={x:l.getAttribute('x2')-0,y:l.getAttribute('y2')-0}; if(garbage.indexOf(l)<0){ if(this.ispoint(p1,pin)){ nextpin=p2; connected.push(l); } else if(this.ispoint(p2,pin)){ nextpin=p1; connected.push(l); } } }.bind(this)); if(connected.length <2){ garbage=garbage.concat(connected); if(nextpin!=undefined)garbage=this.gettrash(garbage,nextpin); } return garbage; } /* //check if selection rectangle overlaps part Schematic.prototype.getPart=function(){ var parts=$$("#webtronics_drawing > g"); parts.forEach(function(p){ var rect=this.tracker(p); if(rectsIntersect(this.selectionRect,rect)){ this.select(p); } }.bind(this)); this.garbage=[]; this.selected.forEach(function(p){ var pins=this.getpins(p); pins.forEach(function(n){ var wires=[]; wires=this.gettrash(wires,n); for(var i=0;i circle,#webtronics_drawing > text ,#webtronics_drawing > line"); parts.forEach(function(p){ var rect=this.tracker(p); if(this.garbage.indexOf(p)<0){ if(rectsIntersect(rect,this.selectionRect)){ this.select(p); } } }.bind(this)); } */ /*check if selection rectangle overlaps part*/ Schematic.prototype.getPart=function(){ var parts=$$("#webtronics_drawing > *"); parts.forEach(function(p){ var rect=this.tracker(p); if(rectsIntersect(this.selectionRect,rect)){ this.select(p); } }.bind(this)); } Schematic.prototype.realPosition=function(x,y){ var real=this.svgRoot.createSVGPoint(); var matrix=this.parseMatrix(this.drawing); real.x=(x-matrix.e)/matrix.a; real.y=(y-matrix.f)/matrix.a; return real; } /*mousedown event handler*/ Schematic.prototype.onMouseDown = function(event){ if(!this.drag){ var real=this.realPosition(Event.pointerX(event),Event.pointerY(event)); this.mouseDown.x = real.x;//Math.round(real.x/this.grid) * this.grid; this.mouseDown.y = real.y;//Math.round(real.y/this.grid) * this.grid; if (this.mode == 'line') { if (!Event.isLeftClick(event)){ this.remove($("templine1")); this.remove($("templine2")); parent.webtronics.setMode('select','Selection'); return; } else this.wiresegment(); } /*clicked on background in select mode ,remove selection*/ else if(this.mode=='select'){ if(Event.isLeftClick(event)){ this.selectionRect.x=real.x; this.selectionRect.y=real.y; this.selectionRect.width=0; this.selectionRect.height=0; /* if there is already a selection rectangle delete it*/ if(this.selection)this.remove(this.selection); this.selection = this.createrect('blue',0.35,real.x,real.y,0,0); this.info.appendChild(this.selection); for(var i=0;i0;i--){ //this aligns the prt to the grid but it won't work if the parts are incorrectly aligned to begin with matrix.e=Math.round(matrix.e/this.grid) * this.grid; matrix.f=Math.round(matrix.f/this.grid) * this.grid; /*move other parts*/ this.move(floating.childNodes[i-1],matrix.e, matrix.f); if(floating.childNodes[i-1].getAttribute('class')!='schematic_tracker'){ //snap pins to wires /* if(floating.childNodes[i-1].tagName=="g"){ this.snaptowire(floating.childNodes[i-1]); } */ this.drawing.appendChild(floating.childNodes[i-1]); } else { this.info.appendChild(floating.childNodes[i-1]); } } this.remove(floating); } Schematic.prototype.onMouseUp = function(event) { // if(this.mode=="line")return; if(event.isLeftClick(event)){ // console.log('mouseup'); /*hide the menu*/ // var menu=window.parent.document.getElementById('webtronics_context_menu'); // if(menu){ // menu.style.display='none'; // } this.drag=false; if(this.mode=='select'){ var floating=$('schematic_floating'); if(floating){ this.dropSelection(); } else{ this.unselect(); this.getPart(); } } else if(this.mode=='rotate'){ this.mode='select'; } if (this.selection) { this.remove(this.selection); this.selectionRect.x=0; this.selectionRect.y=0; this.selectionRect.width=0; this.selectionRect.height=0; } /*skip the mouseup after a rotate*/ } else if(this.mode=="line"){ var menu=window.parent.document.getElementById('webtronics_context_menu'); if(menu){ menu.style.display='none'; } this.remove($("templine1")); this.remove($("templine2")); parent.webtronics.setMode('select','Selection'); } } Schematic.prototype.onMouseMove = function(event) { if(this.mode=='select'){ /*clicked inside bounds*/ if(this.drag){ var real=this.realPosition(Event.pointerX(event),Event.pointerY(event)); mouseAt={x:0,y:0}; mouseAt.x = Math.round(real.x);//Math.round(real.x / this.grid) * this.grid; mouseAt.y =Math.round(real.y);//Math.round(real.y / this.grid) * this.grid; this.dragSelection(mouseAt.x-this.mouseDown.x,mouseAt.y-this.mouseDown.y); } else{ if (this.selection) { var real=this.realPosition(Event.pointerX(event),Event.pointerY(event)); //mouseAt={x:0,y:0}; //mouseAt.x = Math.round(real.x / this.grid) * this.grid; //mouseAt.y =Math.round(real.y / this.grid) * this.grid; this.selectionRect.width=real.x-this.selectionRect.x; this.selectionRect.height=real.y-this.selectionRect.y; if(this.selectionRect.width<0)this.selection.setAttributeNS(null,'x', real.x); if(this.selectionRect.height<0)this.selection.setAttributeNS(null,'y',real.y); this.selection.setAttributeNS(null,'width', Math.abs(this.selectionRect.width)); this.selection.setAttributeNS(null,'height',Math.abs(this.selectionRect.height)); } } } else if (this.mode=='line'){ if(!this.onconnector){ if ($('templine1')){ var real=this.realPosition(Event.pointerX(event),Event.pointerY(event)); mouseAt={x:0,y:0}; mouseAt.x = Math.round(real.x);//Math.round(real.x / this.grid) * this.grid; mouseAt.y =Math.round(real.y);//Math.round(real.y / this.grid) * this.grid; // if(!this.onconnector){ var x=$('templine1').getAttribute('x1')-0; var y=$('templine1').getAttribute('y1')-0; if(Math.abs(x-real.x)>=Math.abs(y-real.y)){ this.resize($('templine1'), x, y, mouseAt.x, y); this.remove($('templine2')); var svg = this.createline('blue',2, mouseAt.x, y, mouseAt.x, mouseAt.y); svg.setAttribute( 'class',"templine"); svg.id = 'templine2'; svg.setAttributeNS(null,'stroke-dasharray','3,2'); this.info.appendChild(svg); } else{ this.resize($('templine1'), x, y, x, mouseAt.y); this.remove($('templine2')); var svg = this.createline('blue',2, x, mouseAt.y, mouseAt.x, mouseAt.y); svg.setAttribute( 'class',"templine"); svg.id = 'templine2'; svg.setAttributeNS(null,'stroke-dasharray','3,2'); this.info.appendChild(svg); } } } } } Schematic.prototype.onWheel=function(event){ //this function is very clunky //And very tough to figure out if(Event.element(event)!=this.svgRoot){ this.changeobserver.disconnect(); var scale=1; var wheel=0; if(event.wheelDelta)wheel=-event.wheelDelta/-120; else wheel=event.detail; var matrix = this.parseMatrix(this.drawing); //var real=this.realPosition(Event.pointerX(event),Event.pointerY(event)); var window={x:event.clientX,y:event.clientY}; var offsetx=((this.container.offsetWidth/2)-window.x)/2; var offsety=((this.container.offsetHeight/2)-window.y)/2; if(wheel>0&&matrix.a<2){ scale=1.04; } else if(wheel<0&&matrix.a>0.3){ scale=0.96; } matrix=matrix.scale(scale); matrix=matrix.translate(offsetx,offsety); // matrix.e=matrix.a<1?offsetx*matrix.a:offsetx/matrix.a; // matrix.f=matrix.a<1?offsety*matrix.a:offsety/matrix.a; this.drawing.setAttributeNS(null,'transform','matrix('+matrix.a+','+matrix.b+','+matrix.c+','+matrix.d+','+matrix.e+','+matrix.f+')'); this.background.setAttributeNS(null,'transform','matrix('+matrix.a+','+matrix.b+','+matrix.c+','+matrix.d+','+matrix.e+','+matrix.f+')'); this.info.setAttributeNS(null,'transform','matrix('+matrix.a+','+matrix.b+','+matrix.c+','+matrix.d+','+matrix.e+','+matrix.f+')'); this.changeobserver.observe(this.drawing, { attributes: true, childList: true, characterData: true ,subtree:true}); Event.stop(event); } } //********************************************************************** ///file io Schematic.prototype.svgSize=function(){ var matrix=this.parseMatrix(this.drawing); this.drawing.removeAttribute('transform'); var svgsize=this.tracker(this.drawing); this.drawing.setAttribute('transform','matrix('+matrix.a+','+matrix.b+','+matrix.c+','+matrix.d+','+matrix.e+','+matrix.f+')'); return svgsize; } Schematic.prototype.shrink=function(elem){ //fix empty space display //maybe add a border like a blueprint? } Schematic.prototype.getDoc = function(shrink,inv) { //need to remove the matrix to get the right size var doc= document.implementation.createDocument("", "", null); var floating= document.createElementNS(this.svgNs, 'g'); this.info.appendChild(floating); var svg = doc.createElementNS(this.svgNs, "svg"); if(inv){ var style=doc.createElementNS(this.svgNs,"style"); style.setAttribute('type',"text/css"); style.appendChild(doc.createCDATASection("g,rect,line{fill:black;stroke:white;}"+ "circle,text{fill:white;stroke:white;}")); svg.appendChild(style); } var bg=doc.createElementNS(this.svgNs,'rect'); bg.setAttribute('x',0); bg.setAttribute('y',0); bg.setAttribute('fill','white'); svg.appendChild(bg); var svgsize=this.svgSize(); //remove whitespace for(var ch=0;ch0;i--){ /*only open these nodes*/ //add wire events /*get rid of empty text*/ if(ch[i-1].tagName=='circle'|| ch[i-1].tagName=='line'|| (ch[i-1].tagName=='text'&&ch[i-1].childNodes.length&&(ch[i-1].id.split("-",1)!='value'))) { var newelem = document.importNode(ch[i-1],true); this.drawing.appendChild(newelem); this.select(newelem); } else if(ch[i-1].tagName=='g'){ var c=ch[i-1].getElementsByTagName('*'); for(var j=0;j0)?(r2.x):(r2.x+r2.width)) < ((r1.width>0)?(r1.x+r1.width):(r1.x)) && ((r2.width>0)?(r2.x+r2.width):(r2.x)) > ((r1.width>0)?(r1.x):(r1.x+r1.width)) && ((r2.height>0)?(r2.y):(r2.y+r2.height)) < ((r1.height>0)?(r1.y+r1.height):(r1.y)) && ((r2.height>0)?(r2.y+r2.height):(r2.y)) > ((r1.height>0)?(r1.y):(r1.y+r1.height)); }; function rectInside(r1 ,r2){ //is r2 inside r1 return r1.x r2.x+r2.width && r1.y+r1.height >r2.y+r2.height; }