D3
OG
Old school D3 from simpler times
All examples
By author
By category
About
erikaris
Full window
Github gist
Web Science #6 - Twitter Followers Friendship Genderize
<!DOCTYPE html> <meta charset="utf-8"> <style> svg { font: 10px sans-serif; } .node { stroke: #fff; stroke-width: 1.5px; } .node-active{ stroke: red; } .node-inactive{ opacity: .1; } .link { stroke: #555; stroke-width: 1.5px; stroke-opacity: .7; marker-end: url(#end); } .link-active { stroke: red; stroke-opacity: 1; } .link-inactive{ opacity: .1; } .overlay { fill: none; pointer-events: all; } .tooltip { position: absolute; display: none; pointer-events: none; background: #fff; padding: 5px; text-align: left; border: solid #ccc 1px; color: #666; } #btnGender { position: absolute; top = 0; left = 0; } </style> <body> <button id="btnGender">Show Gender</button> <script src="//d3js.org/d3.v3.min.js"></script> <script> var width = 960, height = 500; var color = d3.scale.category10(); var force = d3.layout.force() .charge(-120) .linkDistance(170) .size([width, height]); var svg = d3.select("body").append("svg") .attr("width", width) .attr("height", height); var tooltip = d3.select("body").append("div") .attr("class", "tooltip") var defs = svg.append("defs"); defs.append("marker") .attr("id", "end") .attr("viewBox", "0 -5 10 10") .attr("refX", 32) .attr("refY", 0) .attr("markerWidth", 6) .attr("markerHeight", 6) .attr("orient", "auto") .append("path") .attr("d", "M0,-5L10,0L0,5"); d3.json("twitter_followers.json", function(error, graph) { if (error) throw error; var drag = d3.behavior.drag() .origin(function(d) { return d; }) .on("dragstart", function(d) { d3.event.sourceEvent.stopPropagation(); force.start(); }) .on("drag", function(d) { d3.select(this) .attr("cx", d.x = d3.event.x) .attr("cy", d.y = d3.event.y); }) .on("dragend", function(d) {}); force .nodes(graph.nodes) .links(graph.links) .start(); // https://stackoverflow.com/questions/11496734/add-a-background-image-png-to-a-svg-circle-shape var defs = svg.append("defs") defs.selectAll("pattern") .data(graph.nodes).enter() .append("pattern") .attr("id", function(d) { return "av_" + d.id }) .attr("x", "0%") .attr("y", "0%") .attr("viewBox", "0 0 48 48") .attr("width", "100%") .attr("height", "100%") .append("image") .attr("x", "0%") .attr("y", "0%") .attr("width", 48) .attr("height", 48) .attr("xlink:href", function(d) { return d.avatar_url }) var container = svg.append("g"); var link = container.append("g") .attr("class", "links") .selectAll(".link") .data(graph.links) .enter().append("line") .attr("class", "link"); var node = container.append("g") .attr("class", "nodes") .selectAll(".group") .data(graph.nodes) .enter().append("g") .call(drag); node.append("circle") .attr("id", function(d) { return "node_" + d.id }) .attr("class", "node") .attr("r", 20) .style("fill", function(d) { return "url(#av_" + d.id + ")" }) var linkedByIndex = {}; graph.links.forEach(function(d) { linkedByIndex[d.source.index + "," + d.target.index] = 1; }); function isConnected(a, b) { return linkedByIndex[a.index + "," + b.index] || linkedByIndex[b.index + "," + a.index]; } var svgUse; node.on("mouseover", function(d){ // send hovered node to front if(!svgUse) { svgUse = svg.append("svg:use") .attr("id", "hovered_node"); } svgUse.attr("xlink:href", "#node_" + d.id) .attr("display", "") .style('stroke', 'red'); node.classed("node-inactive", function(o) { thisOpacity = isConnected(d, o) ? true : false; return !thisOpacity; }); d3.select(this).classed("node-active", true); d3.select(this).classed("node-inactive", false); node.classed("node-active", function(o) { thisOpacity = isConnected(d, o) ? true : false; this.setAttribute('fill-opacity', thisOpacity); return thisOpacity; }); link.classed("link-active", function(o) { return o.source === d || o.target === d ? true : false; }); link.classed("link-inactive", function(o) { return o.source !== d && o.target !== d ? true : false; }); // show tooltip tooltip.text(d.name) .style("left", (d3.event.pageX + 7) + "px") .style("top", (d3.event.pageY - 15) + "px") .style("display", "block") .style("opacity", 1); }).on("mouseout", function(d){ node.classed("node-active", false); node.classed("node-inactive", false); link.classed("link-active", false); link.classed("link-inactive", false); // hide tooltip tooltip.style("opacity", 0) .style("display", "none"); }); force.on("tick", function() { link.attr("x1", function(d) { return d.source.x; }) .attr("y1", function(d) { return d.source.y; }) .attr("x2", function(d) { return d.target.x; }) .attr("y2", function(d) { return d.target.y; }); node.attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")" }); }); // Do toggle split and reset on button click d3.select("#btnGender").on("click", function() { btn = d3.select(this) node.transition() .style("stroke", function(d) { if(btn.text() == "Show Gender") { return color(d.gender) } else { return "" } }) if(btn.text() == "Show Gender") { node.transition().select(".node") .style("stroke", function(d) { return color(d.gender) }) .style("stroke-width", 3) } else { node.transition().select(".node") .style("stroke", function(d) { return "" }) .style("stroke-width", 1.5) } if(btn.text() == "Show Gender") { btn.text("Reset") } else { btn.text("Show Gender") } }) }); </script>
https://d3js.org/d3.v3.min.js