Skip to content

Instantly share code, notes, and snippets.

@moebio
Created August 19, 2015 17:29
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save moebio/ec78bdeb94085f166899 to your computer and use it in GitHub Desktop.
Save moebio/ec78bdeb94085f166899 to your computer and use it in GitHub Desktop.
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