<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>MapLibre GL JS 3D-Terrain with GSI-DEM</title>
<script src="https://unpkg.com/maplibre-gl@2.2.0-pre.2/dist/maplibre-gl.js"></script>
<link href="https://unpkg.com/maplibre-gl@2.2.0-pre.2/dist/maplibre-gl.css" rel="stylesheet" />
</head>
<body>
<div id="map" style="height:90vh;"></div>
<script>
const gsidem2terrainrgb = (r, g, b) => {
let height = r * 655.36 + g * 2.56 + b * 0.01;
if (r === 128 && g === 0 && b === 0) {
height = 0;
} else if (r >= 128) {
height -= 167772.16;
}
height += 100000;
height *= 10;
const tB = (height / 256 - Math.floor(height / 256)) * 256;
const tG =
(Math.floor(height / 256) / 256 -
Math.floor(Math.floor(height / 256) / 256)) *
256;
const tR =
(Math.floor(Math.floor(height / 256) / 256) / 256 -
Math.floor(Math.floor(Math.floor(height / 256) / 256) / 256)) *
256;
return [tR, tG, tB];
};
maplibregl.addProtocol('gsidem', (params, callback) => {
const image = new Image();
image.crossOrigin = '';
image.onload = () => {
const canvas = document.createElement('canvas');
canvas.width = image.width;
canvas.height = image.height;
const context = canvas.getContext('2d');
context.drawImage(image, 0, 0);
const imageData = context.getImageData(
0,
0,
canvas.width,
canvas.height,
);
for (let i = 0; i < imageData.data.length / 4; i++) {
const tRGB = gsidem2terrainrgb(
imageData.data[i * 4],
imageData.data[i * 4 + 1],
imageData.data[i * 4 + 2],
);
imageData.data[i * 4] = tRGB[0];
imageData.data[i * 4 + 1] = tRGB[1];
imageData.data[i * 4 + 2] = tRGB[2];
}
context.putImageData(imageData, 0, 0);
canvas.toBlob((blob) =>
blob.arrayBuffer().then((arr) => callback(null, arr, null, null)),
);
};
image.src = params.url.replace('gsidem://', '');
return { cancel: () => {} };
});
const map = new maplibregl.Map({
container: 'map',
maxPitch: 85,
center: [138.69,35.3],
zoom: 12,
pitch: 70,
style: {
version: 8,
sources: {
gsi: {
type: 'raster',
tiles: [
'https://cyberjapandata.gsi.go.jp/xyz/seamlessphoto/{z}/{x}/{y}.jpg',
],
attribution: '地理院タイル',
},
gsidem: {
type: 'raster-dem',
tiles: [
'gsidem://https://cyberjapandata.gsi.go.jp/xyz/dem_png/{z}/{x}/{y}.png',
],
tileSize: 256,
maxzoom: 14,
},
},
layers: [
{
id: 'gsi',
type: 'raster',
source: 'gsi',
},
],
terrain: {
source: 'gsidem',
exaggeration: 1.2,
},
},
});
</script>
</body>
</html>
Output
You can jump to the latest bin by adding /latest
to your URL
Keyboard Shortcuts
Shortcut | Action |
---|---|
ctrl + [num] | Toggle nth panel |
ctrl + 0 | Close focused panel |
ctrl + enter | Re-render output. If console visible: run JS in console |
Ctrl + l | Clear the console |
ctrl + / | Toggle comment on selected lines |
ctrl + ] | Indents selected lines |
ctrl + [ | Unindents selected lines |
tab | Code complete & Emmet expand |
ctrl + shift + L | Beautify code in active panel |
ctrl + s | Save & lock current Bin from further changes |
ctrl + shift + s | Open the share options |
ctrl + y | Archive Bin |
Complete list of JS Bin shortcuts |
JS Bin URLs
URL | Action |
---|---|
/ | Show the full rendered output. This content will update in real time as it's updated from the /edit url. |
/edit | Edit the current bin |
/watch | Follow a Code Casting session |
/embed | Create an embeddable version of the bin |
/latest | Load the very latest bin (/latest goes in place of the revision) |
/[username]/last | View the last edited bin for this user |
/[username]/last/edit | Edit the last edited bin for this user |
/[username]/last/watch | Follow the Code Casting session for the latest bin for this user |
/quiet | Remove analytics and edit button from rendered output |
.js | Load only the JavaScript for a bin |
.css | Load only the CSS for a bin |
Except for username prefixed urls, the url may start with http://jsbin.com/abc and the url fragments can be added to the url to view it differently. |