168 lines
4.1 KiB
JavaScript
168 lines
4.1 KiB
JavaScript
const json_files = [
|
|
"tileconfig/osm.json",
|
|
"tileconfig/mapycom.json",
|
|
"tileconfig/praha.json"
|
|
];
|
|
|
|
const center = [50.08804, 14.42076];
|
|
const zoom = 14;
|
|
const mapCounts = [2, 4, 6, 9];
|
|
|
|
let syncing = false;
|
|
let urlUpdateTimer = null;
|
|
|
|
let TILE_SERVERS = [];
|
|
let maps = [];
|
|
let layers = [];
|
|
|
|
function fillDropdown(select) {
|
|
for (const name in TILE_SERVERS) {
|
|
const opt = document.createElement("option");
|
|
opt.value = name;
|
|
opt.textContent = name;
|
|
select.appendChild(opt);
|
|
}
|
|
}
|
|
|
|
function readUrlPosition() {
|
|
const match = window.location.hash.match(/^#map=([0-9.]+)\/(-?[0-9.]+)\/(-?[0-9.]+)/);
|
|
|
|
if (match) {
|
|
const z = parseFloat(match[1]);
|
|
const lat = parseFloat(match[2]);
|
|
const lng = parseFloat(match[3]);
|
|
|
|
if (Number.isFinite(lat) && Number.isFinite(lng) && Number.isFinite(z)) {
|
|
return {
|
|
center: [lat, lng],
|
|
zoom: z
|
|
};
|
|
}
|
|
}
|
|
|
|
return {
|
|
center,
|
|
zoom
|
|
};
|
|
}
|
|
|
|
function writeUrlPosition(map) {
|
|
if (urlUpdateTimer) clearTimeout(urlUpdateTimer);
|
|
|
|
urlUpdateTimer = setTimeout(() => {
|
|
const c = map.getCenter();
|
|
const hash = "#map=" + map.getZoom() + "/" + c.lat.toFixed(5) + "/" + c.lng.toFixed(5);
|
|
|
|
history.replaceState(null, "", hash);
|
|
}, 100);
|
|
}
|
|
|
|
function sync(source) {
|
|
if (syncing) return;
|
|
syncing = true;
|
|
maps.forEach(target => {
|
|
if (target !== source) {
|
|
target.setView(source.getCenter(), source.getZoom(), { animate: false });
|
|
}
|
|
});
|
|
syncing = false;
|
|
|
|
writeUrlPosition(source);
|
|
}
|
|
|
|
function setLayer(map, config, currentLayer) {
|
|
if (currentLayer) map.removeLayer(currentLayer);
|
|
|
|
if (config.type === "xyz") {
|
|
return L.tileLayer(config.url, {
|
|
maxZoom: 19,
|
|
tileSize: 256,
|
|
referrerPolicy: "strict-origin-when-cross-origin"
|
|
}).addTo(map);
|
|
}
|
|
|
|
if (config.type === "wms") {
|
|
return L.tileLayer.wms(config.url, {
|
|
layers: config.layers,
|
|
format: config.format || "image/png",
|
|
transparent: config.transparent ?? true,
|
|
version: config.version || "1.3.0",
|
|
attribution: config.attribution || "",
|
|
referrerPolicy: "strict-origin-when-cross-origin"
|
|
}).addTo(map);
|
|
}
|
|
}
|
|
|
|
function fillMapCountDropdown(select) {
|
|
select.innerHTML = "";
|
|
|
|
mapCounts.forEach(count => {
|
|
const opt = document.createElement("option");
|
|
opt.value = count;
|
|
opt.textContent = count + (count === 2 || count === 4 ? " mapy" : " map");
|
|
select.appendChild(opt);
|
|
});
|
|
}
|
|
|
|
function setMapCount(count) {
|
|
const container = document.getElementById("container");
|
|
container.dataset.count = count;
|
|
|
|
for (let i = 1; i <= maps.length; i++) {
|
|
const wrapper = document.getElementById("map" + i).parentElement;
|
|
wrapper.classList.toggle("hidden", i > count);
|
|
}
|
|
|
|
setTimeout(() => {
|
|
maps.forEach((map, index) => {
|
|
if (index < count) map.invalidateSize(false);
|
|
});
|
|
}, 0);
|
|
}
|
|
|
|
function init() {
|
|
const urlPosition = readUrlPosition();
|
|
const mapCountSelector = document.getElementById("mapCountSelector");
|
|
fillMapCountDropdown(mapCountSelector);
|
|
|
|
for (let i = 1; i <= 9; i++) {
|
|
const select = document.getElementById("select" + i);
|
|
fillDropdown(select);
|
|
|
|
const map = L.map("map" + i, { center: urlPosition.center, zoom: urlPosition.zoom, zoomControl: false });
|
|
map.on("move", () => sync(map));
|
|
map.on("zoom", () => sync(map));
|
|
|
|
L.control.zoom({ position: "topright" }).addTo(map);
|
|
|
|
maps.push(map);
|
|
layers.push(null);
|
|
|
|
layers[i - 1] = setLayer(map, TILE_SERVERS[select.value], layers[i - 1]);
|
|
|
|
select.addEventListener("change", e => {
|
|
const key = e.target.value;
|
|
layers[i - 1] = setLayer(map, TILE_SERVERS[key], layers[i - 1]);
|
|
});
|
|
}
|
|
|
|
mapCountSelector.value = "2";
|
|
mapCountSelector.addEventListener("change", e => {
|
|
setMapCount(parseInt(e.target.value, 10));
|
|
});
|
|
|
|
setMapCount(parseInt(mapCountSelector.value, 10));
|
|
}
|
|
|
|
async function loadTileConfigs(json_files) {
|
|
const results = await Promise.all(
|
|
json_files.map(f => fetch(f).then(r => r.json()))
|
|
);
|
|
|
|
// Merge all JSON objects into TILE_SERVERS
|
|
results.forEach(obj => Object.assign(TILE_SERVERS, obj));
|
|
}
|
|
|
|
loadTileConfigs(json_files).then(() => {
|
|
init();
|
|
});
|