Readme

Earthquake map 🌏

This val loads earthquake data from USGS, a topojson file for the land shape, and supporting libraries. It then creates a map and save it as a SVG string. The result is cached for a day. Note that we must strive to keep it under val.town’s limit of 100kB, hence the heavy simplification of the land shape. (For a simpler example, see becker barley.)

Web pagehttps://fil-earthquakes.web.val.run/
Observable Plot https://observablehq.com/plot/
linkedomhttps://github.com/WebReflection/linkedom
topojsonhttps://github.com/topojson/topojson
earthquakeshttps://earthquake.usgs.gov
worldhttps://observablehq.com/@visionscarto/world-atlas-topojson
csshttps://milligram.io/
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
import { fetch } from "https://esm.town/v/std/fetch";
import { set } from "https://esm.town/v/std/set?v=11";
let { earthquakes_storage } = await import("https://esm.town/v/fil/earthquakes_storage");
export async function earthquakes(req?) {
const yesterday = new Date(-24 * 3600 * 1000 + +new Date()).toISOString();
if (!(earthquakes_storage?.date > yesterday)) {
const dataUrl = "https://earthquake.usgs.gov/earthquakes/feed/v1.0/summary/all_day.geojson";
const worldUrl = "https://cdn.jsdelivr.net/npm/visionscarto-world-atlas@1/world/110m.json";
let [Plot, { document }, topojson, quakes, world] = await Promise.all([
import("https://cdn.jsdelivr.net/npm/@observablehq/plot@0.6.14/+esm"),
import("https://cdn.jsdelivr.net/npm/linkedom@0.15/+esm").then((l) => l.parseHTML("<a>")),
import("https://cdn.jsdelivr.net/npm/topojson@3/+esm"),
fetch(dataUrl).then((r) => r.json()),
fetch(worldUrl).then((r) => r.json()),
]);
world = topojson.presimplify(world, topojson.sphericalTriangleArea);
world = topojson.simplify(world, 0.0001);
const chart = Plot.plot({
document,
projection: { type: "equal-earth", rotate: [-10, 0] },
r: { type: "linear", domain: [0, 5], range: [0, 10] },
marks: [
Plot.geo(topojson.feature(world, world.objects.land)),
Plot.dot(
quakes.features,
Plot.centroid({
r: (d) => d.properties.mag,
fill: "red",
fillOpacity: 0.3,
}),
),
Plot.graticule(),
Plot.sphere(),
],
});
earthquakes_storage = {
date: new Date().toISOString(),
svg: `${chart}`.replaceAll(/(\.\d)\d+/g, "$1"),
};
await set(
"earthquakes_storage",
earthquakes_storage,
);
}
// If invoked through the web endpoint, return a web page.
return req instanceof Request
? new URL(req.url).searchParams.get("svg")
? new Response(
earthquakes_storage.svg.replace(
/^<svg /,
"<svg xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" version=\"1.1\" ",
),
{ headers: { "Content-Type": "image/svg+xml" } },
)
: new Response(
`<body style="padding: 3em;"><h1>Earthquake map</h1><p>Data updated <abbr title="${earthquakes_storage.date}">daily</abbr>; source: USGS.</p>
${earthquakes_storage.svg}
<small><a href="https://www.val.town/v/fil.earthquakes"><b><i>vt</i></b> source code</a>
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:300,300italic,700,700italic">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/normalize/8.0.1/normalize.css">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/milligram/1.4.1/milligram.css">`,
{ headers: { "Content-Type": "text/html" } },
)
: earthquakes_storage;
}
👆 This is a val. Vals are TypeScript snippets of code, written in the browser and run on our servers. Create scheduled functions, email yourself, and persist small pieces of data — all from the browser.