Created
August 19, 2015 17:29
-
-
Save moebio/ec78bdeb94085f166899 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| draw = function(g){ | |
| c.l('***', g); | |
| g.setStroke('black', 2); | |
| g.line(0,0,g.cW,g.cH); | |
| if(network == null) return; | |
| if(MODE==2 || MODE==8) { | |
| var i; | |
| for(i=0; i<configuration.physics.nStepsPerframe; i++){ | |
| forces(); | |
| } | |
| } | |
| if(e3D) forces3D(); | |
| if(MODE==7){ | |
| var rSphere; | |
| if(clustersTable){ | |
| var i = 0; | |
| clustersTable.forEach(function(nodeList){ | |
| rSphere = 200 - 150*i/clustersTable.length; | |
| i++; | |
| nodeList.forEach(function(node){ | |
| var norm = Math.sqrt(Math.pow(node._x, 2) + Math.pow(node._y, 2) + Math.pow(node._z, 2)); | |
| node._x = rSphere*node._x/norm; | |
| node._y = rSphere*node._y/norm; | |
| node._z = rSphere*node._z/norm; | |
| }); | |
| }); | |
| } else { | |
| rSphere = 150; | |
| network.nodeList.forEach(function(node){ | |
| var norm = Math.sqrt(Math.pow(node._x, 2) + Math.pow(node._y, 2) + Math.pow(node._z, 2)); | |
| node._x = rSphere*node._x/norm; | |
| node._y = rSphere*node._y/norm; | |
| node._z = rSphere*node._z/norm; | |
| }); | |
| } | |
| } | |
| //project nodes | |
| if(e3D==null){ | |
| network.nodeList.forEach(function(node){ | |
| projectNode(node) | |
| }); | |
| } | |
| //loops | |
| if(configuration.loops.show && loops) drawLoops(g); | |
| //draw relations | |
| thicknesFadingRelations = 0.9*thicknesFadingRelations + 0.1*( ( (!prevNodeOver && !prevRelationOver) || nodePressed )?1:0 ); | |
| if(!MOVING_RELATIONS && toGenerateRelationsCapture && configuration.relations.RELATIONS_BITMAP_ON_STASIS){ | |
| clearTimeout(timerGenerateCapture); | |
| timerGenerateCapture = setTimeout(generateCaptureAllRelations, 100); | |
| waitingToGenerateCapture = true; | |
| toGenerateRelationsCapture = false; | |
| } | |
| if(MOVING_RELATIONS || !configuration.relations.RELATIONS_BITMAP_ON_STASIS){ | |
| if(e3D==null) drawRelations(g); | |
| } else { | |
| if(!waitingToGenerateCapture) g.drawImage(captureAllRelations,0,0); | |
| } | |
| //draw nodes | |
| drawNodes(g); | |
| if(nodeOver) relationOver = null; | |
| //draw cluster circles and forces | |
| if(MODE==8 && clusterCircles) drawClustersCircles(g); | |
| //general info | |
| if(configuration.graphic.displayInfo){ | |
| g.setText('black', 12); | |
| g.setStroke('white', 3); | |
| g.fsText("n nodes: "+network.nodeList.length+", n relations:"+network.relationList.length, 12, 12); | |
| g.fsText("friction: "+Math.floor(friction*1000)/1000+", kEq:"+kEq+", kSep:"+kSep+", forces "+(MOVING_RELATIONS?'active':'inactive'), 12, 26); | |
| g.fsText("ANTI_COLLISION_FACTOR: "+Math.floor(ANTI_COLLISION_FACTOR*1000)/1000, 12, 40); | |
| g.fsText("scale, centerX, centerY: "+Math.floor(scale*100)/100+", "+Math.floor(centerX*100)/100+", "+Math.floor(centerY*100)/100, 12, 54); | |
| } | |
| if(g.MOUSE_UP_FAST){ | |
| selectedNode = nodeOver; | |
| selectedRelation = relationOver; | |
| if(selectedNode!=null){ | |
| lastSelectedNode = selectedNode; | |
| placeNodesInSelectionLayout(selectedNode); | |
| } else { | |
| selectionLayout = false; | |
| pathsLayout = false; | |
| } | |
| } | |
| if(nodeOver && g.MOUSE_DOWN){//} && !selectionLayout){ | |
| nodePressed = nodeOver; | |
| xOnNode = g.mX - nodePressed._x; | |
| yOnNode = g.mY - nodePressed._y; | |
| } | |
| if(relationOver && g.MOUSE_DOWN) relationPressed = relationOver; | |
| if(nodePressed && g.T_MOUSE_PRESSED>400 && g.mX==g.mX_DOWN && g.mY==g.mY_DOWN){ | |
| nodeSuperPressed = nodePressed; | |
| nodePressed = null; | |
| } | |
| //superpressed | |
| if(nodeSuperPressed){ | |
| //c.l('--> nodeSuperPressed', nodeSuperPressed.id); | |
| var R = 40; | |
| var R2 = R+3; | |
| g.setStroke('rgba(255,0,0,0.5)', 6); | |
| g.sCircle(nodeSuperPressed._x, nodeSuperPressed._y, R); | |
| var dx = g.mX-nodeSuperPressed._x; | |
| var dy = g.mY-nodeSuperPressed._y; | |
| var angle = Math.atan2(dy, dx); | |
| if(nodeOver && nodeOver!=nodeSuperPressed){ | |
| g.line(nodeSuperPressed._x + R2*Math.cos(angle), nodeSuperPressed._y + R2*Math.sin(angle), nodeOver._x - R2*Math.cos(angle), nodeOver._y - R2*Math.sin(angle)); | |
| g.sCircle(nodeOver._x, nodeOver._y, R); | |
| } else { | |
| if( (dx*dx+dy*dy) >R2*R2) g.line(nodeSuperPressed._x + R2*Math.cos(angle), nodeSuperPressed._y + R2*Math.sin(angle), g.mX, g.mY); | |
| } | |
| } | |
| //tooltip | |
| if(!g.MOUSE_PRESSED){ | |
| if( nodeOver!=null && configuration.nodes.tooltip.show && (Math.pow(nodeOver._x-g.mX, 2)+Math.pow(nodeOver._y-g.mY, 2)<40) ){ | |
| drawToolTip(g, nodeOver); | |
| } else if( relationOver!=null && configuration.relations.tooltip.show ) drawToolTip(g, relationOver); | |
| } | |
| if(g.MOUSE_UP){ | |
| nodePressed = null; | |
| relationPressed = null; | |
| __storedFirstShortPath = null; | |
| clearInterval(__shortestPathsTimer); | |
| if(nodeSuperPressed && nodeOver && nodeSuperPressed!=nodeOver){ | |
| placeNodesShortestPaths(nodeSuperPressed, nodeOver); | |
| selectedRelation = network.relationList.getFirstRelationBetweenNodes(nodeSuperPressed, nodeOver); | |
| } | |
| nodeSuperPressed = null; | |
| } | |
| ///send data | |
| var send = false; | |
| //nodes | |
| if(nodeOver!=prevNodeOver){ | |
| outputArray[0].value = nodeOver; | |
| if(nodeOver!=null) outputArray[1].value = nodeOver; | |
| send = true; | |
| } | |
| if(selectedNode!=outputArray[2].value){ | |
| outputArray[2].value = selectedNode; | |
| if(selectedNode!=null) outputArray[3].value = selectedNode; | |
| send = true; | |
| } | |
| //relation | |
| if(relationOver!=prevRelationOver){ | |
| outputArray[4].value = relationOver; | |
| if(relationOver!=null) outputArray[5].value = relationOver; | |
| send = true; | |
| } | |
| if(selectedRelation!=outputArray[6].value){ | |
| outputArray[6].value = selectedRelation; | |
| if(selectedRelation!=null) outputArray[7].value = selectedRelation; | |
| send = true; | |
| } | |
| if(send){ | |
| outputArray = [outputArray[0], outputArray[1], outputArray[2], outputArray[3], outputArray[4], outputArray[5], outputArray[6], outputArray[7], outputArray[8], outputArray[9]]; | |
| outputArray.isOutput = true; | |
| __sendData(outputArray); | |
| } | |
| prevNodeOver = nodeOver; | |
| prevRelationOver = relationOver; | |
| if(nodeOver) lastNodeOver = nodeOver; | |
| if(relationOver) lastRelationOver = relationOver; | |
| //positions memory | |
| if(nMemorizedPositions>0 && nF%200==0){ | |
| var i; | |
| for(i=0; network.nodeList[i]!=null; i++){ | |
| pair = [ Math.round(network.nodeList[i].x), Math.round(network.nodeList[i].y) ]; | |
| positionsMemory[network.id+"@"+network.nodeList[i].id] = pair; | |
| } | |
| __saveData(positionsMemory); | |
| } else if(nMemorizedPositions==-1){ | |
| __saveData({}); | |
| } | |
| } | |
| drawToolTip = function(g, node){ | |
| var x = g.mX; | |
| var y = g.mY; | |
| var w = configuration.nodes.tooltip.width; | |
| var x0 = x; | |
| var title; | |
| var content; | |
| var contentLines; | |
| var list; | |
| if(node.type=='Node'){ | |
| title = node[configuration.nodes.tooltip.titleProperty]; | |
| content = node[configuration.nodes.tooltip.contentProperty]; | |
| } else { | |
| title = node[configuration.relations.tooltip.titleProperty]; | |
| content = node[configuration.relations.tooltip.contentProperty]; | |
| } | |
| content = content==null?"":content; | |
| g.setText('white', 14, null, null, null, 'bold'); | |
| var wTitle = g.getTextW(title); | |
| w = content==""?(wTitle+10):(Math.max(w, wTitle+10)); | |
| if(configuration.nodes.tooltip.image && node.image) w = Math.max(w, node.image.width+10); | |
| if(content==""){ | |
| contentLines = []; | |
| } else { | |
| g.setText('white', 12); | |
| contentLines = mo.DrawTexts.textWordWrapReturnLines(content, w-10, 0, 12); | |
| } | |
| var h = 30 + 12*contentLines.length; | |
| var y0 = y - h - 20; | |
| if(configuration.nodes.tooltip.image && node.image){ | |
| h += node.image.height+10; | |
| y0 -= node.image.height+10; | |
| } | |
| g.setFill('rgb(50,50,50)'); | |
| g.fLines( | |
| x, y, | |
| x0,y-20, | |
| x0,y0, | |
| x0+w,y0, | |
| x0+w,y0+h, | |
| x+20,y0+h | |
| ); | |
| if(configuration.nodes.tooltip.image && node.image){ | |
| g.drawImage(node.image, x0+5, y0+5); | |
| y0+=node.image.height+10; | |
| } | |
| g.setText('white', 14, null, null, null, 'bold'); | |
| g.fText(title, x0+5, y0+5); | |
| g.setText('white', 12); | |
| mo.DrawTexts.fillTextRectangleWithTextLines(contentLines, x0+5, y0+20, 0, 12,null,g);//TODO:update this when fillTextRectangleWithTextLines updates and receives g as 1st param | |
| } | |
| generateCaptureAllRelations = function(){ | |
| captureAllRelations = drawAndcapture(drawRelations, cW,cH); | |
| waitingToGenerateCapture = false; | |
| } | |
| ////loops | |
| /// | |
| drawLoops = function(g){ | |
| mo.c.l(configuration.loops.colors, configuration.loops.dashed); | |
| g.setStroke(configuration.loops.color, configuration.loops.thickness); | |
| if(configuration.loops.dashed) g.context.setLineDash([2,3]); | |
| loops.forEach(function(loop){ | |
| if(configuration.loops.colors) g.setStroke(loop.color, configuration.loops.thickness); | |
| for(i=0; loop[i]!=null; i++){ | |
| loop.polygon[i].x = loop[i]._x; | |
| loop.polygon[i].y = loop[i]._y; | |
| } | |
| _drawSmoothPolygon(g, loop.polygon, true, 80*scale); | |
| }); | |
| g.context.setLineDash([]); | |
| } | |
| _drawSmoothPolygon = function(g, polygon, closed, amount) { | |
| amount = amount==null?30:amount; | |
| var controlPoints; | |
| if(polygon.length<2) return null; | |
| g.context.beginPath(); | |
| if(polygon.length==2){ | |
| var a = Math.atan2(polygon[1].y-polygon[0].y, polygon[1].x-polygon[0].x)-0.5*Math.PI; | |
| var cosa = amount*Math.cos(a); | |
| var sina = amount*Math.sin(a); | |
| g.context.moveTo(polygon[0].x, polygon[0].y); | |
| g.context.bezierCurveTo( | |
| polygon[0].x + cosa, polygon[0].y + sina, | |
| polygon[1].x + cosa, polygon[1].y + sina, | |
| polygon[1].x, polygon[1].y | |
| ); | |
| g.context.bezierCurveTo( | |
| polygon[1].x - cosa, polygon[1].y - sina, | |
| polygon[0].x - cosa, polygon[0].y - sina, | |
| polygon[0].x, polygon[0].y | |
| ); | |
| g.context.stroke(); | |
| return; | |
| } | |
| var i; | |
| var nPoints = polygon.length; | |
| var prevPoint = polygon[nPoints-1]; | |
| var point = polygon[0]; | |
| var nextPoint = polygon[1]; | |
| controlPoints = mo.GeometryOperators.getSoftenControlPoints(prevPoint, point, nextPoint, amount); | |
| var prevCP = controlPoints[1]; | |
| var cP; | |
| g.context.moveTo(point.x, point.y); | |
| prevPoint = point; | |
| var arrows = []; | |
| for(i=1;i<nPoints+1;i++){ | |
| point = polygon[i%nPoints]; | |
| nextPoint = polygon[(i+1)%nPoints]; | |
| controlPoints = GeometryOperators.getSoftenControlPoints(prevPoint, point, nextPoint, amount); | |
| cP = controlPoints[0]; | |
| g.context.bezierCurveTo(prevCP.x, prevCP.y, cP.x, cP.y, point.x, point.y); | |
| //arrow | |
| if(i%2==0){ | |
| p0 = mo.GeometryOperators.bezierCurvePoints( | |
| prevPoint.x, prevPoint.y, | |
| prevCP.x, prevCP.y, | |
| cP.x, cP.y, | |
| point.x, point.y, | |
| 0.49 | |
| ); | |
| p1 = mo.GeometryOperators.bezierCurvePoints( | |
| prevPoint.x, prevPoint.y, | |
| prevCP.x, prevCP.y, | |
| cP.x, cP.y, | |
| point.x, point.y, | |
| 0.51 | |
| ); | |
| a = Math.atan2(p1.y-p0.y,p1.x-p0.x); | |
| arrows.push((p0.x+p1.x)*0.5, (p0.y+p1.y)*0.5, a); | |
| } | |
| prevCP = controlPoints[1]; | |
| prevPoint = point; | |
| } | |
| g.context.stroke(); | |
| for(i=0; arrows[i]!=null;i+=3){ | |
| //triangle(arrows[i], arrows[i+1], arrows[i+2]); | |
| } | |
| } | |
| drawClustersCircles = function(g){ | |
| var x, y, maxD; | |
| var points; | |
| var intensity = 1 - 0.01*friction; | |
| var anti = 1 - intensity; | |
| var circle, circle1; | |
| var i, j; | |
| var dx, dy, delta; | |
| g.setStroke('black', 1); | |
| clustersTable.forEach(function(nodeList, i){ | |
| points = []; | |
| circle = clusterCircles[i]; | |
| //r = nodeList.length*5000; | |
| // x = 0; | |
| // y = 0; | |
| // maxD = 0; | |
| nodeList.forEach(function(node){ | |
| // x+=node._x; | |
| // y+=node._y; | |
| // maxD = Math.max(maxD, Math.sqrt(Math.pow(circle.x-node._x, 2)+Math.pow(circle.y-node._y, 2))); | |
| // if(Math.pow(node.x-anti*circle.x, 2)+Math.pow(node.y-anti*circle.y, 2)>r){ | |
| node.x = intensity*node.x + anti*circle.x; | |
| node.y = intensity*node.y + anti*circle.y; | |
| // } | |
| points.push({x:node._x, y:node._y}); | |
| }); | |
| // circle.x = x/nodeList.length; | |
| // circle.y = y/nodeList.length; | |
| // circle.r = maxD; | |
| nc = makeCircle(points); | |
| if(nc==null) nc = {x:0, y:0, r:0}; | |
| circle.x = nc.x; | |
| circle.y = nc.y; | |
| circle.r = nc.r; | |
| g.sCircle(circle.x, circle.y, circle.r+5); | |
| }); | |
| for(var mm=0; mm<20; mm++){ | |
| var circles = clusterCircles.getSortedRandom(); | |
| for(i=0; circles[i+1]!=null; i++){ | |
| circle = circles[i]; | |
| for(j=i+1; circles[j]!=null; j++){ | |
| circle1 = circles[j]; | |
| dx = circle1.x - circle.x; | |
| dy = circle1.y - circle.y; | |
| d = Math.sqrt(Math.pow(dx, 2)+Math.pow(dy, 2)); | |
| delta = (circle.r+circle1.r+10)*1.1-d; | |
| if(delta>0){ | |
| delta*=0.2; | |
| circle.x -= delta*dx; | |
| circle.y -= delta*dy; | |
| circle1.x += delta*dx; | |
| circle1.y += delta*dy; | |
| } | |
| } | |
| } | |
| } | |
| } | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment