How to make nodes in sankey diagram clickable using d3.js library - javascript

Code Snippet :
We are using d3.js for this.
Sankey diagrams is made up of nodes and links.
Here the data comes from json file.
So how to make all the nodes clickable.
Which methods can we use with the rectangles so that we can make the nodes clickable.
<script>
var margin = {top: 1, right: 1, bottom: 6, left: 1},
width = 960 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
var formatNumber = d3.format(",.0f"), //decimal places
format = function(d) { return formatNumber(d) + " TWh"; },
color = d3.scale.category20();
var svg = d3.select("#chart").append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
var sankey = d3.sankey()
.nodeWidth(15)
.nodePadding(10)
.size([width, height]);
var path = sankey.link();
//d3.json("energy.json", function(energy) {
d3.json("numbers-subset.json", function(energy) {
sankey
.nodes(energy.nodes)
.links(energy.links)
.layout(32);
var link = svg.append("g").selectAll(".link")
.data(energy.links)
.enter().append("path")
.attr("class", "link")
.attr("d", path)
.style("stroke-width", function(d) { return Math.max(1, d.dy); })
.sort(function(a, b) { return b.dy - a.dy; });
link.append("title")
.text(function(d) { return d.source.name + " → " + d.target.name + "\n" + format(d.value); });
var node = svg.append("g").selectAll(".node")
.data(energy.nodes)
.enter().append("g")
.attr("class", "node")
.attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; })
.call(d3.behavior.drag()
.origin(function(d) { return d; })
.on("dragstart", function() { this.parentNode.appendChild(this); })
.on("drag", dragmove));
node.append("rect")
.attr("height", function(d) { return d.dy; })
.attr("width", sankey.nodeWidth())
.style("fill", function(d) { return d.color = color(d.name.split("|")[0]); })
.style("stroke", function(d) { return d3.rgb(d.color).darker(2); })
.append("title")
.text(function(d) { return d.name + "\n" + format(d.value); });
node.append("text")
.attr("x", -6)
.attr("y", function(d) { return d.dy / 2; })
.attr("dy", ".35em")
.attr("text-anchor", "end")
.attr("transform", null)
.text(function(d) { return d.name; })
.filter(function(d) { return d.x < width / 2; })
.attr("x", 6 + sankey.nodeWidth())
.attr("text-anchor", "start");
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);
}
});
</script>

D3.js is very powerful library give you control over each event to each pixel.
but we need to do one thing in the case of events.
Overlapping event we need to by forget .
Add following code in code.
var node = svg.append("g").selectAll(".node")
.data(graph.nodes)
.enter().append("g")
.attr("class", "node")
.attr("transform", function(d) {
return "translate(" + d.x + "," + d.y + ")"; })
.on("click",function(d){
if (d3.event.defaultPrevented) return;
alert("clicked!"+d.value);
})
.call(d3.behavior.drag()
.origin(function(d) { return d; })
.on("dragstart", function() {
this.parentNode.appendChild(this); })
.on("drag", dragmove));

Related

How can I drag group (g) element in D3.js?

I want to make a draggable <g> element containing a <circle> and a <text> but I failed.
Now I have this code:
var margin = {top: -5, right: -5, bottom: -5, left: -5},
width = 1960 - margin.left - margin.right,
height = 1500 - margin.top - margin.bottom;
var drag = d3.behavior.drag()
.origin(function(d) { return d; })
.on("dragstart", dragstarted)
.on("drag", dragged)
.on("dragend", dragended);
var svg = d3.select("body").append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom);
var dotContainer = svg.append("g")
.attr("class", "dotContainer")
.datum({x:220, y:120})
.attr("x", function(d) { return d.x; })
.attr("y", function(d) { return d.y; })
.call(drag);
var dot = dotContainer.append("circle")
.attr("class", "dot")
.datum({x:220, y:120})
.attr("cx", function(d) { return d.x; })
.attr("cy", function(d) { return d.y; })
.attr("r", 5).call(drag);
var text = dotContainer.append("text")
.datum({x:220, y:120})
.attr("x", function(d) { return d.x; })
.attr("y", function(d) { return d.y; })
.text('Title');
function dragstarted(d) {
d3.event.sourceEvent.stopPropagation();
d3.select(this).classed("dragging", true);
}
function dragged(d) {
d3.select(this).attr("cx", d.x = d3.event.x).attr("cy", d.y = d3.event.y);
}
function dragended(d) {
d3.select(this).classed("dragging", false);
}
<script src="https://d3js.org/d3.v3.min.js"></script>
<circle> element is perfectly draggable, ok. But I need to apply dragging to the whole <g> element to drag my circle together with the <text> element.
How can I do this?
When I apply call(drag) to dotContainer like this
dotContainer.call(drag);
then nothing works.
You should rewrite your dotContainer variable this way:
var dotContainer = svg.append("g")
.attr("class", "dotContainer")
.datum({x:220, y:120})
.attr("transform", function(d) { return 'translate(' + d.x + ' '+ d.y + ')'; })
.call(drag);
Remove .call(drag) for dot variable and rewrite dragged function like this:
function dragged(d) {
d.x += d3.event.dx;
d.y += d3.event.dy;
d3.select(this).attr("transform", function(d,i){
return "translate(" + [ d.x,d.y ] + ")"
});
}
Thus we use transform attribute for an initial container position and for the position update during the dragging.
Check demo in the hidden snippet:
var margin = {top: -5, right: -5, bottom: -5, left: -5},
width = 1960 - margin.left - margin.right,
height = 1500 - margin.top - margin.bottom;
var drag = d3.behavior.drag()
.origin(function(d) { return d; })
.on("dragstart", dragstarted)
.on("drag", dragged)
.on("dragend", dragended);
var svg = d3.select("body").append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom);
var dotContainer = svg.append("g")
.attr("class", "dotContainer")
.datum({x:20, y:20})
.attr("transform", function(d) { return 'translate(' + d.x + ' '+ d.y + ')'; })
.call(drag);
var dot = dotContainer.append("circle")
.attr("class", "dot")
.datum({x:20, y:20})
.attr("cx", function(d) { return d.x; })
.attr("cy", function(d) { return d.y; })
.attr("r", 5)
var text = dotContainer.append("text")
.datum({x:20, y:20})
.attr("x", function(d) { return d.x; })
.attr("y", function(d) { return d.y; })
.text('Title');
function dragstarted(d) {
d3.event.sourceEvent.stopPropagation();
d3.select(this).classed("dragging", true);
}
function dragged(d) {
d.x += d3.event.dx;
d.y += d3.event.dy;
d3.select(this).attr("transform", function(d,i){
return "translate(" + [ d.x,d.y ] + ")"
});
}
function dragended(d) {
d3.select(this).classed("dragging", false);
}
.dotContainer {
cursor: move;
}
<script src="https://d3js.org/d3.v3.min.js"></script>

Coordinated pie chart and bar chart in D3.js

I have a brush coordinated with a bar chart. When the brush is moved and resized the bar chart shows only the filtered bars. In the same page I have a pie chart that isn't coordinated with the bar chart and the brush, but I want it to be. I want that also the pie chart updates its content according to the filtered values. How can I do that?
This is my code, followed by the plnkr link where you can see what I've done so far:
<script type="text/javascript">
var margin = {
top: 20,
right: 20,
bottom: 70,
left: 40,
mid: 20
},
w = 750 - margin.left - margin.right,
h = 300 - margin.top - margin.bottom;
var barPadding = 1;
var padding = 20;
var miniHeight = 60;
var selected;
var svg = d3.select(".outer-wrapper .chart").append("svg")
.attr("width", w + margin.left + margin.right)
.attr("height", h + margin.top + margin.mid + miniHeight + margin.bottom)
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
var barsGroup = svg.append('g')
.attr("class","barsGroup");
var miniGroup = svg.append('g')
.attr("class","miniGroup")
.attr("transform","translate(" + 0 + "," + (margin.top + h + margin.mid) + ")");
var brushGroup = svg.append('g')
.attr("class","brushGroup")
.attr("transform","translate(" + 0 + "," + (margin.top + h + margin.mid) + ")");
var w2 = 400;
var h2 = 400;
var outerRadius = w2 / 2;
var innerRadius = w2 / 3;
var arc = d3.svg.arc()
.innerRadius(innerRadius)
.outerRadius(outerRadius);
var pie = d3.layout.pie()
.sort(null)
.value(function(d) { return d.values; });
var color = d3.scale.category20c();
var svg2 = d3.select("body")
.append("svg")
.attr("width", w2)
.attr("height", h2);
d3.csv("data.csv", function(data) {
var dataset = d3.nest()
.key(function(d) {
return d.Year;
})
.sortKeys(d3.ascending)
.rollup(function(values) {
return values.length;
})
.entries(data)
.filter(function(d) {
return d.key != "UNK" && d.key != "VAR" && d.key != 199 && d.key != 211 && d.key != 2017;
});
//SCALES
var xScale = d3.scale.ordinal()
.domain(dataset.map(function(d) {
return d.key
}))
.rangeRoundBands([0, w], 0.05);
var xScaleBrush = d3.scale.ordinal()
.domain(d3.range(dataset.length))
.rangeRoundBands([0, w], 0.05);
var yScale = d3.scale.linear()
.domain([0, d3.max(dataset, function(d) {
return d.values;
})])
.range([h, 0]);
//AXIS
var xAxis = d3.svg.axis()
.scale(xScale)
.orient("bottom")
.tickValues([1900,1920,1930,1940,1950,1960,1970,1980,1990,2000, 2010]);
var yAxis = d3.svg.axis()
.scale(yScale)
.ticks(6)
.orient("left");
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + h + ")")
.selectAll("text")
.style("text-anchor", "end")
.attr("dx", "-.8em")
.attr("dy", "-.55em")
.attr("transform", "rotate(-90)");
svg.append("g")
.attr("class","x2 axis")
.attr("transform", "translate(" + 0 + "," + (margin.top + h + margin.mid + miniHeight) + ")" )
.call(xAxis)
.selectAll("text")
.style("text-anchor", "end")
.attr("dx", "-.8em")
.attr("dy", "-.55em")
.attr("transform", "rotate(-90)");
svg.append("g")
.attr("class", "y axis")
.append("g")
.attr("class", "axisLabel")
.append("text")
.attr("transform", "translate(" + -(margin.left * 0.8) + "," + (h/2) + "), rotate(-90)")
.style("text-anchor", "middle")
.text("Score");
var brush = d3.svg.brush()
.x(xScaleBrush)
.extent([0, w])
.on("brush", display);
brushGroup.append("g")
.attr("class", "brush")
.call(brush)
.selectAll("rect")
.attr("opacity", 0.5)
.attr("height", miniHeight);
function display() {
selected = xScaleBrush.domain()
.filter(function(d){
return (brush.extent()[0] <= xScaleBrush(d)) && (xScaleBrush(d) <= brush.extent()[1]);
});
var start;
var end;
/* Keep a minimum amount of bars on there to avoid any jank */
if (selected.length > 2) {
start = selected[0];
end = selected[selected.length - 1] + 1;
} else {
start = 0;
end = dataset.length;
}
var updatedData = dataset.slice(start, end);
updateBars(updatedData);
}
function update(grp, data, main) {
grp.selectAll("rect").data(data, function(d) {
return d.key;
})
.attr("x", function(d) {
return xScale(d.key);
})
.attr("y", function(d) {
return main ? yScale(d.values) : 0;
})
.attr("width", function (d) {
return xScale.rangeBand();
})
.attr("height", function(d) {
return main ? h - yScale(d.values) : miniHeight;
});
}
function enter(grp, data, main) {
grp.selectAll("rect").data(data, function(d) {
return d.key;
})
.enter()
.append("rect")
.attr("x", function(d, i) {
return xScale(d.key);
})
.attr("y", function(d) {
return main ? yScale( d.values) : 0;
})
.attr("width", function(d) {
return xScale.rangeBand();
})
.attr("height", function(d) {
return main ? h - yScale(d.values) : miniHeight;
})
.attr("fill", function(d) {
var color = d3.scale.linear()
.domain([0, d3.max(dataset, function(d) {
return d.values;
})])
.range([200, 244]);
var deg = color(d.values);
return "hsl(" + deg + ", 100%, 50%)";
})
.on("mouseover", function(d) {
if(main){
d3.select(this)
.attr("fill", "orange");
var xPosition = parseFloat(d3.select(this).attr("x"));
var yPosition = parseFloat(d3.select(this).attr("y")) / 2 + 100;
d3.select("#tooltip")
.style("left", xPosition + "px")
.style("top", yPosition + "px")
.style("z-index", "10")
.select("#value")
.text(d.values);
d3.select("#tooltip")
.select("#key")
.text("Film del " + d.key + " rilasciati su DVD");
d3.select("#tooltip").classed("hidden", false);
}
})
.on("mouseout", function(d) {
d3.select(this)
.transition()
.duration(250)
.attr("fill", function(d) {
var color = d3.scale.linear()
.domain([0, d3.max(dataset, function(d) {
return d.values;
})])
.range([200, 244]);
var deg = color(d.values);
return "hsl(" + deg + ", 100%, 50%)";
});
d3.select("#tooltip").classed("hidden", true);
});
}
function exit(grp, data) {
grp.selectAll("rect").data(data, function(d) {
return d.key;
}).exit()
.remove();
}
function updateBars(data) {
xScale.domain(data.map(function(d) {
return d.key
}));
yScale.domain([0, d3.max(data, function(d) {
return d.values;
})]);
/* Update */
update(barsGroup, data, true);
/* Enter… */
enter(barsGroup, data, true);
/* Exit */
exit(barsGroup, data);
svg.select(".outer-wrapper .chart .y")
.transition()
.duration(10)
.call(yAxis);
svg.select(".outer-wrapper .chart .x")
.transition()
.duration(50)
.call(xAxis);
}
enter(miniGroup, dataset, false);
updateBars(dataset);
var dataset2 = d3.nest()
.key(function(d) { return d.Genre; })
.sortKeys(d3.ascending)
.rollup(function(values) { return values.length; })
.entries(data);
var text = svg2.append("text")
.attr("dx", 200)
.attr("dy", 200)
.attr("font-size", 30)
.style("text-anchor", "middle")
.attr("fill", "#36454f");
var text2 = svg2.append("text")
.attr("dx", 200)
.attr("dy", 230)
.attr("font-size", 20)
.style("text-anchor", "middle")
.attr("fill", "#36454f");
var text3 = svg2.append("text")
.attr("dx", 200)
.attr("dy", 260)
.attr("font-size", 20)
.style("text-anchor", "middle")
.attr("fill", "#36454f");
//Set up groups
var arcs = svg2.selectAll("g.arc")
.data(pie(dataset2))
.enter()
.append("g")
.attr("class", "arc")
.attr("transform", "translate(" + outerRadius + "," + outerRadius + ")")
.on("mouseover", function(d) {
var total = data.length;
var percent = Math.round(1000 * d.value / total) / 10;
text.text(d.data.key).attr("class", "inner-circle");
text2.text(d.value + " DVD");
text3.text(percent +"%");
})
.on("mouseout", function(d) {
text.text(function(d) { return ""; });
text2.text(function(d) { return ""; });
text3.text(function(d) { return ""; });
});
//Draw arc paths
arcs.append("path")
.attr("fill", function(d, i) {
return color(i);
})
.attr("d", arc);
});
</script>
http://plnkr.co/edit/cwNl6zUSOM4yPmUtSRr4?p=preview
You can do that by transforming the part where you build the pieChart into a function that receives the new data.
The only adjustment is that the first thing I'm doing is removing the previous pie chart, to draw it again with the new data:
function updatePie(data){
svg2.selectAll("g.arc").remove();
Here is the complete code:
<script type="text/javascript">
var margin = {
top: 20,
right: 20,
bottom: 70,
left: 40,
mid: 20
},
w = 750 - margin.left - margin.right,
h = 300 - margin.top - margin.bottom;
var barPadding = 1;
var padding = 20;
var miniHeight = 60;
var selected;
var svg = d3.select(".outer-wrapper .chart").append("svg")
.attr("width", w + margin.left + margin.right)
.attr("height", h + margin.top + margin.mid + miniHeight + margin.bottom)
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
var barsGroup = svg.append('g')
.attr("class","barsGroup");
var miniGroup = svg.append('g')
.attr("class","miniGroup")
.attr("transform","translate(" + 0 + "," + (margin.top + h + margin.mid) + ")");
var brushGroup = svg.append('g')
.attr("class","brushGroup")
.attr("transform","translate(" + 0 + "," + (margin.top + h + margin.mid) + ")");
var w2 = 400;
var h2 = 400;
var outerRadius = w2 / 2;
var innerRadius = w2 / 3;
var arc = d3.svg.arc()
.innerRadius(innerRadius)
.outerRadius(outerRadius);
var pie = d3.layout.pie()
.sort(null)
.value(function(d) { return d.values; });
var color = d3.scale.category20c();
var svg2 = d3.select("body")
.append("svg")
.attr("width", w2)
.attr("height", h2);
d3.csv("data.csv", function(data) {
var dataset = d3.nest()
.key(function(d) {
return d.Year;
})
.sortKeys(d3.ascending)
.rollup(function(values) {
return values.length;
})
.entries(data)
.filter(function(d) {
return d.key != "UNK" && d.key != "VAR" && d.key != 199 && d.key != 211 && d.key != 2017;
});
//SCALES
var xScale = d3.scale.ordinal()
.domain(dataset.map(function(d) {
return d.key
}))
.rangeRoundBands([0, w], 0.05);
var xScaleBrush = d3.scale.ordinal()
.domain(d3.range(dataset.length))
.rangeRoundBands([0, w], 0.05);
var yScale = d3.scale.linear()
.domain([0, d3.max(dataset, function(d) {
return d.values;
})])
.range([h, 0]);
//AXIS
var xAxis = d3.svg.axis()
.scale(xScale)
.orient("bottom")
.tickValues([1900,1920,1930,1940,1950,1960,1970,1980,1990,2000, 2010,2020,2030,2040,2050,2060]);
var yAxis = d3.svg.axis()
.scale(yScale)
.ticks(6)
.orient("left");
//Appendi asse x
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + h + ")")
.selectAll("text")
.style("text-anchor", "end")
.attr("dx", "-.8em")
.attr("dy", "-.55em")
.attr("transform", "rotate(-90)");
//Asse x per brush
svg.append("g")
.attr("class","x2 axis")
.attr("transform", "translate(" + 0 + "," + (margin.top + h + margin.mid + miniHeight) + ")" )
.call(xAxis)
.selectAll("text")
.style("text-anchor", "end")
.attr("dx", "-.8em")
.attr("dy", "-.55em")
.attr("transform", "rotate(-90)");
svg.append("g")
.attr("class", "y axis")
.append("g")
.attr("class", "axisLabel")
.append("text")
.attr("transform", "translate(" + -(margin.left * 0.8) + "," + (h/2) + "), rotate(-90)")
.style("text-anchor", "middle")
.text("Score");
var brush = d3.svg.brush()
.x(xScaleBrush)
.extent([0, w])
.on("brush", display);
brushGroup.append("g")
.attr("class", "brush")
.call(brush)
.selectAll("rect")
.attr("opacity", 0.5)
.attr("height", miniHeight);
function display() {
selected = xScaleBrush.domain()
.filter(function(d){
return (brush.extent()[0] <= xScaleBrush(d)) && (xScaleBrush(d) <= brush.extent()[1]);
});
var start;
var end;
/* Keep a minimum amount of bars on there to avoid any jank */
if (selected.length > 2) {
start = selected[0];
end = selected[selected.length - 1] + 1;
} else {
start = 0;
end = dataset.length;
}
var updatedData = dataset.slice(start, end);
updateBars(updatedData);
updatePie(updatedData);
}
function update(grp, data, main) {
grp.selectAll("rect").data(data, function(d) {
return d.key;
})
.attr("x", function(d) {
return xScale(d.key);
})
.attr("y", function(d) {
return main ? yScale(d.values) : 0;
})
.attr("width", function (d) {
return xScale.rangeBand();
})
.attr("height", function(d) {
return main ? h - yScale(d.values) : miniHeight;
});
}
function enter(grp, data, main) {
grp.selectAll("rect").data(data, function(d) {
return d.key;
})
.enter()
.append("rect")
.attr("x", function(d, i) {
return xScale(d.key);
})
.attr("y", function(d) {
return main ? yScale( d.values) : 0;
})
.attr("width", function(d) {
return xScale.rangeBand();
})
.attr("height", function(d) {
return main ? h - yScale(d.values) : miniHeight;
})
.attr("fill", function(d) {
var color = d3.scale.linear()
.domain([0, d3.max(dataset, function(d) {
return d.values;
})])
.range([200, 244]);
var deg = color(d.values);
return "hsl(" + deg + ", 100%, 50%)";
})
.on("mouseover", function(d) {
if(main){
d3.select(this)
.attr("fill", "orange");
var xPosition = parseFloat(d3.select(this).attr("x"));
var yPosition = parseFloat(d3.select(this).attr("y")) / 2 + 100;
d3.select("#tooltip")
.style("left", xPosition + "px")
.style("top", yPosition + "px")
.style("z-index", "10")
.select("#value")
.text(d.values);
d3.select("#tooltip")
.select("#key")
.text("Film del " + d.key + " rilasciati su DVD");
d3.select("#tooltip").classed("hidden", false);
}
})
.on("mouseout", function(d) {
d3.select(this)
.transition()
.duration(250)
.attr("fill", function(d) {
var color = d3.scale.linear()
.domain([0, d3.max(dataset, function(d) {
return d.values;
})])
.range([200, 244]);
var deg = color(d.values);
return "hsl(" + deg + ", 100%, 50%)";
});
d3.select("#tooltip").classed("hidden", true);
});
}
function exit(grp, data) {
grp.selectAll("rect").data(data, function(d) {
return d.key;
}).exit()
.remove();
}
function updateBars(data) {
xScale.domain(data.map(function(d) {
return d.key
}));
yScale.domain([0, d3.max(data, function(d) {
return d.values;
})]);
/* Update */
update(barsGroup, data, true);
/* Enter… */
enter(barsGroup, data, true);
/* Exit */
exit(barsGroup, data);
svg.select(".outer-wrapper .chart .y")
.transition()
.duration(10)
.call(yAxis);
svg.select(".outer-wrapper .chart .x")
.transition()
.duration(50)
.call(xAxis);
}
enter(miniGroup, dataset, false);
updateBars(dataset);
var dataset2 = d3.nest()
.key(function(d) { return d.Genre; })
.sortKeys(d3.ascending)
.rollup(function(values) { return values.length; })
.entries(data);
var text = svg2.append("text")
.attr("dx", 200)
.attr("dy", 200)
.attr("font-size", 30)
.style("text-anchor", "middle")
.attr("fill", "#36454f");
var text2 = svg2.append("text")
.attr("dx", 200)
.attr("dy", 230)
.attr("font-size", 20)
.style("text-anchor", "middle")
.attr("fill", "#36454f");
var text3 = svg2.append("text")
.attr("dx", 200)
.attr("dy", 260)
.attr("font-size", 20)
.style("text-anchor", "middle")
.attr("fill", "#36454f");
function updatePie(data){
svg2.selectAll("g.arc").remove();
var arcs = svg2.selectAll("g.arc")
.data(pie(data))
.enter()
.append("g")
.attr("class", "arc")
.attr("transform", "translate(" + outerRadius + "," + outerRadius + ")")
.on("mouseover", function(d) {
var total = data.length;
var percent = Math.round(1000 * d.value / total) / 10;
text.text(d.data.key).attr("class", "inner-circle");
text2.text(d.value + " DVD");
text3.text(percent +"%");
})
.on("mouseout", function(d) {
text.text(function(d) { return ""; });
text2.text(function(d) { return ""; });
text3.text(function(d) { return ""; });
});
arcs.append("path")
.attr("fill", function(d, i) {
return color(i);
})
.attr("d", arc);
}
updatePie(dataset2);
});

Adding hover effect in d3 word cloud

I am using D3 Cloud to build a word cloud (https://github.com/jasondavies/d3-cloud) and I would like to add an hover effect similar to http://www.jasondavies.com/wordcloud.
Here is the sample code. Complete code is at http://plnkr.co/edit/gNtHZ0lMRTP98mptm3W8?p=preview
var sizeScale = d3.scale.linear()
.domain([0, d3.max(frequency_list, function(d) { return d.freq} )]).range([10, 95]);
layout = d3.layout.cloud().size([w, h])
.words(frequency_list)
.padding(5)
.rotate(function() { return ~~(Math.random() * 2) * 90; })
.font("Impact")
.fontSize(function(d) { return sizeScale(d.freq); })
.on("end",draw)
.start();
}
function draw(words) {
var fill = d3.scale.category20();
d3.select(container).remove();
d3.select("body").append(container)
.attr("width", w)
.attr("height", h)
.append("g")
.attr("transform", "translate(" + [w/2, h/2] + ")")
.selectAll("text")
.data(words)
.enter().append("text")
.transition()
.duration(function(d) { return d.time} )
.attr('opacity', 1)
.style("font-size", function(d) { return d.size + "px"; })
.style("font-family", "Impact")
.style("fill", function(d, i) { return fill(i); })
.attr("text-anchor", "middle")
.attr("transform", function(d) {
return "rotate(" + d.rotate + ")";
})
.attr("transform", function(d) {
return "translate(" + [d.x, d.y] + ")rotate(" + d.rotate + ")";
})
.text(function(d) { return d.text; });
}
On the page you link to, he's using a :hover pseudo-class.
<style>
text:hover { opacity: .7 !important; }
</style>
Updated code here.

How to force y position of one branch in d3 sankey plugin?

I would like to force one branch of sankey diagram to be on top.
Instead of diagram like this:
would like to generate diagram where nodes 1, 2, 7, 15, 10 and 14 are always on top:
Link to fiddle with current code: http://jsfiddle.net/w5jfp9t0/1/
var margin = {top: 1, right: 1, bottom: 6, left: 1};
var width = 1052 - margin.left - margin.right;
var height = 500 - margin.top - margin.bottom;
var formatNumber = d3.format(",.0f"),
format = function(d) { return formatNumber(d); },
color = d3.scale.category20();
var svg = d3.select("#chart_sankey").append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
var sankey = d3.sankey()
.nodeWidth(35)
.nodePadding(10)
.size([width, height]);
var path = sankey.link();
raw = '{"nodes":[{"name":"Node 1"},{"name":"Node 2"},{"name":"Node 3"},{"name":"Node 4"},{"name":"Node 5"},{"name":"Node 6"},{"name":"Node 7"},{"name":"Node 8"},{"name":"Node 9"},{"name":"Node 10"},{"name":"Node 11"},{"name":"Node 12"},{"name":"Node 13"},{"name":"Node 14"},{"name":"Node 15"}],"links":[{"source":9,"target":13,"value":25},{"source":14,"target":9,"value":37},{"source":14,"target":11,"value":16},{"source":14,"target":12,"value":8},{"source":14,"target":10,"value":68},{"source":6,"target":14,"value":154},{"source":6,"target":8,"value":40},{"source":1,"target":6,"value":345},{"source":1,"target":7,"value":66},{"source":1,"target":3,"value":17},{"source":1,"target":4,"value":25},{"source":1,"target":5,"value":117},{"source":0,"target":1,"value":692},{"source":0,"target":2,"value":19}]}';
data = JSON.parse(raw);
sankey.nodes(data.nodes)
.links(data.links)
.layout(32);
var link = svg.append("g")
.selectAll(".link")
.data(data.links)
.enter().append("path")
.attr("class", "link")
.attr("d", path)
.style("stroke-width", function(d) { return Math.max(1, d.dy); })
.sort(function(a, b) { return b.dy - a.dy; });
var nodes = data.nodes;
var node = svg.append("g").selectAll(".node")
.data(nodes)
.enter().append("g")
.attr("class", "node")
.attr("transform", function(d) {
return "translate(" + d.x + "," + d.y + ")"; })
.call(d3.behavior.drag()
.origin(function(d) { return d; })
.on("dragstart", function() { this.parentNode.appendChild(this); })
.on("drag", dragmove));
sankey.relayout();
node.filter(function(d) { return d.value != 0; }) // append text only if node value is not zero
.append("rect")
.attr("height", function(d) { return d.dy; })
.attr("width", sankey.nodeWidth())
.style("fill", function(d) { return d.color = color(d.name.replace(/ .*/, "")); })
.style("stroke", function(d) { return d3.rgb(d.color).darker(2); })
.append("title")
.text(function(d) { return d.name + "\n" + format(d.value); });
node.filter(function(d) { return d.value != 0; }) // append text only if node value is not zero
.append("text")
.attr("x", -6)
.attr("y", function(d) { return d.dy / 2; })
.attr("dy", ".35em")
.attr("text-anchor", "end")
.attr("transform", null)
.text(function(d) { return d.name; })
.filter(function(d) { return d.x == 0; }) // at first column append text after column
.attr("x", 6 + sankey.nodeWidth())
.attr("text-anchor", "start");
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);
}
What do I need to change to accomplish this?
Note
To be honest, I never used that plugin. I don't see an option to get the desired behaviour directly - thus I looked at the source of sankey.js to make the adjustments. Below I show how I'd modify - you might want to do it more thoroughly :)
Idea
Looking at the code of sankey.js, you see that the nodes are placed (y-direction) using the center function:
function center(node) {
return node.y + node.dy / 2;
}
As I don't see a parameter to change that behaviour, you can change it to:
function center(node) {
return 0;
}
If you then also revert the sorting order:
function ascendingDepth(a, b) {
return b.y - a.y;
}
you get the following picture:

Force + Drag + Zoom : freeze after few seconds

First, I'm quite new in D3.
I'm trying to implement different behaviors in a single D3 graph, using these examples :
Drag + Zoom
Force-directed Graph
But my graph freezes after few seconds and I don't understand why...
Here is my code : http://jsfiddle.net/blt909/aVhd8/20/ [WORKING FINE VERSION]
var margin = {top: -5, right: -5, bottom: -5, left: -5};
var width = 500 - margin.left - margin.right,
height = 400- margin.top - margin.bottom;
var color = d3.scale.category20();
var force = d3.layout.force()
.charge(-200)
.linkDistance(50)
.size([width + margin.left + margin.right, height + margin.top + margin.bottom]);
var zoom = d3.behavior.zoom()
.scaleExtent([1, 10])
.on("zoom", zoomed);
var drag = d3.behavior.drag()
.origin(function(d) { return d; })
.on("dragstart", dragstarted)
.on("drag", dragged)
.on("dragend", dragended);
var svg = d3.select("#map").append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.right + ")")
.call(zoom);
var rect = svg.append("rect")
.attr("width", width)
.attr("height", height)
.style("fill", "none")
.style("pointer-events", "all");
var container = svg.append("g");
force
.nodes(graph.nodes)
.links(graph.links)
.start();
var tooltip = d3.select("body")
.append("foreignObject")
.append("xhtml:div")
.attr("id", "tooltip")
.style("position", "absolute")
.style("z-index", "10")
.style("color", "#eeeeee")
.style("visibility", "hidden")
.text("");
var link = container.append("g")
.attr("class", "links")
.selectAll(".link")
.data(graph.links)
.enter().append("line")
.attr("class", "link")
.style("stroke-width", function(d) { return Math.sqrt(d.value); });
var node = container.append("g")
.attr("class", "nodes")
.selectAll(".node")
.data(graph.nodes)
.enter().append("g")
.attr("class", "node")
.attr("cx", function(d) { return d.x; })
.attr("cy", function(d) { return d.y; })
.call(drag);
node.append("circle")
.attr("r", function(d) { return d.weight * 2+ 12; })
.style("fill", function(d) { return color(1/d.rating); });
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 + ")"; });
});
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];
}
node.on("mouseover", function(d){
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;
});
d3.select(this).classed("node-active", true);
d3.select(this).select("circle").transition()
.duration(750)
.attr("r", (d.weight * 2+ 12)*1.5);
})
.on("mouseout", function(d){
node.classed("node-active", false);
link.classed("link-active", false);
d3.select(this).select("circle").transition()
.duration(750)
.attr("r", d.weight * 2+ 12);
});
function dottype(d) {
d.x = +d.x;
d.y = +d.y;
return d;
}
function zoomed() {
container.attr("transform", "translate(" + d3.event.translate + ")scale(" + d3.event.scale + ")");
}
function dragstarted(d) {
d3.event.sourceEvent.stopPropagation();
d3.select(this).classed("dragging", true);
//ADDING force.start(); HERE SOLVES THE ISSUE
force.start();
}
function dragged(d) {
d3.select(this).attr("cx", d.x = d3.event.x).attr("cy", d.y = d3.event.y);
}
function dragended(d) {
d3.select(this).classed("dragging", false);
}
Thanks for your help
Putting force.start(); inside dragstarted function stops freezing.
function dragstarted(d) {
d3.event.sourceEvent.stopPropagation();
d3.select(this).classed("dragging", true);
force.start();
};
Here is fiddle

Categories