1// d3 force graphs related, i.e. visualization + physics 2 3 4function myGraph(selector) { 5 6 // Add and remove elements on the graph object 7 this.addNode = function (id, type, x, y) { 8 nodes.push({"id": id, "type": type, x: x, y: y, vx:0, vy:0, links:[]}); 9 return nodes[nodes.length-1]; 10 }; 11 12 this.removeNode = function (id) { 13 var n = findNode(id); 14 while (n.links.length > 0) { 15 removeLinkIndex(links.indexOf(n.links[0])); 16 } 17 nodes.splice(findNodeIndex(id), 1); 18 }; 19 20 var removeLinkIndex = function(i) { 21 var slinks = links[i].source.links; 22 slinks.splice(slinks.indexOf(links[i]), 1); 23 var tlinks = links[i].target.links; 24 tlinks.splice(tlinks.indexOf(links[i]), 1); 25 links.splice(i, 1); 26 } 27 28 this.removeLink = function (source, target) { 29 for (var i = 0; i < links.length; i++) { 30 if (links[i].source.id == source && links[i].target.id == target) { 31 removeLinkIndex(i); 32 break; 33 } 34 } 35 }; 36 37 this.removeAllLinks = function () { 38 links.splice(0, links.length); 39 update(); 40 }; 41 42 this.removeAllNodes = function () { 43 nodes.splice(0, nodes.length); 44 links.splice(0, links.length); 45 newNodeIndex = 0; 46 update(); 47 }; 48 49 this.addLink = function (source, target, value) { 50 var nsource = findNode(source); 51 var ntarget = findNode(target); 52 var newLink = {"source": nsource, "target": ntarget, "value": value}; 53 nsource.links.push(newLink); 54 ntarget.links.push(newLink); 55 links.push(newLink); 56 }; 57 58 this.findNode = function (id) { 59 for (var i in nodes) { 60 if (nodes[i]["id"] === id) return nodes[i]; 61 } 62 ; 63 }; 64 65 var findNodeIndex = function (id) { 66 for (var i = 0; i < nodes.length; i++) { 67 if (nodes[i].id == id) { 68 return i; 69 } 70 } 71 72 }; 73 74 this.getLinked = function (node) { 75 return node.links.map(function(e) { 76 return (e.source === node ? e.target : e.source); 77 }); 78 } 79 80 this.screenToWorldPoint = function(x,y) { 81 var svgEl = svg.node(); 82 var pt = svgEl.createSVGPoint(); 83 pt.x = x; 84 pt.y = y; 85 pt = pt.matrixTransform(vis.node().getCTM().inverse()); 86 return pt; 87 } 88 89 // set up the D3 visualisation in the specified element 90 91 var color = d3.scaleOrdinal() 92 .domain(graphNodes) 93 .range(graphNodesColors); 94 95 96 var svg = d3.select(selector) 97 .append("svg:svg") 98 .attr("width", w) 99 .attr("height", h) 100 .attr("id", "svg") 101 .attr("pointer-events", "all") 102 .attr("viewBox", "0 0 " + w + " " + h) 103 .attr("preserveAspectRatio", "xMinYMin meet") //mod 104 .on("click",backClick) 105 106 107 108 var vis = svg.append('svg:g'); 109 110 var force = d3.forceSimulation(); 111 112 this.nodes = force.nodes() 113 this.links = []; 114 115 d3.select("input[id='gravRange']") 116 .on("input", inputted); 117 118// d3.select("input[id='rewritesRange']") 119// .on("input", inputted); 120 121 this.update = function () { 122 // Update transform list 123 findAllTransforms(); 124 125 // Update graph 126 var link = vis.selectAll("line") 127 .data(links, function (d) { 128 return d.source.id + "-" + d.target.id; 129 }); 130 131 var linkEnter = link.enter() 132 .append("line") 133 .style("stroke-opacity",0).style("fill-opacity",0) 134 .attr("id", function (d) { 135 return d.source.id + "-" + d.target.id; 136 }) 137 .attr("stroke-width", function (d) { 138 return d.value / 10; 139 }) 140 .transition() 141// .delay(0.2) 142 .duration(2) 143 .style("stroke-opacity",1).style("fill-opacity",1) 144 .attr("class", "link") 145 //link.append("title") 146 // .text(function (d) { 147 // return d.value; 148 // }); 149 link.exit().remove(); 150 151 link = link.merge(linkEnter) 152 153 var node = vis.selectAll("g.node") 154 .data(nodes, function (d) { 155 return d.id; 156 }); 157 158 var nodeEnter = node.enter().append("g") 159 .attr("class", "node") 160 161 nodeEnter.append("svg:circle") 162 .style("stroke-opacity",0).style("fill-opacity",0) 163 .transition() 164// .delay(0.2) 165 .duration(1) 166 .style("stroke-opacity",1).style("fill-opacity",1) 167 .attr("r", function(d) { 168 if (d.type == "in" || d.type == "out" || d.type == "middle") { 169 return 4; 170 } else { 171 return 8; 172 } 173 }) 174 .attr("id", function (d) { 175 return "Node;" + d.id; 176 }) 177 .attr("class", "nodeStrokeClass") 178 .attr("fill", function(d) { return color(d.type); }) 179 //nodeEnter.append("svg:text") 180 // .attr("class", "textClass") 181 // .attr("x", 14) 182 // .attr("y", ".31em") 183 // .text(function (d) { 184 // return d.type; 185 // }); 186 187 node.exit().remove(); 188 189 node = node.merge(nodeEnter) 190 .on("click",nodeClick) 191 .on("mouseenter",nodeHover) 192 .call(d3.drag() 193 .on("start", dragstarted) 194 .on("drag", dragged) 195 .on("end", dragended) 196 ); 197 198 function dragstarted(d) { 199 if (!d3.event.active) force.alphaTarget(0.1).restart(); 200 d.fx = d.x; 201 d.fy = d.y; 202 } 203 204 function dragged(d) { 205 d.fx = d3.event.x; 206 d.fy = d3.event.y; 207 } 208 209 function dragended(d) { 210 if (!d3.event.active) force.alphaTarget(0); 211 d.fx = null; 212 d.fy = null; 213 } 214 215 function gravForce() { 216 var gravi = (document.getElementById("gravRange").value) / 1000; 217 return gravi; 218 } 219 220 // Keep node objects on top of edges
221 $(".nodeStrokeClass").each(function( index ) { 222 var gnode = this.parentNode; 223 gnode.parentNode.appendChild(gnode); 224 }); 225 226 d3.zoom().on("zoom", function zoom_actions(){ 227 vis.attr("transform", d3.event.transform) 228 })(svg) 229 // Restart the force layout. 230 231 force 232 .alpha(forceAlpha) 233 .alphaDecay(forceAlphaDecay) 234 .velocityDecay(forceVelocityDecay) 235 .force("charge_force", d3.forceManyBody().strength(chargeForceStrength)) 236 .force("center_x", d3.forceX(w / 2).strength(gravForce)) 237 .force("center_y", d3.forceY(h / 2).strength(gravForce)) 238 .force("links", d3.forceLink(links).id(function (d) { return d.id; }).distance(function(d) { 239 if (d.value == 1) { 240 return 2; 241 } else { 242 return 1; 243 } 244 }).strength(forceStrength)) 245 .on("tick", function () { 246 247 node.attr("transform", function (d) { 248 return "translate(" + d.x + "," + d.y + ")"; 249 }); 250 251 link.attr("x1", function (d) { 252 return d.source.x; 253 }) 254 .attr("y1", function (d) { 255 return d.source.y; 256 }) 257 .attr("x2", function (d) { 258 return d.target.x; 259 }) 260 .attr("y2", function (d) { 261 return d.target.y; 262 }); 263 }) 264 .restart(); 265 266// end definition update() 267 }; 268 269function inputted() { 270 force.alphaTarget(1); 271 force.restart(); 272 update(); 273} 274 275// Make it all go 276 update(); 277 278// end function myGraph 279} 280 281 282 283function setMode(newMode, newType) { 284 mode = newMode; 285 addType = newType; 286 selection = null; 287} 288 289 290 291function findLinkedOfType(node, type) { 292 var linked = getLinked(node); 293 for (var i=0; i<linked.length; i++) { 294 var o = linked[i]; 295 if (o.type == type) { 296 return o; 297 } 298 } 299} 300 301function findLinkedHalfEdge(node) { 302 var linked = getLinked(node); 303 for (var i=0; i<linked.length; i++) { 304 var o = linked[i]; 305 if (!isCenter(o)) { 306 return o; 307 } 308 } 309} 310 311function findLinkedCenter(node) { 312 if (isCenter(node)) { 313 return node; 314 } 315 var linked = getLinked(node); 316 for (var i=0; i<linked.length; i++) { 317 var o = linked[i]; 318 if (isCenter(o)) { 319 return o; 320 } 321 } 322} 323 324function isCenter(node) { 325 return !(node.type == "in" || node.type == "out" || node.type == "middle"); 326} 327 328 329 330 331function removeNodeAndEdges(center) { 332 var linked2 = getLinked(center); 333 for (var i=0; i<linked2.length; i++) { 334 removeNode(linked2[i].id); 335 } 336 removeNode(center.id); 337} 338 339function addNodeAndEdges(type,x,y) { 340 x = x || w/2; 341 y = y || h/2; 342 343 var i = newNodeIndex; 344 345 var valence = nodeValence[type]; 346 347 if (!valence) throw new TypeError("Unknown type" + type); 348 349 var portTypes = nodePortTypes[valence.length-1]; 350 var portList = [i]; 351 352 for (k=0; k<valence.length; k++) { 353 addNode(i+k+1, portTypes[k], x + (Math.random()*20), y + (Math.random()*20)) 354 findNode(i+k+1).dir = valence[k]; 355 portList.push(i+k+1); 356 } 357 358 addNode(i, type, x, y); 359 360 for (k=0; k<valence.length; k++) { 361 addLink(i, i+k+1, 2) 362 } 363 364 newNodeIndex += valence.length + 1; 365 366 return portList; 367} 368 369 370 function moveLink1(s1,d2i) { 371 // Connect the other side of s1 to d2 372 var s2 = findLinkedHalfEdge(s1); 373 if (s2 != null) { 374 removeLink(s1.id,s2.id); 375 removeLink(s2.id,s1.id); 376 addLink(s2.id,d2i,2); 377 } 378 } 379 380 function moveLink2(s1,d1) { 381 // Connect the other side of two half-edges to each other 382 var s2 = findLinkedHalfEdge(s1); 383 var d2 = findLinkedHalfEdge(d1); 384 if (s2 != null) { 385 removeLink(s1.id,s2.id); 386 removeLink(s2.id,s1.id); 387 } 388 if (d2 != null) { 389 removeLink(d1.id,d2.id); 390 removeLink(d2.id,d1.id); 391 } 392 if (s2 != null && d2 != null && s2 != d1) 393 addLink(s2.id,d2.id,2); 394 } 395 396function backClick(d,i) { 397 var e = d3.event; 398 var pt = screenToWorldPoint(e.offsetX,e.offsetY) 399 400 switch (mode) { 401 case "add": 402 addNodeAndEdges(addType,pt.x,pt.y); 403 update(); 404 break; 405 case "delete": 406 break; 407 case "transform": 408 break; 409 case "link": 410 selection = null; 411 break; 412 } 413} 414 415function nodeClick(d,i) { 416 var e = d3.event; 417 switch (mode) { 418 case "add": 419 break; 420 case "delete": 421 var center = findLinkedCenter(d); 422 423 removeNodeAndEdges(center); 424 update(); 425 426 break; 427 case "transform": 428 var trans = findTransform(d); 429 if (trans) { 430 doTransform(d, trans); 431 update(); 432 } 433 434 break; 435 case "link": 436 var linkCount = getLinked(d).length; 437 438 if (isCenter(d)) { 439 return; 440 } 441 442 if (linkCount == 1) { 443 if (selection != null && selection.dir != d.dir) { 444 addLink(selection.id, d.id, 2); 445 update(); 446 selection = null; 447 } else { 448 selection = d; 449 } 450 } else { 451 var other = findLinkedHalfEdge(d); 452 removeLink(d.id, other.id); 453 removeLink(other.id, d.id); 454 selection = null; 455 } 456 update(); 457 break; 458 } 459 460 e.stopPropagation(); 461} 462 463function nodeHover(d,i) { 464 var e = d3.event; 465 exportMolToScreen(); 466 switch (mode) { 467 case "transform": 468 var trans = findTransform(d); 469 if (trans) { 470 doTransform(d, trans); 471 update(); 472 } 473 474 break; 475 } 476 exportMolToScreenAfter(); 477} 478 479 480 481
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.