diff --git a/CMakeLists.txt b/CMakeLists.txt index c03e07b..5f0a47b 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,10 +2,24 @@ cmake_minimum_required (VERSION 2.8) project (qlever-mapui) +include(CMakePrintHelpers) + +cmake_print_variables(CMAKE_BUILD_TYPE) + +# only change first char if (CMAKE_BUILD_TYPE) - string(TOUPPER ${CMAKE_BUILD_TYPE} CMAKE_BUILD_TYPE) + string(SUBSTRING ${CMAKE_BUILD_TYPE} 0 1 FIRST_CHAR) + string(TOUPPER ${FIRST_CHAR} FIRST_CHAR) + string(REGEX REPLACE "^.(.*)" "${FIRST_CHAR}\\1" CMAKE_BUILD_TYPE "${CMAKE_BUILD_TYPE}") endif() +# old solution +#if (CMAKE_BUILD_TYPE) +# string(TOUPPER ${CMAKE_BUILD_TYPE} CMAKE_BUILD_TYPE) +#endif() + +cmake_print_variables(CMAKE_BUILD_TYPE) + enable_testing() set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/") diff --git a/src/qlever-petrimaps/GeomCache.cpp b/src/qlever-petrimaps/GeomCache.cpp index 431b1b3..ae76609 100644 --- a/src/qlever-petrimaps/GeomCache.cpp +++ b/src/qlever-petrimaps/GeomCache.cpp @@ -10,6 +10,7 @@ #include #include #include +#include #include "qlever-petrimaps/GeomCache.h" #include "qlever-petrimaps/Misc.h" @@ -116,6 +117,8 @@ size_t GeomCache::writeCbCount(void* contents, size_t size, size_t nmemb, // _____________________________________________________________________________ void GeomCache::parse(const char* c, size_t size) { + _loadStatusStage = _LoadStatusStages::Parse; + const char* start = c; while (c < start + size) { if (_raw.size() < 10000) _raw.push_back(*c); @@ -312,8 +315,7 @@ void GeomCache::parse(const char* c, size_t size) { LOG(INFO) << "[GEOMCACHE] " << "@ row " << _curRow << " (" << std::fixed << std::setprecision(2) - << (static_cast(_curRow) / - static_cast(_totalSize) * 100) + << getLoadStatusPercent() << "%, " << _pointsFSize << " points, " << _linesFSize << " (open) polygons)"; } @@ -339,8 +341,40 @@ void GeomCache::parse(const char* c, size_t size) { } } +double GeomCache::getLoadStatusPercent() { + /* + There are 2 loading stages: Parse, afterwards ParseIds. + Because ParseIds is usually pretty short, we merge the progress of both stages to one total progress. + Progress is calculated by _curRow / _totalSize, which are handled by each stage individually. + */ + if (_totalSize == 0) { + return 0.0; + } + + float parsePercent = 95.0f; + float parseIdsPercent = 5.0f; + float totalPercent = 0.0f; + switch(_loadStatusStage) { + case _LoadStatusStages::Parse: + totalPercent = std::atomic(_curRow) / static_cast(_totalSize) * parsePercent; + break; + case _LoadStatusStages::ParseIds: + totalPercent = parsePercent; + totalPercent += std::atomic(_curRow) / static_cast(_totalSize) * parseIdsPercent; + break; + } + + return totalPercent; +} + +int GeomCache::getLoadStatusStage() { + return _loadStatusStage; +} + // _____________________________________________________________________________ void GeomCache::parseIds(const char* c, size_t size) { + _loadStatusStage = _LoadStatusStages::ParseIds; + size_t lastQid = -1; for (size_t i = 0; i < size; i++) { if (_raw.size() < 10000) _raw.push_back(c[i]); diff --git a/src/qlever-petrimaps/GeomCache.h b/src/qlever-petrimaps/GeomCache.h index 22602c1..f438adc 100644 --- a/src/qlever-petrimaps/GeomCache.h +++ b/src/qlever-petrimaps/GeomCache.h @@ -89,6 +89,9 @@ class GeomCache { return id + 1 < _lines.size() ? _lines[id + 1] : _linePoints.size(); } + double getLoadStatusPercent(); + int getLoadStatusStage(); + private: std::string _backendUrl; CURL* _curl; @@ -97,6 +100,9 @@ class GeomCache { ID _curId; QLEVER_ID_TYPE _maxQid; size_t _curRow, _curUniqueGeom; + + enum _LoadStatusStages {Parse = 1, ParseIds}; + _LoadStatusStages _loadStatusStage; static size_t writeCb(void* contents, size_t size, size_t nmemb, void* userp); static size_t writeCbIds(void* contents, size_t size, size_t nmemb, diff --git a/src/qlever-petrimaps/server/Server.cpp b/src/qlever-petrimaps/server/Server.cpp index 5c7174a..e56948e 100755 --- a/src/qlever-petrimaps/server/Server.cpp +++ b/src/qlever-petrimaps/server/Server.cpp @@ -81,6 +81,8 @@ util::http::Answer Server::handle(const util::http::Req& req, int con) const { a = handlePosReq(params); } else if (cmd == "/export") { a = handleExportReq(params, con); + } else if (cmd == "/loadstatus") { + a = handleLoadStatusReq(params); } else if (cmd == "/build.js") { a = util::http::Answer( "200 OK", std::string(build_js, build_js + sizeof build_js / @@ -745,6 +747,7 @@ util::http::Answer Server::handleLoadReq(const Params& pars) const { LOG(INFO) << "[SERVER] Queried backend is " << backend; + createCache(backend); loadCache(backend); auto answ = util::http::Answer("200 OK", "{}"); @@ -764,6 +767,7 @@ util::http::Answer Server::handleQueryReq(const Params& pars) const { LOG(INFO) << "[SERVER] Queried backend is " << backend; LOG(INFO) << "[SERVER] Query is:\n" << query; + createCache(backend); loadCache(backend); std::string queryId = backend + "$" + query; @@ -1108,6 +1112,22 @@ util::http::Answer Server::handleExportReq(const Params& pars, int sock) const { return aw; } +util::http::Answer Server::handleLoadStatusReq(const Params& pars) const { + if (pars.count("backend") == 0 || pars.find("backend")->second.empty()) + throw std::invalid_argument("No backend (?backend=) specified."); + auto backend = pars.find("backend")->second; + createCache(backend); + std::shared_ptr cache = _caches[backend]; + double loadStatusPercent = cache->getLoadStatusPercent(); + int loadStatusStage = cache->getLoadStatusStage(); + + std::stringstream json; + json << "{\"percent\": " << loadStatusPercent << ", \"stage\": " << loadStatusStage << "}"; + util::http::Answer ans = util::http::Answer("200 OK", json.str()); + + return ans; +} + // _____________________________________________________________________________ void Server::drawPoint(std::vector& points, std::vector& points2, int px, int py, int w, @@ -1140,9 +1160,7 @@ std::string Server::getSessionId() const { return std::to_string(d(rng)); } -// _____________________________________________________________________________ -void Server::loadCache(const std::string& backend) const { - std::shared_ptr reqor; +void Server::createCache(const std::string& backend) const { std::shared_ptr cache; { @@ -1154,6 +1172,12 @@ void Server::loadCache(const std::string& backend) const { _caches[backend] = cache; } } +} + +// _____________________________________________________________________________ +void Server::loadCache(const std::string& backend) const { + //std::shared_ptr reqor; + std::shared_ptr cache = _caches[backend]; try { cache->load(_cacheDir); diff --git a/src/qlever-petrimaps/server/Server.h b/src/qlever-petrimaps/server/Server.h index a2c9444..14e0a5f 100755 --- a/src/qlever-petrimaps/server/Server.h +++ b/src/qlever-petrimaps/server/Server.h @@ -40,7 +40,9 @@ class Server : public util::http::Handler { util::http::Answer handleLoadReq(const Params& pars) const; util::http::Answer handleExportReq(const Params& pars, int sock) const; + util::http::Answer handleLoadStatusReq(const Params& pars) const; + void createCache(const std::string& backend) const; void loadCache(const std::string& backend) const; void clearSession(const std::string& id) const; diff --git a/web/index.html b/web/index.html index b586cb0..15a09a7 100755 --- a/web/index.html +++ b/web/index.html @@ -16,19 +16,28 @@
-
- - - -
-
-
+
+ + + +
+
-
-
Loading results from QLever...
-
-
-
+
+
Loading results from QLever
+
+ +
+
Parsing geometry... (1/2)
+
+
+
0.00%
+
+
+
+
+ + diff --git a/web/script.js b/web/script.js index 7b6a6de..7a2e47f 100755 --- a/web/script.js +++ b/web/script.js @@ -1,26 +1,29 @@ -var sessionId; -var curGeojson; -var curGeojsonId = -1; +let sessionId; +let curGeojson; +let curGeojsonId = -1; -var urlParams = new URLSearchParams(window.location.search); -var qleverBackend = urlParams.get("backend"); -var query = urlParams.get("query"); +let urlParams = new URLSearchParams(window.location.search); +let qleverBackend = urlParams.get("backend"); +let query = urlParams.get("query"); -var map = L.map('m', { +// id of SetInterval to stop loadStatus requests on error or load finish +let loadStatusIntervalId = -1; + +let map = L.map('m', { renderer: L.canvas(), preferCanvas: true }).setView([47.9965, 7.8469], 13); map.attributionControl.setPrefix('University of Freiburg'); -var layerControl = L.control.layers([], [], {collapsed:true, position: 'topleft'}).addTo(map); +let layerControl = L.control.layers([], [], {collapsed:true, position: 'topleft'}).addTo(map); -var osmLayer = L.tileLayer('https://tile.openstreetmap.org/{z}/{x}/{y}.png', { +let osmLayer = L.tileLayer('https://tile.openstreetmap.org/{z}/{x}/{y}.png', { attribution: '© OpenStreetMap', maxZoom: 19, opacity:0.9 }).addTo(map); -var genError = "

Session has been removed from cache.

Resend request

"; +let genError = "

Session has been removed from cache.

Resend request

"; function openPopup(data) { if (data.length > 0) { @@ -71,7 +74,7 @@ function openPopup(data) { // the result value as another. Reformat a bit, so that it looks nice in // an HTML table. let key = variable.substring(1); - if (row[i] == null) { row[i] = "---"; } + if (row[i] == null) { row[i] = "---" } let value = row[i].replace(/\\([()])/g, "$1") .replace(/<((.*)\/(.*))>/, "$3") @@ -116,14 +119,13 @@ function getGeoJsonLayer(geom) { opacity: 1, fillOpacity: 0.2 });} - }) + }); } function showError(error) { error = error.toString(); - console.log(error); document.getElementById("msg").style.display = "block"; - document.getElementById("loader").style.display = "none"; + document.getElementById("load").style.display = "none"; document.getElementById("msg-inner").style.color = "red"; document.getElementById("msg-inner").style.fontSize = "20px"; document.getElementById("msg-inner").innerHTML = error.split("\n")[0]; @@ -188,7 +190,7 @@ function loadMap(id, bounds, numObjects) { layerControl.addBaseLayer(autoLayer, "Auto"); map.on('click', function(e) { - const ll= e.latlng; + const ll = e.latlng; const pos = L.Projection.SphericalMercator.project(ll); const w = map.getPixelBounds().max.x - map.getPixelBounds().min.x; @@ -227,15 +229,65 @@ function loadMap(id, bounds, numObjects) { }); } -console.log("Fetching results...") -fetch('query' + window.location.search) - .then(response => { - if (!response.ok) return response.text().then(text => {throw new Error(text)}); - return response; +function updateLoad(stage, percent) { + const stageElem = document.getElementById("load-stage"); + const barElem = document.getElementById("load-bar"); + const percentElem = document.getElementById("load-percent"); + switch (stage) { + case 1: + stageElem.innerHTML = "Parsing geometry... (1/2)"; + break; + case 2: + stageElem.innerHTML = "Parsing geometry Ids... (2/2)"; + break; + } + barElem.style.width = percent + "%"; + percentElem.innerHTML = percent.toString() + "%"; +} + +function fetchResults() { + console.log("Fetching results..."); + + fetch('query' + window.location.search) + .then(response => { + if (!response.ok) return response.text().then(text => {throw new Error(text)}); + return response; + }) + .then(response => response.json()) + .then(data => { + clearInterval(loadStatusIntervalId); + loadMap(data["qid"], data["bounds"], data["numobjects"]); }) - .then(response => response.json()) - .then(data => loadMap(data["qid"], data["bounds"], data["numobjects"])) - .catch(error => {showError(error);}); + .catch(error => showError(error)); +} + +function fetchLoadStatusInterval(interval) { + fetchLoadStatus(); + loadStatusIntervalId = setInterval(fetchLoadStatus, interval); +} + +async function fetchLoadStatus() { + console.log("Fetching load status..."); + + fetch('loadstatus?backend=' + qleverBackend) + .then(response => { + if (!response.ok) return response.text().then(text => {throw new Error(text)}); + return response; + }) + .then(response => response.json()) + .then(data => { + var stage = data["stage"]; + var percent = parseFloat(data["percent"]).toFixed(2); + updateLoad(stage, percent); + }) + .catch(error => { + showError(error); + clearInterval(loadStatusIntervalId); + }); +} + +fetchResults(); +fetchLoadStatusInterval(1000); document.getElementById("ex-geojson").onclick = function() { if (!sessionId) return; diff --git a/web/style.css b/web/style.css index 491c547..ce7ef73 100755 --- a/web/style.css +++ b/web/style.css @@ -1,112 +1,690 @@ -.leaflet-image-layer,.leaflet-layer,.leaflet-pane,.leaflet-pane>canvas,.leaflet-pane>svg,.leaflet-tile,.leaflet-tile-container,.leaflet-zoom-box{position:absolute;left:0;top:0}.leaflet-container{overflow:hidden}.leaflet-tile{-webkit-user-select:none;-moz-user-select:none;user-select:none;-webkit-user-drag:none}.leaflet-tile::selection{background:0 0}.leaflet-safari .leaflet-tile{image-rendering:-webkit-optimize-contrast}.leaflet-safari .leaflet-tile-container{width:1600px;height:1600px;-webkit-transform-origin:0 0}.leaflet-container .leaflet-overlay-pane svg,.leaflet-container .leaflet-shadow-pane img,.leaflet-container .leaflet-tile,.leaflet-container .leaflet-tile-pane img,.leaflet-container img.leaflet-image-layer{max-width:none!important;max-height:none!important}.leaflet-container.leaflet-touch-zoom{-ms-touch-action:pan-x pan-y;touch-action:pan-x pan-y}.leaflet-container.leaflet-touch-drag{-ms-touch-action:pinch-zoom;touch-action:none;touch-action:pinch-zoom}.leaflet-container.leaflet-touch-drag.leaflet-touch-zoom{-ms-touch-action:none;touch-action:none}.leaflet-container{-webkit-tap-highlight-color:transparent}.leaflet-container a{-webkit-tap-highlight-color:rgba(51,181,229,.4)}.leaflet-tile{filter:inherit;visibility:hidden}.leaflet-tile-loaded{visibility:inherit}.leaflet-zoom-box{width:0;height:0;-moz-box-sizing:border-box;box-sizing:border-box;z-index:800}.leaflet-overlay-pane svg{-moz-user-select:none}.leaflet-pane{z-index:400}.leaflet-tile-pane{z-index:200}.leaflet-overlay-pane{z-index:400}.leaflet-shadow-pane{z-index:500}.leaflet-marker-pane{z-index:600}.leaflet-tooltip-pane{z-index:650}.leaflet-popup-pane{z-index:700}.leaflet-map-pane canvas{z-index:100}.leaflet-map-pane svg{z-index:200}.leaflet-vml-shape{width:1px;height:1px}.lvml{behavior:url(#default#VML);display:inline-block;position:absolute}.leaflet-control{position:relative;z-index:800;pointer-events:visiblePainted;pointer-events:auto}.leaflet-bottom,.leaflet-top{position:absolute;z-index:1000;pointer-events:none}.leaflet-top{top:0}.leaflet-right{right:0}.leaflet-bottom{bottom:0}.leaflet-left{left:0}.leaflet-control{float:left;clear:both}.leaflet-right .leaflet-control{float:right}.leaflet-top .leaflet-control{margin-top:10px}.leaflet-bottom .leaflet-control{margin-bottom:10px}.leaflet-left .leaflet-control{margin-left:10px}.leaflet-right .leaflet-control{margin-right:10px}.leaflet-fade-anim .leaflet-tile{will-change:opacity}.leaflet-fade-anim .leaflet-popup{opacity:0;-webkit-transition:opacity .2s linear;-moz-transition:opacity .2s linear;transition:opacity .2s linear}.leaflet-fade-anim .leaflet-map-pane .leaflet-popup{opacity:1}.leaflet-zoom-animated{-webkit-transform-origin:0 0;-ms-transform-origin:0 0;transform-origin:0 0}.leaflet-zoom-anim .leaflet-zoom-animated{will-change:transform}.leaflet-zoom-anim .leaflet-zoom-animated{-webkit-transition:-webkit-transform .25s cubic-bezier(0,0,.25,1);-moz-transition:-moz-transform .25s cubic-bezier(0,0,.25,1);transition:transform .25s cubic-bezier(0,0,.25,1)}.leaflet-pan-anim .leaflet-tile,.leaflet-zoom-anim .leaflet-tile{-webkit-transition:none;-moz-transition:none;transition:none}.leaflet-zoom-anim .leaflet-zoom-hide{visibility:hidden}.leaflet-interactive{cursor:pointer}.leaflet-grab{cursor:-webkit-grab;cursor:-moz-grab;cursor:grab}.leaflet-control,.leaflet-popup-pane{cursor:auto}.leaflet-dragging .leaflet-grab,.leaflet-dragging .leaflet-grab .leaflet-interactive{cursor:move;cursor:-webkit-grabbing;cursor:-moz-grabbing;cursor:grabbing}.leaflet-image-layer,.leaflet-pane>svg path,.leaflet-tile-container{pointer-events:none}.leaflet-image-layer.leaflet-interactive,.leaflet-pane>svg path.leaflet-interactive,svg.leaflet-image-layer.leaflet-interactive path{pointer-events:visiblePainted;pointer-events:auto}.leaflet-container{background:#ddd;outline:0}.leaflet-container a{color:#0078a8}.leaflet-container a.leaflet-active{outline:2px solid orange}.leaflet-zoom-box{border:2px dotted #38f;background:rgba(255,255,255,.5)}.leaflet-bar{box-shadow:0 1px 5px rgba(0,0,0,.65);border-radius:4px}.leaflet-bar a,.leaflet-bar a:hover{background-color:#fff;border-bottom:1px solid #ccc;width:26px;height:26px;line-height:26px;display:block;text-align:center;text-decoration:none;color:#000}.leaflet-bar a,.leaflet-control-layers-toggle{background-position:50% 50%;background-repeat:no-repeat;display:block}.leaflet-bar a:hover{background-color:#f4f4f4}.leaflet-bar a:first-child{border-top-left-radius:4px;border-top-right-radius:4px}.leaflet-bar a:last-child{border-bottom-left-radius:4px;border-bottom-right-radius:4px;border-bottom:none}.leaflet-bar a.leaflet-disabled{cursor:default;background-color:#f4f4f4;color:#bbb}.leaflet-touch .leaflet-bar a{width:30px;height:30px;line-height:30px}.leaflet-touch .leaflet-bar a:first-child{border-top-left-radius:2px;border-top-right-radius:2px}.leaflet-touch .leaflet-bar a:last-child{border-bottom-left-radius:2px;border-bottom-right-radius:2px}.leaflet-control-zoom-in,.leaflet-control-zoom-out{text-indent:1px}.leaflet-touch .leaflet-control-zoom-in,.leaflet-touch .leaflet-control-zoom-out{font-size:22px}.leaflet-container .leaflet-control-attribution{background:#fff;background:rgba(255,255,255,.7);margin:0}.leaflet-control-attribution{padding:0 5px;color:#333}.leaflet-control-attribution a{text-decoration:none}.leaflet-control-attribution a:hover{text-decoration:underline}.leaflet-container .leaflet-control-attribution{font-size:11px}.leaflet-touch .leaflet-bar,.leaflet-touch .leaflet-control-attribution,.leaflet-touch .leaflet-control-layers{box-shadow:none}.leaflet-touch .leaflet-bar,.leaflet-touch .leaflet-control-layers{border:2px solid rgba(0,0,0,.2);background-clip:padding-box}.leaflet-popup{position:absolute;text-align:center;margin-bottom:20px}.leaflet-popup-content-wrapper{padding:1px;text-align:left;border-radius:12px}.leaflet-popup-content{margin:13px 19px;line-height:1.4}.leaflet-popup-content p{margin:18px 0}.leaflet-popup-tip-container{width:40px;height:20px;position:absolute;left:50%;margin-left:-20px;overflow:hidden;pointer-events:none}.leaflet-popup-tip{width:17px;height:17px;padding:1px;margin:-10px auto 0;-webkit-transform:rotate(45deg);-moz-transform:rotate(45deg);-ms-transform:rotate(45deg);transform:rotate(45deg)}.leaflet-popup-content-wrapper,.leaflet-popup-tip{background:#fff;color:#333;box-shadow:0 3px 14px rgba(0,0,0,.4)}.leaflet-container a.leaflet-popup-close-button{position:absolute;top:0;right:0;padding:5px 5px 0 0;border:none;text-align:center;width:22px;height:18px;font:24px/22px Tahoma,Verdana,sans-serif;color:#c3c3c3;text-decoration:none;font-weight:700;background:0 0}.leaflet-container a.leaflet-popup-close-button:hover{color:#999}.leaflet-popup-scrolled{overflow:auto;border-bottom:1px solid #ddd;border-top:1px solid #ddd}body{padding:0;margin:0;font-family:sans-serif}body,html{height:100%;width:100%}tt{letter-spacing:-.5px}#attr-tbl tr{background-color:#c0f7c0}.stat-label{white-space:nowrap;background:0 0}#attr-tbl .err-10{background-color:red}#attr-tbl .err-9{background-color:#ff1010}#attr-tbl .err-8{background-color:#f92424}#attr-tbl .err-7{background-color:#f93838}#attr-tbl .err-6{background-color:#f56262}#attr-tbl .err-5{background-color:#f38484}.attr-err-info{margin-top:5px;font-size:13px;font-style:italic}.leaflet-popup-content-wrapper{border-radius:5px}#attr-tbl .err-wrap{max-height:100px;display:block;overflow-y:auto}#attr-tbl{margin-top:10px;width:100%}.nmt,.omt,.sugtit{font-style:normal;font-weight:700}#gsn,#gso{margin-top:8px;padding-top:4px;border-top:solid 1px #aaa}#gsn div{background-color:#b6b6e4;border-left:solid 4px #00f;padding:2px;margin:2px;padding-left:5px}#gso div{border-left:solid 4px #78f378;padding:2px;margin:2px;padding-left:5px}#sugg{margin-top:8px;padding-top:4px;border-top:solid 1px #aaa;color:#0000c3}#sugg ul{padding:5px;margin:5px;padding-top:0} #m,main{width:100%;height:100%}#msg {position:absolute;width:400px;border-radius:4px;top:50%;left:50%;margin-left:-200px;margin-top:-150px;background-color:white;border:solid 1px black;text-align:center;z-index:99999;padding:50px;}#m{cursor: pointer;} +.leaflet-image-layer, .leaflet-layer, .leaflet-pane, .leaflet-pane>canvas, .leaflet-pane>svg, .leaflet-tile, .leaflet-tile-container, .leaflet-zoom-box { + position: absolute; + left: 0; + top: 0 +} + +.leaflet-container { + overflow: hidden +} + +.leaflet-tile { + -webkit-user-select: none; + -moz-user-select: none; + user-select: none; + -webkit-user-drag: none +} + +.leaflet-tile::selection { + background: 0 0 +} + +.leaflet-safari .leaflet-tile { + image-rendering: -webkit-optimize-contrast +} + +.leaflet-safari .leaflet-tile-container { + width: 1600px; + height: 1600px; + -webkit-transform-origin: 0 0 +} + +.leaflet-container .leaflet-overlay-pane svg, .leaflet-container .leaflet-shadow-pane img, .leaflet-container .leaflet-tile, .leaflet-container .leaflet-tile-pane img, .leaflet-container img.leaflet-image-layer { + max-width: none !important; + max-height: none !important +} + +.leaflet-container.leaflet-touch-zoom { + -ms-touch-action: pan-x pan-y; + touch-action: pan-x pan-y +} + +.leaflet-container.leaflet-touch-drag { + -ms-touch-action: pinch-zoom; + touch-action: none; + touch-action: pinch-zoom +} + +.leaflet-container.leaflet-touch-drag.leaflet-touch-zoom { + -ms-touch-action: none; + touch-action: none +} + +.leaflet-container { + -webkit-tap-highlight-color: transparent +} + +.leaflet-container a { + -webkit-tap-highlight-color: rgba(51, 181, 229, .4) +} + +.leaflet-tile { + filter: inherit; + visibility: hidden +} + +.leaflet-tile-loaded { + visibility: inherit +} + +.leaflet-zoom-box { + width: 0; + height: 0; + -moz-box-sizing: border-box; + box-sizing: border-box; + z-index: 800 +} + +.leaflet-overlay-pane svg { + -moz-user-select: none +} + +.leaflet-pane { + z-index: 400 +} + +.leaflet-tile-pane { + z-index: 200 +} + +.leaflet-overlay-pane { + z-index: 400 +} + +.leaflet-shadow-pane { + z-index: 500 +} + +.leaflet-marker-pane { + z-index: 600 +} + +.leaflet-tooltip-pane { + z-index: 650 +} + +.leaflet-popup-pane { + z-index: 700 +} + +.leaflet-map-pane canvas { + z-index: 100 +} + +.leaflet-map-pane svg { + z-index: 200 +} + +.leaflet-vml-shape { + width: 1px; + height: 1px +} + +.lvml { + behavior: url(#default#VML); + display: inline-block; + position: absolute +} + +.leaflet-control { + position: relative; + z-index: 800; + pointer-events: visiblePainted; + pointer-events: auto +} + +.leaflet-bottom, .leaflet-top { + position: absolute; + z-index: 1000; + pointer-events: none +} + +.leaflet-top { + top: 0 +} + +.leaflet-right { + right: 0 +} + +.leaflet-bottom { + bottom: 0 +} + +.leaflet-left { + left: 0 +} + +.leaflet-control { + float: left; + clear: both +} + +.leaflet-right .leaflet-control { + float: right +} + +.leaflet-top .leaflet-control { + margin-top: 10px +} + +.leaflet-bottom .leaflet-control { + margin-bottom: 10px +} + +.leaflet-left .leaflet-control { + margin-left: 10px +} + +.leaflet-right .leaflet-control { + margin-right: 10px +} + +.leaflet-fade-anim .leaflet-tile { + will-change: opacity +} + +.leaflet-fade-anim .leaflet-popup { + opacity: 0; + -webkit-transition: opacity .2s linear; + -moz-transition: opacity .2s linear; + transition: opacity .2s linear +} + +.leaflet-fade-anim .leaflet-map-pane .leaflet-popup { + opacity: 1 +} + +.leaflet-zoom-animated { + -webkit-transform-origin: 0 0; + -ms-transform-origin: 0 0; + transform-origin: 0 0 +} + +.leaflet-zoom-anim .leaflet-zoom-animated { + will-change: transform +} + +.leaflet-zoom-anim .leaflet-zoom-animated { + -webkit-transition: -webkit-transform .25s cubic-bezier(0, 0, .25, 1); + -moz-transition: -moz-transform .25s cubic-bezier(0, 0, .25, 1); + transition: transform .25s cubic-bezier(0, 0, .25, 1) +} + +.leaflet-pan-anim .leaflet-tile, .leaflet-zoom-anim .leaflet-tile { + -webkit-transition: none; + -moz-transition: none; + transition: none +} + +.leaflet-zoom-anim .leaflet-zoom-hide { + visibility: hidden +} + +.leaflet-interactive { + cursor: pointer +} + +.leaflet-grab { + cursor: -webkit-grab; + cursor: -moz-grab; + cursor: grab +} + +.leaflet-control, .leaflet-popup-pane { + cursor: auto +} + +.leaflet-dragging .leaflet-grab, .leaflet-dragging .leaflet-grab .leaflet-interactive { + cursor: move; + cursor: -webkit-grabbing; + cursor: -moz-grabbing; + cursor: grabbing +} + +.leaflet-image-layer, .leaflet-pane>svg path, .leaflet-tile-container { + pointer-events: none +} + +.leaflet-image-layer.leaflet-interactive, .leaflet-pane>svg path.leaflet-interactive, svg.leaflet-image-layer.leaflet-interactive path { + pointer-events: visiblePainted; + pointer-events: auto +} + +.leaflet-container { + background: #ddd; + outline: 0 +} + +.leaflet-container a { + color: #0078a8 +} + +.leaflet-container a.leaflet-active { + outline: 2px solid orange +} + +.leaflet-zoom-box { + border: 2px dotted #38f; + background: rgba(255, 255, 255, .5) +} + +.leaflet-bar { + box-shadow: 0 1px 5px rgba(0, 0, 0, .65); + border-radius: 4px +} + +.leaflet-bar a, .leaflet-bar a:hover { + background-color: #fff; + border-bottom: 1px solid #ccc; + width: 26px; + height: 26px; + line-height: 26px; + display: block; + text-align: center; + text-decoration: none; + color: #000 +} + +.leaflet-bar a, .leaflet-control-layers-toggle { + background-position: 50% 50%; + background-repeat: no-repeat; + display: block +} + +.leaflet-bar a:hover { + background-color: #f4f4f4 +} + +.leaflet-bar a:first-child { + border-top-left-radius: 4px; + border-top-right-radius: 4px +} + +.leaflet-bar a:last-child { + border-bottom-left-radius: 4px; + border-bottom-right-radius: 4px; + border-bottom: none +} + +.leaflet-bar a.leaflet-disabled { + cursor: default; + background-color: #f4f4f4; + color: #bbb +} + +.leaflet-touch .leaflet-bar a { + width: 30px; + height: 30px; + line-height: 30px +} + +.leaflet-touch .leaflet-bar a:first-child { + border-top-left-radius: 2px; + border-top-right-radius: 2px +} + +.leaflet-touch .leaflet-bar a:last-child { + border-bottom-left-radius: 2px; + border-bottom-right-radius: 2px +} + +.leaflet-control-zoom-in, .leaflet-control-zoom-out { + text-indent: 1px +} + +.leaflet-touch .leaflet-control-zoom-in, .leaflet-touch .leaflet-control-zoom-out { + font-size: 22px +} + +.leaflet-container .leaflet-control-attribution { + background: #fff; + background: rgba(255, 255, 255, .7); + margin: 0 +} + +.leaflet-control-attribution { + padding: 0 5px; + color: #333 +} + +.leaflet-control-attribution a { + text-decoration: none +} + +.leaflet-control-attribution a:hover { + text-decoration: underline +} + +.leaflet-container .leaflet-control-attribution { + font-size: 11px +} + +.leaflet-touch .leaflet-bar, .leaflet-touch .leaflet-control-attribution, .leaflet-touch .leaflet-control-layers { + box-shadow: none +} + +.leaflet-touch .leaflet-bar, .leaflet-touch .leaflet-control-layers { + border: 2px solid rgba(0, 0, 0, .2); + background-clip: padding-box +} + +.leaflet-popup { + position: absolute; + text-align: center; + margin-bottom: 20px +} + +.leaflet-popup-content-wrapper { + padding: 1px; + text-align: left; + border-radius: 12px +} + +.leaflet-popup-content { + margin: 13px 19px; + line-height: 1.4 +} + +.leaflet-popup-content p { + margin: 18px 0 +} + +.leaflet-popup-tip-container { + width: 40px; + height: 20px; + position: absolute; + left: 50%; + margin-left: -20px; + overflow: hidden; + pointer-events: none +} + +.leaflet-popup-tip { + width: 17px; + height: 17px; + padding: 1px; + margin: -10px auto 0; + -webkit-transform: rotate(45deg); + -moz-transform: rotate(45deg); + -ms-transform: rotate(45deg); + transform: rotate(45deg) +} + +.leaflet-popup-content-wrapper, .leaflet-popup-tip { + background: #fff; + color: #333; + box-shadow: 0 3px 14px rgba(0, 0, 0, .4) +} + +.leaflet-container a.leaflet-popup-close-button { + position: absolute; + top: 0; + right: 0; + padding: 5px 5px 0 0; + border: none; + text-align: center; + width: 22px; + height: 18px; + font: 24px/22px Tahoma, Verdana, sans-serif; + color: #c3c3c3; + text-decoration: none; + font-weight: 700; + background: 0 0 +} + +.leaflet-container a.leaflet-popup-close-button:hover { + color: #999 +} + +.leaflet-popup-scrolled { + overflow: auto; + border-bottom: 1px solid #ddd; + border-top: 1px solid #ddd +} + +body { + padding: 0; + margin: 0; + font-family: sans-serif +} + +body, html { + height: 100%; + width: 100% +} + +tt { + letter-spacing: -.5px +} + +#attr-tbl tr { + background-color: #c0f7c0 +} + +.stat-label { + white-space: nowrap; + background: 0 0 +} + +#attr-tbl .err-10 { + background-color: red +} + +#attr-tbl .err-9 { + background-color: #ff1010 +} + +#attr-tbl .err-8 { + background-color: #f92424 +} + +#attr-tbl .err-7 { + background-color: #f93838 +} + +#attr-tbl .err-6 { + background-color: #f56262 +} + +#attr-tbl .err-5 { + background-color: #f38484 +} + +.attr-err-info { + margin-top: 5px; + font-size: 13px; + font-style: italic +} + +.leaflet-popup-content-wrapper { + border-radius: 5px +} + +#attr-tbl .err-wrap { + max-height: 100px; + display: block; + overflow-y: auto +} + +#attr-tbl { + margin-top: 10px; + width: 100% +} + +.nmt, .omt, .sugtit { + font-style: normal; + font-weight: 700 +} + +#gsn, #gso { + margin-top: 8px; + padding-top: 4px; + border-top: solid 1px #aaa +} + +#gsn div { + background-color: #b6b6e4; + border-left: solid 4px #00f; + padding: 2px; + margin: 2px; + padding-left: 5px +} + +#gso div { + border-left: solid 4px #78f378; + padding: 2px; + margin: 2px; + padding-left: 5px +} + +#sugg { + margin-top: 8px; + padding-top: 4px; + border-top: solid 1px #aaa; + color: #0000c3 +} + +#sugg ul { + padding: 5px; + margin: 5px; + padding-top: 0 +} + +#m, main { + width: 100%; + height: 100% +} + +#m { + cursor: pointer; +} .leaflet-control-layers { - box-shadow: 0 1px 5px rgba(0,0,0,0.4); - background: #fff; - border-radius: 5px; - } + box-shadow: 0 1px 5px rgba(0, 0, 0, 0.4); + background: #fff; + border-radius: 5px; +} + .leaflet-control-layers-toggle { - text-decoration: none; - text-align: center; - width: 36px; - height: 36px; - color: black; - } + text-decoration: none; + text-align: center; + width: 36px; + height: 36px; + color: black; +} + .leaflet-control-layers-toggle:after { - content: "🗺"; - line-height:45px; - font-size:25px; - color: black; - } + content: "🗺"; + line-height: 45px; + font-size: 25px; + color: black; +} + .leaflet-retina .leaflet-control-layers-toggle { - background-image: url(images/layers-2x.png); - background-size: 26px 26px; - } + background-image: url(images/layers-2x.png); + background-size: 26px 26px; +} + .leaflet-touch .leaflet-control-layers-toggle { - width: 44px; - height: 44px; - } -.leaflet-control-layers .leaflet-control-layers-list, -.leaflet-control-layers-expanded .leaflet-control-layers-toggle { - display: none; - } + width: 44px; + height: 44px; +} + +.leaflet-control-layers .leaflet-control-layers-list, .leaflet-control-layers-expanded .leaflet-control-layers-toggle { + display: none; +} + .leaflet-control-layers-expanded .leaflet-control-layers-list { - display: block; - position: relative; - } + display: block; + position: relative; +} + .leaflet-control-layers-expanded { - padding: 6px 10px 6px 6px; - color: #333; - background: #fff; - } + padding: 6px 10px 6px 6px; + color: #333; + background: #fff; +} + .leaflet-control-layers-scrollbar { - overflow-y: scroll; - overflow-x: hidden; - padding-right: 5px; - } + overflow-y: scroll; + overflow-x: hidden; + padding-right: 5px; +} + .leaflet-control-layers-selector { - margin-top: 2px; - position: relative; - top: 1px; - } + margin-top: 2px; + position: relative; + top: 1px; +} + .leaflet-control-layers label { - display: block; - font-size: 13px; - font-size: 1.08333em; - } + display: block; + font-size: 13px; + font-size: 1.08333em; +} + .leaflet-control-layers-separator { - height: 0; - border-top: 1px solid #ddd; - margin: 5px -10px 5px -6px; - } + height: 0; + border-top: 1px solid #ddd; + margin: 5px -10px 5px -6px; +} h1, #msg-inner { - font: 1.5em sans-serif; - margin-bottom: 40px; - opacity: 0.8; + font: 1.5em sans-serif; + margin-bottom: 40px; + opacity: 0.8; +} + +#msg { + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + width: 25%; + border-radius: 4px; + background-color: white; + border: solid 1px black; + text-align: center; + z-index: 99999; + padding: 50px; } #msg-inner-desc { - font: 0.9em mono; - text-align: left; - background-color: #fefefe; - width: 100%; - max-height: 200px; - overflow-y: auto; - overflow-x: auto; -} - -#loader { - display: inline-block; - width: 35px; - height: 35px; - border: 3px solid rgba(0,0,0,.3); - border-radius: 50%; - border-top-color: #fff; - animation: spin 1s ease-in-out infinite; - -webkit-animation: spin 1s ease-in-out infinite; + font: 0.9em mono; + text-align: left; + background-color: #fefefe; + width: 100%; + max-height: 200px; + overflow-y: auto; + overflow-x: auto; } @keyframes spin { - to { -webkit-transform: rotate(360deg); } + to { + -webkit-transform: rotate(360deg); + } } + @-webkit-keyframes spin { - to { -webkit-transform: rotate(360deg); } + to { + -webkit-transform: rotate(360deg); + } } .leaflet-popup-content img { - width:200px; + width: 200px; } .leaflet-popup-content a { - border: none; + border: none; } #ex { - position: absolute; - top: 10px; - right: 10px; - z-index:9999; + position: absolute; + top: 10px; + right: 10px; + z-index: 9999; } #stats { @@ -120,12 +698,57 @@ h1, #msg-inner { background: white; } +#load-status { + display: grid; + + width: 100%; + background-color: white; + + border-radius: 4px; + border: solid 1px black; +} + +#load-bar { + grid-column: 1; + grid-row: 1; + + width: 0%; + height: 30px; + background-color: black; + transition: width 500ms; +} + +#load-percent { + grid-column: 1; + grid-row: 1; + + text-align: center; + font-size: 15px; + line-height: 30px; + color: white; + mix-blend-mode: difference; +} + +#load-spinner { + position: absolute; + right: 8px; + top: 8px; + display: inline-block; + width: 16px; + height: 16px; + border: 3px solid rgba(0, 0, 0, .3); + border-radius: 50%; + border-top-color: #fff; + animation: spin 1s ease-in-out infinite; + -webkit-animation: spin 1s ease-in-out infinite; +} + #stats span { padding: 5px; } #ex button { - padding: 6px 12px; + padding: 6px 12px; margin-bottom: 0; font-size: 15px; -ms-touch-action: manipulation; @@ -143,7 +766,7 @@ h1, #msg-inner { line-height: 1.42857143; text-align: center; white-space: nowrap; - background-color:white; + background-color: white; } #ex button:hover { @@ -151,5 +774,5 @@ h1, #msg-inner { } .export-link { - font-size: 80%; -} + font-size: 80%; +} \ No newline at end of file