2018-10-09 15:00:25 +03:00
|
|
|
<!DOCTYPE html>
|
|
|
|
<html>
|
2019-02-04 20:22:02 +03:00
|
|
|
<head>
|
|
|
|
<meta charset="utf-8" />
|
|
|
|
<title>Martin Debug Page</title>
|
2021-10-07 19:54:25 +03:00
|
|
|
<meta
|
|
|
|
name="viewport"
|
|
|
|
content="initial-scale=1,maximum-scale=1,user-scalable=no"
|
|
|
|
/>
|
2022-10-16 21:56:29 +03:00
|
|
|
<script src="https://unpkg.com/maplibre-gl@2.1.9/dist/maplibre-gl.js"></script>
|
|
|
|
<link href="https://unpkg.com/maplibre-gl@2.1.9/dist/maplibre-gl.css" rel="stylesheet" />
|
2019-02-04 20:22:02 +03:00
|
|
|
|
|
|
|
<style>
|
|
|
|
body {
|
|
|
|
margin: 0;
|
|
|
|
padding: 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
#map {
|
|
|
|
position: absolute;
|
|
|
|
top: 0;
|
|
|
|
bottom: 0;
|
|
|
|
width: 100%;
|
|
|
|
}
|
2021-10-07 19:54:25 +03:00
|
|
|
|
|
|
|
#menu {
|
|
|
|
background: #fff;
|
|
|
|
position: absolute;
|
2023-05-25 19:07:43 +03:00
|
|
|
right: 5px;
|
2021-10-07 19:54:25 +03:00
|
|
|
z-index: 1;
|
2023-05-25 19:07:43 +03:00
|
|
|
width: 100%;
|
|
|
|
height: 100%;
|
2021-10-07 19:54:25 +03:00
|
|
|
border-radius: 3px;
|
|
|
|
font-family: 'Open Sans', sans-serif;
|
|
|
|
overflow: scroll;
|
|
|
|
}
|
|
|
|
|
|
|
|
#menu a {
|
|
|
|
font-size: 13px;
|
|
|
|
color: #404040;
|
|
|
|
display: block;
|
|
|
|
margin: 0;
|
|
|
|
padding: 0;
|
|
|
|
padding: 10px;
|
|
|
|
text-decoration: none;
|
|
|
|
border-bottom: 1px solid rgba(0, 0, 0, 0.25);
|
|
|
|
text-align: center;
|
|
|
|
overflow: hidden;
|
|
|
|
white-space: nowrap;
|
|
|
|
text-overflow: ellipsis;
|
|
|
|
}
|
|
|
|
|
|
|
|
#menu a:last-child {
|
|
|
|
border: none;
|
|
|
|
}
|
|
|
|
|
|
|
|
#menu a:hover {
|
|
|
|
background-color: #f8f8f8;
|
|
|
|
color: #404040;
|
|
|
|
}
|
|
|
|
|
|
|
|
#menu a.active {
|
|
|
|
background-color: #3887be;
|
|
|
|
color: #ffffff;
|
|
|
|
}
|
|
|
|
|
|
|
|
#menu a.active:hover {
|
|
|
|
background: #3074a4;
|
|
|
|
}
|
2023-05-18 06:15:29 +03:00
|
|
|
|
|
|
|
#menu-search {
|
|
|
|
padding: 2px;
|
|
|
|
width: 100%;
|
|
|
|
}
|
|
|
|
|
|
|
|
#menu a.active #colorbox {
|
|
|
|
display: block;
|
|
|
|
}
|
|
|
|
|
|
|
|
#menu a #colorbox {
|
|
|
|
display: none;
|
|
|
|
}
|
|
|
|
|
|
|
|
#colorbox {
|
|
|
|
-webkit-appearance: none;
|
|
|
|
-moz-appearance: none;
|
|
|
|
appearance: none;
|
|
|
|
height: 15px;
|
|
|
|
width: 15px;
|
|
|
|
border: 1px solid white;
|
|
|
|
outline: none;
|
|
|
|
float: right;
|
|
|
|
margin-left: 5px;
|
|
|
|
cursor: pointer;
|
|
|
|
}
|
|
|
|
|
|
|
|
#colorbox::-webkit-color-swatch {
|
|
|
|
border: none;
|
|
|
|
}
|
|
|
|
|
|
|
|
#colorbox::-moz-color-swatch {
|
|
|
|
border: none;
|
|
|
|
}
|
2023-05-25 19:07:43 +03:00
|
|
|
|
|
|
|
#container {
|
|
|
|
position: absolute;
|
|
|
|
top: 10px;
|
|
|
|
bottom: 10px;
|
|
|
|
left: 10px;
|
|
|
|
width: 120px;
|
|
|
|
height: 95vh;
|
|
|
|
}
|
|
|
|
|
|
|
|
.resizer {
|
|
|
|
position: absolute;
|
|
|
|
cursor: col-resize;
|
|
|
|
height: 100%;
|
|
|
|
right: 0;
|
|
|
|
top: 0;
|
|
|
|
width: 5px;
|
|
|
|
z-index: 1;
|
|
|
|
}
|
2019-02-04 20:22:02 +03:00
|
|
|
</style>
|
|
|
|
</head>
|
|
|
|
|
|
|
|
<body>
|
2023-05-25 19:07:43 +03:00
|
|
|
<div id="container">
|
|
|
|
<nav id="menu">
|
|
|
|
<input
|
|
|
|
oninput="handleSearch()"
|
|
|
|
id="menu-search"
|
|
|
|
type="search"
|
|
|
|
placeholder="Search..."
|
|
|
|
/>
|
|
|
|
</nav>
|
|
|
|
<div class="resizer"></div>
|
|
|
|
</div>
|
2019-02-04 20:22:02 +03:00
|
|
|
<div id="map"></div>
|
2023-05-25 19:07:43 +03:00
|
|
|
<script>
|
|
|
|
//ignore this ,it's just to allow user resize menu by drag
|
|
|
|
const container = document.getElementById('container');
|
|
|
|
|
|
|
|
let x = 0;
|
|
|
|
let y = 0;
|
|
|
|
let w = 0;
|
|
|
|
|
|
|
|
const mouseDownHandler = function (e) {
|
|
|
|
x = e.clientX;
|
|
|
|
y = e.clientY;
|
|
|
|
|
|
|
|
const styles = window.getComputedStyle(container);
|
|
|
|
w = parseInt(styles.width, 10);
|
|
|
|
|
|
|
|
document.addEventListener('mousemove', mouseMoveHandler);
|
|
|
|
document.addEventListener('mouseup', mouseUpHandler);
|
|
|
|
};
|
|
|
|
|
|
|
|
const mouseMoveHandler = function (e) {
|
|
|
|
const dx = e.clientX - x;
|
|
|
|
const dy = e.clientY - y;
|
|
|
|
|
|
|
|
container.style.width = `${w + dx}px`;
|
|
|
|
};
|
|
|
|
|
|
|
|
container.addEventListener('mousedown', mouseDownHandler)
|
2019-02-04 20:22:02 +03:00
|
|
|
|
2023-05-25 19:07:43 +03:00
|
|
|
const mouseUpHandler = function () {
|
|
|
|
document.removeEventListener('mousemove', mouseMoveHandler);
|
|
|
|
document.removeEventListener('mouseup', mouseUpHandler);
|
|
|
|
};
|
|
|
|
</script>
|
2019-02-04 20:22:02 +03:00
|
|
|
<script>
|
2023-05-18 06:15:29 +03:00
|
|
|
function handleSearch() {
|
|
|
|
const search = document.getElementById("menu-search").value;
|
|
|
|
const links = document.querySelectorAll("#menu a");
|
|
|
|
for (const link of links) {
|
|
|
|
if (link.textContent.toLowerCase().includes(search.toLowerCase())) {
|
|
|
|
link.style.display = "block";
|
|
|
|
} else {
|
|
|
|
link.style.display = "none";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Reference from: https://stackoverflow.com/a/16348977/11522644
|
|
|
|
const stringToColour = function (str) {
|
|
|
|
let hash = 0;
|
|
|
|
for (let i = 0; i < str.length; i++) {
|
|
|
|
hash = str.charCodeAt(i) + ((hash << 5) - hash);
|
|
|
|
}
|
|
|
|
let colour = "#";
|
|
|
|
for (let i = 0; i < 3; i++) {
|
|
|
|
const value = (hash >> (i * 8)) & 0xff;
|
|
|
|
colour += ("00" + value.toString(16)).substr(-2);
|
|
|
|
}
|
|
|
|
return colour;
|
|
|
|
};
|
2022-10-16 21:56:29 +03:00
|
|
|
const map = new maplibregl.Map({
|
2019-02-04 20:22:02 +03:00
|
|
|
container: 'map',
|
2022-10-16 21:56:29 +03:00
|
|
|
style: 'https://basemaps.cartocdn.com/gl/positron-gl-style/style.json',
|
2019-02-04 20:22:02 +03:00
|
|
|
zoom: 0,
|
2021-02-23 12:01:45 +03:00
|
|
|
center: [0, 0],
|
2021-10-07 19:54:25 +03:00
|
|
|
hash: true
|
2018-10-09 15:00:25 +03:00
|
|
|
});
|
|
|
|
|
2021-10-07 19:54:25 +03:00
|
|
|
function geometryTypeToLayerType(geometryType) {
|
|
|
|
switch (geometryType) {
|
|
|
|
case 'POINT':
|
|
|
|
case 'GEOMETRY':
|
|
|
|
return 'circle';
|
|
|
|
case 'LINESTRING':
|
|
|
|
case 'MULTILINESTRING':
|
|
|
|
case 'COMPOUNDCURVE':
|
|
|
|
return 'line';
|
|
|
|
case 'POLYGON':
|
|
|
|
case 'MULTIPOLYGON':
|
|
|
|
case 'CURVEPOLYGON':
|
|
|
|
case 'SURFACE':
|
|
|
|
case 'MULTISURFACE':
|
|
|
|
return 'fill';
|
|
|
|
default:
|
2021-10-13 14:51:29 +03:00
|
|
|
return 'circle';
|
2021-10-07 19:54:25 +03:00
|
|
|
}
|
|
|
|
}
|
2019-10-26 20:37:49 +03:00
|
|
|
|
2021-10-13 14:51:29 +03:00
|
|
|
map.on('load', async function () {
|
2023-08-30 10:19:33 +03:00
|
|
|
const catalog = await fetch('http://0.0.0.0:3000/catalog');
|
|
|
|
const sources = (await catalog.json()).tiles;
|
2021-10-13 14:51:29 +03:00
|
|
|
|
|
|
|
// Set up the corresponding toggle button for each layer.
|
2023-08-30 10:19:33 +03:00
|
|
|
// TODO: we may want to show each source metadata on hover or some other way?
|
|
|
|
for (const [id, source] of Object.entries(sources)) {
|
2021-10-13 14:51:29 +03:00
|
|
|
// Skip layers that already have a button set up.
|
2023-08-28 07:31:22 +03:00
|
|
|
if (document.getElementById(id)) {
|
2021-10-13 14:51:29 +03:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
const layerType = geometryTypeToLayerType(source.geometry_type);
|
|
|
|
|
|
|
|
map.addLayer({
|
2023-08-28 07:31:22 +03:00
|
|
|
id: id,
|
2021-10-13 14:51:29 +03:00
|
|
|
type: layerType,
|
|
|
|
source: {
|
|
|
|
type: 'vector',
|
2023-08-28 07:31:22 +03:00
|
|
|
url: `http://0.0.0.0:3000/${id}`
|
2021-10-13 14:51:29 +03:00
|
|
|
},
|
2023-08-28 07:31:22 +03:00
|
|
|
'source-layer': id,
|
2021-10-13 14:51:29 +03:00
|
|
|
layout: {
|
|
|
|
visibility: 'none'
|
|
|
|
},
|
|
|
|
paint: {
|
2023-08-28 07:31:22 +03:00
|
|
|
[`${layerType}-color`]: stringToColour(id)
|
2021-10-07 19:54:25 +03:00
|
|
|
}
|
|
|
|
});
|
2021-10-13 14:51:29 +03:00
|
|
|
|
2023-08-28 07:31:22 +03:00
|
|
|
map.on('click', id, (e) => {
|
2021-10-21 12:20:33 +03:00
|
|
|
console.log(e.features);
|
|
|
|
});
|
|
|
|
|
2023-05-18 06:15:29 +03:00
|
|
|
const colorbox = document.createElement("input");
|
|
|
|
colorbox.type = "color";
|
|
|
|
colorbox.id = "colorbox";
|
2023-08-28 07:31:22 +03:00
|
|
|
colorbox.value = stringToColour(id);
|
|
|
|
colorbox.style.backgroundColor = stringToColour(id);
|
2023-05-18 06:15:29 +03:00
|
|
|
colorbox.onclick = function(e){
|
|
|
|
e.stopPropagation();
|
|
|
|
}
|
|
|
|
colorbox.onchange = function(e){
|
2023-08-28 07:31:22 +03:00
|
|
|
map.setPaintProperty(id, `${layerType}-color`, e.target.value);
|
2023-05-18 06:15:29 +03:00
|
|
|
colorbox.style.backgroundColor = e.target.value;
|
|
|
|
}
|
|
|
|
|
2021-10-13 14:51:29 +03:00
|
|
|
// Create a link.
|
|
|
|
const link = document.createElement('a');
|
2023-08-28 07:31:22 +03:00
|
|
|
link.id = id;
|
2021-10-13 14:51:29 +03:00
|
|
|
link.href = '#';
|
2023-08-28 07:31:22 +03:00
|
|
|
link.textContent = id;
|
|
|
|
link.title = id;
|
2023-05-18 06:15:29 +03:00
|
|
|
link.appendChild(colorbox);
|
2021-10-13 14:51:29 +03:00
|
|
|
|
|
|
|
// Show or hide layer when the toggle is clicked.
|
|
|
|
link.onclick = function (e) {
|
|
|
|
const clickedLayer = this.textContent;
|
|
|
|
e.preventDefault();
|
|
|
|
e.stopPropagation();
|
|
|
|
|
|
|
|
const visibility = map.getLayoutProperty(
|
|
|
|
clickedLayer,
|
|
|
|
'visibility'
|
|
|
|
);
|
|
|
|
|
|
|
|
// Toggle layer visibility by changing the layout object's visibility property.
|
|
|
|
if (visibility === 'visible') {
|
|
|
|
map.setLayoutProperty(clickedLayer, 'visibility', 'none');
|
|
|
|
this.className = '';
|
|
|
|
} else {
|
|
|
|
this.className = 'active';
|
|
|
|
map.setLayoutProperty(clickedLayer, 'visibility', 'visible');
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
const layers = document.getElementById('menu');
|
|
|
|
layers.appendChild(link);
|
|
|
|
}
|
2019-02-04 20:22:02 +03:00
|
|
|
});
|
|
|
|
</script>
|
|
|
|
</body>
|
|
|
|
</html>
|