mirror of
https://github.com/bilawalsidhu/gods-eye-view.git
synced 2026-11-15 07:42:23 +00:00
Draw Data Library coverage outlines from the bundled Natural Earth countries
Imagery outlines fetched Natural Earth's 1:50m countries (about 3 MB) from the natural-earth-vector repository's master branch on GitHub at run time: a moving, rate-limited source whose failures silently removed the outlines. Core already ships the pinned 1:10m countries pack, so the outlines now read that, once, the first time an outline needs it.
This commit is contained in:
1 parent
8d90cac7dc
commit
9e57fd84c8
3 files changed
+55
-25
No files matched your search
@@ -3,9 +3,10 @@
|
|||||||
Offline polygons with no network dependency. The voice-annotation resolver
|
Offline polygons with no network dependency. The voice-annotation resolver
|
||||||
(`src/data/naturalEarthRegions.js`) reads the named regions, so "outline the
|
(`src/data/naturalEarthRegions.js`) reads the named regions, so "outline the
|
||||||
Alps" resolves to the real range geometry; area annotations read the
|
Alps" resolves to the real range geometry; area annotations read the
|
||||||
countries, states and provinces (`src/data/adminBoundaries.js`); and the News
|
countries, states and provinces (`src/data/adminBoundaries.js`); the News
|
||||||
layer reads the countries and the disputed areas
|
layer reads the countries and the disputed areas
|
||||||
(`server/providers/news/areas.js`).
|
(`server/providers/news/areas.js`); and Data Library imagery draws its
|
||||||
|
coverage outlines from the countries (`src/library/outlines.js`).
|
||||||
|
|
||||||
| File | Source dataset | Features |
|
| File | Source dataset | Features |
|
||||||
|------|----------------|----------|
|
|------|----------------|----------|
|
||||||
|
|||||||
+30
-23
@@ -2,40 +2,47 @@
|
|||||||
* Coverage outlines for Data Library imagery: the borders of the countries an
|
* Coverage outlines for Data Library imagery: the borders of the countries an
|
||||||
* entry covers, so the edge of an aerial photo layer is plain on the map.
|
* entry covers, so the edge of an aerial photo layer is plain on the map.
|
||||||
*
|
*
|
||||||
* Borders come from Natural Earth's 1:50m admin-0 countries (public domain),
|
* Borders come from the bundled Natural Earth 1:10m admin-0 countries pack
|
||||||
* a provider-hosted file fetched live and kept for the session, so nothing is
|
* (public domain, pinned; see src/data/local_data/natural_earth/README.md),
|
||||||
* bundled. Pure apart from `loadCountryOutlines`, which takes `fetchImpl`.
|
* read once the first outline needs it. Pure apart from
|
||||||
|
* `loadCountryOutlines`.
|
||||||
*/
|
*/
|
||||||
import { readResponseTextCapped } from '../sources/httpBody.js';
|
import { loadBundledJson } from '../data/bundledJson.js';
|
||||||
|
import { decodeRing } from '../data/adminBoundaries.js';
|
||||||
|
|
||||||
export const COUNTRY_OUTLINES_URL =
|
const COUNTRIES_PACK_URL = new URL(
|
||||||
'https://raw.githubusercontent.com/nvkelso/natural-earth-vector/master/geojson/ne_50m_admin_0_countries.geojson';
|
'../data/local_data/natural_earth/countries.json',
|
||||||
/** The 1:50m file is about 3 MB. */
|
import.meta.url,
|
||||||
const OUTLINES_MAX_BYTES = 8 * 1024 * 1024;
|
);
|
||||||
/** Outline modes a manifest may ask for. */
|
/** Outline modes a manifest may ask for. */
|
||||||
export const OUTLINE_MODES = Object.freeze(['coverage', 'countries', 'bbox']);
|
export const OUTLINE_MODES = Object.freeze(['coverage', 'countries', 'bbox']);
|
||||||
|
|
||||||
let pending = null;
|
let pending = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Natural Earth country features, fetched once per page.
|
* Country features with closed outer rings, in the GeoJSON shape
|
||||||
* @param {typeof fetch} fetchImpl
|
* `outlineRings` reads, loaded once per page.
|
||||||
|
* @param {(url: URL) => Promise<object>} [loadPack]
|
||||||
* @returns {Promise<object[]>}
|
* @returns {Promise<object[]>}
|
||||||
*/
|
*/
|
||||||
export function loadCountryOutlines(
|
export function loadCountryOutlines(loadPack = loadBundledJson) {
|
||||||
fetchImpl = (...args) => globalThis.fetch(...args),
|
|
||||||
) {
|
|
||||||
pending ||= (async () => {
|
pending ||= (async () => {
|
||||||
const response = await fetchImpl(COUNTRY_OUTLINES_URL, {
|
const pack = await loadPack(COUNTRIES_PACK_URL);
|
||||||
credentials: 'omit',
|
if (!Array.isArray(pack?.features)) throw new Error('not a country pack');
|
||||||
referrerPolicy: 'no-referrer',
|
const decimals = pack.meta?.decimals;
|
||||||
redirect: 'error',
|
return pack.features.map((feature) => ({
|
||||||
});
|
type: 'Feature',
|
||||||
if (!response.ok) throw new Error(`HTTP ${response.status}`);
|
properties: { ISO_A2: feature.iso2 },
|
||||||
const text = await readResponseTextCapped(response, OUTLINES_MAX_BYTES);
|
geometry: {
|
||||||
const features = JSON.parse(text)?.features;
|
type: 'MultiPolygon',
|
||||||
if (!Array.isArray(features)) throw new Error('not a FeatureCollection');
|
coordinates: (feature.polygons || []).map((polygon) =>
|
||||||
return features;
|
polygon.map((encoded) => {
|
||||||
|
const ring = decodeRing(encoded, feature.d ?? decimals);
|
||||||
|
return ring.length ? [...ring, ring[0]] : ring;
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
},
|
||||||
|
}));
|
||||||
})().catch((error) => {
|
})().catch((error) => {
|
||||||
pending = null;
|
pending = null;
|
||||||
throw error;
|
throw error;
|
||||||
|
|||||||
@@ -68,3 +68,25 @@ test('a bbox outline is the coverage rectangle, with no border file needed', ()
|
|||||||
],
|
],
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('outlines come from the bundled Natural Earth countries, closed and in coverage', async () => {
|
||||||
|
const { loadCountryOutlines, resetCountryOutlines } = await import(
|
||||||
|
'./outlines.js'
|
||||||
|
);
|
||||||
|
resetCountryOutlines();
|
||||||
|
const countries = await loadCountryOutlines();
|
||||||
|
for (const id of ['ign-orthophotos-france', 'ee-maa-amet-ortofoto']) {
|
||||||
|
const entry = libraryEntry(id);
|
||||||
|
const rings = outlineRings(countries, entry);
|
||||||
|
assert.ok(rings.length > 0, id);
|
||||||
|
for (const ring of rings) assert.deepEqual(ring.at(-1), ring[0]);
|
||||||
|
}
|
||||||
|
// A pack that cannot load is retried on the next call.
|
||||||
|
resetCountryOutlines();
|
||||||
|
await assert.rejects(
|
||||||
|
loadCountryOutlines(async () => {
|
||||||
|
throw new Error('unreadable');
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
assert.ok((await loadCountryOutlines()).length > 200);
|
||||||
|
});
|
||||||
Reference in new issue
Block a user