forked from curran's block: Tilted Labels
Hover over the bars to reveal the number of satellites for that purpose for the selected country.
Hover over the legend keys to highlight the selected purpose in the country bar chart.
forked from apratt2003's block: [unlisted] Satellites by Countries Interactive
xxxxxxxxxx
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<script src="https://d3js.org/d3.v4.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3-legend/2.24.0/d3-legend.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3-tip/0.7.1/d3-tip.min.js"></script>
<title>Top Internet Countries Visualization</title>
<style>
body {
margin: 0px;
}
.domain {
display: none;
}
.tick line {
stroke: #C0C0BB;
}
.tick text {
fill: #8E8883;
font-size: 8pt;
font-family: sans-serif;
}
.axis-label {
fill: #635F5D;
font-size: 20pt;
font-family: sans-serif;
}
.color-legend text {
font-size: 8pt;
font-family: 'Open Sans', sans-serif;
}
.d3-tip {
font-family: 'Open Sans', sans-serif;
font-size: 19pt;
line-height: 1;
padding: 7px;
background: black;
color: lightgray;
border-radius: 20px;
}
</style>
</head>
<body>
<svg width="960" height="500"></svg>
<script>
const xValue = d => d.Country;
const xLabel = 'Country';
const yValue = "Number";
const yLabel = 'Number of Satellites';
const colorColumn = 'Purpose';
const layerColumn = colorColumn;
var numCountries = 10;
var hoveredColorValue;
var hoveredStrokeColor = "black";
const margin = { left: 99, right: 70, top: 20, bottom: 105 };
const svg = d3.select('svg');
const width = svg.attr('width');
const height = svg.attr('height');
const innerWidth = width - margin.left - margin.right;
const innerHeight = height - margin.top - margin.bottom;
const g = svg.append('g')
.attr('transform', `translate(${margin.left},${margin.top})`);
const xAxisG = g.append('g').attr('transform', `translate(0, ${innerHeight})`);
const yAxisG = g.append('g');
var baseBarLayer = g.append("g")
.attr("id", "baseBarLayer");
var overlayRect = g.append("g")
.append("rect")
.attr("width", innerWidth)
.attr("height", innerHeight)
.style("pointer-events", "none");
var foregroundBarLayer = g.append("g")
.attr("id", "foregroundBarLayer");
xAxisG.append('text')
.attr('class', 'axis-label')
.attr('x', innerWidth / 2)
.attr('y', 76)
.text(xLabel);
yAxisG.append('text')
.attr('class', 'axis-label')
.attr('x', -innerHeight / 2 - 3)
.attr('y', -57)
.attr('transform', `rotate(-90)`)
.style('text-anchor', 'middle')
.text(yLabel);
var colorLegendG = g.append("g")
.attr("class", "color-legend")
.attr("transform", "translate(620,14)");
const xScale = d3.scaleBand()
.paddingInner(0.1)
.paddingOuter(0.2);
const yScale = d3.scaleLinear();
const xAxis = d3.axisBottom()
.scale(xScale)
.tickSize(-innerHeight);
const yTicks = 10;
const yAxis = d3.axisLeft()
.scale(yScale)
.ticks(yTicks)
.tickPadding(15)
.tickSize(-innerWidth);
const colorScale = d3.scaleOrdinal(d3.schemeCategory20);
var colorLegend = d3.legendColor()
.scale(colorScale)
.shapePadding(3)
.shapeWidth(15)
.shapeHeight(15)
.labelOffset(5)
.ascending(true)
.title("Satellite Purposes");
var tip = d3.tip()
.attr("class", "d3-tip")
.offset([-10, 0])
.html(function(d) {
return [
(d[1]-d[0]),
" satellites"
].join("");
});
g.call(tip);
//Render function--------------------------------------------------------------------
function render(data){
colorScale.domain(data.map(function (d){
return d[colorColumn];
}));
var nested = d3.nest()
.key(xValue)
.key(function (d) {return d[layerColumn];})
.rollup(function (d) { return d[0].Number; })
.object(data);
var purposes = Object.keys(d3.nest()
.key(function (d) {return d[layerColumn];})
.object(data));
//console.log(purposes);
var transformed = Object.keys(nested)
.map(function (country) {
var row = {};
purposes.forEach(function (purpose){
if(nested[country][purpose]){
row[purpose] = nested[country][purpose];
} else {
// Fill in zero for missing values.
row[purpose] = 0;
}
});
row.Country = country;
return row;
});
//console.log(transformed);
var stack = d3.stack()
.keys(purposes)
//.order(d3.stackOrderNone)
//.offset(d3.stackOffsetNone);
var stacked = stack(transformed);
//console.log(stacked);
xScale
.domain(data.map(xValue)).range([0, innerWidth]);
yScale
.domain([0, d3.max(stacked.map(function (d){
return d3.max(d, function (d){ return d[1];});
}))])
.range([innerHeight, 0])
.nice(yTicks);
xAxisG.call(xAxis);
xAxisG.selectAll('.tick line').remove();
xAxisG.selectAll('.tick text')
.attr('transform', 'rotate(-45)')
.attr('text-anchor', 'end')
.attr('alignment-baseline', 'middle')
.attr('x', -5)
.attr('y', 6)
.attr('dy', 0);
yAxisG.call(yAxis);
renderBars(baseBarLayer, stacked);
if(hoveredColorValue){
troubleShoot("step 001 passes ");
setOverlayTransparency(0.6);
troubleShoot("step 002 passed ");
//Line 243 issue -------------------------------
var hoveredStack = stacked.filter(function (layer){
return layer.key === hoveredColorValue;
});
renderBars(foregroundBarLayer, hoveredStack);
} else {
troubleShoot("step 004 passed ");
setOverlayTransparency(0.0);
renderBars(foregroundBarLayer, []);
}
colorLegendG.call(colorLegend);
listenForHover(colorLegendG.selectAll("rect"), data);
//listenForHover(colorLegendG.selectAll("text"), data);
}
function setOverlayTransparency(alpha){
overlayRect
.transition().duration(00)
.attr("fill", "rgba(255, 255, 255, " + alpha + ")");
}
function renderBars(g, stacked){
var layers = g.selectAll('g').data(stacked);
layers.exit().remove();
layers = layers.enter().append('g')
.merge(layers)
.attr('fill', function(d) { return colorScale(d.key); });
var pancakes = layers.selectAll('rect')
.data(function (d) { return d; });
pancakes.exit().remove();
pancakes.enter().append("rect")
.merge(pancakes)
.attr('width', d => xScale.bandwidth())
.attr('x', function (d) { return xScale(xValue(d.data)); })
.attr('y', function (d) { return yScale(d[1]); })
.attr('height', function (d) { return yScale(d[0]) - yScale(d[1]); })
.on("mouseover", tip.show)
.on("mouseout", tip.hide);
}
function listenForHover(selection, data){
selection
.on("mouseover", function (d){
hoveredColorValue = d;
render(data);
})
.on("mouseout", function (d){
hoveredColorValue = null;
render(data);
})
.style("cursor", "pointer");
}
function print(data){
d3.select("body").append("pre")
.text(JSON.stringify(layers, null, 2));
}
//print()
function troubleShoot(target){
d3.select("body").append("text")
.attr("x", 50)
.attr("y", 50)
.attr("dy", ".35em")
.text(target);
}
//troubleShoot()
function type(d) {
d.Number = +d.Number;
return d;
}
d3.csv('satpurposeTop10.csv', type, render);
</script>
</body>
</html>
https://d3js.org/d3.v4.min.js
https://cdnjs.cloudflare.com/ajax/libs/d3-legend/2.24.0/d3-legend.min.js
https://cdnjs.cloudflare.com/ajax/libs/d3-tip/0.7.1/d3-tip.min.js