(function () { var mapaEl = document.getElementById('map'); var dataEl = document.getElementById('stari-data'); if (!mapaEl || !dataEl || typeof L === 'undefined') { return; } var stari = JSON.parse(dataEl.textContent || '{}'); var maxMesicu = parseInt(mapaEl.getAttribute('data-max'), 10) || 24; var maxPrideleni = parseInt(mapaEl.getAttribute('data-prideleni'), 10) || 12; var geojsonUrl = mapaEl.getAttribute('data-geojson'); var obvodId = mapaEl.getAttribute('data-obvod'); var prihlaseny = mapaEl.getAttribute('data-prihlaseny') === '1'; var rezim = mapaEl.getAttribute('data-filtr'); if (!prihlaseny || (rezim !== 'stari' && rezim !== 'nedokoncene')) { rezim = 'obvody'; } var ZELENA = [27, 158, 62]; var ZLUTA = [230, 184, 0]; var CERVENA = [198, 40, 40]; var SEDA = '#9e9e9e'; var SEDA_HRANICE = '#616161'; var MODRA = '#2652a8'; var MODRA_PLOCHA = '#5c8fd6'; function mix(a, b, t) { return [ Math.round(a[0] + (b[0] - a[0]) * t), Math.round(a[1] + (b[1] - a[1]) * t), Math.round(a[2] + (b[2] - a[2]) * t), ]; } function rgb(kanaly) { return 'rgb(' + kanaly[0] + ',' + kanaly[1] + ',' + kanaly[2] + ')'; } function barvaStari(mesice, stupnice) { var max = stupnice || maxMesicu; var t = mesice == null ? 1 : Math.max(0, Math.min(mesice / max, 1)); if (t < 0.5) { return rgb(mix(ZELENA, ZLUTA, t / 0.5)); } return rgb(mix(ZLUTA, CERVENA, (t - 0.5) / 0.5)); } function infoObvodu(feature) { if (!feature.properties || feature.properties.number == null) { return null; } return stari[String(feature.properties.number)] || null; } function style(feature) { var info = infoObvodu(feature); if (rezim === 'obvody') { return { fillColor: MODRA_PLOCHA, color: '#1d4f91', weight: 2, opacity: 1, fillOpacity: 0.4, }; } if (rezim === 'nedokoncene') { if (info && info.probiha) { var barvaPrideleni = barvaStari(info.prideleni, maxPrideleni); return { fillColor: barvaPrideleni, color: barvaPrideleni, weight: 2, opacity: 1, fillOpacity: 0.55, }; } return { fillColor: '#b0bec5', color: '#90a4ae', weight: 1, opacity: 0.4, dashArray: '3', fillOpacity: 0.04, }; } var mesice = info ? info.mesice : null; var barva = barvaStari(mesice); if (info && info.probiha) { return { fillColor: SEDA, color: SEDA_HRANICE, weight: 2, opacity: 1, fillOpacity: 0.72, }; } return { fillColor: barva, color: barva, weight: 2, opacity: 1, fillOpacity: 0.55, }; } var API_KEY = 'Uw8gm6JPZpnT3GfNnh8adARpQI-WBGy6QaY9g6VhD74'; var mapyCZ = L.tileLayer('https://api.mapy.cz/v1/maptiles/basic/256/{z}/{x}/{y}?apikey=' + API_KEY, { minZoom: 0, maxZoom: 19, attribution: '© Seznam.cz a.s. a další', }); var mapyCZletecka = L.tileLayer('https://api.mapy.cz/v1/maptiles/aerial/256/{z}/{x}/{y}?apikey=' + API_KEY, { minZoom: 0, maxZoom: 19, attribution: '© Seznam.cz a.s. a další', }); var osm = L.tileLayer('https://tile.openstreetmap.org/{z}/{x}/{y}.png', { maxZoom: 19, attribution: '© OpenStreetMap', }); var map = L.map(mapaEl, { center: [50.853501146, 14.8425], zoom: 13, layers: [mapyCZ], }); L.control.layers({ 'Mapy.cz': mapyCZ, 'Mapy.cz (letecká)': mapyCZletecka, 'OpenStreetMap': osm, }).addTo(map); var LogoControl = L.Control.extend({ options: { position: 'bottomleft' }, onAdd: function () { var container = L.DomUtil.create('div'); var link = L.DomUtil.create('a', '', container); link.setAttribute('href', 'http://mapy.cz/'); link.setAttribute('target', '_blank'); link.innerHTML = 'Mapy.cz'; L.DomEvent.disableClickPropagation(link); return container; }, }); new LogoControl().addTo(map); var legendaEl = null; var Legenda = L.Control.extend({ options: { position: 'bottomright' }, onAdd: function () { legendaEl = L.DomUtil.create('div', 'stari-legenda'); legendaEl.innerHTML = obsahLegendy(); L.DomEvent.disableClickPropagation(legendaEl); return legendaEl; }, }); new Legenda().addTo(map); var filtrTlacitka = []; var Filtr = L.Control.extend({ options: { position: 'topright' }, onAdd: function () { var div = L.DomUtil.create('div', 'mapa-filtr'); div.innerHTML = '' + '' + ''; L.DomEvent.disableClickPropagation(div); filtrTlacitka = div.querySelectorAll('button'); filtrTlacitka.forEach(function (tlacitko) { tlacitko.addEventListener('click', function () { nastavRezim(tlacitko.getAttribute('data-rezim')); }); }); return div; }, }); if (prihlaseny) { new Filtr().addTo(map); } function textMesicu(mesice) { if (mesice == null) { return '—'; } return mesice + ' měs.'; } function textBadge(mesice) { return mesice == null ? '—' : mesice + ' měs.'; } function barvaTextu(mesice, stupnice) { var max = stupnice || maxMesicu; var t = mesice == null ? 1 : Math.max(0, Math.min(mesice / max, 1)); return t > 0.72 ? '#fff' : '#1a1a1a'; } function htmlKolecko(text, mesice, sede, stupnice) { var barva = sede ? SEDA : barvaStari(mesice, stupnice); var okraj = sede ? SEDA_HRANICE : barva; var textBarva = sede ? '#1a1a1a' : barvaTextu(mesice, stupnice); return '
' + text + '
'; } function htmlZnacky(cislo, info) { if (rezim === 'obvody') { return '
' + cislo + '
'; } if (rezim === 'nedokoncene') { var prideleni = info ? info.prideleni : null; var barvaPrideleni = barvaStari(prideleni, maxPrideleni); return '
' + htmlKolecko(cislo, prideleni, false, maxPrideleni) + '
' + textBadge(prideleni) + '
' + '
'; } var mesice = info ? info.mesice : null; var html = '
' + htmlKolecko(cislo, mesice, !!(info && info.probiha)); if (!info || !info.probiha) { var barva = barvaStari(mesice); html += '
' + textBadge(mesice) + '
'; } return html + '
'; } function htmlSkupiny(pocet, mesice, sede, stupnice) { return '
' + htmlKolecko(pocet + 'x', mesice, sede, stupnice) + '
'; } function vytvorSkupinu() { return L.markerClusterGroup({ showCoverageOnHover: false, spiderfyOnMaxZoom: true, zoomToBoundsOnClick: true, maxClusterRadius: 46, disableClusteringAtZoom: 17, iconCreateFunction: function (cluster) { var pocet = cluster.getChildCount(); if (rezim === 'obvody') { return L.divIcon({ className: 'obvod-skupina', html: '
' + pocet + 'x
', iconSize: [44, 44], iconAnchor: [22, 22], }); } if (rezim === 'nedokoncene') { var nejPrideleni = 0; var bezPrideleni = false; cluster.getAllChildMarkers().forEach(function (marker) { if (marker.odPrideleni == null) { bezPrideleni = true; } else if (marker.odPrideleni > nejPrideleni) { nejPrideleni = marker.odPrideleni; } }); return L.divIcon({ className: 'obvod-skupina', html: htmlSkupiny(pocet, bezPrideleni ? null : nejPrideleni, false, maxPrideleni), iconSize: [44, 44], iconAnchor: [22, 22], }); } var nej = 0; var bezData = false; var maHotovy = false; cluster.getAllChildMarkers().forEach(function (marker) { if (marker.obvodProbiha) { return; } maHotovy = true; if (marker.obvodMesice == null) { bezData = true; } else if (marker.obvodMesice > nej) { nej = marker.obvodMesice; } }); var sede = !maHotovy; return L.divIcon({ className: 'obvod-skupina', html: htmlSkupiny(pocet, sede || bezData ? null : nej, sede), iconSize: [44, 44], iconAnchor: [22, 22], }); }, }); } var znacky = null; function popupHtml(cislo, info) { if (!prihlaseny) { return 'Obvod č. ' + cislo + ''; } var html = 'Obvod č. ' + cislo + '
'; if (!info || info.vraceno == null) { html += 'Zatím bez propracování'; } else { html += 'Naposledy propracováno ' + info.vraceno + ' (' + textMesicu(info.mesice) + ')'; } if (info && info.probiha) { html += '
Přiděleno ' + (info.prideleniDatum || '—') + ' (' + textMesicu(info.prideleni) + ')'; } if (info && info.url) { html += '
Otevřít obvod'; } return html; } function jeLatLng(hodnota) { return hodnota && typeof hodnota.lat === 'number' && typeof hodnota.lng === 'number'; } function prstence(latlngs) { if (!latlngs || !latlngs.length) { return []; } if (jeLatLng(latlngs[0])) { return [latlngs.map(function (bod) { return [bod.lng, bod.lat]; })]; } if (jeLatLng(latlngs[0][0])) { return latlngs.map(function (prstenec) { return prstenec.map(function (bod) { return [bod.lng, bod.lat]; }); }); } var nej = []; var nejPlocha = -1; latlngs.forEach(function (polygon) { var rings = prstence(polygon); var plocha = rings.length ? Math.abs(plochaPrstence(rings[0])) : 0; if (plocha > nejPlocha) { nejPlocha = plocha; nej = rings; } }); return nej; } function plochaPrstence(prstenec) { var plocha = 0; for (var i = 0, j = prstenec.length - 1; i < prstenec.length; j = i++) { plocha += prstenec[i][0] * prstenec[j][1] - prstenec[j][0] * prstenec[i][1]; } return plocha; } function vzdalenostUsecky(px, py, a, b) { var x = a[0]; var y = a[1]; var dx = b[0] - x; var dy = b[1] - y; if (dx !== 0 || dy !== 0) { var t = ((px - x) * dx + (py - y) * dy) / (dx * dx + dy * dy); if (t > 1) { x = b[0]; y = b[1]; } else if (t > 0) { x += dx * t; y += dy * t; } } dx = px - x; dy = py - y; return dx * dx + dy * dy; } function vzdalenostPolygonu(x, y, prstenceBodu) { var uvnitr = false; var nejmensi = Infinity; prstenceBodu.forEach(function (prstenec) { for (var i = 0, j = prstenec.length - 1; i < prstenec.length; j = i++) { var a = prstenec[i]; var b = prstenec[j]; if ((a[1] > y) !== (b[1] > y) && x < ((b[0] - a[0]) * (y - a[1])) / (b[1] - a[1]) + a[0]) { uvnitr = !uvnitr; } nejmensi = Math.min(nejmensi, vzdalenostUsecky(x, y, a, b)); } }); return (uvnitr ? 1 : -1) * Math.sqrt(nejmensi); } function bunka(x, y, h, prstenceBodu) { var d = vzdalenostPolygonu(x, y, prstenceBodu); return { x: x, y: y, h: h, d: d, max: d + h * Math.SQRT2 }; } function vlozHaldu(halda, bunkaBodu) { halda.push(bunkaBodu); var i = halda.length - 1; while (i > 0) { var rodic = (i - 1) >> 1; if (halda[rodic].max >= halda[i].max) { break; } var tmp = halda[rodic]; halda[rodic] = halda[i]; halda[i] = tmp; i = rodic; } } function vyberHaldu(halda) { var vrchol = halda[0]; var posledni = halda.pop(); if (halda.length && vrchol !== posledni) { halda[0] = posledni; var i = 0; while (true) { var levy = i * 2 + 1; var pravy = levy + 1; var nej = i; if (levy < halda.length && halda[levy].max > halda[nej].max) { nej = levy; } if (pravy < halda.length && halda[pravy].max > halda[nej].max) { nej = pravy; } if (nej === i) { break; } var tmp = halda[i]; halda[i] = halda[nej]; halda[nej] = tmp; i = nej; } } return vrchol; } function teziste(prstenceBodu) { var prstenec = prstenceBodu[0]; var plocha = 0; var x = 0; var y = 0; for (var i = 0, j = prstenec.length - 1; i < prstenec.length; j = i++) { var f = prstenec[i][0] * prstenec[j][1] - prstenec[j][0] * prstenec[i][1]; x += (prstenec[i][0] + prstenec[j][0]) * f; y += (prstenec[i][1] + prstenec[j][1]) * f; plocha += f; } if (plocha === 0) { return [prstenec[0][0], prstenec[0][1]]; } return [x / (3 * plocha), y / (3 * plocha)]; } function bodUvnitr(prstenceBodu) { var minX = Infinity; var minY = Infinity; var maxX = -Infinity; var maxY = -Infinity; prstenceBodu[0].forEach(function (bod) { minX = Math.min(minX, bod[0]); minY = Math.min(minY, bod[1]); maxX = Math.max(maxX, bod[0]); maxY = Math.max(maxY, bod[1]); }); var sirka = maxX - minX; var vyska = maxY - minY; var krok = Math.min(sirka, vyska); if (krok === 0) { return [minX, minY]; } var pul = krok / 2; var halda = []; for (var x = minX; x < maxX; x += krok) { for (var y = minY; y < maxY; y += krok) { vlozHaldu(halda, bunka(x + pul, y + pul, pul, prstenceBodu)); } } var stred = teziste(prstenceBodu); var nej = bunka(stred[0], stred[1], 0, prstenceBodu); var obdelnik = bunka(minX + sirka / 2, minY + vyska / 2, 0, prstenceBodu); if (obdelnik.d > nej.d) { nej = obdelnik; } var presnost = Math.max(krok / 40, 0.00005); var pojistka = 0; while (halda.length && pojistka < 8000) { var aktualni = vyberHaldu(halda); pojistka++; if (aktualni.d > nej.d) { nej = aktualni; } if (aktualni.max - nej.d <= presnost) { continue; } var h = aktualni.h / 2; vlozHaldu(halda, bunka(aktualni.x - h, aktualni.y - h, h, prstenceBodu)); vlozHaldu(halda, bunka(aktualni.x + h, aktualni.y - h, h, prstenceBodu)); vlozHaldu(halda, bunka(aktualni.x - h, aktualni.y + h, h, prstenceBodu)); vlozHaldu(halda, bunka(aktualni.x + h, aktualni.y + h, h, prstenceBodu)); } return [nej.x, nej.y]; } function vnitrniBod(layer) { var rings = prstence(layer.getLatLngs()); if (!rings.length) { return layer.getBounds().getCenter(); } var bod = bodUvnitr(rings); if (vzdalenostPolygonu(bod[0], bod[1], rings) <= 0) { return layer.getBounds().getCenter(); } return L.latLng(bod[1], bod[0]); } function onEachFeature(feature, layer) { var cislo = feature.properties && feature.properties.number != null ? feature.properties.number : ''; var info = infoObvodu(feature); var stred = vnitrniBod(layer); var nedokonceny = !!(info && info.probiha); if (rezim !== 'nedokoncene' || nedokonceny) { var marker = L.marker(stred, { icon: L.divIcon({ className: 'obvod-znacka', html: htmlZnacky(cislo, info), iconSize: [58, 46], iconAnchor: [29, 14], }), interactive: false, keyboard: false, }); marker.obvodMesice = info ? info.mesice : null; marker.odPrideleni = info ? info.prideleni : null; marker.obvodProbiha = nedokonceny; znacky.addLayer(marker); } layer.bindPopup(popupHtml(cislo, info)); layer.on({ mouseover: function (e) { e.target.setStyle({ weight: 4, fillOpacity: 0.8 }); e.target.bringToFront(); }, mouseout: function (e) { geojson.resetStyle(e.target); }, }); } var geojson = null; var geoData = null; function filtrObvodu(feature) { if (!obvodId) { return true; } return feature.properties && String(feature.properties.number) === String(obvodId); } function obsahLegendy() { if (rezim === 'nedokoncene') { return '
Měsíce od začátku přidělení
' + '
' + '
0' + Math.round(maxPrideleni / 2) + '' + maxPrideleni + '+
'; } return '
Měsíce od posledního propracování
' + '
' + '
0' + Math.round(maxMesicu / 2) + '' + maxMesicu + '+
' + '
právě se propracovává
'; } function oznacFiltr() { filtrTlacitka.forEach(function (tlacitko) { tlacitko.classList.toggle('is-active', tlacitko.getAttribute('data-rezim') === rezim); }); if (legendaEl) { legendaEl.style.display = rezim === 'obvody' ? 'none' : ''; if (rezim !== 'obvody') { legendaEl.innerHTML = obsahLegendy(); } } } function prekresli(poprve) { if (geojson) { map.removeLayer(geojson); } if (znacky) { map.removeLayer(znacky); } znacky = vytvorSkupinu(); geojson = L.geoJSON(geoData, { style: style, filter: filtrObvodu, onEachFeature: onEachFeature, }).addTo(map); znacky.addTo(map); oznacFiltr(); if (poprve && geojson.getLayers().length) { map.fitBounds(geojson.getBounds(), { padding: [12, 12], animate: false }); } } function nastavRezim(novy) { if (!prihlaseny || (novy !== 'stari' && novy !== 'nedokoncene')) { novy = 'obvody'; } if (novy === rezim) { return; } rezim = novy; prekresli(false); if (window.history && window.history.replaceState) { var url = new URL(window.location.href); if (rezim === 'obvody') { url.searchParams.delete('filtr'); } else { url.searchParams.set('filtr', rezim); } window.history.replaceState(null, '', url); } } $.getJSON(geojsonUrl, function (data) { geoData = data; prekresli(true); }); L.control.locate({ flyTo: true, strings: { title: 'Moje poloha', metersUnit: 'metrů', feetUnit: 'feet', popup: 'Nacházíš se v okolí {distance} {unit} od tohoto bodu.', outsideMapBoundsMsg: 'Zdá se, že jsi mimo oblast mapy.', }, }).addTo(map); })();