Skip to content

Instantly share code, notes, and snippets.

@sabrinamochi
Last active July 10, 2019 05:58
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save sabrinamochi/94823908d4f921482e3f5891b8d2212c to your computer and use it in GitHub Desktop.
Save sabrinamochi/94823908d4f921482e3f5891b8d2212c to your computer and use it in GitHub Desktop.
Planets

This is a visualisation of our solar system’s planets. It's based on the tutorial from DATAMAKE.

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<style>
.planet {
stroke-width: 4px;
}
#Sun {
fill: orange;
stroke: orange;
}
#Mercury {
stroke: #A17F5D;
fill: #A17F5D;
}
#Venus {
stroke: #E89624 fill:#E89624
}
#Earth {
stroke: #518E87;
fill: #518E87;
}
#Mars {
stroke: #964120;
fill: #964120
}
#Jupiter {
stroke: #F8800F;
fill: #F8800F;
}
#Saturn {
stroke: #E0B463;
fill: #E0B463;
}
#Uranus {
stroke: #D1E3F4;
fill: #D1E3F4;
}
#Neptune {
stroke: #515CA8;
fill: #515CA8;
}
body {
font-family: Arial, Helvetica, sans-serif;
font-size: 0.75rem;
background: radial-gradient(#091C33, #091426);
}
#title {
position: absolute;
top: 0;
left: 0;
width: 100%;
text-align: center;
color: #ddd;
}
a {
color: #ddd;
}
a:link {
text-decoration: none;
}
a:hover {
color: orange;
}
#pink {
border-bottom: 2px solid orange;
padding-bottom: 0.25rem;
}
.text {
fill: #ddd;
}
path.domain {
stroke: none;
}
.tick line {
stroke: #ddd;
stroke-width: 0.5;
shape-rendering: crispEdges;
stroke-dasharray: 1, 5;
}
.lines {
fill: none;
}
</style>
<title>planet</title>
<script type="text/javascript" src="https://d3js.org/d3.v5.min.js"></script>
<link rel="stylesheet" href="style.css">
</head>
<body>
<h1 id='title'>Measuring Our Planets'
<span id='pink'>
<a href="https://en.wikipedia.org/wiki/Solar_System#Distances_and_scales" target="_blank">Distance </a>
</span>
</h1>
<div id='vis'>
</div>
<script type="text/javascript">
function make(data) {
var margin = {
top: +500 * 0.3,
bottom: +500 * 0.4,
left: 50,
right: 50
}
var h = 500 - margin.top - margin.bottom;
var maxDist = d3.max(data, function(d) {
return +d.distance;
})
var mapScale = 1 / 10e4;
// full width of all planets
var chartWidth = maxDist * mapScale;
var screenWidth = 1000 - margin.left - margin.right;
var svg = d3.select('#vis')
.append('svg')
.attr('width', 1000)
.attr('height', 500)
.append('g')
.attr('class', 'chart')
.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');
var listenerRect = svg.append('rect')
.attr('x', 0)
.attr('y', -margin.top)
.attr('width', screenWidth)
.attr('height', 500)
.style('opacity', 0);
var rScale = d3.scaleLinear()
.domain([0, d3.max(data, function(d) {
return d.radius;
})])
.range([3, (h / 2) * 0.5]);
var xScale = d3.scaleLinear()
.domain([0, maxDist])
.range([0, chartWidth]);
var xAxis = d3.axisBottom(xScale)
.tickSizeOuter(0)
.tickPadding(10)
// tickValues require an array, which can be made by data.map
.tickValues(data.map(function(e) {
return e.distance;
}))
// since tickFormat receives the values from tickValues
// d became d.distance
.tickFormat(function(d, i) {
return data[i].planet + ' ' + d3.format(',')(d) + ' km';
})
// since we want the zoom base to be on top of all other elements,
// we insert xaxis
// listenerRect should be the last child element of svg
var xAxisDraw = svg.insert('g', ':first-child')
.attr('class', 'x_axis')
.call(xAxis);
// getBBox() 用于获取元素范围的最小矩形边际
// retrieve the height of text label
var labelHeight = xAxisDraw.select('text').node().getBBox().height;
xAxisDraw.attr('transform', 'translate(0,' + (labelHeight * data.length + h) + ')');
xAxisDraw.selectAll('text')
.attr('class', 'text')
.attr('y', function(d, i) {
return -(i * labelHeight + labelHeight)
})
//x、y 與 dx、dy 的差異: 前者為絕對位置,後者為相對位置
.attr('dx', '-0.15em')
.attr('dy', '1.15em')
.style('text-anchor', 'start');
xAxisDraw.selectAll('line')
.attr('y1', function(d, i) {
return -(i * labelHeight + labelHeight)
})
.attr('y2', function(d, i) {
return -(i * labelHeight + labelHeight +
h + labelHeight * (data.length - 1 - i))
});
var gPlanets = svg.insert('g', '.listenerRect')
.attr('class', 'planets-group')
var planets = gPlanets.selectAll('.planet')
.data(data)
.enter()
.append('circle')
.attr('class', 'planet')
.attr('id', function(d) {
return d.planet;
})
.attr('cx', function(d) {
return xScale(d.distance);
})
.attr('cy', 0)
.attr('r', function(d) {
return rScale(d.radius)
});
var minZoom = 1 / (chartWidth / 1000) * 0.75;
var zoom = d3.zoom()
.scaleExtent([minZoom, 20])
.on('zoom', zoomed);
listenerRect.call(zoom);
function zoomed() {
var transform = d3.event.transform;
// to prevent the planets moving to the right
// x should never be higher than 0
transform.x = Math.min(0, transform.x);
transform.y = 0;
var xScaleNew = transform.rescaleX(xScale);
// only zoom the cx and r
// so the stroke width wont be affected
planets.attr('cx', function(d) {
return xScaleNew(d.distance);
})
.attr('r', function(d) {
return rScale(d.radius) * transform.k;
});
// update the scale of xAxis and redraw it
xAxis.scale(xScaleNew);
xAxisDraw.call(xAxis);
xAxisDraw.selectAll('text')
.attr('y', function(d, i) {
return -(i * labelHeight + labelHeight)
})
xAxisDraw.selectAll('line')
.attr('y1', function(d, i) {
return -(i * labelHeight + labelHeight)
})
.attr('y2', function(d, i) {
return -(i * labelHeight + labelHeight +
h + labelHeight * (data.length - 1 - i))
});
}
// start by zooming in to a scale factor of 20 without panning
var initialTransform = d3.zoomIdentity.scale(20);
listenerRect.call(zoom.transform, initialTransform);
// after the initial zoom in...
// we zoom out a bit
progZoom()
function progZoom() {
var zoomOutTransform = d3.zoomIdentity
// there's no translation here.
.translate(0, 0)
.scale(minZoom);
listenerRect.transition()
.duration(5000)
.call(zoom.transform, zoomOutTransform)
.on('end', zoomToNormal);
function zoomToNormal() {
listenerRect.transition()
.duration(3000)
.ease(d3.easeQuadInOut)
.call(zoom.transform, d3.zoomIdentity)
}
}
}
var rowConverter = function(d) {
return {
index: +d.index,
planet: d.planet,
distance: +d.distance,
radius: +d.radius
};
};
d3.csv('https://raw.githubusercontent.com/sabrinamochi/planets_distance/master/planet.csv', rowConverter).then(function(data) {
console.table(data, ['planet', 'distance', 'radius']);
make(data);
});
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment