1HTMLWidgets.widget({ 2 3 name: "forceNetwork", 4 5 type: "output", 6 7 initialize: function(el, width, height) { 8 9 d3.select(el).append("svg") 10 .attr("width", width) 11 .attr("height", height); 12 13 return d3.forceSimulation(); 14 }, 15 16 resize: function(el, width, height, force) { 17 18 d3.select(el).select("svg") 19 .attr("width", width) 20 .attr("height", height); 21 22 force.force("center", d3.forceCenter(width / 2, height / 2)) 23 .restart(); 24 }, 25 26 renderValue: function(el, x, force) { 27 28 // Compute the node radius using the javascript math expression specified 29 function nodeSize(d) { 30 if(options.nodesize){ 31 return eval(options.radiusCalculation); 32 33 }else{ 34 return 6} 35 36 } 37 38 39 // alias options 40 var options = x.options; 41 42 // convert links and nodes data frames to d3 friendly format 43 var links = HTMLWidgets.dataframeToD3(x.links); 44 var nodes = HTMLWidgets.dataframeToD3(x.nodes); 45 46 // create linkedByIndex to quickly search for node neighbors 47 // adapted from: http://stackoverflow.com/a/8780277/4389763 48 var linkedByIndex = {}; 49 links.forEach(function(d) { 50 linkedByIndex[d.source + "," + d.target] = 1; 51 linkedByIndex[d.target + "," + d.source] = 1; 52 }); 53 function neighboring(a, b) { 54 return linkedByIndex[a.index + "," + b.index]; 55 } 56 57 // get the width and height 58 var width = el.offsetWidth; 59 var height = el.offsetHeight; 60 61 var color = eval(options.colourScale); 62 63 // set this up even if zoom = F 64 var zoom = d3.zoom(); 65 66 // create d3 force layout 67 force 68 .nodes(d3.values(nodes)) 69 .force("link", d3.forceLink(links).distance(options.linkDistance)) 70 .force("center", d3.forceCenter(width / 2, height / 2)) 71 .force("charge", d3.forceManyBody().strength(options.charge)) 72 .on("tick", tick); 73 74 force.alpha(1).restart(); 75 76 var drag = d3.drag() 77 .on("start", dragstart) 78 .on("drag", dragged) 79 .on("end", dragended) 80 function dragstart(d) { 81 if (!d3.event.active) force.alphaTarget(0.3).restart(); 82 d.fx = d.x; 83 d.fy = d.y; 84 } 85 function dragged(d) { 86 d.fx = d3.event.x; 87 d.fy = d3.event.y; 88 } 89 function dragended(d) { 90 if (!d3.event.active) force.alphaTarget(0); 91 d.fx = null; 92 d.fy = null; 93 } 94 95 // select the svg element and remove existing children 96 var svg = d3.select(el).select("svg"); 97 svg.selectAll("*").remove(); 98 // add two g layers; the first will be zoom target if zoom = T 99 // fine to have two g layers even if zoom = F 100 svg = svg 101 .append("g").attr("class","zoom-layer") 102 .append("g") 103 104 // add zooming if requested 105 if (options.zoom) { 106 function redraw() { 107 d3.select(el).select(".zoom-layer") 108 .attr("transform", d3.event.transform); 109 } 110 zoom.on("zoom", redraw) 111 112 d3.select(el).select("svg") 113 .attr("pointer-events", "all") 114 .call(zoom); 115 116 } else { 117 zoom.on("zoom", null); 118 } 119 120 // draw links 121 var link = svg.selectAll(".link") 122 .data(links) 123 .enter().append("line") 124 .attr("class", "link") 125 .style("stroke", function(d) { return d.colour ; }) 126 //.style("stroke", options.linkColour) 127 .style("opacity", options.opacity) 128 .style("stroke-width", eval("(" + options.linkWidth + ")")) 129 .on("mouseover", function(d) { 130 d3.select(this) 131 .style("opacity", 1); 132 }) 133 .on("mouseout", function(d) { 134 d3.select(this) 135 .style("opacity", options.opacity); 136 }); 137 138 if (options.arrows) { 139 link.style("marker-end", function(d) { return "url(#arrow-" + d.colour + ")"; }); 140 141 var linkColoursArr = d3.nest().key(function(d) { return d.colour; }).entries(links); 142 143 svg.append("defs").selectAll("marker") 144 .data(linkColoursArr) 145 .enter().append("marker") 146 .attr("id", function(d) { return "arrow-" + d.key; }) 147 .attr("viewBox", "0, -5, 10, 10") 148 .attr("refX", 0) 149 .attr("markerWidth", 4) 150 .attr("markerHeight", 4) 151 .attr("orient", "auto") 152 .style("fill", "context-fill") 153 .style("fill", function(d) { return d.key; }) 154 .style("opacity", options.opacity) 155 .append("path") 156 .attr("d", "M0,-5 L10,0 L0,5"); 157 } 158 159 // draw nodes 160 var node = svg.selectAll(".node") 161 .data(force.nodes()) 162 .enter().append("g") 163 .attr("class", "node") 164 .style("fill", function(d) { return color(d.group); }) 165 .style("opacity", options.opacity)
166 .on("mouseover", mouseover) 167 .on("mouseout", mouseout) 168 .on("click", click) 169 .call(drag); 170 171 node.append("circle") 172 .attr("r", function(d){return nodeSize(d);}) 173 .style("stroke", "#fff") 174 .style("opacity", options.opacity) 175 .style("stroke-width", "1.5px"); 176 177 node.append("svg:text") 178 .attr("class", "nodetext") 179 .attr("dx", 12) 180 .attr("dy", ".35em") 181 .text(function(d) { return d.name }) 182 .style("font", options.fontSize + "px " + options.fontFamily) 183 .style("opacity", options.opacityNoHover) 184 .style("pointer-events", "none"); 185 186 function tick() { 187 node.attr("transform", function(d) { 188 if(options.bounded){ // adds bounding box 189 d.x = Math.max(nodeSize(d), Math.min(width - nodeSize(d), d.x)); 190 d.y = Math.max(nodeSize(d), Math.min(height - nodeSize(d), d.y)); 191 } 192 193 return "translate(" + d.x + "," + d.y + ")"}); 194 195 function idx(d, type) { 196 var linkWidthFunc = eval("(" + options.linkWidth + ")"); 197 var a = d.target.x - d.source.x; 198 var b = d.target.y - d.source.y; 199 var c = Math.sqrt(Math.pow(a, 2) + Math.pow(b, 2)); 200 if (type == "x1") return (d.source.x + ((nodeSize(d.source) * a) / c)); 201 if (type == "y1") return (d.source.y + ((nodeSize(d.source) * b) / c)); 202 if (options.arrows) { 203 if (type == "x2") return (d.target.x - ((((5 * linkWidthFunc(d)) + nodeSize(d.target)) * a) / c)); 204 if (type == "y2") return (d.target.y - ((((5 * linkWidthFunc(d)) + nodeSize(d.target)) * b) / c)); 205 } else { 206 if (type == "x2") return (d.target.x - ((nodeSize(d.target) * a) / c)); 207 if (type == "y2") return (d.target.y - ((nodeSize(d.target) * b) / c)); 208 } 209 } 210 211 link 212 .attr("x1", function(d) { return idx(d, "x1"); }) 213 .attr("y1", function(d) { return idx(d, "y1"); }) 214 .attr("x2", function(d) { return idx(d, "x2"); }) 215 .attr("y2", function(d) { return idx(d, "y2"); }); 216 } 217 218 function mouseover(d) { 219 // unfocus non-connected links and nodes 220 //if (options.focusOnHover) { 221 var unfocusDivisor = 4; 222 223 link.transition().duration(200) 224 .style("opacity", function(l) { return d != l.source && d != l.target ? +options.opacity / unfocusDivisor : +options.opacity }); 225 226 node.transition().duration(200) 227 .style("opacity", function(o) { return d.index == o.index || neighboring(d, o) ? +options.opacity : +options.opacity / unfocusDivisor; }); 228 //} 229 230 d3.select(this).select("circle").transition() 231 .duration(750) 232 .attr("r", function(d){return nodeSize(d)+5;}); 233 d3.select(this).select("text").transition() 234 .duration(750) 235 .attr("x", 13) 236 .style("stroke-width", ".5px") 237 .style("font", options.clickTextSize + "px ") 238 .style("opacity", 1); 239 } 240 241 function mouseout() { 242 node.style("opacity", +options.opacity); 243 link.style("opacity", +options.opacity); 244 245 d3.select(this).select("circle").transition() 246 .duration(750) 247 .attr("r", function(d){return nodeSize(d);}); 248 d3.select(this).select("text").transition() 249 .duration(1250) 250 .attr("x", 0) 251 .style("font", options.fontSize + "px ") 252 .style("opacity", options.opacityNoHover); 253 } 254 255 function click(d) { 256 return eval(options.clickAction) 257 } 258 259 // add legend option 260 if(options.legend){ 261 var legendRectSize = 18; 262 var legendSpacing = 4; 263 var legend = svg.selectAll('.legend') 264 .data(color.domain()) 265 .enter() 266 .append('g') 267 .attr('class', 'legend') 268 .attr('transform', function(d, i) { 269 var height = legendRectSize + legendSpacing; 270 var offset = height * color.domain().length / 2; 271 var horz = legendRectSize; 272 var vert = i * height+4; 273 return 'translate(' + horz + ',' + vert + ')'; 274 }); 275 276 legend.append('rect') 277 .attr('width', legendRectSize) 278 .attr('height', legendRectSize) 279 .style('fill', color) 280 .style('stroke', color); 281 282 legend.append('text') 283 .attr('x', legendRectSize + legendSpacing) 284 .attr('y', legendRectSize - legendSpacing) 285 .text(function(d) { return d; }); 286 } 287 288 // make font-family consistent across all elements 289 d3.select(el).selectAll('text').style('font-family', options.fontFamily); 290 }, 291});
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.