Skip to content

Instantly share code, notes, and snippets.

@sbrudz
Last active February 9, 2019 01:47
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 sbrudz/fa4db4706aa31f6db1bd7c1ddbc324d4 to your computer and use it in GitHub Desktop.
Save sbrudz/fa4db4706aa31f6db1bd7c1ddbc324d4 to your computer and use it in GitHub Desktop.
Continental Drift using Vega
license: gpl-3.0

A visualization of paleoshorelines and continental drift over time using data from the GPlates API and the Vega data visualization library.

<!DOCTYPE html>
<head>
<meta charset="utf-8">
<script src="https://cdn.jsdelivr.net/npm/vega@4"></script>
<script src="https://cdn.jsdelivr.net/npm/vega-embed@3"></script>
<link rel="stylesheet" type="text/css" href="spinner.css">
<style>
#loader {
top: 0;
left: 0;
position: fixed;
width: 100%;
height: 100%;
background-color: lightgray;
display: flex;
justify-content: center;
align-items: center;
}
#vis {
display: flex;
flex-wrap: wrap-reverse;
justify-content: space-around;
align-items: center;
}
#vis .vega-bindings {
height: 8em;
display: flex;
flex-direction: column;
justify-content: space-around;
align-content: center;
border: 1px solid darkgrey;
padding: 10px;
}
#vis .vega-bind {
display: flex;
align-items: center;
}
#vis .vega-bind-name {
display: inline-block;
width: 150px;
}
</style>
</head>
<body>
<div id="loader">
<div class="lds-spinner"><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div></div>
</div>
<div id="vis">
</div>
<script>
const loader = document.querySelector("#loader");
const spec = "plates.vg.json";
vegaEmbed('#vis', spec)
// result.view provides access to the Vega View API
.then(result => {
const timeSlider = document.querySelector("input[name='time']");
result.view.addSignalListener('model', (name, value) => {
const models = result.view.data("models");
const selectedModel = models.find(model => model.name === value);
if (selectedModel) {
timeSlider.max = selectedModel.max;
} else {
timeSlider.max = 200;
}
const clampedTime = Math.min(timeSlider.value, timeSlider.max);
result.view.signal("time", clampedTime);
loader.style.visibility = 'visible';
});
result.view.addSignalListener('time', (name, value) => {
loader.style.visibility = 'visible';
});
result.view.addDataListener("world", (name, value) => {
loader.style.visibility = 'hidden';
});
})
.catch(console.warn);
</script>
</body>
{
"$schema": "https://vega.github.io/schema/vega/v4.0.json",
"padding": 10,
"width": 450,
"height": 450,
"autosize": "pad",
"signals": [
{
"name": "rotate0", "value": 0,
"bind": {"name": "Rotate Vert. Axis", "input": "range", "min": -180, "max": 180}
},
{
"name": "rotate1", "value": 0,
"bind": {"name": "Rotate Horiz. Axis","input": "range", "min": -180, "max": 180}
},
{
"name": "model", "value": "SETON2012",
"bind": {
"name": "Reconstruction Model",
"input": "select",
"options": ["SETON2012", "MULLER2016", "GOLONKA", "PALEOMAP", "MATTHEWS2016"]
}
},
{
"name": "time", "value": 140,
"bind": {"name": "Time (million yrs ago)", "input": "range", "min": 0, "max": 200, "debounce": 500}
}
],
"data": [
{
"name": "sphere",
"values": [
{"type": "Sphere"}
]
},
{
"name": "graticule",
"transform": [
{ "type": "graticule", "step": [15, 15] }
]
},
{
"name": "models",
"values": [
{ "name": "SETON2012", "max": 200,
"title": "Global continental and ocean basin reconstructions since 200 Ma",
"url": "https://www.earthbyte.org/global-continental-and-ocean-basin-reconstructions-since-200-ma/",
"authors": "M. Seton, R.D. Müller, S. Zahirovic, C. Gaina, T.H. Torsvik, G. Shephard, A. Talsma, M. Gurnis, M. Turner, S. Maus, M. Chandler",
"publication": "Earth-Science Reviews, Volume 113, Issues 3-4, July 2012, Pages 212-270, ISSN 0012-8252, 10.1016/j.earscirev.2012.03.002."
},
{ "name": "MULLER2016", "max": 230,
"title": "Ocean basin evolution and global-scale plate reorganization events since Pangea breakup",
"url": "https://www.earthbyte.org/ocean-basin-evolution-and-global-scale-plate-reorganization-events-since-pangea-breakup/",
"authors": "Müller R.D., Seton, M., Zahirovic, S., Williams, S.E., Matthews, K.J., Wright, N.M., Shephard, G.E., Maloney, K.T., Barnett-Moore, N., Hosseinpour, M., Bower, D.J., Cannon, J.",
"publication": "Annual Review of Earth and Planetary Sciences, Vol 44, 107-138. DOI: 10.1146/annurev-earth-060115-012211."
},
{ "name": "GOLONKA", "max": 540,
"title": "Global Plate Tectonics and Paleogeography of Southeast Asia",
"url": "Faculty of Geology, Geophysics and Environmental Protection, AGH University of Science and Technology, Arkadia, Krakow, Poland.",
"authors": "GOLONKA J., KROBICKI M., PAJAK J., VAN GIANG N. & ZUCHIEWICZ W. 2006.",
"publication": ""
},
{ "name": "PALEOMAP", "max": 750,
"title": "PALEOMAP PaleoAtlas for GPlates",
"url": "https://www.earthbyte.org/paleomap-paleoatlas-for-gplates/",
"authors": "",
"publication": ""
},
{ "name": "MATTHEWS2016", "max": 410,
"title": "Global plate boundary evolution and kinematics since the late Paleozoic",
"url": "https://www.earthbyte.org/global-plate-boundary-evolution-and-kinematics-since-the-late-paleozoic/",
"authors": "Matthews, K.J., Maloney, K.T., Zahirovic, S., Williams, S.E., Seton, M., and Müller, R.D.",
"publication": "Global and Planetary Change, 146, 226-250. DOI: 10.1016/j.gloplacha.2016.10.002"
}
]
},
{
"name": "world",
"url": {"signal": "'https://gws.gplates.org/reconstruct/coastlines/?&time='+time+'&model='+model"},
"format": {
"type": "json"
}
}
],
"projections": [
{
"name": "projection",
"scale": 225,
"type": "orthographic",
"translate": {"signal": "[width/2, height/2]"},
"rotate": [{"signal": "rotate0"}, {"signal": "rotate1"}, 0]
}
],
"marks": [
{
"type": "shape",
"from": {"data": "sphere"},
"encode": {
"update": {
"fill": {"value": "#50A6C2"},
"stroke": {"value": "black"},
"strokeWidth": {"value": 1.5}
}
},
"transform": [
{
"type": "geoshape",
"projection": "projection"
}
]
},
{
"type": "shape",
"from": {"data": "graticule"},
"encode": {
"update": {
"strokeWidth": {"value": 1},
"stroke": {"value": "#ddd"},
"fill": {"value": null}
}
},
"transform": [
{ "type": "geoshape", "projection": "projection" }
]
},
{
"type": "shape",
"from": {"data": "world"},
"encode": {
"update": {
"fill": {"value": "#E7C6A5"},
"stroke": {"value": "black"},
"strokeWidth": {"value": 0.35}
}
},
"transform": [
{
"type": "geoshape",
"projection": "projection"
}
]
}
]
}
// from https://loading.io/css/
.lds-spinner {
color: official;
display: inline-block;
position: relative;
width: 64px;
height: 64px;
}
.lds-spinner div {
transform-origin: 32px 32px;
animation: lds-spinner 1.2s linear infinite;
}
.lds-spinner div:after {
content: " ";
display: block;
position: absolute;
top: 3px;
left: 29px;
width: 5px;
height: 14px;
border-radius: 20%;
background: #fff;
}
.lds-spinner div:nth-child(1) {
transform: rotate(0deg);
animation-delay: -1.1s;
}
.lds-spinner div:nth-child(2) {
transform: rotate(30deg);
animation-delay: -1s;
}
.lds-spinner div:nth-child(3) {
transform: rotate(60deg);
animation-delay: -0.9s;
}
.lds-spinner div:nth-child(4) {
transform: rotate(90deg);
animation-delay: -0.8s;
}
.lds-spinner div:nth-child(5) {
transform: rotate(120deg);
animation-delay: -0.7s;
}
.lds-spinner div:nth-child(6) {
transform: rotate(150deg);
animation-delay: -0.6s;
}
.lds-spinner div:nth-child(7) {
transform: rotate(180deg);
animation-delay: -0.5s;
}
.lds-spinner div:nth-child(8) {
transform: rotate(210deg);
animation-delay: -0.4s;
}
.lds-spinner div:nth-child(9) {
transform: rotate(240deg);
animation-delay: -0.3s;
}
.lds-spinner div:nth-child(10) {
transform: rotate(270deg);
animation-delay: -0.2s;
}
.lds-spinner div:nth-child(11) {
transform: rotate(300deg);
animation-delay: -0.1s;
}
.lds-spinner div:nth-child(12) {
transform: rotate(330deg);
animation-delay: 0s;
}
@keyframes lds-spinner {
0% {
opacity: 1;
}
100% {
opacity: 0;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment