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 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125
| import DataTile from 'ol/source/DataTile.js'; import Map from 'ol/Map.js'; import TileLayer from 'ol/layer/WebGLTile.js'; import View from 'ol/View.js'; import {useGeographic} from 'ol/proj.js';
useGeographic();
const tiles = new pmtiles.PMTiles( 'https://pub-9288c68512ed46eca46ddcade307709b.r2.dev/protomaps-sample-datasets/terrarium_z9.pmtiles' );
function loadImage(src) { return new Promise((resolve, reject) => { const img = new Image(); img.addEventListener('load', () => resolve(img)); img.addEventListener('error', () => reject(new Error('load failed'))); img.src = src; }); }
async function loader(z, x, y) { const response = await tiles.getZxy(z, x, y); const blob = new Blob([response.data]); const src = URL.createObjectURL(blob); const image = await loadImage(src); URL.revokeObjectURL(src); return image; }
function elevation(xOffset, yOffset) { const red = ['band', 1, xOffset, yOffset]; const green = ['band', 2, xOffset, yOffset]; const blue = ['band', 3, xOffset, yOffset]; return ['-', ['+', ['*', 256 * 256, red], ['*', 256, green], blue], 32768]; }
const dp = ['*', 2, ['resolution']]; const z0x = ['*', ['var', 'vert'], elevation(-1, 0)]; const z1x = ['*', ['var', 'vert'], elevation(1, 0)]; const dzdx = ['/', ['-', z1x, z0x], dp]; const z0y = ['*', ['var', 'vert'], elevation(0, -1)]; const z1y = ['*', ['var', 'vert'], elevation(0, 1)]; const dzdy = ['/', ['-', z1y, z0y], dp]; const slope = ['atan', ['^', ['+', ['^', dzdx, 2], ['^', dzdy, 2]], 0.5]]; const aspect = ['clamp', ['atan', ['-', 0, dzdx], dzdy], -Math.PI, Math.PI]; const sunEl = ['*', Math.PI / 180, ['var', 'sunEl']]; const sunAz = ['*', Math.PI / 180, ['var', 'sunAz']];
const incidence = [ '+', ['*', ['sin', sunEl], ['cos', slope]], ['*', ['*', ['cos', sunEl], ['sin', slope]], ['cos', ['-', sunAz, aspect]]], ];
const variables = {};
const layer = new TileLayer({ source: new DataTile({ loader, wrapX: true, maxZoom: 9, attributions: "<a href='https://github.com/tilezen/joerd/blob/master/docs/attribution.md#attribution'>Tilezen Jörð</a>", }), style: { variables: variables, color: ['array', incidence, incidence, incidence, 1], }, });
const controlIds = ['vert', 'sunEl', 'sunAz']; controlIds.forEach(function (id) { const control = document.getElementById(id); const output = document.getElementById(id + 'Out'); function updateValues() { output.innerText = control.value; variables[id] = Number(control.value); } updateValues(); control.addEventListener('input', function () { updateValues(); layer.updateStyleVariables(variables); }); });
const map = new Map({ target: 'map', layers: [layer], view: new View({ center: [0, 0], zoom: 1, }), });
function getElevation(data) { const red = data[0]; const green = data[1]; const blue = data[2]; return red * 256 + green + blue / 256 - 32768; }
function formatLocation([lon, lat]) { const NS = lat < 0 ? 'S' : 'N'; const EW = lon < 0 ? 'W' : 'E'; return `${Math.abs(lat).toFixed(1)}° ${NS}, ${Math.abs(lon).toFixed( 1 )}° ${EW}`; }
const elevationOut = document.getElementById('elevationOut'); const locationOut = document.getElementById('locationOut'); function displayPixelValue(event) { const data = layer.getData(event.pixel); if (!data) { return; } elevationOut.innerText = getElevation(data).toLocaleString() + ' m'; locationOut.innerText = formatLocation(event.coordinate); } map.on(['pointermove', 'click'], displayPixelValue);
|