A rocket progress indicator made using svg + canvas.
Last active
January 9, 2020 20:46
-
-
Save philipcdavis/7526aab13bc2cb08ec4ac7384087546e to your computer and use it in GitHub Desktop.
Rocket Progress Indicator
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html> | |
<head> | |
<meta charset="utf-8"> | |
<meta name="viewport" content="width=device-width, initial-scale=1"> | |
<title>Quest</title> | |
<link rel="stylesheet" href="style.css"/> | |
<link rel="stylesheet" href="https://unpkg.com/tachyons@4.7.0/css/tachyons.min.css"/> | |
</head> | |
<body class="sans-serif dark-red-bg"> | |
<div class="m0"> | |
<div class="mw8"> | |
<div class="fl w100 w-third"> | |
<div id="canvas01" class="spaceship-container"> | |
<svg id="rocket-flames" width="11px" height="38px" viewBox="0 0 11 38"> | |
<g id="flames"> | |
<polygon id="rocket-flame-light" fill="#9D0000" opacity="0.642266757" points="5.5 0.71875 11 38 0 38"></polygon> | |
<polygon id="rocket-flame-dark" class="pulse pulse-delay" fill="#FF2020" opacity="0.813462409" points="5.5 0.71875 9 38 2 38"></polygon> | |
</g> | |
</svg> | |
<svg id="rocket-container" width="11px" height="55px" viewBox="0 0 11 55"> | |
<g id="rocket"> | |
<polygon class="flame-move" id="Path-2" fill="#FFB914" points="4.33113325 30.9988397 5.52162438 54.7288392 6.61158311 30.9988397"></polygon> | |
<polygon id="Rectangle-8" fill="#86240C" points="3 29 8 29 7.66344736 31 3.38228707 31"></polygon> | |
<path d="M3.29538202,24.0004897 C3.29538202,24.0004897 0.724655534,25.40952 0.222970933,26.512686 C-0.278713667,27.6158519 0.222970933,30.756486 0.222970933,30.756486 C0.222970933,30.756486 1.07942895,29.7177413 1.64769101,29.2611171 C2.21595307,28.8044929 3.29538202,28.287665 3.29538202,28.287665 L3.29538202,24.0004897 Z" id="Path-2-Copy-3" fill="#546B7C"></path> | |
<path d="M10.9475559,24.0004897 C10.9475559,24.0004897 8.37682945,25.40952 7.87514485,26.512686 C7.37346025,27.6158519 7.87514485,30.756486 7.87514485,30.756486 C7.87514485,30.756486 8.73160286,29.7177413 9.29986492,29.2611171 C9.86812698,28.8044929 10.9475559,28.287665 10.9475559,28.287665 L10.9475559,24.0004897 Z" id="Path-2-Copy-4" fill="#546B7C" transform="translate(9.299865, 27.378488) scale(-1, 1) translate(-9.299865, -27.378488) "></path> | |
<path d="M3.04746713,29.546875 C2.3947312,26.5484437 1.98939014,22.2246713 1.98939014,17.0412693 C1.98939014,6.84589693 5.49202694,0.232183562 5.49202694,0.232183562 C5.49202694,0.232183562 8.99466373,6.84589693 8.99466373,17.0412693 C8.99466373,22.2246713 8.58932267,26.5484437 7.93658674,29.546875 L3.04746713,29.546875 Z" id="Combined-Shape-Copy" fill="#FFFFFF"></path> | |
</g> | |
</svg> | |
</div> | |
</div> | |
<div class="fl w-100 w-two-thirds dt"> | |
<div class="dtc v-mid white" style="height: 496px;"> | |
<div class="menlo hot-red hot-red-text-glow b">Rocket Progress Bar</div> | |
<p class="menlo white o-80">Click the button below to generate random data values</p> | |
<button class="btn btn-red b pointer pull-right mt1" onclick="spaceship()">To Infinity</button> | |
</div> | |
</div> | |
</div> | |
</div> | |
<script src="https://d3js.org/d3.v4.min.js"></script> | |
<script src="spaceship.js"></script> | |
<script src="stars.js"></script> | |
<script> | |
var height = 400; | |
var width = 200; | |
var padding = {top: 40, bottom: 61, right: 20, left: 20 }; | |
var selector = "#canvas"; | |
generateStars({ | |
height: height * 2, | |
width: width * 2, | |
padding: padding, | |
selector: selector + "01" | |
}); | |
var spaceship = generateSpaceship({ | |
height: height, | |
width: width, | |
padding: padding, | |
selector: selector + "01" | |
}) | |
</script> | |
</body> | |
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
function generateSpaceship(config) { | |
var data = { | |
current: 0, | |
total: 20000 | |
}; | |
var height = config.height; | |
var width = config.width; | |
var rocketHeight = 55; | |
var rocketWidth = 11; | |
var padding = config.padding; | |
var heightPadded = height + padding.top + padding.bottom; | |
var widthPadded = width + padding.left + padding.right; | |
var yScale = d3.scaleLinear() | |
.domain([0, data.total]) | |
.range([0, height]) | |
var axisScale = d3.scaleLinear() | |
.domain([0, data.total]) | |
.range([height, 0]) | |
var flameWidthScale = d3.scaleLinear() | |
.domain([0, data.total]) | |
.range([1, 4]) | |
var labelColorScale = d3.scaleLinear().domain([0,4]).range([d3.rgb("#FF2525"), d3.rgb('#FFFFFF')]); | |
var rocket = d3.select(config.selector + " #rocket-container") | |
.attr("style", "position: absolute; left: calc(50% - 5px); bottom: 0;"); | |
var rocketFlame = d3.select(config.selector + " #rocket-flames") | |
.attr("style", "position: absolute; left: calc(50% - 5px); bottom: 0; "); | |
var numberAxis = d3.axisRight(axisScale) | |
.ticks(5, "s"); | |
var circleAxis = d3.axisRight(axisScale) | |
.ticks(60) | |
.tickFormat(""); | |
d3.select(config.selector) | |
.attr("style", "width:" + widthPadded + "px; height: "+ heightPadded +"px;") | |
d3.select(config.selector) | |
.append("svg") | |
.attr("class", "axisSvg") | |
.attr("width", width + padding.left + padding.right) | |
.attr("height", height + padding.top + padding.bottom) | |
.append("g") | |
.attr("transform", "translate("+ padding.left +","+ padding.top +")") | |
.attr("class", "number-axis") | |
.call(numberAxis) | |
.append("g") | |
.attr("class", "circle-axis") | |
.call(circleAxis); | |
var numberTicks = d3.selectAll(".number-axis .tick"); | |
numberTicks | |
.each(function(d, i) { | |
d3.select(this).select("text") | |
.attr("fill", labelColorScale(i)); | |
}) | |
var circleTicks = d3.selectAll(config.selector + " .circle-axis .tick"); | |
circleTicks.each(function() { | |
d3.select(this) | |
.append("circle") | |
.attr("r", 3) | |
.attr("fill", "rgba(142,52,52,0.4)"); | |
}); | |
d3.selectAll("line").remove(); | |
d3.selectAll(".domain").remove(); | |
function updateRocket() { | |
data.current = Math.random() * 20000; | |
var flameCurrent = yScale(data.current) + 50; | |
circleTicks.selectAll(config.selector + " circle") | |
.transition() | |
.duration(1000) | |
.attr("fill", function(d) { | |
return d <= data.current ? "#FF2020" : "rgba(142,52,52,0.4)" | |
}); | |
var flameContainer = rocketFlame.transition() | |
.duration(1000) | |
.attr("height", flameCurrent) | |
.attr("style", "position: absolute; left: calc(50% - 5px); bottom: 0; transform: scaleX(" + flameWidthScale(data.current) + ") ") | |
.attr("viewBox", "0 0 11 " + flameCurrent); | |
flameContainer.select(config.selector + " #rocket-flame-light") | |
.attr("points", "5.5 0.71875 11 " + flameCurrent + " 0 " + flameCurrent + ""); | |
flameContainer.select(config.selector + " #rocket-flame-dark") | |
.attr("points", "5.5 0.71875 9 " + flameCurrent + " 2 " + flameCurrent + ""); | |
rocket.transition() | |
.duration(1000) | |
.attr("style", "position: absolute; left: calc(50% - 5px); bottom: "+ yScale(data.current)+"; "); | |
} | |
setTimeout(function() { | |
updateRocket() | |
}, 500) | |
return updateRocket; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
function generateStars(config) { | |
var height = (config.height + config.padding.top + config.padding.bottom) * 2; | |
var width = (config.width + config.padding.left + config.padding.right) * 2; | |
var x = d3.scaleLinear() | |
.domain([0, 100]) | |
.range([0, config.width]); | |
var y = d3.scaleLinear() | |
.domain([0, 100]) | |
.range([0, config.height]); | |
var colors = ["#9E5555", "#FF7F7F", "#FFDADA"]; | |
var colorScale = d3.scaleQuantize().domain([0,1]).range(colors); | |
var starData = d3.range(80).map(function() { | |
var random = Math.random() | |
var dataObject = { | |
x: Math.random() * 100, | |
y: Math.random() * 100, | |
yv: random < 0.90 ? random / 10 : random, | |
size: (random * 3), | |
color: colorScale(random) | |
}; | |
return dataObject; | |
}); | |
var canvas = d3.select(config.selector).insert("canvas", ":first-child") | |
.attr("width", config.width) | |
.attr("height", config.height) | |
.attr("id", "star-canvas"); | |
// node returns first dom element in a selection | |
var context = canvas.node().getContext("2d"); | |
d3.timer(function() { | |
// context.clearRect(0, 0, width, height); | |
context.fillStyle = 'rgba(0,0,0,0.5)'; | |
context.fillRect(0, 0, config.width, config.height); | |
starData.forEach(function(d) { | |
d.y += d.yv; | |
// Recycle old circles | |
if(d.y > (100 + d.size) ) { | |
d.y = 0 - d.size; | |
d.x = Math.random() * 100; | |
} | |
context.fillStyle = d.color; | |
context.beginPath(); | |
context.arc(x(d.x), y(d.y), d.size, 0, 2 * Math.PI); | |
context.fill(); | |
}); | |
}); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
.hot-red { | |
color: #FF2020; | |
} | |
.hot-red-text-glow { | |
text-shadow: 0 0 3px rgba(255,32,32, 0.5); | |
} | |
.dark-red-bg { | |
background-color: #201818; | |
} | |
.red-border { | |
border: 1px solid #FF2020; | |
} | |
.ddc { | |
font-family: "DDC", sans-serif; | |
} | |
.menlo { | |
font-family: Menlo, monospace; | |
} | |
.btn { | |
border-radius: 20px; | |
font-size: 14px; | |
padding: 10px 25px; | |
text-decoration: none; | |
outline: none; | |
} | |
.btn-red { | |
background-color: #FF2020; | |
color: white; | |
box-shadow: 0 0 7px #FF2020; | |
border: none; | |
} | |
.bb-red { | |
border-bottom: 1px solid #FF2020; | |
} | |
.bt-red { | |
border-top: 1px solid #FF2020; | |
} | |
.spaceship-container { | |
background-image: linear-gradient(0deg, #630202 -40%, rgba(68,42,42,0.1) 100%); | |
position: relative; | |
border-bottom: 1px solid #FF2020; | |
border-right: 1px solid #FF2020; | |
} | |
@keyframes pulse { | |
0% { | |
opacity: 0.3; | |
} | |
100% { | |
opacity: 0.5; | |
} | |
} | |
@keyframes twitch { | |
0% { | |
transform: translateY(-20px); | |
} | |
100% { | |
transform: translateY(0); | |
} | |
} | |
canvas { | |
width: 100%; | |
height: 100%; | |
position: absolute; | |
z-index: -1; | |
} | |
.pulse { | |
animation-duration: 1s; | |
animation-name: pulse; | |
animation-iteration-count: infinite; | |
animation-direction: alternate; | |
} | |
.flame-move { | |
animation-duration: 1s; | |
animation-name: twitch; | |
animation-iteration-count: infinite; | |
animation-direction: alternate; | |
} | |
.tick text { | |
font-weight: bold; | |
font-family: "Menlo", monospace; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment