Compare commits
No commits in common. "5dd3a13b3b24b8cbbff5e73b7a687a3f0ef5545f90013f10e30b7339fce396f0" and "e1b205d01c478797038e1c9a35605852dfb52040e7d13445a480bf7641f6f20c" have entirely different histories.
5dd3a13b3b
...
e1b205d01c
5 changed files with 53 additions and 426 deletions
60
dve.css
60
dve.css
|
|
@ -57,66 +57,6 @@ html, body {
|
||||||
top: auto;
|
top: auto;
|
||||||
bottom: 10px;
|
bottom: 10px;
|
||||||
}
|
}
|
||||||
.layer-selector {
|
|
||||||
padding: 0;
|
|
||||||
min-width: 190px;
|
|
||||||
}
|
|
||||||
.layer-selector-button {
|
|
||||||
width: 100%;
|
|
||||||
max-width: 280px;
|
|
||||||
border: 0;
|
|
||||||
background: transparent;
|
|
||||||
padding: 6px 24px 6px 8px;
|
|
||||||
text-align: left;
|
|
||||||
font: inherit;
|
|
||||||
cursor: pointer;
|
|
||||||
white-space: nowrap;
|
|
||||||
overflow: hidden;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
}
|
|
||||||
.layer-selector-button::after {
|
|
||||||
content: "▾";
|
|
||||||
position: absolute;
|
|
||||||
right: 8px;
|
|
||||||
}
|
|
||||||
.layer-selector-menu {
|
|
||||||
display: none;
|
|
||||||
min-width: 260px;
|
|
||||||
max-width: 360px;
|
|
||||||
max-height: 65vh;
|
|
||||||
overflow: auto;
|
|
||||||
border-top: 1px solid rgba(0,0,0,0.15);
|
|
||||||
}
|
|
||||||
.layer-selector.open .layer-selector-menu {
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
.layer-group-title {
|
|
||||||
padding: 8px 8px 4px;
|
|
||||||
font-weight: bold;
|
|
||||||
color: #555;
|
|
||||||
}
|
|
||||||
.layer-option,
|
|
||||||
.layer-overlay-option {
|
|
||||||
display: block;
|
|
||||||
box-sizing: border-box;
|
|
||||||
width: 100%;
|
|
||||||
border: 0;
|
|
||||||
background: transparent;
|
|
||||||
padding: 5px 8px 5px 18px;
|
|
||||||
text-align: left;
|
|
||||||
font: inherit;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
.layer-option:hover,
|
|
||||||
.layer-overlay-option:hover {
|
|
||||||
background: rgba(0,0,0,0.08);
|
|
||||||
}
|
|
||||||
.layer-option.active {
|
|
||||||
font-weight: bold;
|
|
||||||
}
|
|
||||||
.layer-overlay-option input {
|
|
||||||
margin-right: 6px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.crosshair {
|
.crosshair {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
|
|
|
||||||
264
dve.js
264
dve.js
|
|
@ -1,18 +1,12 @@
|
||||||
const json_files = [
|
const json_files = [
|
||||||
"tileconfig/osm.json",
|
"tileconfig/osm.json",
|
||||||
"tileconfig/mapycom.json",
|
"tileconfig/mapycom.json",
|
||||||
"tileconfig/praha.json",
|
"tileconfig/praha.json"
|
||||||
"tileconfig/others.json"
|
|
||||||
];
|
];
|
||||||
|
|
||||||
const center = [50.08804, 14.42076];
|
const center = [50.08804, 14.42076];
|
||||||
const zoom = 14;
|
const zoom = 14;
|
||||||
const mapCounts = [1, 2, 4, 6, 9];
|
const mapCounts = [1, 2, 4, 6, 9];
|
||||||
const layerCategories = {
|
|
||||||
classic: "Klasické",
|
|
||||||
ortho: "Ortomapy",
|
|
||||||
overlay: "Overlaye"
|
|
||||||
};
|
|
||||||
|
|
||||||
let syncing = false;
|
let syncing = false;
|
||||||
let urlUpdateTimer = null;
|
let urlUpdateTimer = null;
|
||||||
|
|
@ -20,151 +14,18 @@ let activeMouseMap = null;
|
||||||
let activeMousePoint = null;
|
let activeMousePoint = null;
|
||||||
let activeMouseLatLng = null;
|
let activeMouseLatLng = null;
|
||||||
|
|
||||||
let TILE_SERVERS = {};
|
let TILE_SERVERS = [];
|
||||||
let maps = [];
|
let maps = [];
|
||||||
let baseLayers = [];
|
let layers = [];
|
||||||
let overlayLayers = [];
|
|
||||||
let crosshairs = [];
|
let crosshairs = [];
|
||||||
|
|
||||||
function getLayerCategory(name, config) {
|
function fillDropdown(select) {
|
||||||
const category = (config.category || "").toString().toLowerCase();
|
for (const name in TILE_SERVERS) {
|
||||||
const lowerName = name.toLowerCase();
|
const opt = document.createElement("option");
|
||||||
|
opt.value = name;
|
||||||
if (["overlay", "overlays", "prekryv", "překryv"].includes(category)) return "overlay";
|
opt.textContent = name;
|
||||||
if (["ortho", "ortomap", "orthomap", "orthophoto", "ortofoto", "ortomapa"].includes(category)) return "ortho";
|
select.appendChild(opt);
|
||||||
if (["classic", "base", "normal", "klasicke", "klasické"].includes(category)) return "classic";
|
}
|
||||||
|
|
||||||
if (lowerName.includes("overlay")) return "overlay";
|
|
||||||
if (lowerName.includes("orto")) return "ortho";
|
|
||||||
|
|
||||||
return "classic";
|
|
||||||
}
|
|
||||||
|
|
||||||
function getLayerNamesByCategory(category) {
|
|
||||||
return Object.keys(TILE_SERVERS).filter(name => getLayerCategory(name, TILE_SERVERS[name]) === category);
|
|
||||||
}
|
|
||||||
|
|
||||||
function getBaseLayerNames() {
|
|
||||||
return Object.keys(TILE_SERVERS).filter(name => getLayerCategory(name, TILE_SERVERS[name]) !== "overlay");
|
|
||||||
}
|
|
||||||
|
|
||||||
function getValidBaseLayerName(name) {
|
|
||||||
if (name && TILE_SERVERS[name] && getLayerCategory(name, TILE_SERVERS[name]) !== "overlay") return name;
|
|
||||||
|
|
||||||
return getBaseLayerNames()[0] || Object.keys(TILE_SERVERS)[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
function getValidOverlayNames(names) {
|
|
||||||
const selected = [];
|
|
||||||
|
|
||||||
names.forEach(name => {
|
|
||||||
if (
|
|
||||||
!selected.includes(name) &&
|
|
||||||
TILE_SERVERS[name] &&
|
|
||||||
getLayerCategory(name, TILE_SERVERS[name]) === "overlay"
|
|
||||||
) {
|
|
||||||
selected.push(name);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return selected;
|
|
||||||
}
|
|
||||||
|
|
||||||
function closeLayerSelectors(except) {
|
|
||||||
document.querySelectorAll(".layer-selector.open").forEach(selector => {
|
|
||||||
if (selector !== except) selector.classList.remove("open");
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function updateLayerSelectorLabel(selector) {
|
|
||||||
const button = selector.querySelector(".layer-selector-button");
|
|
||||||
const state = getLayerSelectorState(selector.dataset.index);
|
|
||||||
button.textContent = state.base + (state.overlays.length ? " +" + state.overlays.length : "");
|
|
||||||
|
|
||||||
selector.querySelectorAll(".layer-option").forEach(option => {
|
|
||||||
option.classList.toggle("active", option.dataset.layer === state.base);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function addLayerGroup(menu, title, names, overlay, selector) {
|
|
||||||
if (!names.length) return;
|
|
||||||
|
|
||||||
const groupTitle = document.createElement("div");
|
|
||||||
groupTitle.className = "layer-group-title";
|
|
||||||
groupTitle.textContent = title;
|
|
||||||
menu.appendChild(groupTitle);
|
|
||||||
|
|
||||||
names.forEach(name => {
|
|
||||||
if (overlay) {
|
|
||||||
const label = document.createElement("label");
|
|
||||||
const input = document.createElement("input");
|
|
||||||
label.className = "layer-overlay-option";
|
|
||||||
input.type = "checkbox";
|
|
||||||
input.dataset.layer = name;
|
|
||||||
input.checked = selector._initialOverlays.includes(name);
|
|
||||||
label.appendChild(input);
|
|
||||||
label.appendChild(document.createTextNode(name));
|
|
||||||
menu.appendChild(label);
|
|
||||||
|
|
||||||
input.addEventListener("change", e => {
|
|
||||||
const index = parseInt(selector.dataset.index, 10);
|
|
||||||
setOverlayLayer(index, name, e.target.checked);
|
|
||||||
updateLayerSelectorLabel(selector);
|
|
||||||
writeUrlState(maps[index]);
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
const option = document.createElement("button");
|
|
||||||
option.type = "button";
|
|
||||||
option.className = "layer-option";
|
|
||||||
option.dataset.layer = name;
|
|
||||||
option.textContent = name;
|
|
||||||
menu.appendChild(option);
|
|
||||||
|
|
||||||
option.addEventListener("click", () => {
|
|
||||||
const index = parseInt(selector.dataset.index, 10);
|
|
||||||
selector.dataset.baseLayer = name;
|
|
||||||
setBaseLayer(index, name);
|
|
||||||
updateLayerSelectorLabel(selector);
|
|
||||||
selector.classList.remove("open");
|
|
||||||
writeUrlState(maps[index]);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function fillLayerSelector(selector, index, state) {
|
|
||||||
const baseLayer = getValidBaseLayerName(state.base);
|
|
||||||
const overlays = getValidOverlayNames(state.overlays || []);
|
|
||||||
|
|
||||||
selector.innerHTML = "";
|
|
||||||
selector.dataset.index = index;
|
|
||||||
selector.dataset.baseLayer = baseLayer;
|
|
||||||
selector._initialOverlays = overlays;
|
|
||||||
|
|
||||||
const button = document.createElement("button");
|
|
||||||
button.type = "button";
|
|
||||||
button.className = "layer-selector-button";
|
|
||||||
selector.appendChild(button);
|
|
||||||
|
|
||||||
const menu = document.createElement("div");
|
|
||||||
menu.className = "layer-selector-menu";
|
|
||||||
selector.appendChild(menu);
|
|
||||||
|
|
||||||
addLayerGroup(menu, layerCategories.classic, getLayerNamesByCategory("classic"), false, selector);
|
|
||||||
addLayerGroup(menu, layerCategories.ortho, getLayerNamesByCategory("ortho"), false, selector);
|
|
||||||
addLayerGroup(menu, layerCategories.overlay, getLayerNamesByCategory("overlay"), true, selector);
|
|
||||||
|
|
||||||
["click", "mousedown", "dblclick", "wheel", "touchstart"].forEach(type => {
|
|
||||||
selector.addEventListener(type, e => e.stopPropagation());
|
|
||||||
});
|
|
||||||
|
|
||||||
button.addEventListener("click", () => {
|
|
||||||
const open = !selector.classList.contains("open");
|
|
||||||
closeLayerSelectors(selector);
|
|
||||||
selector.classList.toggle("open", open);
|
|
||||||
});
|
|
||||||
|
|
||||||
updateLayerSelectorLabel(selector);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function readUrlState() {
|
function readUrlState() {
|
||||||
|
|
@ -196,31 +57,23 @@ function readUrlState() {
|
||||||
}
|
}
|
||||||
|
|
||||||
for (let i = 1; i <= state.count; i++) {
|
for (let i = 1; i <= state.count; i++) {
|
||||||
state.layers.push({
|
const layer = params.get("layer" + i);
|
||||||
base: params.get("layer" + i),
|
|
||||||
overlays: params.getAll("overlay" + i)
|
if (layer) state.layers.push(layer);
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getLayerSelectorState(index) {
|
function getSelectedLayers(count) {
|
||||||
const selector = document.getElementById("select" + (parseInt(index, 10) + 1));
|
const selected = [];
|
||||||
const overlays = [];
|
|
||||||
|
|
||||||
selector.querySelectorAll(".layer-overlay-option input:checked").forEach(input => {
|
for (let i = 1; i <= count; i++) {
|
||||||
overlays.push(input.dataset.layer);
|
const select = document.getElementById("select" + i);
|
||||||
});
|
if (select && select.value) selected.push(select.value);
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return selected;
|
||||||
base: selector.dataset.baseLayer,
|
|
||||||
overlays
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function addUrlParam(parts, key, value) {
|
|
||||||
if (value) parts.push(key + "=" + encodeURIComponent(value));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function writeUrlState(map) {
|
function writeUrlState(map) {
|
||||||
|
|
@ -229,18 +82,15 @@ function writeUrlState(map) {
|
||||||
urlUpdateTimer = setTimeout(() => {
|
urlUpdateTimer = setTimeout(() => {
|
||||||
const c = map.getCenter();
|
const c = map.getCenter();
|
||||||
const count = parseInt(document.getElementById("mapCountSelector").value, 10);
|
const count = parseInt(document.getElementById("mapCountSelector").value, 10);
|
||||||
const parts = [];
|
|
||||||
let hash = "#map=" + map.getZoom() + "/" + c.lat.toFixed(5) + "/" + c.lng.toFixed(5);
|
let hash = "#map=" + map.getZoom() + "/" + c.lat.toFixed(5) + "/" + c.lng.toFixed(5);
|
||||||
|
|
||||||
parts.push("count=" + count);
|
hash += "&count=" + count;
|
||||||
|
|
||||||
for (let i = 0; i < count; i++) {
|
const selected = getSelectedLayers(count);
|
||||||
const state = getLayerSelectorState(i);
|
selected.forEach((name, index) => {
|
||||||
addUrlParam(parts, "layer" + (i + 1), state.base);
|
hash += "&layer" + (index + 1) + "=" + encodeURIComponent(name);
|
||||||
state.overlays.forEach(name => addUrlParam(parts, "overlay" + (i + 1), name));
|
});
|
||||||
}
|
|
||||||
|
|
||||||
hash += "&" + parts.join("&");
|
|
||||||
history.replaceState(null, "", hash);
|
history.replaceState(null, "", hash);
|
||||||
}, 100);
|
}, 100);
|
||||||
}
|
}
|
||||||
|
|
@ -259,14 +109,15 @@ function sync(source) {
|
||||||
updateCrosshairs();
|
updateCrosshairs();
|
||||||
}
|
}
|
||||||
|
|
||||||
function createLayer(config, zIndex) {
|
function setLayer(map, config, currentLayer) {
|
||||||
|
if (currentLayer) map.removeLayer(currentLayer);
|
||||||
|
|
||||||
if (config.type === "xyz") {
|
if (config.type === "xyz") {
|
||||||
return L.tileLayer(config.url, {
|
return L.tileLayer(config.url, {
|
||||||
maxZoom: 19,
|
maxZoom: 19,
|
||||||
tileSize: 256,
|
tileSize: 256,
|
||||||
zIndex,
|
|
||||||
referrerPolicy: "strict-origin-when-cross-origin"
|
referrerPolicy: "strict-origin-when-cross-origin"
|
||||||
});
|
}).addTo(map);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (config.type === "wms") {
|
if (config.type === "wms") {
|
||||||
|
|
@ -276,40 +127,8 @@ function createLayer(config, zIndex) {
|
||||||
transparent: config.transparent ?? true,
|
transparent: config.transparent ?? true,
|
||||||
version: config.version || "1.3.0",
|
version: config.version || "1.3.0",
|
||||||
attribution: config.attribution || "",
|
attribution: config.attribution || "",
|
||||||
zIndex,
|
|
||||||
referrerPolicy: "strict-origin-when-cross-origin"
|
referrerPolicy: "strict-origin-when-cross-origin"
|
||||||
});
|
}).addTo(map);
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function setLayer(map, config, currentLayer, zIndex) {
|
|
||||||
if (currentLayer) map.removeLayer(currentLayer);
|
|
||||||
|
|
||||||
return createLayer(config, zIndex).addTo(map);
|
|
||||||
}
|
|
||||||
|
|
||||||
function bringOverlayLayersToFront(index) {
|
|
||||||
Object.values(overlayLayers[index]).forEach(layer => {
|
|
||||||
layer.setZIndex(100);
|
|
||||||
layer.bringToFront();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function setBaseLayer(index, name) {
|
|
||||||
baseLayers[index] = setLayer(maps[index], TILE_SERVERS[name], baseLayers[index], 1);
|
|
||||||
bringOverlayLayersToFront(index);
|
|
||||||
}
|
|
||||||
|
|
||||||
function setOverlayLayer(index, name, enabled) {
|
|
||||||
if (enabled) {
|
|
||||||
if (!overlayLayers[index][name]) {
|
|
||||||
overlayLayers[index][name] = createLayer(TILE_SERVERS[name], 100).addTo(maps[index]);
|
|
||||||
}
|
|
||||||
|
|
||||||
overlayLayers[index][name].bringToFront();
|
|
||||||
} else if (overlayLayers[index][name]) {
|
|
||||||
maps[index].removeLayer(overlayLayers[index][name]);
|
|
||||||
delete overlayLayers[index][name];
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -413,11 +232,13 @@ function init() {
|
||||||
const mapCountSelector = document.getElementById("mapCountSelector");
|
const mapCountSelector = document.getElementById("mapCountSelector");
|
||||||
fillMapCountDropdown(mapCountSelector);
|
fillMapCountDropdown(mapCountSelector);
|
||||||
|
|
||||||
document.addEventListener("click", () => closeLayerSelectors());
|
|
||||||
|
|
||||||
for (let i = 1; i <= 9; i++) {
|
for (let i = 1; i <= 9; i++) {
|
||||||
const selector = document.getElementById("select" + i);
|
const select = document.getElementById("select" + i);
|
||||||
fillLayerSelector(selector, i - 1, urlState.layers[i - 1] || {});
|
fillDropdown(select);
|
||||||
|
|
||||||
|
if (urlState.layers[i - 1] && TILE_SERVERS[urlState.layers[i - 1]]) {
|
||||||
|
select.value = urlState.layers[i - 1];
|
||||||
|
}
|
||||||
|
|
||||||
const map = L.map("map" + i, { center: urlState.center, zoom: urlState.zoom, zoomControl: false });
|
const map = L.map("map" + i, { center: urlState.center, zoom: urlState.zoom, zoomControl: false });
|
||||||
map.on("move", () => sync(map));
|
map.on("move", () => sync(map));
|
||||||
|
|
@ -426,14 +247,17 @@ function init() {
|
||||||
L.control.zoom({ position: "topright" }).addTo(map);
|
L.control.zoom({ position: "topright" }).addTo(map);
|
||||||
|
|
||||||
maps.push(map);
|
maps.push(map);
|
||||||
baseLayers.push(null);
|
layers.push(null);
|
||||||
overlayLayers.push({});
|
|
||||||
crosshairs.push(createCrosshair(map));
|
crosshairs.push(createCrosshair(map));
|
||||||
initCrosshair(map);
|
initCrosshair(map);
|
||||||
|
|
||||||
const layerState = getLayerSelectorState(i - 1);
|
layers[i - 1] = setLayer(map, TILE_SERVERS[select.value], layers[i - 1]);
|
||||||
setBaseLayer(i - 1, layerState.base);
|
|
||||||
layerState.overlays.forEach(name => setOverlayLayer(i - 1, name, true));
|
select.addEventListener("change", e => {
|
||||||
|
const key = e.target.value;
|
||||||
|
layers[i - 1] = setLayer(map, TILE_SERVERS[key], layers[i - 1]);
|
||||||
|
writeUrlState(map);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
mapCountSelector.value = urlState.count;
|
mapCountSelector.value = urlState.count;
|
||||||
|
|
|
||||||
18
index.html
18
index.html
|
|
@ -31,39 +31,39 @@
|
||||||
<body>
|
<body>
|
||||||
<div id="container" data-count="2">
|
<div id="container" data-count="2">
|
||||||
<div class="map-wrapper">
|
<div class="map-wrapper">
|
||||||
<div id="select1" class="selector layer-selector"></div>
|
<select id="select1" class="selector"></select>
|
||||||
<div id="map1" class="map"></div>
|
<div id="map1" class="map"></div>
|
||||||
</div>
|
</div>
|
||||||
<div class="map-wrapper">
|
<div class="map-wrapper">
|
||||||
<div id="select2" class="selector layer-selector"></div>
|
<select id="select2" class="selector"></select>
|
||||||
<div id="map2" class="map"></div>
|
<div id="map2" class="map"></div>
|
||||||
</div>
|
</div>
|
||||||
<div class="map-wrapper hidden">
|
<div class="map-wrapper hidden">
|
||||||
<div id="select3" class="selector layer-selector"></div>
|
<select id="select3" class="selector"></select>
|
||||||
<div id="map3" class="map"></div>
|
<div id="map3" class="map"></div>
|
||||||
</div>
|
</div>
|
||||||
<div class="map-wrapper hidden">
|
<div class="map-wrapper hidden">
|
||||||
<div id="select4" class="selector layer-selector"></div>
|
<select id="select4" class="selector"></select>
|
||||||
<div id="map4" class="map"></div>
|
<div id="map4" class="map"></div>
|
||||||
</div>
|
</div>
|
||||||
<div class="map-wrapper hidden">
|
<div class="map-wrapper hidden">
|
||||||
<div id="select5" class="selector layer-selector"></div>
|
<select id="select5" class="selector"></select>
|
||||||
<div id="map5" class="map"></div>
|
<div id="map5" class="map"></div>
|
||||||
</div>
|
</div>
|
||||||
<div class="map-wrapper hidden">
|
<div class="map-wrapper hidden">
|
||||||
<div id="select6" class="selector layer-selector"></div>
|
<select id="select6" class="selector"></select>
|
||||||
<div id="map6" class="map"></div>
|
<div id="map6" class="map"></div>
|
||||||
</div>
|
</div>
|
||||||
<div class="map-wrapper hidden">
|
<div class="map-wrapper hidden">
|
||||||
<div id="select7" class="selector layer-selector"></div>
|
<select id="select7" class="selector"></select>
|
||||||
<div id="map7" class="map"></div>
|
<div id="map7" class="map"></div>
|
||||||
</div>
|
</div>
|
||||||
<div class="map-wrapper hidden">
|
<div class="map-wrapper hidden">
|
||||||
<div id="select8" class="selector layer-selector"></div>
|
<select id="select8" class="selector"></select>
|
||||||
<div id="map8" class="map"></div>
|
<div id="map8" class="map"></div>
|
||||||
</div>
|
</div>
|
||||||
<div class="map-wrapper hidden">
|
<div class="map-wrapper hidden">
|
||||||
<div id="select9" class="selector layer-selector"></div>
|
<select id="select9" class="selector"></select>
|
||||||
<div id="map9" class="map"></div>
|
<div id="map9" class="map"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -2,53 +2,5 @@
|
||||||
"OpenStreetMap": {
|
"OpenStreetMap": {
|
||||||
"url": "https://tile.openstreetmap.org/{z}/{x}/{y}.png",
|
"url": "https://tile.openstreetmap.org/{z}/{x}/{y}.png",
|
||||||
"type": "xyz"
|
"type": "xyz"
|
||||||
},
|
|
||||||
"OpenStreetMap DE": {
|
|
||||||
"url": "https://tile.openstreetmap.de/{z}/{x}/{y}.png",
|
|
||||||
"type": "xyz"
|
|
||||||
},
|
|
||||||
"OpenStreetMap HOT": {
|
|
||||||
"url": "https://{s}.tile.openstreetmap.fr/hot/{z}/{x}/{y}.png",
|
|
||||||
"type": "xyz"
|
|
||||||
},
|
|
||||||
"CyclOSM Lite overlay": {
|
|
||||||
"url": "https://{s}.tile-cyclosm.openstreetmap.fr/cyclosm-lite/{z}/{x}/{y}.png",
|
|
||||||
"type": "xyz"
|
|
||||||
},
|
|
||||||
"OpenTopoMap": {
|
|
||||||
"url": "https://{s}.tile.opentopomap.org/{z}/{x}/{y}.png",
|
|
||||||
"type": "xyz"
|
|
||||||
},
|
|
||||||
"ÖPNVKarte": {
|
|
||||||
"url": "https://tile.memomaps.de/tilegen/{z}/{x}/{y}.png",
|
|
||||||
"type": "xyz"
|
|
||||||
},
|
|
||||||
"OpenRailwayMap Standard overlay": {
|
|
||||||
"url": "https://{s}.tiles.openrailwaymap.org/standard/{z}/{x}/{y}.png",
|
|
||||||
"type": "xyz"
|
|
||||||
},
|
|
||||||
"OpenRailwayMap Maxspeed overlay": {
|
|
||||||
"url": "https://{s}.tiles.openrailwaymap.org/maxspeed/{z}/{x}/{y}.png",
|
|
||||||
"type": "xyz"
|
|
||||||
},
|
|
||||||
"OpenRailwayMap Signals overlay": {
|
|
||||||
"url": "https://{s}.tiles.openrailwaymap.org/signals/{z}/{x}/{y}.png",
|
|
||||||
"type": "xyz"
|
|
||||||
},
|
|
||||||
"Waymarked Trails Hiking overlay": {
|
|
||||||
"url": "https://tile.waymarkedtrails.org/hiking/{z}/{x}/{y}.png",
|
|
||||||
"type": "xyz"
|
|
||||||
},
|
|
||||||
"Waymarked Trails Cycling overlay": {
|
|
||||||
"url": "https://tile.waymarkedtrails.org/cycling/{z}/{x}/{y}.png",
|
|
||||||
"type": "xyz"
|
|
||||||
},
|
|
||||||
"Waymarked Trails Riding overlay": {
|
|
||||||
"url": "https://tile.waymarkedtrails.org/riding/{z}/{x}/{y}.png",
|
|
||||||
"type": "xyz"
|
|
||||||
},
|
|
||||||
"OpenSeaMap Seamarks overlay": {
|
|
||||||
"url": "https://tiles.openseamap.org/seamark/{z}/{x}/{y}.png",
|
|
||||||
"type": "xyz"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,89 +0,0 @@
|
||||||
{
|
|
||||||
"CARTO Positron": {
|
|
||||||
"url": "https://cartodb-basemaps-{s}.global.ssl.fastly.net/light_all/{z}/{x}/{y}.png",
|
|
||||||
"type": "xyz"
|
|
||||||
},
|
|
||||||
"CARTO Dark Matter": {
|
|
||||||
"url": "https://cartodb-basemaps-{s}.global.ssl.fastly.net/dark_all/{z}/{x}/{y}.png",
|
|
||||||
"type": "xyz"
|
|
||||||
},
|
|
||||||
"CARTO Voyager": {
|
|
||||||
"url": "https://cartodb-basemaps-{s}.global.ssl.fastly.net/rastertiles/voyager/{z}/{x}/{y}.png",
|
|
||||||
"type": "xyz"
|
|
||||||
},
|
|
||||||
"Geoapify OSM Bright Smooth API key": {
|
|
||||||
"url": "https://maps.geoapify.com/v1/tile/osm-bright-smooth/{z}/{x}/{y}.png?apiKey=YOUR_GEOAPIFY_KEY",
|
|
||||||
"type": "xyz"
|
|
||||||
},
|
|
||||||
"Lima Labs Carto demo": {
|
|
||||||
"url": "https://cdn.lima-labs.com/{z}/{x}/{y}.png?api=demo",
|
|
||||||
"type": "xyz"
|
|
||||||
},
|
|
||||||
"Esri World Imagery": {
|
|
||||||
"url": "https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}",
|
|
||||||
"type": "xyz",
|
|
||||||
"category": "ortho"
|
|
||||||
},
|
|
||||||
"Esri World Street Map": {
|
|
||||||
"url": "https://server.arcgisonline.com/ArcGIS/rest/services/World_Street_Map/MapServer/tile/{z}/{y}/{x}",
|
|
||||||
"type": "xyz"
|
|
||||||
},
|
|
||||||
"Esri World Topo Map": {
|
|
||||||
"url": "https://server.arcgisonline.com/ArcGIS/rest/services/World_Topo_Map/MapServer/tile/{z}/{y}/{x}",
|
|
||||||
"type": "xyz"
|
|
||||||
},
|
|
||||||
"Esri NatGeo World Map": {
|
|
||||||
"url": "https://server.arcgisonline.com/ArcGIS/rest/services/NatGeo_World_Map/MapServer/tile/{z}/{y}/{x}",
|
|
||||||
"type": "xyz"
|
|
||||||
},
|
|
||||||
"Esri World Terrain": {
|
|
||||||
"url": "https://server.arcgisonline.com/ArcGIS/rest/services/World_Terrain_Base/MapServer/tile/{z}/{y}/{x}",
|
|
||||||
"type": "xyz"
|
|
||||||
},
|
|
||||||
"Esri World Shaded Relief": {
|
|
||||||
"url": "https://server.arcgisonline.com/ArcGIS/rest/services/World_Shaded_Relief/MapServer/tile/{z}/{y}/{x}",
|
|
||||||
"type": "xyz"
|
|
||||||
},
|
|
||||||
"Esri World Physical": {
|
|
||||||
"url": "https://server.arcgisonline.com/ArcGIS/rest/services/World_Physical_Map/MapServer/tile/{z}/{y}/{x}",
|
|
||||||
"type": "xyz"
|
|
||||||
},
|
|
||||||
"Esri Ocean Basemap": {
|
|
||||||
"url": "https://server.arcgisonline.com/ArcGIS/rest/services/Ocean/World_Ocean_Base/MapServer/tile/{z}/{y}/{x}",
|
|
||||||
"type": "xyz"
|
|
||||||
},
|
|
||||||
"Esri World Gray Canvas": {
|
|
||||||
"url": "https://server.arcgisonline.com/ArcGIS/rest/services/Canvas/World_Light_Gray_Base/MapServer/tile/{z}/{y}/{x}",
|
|
||||||
"type": "xyz"
|
|
||||||
},
|
|
||||||
"USGS Topo": {
|
|
||||||
"url": "https://basemap.nationalmap.gov/arcgis/rest/services/USGSTopo/MapServer/tile/{z}/{y}/{x}",
|
|
||||||
"type": "xyz"
|
|
||||||
},
|
|
||||||
"USGS Imagery Only": {
|
|
||||||
"url": "https://basemap.nationalmap.gov/arcgis/rest/services/USGSImageryOnly/MapServer/tile/{z}/{y}/{x}",
|
|
||||||
"type": "xyz",
|
|
||||||
"category": "ortho"
|
|
||||||
},
|
|
||||||
"USGS Imagery Topo": {
|
|
||||||
"url": "https://basemap.nationalmap.gov/arcgis/rest/services/USGSImageryTopo/MapServer/tile/{z}/{y}/{x}",
|
|
||||||
"type": "xyz",
|
|
||||||
"category": "ortho"
|
|
||||||
},
|
|
||||||
"USGS Shaded Relief": {
|
|
||||||
"url": "https://basemap.nationalmap.gov/arcgis/rest/services/USGSShadedReliefOnly/MapServer/tile/{z}/{y}/{x}",
|
|
||||||
"type": "xyz"
|
|
||||||
},
|
|
||||||
"USGS Hydrography overlay": {
|
|
||||||
"url": "https://basemap.nationalmap.gov/arcgis/rest/services/USGSHydroCached/MapServer/tile/{z}/{y}/{x}",
|
|
||||||
"type": "xyz"
|
|
||||||
},
|
|
||||||
"ČÚZK Ortofoto ČR Web Mercator": {
|
|
||||||
"url": "https://ags.cuzk.gov.cz/arcgis1/rest/services/ORTOFOTO_WM/MapServer/tile/{z}/{y}/{x}",
|
|
||||||
"type": "xyz"
|
|
||||||
},
|
|
||||||
"ČÚZK Základní topografická mapa ČR Web Mercator": {
|
|
||||||
"url": "https://ags.cuzk.gov.cz/arcgis1/rest/services/ZTM_WM/MapServer/tile/{z}/{y}/{x}",
|
|
||||||
"type": "xyz"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue