Dynamically generated gradients
Last active
February 5, 2016 22:02
-
-
Save dankronstal/b12b025d0eea52ad3f4a to your computer and use it in GitHub Desktop.
Arc Gradients
This file contains 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
<!DOCTYPE html> | |
<html> | |
<head> | |
<meta charset='utf-8'> | |
<title>Arc Gradients</title> | |
<style> | |
</style> | |
</head> | |
<body> | |
<script src='https://d3js.org/d3.v3.min.js'></script> | |
<p>Click nodes to create links; ltr above, rtl below</p> | |
<script> | |
/*** start set up data ***/ | |
// used to assign nodes color by group | |
var color = d3.scale.category20(); | |
var graph = { | |
"nodes":[], | |
"links":[] | |
}; | |
for(i=0; i<100; i++) | |
{ | |
graph.nodes.push({"name":"node"+i, "id":i, "color":color(i)}); | |
} | |
/*** end set up data ***/ | |
var width = 1000; // width of svg image | |
var height = 800; // height of svg image | |
var margin = 20; // amount of margin around plot area | |
var pad = margin / 2; // actual padding amount | |
var radius = 5; // fixed node radius | |
var yfixed = height/2-margin;// pad + radius; // y position for all nodes | |
var newLink = null; | |
var tmpLink = null; | |
var popped; | |
var svg = d3.select("body") | |
.append("svg") | |
.attr("id", "arc") | |
.attr("width", width) | |
.attr("height", height); | |
var gradientDefs = svg.append("svg:defs"); | |
// create plot area within svg image | |
var plot = svg.append("g") | |
.attr("id", "plot") | |
.attr("transform", "translate(" + pad + ", " + pad + ")"); | |
// fix graph links to map to objects instead of indices | |
graph.links.forEach(function(d, i) { | |
d.source = isNaN(d.source) ? d.source : graph.nodes[d.source]; | |
d.target = isNaN(d.target) ? d.target : graph.nodes[d.target]; | |
}); | |
// must be done AFTER links are fixed | |
linearLayout(graph.nodes); | |
// draw links first, so nodes appear on top | |
drawLinks(graph.links); | |
// draw nodes last | |
drawNodes(graph.nodes); | |
// Layout nodes linearly, sorted by group | |
function linearLayout(nodes) { | |
// used to scale node index to x position | |
var xscale = d3.scale.linear() | |
.domain([0, nodes.length - 1]) | |
.range([radius, width - margin - radius]); | |
// calculate pixel location for each node | |
nodes.forEach(function(d, i) { | |
d.x = xscale(i); | |
d.y = yfixed; | |
}); | |
} | |
// Draws nodes on plot | |
function drawNodes(nodes) { | |
d3.select("#plot").selectAll(".node") | |
.data(nodes) | |
.enter() | |
.append("circle") | |
.attr("class", "node") | |
.attr("id", function(d, i) { return d.name; }) | |
.attr("cx", function(d, i) { return d.x; }) | |
.attr("cy", function(d, i) { return d.y; }) | |
.attr("r", function(d, i) { return radius; }) | |
.style("fill", function(d, i) { return d.color; }) | |
.attr("pointer-events", "all") | |
.on("click", function(d){ | |
if(newLink != null) { | |
newLink.target = d.id > newLink.source.id ? d : newLink.source; | |
newLink.source = d.id > newLink.source.id ? newLink.source : d; | |
newLink.torb= d.id == newLink.source.id ? 1 : -1; | |
newLink.value = 2; | |
newLink.fill = generateGradientFill(newLink.source,newLink.target); | |
graph.links.push(newLink); | |
drawLinks(graph.links); | |
d3.select("#"+newLink.source.name).style("fill",function(dd){ return d3.rgb(dd.color).darker(1);}); | |
d3.select("#"+newLink.target.name).style("fill",function(dd){ return d3.rgb(dd.color).darker(1);}); | |
newLink = null; | |
}else{ | |
newLink = {}; | |
newLink.source = d; | |
d3.select(this).style("fill",function(dd){ return d3.rgb(dd.color).brighter(1);}); | |
} | |
}) | |
.on("mousemove", function(d){ | |
if(newLink != null) { | |
tmpLink = {source: newLink.source, target: d, value: 2, isTmp:1}; | |
tmpLink.torb= d.id == tmpLink.source.id ? 1 : -1; | |
graph.links.push(tmpLink); | |
drawLinks(graph.links); | |
} | |
}) | |
.on("mouseout", function(d){ | |
tmpIndex = -1; | |
graph.links.forEach(function(d,i){ | |
if(d.isTmp == 1) tmpIndex = i; | |
}); | |
if(tmpIndex >=0){ | |
graph.links.splice(tmpIndex,1); | |
drawLinks(graph.links); | |
} | |
}); | |
} | |
// Draws nice arcs for each link on plot | |
function drawLinks(links) { | |
// scale to generate radians (just for lower-half of circle) | |
var radians = d3.scale.linear() | |
.range([Math.PI / 2, 3 * Math.PI / 2]); | |
// path generator for arcs (uses polar coordinates) | |
var arc = d3.svg.line.radial() | |
.interpolate("linear") | |
.tension(0) | |
.angle(function(d) { return radians(d); }); | |
// add links | |
d3.select("#plot").selectAll(".link") | |
.data(links) | |
.enter() | |
.insert("path") | |
.attr("fill", "none") | |
.attr("stroke-width", function(d){ return d.value; }) | |
.attr("stroke", function(d){ return d.fill; }) | |
.attr("transform", function(d, i) { | |
// arc will always be drawn around (0, 0) | |
// shift so (0, 0) will be between source and target | |
var xshift = d.source.x + (d.target.x - d.source.x) / 2; | |
var yshift = yfixed; | |
return "translate(" + xshift + ", " + yshift + ")"; | |
}) | |
.attr("d", function(d, i) { | |
// get x distance between source and target | |
var xdist = Math.abs(d.source.x - d.target.x); | |
// set arc radius based on x distance | |
arc.radius(xdist / 2); | |
// want to generate 1/3 as many points per pixel in x direction | |
var points = d3.range(0, Math.ceil(xdist)); | |
// set radian scale domain | |
//radians.domain([0, points.length - 1]); //orient arcs at bottom | |
radians.domain([0, d.torb * points.length - 1]);//orient arcs according to torb property | |
// return path for arc | |
return arc(points); | |
}); | |
} | |
function generateGradientFill(s,t){ | |
// Define the gradient | |
newGrad = gradientDefs.append("svg:linearGradient") | |
.attr("id", function(){ return "gradFor"+s.name+t.name; }) | |
.attr("spreadMethod", "pad"); | |
// Define the gradient color stops | |
newGrad.append("svg:stop") | |
.attr("offset", "0%") | |
.attr("stop-color", s.color) | |
.attr("stop-opacity", .75); | |
newGrad.append("svg:stop") | |
.attr("offset", "100%") | |
.attr("stop-color", t.color) | |
.attr("stop-opacity", .75); | |
return "url(#"+newGrad.attr("id")+")"; | |
} | |
</script> | |
</body> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment