Skip to content

Commit e2a64d6

Browse files
committed
Animated space junk visualization.
1 parent 9638cb7 commit e2a64d6

File tree

378 files changed

+118330
-0
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

378 files changed

+118330
-0
lines changed

app.css

+46
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
/*
2+
Set the background to 'black', because it represents space.
3+
*/
4+
body {
5+
background: black;
6+
}
7+
8+
.title-text {
9+
fill: white;
10+
font-size: 34px;
11+
text-anchor: middle;
12+
}
13+
14+
/*
15+
Style the visual the represents the earth.
16+
*/
17+
.earth {
18+
fill: #01499D;
19+
}
20+
21+
/*
22+
Color code the different sizes of space junk.
23+
*/
24+
25+
.junk.SMALL {
26+
fill: yellow;
27+
}
28+
29+
.junk.MEDIUM {
30+
fill: orange;
31+
}
32+
33+
.junk.LARGE {
34+
fill: red;
35+
}
36+
37+
.hover-title {
38+
font-weight: bold;
39+
font-size: 20px;
40+
}
41+
42+
.hover-text {
43+
fill: white;
44+
text-anchor: middle;
45+
font-size: 16px;
46+
}

app.js

+140
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
//
2+
// Now using a D3 data join to add our data to the visualization.
3+
//
4+
5+
function pointOnCircle (radius, angleDegrees) { // Helper function to create a point on the perimeter of a circle.
6+
var angleRadians = (angleDegrees * Math.PI) / 180;
7+
return {
8+
x: radius * Math.cos(angleRadians),
9+
y: radius * Math.sin(angleRadians)
10+
};
11+
};
12+
13+
window.onload = function () {
14+
15+
var width = window.innerWidth; // Dimensions for our visualization are derived from the size of the browser window.
16+
var height = window.innerHeight;
17+
18+
var earthRadius = 6371; // This is the real radius of the earth!
19+
var earthTranslation = "translate(" + (width/2) + ", " + (height/2) + ")"; // Setup a translation to position the earth.
20+
var maxDistanceFromEarth = 6000; // Let's put a limit on what we can display.
21+
22+
d3.json("data/us-space-junk.json")
23+
.then(function (spaceJunkData) {
24+
25+
var filteredData = spaceJunkData.filter(spaceJunkRecord => spaceJunkRecord.PERIGEE <= maxDistanceFromEarth); // Filter out data beyond our limit.
26+
27+
filteredData.forEach(function (spaceJunkRecord, rowIndex) {
28+
spaceJunkRecord.id = rowIndex;
29+
spaceJunkRecord.orbitAngle = Math.random() * 360;
30+
});
31+
32+
var maxOrbitRadius = d3.max(filteredData.map(spaceJunkRecord => earthRadius + spaceJunkRecord.PERIGEE)); // Determine the maximum orbit distance from the earth.
33+
34+
var radiusScale = d3.scaleLinear() // Create a scale for the radius.
35+
.domain([0, maxOrbitRadius])
36+
.range([0, Math.min(height/2, width/2)]);
37+
38+
function computeSpaceJunkPosition (spaceJunkRecord, distance) { // Function to compute the position of space junk within the visualization, we need to reuse this now.
39+
var orbitRadius = radiusScale(earthRadius + distance); // The distance from the center of the earth that the space junk is orbiting.
40+
var point = pointOnCircle(orbitRadius, spaceJunkRecord.orbitAngle); // Choose a random position in orbit that is relative to the earth.
41+
return {
42+
x: (width/2) + point.x, // Translate the space junk coordinates into visualization-relative coordinates.,
43+
y: (height/2) + point.y
44+
};
45+
};
46+
47+
function spaceJunkTranslation (spaceJunkRecord, orbitalDistance) {
48+
var pos = computeSpaceJunkPosition(spaceJunkRecord, orbitalDistance);
49+
return "translate(" + pos.x + ", " + pos.y + ")" ;
50+
};
51+
52+
function spaceJunkTranslationStart (spaceJunkRecord) {
53+
return spaceJunkTranslation(spaceJunkRecord, 0);
54+
};
55+
56+
function spaceJunkTranslationEnd (spaceJunkRecord) {
57+
return spaceJunkTranslation(spaceJunkRecord, spaceJunkRecord.PERIGEE);
58+
};
59+
60+
function addText (className, text, pos, offset) { // Helper function to add some hover text.
61+
svgElement.append("text") // Append the hover text to the end of the SVG so it is rendered over the top of everything else.
62+
.attr("class", className) // Id the text so we can remove it later.
63+
.attr("x", pos.x)
64+
.attr("y", pos.y + offset) // Offset the Y position slightly so the text is below the space junk.
65+
.text(text);
66+
};
67+
68+
function hover (spaceJunkRecord, index) { // Function called when a space junk is hovered.
69+
70+
d3.select(this)
71+
.select("circle")
72+
.attr("r", 6); // Make the hovered space junk larger.
73+
74+
var pos = computeSpaceJunkPosition(spaceJunkRecord, spaceJunkRecord.PERIGEE);
75+
addText("hover-text hover-title", spaceJunkRecord.OBJECT_NAME, pos, 50);
76+
addText("hover-text", "Size: " + spaceJunkRecord.RCS_SIZE, pos, 70);
77+
addText("hover-text", "Launched: " + spaceJunkRecord.LAUNCH, pos, 85);
78+
};
79+
80+
function unhover (spaceJunkRecord, index) { // Function called when a space junk is unhovered.
81+
82+
d3.select(this)
83+
.select("circle")
84+
.attr("r", 2); // Revert the hovered space junk to normal size.
85+
86+
d3.selectAll(".hover-text")
87+
.remove(); // Remove all hover text.
88+
};
89+
90+
var svgElement = d3.select("svg.chart") // Select the root SVG element for our visualization.
91+
.attr("width", width) // Set the width and height of the elemnt.
92+
.attr("height", height);
93+
94+
var theEarth = svgElement.append("circle") // Add a circle to our visualization to represent the 'earth'.
95+
theEarth.attr("class", "earth") // Set the CSS class for the element to so that we can style our 'earth'.
96+
.attr("transform", earthTranslation) // Position the circle in the middle of the visualization.
97+
.attr("r", radiusScale(earthRadius)); // Set the radius the earth.
98+
99+
var currentYear = 1957; // Current year in the animation.
100+
addText("title-text", currentYear.toString(), { x: width/2, y: 30 }, 0);
101+
102+
// Animate the current year forward in time.
103+
setInterval(function () {
104+
++currentYear;
105+
106+
svgElement.select(".title-text") // Update the title text to to the current year.
107+
.text(currentYear.toString());
108+
109+
var currentData = filteredData.filter(row => moment(row.LAUNCH, "DD/MM/YYYY").year() <= currentYear); // Filter data up until the 'current year'.
110+
111+
const spaceJunk = svgElement.selectAll("g") // Select all g elements.
112+
.data(currentData, function (spaceJunkRecord) { return spaceJunkRecord.id; }); // 'Join' our data to the selection.
113+
spaceJunk.enter() // Specify what happens for each incoming data point.
114+
.append("g") // Append a group element for each data point.
115+
.on("mouseover", hover)
116+
.on("mouseout", unhover)
117+
.attr("class", function (spaceJunkRecord) { // Set CSS clas so we can style our space junk.
118+
return "junk " + spaceJunkRecord.RCS_SIZE;
119+
})
120+
.attr("transform", spaceJunkTranslationStart);
121+
122+
spaceJunk.transition() // Animate the space junk to its destination position.
123+
.duration(1000)
124+
.attr("transform", spaceJunkTranslationEnd)
125+
.ease(d3.easeBackOut);
126+
127+
spaceJunk.append("circle") // Add a circle to represent the space junk.
128+
.attr("r", 5) // Hard-coded circle radius.
129+
.transition()
130+
.attr("r", 2);
131+
132+
}, 1000); // Go forward one year ever second.
133+
134+
135+
})
136+
.catch(function (err) {
137+
console.error("Failed to load data file.");
138+
console.error(err);
139+
});
140+
};

bower.json

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
{
2+
"name": "listing-1",
3+
"homepage": "https://github.com/Data-Wrangling-with-JavaScript/chapter-13",
4+
"authors": [
5+
"Ashley Davis <ashley@codecapers.com.au>"
6+
],
7+
"description": "",
8+
"main": "",
9+
"license": "MIT",
10+
"ignore": [
11+
"**/.*",
12+
"node_modules",
13+
"bower_components",
14+
"test",
15+
"tests"
16+
],
17+
"dependencies": {
18+
"d3": "^5.0.0",
19+
"moment": "^2.22.1"
20+
}
21+
}

bower_components/d3/.bower.json

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
{
2+
"name": "d3",
3+
"description": "A JavaScript visualization library for HTML and SVG.",
4+
"main": "d3.js",
5+
"license": "BSD-3-Clause",
6+
"ignore": [],
7+
"homepage": "https://github.com/mbostock-bower/d3-bower",
8+
"version": "5.0.0",
9+
"_release": "5.0.0",
10+
"_resolution": {
11+
"type": "version",
12+
"tag": "v5.0.0",
13+
"commit": "d39a7a48e01f0a97966dd86e3e4d71df52cf7d25"
14+
},
15+
"_source": "https://github.com/mbostock-bower/d3-bower.git",
16+
"_target": "^5.0.0",
17+
"_originalSource": "d3",
18+
"_direct": true
19+
}

bower_components/d3/LICENSE

+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
Copyright 2010-2017 Mike Bostock
2+
All rights reserved.
3+
4+
Redistribution and use in source and binary forms, with or without modification,
5+
are permitted provided that the following conditions are met:
6+
7+
* Redistributions of source code must retain the above copyright notice, this
8+
list of conditions and the following disclaimer.
9+
10+
* Redistributions in binary form must reproduce the above copyright notice,
11+
this list of conditions and the following disclaimer in the documentation
12+
and/or other materials provided with the distribution.
13+
14+
* Neither the name of the author nor the names of contributors may be used to
15+
endorse or promote products derived from this software without specific prior
16+
written permission.
17+
18+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
19+
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20+
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
22+
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23+
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24+
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
25+
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26+
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27+
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

bower_components/d3/README.md

+57
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
# D3: Data-Driven Documents
2+
3+
<a href="https://d3js.org"><img src="https://d3js.org/logo.svg" align="left" hspace="10" vspace="6"></a>
4+
5+
**D3** (or **D3.js**) is a JavaScript library for visualizing data using web standards. D3 helps you bring data to life using SVG, Canvas and HTML. D3 combines powerful visualization and interaction techniques with a data-driven approach to DOM manipulation, giving you the full capabilities of modern browsers and the freedom to design the right visual interface for your data.
6+
7+
## Resources
8+
9+
* [API Reference](https://github.com/d3/d3/blob/master/API.md)
10+
* [Release Notes](https://github.com/d3/d3/releases)
11+
* [Gallery](https://github.com/d3/d3/wiki/Gallery)
12+
* [Examples](https://bl.ocks.org/mbostock)
13+
* [Wiki](https://github.com/d3/d3/wiki)
14+
15+
## Installing
16+
17+
If you use npm, `npm install d3`. Otherwise, download the [latest release](https://github.com/d3/d3/releases/latest). The released bundle supports anonymous AMD, CommonJS, and vanilla environments. You can load directly from [d3js.org](https://d3js.org), [CDNJS](https://cdnjs.com/libraries/d3), or [unpkg](https://unpkg.com/d3/). For example:
18+
19+
```html
20+
<script src="https://d3js.org/d3.v5.js"></script>
21+
```
22+
23+
For the minified version:
24+
25+
```html
26+
<script src="https://d3js.org/d3.v5.min.js"></script>
27+
```
28+
29+
You can also use the standalone D3 microlibraries. For example, [d3-selection](https://github.com/d3/d3-selection):
30+
31+
```html
32+
<script src="https://d3js.org/d3-selection.v1.js"></script>
33+
```
34+
35+
D3 is written using [ES2015 modules](http://www.2ality.com/2014/09/es6-modules-final.html). Create a [custom bundle using Rollup](https://bl.ocks.org/mbostock/bb09af4c39c79cffcde4), Webpack, or your preferred bundler. To import D3 into an ES2015 application, either import specific symbols from specific D3 modules:
36+
37+
```js
38+
import {scaleLinear} from "d3-scale";
39+
```
40+
41+
Or import everything into a namespace (here, `d3`):
42+
43+
```js
44+
import * as d3 from "d3";
45+
```
46+
47+
In Node:
48+
49+
```js
50+
var d3 = require("d3");
51+
```
52+
53+
You can also require individual modules and combine them into a `d3` object using [Object.assign](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign):
54+
55+
```js
56+
var d3 = Object.assign({}, require("d3-format"), require("d3-geo"), require("d3-geo-projection"));
57+
```

bower_components/d3/bower.json

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"name": "d3",
3+
"description": "A JavaScript visualization library for HTML and SVG.",
4+
"main": "d3.js",
5+
"license": "BSD-3-Clause",
6+
"ignore": []
7+
}

0 commit comments

Comments
 (0)