var units = "Widgets"; // Dimensions var w = 960, h = 600; var margin = {top: 10, right: 10, bottom: 10, left:25}, width = w - margin.left - margin.right, height = h - margin.top - margin.bottom; // format variables var formatNumber = d3.format(",.0f"), // zero decimal places format = function(d) { return formatNumber(d) + "" + units; }, color = d3.scaleOrdinal(d3.schemeCategory20); var red = d3.color("hsl(0, 80%, 50%)"); // {h: 0, l: 0.5, s: 0.8, opacity: 1} // color = d3.scaleOrdinal(d3.schemeCategory10()); // SVG Canvas var svg = d3.select("#chart_15").append("svg") .attr("width", w+100) .attr("height", 700) .append("g") .attr("transform", "translate(" + 100+ ","+45+")"); var sankey = d3.sankey() .nodeWidth(20) .nodePadding(40) .size([width-400, height]) //Changes length of links// .align("left"); var path = sankey.link(); // for gradient coloring var defs = svg.append("defs"); var graph; // Read data d3.csv("sankey.csv", function(error, data) { // Define graph graph = {"nodes" : [], "links" : []}; // Arrange .csv data file data.forEach(function (d) { graph.nodes.push({ "name": d.source }); // graph.nodes.push({ "name1": d.source }); graph.nodes.push({ "name": d.target }); graph.links.push({ "source": d.source, "target":d.target, "value": +d.value }); }); // return only the distinct / unique nodes graph.nodes = d3.keys(d3.nest() .key(function (d) { return d.name; }) .object(graph.nodes)); // Properties for nodes to keep track of whether they are collapsed and how many of their parent nodes are collapsed graph.nodes.forEach(function (d,i) { graph.nodes[i] = { "name": d }; graph.nodes[i].collapsing = 0; // count of collapsed parent nodes graph.nodes[i].collapsed = true; graph.nodes.collapsible = true; }); // links point to the whole source or target node rather than the index because we need the source nodes for filtering. //I also set all target nodes are collapsible. graph.links.forEach(function(e) { e.source = graph.nodes.filter(function(n) { return n.name === e.source; })[0], e.target = graph.nodes.filter(function(n) { return n.name === e.target; })[0]; e.target.collapsible = true; }); // // Collapse after the second level // graph.nodes.forEach(collapsed); // update(name); // // Collapse the node and all it's children // function collapsed(d) { // if(d.nodes) { // d._nodes = d.nodes // d._nodes.forEach(collapsed) // d.nodes = null // } // } update(); }); var nodes, links; function update() { nodes = graph.nodes.filter(function(d) { // return nodes with no collapsed parent nodes return d.collapsing == 0; }); links = graph.links.filter(function(d) { // return only links where source and target are visible return d.source.collapsing == 0 && d.target.collapsing == 0; }); // Sankey properties sankey .nodes(nodes) .links(links) .layout(32); // I need to call the function that renders the sankey, remove and call it again, // or the gradient coloring doesn't apply (I don't know why) sankeyGen(); svg.selectAll("g").remove(); sankey.align("left").layout(32); sankeyGen(); } function sankeyGen() { /* function that will create a unique id for your gradient from a link data object. It's also a good idea to give a name to the function for determining node colour */ // define utility functions function getGradID(d) { return "linkGrad-" + d.source.name + "-" + d.target.name; }; // function nodeColor(d) { // return d.color = color(d.name.replace(/ .*/, "")); // }; // create gradients for the links var grads = defs.selectAll("linearGradient") .data(links, getGradID); grads.enter().append("linearGradient") .attr("id", getGradID) .attr("gradientUnits", "userSpaceOnUse"); function positionGrads() { grads.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;}); } positionGrads(); grads.html("") //erase any existing elements on update .append("stop") .attr("offset", "0%") // .attr("stop-color", function(d) { // return nodeColor( (+d.source.x <= +d.target.x)? d.source: d.target) ; // }); grads.append("stop") .attr("offset", "100%") // .attr("stop-color", function(d) { // return nodeColor( (+d.source.x > +d.target.x)? d.source: d.target) // }); //////////////////////////////////// ////// LINKS ////////////// // // ENTER the links//////Link Color////// console.log(links) var link = svg.append("g").selectAll(".link") .data(links) .enter().append("path") .attr("class", "link") .attr("d", path) .style("stroke", function(d) { return "url(#" + getGradID(d) + ")"; }) // .style("stroke", function(d) { // return d.source.color; //}) .style("stroke", function(link) { return color(link.source,214) || color(link.target, 1) || colors.fallback; }) .style("stroke-width", function(d) { return Math.max(1, d.dy); }) .sort(function(a, b) { return b.dy - a.dy; }); // add the link titles link.append("title") .text(function(d) { return d.source.name + " → " + d.target.name; }); ////// NODES ////// // // ENTER the nodes var node = svg.append("g").selectAll(".node") .data(nodes) .style("fill", "red") .enter().append("g") .attr("class", function(d) { return "node " + d.name; }) .attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")" }) //// Drag the nodes //// /*.call(d3.drag() .subject(function(d) { return d; }) .on("start", function() { this.parentNode.appendChild(this);}) .on("drag", dragmove) );*/ // add the rectangles for the nodes node.append("rect") .attr("height", function(d) { return d.dy; }) .attr("width", sankey.nodeWidth()) // .style("fill", function(d) { // return d.color = color(d.name.replace(/ .*/, "")); // }) // Colors all rectangle nodes .style("fill", function(d) { return "#0000FF"; }) .style("stroke", function(d) { // return color(d.name.replace(/ .*/, "")); // return d3.rgb(d.color).darker(2); // return "white" }) .append("title") .text(function(d) { return d.name + "\n" ; }); // Scale for text var graphValues = new Array(nodes.length-1); for (var i = 0; i <= nodes.length-1; i++) { graphValues[i] = nodes[i].value; }; var textScale = d3.scaleLinear() .domain([d3.min(graphValues), d3.max(graphValues)]) .range([10, 20]); // add in the title for the nodes node.append("text") // .style("font-size", function(d) { return textScale(d.value); }) .style("font-family", "Times-Roman") .style("color", "red") .attr("x", function(d) { return d.dx / 2}) .attr("y", function(d) { return d.dy / 2; }) .attr("dy", "1em") .attr("dx", "-6em") // .text(function(d) { return d.name; }) .attr("text-anchor", "end") .attr("transform", null) // .style("color", "red") // Selects the main node .filter(function(d) { return d.x < 1; }) .attr("x", function(d) { return - d.dy / 2 }) .attr("y", 0) .attr("text-anchor", "start"); // the function for moving the nodes // function dragmove(d) { // d3.select(this) // .attr("transform", // "translate(" + d.x + "," + (d.y = Math.max(0, Math.min(height - d.dy, d3.event.y))) + ")"); // sankey.relayout(); // link.attr("d", path); // } // d3.selectAll('.node') // .transition() // // .duration(2150) // .attr('opacity', ); // d3.selectAll('.link') // .transition() // // .duration(2444) // .style('opacity', ); node.append("text").text(function(d) { return "" + d.name +"";}) .attr("x", function(d) { return d.dx / 2}) .attr("y", function(d) { return d.dy / 2; }) .attr("dy", "1em") .attr("dx", "-5em") .filter(function(d) { return d.x < 1; }) .attr("x", function(d) { return - d.dy / 2 }) .attr("y", 0) // .attr("fill-opacity", 0) // .transition().delay(3500).duration(1500) // .attr("fill-opacity", 1); // .transition() // // .duration() // .style('opacity',1) // // .attr("text-anchor", "start"); // .style("opacity","0") // .transition("opacity", "0.001"); // node.select(this).append().style("fill", "red"); /////////////////////Onclick functions and calls////// d3.select("#reset").on("click", function (d) { d3.selectAll('.node') // .transition() // .duration(2250) .style('opacity',0.01) .attr("fill-opacity", 0.01) .transition().delay(35).duration(15) .transition().delay(35).duration(15) d3.selectAll('.link') // .transition() // .duration(2444) .style('opacity',0.01) .attr("fill-opacity", 0.01) .transition().delay(3500).duration(1500) .transition().delay(35).duration(1500) }); // d3.select("#reset").on("click", function (d) { d3.select("#chart_15").style("opacity",1); // }); // d3.select("#reset").on("click", reset) // function reset(){ // node.selectAll(".link").selectAll(".node").selectAll(".link").style("opacity", 0) // d3.selectALL("graph").style("opacity", 0) // // // d3.select(this).style("opacity", 2); // d3.select("#chart_15").on("click", function(d) { node.selectAll(".link").selectAll(".node").selectAll(".link").style("opacity", 0) // d3.select(this).style("opacity", 2); // // // } // }); // Start button causes the text to appear temporarily // d3.select("#start").on("click", clicked); // d3.select("#start").on("click", start); // function start() { // node.append("text").text(function(d) { return d.name; }).attr("x", function(d) { return d.dx / 2}) // .attr("y", function(d) { return d.dy / 2; }) // .attr("dy", "1em") // .attr("dx", "-5em") // .filter(function(d) { return d.x < 1; }) // .attr("x", function(d) { return - d.dy / 2 }) // .attr("y", 0) // .attr("fill-opacity", 0) // // .transition().delay(3500).duration(1500) // .transition().delay(35).duration(1500) // .attr("fill-opacity", 1); // // .transition() // // .duration(2444) // // .style('opacity',1) // // // .attr("text-anchor", "start"); // // .remove() // // changeopacity(); // }; function changeopacity(){ node.append("text").text(function(d) { return d.name; }).attr("x", function(d) { return d.dx / 2}) .attr("y", function(d) { return d.dy / 2; }) .attr("dy", "1em") .attr("dx", "-5em") .filter(function(d) { return d.x < 1; }) .attr("x", function(d) { return - d.dy / 2 }) .attr("y", 0) .style('opacity', 1) } // node.on("click", // click,clicked // ); // node.on("click", clicked); function clicked() { // if (d3.event.defaultPrevented) return; // dragged d3.select(this).transition() .style("fill", function(d){ return "red";}) // .attr("r", 64) .transition() // .attr("r", 32) node.append("rect").tyle("fill", function(d) { return "#65c18c"; }) // .style("fill", color(i)) .style() node.append("text").text(function(d) { return d.name; }).attr("x", function(d) { return d.dx / 2}) .attr("y", function(d) { return d.dy / 2; }) .attr("dy", "1em") .attr("dx", "-5em") .filter(function(d) { return d.x < 1; }) .attr("x", function(d) { return - d.dy / 2 }) .attr("y", 0) .transition() .duration(2444) .style('opacity',1) // .attr("text-anchor", "start"); } node.on('click', click); function click(d) { changeopacity(); if (d3.event.defaultPrevented) return; if (d.collapsible) { // If it was visible, it will become collapsed so we should decrement child nodes count // If it was collapsed, it will become visible so we should increment child nodes count var inc = d.collapsed ? -1 : 1; recurse(d); d3.select(this).transition() // .style("fill", function(d){ return "red";}) // // // .attr("r", 64) // // .transition() // .attr("r", 32) // node.append("rect").tyle("fill", function(d) { return "#65c18c"; // }) .style("fill", color(d)) .style("opacity", 1); function recurse(sourceNode){ //check if link is from this node, and if so, collapse graph.links.forEach(function(l) { if (l.source.name === sourceNode.name){ l.target.collapsing += inc; recurse(l.target); } }); } d.collapsed = !d.collapsed; // toggle state of node } update(); } // } ///////////////////// };