Inital commit
102
static/Sidebar/L.Control.Sidebar.css
Normal file
@ -0,0 +1,102 @@
|
||||
.leaflet-sidebar {
|
||||
position: absolute;
|
||||
height: 100%;
|
||||
-webkit-box-sizing: border-box;
|
||||
-moz-box-sizing: border-box;
|
||||
box-sizing: border-box;
|
||||
padding: 10px;
|
||||
z-index: 2000; }
|
||||
.leaflet-sidebar.left {
|
||||
left: -500px;
|
||||
transition: left 0.5s, width 0.5s;
|
||||
padding-right: 0; }
|
||||
.leaflet-sidebar.left.visible {
|
||||
left: 0; }
|
||||
.leaflet-sidebar.right {
|
||||
right: -500px;
|
||||
transition: right 0.5s, width 0.5s;
|
||||
padding-left: 0; }
|
||||
.leaflet-sidebar.right.visible {
|
||||
right: 0; }
|
||||
.leaflet-sidebar > .leaflet-control {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
overflow: auto;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
-webkit-box-sizing: border-box;
|
||||
-moz-box-sizing: border-box;
|
||||
box-sizing: border-box;
|
||||
padding: 8px 24px;
|
||||
font-size: 1.1em;
|
||||
/*background: white;*/
|
||||
box-shadow: 0 1px 7px rgba(0, 0, 0, 0.65);
|
||||
-webkit-border-radius: 4px;
|
||||
border-radius: 4px; }
|
||||
.leaflet-touch .leaflet-sidebar > .leaflet-control {
|
||||
box-shadow: none;
|
||||
border: 2px solid rgba(0, 0, 0, 0.2);
|
||||
background-clip: padding-box; }
|
||||
@media (max-width: 767px) {
|
||||
.leaflet-sidebar {
|
||||
width: 100%;
|
||||
padding: 0; }
|
||||
.leaflet-sidebar.left.visible ~ .leaflet-left {
|
||||
left: 100%; }
|
||||
.leaflet-sidebar.right.visible ~ .leaflet-right {
|
||||
right: 100%; }
|
||||
.leaflet-sidebar.left {
|
||||
left: -100%; }
|
||||
.leaflet-sidebar.left.visible {
|
||||
left: 0; }
|
||||
.leaflet-sidebar.right {
|
||||
right: -100%; }
|
||||
.leaflet-sidebar.right.visible {
|
||||
right: 0; }
|
||||
.leaflet-sidebar > .leaflet-control {
|
||||
box-shadow: none;
|
||||
-webkit-border-radius: 0;
|
||||
border-radius: 0; }
|
||||
.leaflet-touch .leaflet-sidebar > .leaflet-control {
|
||||
border: 0; } }
|
||||
@media (min-width: 768px) and (max-width: 991px) {
|
||||
.leaflet-sidebar {
|
||||
width: 305px; }
|
||||
.leaflet-sidebar.left.visible ~ .leaflet-left {
|
||||
left: 305px; }
|
||||
.leaflet-sidebar.right.visible ~ .leaflet-right {
|
||||
right: 305px; } }
|
||||
@media (min-width: 992px) and (max-width: 1199px) {
|
||||
.leaflet-sidebar {
|
||||
width: 390px; }
|
||||
.leaflet-sidebar.left.visible ~ .leaflet-left {
|
||||
left: 390px; }
|
||||
.leaflet-sidebar.right.visible ~ .leaflet-right {
|
||||
right: 390px; } }
|
||||
@media (min-width: 1200px) {
|
||||
.leaflet-sidebar {
|
||||
width: 460px; }
|
||||
.leaflet-sidebar.left.visible ~ .leaflet-left {
|
||||
left: 460px; }
|
||||
.leaflet-sidebar.right.visible ~ .leaflet-right {
|
||||
right: 460px; } }
|
||||
.leaflet-sidebar .close {
|
||||
position: absolute;
|
||||
right: 20px;
|
||||
top: 20px;
|
||||
width: 31px;
|
||||
height: 31px;
|
||||
color: #333;
|
||||
font-size: 25px;
|
||||
line-height: 1em;
|
||||
text-align: center;
|
||||
background: white;
|
||||
-webkit-border-radius: 16px;
|
||||
border-radius: 16px;
|
||||
cursor: pointer;
|
||||
z-index: 1000; }
|
||||
|
||||
.leaflet-left {
|
||||
transition: left 0.5s; }
|
||||
|
||||
.leaflet-right {
|
||||
transition: right 0.5s; }
|
202
static/Sidebar/L.Control.Sidebar.js
Normal file
@ -0,0 +1,202 @@
|
||||
L.Control.Sidebar = L.Control.extend({
|
||||
|
||||
includes: L.Evented.prototype || L.Mixin.Events,
|
||||
|
||||
options: {
|
||||
closeButton: true,
|
||||
position: 'left',
|
||||
autoPan: true,
|
||||
},
|
||||
|
||||
initialize: function (placeholder, options) {
|
||||
L.setOptions(this, options);
|
||||
|
||||
// Find content container
|
||||
var content = this._contentContainer = L.DomUtil.get(placeholder);
|
||||
|
||||
// Remove the content container from its original parent
|
||||
if(content.parentNode != undefined){
|
||||
content.parentNode.removeChild(content);
|
||||
}
|
||||
var l = 'leaflet-';
|
||||
|
||||
// Create sidebar container
|
||||
var container = this._container =
|
||||
L.DomUtil.create('div', l + 'sidebar ' + this.options.position);
|
||||
|
||||
// Style and attach content container
|
||||
L.DomUtil.addClass(content, l + 'control');
|
||||
container.appendChild(content);
|
||||
|
||||
// Create close button and attach it if configured
|
||||
if (this.options.closeButton) {
|
||||
var close = this._closeButton =
|
||||
L.DomUtil.create('a', 'close', container);
|
||||
close.innerHTML = '×';
|
||||
}
|
||||
},
|
||||
|
||||
addTo: function (map) {
|
||||
var container = this._container;
|
||||
var content = this._contentContainer;
|
||||
|
||||
// Attach event to close button
|
||||
if (this.options.closeButton) {
|
||||
var close = this._closeButton;
|
||||
|
||||
L.DomEvent.on(close, 'click', this.hide, this);
|
||||
}
|
||||
|
||||
L.DomEvent
|
||||
.on(container, 'transitionend',
|
||||
this._handleTransitionEvent, this)
|
||||
.on(container, 'webkitTransitionEnd',
|
||||
this._handleTransitionEvent, this);
|
||||
|
||||
// Attach sidebar container to controls container
|
||||
var controlContainer = map._controlContainer;
|
||||
controlContainer.insertBefore(container, controlContainer.firstChild);
|
||||
|
||||
this._map = map;
|
||||
|
||||
// Make sure we don't drag the map when we interact with the content
|
||||
var stop = L.DomEvent.stopPropagation;
|
||||
var fakeStop = L.DomEvent._fakeStop || stop;
|
||||
L.DomEvent
|
||||
.on(content, 'contextmenu', stop)
|
||||
.on(content, 'click', fakeStop)
|
||||
.on(content, 'mousedown', stop)
|
||||
.on(content, 'touchstart', stop)
|
||||
.on(content, 'dblclick', fakeStop)
|
||||
.on(content, 'mousewheel', stop)
|
||||
.on(content, 'wheel', stop)
|
||||
.on(content, 'scroll', stop)
|
||||
.on(content, 'MozMousePixelScroll', stop);
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
removeFrom: function (map) {
|
||||
//if the control is visible, hide it before removing it.
|
||||
this.hide();
|
||||
|
||||
var container = this._container;
|
||||
var content = this._contentContainer;
|
||||
|
||||
// Remove sidebar container from controls container
|
||||
var controlContainer = map._controlContainer;
|
||||
controlContainer.removeChild(container);
|
||||
|
||||
//disassociate the map object
|
||||
this._map = null;
|
||||
|
||||
// Unregister events to prevent memory leak
|
||||
var stop = L.DomEvent.stopPropagation;
|
||||
var fakeStop = L.DomEvent._fakeStop || stop;
|
||||
L.DomEvent
|
||||
.off(content, 'contextmenu', stop)
|
||||
.off(content, 'click', fakeStop)
|
||||
.off(content, 'mousedown', stop)
|
||||
.off(content, 'touchstart', stop)
|
||||
.off(content, 'dblclick', fakeStop)
|
||||
.off(content, 'mousewheel', stop)
|
||||
.off(content, 'wheel', stop)
|
||||
.off(content, 'scroll', stop)
|
||||
.off(content, 'MozMousePixelScroll', stop);
|
||||
|
||||
L.DomEvent
|
||||
.off(container, 'transitionend',
|
||||
this._handleTransitionEvent, this)
|
||||
.off(container, 'webkitTransitionEnd',
|
||||
this._handleTransitionEvent, this);
|
||||
|
||||
if (this._closeButton && this._close) {
|
||||
var close = this._closeButton;
|
||||
|
||||
L.DomEvent.off(close, 'click', this.hide, this);
|
||||
}
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
isVisible: function () {
|
||||
return L.DomUtil.hasClass(this._container, 'visible');
|
||||
},
|
||||
|
||||
show: function () {
|
||||
if (!this.isVisible()) {
|
||||
L.DomUtil.addClass(this._container, 'visible');
|
||||
if (this.options.autoPan) {
|
||||
this._map.panBy([-this.getOffset() / 2, 0], {
|
||||
duration: 0.5
|
||||
});
|
||||
}
|
||||
this.fire('show');
|
||||
}
|
||||
},
|
||||
|
||||
hide: function (e) {
|
||||
if (this.isVisible()) {
|
||||
L.DomUtil.removeClass(this._container, 'visible');
|
||||
if (this.options.autoPan) {
|
||||
this._map.panBy([this.getOffset() / 2, 0], {
|
||||
duration: 0.5
|
||||
});
|
||||
}
|
||||
this.fire('hide');
|
||||
}
|
||||
if(e) {
|
||||
L.DomEvent.stopPropagation(e);
|
||||
}
|
||||
},
|
||||
|
||||
toggle: function () {
|
||||
if (this.isVisible()) {
|
||||
this.hide();
|
||||
} else {
|
||||
this.show();
|
||||
}
|
||||
},
|
||||
|
||||
getContainer: function () {
|
||||
return this._contentContainer;
|
||||
},
|
||||
|
||||
getCloseButton: function () {
|
||||
return this._closeButton;
|
||||
},
|
||||
|
||||
setContent: function (content) {
|
||||
var container = this.getContainer();
|
||||
|
||||
if (typeof content === 'string') {
|
||||
container.innerHTML = content;
|
||||
} else {
|
||||
// clean current content
|
||||
while (container.firstChild) {
|
||||
container.removeChild(container.firstChild);
|
||||
}
|
||||
|
||||
container.appendChild(content);
|
||||
}
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
getOffset: function () {
|
||||
if (this.options.position === 'right') {
|
||||
return -this._container.offsetWidth;
|
||||
} else {
|
||||
return this._container.offsetWidth;
|
||||
}
|
||||
},
|
||||
|
||||
_handleTransitionEvent: function (e) {
|
||||
if (e.propertyName == 'left' || e.propertyName == 'right')
|
||||
this.fire(this.isVisible() ? 'shown' : 'hidden');
|
||||
}
|
||||
});
|
||||
|
||||
L.control.sidebar = function (placeholder, options) {
|
||||
return new L.Control.Sidebar(placeholder, options);
|
||||
};
|
158
static/Sidebar/L.Control.Sidebar.scss
Normal file
@ -0,0 +1,158 @@
|
||||
$threshold-lg: 1200px;
|
||||
$threshold-md: 992px;
|
||||
$threshold-sm: 768px;
|
||||
|
||||
$width-lg: 460px;
|
||||
$width-md: 390px;
|
||||
$width-sm: 305px;
|
||||
$width-xs: 100%;
|
||||
|
||||
$transition-duration: 0.5s;
|
||||
|
||||
@mixin border-radius($border-radius) {
|
||||
-webkit-border-radius: $border-radius;
|
||||
border-radius: $border-radius;
|
||||
}
|
||||
|
||||
@mixin box-sizing($box-sizing) {
|
||||
-webkit-box-sizing: $box-sizing;
|
||||
-moz-box-sizing: $box-sizing;
|
||||
box-sizing: $box-sizing;
|
||||
}
|
||||
|
||||
@mixin widths($width) {
|
||||
width: $width;
|
||||
|
||||
&.left.visible ~ .leaflet-left {
|
||||
left: $width;
|
||||
}
|
||||
|
||||
&.right.visible ~ .leaflet-right {
|
||||
right: $width;
|
||||
}
|
||||
}
|
||||
|
||||
.leaflet-sidebar {
|
||||
position: absolute;
|
||||
height: 100%;
|
||||
|
||||
@include box-sizing(border-box);
|
||||
padding: 10px;
|
||||
|
||||
z-index: 2000;
|
||||
|
||||
&.left {
|
||||
left: -500px;
|
||||
transition: left $transition-duration, width $transition-duration;
|
||||
|
||||
padding-right: 0;
|
||||
|
||||
&.visible {
|
||||
left: 0;
|
||||
}
|
||||
}
|
||||
|
||||
&.right {
|
||||
right: -500px;
|
||||
transition: right $transition-duration, width $transition-duration;
|
||||
|
||||
padding-left: 0;
|
||||
|
||||
&.visible {
|
||||
right: 0;
|
||||
}
|
||||
}
|
||||
|
||||
& > .leaflet-control {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
|
||||
overflow: auto;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
|
||||
@include box-sizing(border-box);
|
||||
padding: 8px 24px;
|
||||
|
||||
font-size: 1.1em;
|
||||
|
||||
background: white;
|
||||
box-shadow: 0 1px 7px rgba(0,0,0,0.65);
|
||||
@include border-radius(4px);
|
||||
|
||||
.leaflet-touch & {
|
||||
box-shadow: none;
|
||||
border: 2px solid rgba(0,0,0,0.2);
|
||||
background-clip: padding-box;
|
||||
}
|
||||
}
|
||||
|
||||
@media(max-width:$threshold-sm - 1px) {
|
||||
@include widths($width-xs);
|
||||
|
||||
padding: 0;
|
||||
|
||||
&.left {
|
||||
left: -$width-xs;
|
||||
|
||||
&.visible {
|
||||
left: 0;
|
||||
}
|
||||
}
|
||||
|
||||
&.right {
|
||||
right: -$width-xs;
|
||||
|
||||
&.visible {
|
||||
right: 0;
|
||||
}
|
||||
}
|
||||
|
||||
& > .leaflet-control {
|
||||
box-shadow: none;
|
||||
@include border-radius(0);
|
||||
|
||||
.leaflet-touch & {
|
||||
border: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media(min-width:$threshold-sm) and (max-width:$threshold-md - 1px) {
|
||||
@include widths($width-sm);
|
||||
}
|
||||
|
||||
@media(min-width:$threshold-md) and (max-width:$threshold-lg - 1px) {
|
||||
@include widths($width-md);
|
||||
}
|
||||
|
||||
@media(min-width:$threshold-lg) {
|
||||
@include widths($width-lg);
|
||||
}
|
||||
|
||||
.close {
|
||||
position: absolute;
|
||||
right: 20px;
|
||||
top: 20px;
|
||||
width: 31px;
|
||||
height: 31px;
|
||||
|
||||
color: #333;
|
||||
font-size: 25pt;
|
||||
line-height: 1em;
|
||||
text-align: center;
|
||||
background: white;
|
||||
@include border-radius(16px);
|
||||
cursor: pointer;
|
||||
|
||||
// https://github.com/Turbo87/leaflet-sidebar/issues/36
|
||||
z-index: 1000;
|
||||
}
|
||||
}
|
||||
|
||||
.leaflet-left {
|
||||
transition: left $transition-duration;
|
||||
}
|
||||
|
||||
.leaflet-right {
|
||||
transition: right $transition-duration;
|
||||
}
|
2
static/browserconfig.xml
Normal file
@ -0,0 +1,2 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<browserconfig><msapplication><tile><square70x70logo src="/favicon/ms-icon-70x70.png"/><square150x150logo src="/favicon/ms-icon-150x150.png"/><square310x310logo src="/favicon/ms-icon-310x310.png"/><TileColor>#ffffff</TileColor></tile></msapplication></browserconfig>
|
106
static/css/mainMap.css
Normal file
@ -0,0 +1,106 @@
|
||||
body,
|
||||
html {
|
||||
background-color: white;
|
||||
height: 100%;
|
||||
margin: 0px;
|
||||
}
|
||||
.inspector {
|
||||
margin: 0px;
|
||||
height: 100vh;
|
||||
width: 29%;
|
||||
float: right;
|
||||
position: fixed;
|
||||
right: 0px;
|
||||
top: 0px;
|
||||
border: 1px solid rgba(97, 97, 97, 0.486);
|
||||
border-radius: 2px;
|
||||
margin: 5px;
|
||||
padding: 4px;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
.fullheight {
|
||||
height: 100%;
|
||||
}
|
||||
.map {
|
||||
margin: 0px;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
z-index: 1;
|
||||
padding: 0px;
|
||||
/*float: left;*/
|
||||
}
|
||||
|
||||
.lds-ripple {
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
width: 80px;
|
||||
height: 80px;
|
||||
}
|
||||
.lds-ripple div {
|
||||
position: absolute;
|
||||
border: 4px solid #fed;
|
||||
opacity: 1;
|
||||
border-radius: 50%;
|
||||
animation: lds-ripple 1s cubic-bezier(0, 0.2, 0.8, 1) infinite;
|
||||
}
|
||||
.lds-ripple div:nth-child(2) {
|
||||
animation-delay: -0.5s;
|
||||
}
|
||||
@keyframes lds-ripple {
|
||||
0% {
|
||||
top: 36px;
|
||||
left: 36px;
|
||||
width: 0;
|
||||
height: 0;
|
||||
opacity: 1;
|
||||
}
|
||||
100% {
|
||||
top: 0px;
|
||||
left: 0px;
|
||||
width: 72px;
|
||||
height: 72px;
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.dropdown:hover .dropdown-menu {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.reportBtn {
|
||||
cursor: pointer;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.animate-right {
|
||||
position: relative;
|
||||
animation: animateright 0.6s;
|
||||
}
|
||||
|
||||
.animate-right-back {
|
||||
position: relative;
|
||||
animation: animaterightBack 0.6s;
|
||||
}
|
||||
@keyframes animateright {
|
||||
from {
|
||||
right: -300px;
|
||||
opacity: 0;
|
||||
}
|
||||
to {
|
||||
right: 0;
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@keyframes animaterightBack {
|
||||
from {
|
||||
right: 0;
|
||||
opacity: 1;
|
||||
}
|
||||
to {
|
||||
right: -300px;
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
3
static/css/tailwindTemp.css
Normal file
@ -0,0 +1,3 @@
|
||||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
BIN
static/favicon/android-icon-144x144.png
Normal file
After Width: | Height: | Size: 8.1 KiB |
BIN
static/favicon/android-icon-192x192.png
Normal file
After Width: | Height: | Size: 8.9 KiB |
BIN
static/favicon/android-icon-36x36.png
Normal file
After Width: | Height: | Size: 2.4 KiB |
BIN
static/favicon/android-icon-48x48.png
Normal file
After Width: | Height: | Size: 2.9 KiB |
BIN
static/favicon/android-icon-72x72.png
Normal file
After Width: | Height: | Size: 4.1 KiB |
BIN
static/favicon/android-icon-96x96.png
Normal file
After Width: | Height: | Size: 5.3 KiB |
BIN
static/favicon/apple-icon-114x114.png
Normal file
After Width: | Height: | Size: 6.3 KiB |
BIN
static/favicon/apple-icon-120x120.png
Normal file
After Width: | Height: | Size: 6.5 KiB |
BIN
static/favicon/apple-icon-144x144.png
Normal file
After Width: | Height: | Size: 8.1 KiB |
BIN
static/favicon/apple-icon-152x152.png
Normal file
After Width: | Height: | Size: 8.6 KiB |
BIN
static/favicon/apple-icon-180x180.png
Normal file
After Width: | Height: | Size: 10 KiB |
BIN
static/favicon/apple-icon-57x57.png
Normal file
After Width: | Height: | Size: 3.3 KiB |
BIN
static/favicon/apple-icon-60x60.png
Normal file
After Width: | Height: | Size: 3.4 KiB |
BIN
static/favicon/apple-icon-72x72.png
Normal file
After Width: | Height: | Size: 4.1 KiB |
BIN
static/favicon/apple-icon-76x76.png
Normal file
After Width: | Height: | Size: 4.3 KiB |
BIN
static/favicon/apple-icon-precomposed.png
Normal file
After Width: | Height: | Size: 9.9 KiB |
BIN
static/favicon/apple-icon.png
Normal file
After Width: | Height: | Size: 9.9 KiB |
2
static/favicon/browserconfig.xml
Normal file
@ -0,0 +1,2 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<browserconfig><msapplication><tile><square70x70logo src="/ms-icon-70x70.png"/><square150x150logo src="/ms-icon-150x150.png"/><square310x310logo src="/ms-icon-310x310.png"/><TileColor>#ffffff</TileColor></tile></msapplication></browserconfig>
|
BIN
static/favicon/favicon-16x16.png
Normal file
After Width: | Height: | Size: 1.8 KiB |
BIN
static/favicon/favicon-32x32.png
Normal file
After Width: | Height: | Size: 2.2 KiB |
BIN
static/favicon/favicon-96x96.png
Normal file
After Width: | Height: | Size: 5.3 KiB |
BIN
static/favicon/favicon.ico
Normal file
After Width: | Height: | Size: 1.1 KiB |
BIN
static/favicon/ms-icon-144x144.png
Normal file
After Width: | Height: | Size: 8.1 KiB |
BIN
static/favicon/ms-icon-150x150.png
Normal file
After Width: | Height: | Size: 8.4 KiB |
BIN
static/favicon/ms-icon-310x310.png
Normal file
After Width: | Height: | Size: 22 KiB |
BIN
static/favicon/ms-icon-70x70.png
Normal file
After Width: | Height: | Size: 3.9 KiB |
BIN
static/favicon/oldLogo/android-icon-144x144.png
Normal file
After Width: | Height: | Size: 10 KiB |
BIN
static/favicon/oldLogo/android-icon-192x192.png
Normal file
After Width: | Height: | Size: 12 KiB |
BIN
static/favicon/oldLogo/android-icon-36x36.png
Normal file
After Width: | Height: | Size: 2.4 KiB |
BIN
static/favicon/oldLogo/android-icon-48x48.png
Normal file
After Width: | Height: | Size: 3.2 KiB |
BIN
static/favicon/oldLogo/android-icon-72x72.png
Normal file
After Width: | Height: | Size: 4.5 KiB |
BIN
static/favicon/oldLogo/android-icon-96x96.png
Normal file
After Width: | Height: | Size: 6.3 KiB |
BIN
static/favicon/oldLogo/apple-icon-114x114.png
Normal file
After Width: | Height: | Size: 7.7 KiB |
BIN
static/favicon/oldLogo/apple-icon-120x120.png
Normal file
After Width: | Height: | Size: 8.3 KiB |
BIN
static/favicon/oldLogo/apple-icon-144x144.png
Normal file
After Width: | Height: | Size: 10 KiB |
BIN
static/favicon/oldLogo/apple-icon-152x152.png
Normal file
After Width: | Height: | Size: 11 KiB |
BIN
static/favicon/oldLogo/apple-icon-180x180.png
Normal file
After Width: | Height: | Size: 14 KiB |
BIN
static/favicon/oldLogo/apple-icon-57x57.png
Normal file
After Width: | Height: | Size: 3.6 KiB |
BIN
static/favicon/oldLogo/apple-icon-60x60.png
Normal file
After Width: | Height: | Size: 3.8 KiB |
BIN
static/favicon/oldLogo/apple-icon-72x72.png
Normal file
After Width: | Height: | Size: 4.5 KiB |
BIN
static/favicon/oldLogo/apple-icon-76x76.png
Normal file
After Width: | Height: | Size: 4.8 KiB |
BIN
static/favicon/oldLogo/apple-icon-precomposed.png
Normal file
After Width: | Height: | Size: 13 KiB |
BIN
static/favicon/oldLogo/apple-icon.png
Normal file
After Width: | Height: | Size: 13 KiB |
BIN
static/favicon/oldLogo/favicon-16x16.png
Normal file
After Width: | Height: | Size: 1.6 KiB |
BIN
static/favicon/oldLogo/favicon-32x32.png
Normal file
After Width: | Height: | Size: 2.3 KiB |
BIN
static/favicon/oldLogo/favicon-96x96.png
Normal file
After Width: | Height: | Size: 6.3 KiB |
BIN
static/favicon/oldLogo/ms-icon-144x144.png
Normal file
After Width: | Height: | Size: 10 KiB |
BIN
static/favicon/oldLogo/ms-icon-150x150.png
Normal file
After Width: | Height: | Size: 11 KiB |
BIN
static/favicon/oldLogo/ms-icon-310x310.png
Normal file
After Width: | Height: | Size: 30 KiB |
BIN
static/favicon/oldLogo/ms-icon-70x70.png
Normal file
After Width: | Height: | Size: 4.4 KiB |
BIN
static/favicon/oldLogo/old/android-icon-192x192.png
Normal file
After Width: | Height: | Size: 8.7 KiB |
BIN
static/favicon/oldLogo/old/apple-icon-114x114.png
Normal file
After Width: | Height: | Size: 4.2 KiB |
BIN
static/favicon/oldLogo/old/apple-icon-120x120.png
Normal file
After Width: | Height: | Size: 4.5 KiB |
BIN
static/favicon/oldLogo/old/apple-icon-144x144.png
Normal file
After Width: | Height: | Size: 5.9 KiB |
BIN
static/favicon/oldLogo/old/apple-icon-152x152.png
Normal file
After Width: | Height: | Size: 6.4 KiB |
BIN
static/favicon/oldLogo/old/apple-icon-180x180.png
Normal file
After Width: | Height: | Size: 8.0 KiB |
BIN
static/favicon/oldLogo/old/apple-icon-57x57.png
Normal file
After Width: | Height: | Size: 1.8 KiB |
BIN
static/favicon/oldLogo/old/apple-icon-60x60.png
Normal file
After Width: | Height: | Size: 1.9 KiB |
BIN
static/favicon/oldLogo/old/apple-icon-72x72.png
Normal file
After Width: | Height: | Size: 2.4 KiB |
BIN
static/favicon/oldLogo/old/apple-icon-76x76.png
Normal file
After Width: | Height: | Size: 2.6 KiB |
BIN
static/favicon/oldLogo/old/favicon-16x16.png
Normal file
After Width: | Height: | Size: 423 B |
BIN
static/favicon/oldLogo/old/favicon-256x256.png
Normal file
After Width: | Height: | Size: 12 KiB |
BIN
static/favicon/oldLogo/old/favicon-32x32.png
Normal file
After Width: | Height: | Size: 959 B |
BIN
static/favicon/oldLogo/old/favicon-96x96.png
Normal file
After Width: | Height: | Size: 3.4 KiB |
BIN
static/favicon/oldLogo/old/favicon.ico
Normal file
After Width: | Height: | Size: 1.1 KiB |
BIN
static/favicon/oldLogo/old/ms-icon-144x144.png
Normal file
After Width: | Height: | Size: 5.9 KiB |
BIN
static/favicon/oldLogo/old/ms-icon-150x150.png
Normal file
After Width: | Height: | Size: 6.3 KiB |
BIN
static/favicon/oldLogo/old/ms-icon-310x310.png
Normal file
After Width: | Height: | Size: 13 KiB |
BIN
static/favicon/oldLogo/old/ms-icon-70x70.png
Normal file
After Width: | Height: | Size: 2.4 KiB |
BIN
static/img/DJI_0361Copyright.JPG
Normal file
After Width: | Height: | Size: 4.5 MiB |
BIN
static/img/cctv.png
Normal file
After Width: | Height: | Size: 12 KiB |
BIN
static/img/marker-icon.png
Normal file
After Width: | Height: | Size: 1.4 KiB |
1
static/img/pointsight_concept_dot.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg id="Ebene_1" data-name="Ebene 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 2000 2000"><defs><style>.cls-1{fill:#e30613;}.cls-2{fill:none;stroke:#fff;stroke-miterlimit:10;stroke-width:19px;}</style></defs><circle class="cls-1" cx="990.4" cy="1000" r="558.07"/><path class="cls-2" d="M950.58,864.56c-2.41,7.4-11.44,25-15.39,37.63-6.22,20-9.37,30.16-11.47,39.29a273.68,273.68,0,0,0-6.26,41,257.38,257.38,0,0,0,1.39,51.46c2.83,21.71,7.77,37.37,12.87,53.54,5.35,17,12.94,35.77,17.32,45.9"/><path class="cls-2" d="M1004.39,841.34c3.27,6.92,7.81,17,12.51,29.55,18.88,50.24,22.46,91.46,23.3,102.92a348.33,348.33,0,0,1-1.74,68.15,354.63,354.63,0,0,1-37.9,120.31"/><path class="cls-2" d="M1097.57,787.45c6.24,12.63,13.89,29.31,21.56,49.37,5.86,15.35,13.48,35.5,19.82,62.59a471.22,471.22,0,0,1,8.69,151.59,442.55,442.55,0,0,1-13.21,66.76,462.49,462.49,0,0,1-37.21,93.19"/><path class="cls-2" d="M1152.16,761.37a465.83,465.83,0,0,1,22.6,46.59,454.65,454.65,0,0,1,19.47,56.68c.86,3.18,4.18,15.63,7.65,33.37A563.18,563.18,0,0,1,1212,982.16a503.51,503.51,0,0,1-3.82,84.84,524,524,0,0,1-19.82,86.23,549.18,549.18,0,0,1-33,81"/><polyline class="cls-2" points="1234.95 717.12 690.7 999.02 1234.43 1282.88"/></svg>
|
After Width: | Height: | Size: 1.2 KiB |
BIN
static/img/signal.png
Normal file
After Width: | Height: | Size: 21 KiB |
BIN
static/img/temperature.png
Normal file
After Width: | Height: | Size: 6.9 KiB |
BIN
static/img/wifi.png
Normal file
After Width: | Height: | Size: 15 KiB |
9
static/js/leaflet-search/leaflet-search.js
Normal file
1
static/js/leaflet-search/leaflet-search.js.map
Normal file
89
static/js/main.js
Normal file
@ -0,0 +1,89 @@
|
||||
|
||||
(function ($) {
|
||||
"use strict";
|
||||
|
||||
|
||||
/*==================================================================
|
||||
[ Focus input ]*/
|
||||
$('.input100').each(function(){
|
||||
$(this).on('blur', function(){
|
||||
if($(this).val().trim() != "") {
|
||||
$(this).addClass('has-val');
|
||||
}
|
||||
else {
|
||||
$(this).removeClass('has-val');
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
/*==================================================================
|
||||
[ Validate ]*/
|
||||
var input = $('.validate-input .input100');
|
||||
|
||||
$('.validate-form').on('submit',function(){
|
||||
var check = true;
|
||||
|
||||
for(var i=0; i<input.length; i++) {
|
||||
if(validate(input[i]) == false){
|
||||
showValidate(input[i]);
|
||||
check=false;
|
||||
}
|
||||
}
|
||||
|
||||
return check;
|
||||
});
|
||||
|
||||
|
||||
$('.validate-form .input100').each(function(){
|
||||
$(this).focus(function(){
|
||||
hideValidate(this);
|
||||
});
|
||||
});
|
||||
|
||||
function validate (input) {
|
||||
if($(input).attr('type') == 'email' || $(input).attr('name') == 'email') {
|
||||
if($(input).val().trim().match(/^([a-zA-Z0-9_\-\.]+)@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.)|(([a-zA-Z0-9\-]+\.)+))([a-zA-Z]{1,5}|[0-9]{1,3})(\]?)$/) == null) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if($(input).val().trim() == ''){
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function showValidate(input) {
|
||||
var thisAlert = $(input).parent();
|
||||
|
||||
$(thisAlert).addClass('alert-validate');
|
||||
}
|
||||
|
||||
function hideValidate(input) {
|
||||
var thisAlert = $(input).parent();
|
||||
|
||||
$(thisAlert).removeClass('alert-validate');
|
||||
}
|
||||
|
||||
/*==================================================================
|
||||
[ Show pass ]*/
|
||||
var showPass = 0;
|
||||
$('.btn-show-pass').on('click', function(){
|
||||
if(showPass == 0) {
|
||||
$(this).next('input').attr('type','text');
|
||||
$(this).find('i').removeClass('zmdi-eye');
|
||||
$(this).find('i').addClass('zmdi-eye-off');
|
||||
showPass = 1;
|
||||
}
|
||||
else {
|
||||
$(this).next('input').attr('type','password');
|
||||
$(this).find('i').addClass('zmdi-eye');
|
||||
$(this).find('i').removeClass('zmdi-eye-off');
|
||||
showPass = 0;
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
|
||||
})(jQuery);
|
589
static/js/map.js
Normal file
@ -0,0 +1,589 @@
|
||||
/* eslint-disable no-undef */
|
||||
|
||||
let retryConnection = false;
|
||||
|
||||
var markers = L.markerClusterGroup({
|
||||
chunkedLoading: true,
|
||||
removeOutsideVisibleBounds: true,
|
||||
});
|
||||
|
||||
// Prepare everything we need for the map
|
||||
let theMarker = L.Marker.extend({
|
||||
options: {
|
||||
id: "-1",
|
||||
},
|
||||
});
|
||||
// Icons
|
||||
const defaultIcon = L.icon({
|
||||
iconUrl: "/img/marker-icon.png",
|
||||
shadowUrl: "",
|
||||
iconSize: [25, 41], // size of the icon
|
||||
shadowSize: [41, 41], // size of the shadow
|
||||
iconAnchor: [12, 41], // point of the icon which will correspond to marker's location
|
||||
popupAnchor: [1, -34], // point from which the popup should open relative to the iconAnchor
|
||||
});
|
||||
|
||||
const signalIcon = L.icon({
|
||||
iconUrl: "/img/signal.png",
|
||||
shadowUrl: "",
|
||||
|
||||
iconSize: [30, 30], // size of the icon
|
||||
shadowSize: [0, 0], // size of the shadow
|
||||
iconAnchor: [15, 15], // point of the icon which will correspond to marker's location
|
||||
shadowAnchor: [0, 0], // the same for the shadow
|
||||
popupAnchor: [0, 0], // point from which the popup should open relative to the iconAnchor
|
||||
});
|
||||
|
||||
const temperatureIcon = L.icon({
|
||||
iconUrl: "/img/temperature.png",
|
||||
shadowUrl: "",
|
||||
|
||||
iconSize: [30, 30], // size of the icon
|
||||
shadowSize: [0, 0], // size of the shadow
|
||||
iconAnchor: [15, 15], // point of the icon which will correspond to marker's location
|
||||
shadowAnchor: [0, 0], // the same for the shadow
|
||||
popupAnchor: [0, 0], // point from which the popup should open relative to the iconAnchor
|
||||
});
|
||||
|
||||
const cctvIcon = L.icon({
|
||||
iconUrl: "/img/cctv.png",
|
||||
shadowUrl: "",
|
||||
|
||||
iconSize: [30, 30], // size of the icon
|
||||
shadowSize: [0, 0], // size of the shadow
|
||||
iconAnchor: [15, 15], // point of the icon which will correspond to marker's location
|
||||
shadowAnchor: [0, 0], // the same for the shadow
|
||||
popupAnchor: [0, 0], // point from which the popup should open relative to the iconAnchor
|
||||
});
|
||||
|
||||
const wifiIcon = L.icon({
|
||||
iconUrl: "/img/wifi.png",
|
||||
shadowUrl: "",
|
||||
|
||||
iconSize: [30, 30], // size of the icon
|
||||
shadowSize: [0, 0], // size of the shadow
|
||||
iconAnchor: [15, 15], // point of the icon which will correspond to marker's location
|
||||
shadowAnchor: [0, 0], // the same for the shadow
|
||||
popupAnchor: [0, 0], // point from which the popup should open relative to the iconAnchor
|
||||
});
|
||||
|
||||
function showPosition(position) {
|
||||
mymap.setView(
|
||||
new L.LatLng(position.coords.latitude, position.coords.longitude),
|
||||
10
|
||||
);
|
||||
}
|
||||
// Share a point
|
||||
function sharePOI(id) {
|
||||
const url = "https://pointsight.project-name-here.de/#" + id;
|
||||
sidebar.prevContent = sidebar._contentContainer.innerHTML;
|
||||
navigator.clipboard.writeText(url);
|
||||
makeToastNotification(
|
||||
"Copy successful",
|
||||
"The link to this point has been copied to your clipboard"
|
||||
);
|
||||
}
|
||||
|
||||
function prepareSidebar(point_id, panTo = false) {
|
||||
const rawData = httpGet(
|
||||
"/api/retrieve?uid=" +
|
||||
point_id +
|
||||
"&key=b03f8aaf-1f32-4d9e-914a-9a50f904833d"
|
||||
);
|
||||
if (rawData.length > 0 && !rawData.includes("502 Bad Gateway")) {
|
||||
retryConnection = false;
|
||||
try {
|
||||
toggleModal("popup-modal-no-conn", false);
|
||||
retryConnection = false;
|
||||
} catch (error) {
|
||||
error;
|
||||
}
|
||||
const moreData = JSON.parse(rawData)[0][0];
|
||||
// Inject toolbar
|
||||
let inspector =
|
||||
'<i class="fas fa-flag reportBtn" style="padding: 4px;" onclick="reportPOI(\'' +
|
||||
point_id +
|
||||
"')\"></i>";
|
||||
inspector +=
|
||||
'<i class="fas fa-share-alt reportBtn" style="padding: 4px;" onclick="sharePOI(\'' +
|
||||
point_id +
|
||||
"')\"></i>";
|
||||
console.warn(moreData);
|
||||
if (moreData.type == "webcam-iframe") {
|
||||
// Prepare the template
|
||||
inspector += httpGet("/templates/inspectorContentIframe.html");
|
||||
inspector = inspector.replaceAll("#TITLE", moreData.titel);
|
||||
inspector = inspector.replaceAll("#URL", moreData.url);
|
||||
inspector = inspector.replaceAll("#URL", moreData.url);
|
||||
} else if (moreData.type == "webcam-image") {
|
||||
// Prepare the template
|
||||
inspector += httpGet("/templates/inspectorContentImage.html");
|
||||
inspector = inspector.replaceAll("#TITLE", moreData.titel);
|
||||
inspector = inspector.replaceAll("#URL", moreData.url);
|
||||
} else if (moreData.type == "iframe") {
|
||||
// Prepare the template
|
||||
inspector += httpGet("/templates/inspectorContentIframe.html");
|
||||
inspector = inspector.replaceAll("#TITLE", moreData.titel);
|
||||
inspector = inspector.replaceAll("#URL", moreData.url);
|
||||
inspector = inspector.replaceAll("#URL", moreData.url);
|
||||
} else if (moreData.type == "request-info") {
|
||||
// Prepare the template
|
||||
inspector += httpGet("/templates/inspectorGeneral.html");
|
||||
inspector = inspector.replaceAll("#TITLE", moreData.object.titel);
|
||||
inspector = inspector.replaceAll("#description", httpGet(moreData.url));
|
||||
} else {
|
||||
inspector += httpGet("/templates/inspectorGeneral.html");
|
||||
inspector = inspector.replaceAll("#TITLE", moreData.titel);
|
||||
inspector = inspector.replaceAll("#description", moreData.description);
|
||||
}
|
||||
// document.getElementById("inspector").innerHTML = inspector;
|
||||
|
||||
sidebar.setContent(inspector);
|
||||
sidebar.show();
|
||||
if (panTo) {
|
||||
mymap.panTo([moreData.location.x, moreData.location.y]);
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
if (!retryConnection) {
|
||||
toggleModal("popup-modal-no-conn", true);
|
||||
}
|
||||
|
||||
retryConnection = true;
|
||||
} catch (error) {
|
||||
error;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Handles click actions for markers
|
||||
function onClick(e) {
|
||||
prepareSidebar(this.options.object.uid);
|
||||
}
|
||||
|
||||
const form = document.getElementById("reportForm");
|
||||
form.addEventListener("submit", (event) => {
|
||||
// submit event detected
|
||||
event.preventDefault();
|
||||
console.log("Report done by users");
|
||||
// Change the UI
|
||||
document.getElementById("reportBtnText").style.display = "none";
|
||||
document.getElementById("loadingSpinner").style.display = "block";
|
||||
document.getElementById("submitBtn").disabled = true;
|
||||
// Get all values
|
||||
const formy = new FormData(form);
|
||||
const reason = formy.get("reason");
|
||||
const email = formy.get("email");
|
||||
const pointId = document.getElementById("pointId").innerHTML;
|
||||
const baseUrl =
|
||||
"/api/internal/report?key=b03f8aaf-1f32-4d9e-914a-9a50f904833d&";
|
||||
let reqUrl =
|
||||
baseUrl + "reason=" + reason + "&mail=" + email + "&point_id=" + pointId;
|
||||
const response = httpGet(reqUrl);
|
||||
const reponseParsed = JSON.parse(response);
|
||||
if (reponseParsed.status == "success") {
|
||||
setTimeout(() => {
|
||||
document.getElementById("loadingDone").style.display = "block";
|
||||
document.getElementById("loadingSpinner").style.display = "none";
|
||||
}, 1000);
|
||||
setTimeout(() => {
|
||||
document.getElementById("reportBtnText").style.display = "block";
|
||||
document.getElementById("loadingSpinner").style.display = "none";
|
||||
document.getElementById("submitBtn").disabled = false;
|
||||
document.getElementById("loadingDone").style.display = "none";
|
||||
toggleModal("report-modal", false);
|
||||
form.reset();
|
||||
makeToastNotification("Report successful", "Thank you for your report.");
|
||||
}, 2000);
|
||||
} else {
|
||||
if (reponseParsed.message == "Invalid mail") {
|
||||
setTimeout(() => {
|
||||
document.getElementById("reportBtnText").style.display = "block";
|
||||
document.getElementById("loadingSpinner").style.display = "none";
|
||||
document.getElementById("loadingDone").style.display = "none";
|
||||
document.getElementById("submitBtn").disabled = false;
|
||||
toggleModal("report-modal", false);
|
||||
form.reset();
|
||||
|
||||
document.getElementById("Geomodal-content").innerHTML =
|
||||
"It seemed like you provided an invalid mail address. Please try again.";
|
||||
toggleModal("popup-modal", true);
|
||||
}, 1000);
|
||||
} else {
|
||||
setTimeout(() => {
|
||||
document.getElementById("reportBtnText").style.display = "block";
|
||||
document.getElementById("loadingSpinner").style.display = "none";
|
||||
document.getElementById("loadingDone").style.display = "none";
|
||||
document.getElementById("submitBtn").disabled = false;
|
||||
toggleModal("report-modal", false);
|
||||
form.reset();
|
||||
|
||||
document.getElementById("Geomodal-content").innerHTML =
|
||||
"Something went wrong, please try again later";
|
||||
toggleModal("popup-modal", true);
|
||||
}, 1000);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
function reportPOI(poi_id) {
|
||||
document.getElementById("pointId").innerHTML = poi_id;
|
||||
toggleModal("report-modal", true);
|
||||
/*const url = "/api/internal/report&key=b03f8aaf-1f32-4d9e-914a-9a50f904833d&"
|
||||
console.log(poi_id)*/
|
||||
}
|
||||
function httpGet(theUrl) {
|
||||
var xmlHttp = new XMLHttpRequest();
|
||||
xmlHttp.open("GET", theUrl, false); // false for synchronous request
|
||||
xmlHttp.send(null);
|
||||
return xmlHttp.responseText;
|
||||
}
|
||||
|
||||
function httpGetTriggerForMapData(theUrl) {
|
||||
var xmlHttp = new XMLHttpRequest();
|
||||
xmlHttp.open("GET", theUrl, true); // Doing it asynchronous
|
||||
xmlHttp.send(null);
|
||||
xmlHttp.onerror = function (e) {
|
||||
console.log(e);
|
||||
};
|
||||
xmlHttp.onloadend = function (e) {
|
||||
setTimeout(function () {
|
||||
if (
|
||||
xmlHttp.responseText.length > 0 &&
|
||||
!xmlHttp.responseText.includes("502 Bad Gateway")
|
||||
) {
|
||||
retryConnection = false;
|
||||
try {
|
||||
toggleModal("popup-modal-no-conn", false);
|
||||
retryConnection = false;
|
||||
} catch (error) {
|
||||
error;
|
||||
}
|
||||
response = xmlHttp.responseText;
|
||||
allMarks = 0;
|
||||
response = JSON.parse(response);
|
||||
allMarks = response;
|
||||
|
||||
markerList = [];
|
||||
for (h in response) {
|
||||
item = response[h];
|
||||
let mIcon = defaultIcon;
|
||||
if (item.icon == "signalIcon") {
|
||||
mIcon = signalIcon;
|
||||
} else if (item.icon == "cctvIcon") {
|
||||
mIcon = cctvIcon;
|
||||
} else if (item.icon == "wifiIcon") {
|
||||
mIcon = wifiIcon;
|
||||
} else if (item.icon == "temperatureIcon") {
|
||||
mIcon = temperatureIcon;
|
||||
}
|
||||
|
||||
var marker = new theMarker([item.location.x, item.location.y], {
|
||||
icon: mIcon,
|
||||
object: item,
|
||||
}).on("click", onClick);
|
||||
markerList.push(marker);
|
||||
}
|
||||
// response.forEach(addPin);
|
||||
markers.clearLayers();
|
||||
markers.addLayers(markerList);
|
||||
mymap.addLayer(markers);
|
||||
syncBtn.state("default"); // Make sure the button is back to default
|
||||
} else {
|
||||
try {
|
||||
if (!retryConnection) {
|
||||
toggleModal("popup-modal-no-conn", true);
|
||||
}
|
||||
|
||||
retryConnection = true;
|
||||
} catch (error) {
|
||||
error;
|
||||
}
|
||||
}
|
||||
}, 50);
|
||||
};
|
||||
}
|
||||
|
||||
// Try to find where to user is
|
||||
function home() {
|
||||
if (navigator.geolocation) {
|
||||
setTimeout(function () {
|
||||
navigator.geolocation.getCurrentPosition(showPosition);
|
||||
}, 200);
|
||||
} else {
|
||||
console.warn("Geolocation of user could not be fetched");
|
||||
}
|
||||
}
|
||||
|
||||
home();
|
||||
|
||||
let allMarks = [];
|
||||
var layerGroup = L.layerGroup().addTo(mymap);
|
||||
var scale = L.control.scale().addTo(mymap);
|
||||
var locator = L.control
|
||||
.locate({
|
||||
onLocationError: function (err) {
|
||||
console.log(err);
|
||||
let tip = err.message;
|
||||
if (err.message.indexOf("User denied Geolocation") > -1) {
|
||||
tip =
|
||||
"You have denied the location request. Please allow it in your browser settings.";
|
||||
}
|
||||
document.getElementById("Geomodal-content").innerHTML = tip;
|
||||
toggleModal("popup-modal", true);
|
||||
},
|
||||
})
|
||||
.addTo(mymap);
|
||||
|
||||
/*mymap.addControl(
|
||||
new L.Control.Fullscreen({
|
||||
title: {
|
||||
false: "View Fullscreen",
|
||||
true: "Exit Fullscreen",
|
||||
},
|
||||
})
|
||||
);*/
|
||||
|
||||
var sidebar = L.control.sidebar("sidebar", {
|
||||
closeButton: true,
|
||||
position: "right",
|
||||
});
|
||||
mymap.addControl(sidebar);
|
||||
|
||||
var sidebar2 = L.control.sidebar("sidebar-left", {
|
||||
// Filter one
|
||||
closeButton: true,
|
||||
position: "left",
|
||||
});
|
||||
mymap.addControl(sidebar2);
|
||||
// sidebar2.setContent(httpGet("/templates/filterPage.html"));
|
||||
|
||||
L.easyButton("fa-filter", function (btn, map) {
|
||||
if (sidebar2.isVisible()) {
|
||||
sidebar2.hide();
|
||||
} else {
|
||||
sidebar2.show();
|
||||
}
|
||||
}).addTo(mymap);
|
||||
|
||||
syncBtn = L.easyButton({
|
||||
states: [
|
||||
{
|
||||
stateName: "default", // name the state
|
||||
icon: "fa-sync", // and define its properties
|
||||
title: "Reload POIs", // like its title
|
||||
onClick: function (btn, map) {
|
||||
// and its callback
|
||||
updatePois(); // Update all da fancy POIs
|
||||
btn.state("loading"); // change state on click!
|
||||
},
|
||||
},
|
||||
{
|
||||
stateName: "loading",
|
||||
icon: "fa-sync fa-spin",
|
||||
title: "Reloading...",
|
||||
},
|
||||
],
|
||||
});
|
||||
syncBtn.addTo(mymap);
|
||||
|
||||
searchBtn = L.easyButton({
|
||||
states: [
|
||||
{
|
||||
stateName: "default", // name the state
|
||||
icon: "fa-search", // and define its properties
|
||||
title: "Search", // like its title
|
||||
onClick: function (btn, map) {
|
||||
// and its callback
|
||||
sear.toggle();
|
||||
btn.state("search"); // change state on click!
|
||||
},
|
||||
},
|
||||
{
|
||||
stateName: "search",
|
||||
icon: "fa-search fa-spin",
|
||||
title: "Hide search",
|
||||
onClick: function (btn, map) {
|
||||
// and its callback
|
||||
sear.toggle();
|
||||
btn.state("default"); // change state on click!
|
||||
},
|
||||
},
|
||||
],
|
||||
});
|
||||
searchBtn.addTo(mymap);
|
||||
|
||||
// Start getting the pois
|
||||
setTimeout(updatePois, 500);
|
||||
var additionalFilters = "";
|
||||
function updatePois() {
|
||||
// Create a filter string
|
||||
const enabledFilters = [];
|
||||
try {
|
||||
for (fi in tagsAvail) {
|
||||
const tag = tagsAvail[fi];
|
||||
if (document.getElementById("tag_" + tag).checked ) {
|
||||
enabledFilters.push(tag);
|
||||
}
|
||||
}
|
||||
additionalFilters =
|
||||
'{"conjunction": "OR", "filters": [["tag","' + enabledFilters.join('"],["tag","') + '"]]}';
|
||||
} catch (error) {
|
||||
console.log("Filter sidebar seems not ready yet");
|
||||
}
|
||||
|
||||
console.log(additionalFilters);
|
||||
const bounds = mymap.getBounds();
|
||||
httpGetTriggerForMapData(
|
||||
"/api/getPOI?boundingEast=" +
|
||||
bounds.getNorthEast().lat +
|
||||
";" +
|
||||
bounds.getNorthEast().lng +
|
||||
"&boundingWest=" +
|
||||
bounds.getSouthWest().lat +
|
||||
";" +
|
||||
bounds.getSouthWest().lng +
|
||||
"&key=b03f8aaf-1f32-4d9e-914a-9a50f904833d&filter=" +
|
||||
additionalFilters
|
||||
);
|
||||
}
|
||||
|
||||
let prevZoom = mymap.getZoom();
|
||||
let prevCenter = mymap.getCenter();
|
||||
let hasCenterChanged = false;
|
||||
let maxZoomReached = mymap.getZoom();
|
||||
|
||||
setTimeout(function () {
|
||||
prevCenter = mymap.getCenter();
|
||||
prevZoom = mymap.getZoom();
|
||||
}, 200);
|
||||
|
||||
function getDistanceBetweenCoordinates(lat1, lon1, lat2, lon2) {
|
||||
var R = 6371; // Radius of the earth in km
|
||||
var dLat = deg2rad(lat2 - lat1); // deg2rad below
|
||||
var dLon = deg2rad(lon2 - lon1);
|
||||
var a =
|
||||
Math.sin(dLat / 2) * Math.sin(dLat / 2) +
|
||||
Math.cos(deg2rad(lat1)) *
|
||||
Math.cos(deg2rad(lat2)) *
|
||||
Math.sin(dLon / 2) *
|
||||
Math.sin(dLon / 2);
|
||||
var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
|
||||
var d = R * c; // Distance in km
|
||||
return d;
|
||||
}
|
||||
|
||||
function deg2rad(deg) {
|
||||
return deg * (Math.PI / 180);
|
||||
}
|
||||
|
||||
mymap.on("dragend", function () {
|
||||
console.info(
|
||||
getDistanceBetweenCoordinates(
|
||||
prevCenter.lat,
|
||||
prevCenter.lng,
|
||||
mymap.getCenter().lat,
|
||||
mymap.getCenter().lng
|
||||
)
|
||||
);
|
||||
if (
|
||||
getDistanceBetweenCoordinates(
|
||||
prevCenter.lat,
|
||||
prevCenter.lng,
|
||||
mymap.getCenter().lat,
|
||||
mymap.getCenter().lng
|
||||
) >= 20
|
||||
) {
|
||||
setTimeout(updatePois, 2);
|
||||
console.info("Updating POIs");
|
||||
}
|
||||
prevCenter = mymap.getCenter();
|
||||
maxZoomReached = mymap.getZoom();
|
||||
hasCenterChanged = true;
|
||||
});
|
||||
|
||||
mymap.on("zoomend", function () {
|
||||
console.info(mymap.getZoom() - prevZoom);
|
||||
prevZoom = mymap.getZoom();
|
||||
|
||||
if (mymap.getZoom() <= maxZoomReached) {
|
||||
maxZoomReached = mymap.getZoom();
|
||||
console.info("Updating POIs");
|
||||
setTimeout(updatePois, 2);
|
||||
} else {
|
||||
if (hasCenterChanged == false) {
|
||||
veryLongIntegerVariableWhichNoOneWillEverUseHopefully = 42;
|
||||
} else {
|
||||
console.info("Updating POIs");
|
||||
setTimeout(updatePois, 2);
|
||||
}
|
||||
}
|
||||
hasCenterChanged = false;
|
||||
});
|
||||
|
||||
function applyFilter() {
|
||||
const val = document.getElementById("filter").value;
|
||||
console.log(val);
|
||||
additionalFilters =
|
||||
'{"filters": [["tag", "' + val + '"]], "conjunction": "OR"}'; // {"filters": [["tag", "webcam"]], "conjunction": "OR"}
|
||||
updatePois();
|
||||
}
|
||||
|
||||
setTimeout(function () {
|
||||
let lat = -1;
|
||||
let lng = -1;
|
||||
let zoom = 5;
|
||||
let shouldThings = 0;
|
||||
let point_id = "";
|
||||
if (window.location.href.indexOf("#") > -1) {
|
||||
point_id = window.location.href.split("#")[1];
|
||||
prepareSidebar(point_id, true);
|
||||
setTimeout(updatePois, 500);
|
||||
} else {
|
||||
window.location.search
|
||||
.substr(1)
|
||||
.split("&")
|
||||
.forEach(function (item) {
|
||||
const param = item.split("=");
|
||||
if (param[0] === "lat" && _.isFinite(param[1])) {
|
||||
lat = param[1];
|
||||
shouldThings++;
|
||||
} else if (param[0] === "lng" && _.isFinite(param[1])) {
|
||||
lng = param[1];
|
||||
shouldThings++;
|
||||
} else if (param[0] === "zoom" && _.isFinite(param[1])) {
|
||||
zoom = param[1];
|
||||
shouldThings++;
|
||||
}
|
||||
if (shouldThings >= 2) {
|
||||
mymap.flyTo([lat, lng], zoom);
|
||||
console.log(lat, lng, zoom);
|
||||
}
|
||||
});
|
||||
}
|
||||
}, 500);
|
||||
|
||||
setInterval(function () {
|
||||
if (retryConnection) {
|
||||
updatePois();
|
||||
}
|
||||
}, 5000);
|
||||
|
||||
mymap.on("contextmenu.show", (e) => {
|
||||
mymap.contextmenu.removeItem(0);
|
||||
mymap.contextmenu.insertItem(
|
||||
{
|
||||
text:
|
||||
"<b class='background-color=\"red\"'>" +
|
||||
e.latlng.lat.toFixed(4) +
|
||||
", " +
|
||||
e.latlng.lng.toFixed(4) +
|
||||
"</b>",
|
||||
callback: copyLocation,
|
||||
},
|
||||
0
|
||||
);
|
||||
});
|
||||
sear = L.control.search({ position: "topleft" });
|
||||
|
||||
mymap.addControl(sear);
|
1
static/js/qrcode.min.js
vendored
Normal file
74
static/js/site.js
Normal file
@ -0,0 +1,74 @@
|
||||
/* eslint-disable no-undef */
|
||||
function httpGet(theUrl) {
|
||||
var xmlHttp = new XMLHttpRequest();
|
||||
xmlHttp.open("GET", theUrl, false); // false for synchronous request
|
||||
try {
|
||||
xmlHttp.send(null);
|
||||
} catch (error) {
|
||||
try {
|
||||
if (!retryConnection) {
|
||||
toggleModal("popup-modal-no-conn", true);
|
||||
}
|
||||
|
||||
retryConnection = true;
|
||||
} catch (error) {
|
||||
error;
|
||||
}
|
||||
}
|
||||
|
||||
return xmlHttp.responseText;
|
||||
}
|
||||
|
||||
function home() {
|
||||
if (navigator.geolocation) {
|
||||
setTimeout(function () {
|
||||
navigator.geolocation.getCurrentPosition(showPosition);
|
||||
}, 200);
|
||||
} else {
|
||||
console.warn("Geolocation of user could not be fetched");
|
||||
}
|
||||
}
|
||||
|
||||
function on() {
|
||||
document.getElementById("overlay").style.display = "block";
|
||||
}
|
||||
|
||||
function off() {
|
||||
document.getElementById("overlay").style.display = "none";
|
||||
}
|
||||
|
||||
function makeToastNotification(title, message) {
|
||||
document.getElementById("notificationToast").style.display = "block";
|
||||
document.getElementById("toast_title").innerHTML = title;
|
||||
document.getElementById("toast_desc").innerHTML = message;
|
||||
try {
|
||||
setTimeout(function () {
|
||||
document
|
||||
.getElementById("notificationToast")
|
||||
.classList.remove("animate-right");
|
||||
document
|
||||
.getElementById("notificationToast")
|
||||
.classList.add("animate-right-back");
|
||||
setTimeout(function () {
|
||||
document.getElementById("notificationToast").style.display = "none";
|
||||
setTimeout(function () {
|
||||
document
|
||||
.getElementById("notificationToast")
|
||||
.classList.add("animate-right");
|
||||
document
|
||||
.getElementById("notificationToast")
|
||||
.classList.remove("animate-right-back");
|
||||
}, 50);
|
||||
}, 500);
|
||||
}, 2000);
|
||||
} catch (error) {
|
||||
console.warn(
|
||||
"Failed to show toast notification with title: `" +
|
||||
title +
|
||||
"` and message: `" +
|
||||
message +
|
||||
"`"
|
||||
);
|
||||
alert(title + " \n" + message);
|
||||
}
|
||||
}
|
60
static/leafletCluster/dist/MarkerCluster.Default.css
vendored
Normal file
@ -0,0 +1,60 @@
|
||||
.marker-cluster-small {
|
||||
background-color: rgba(181, 226, 140, 0.6);
|
||||
}
|
||||
.marker-cluster-small div {
|
||||
background-color: rgba(110, 204, 57, 0.6);
|
||||
}
|
||||
|
||||
.marker-cluster-medium {
|
||||
background-color: rgba(241, 211, 87, 0.6);
|
||||
}
|
||||
.marker-cluster-medium div {
|
||||
background-color: rgba(240, 194, 12, 0.6);
|
||||
}
|
||||
|
||||
.marker-cluster-large {
|
||||
background-color: rgba(253, 156, 115, 0.6);
|
||||
}
|
||||
.marker-cluster-large div {
|
||||
background-color: rgba(241, 128, 23, 0.6);
|
||||
}
|
||||
|
||||
/* IE 6-8 fallback colors */
|
||||
.leaflet-oldie .marker-cluster-small {
|
||||
background-color: rgb(181, 226, 140);
|
||||
}
|
||||
.leaflet-oldie .marker-cluster-small div {
|
||||
background-color: rgb(110, 204, 57);
|
||||
}
|
||||
|
||||
.leaflet-oldie .marker-cluster-medium {
|
||||
background-color: rgb(241, 211, 87);
|
||||
}
|
||||
.leaflet-oldie .marker-cluster-medium div {
|
||||
background-color: rgb(240, 194, 12);
|
||||
}
|
||||
|
||||
.leaflet-oldie .marker-cluster-large {
|
||||
background-color: rgb(253, 156, 115);
|
||||
}
|
||||
.leaflet-oldie .marker-cluster-large div {
|
||||
background-color: rgb(241, 128, 23);
|
||||
}
|
||||
|
||||
.marker-cluster {
|
||||
background-clip: padding-box;
|
||||
border-radius: 20px;
|
||||
}
|
||||
.marker-cluster div {
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
margin-left: 5px;
|
||||
margin-top: 5px;
|
||||
|
||||
text-align: center;
|
||||
border-radius: 15px;
|
||||
font: 12px "Helvetica Neue", Arial, Helvetica, sans-serif;
|
||||
}
|
||||
.marker-cluster span {
|
||||
line-height: 30px;
|
||||
}
|
14
static/leafletCluster/dist/MarkerCluster.css
vendored
Normal file
@ -0,0 +1,14 @@
|
||||
.leaflet-cluster-anim .leaflet-marker-icon, .leaflet-cluster-anim .leaflet-marker-shadow {
|
||||
-webkit-transition: -webkit-transform 0.3s ease-out, opacity 0.3s ease-in;
|
||||
-moz-transition: -moz-transform 0.3s ease-out, opacity 0.3s ease-in;
|
||||
-o-transition: -o-transform 0.3s ease-out, opacity 0.3s ease-in;
|
||||
transition: transform 0.3s ease-out, opacity 0.3s ease-in;
|
||||
}
|
||||
|
||||
.leaflet-cluster-spider-leg {
|
||||
/* stroke-dashoffset (duration and function) should match with leaflet-marker-icon transform in order to track it exactly */
|
||||
-webkit-transition: -webkit-stroke-dashoffset 0.3s ease-out, -webkit-stroke-opacity 0.3s ease-in;
|
||||
-moz-transition: -moz-stroke-dashoffset 0.3s ease-out, -moz-stroke-opacity 0.3s ease-in;
|
||||
-o-transition: -o-stroke-dashoffset 0.3s ease-out, -o-stroke-opacity 0.3s ease-in;
|
||||
transition: stroke-dashoffset 0.3s ease-out, stroke-opacity 0.3s ease-in;
|
||||
}
|
2690
static/leafletCluster/dist/leaflet.markercluster-src.js
vendored
Normal file
1
static/leafletCluster/dist/leaflet.markercluster-src.js.map
vendored
Normal file
3
static/leafletCluster/dist/leaflet.markercluster.js
vendored
Normal file
1
static/leafletCluster/dist/leaflet.markercluster.js.map
vendored
Normal file
54
static/leafletContextmenu/leaflet.contextmenu.css
Normal file
@ -0,0 +1,54 @@
|
||||
.leaflet-contextmenu {
|
||||
display: none;
|
||||
box-shadow: 0 1px 7px rgba(0,0,0,0.4);
|
||||
-webkit-border-radius: 4px;
|
||||
border-radius: 4px;
|
||||
padding: 4px 0;
|
||||
background-color: #fff;
|
||||
cursor: default;
|
||||
-webkit-user-select: none;
|
||||
-moz-user-select: none;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.leaflet-contextmenu a.leaflet-contextmenu-item {
|
||||
display: block;
|
||||
color: #222;
|
||||
font-size: 12px;
|
||||
line-height: 20px;
|
||||
text-decoration: none;
|
||||
padding: 0 12px;
|
||||
border-top: 1px solid transparent;
|
||||
border-bottom: 1px solid transparent;
|
||||
cursor: default;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.leaflet-contextmenu a.leaflet-contextmenu-item-disabled {
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
.leaflet-contextmenu a.leaflet-contextmenu-item.over {
|
||||
background-color: #f4f4f4;
|
||||
border-top: 1px solid #f0f0f0;
|
||||
border-bottom: 1px solid #f0f0f0;
|
||||
}
|
||||
|
||||
.leaflet-contextmenu a.leaflet-contextmenu-item-disabled.over {
|
||||
background-color: inherit;
|
||||
border-top: 1px solid transparent;
|
||||
border-bottom: 1px solid transparent;
|
||||
}
|
||||
|
||||
.leaflet-contextmenu-icon {
|
||||
margin: 2px 8px 0 0;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
float: left;
|
||||
border: 0;
|
||||
}
|
||||
|
||||
.leaflet-contextmenu-separator {
|
||||
border-bottom: 1px solid #ccc;
|
||||
margin: 5px 0;
|
||||
}
|
592
static/leafletContextmenu/leaflet.contextmenu.js
Normal file
@ -0,0 +1,592 @@
|
||||
/*
|
||||
Leaflet.contextmenu, a context menu for Leaflet.
|
||||
(c) 2015, Adam Ratcliffe, GeoSmart Maps Limited
|
||||
|
||||
@preserve
|
||||
*/
|
||||
|
||||
(function(factory) {
|
||||
// Packaging/modules magic dance
|
||||
var L;
|
||||
if (typeof define === 'function' && define.amd) {
|
||||
// AMD
|
||||
define(['leaflet'], factory);
|
||||
} else if (typeof module === 'object' && typeof module.exports === 'object') {
|
||||
// Node/CommonJS
|
||||
L = require('leaflet');
|
||||
module.exports = factory(L);
|
||||
} else {
|
||||
// Browser globals
|
||||
if (typeof window.L === 'undefined') {
|
||||
throw new Error('Leaflet must be loaded first');
|
||||
}
|
||||
factory(window.L);
|
||||
}
|
||||
})(function(L) {
|
||||
L.Map.mergeOptions({
|
||||
contextmenuItems: []
|
||||
});
|
||||
|
||||
L.Map.ContextMenu = L.Handler.extend({
|
||||
_touchstart: L.Browser.msPointer ? 'MSPointerDown' : L.Browser.pointer ? 'pointerdown' : 'touchstart',
|
||||
|
||||
statics: {
|
||||
BASE_CLS: 'leaflet-contextmenu'
|
||||
},
|
||||
|
||||
initialize: function (map) {
|
||||
L.Handler.prototype.initialize.call(this, map);
|
||||
|
||||
this._items = [];
|
||||
this._visible = false;
|
||||
|
||||
var container = this._container = L.DomUtil.create('div', L.Map.ContextMenu.BASE_CLS, map._container);
|
||||
container.style.zIndex = 10000;
|
||||
container.style.position = 'absolute';
|
||||
|
||||
if (map.options.contextmenuWidth) {
|
||||
container.style.width = map.options.contextmenuWidth + 'px';
|
||||
}
|
||||
|
||||
this._createItems();
|
||||
|
||||
L.DomEvent
|
||||
.on(container, 'click', L.DomEvent.stop)
|
||||
.on(container, 'mousedown', L.DomEvent.stop)
|
||||
.on(container, 'dblclick', L.DomEvent.stop)
|
||||
.on(container, 'contextmenu', L.DomEvent.stop);
|
||||
},
|
||||
|
||||
addHooks: function () {
|
||||
var container = this._map.getContainer();
|
||||
|
||||
L.DomEvent
|
||||
.on(container, 'mouseleave', this._hide, this)
|
||||
.on(document, 'keydown', this._onKeyDown, this);
|
||||
|
||||
if (L.Browser.touch) {
|
||||
L.DomEvent.on(document, this._touchstart, this._hide, this);
|
||||
}
|
||||
|
||||
this._map.on({
|
||||
contextmenu: this._show,
|
||||
mousedown: this._hide,
|
||||
zoomstart: this._hide
|
||||
}, this);
|
||||
},
|
||||
|
||||
removeHooks: function () {
|
||||
var container = this._map.getContainer();
|
||||
|
||||
L.DomEvent
|
||||
.off(container, 'mouseleave', this._hide, this)
|
||||
.off(document, 'keydown', this._onKeyDown, this);
|
||||
|
||||
if (L.Browser.touch) {
|
||||
L.DomEvent.off(document, this._touchstart, this._hide, this);
|
||||
}
|
||||
|
||||
this._map.off({
|
||||
contextmenu: this._show,
|
||||
mousedown: this._hide,
|
||||
zoomstart: this._hide
|
||||
}, this);
|
||||
},
|
||||
|
||||
showAt: function (point, data) {
|
||||
if (point instanceof L.LatLng) {
|
||||
point = this._map.latLngToContainerPoint(point);
|
||||
}
|
||||
this._showAtPoint(point, data);
|
||||
},
|
||||
|
||||
hide: function () {
|
||||
this._hide();
|
||||
},
|
||||
|
||||
addItem: function (options) {
|
||||
return this.insertItem(options);
|
||||
},
|
||||
|
||||
insertItem: function (options, index) {
|
||||
index = index !== undefined ? index: this._items.length;
|
||||
|
||||
var item = this._createItem(this._container, options, index);
|
||||
|
||||
this._items.push(item);
|
||||
|
||||
this._sizeChanged = true;
|
||||
|
||||
this._map.fire('contextmenu.additem', {
|
||||
contextmenu: this,
|
||||
el: item.el,
|
||||
index: index
|
||||
});
|
||||
|
||||
return item.el;
|
||||
},
|
||||
|
||||
removeItem: function (item) {
|
||||
var container = this._container;
|
||||
|
||||
if (!isNaN(item)) {
|
||||
item = container.children[item];
|
||||
}
|
||||
|
||||
if (item) {
|
||||
this._removeItem(L.Util.stamp(item));
|
||||
|
||||
this._sizeChanged = true;
|
||||
|
||||
this._map.fire('contextmenu.removeitem', {
|
||||
contextmenu: this,
|
||||
el: item
|
||||
});
|
||||
|
||||
return item;
|
||||
}
|
||||
|
||||
return null;
|
||||
},
|
||||
|
||||
removeAllItems: function () {
|
||||
var items = this._container.children,
|
||||
item;
|
||||
|
||||
while (items.length) {
|
||||
item = items[0];
|
||||
this._removeItem(L.Util.stamp(item));
|
||||
}
|
||||
return items;
|
||||
},
|
||||
|
||||
hideAllItems: function () {
|
||||
var item, i, l;
|
||||
|
||||
for (i = 0, l = this._items.length; i < l; i++) {
|
||||
item = this._items[i];
|
||||
item.el.style.display = 'none';
|
||||
}
|
||||
},
|
||||
|
||||
showAllItems: function () {
|
||||
var item, i, l;
|
||||
|
||||
for (i = 0, l = this._items.length; i < l; i++) {
|
||||
item = this._items[i];
|
||||
item.el.style.display = '';
|
||||
}
|
||||
},
|
||||
|
||||
setDisabled: function (item, disabled) {
|
||||
var container = this._container,
|
||||
itemCls = L.Map.ContextMenu.BASE_CLS + '-item';
|
||||
|
||||
if (!isNaN(item)) {
|
||||
item = container.children[item];
|
||||
}
|
||||
|
||||
if (item && L.DomUtil.hasClass(item, itemCls)) {
|
||||
if (disabled) {
|
||||
L.DomUtil.addClass(item, itemCls + '-disabled');
|
||||
this._map.fire('contextmenu.disableitem', {
|
||||
contextmenu: this,
|
||||
el: item
|
||||
});
|
||||
} else {
|
||||
L.DomUtil.removeClass(item, itemCls + '-disabled');
|
||||
this._map.fire('contextmenu.enableitem', {
|
||||
contextmenu: this,
|
||||
el: item
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
isVisible: function () {
|
||||
return this._visible;
|
||||
},
|
||||
|
||||
_createItems: function () {
|
||||
var itemOptions = this._map.options.contextmenuItems,
|
||||
item,
|
||||
i, l;
|
||||
|
||||
for (i = 0, l = itemOptions.length; i < l; i++) {
|
||||
this._items.push(this._createItem(this._container, itemOptions[i]));
|
||||
}
|
||||
},
|
||||
|
||||
_createItem: function (container, options, index) {
|
||||
if (options.separator || options === '-') {
|
||||
return this._createSeparator(container, index);
|
||||
}
|
||||
|
||||
var itemCls = L.Map.ContextMenu.BASE_CLS + '-item',
|
||||
cls = options.disabled ? (itemCls + ' ' + itemCls + '-disabled') : itemCls,
|
||||
el = this._insertElementAt('a', cls, container, index),
|
||||
callback = this._createEventHandler(el, options.callback, options.context, options.hideOnSelect),
|
||||
icon = this._getIcon(options),
|
||||
iconCls = this._getIconCls(options),
|
||||
html = '';
|
||||
|
||||
if (icon) {
|
||||
html = '<img class="' + L.Map.ContextMenu.BASE_CLS + '-icon" src="' + icon + '"/>';
|
||||
} else if (iconCls) {
|
||||
html = '<span class="' + L.Map.ContextMenu.BASE_CLS + '-icon ' + iconCls + '"></span>';
|
||||
}
|
||||
|
||||
el.innerHTML = html + options.text;
|
||||
el.href = '#';
|
||||
|
||||
L.DomEvent
|
||||
.on(el, 'mouseover', this._onItemMouseOver, this)
|
||||
.on(el, 'mouseout', this._onItemMouseOut, this)
|
||||
.on(el, 'mousedown', L.DomEvent.stopPropagation)
|
||||
.on(el, 'click', callback);
|
||||
|
||||
if (L.Browser.touch) {
|
||||
L.DomEvent.on(el, this._touchstart, L.DomEvent.stopPropagation);
|
||||
}
|
||||
|
||||
// Devices without a mouse fire "mouseover" on tap, but never “mouseout"
|
||||
if (!L.Browser.pointer) {
|
||||
L.DomEvent.on(el, 'click', this._onItemMouseOut, this);
|
||||
}
|
||||
|
||||
return {
|
||||
id: L.Util.stamp(el),
|
||||
el: el,
|
||||
callback: callback
|
||||
};
|
||||
},
|
||||
|
||||
_removeItem: function (id) {
|
||||
var item,
|
||||
el,
|
||||
i, l, callback;
|
||||
|
||||
for (i = 0, l = this._items.length; i < l; i++) {
|
||||
item = this._items[i];
|
||||
|
||||
if (item.id === id) {
|
||||
el = item.el;
|
||||
callback = item.callback;
|
||||
|
||||
if (callback) {
|
||||
L.DomEvent
|
||||
.off(el, 'mouseover', this._onItemMouseOver, this)
|
||||
.off(el, 'mouseover', this._onItemMouseOut, this)
|
||||
.off(el, 'mousedown', L.DomEvent.stopPropagation)
|
||||
.off(el, 'click', callback);
|
||||
|
||||
if (L.Browser.touch) {
|
||||
L.DomEvent.off(el, this._touchstart, L.DomEvent.stopPropagation);
|
||||
}
|
||||
|
||||
if (!L.Browser.pointer) {
|
||||
L.DomEvent.on(el, 'click', this._onItemMouseOut, this);
|
||||
}
|
||||
}
|
||||
|
||||
this._container.removeChild(el);
|
||||
this._items.splice(i, 1);
|
||||
|
||||
return item;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
},
|
||||
|
||||
_createSeparator: function (container, index) {
|
||||
var el = this._insertElementAt('div', L.Map.ContextMenu.BASE_CLS + '-separator', container, index);
|
||||
|
||||
return {
|
||||
id: L.Util.stamp(el),
|
||||
el: el
|
||||
};
|
||||
},
|
||||
|
||||
_createEventHandler: function (el, func, context, hideOnSelect) {
|
||||
var me = this,
|
||||
map = this._map,
|
||||
disabledCls = L.Map.ContextMenu.BASE_CLS + '-item-disabled',
|
||||
hideOnSelect = (hideOnSelect !== undefined) ? hideOnSelect : true;
|
||||
|
||||
return function (e) {
|
||||
if (L.DomUtil.hasClass(el, disabledCls)) {
|
||||
return;
|
||||
}
|
||||
|
||||
var map = me._map,
|
||||
containerPoint = me._showLocation.containerPoint,
|
||||
layerPoint = map.containerPointToLayerPoint(containerPoint),
|
||||
latlng = map.layerPointToLatLng(layerPoint),
|
||||
relatedTarget = me._showLocation.relatedTarget,
|
||||
data = {
|
||||
containerPoint: containerPoint,
|
||||
layerPoint: layerPoint,
|
||||
latlng: latlng,
|
||||
relatedTarget: relatedTarget
|
||||
};
|
||||
|
||||
if (hideOnSelect) {
|
||||
me._hide();
|
||||
}
|
||||
|
||||
if (func) {
|
||||
func.call(context || map, data);
|
||||
}
|
||||
|
||||
me._map.fire('contextmenu.select', {
|
||||
contextmenu: me,
|
||||
el: el
|
||||
});
|
||||
};
|
||||
},
|
||||
|
||||
_insertElementAt: function (tagName, className, container, index) {
|
||||
var refEl,
|
||||
el = document.createElement(tagName);
|
||||
|
||||
el.className = className;
|
||||
|
||||
if (index !== undefined) {
|
||||
refEl = container.children[index];
|
||||
}
|
||||
|
||||
if (refEl) {
|
||||
container.insertBefore(el, refEl);
|
||||
} else {
|
||||
container.appendChild(el);
|
||||
}
|
||||
|
||||
return el;
|
||||
},
|
||||
|
||||
_show: function (e) {
|
||||
this._showAtPoint(e.containerPoint, e);
|
||||
},
|
||||
|
||||
_showAtPoint: function (pt, data) {
|
||||
if (this._items.length) {
|
||||
var map = this._map,
|
||||
event = L.extend(data || {}, {contextmenu: this});
|
||||
|
||||
this._showLocation = {
|
||||
containerPoint: pt
|
||||
};
|
||||
|
||||
if (data && data.relatedTarget){
|
||||
this._showLocation.relatedTarget = data.relatedTarget;
|
||||
}
|
||||
|
||||
this._setPosition(pt);
|
||||
|
||||
if (!this._visible) {
|
||||
this._container.style.display = 'block';
|
||||
this._visible = true;
|
||||
}
|
||||
|
||||
this._map.fire('contextmenu.show', event);
|
||||
}
|
||||
},
|
||||
|
||||
_hide: function () {
|
||||
if (this._visible) {
|
||||
this._visible = false;
|
||||
this._container.style.display = 'none';
|
||||
this._map.fire('contextmenu.hide', {contextmenu: this});
|
||||
}
|
||||
},
|
||||
|
||||
_getIcon: function (options) {
|
||||
return L.Browser.retina && options.retinaIcon || options.icon;
|
||||
},
|
||||
|
||||
_getIconCls: function (options) {
|
||||
return L.Browser.retina && options.retinaIconCls || options.iconCls;
|
||||
},
|
||||
|
||||
_setPosition: function (pt) {
|
||||
var mapSize = this._map.getSize(),
|
||||
container = this._container,
|
||||
containerSize = this._getElementSize(container),
|
||||
anchor;
|
||||
|
||||
if (this._map.options.contextmenuAnchor) {
|
||||
anchor = L.point(this._map.options.contextmenuAnchor);
|
||||
pt = pt.add(anchor);
|
||||
}
|
||||
|
||||
container._leaflet_pos = pt;
|
||||
|
||||
if (pt.x + containerSize.x > mapSize.x) {
|
||||
container.style.left = 'auto';
|
||||
container.style.right = Math.min(Math.max(mapSize.x - pt.x, 0), mapSize.x - containerSize.x - 1) + 'px';
|
||||
} else {
|
||||
container.style.left = Math.max(pt.x, 0) + 'px';
|
||||
container.style.right = 'auto';
|
||||
}
|
||||
|
||||
if (pt.y + containerSize.y > mapSize.y) {
|
||||
container.style.top = 'auto';
|
||||
container.style.bottom = Math.min(Math.max(mapSize.y - pt.y, 0), mapSize.y - containerSize.y - 1) + 'px';
|
||||
} else {
|
||||
container.style.top = Math.max(pt.y, 0) + 'px';
|
||||
container.style.bottom = 'auto';
|
||||
}
|
||||
},
|
||||
|
||||
_getElementSize: function (el) {
|
||||
var size = this._size,
|
||||
initialDisplay = el.style.display;
|
||||
|
||||
if (!size || this._sizeChanged) {
|
||||
size = {};
|
||||
|
||||
el.style.left = '-999999px';
|
||||
el.style.right = 'auto';
|
||||
el.style.display = 'block';
|
||||
|
||||
size.x = el.offsetWidth;
|
||||
size.y = el.offsetHeight;
|
||||
|
||||
el.style.left = 'auto';
|
||||
el.style.display = initialDisplay;
|
||||
|
||||
this._sizeChanged = false;
|
||||
}
|
||||
|
||||
return size;
|
||||
},
|
||||
|
||||
_onKeyDown: function (e) {
|
||||
var key = e.keyCode;
|
||||
|
||||
// If ESC pressed and context menu is visible hide it
|
||||
if (key === 27) {
|
||||
this._hide();
|
||||
}
|
||||
},
|
||||
|
||||
_onItemMouseOver: function (e) {
|
||||
L.DomUtil.addClass(e.target || e.srcElement, 'over');
|
||||
},
|
||||
|
||||
_onItemMouseOut: function (e) {
|
||||
L.DomUtil.removeClass(e.target || e.srcElement, 'over');
|
||||
}
|
||||
});
|
||||
|
||||
L.Map.addInitHook('addHandler', 'contextmenu', L.Map.ContextMenu);
|
||||
L.Mixin.ContextMenu = {
|
||||
bindContextMenu: function (options) {
|
||||
L.setOptions(this, options);
|
||||
this._initContextMenu();
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
unbindContextMenu: function (){
|
||||
this.off('contextmenu', this._showContextMenu, this);
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
addContextMenuItem: function (item) {
|
||||
this.options.contextmenuItems.push(item);
|
||||
},
|
||||
|
||||
removeContextMenuItemWithIndex: function (index) {
|
||||
var items = [];
|
||||
for (var i = 0; i < this.options.contextmenuItems.length; i++) {
|
||||
if (this.options.contextmenuItems[i].index == index){
|
||||
items.push(i);
|
||||
}
|
||||
}
|
||||
var elem = items.pop();
|
||||
while (elem !== undefined) {
|
||||
this.options.contextmenuItems.splice(elem,1);
|
||||
elem = items.pop();
|
||||
}
|
||||
},
|
||||
|
||||
replaceContextMenuItem: function (item) {
|
||||
this.removeContextMenuItemWithIndex(item.index);
|
||||
this.addContextMenuItem(item);
|
||||
},
|
||||
|
||||
_initContextMenu: function () {
|
||||
this._items = [];
|
||||
|
||||
this.on('contextmenu', this._showContextMenu, this);
|
||||
},
|
||||
|
||||
_showContextMenu: function (e) {
|
||||
var itemOptions,
|
||||
data, pt, i, l;
|
||||
|
||||
if (this._map.contextmenu) {
|
||||
data = L.extend({relatedTarget: this}, e);
|
||||
|
||||
pt = this._map.mouseEventToContainerPoint(e.originalEvent);
|
||||
|
||||
if (!this.options.contextmenuInheritItems) {
|
||||
this._map.contextmenu.hideAllItems();
|
||||
}
|
||||
|
||||
for (i = 0, l = this.options.contextmenuItems.length; i < l; i++) {
|
||||
itemOptions = this.options.contextmenuItems[i];
|
||||
this._items.push(this._map.contextmenu.insertItem(itemOptions, itemOptions.index));
|
||||
}
|
||||
|
||||
this._map.once('contextmenu.hide', this._hideContextMenu, this);
|
||||
|
||||
this._map.contextmenu.showAt(pt, data);
|
||||
}
|
||||
},
|
||||
|
||||
_hideContextMenu: function () {
|
||||
var i, l;
|
||||
|
||||
for (i = 0, l = this._items.length; i < l; i++) {
|
||||
this._map.contextmenu.removeItem(this._items[i]);
|
||||
}
|
||||
this._items.length = 0;
|
||||
|
||||
if (!this.options.contextmenuInheritItems) {
|
||||
this._map.contextmenu.showAllItems();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
var classes = [L.Marker, L.Path],
|
||||
defaultOptions = {
|
||||
contextmenu: false,
|
||||
contextmenuItems: [],
|
||||
contextmenuInheritItems: true
|
||||
},
|
||||
cls, i, l;
|
||||
|
||||
for (i = 0, l = classes.length; i < l; i++) {
|
||||
cls = classes[i];
|
||||
|
||||
// L.Class should probably provide an empty options hash, as it does not test
|
||||
// for it here and add if needed
|
||||
if (!cls.prototype.options) {
|
||||
cls.prototype.options = defaultOptions;
|
||||
} else {
|
||||
cls.mergeOptions(defaultOptions);
|
||||
}
|
||||
|
||||
cls.addInitHook(function () {
|
||||
if (this.options.contextmenu) {
|
||||
this._initContextMenu();
|
||||
}
|
||||
});
|
||||
|
||||
cls.include(L.Mixin.ContextMenu);
|
||||
}
|
||||
return L.Map.ContextMenu;
|
||||
});
|
1
static/leafletContextmenu/leaflet.contextmenu.min.css
vendored
Normal file
@ -0,0 +1 @@
|
||||
.leaflet-contextmenu{display:none;box-shadow:0 1px 7px rgba(0,0,0,0.4);-webkit-border-radius:4px;border-radius:4px;padding:4px 0;background-color:#fff;cursor:default;-webkit-user-select:none;-moz-user-select:none;user-select:none}.leaflet-contextmenu a.leaflet-contextmenu-item{display:block;color:#222;font-size:12px;line-height:20px;text-decoration:none;padding:0 12px;border-top:1px solid transparent;border-bottom:1px solid transparent;cursor:default;outline:0}.leaflet-contextmenu a.leaflet-contextmenu-item-disabled{opacity:.5}.leaflet-contextmenu a.leaflet-contextmenu-item.over{background-color:#f4f4f4;border-top:1px solid #f0f0f0;border-bottom:1px solid #f0f0f0}.leaflet-contextmenu a.leaflet-contextmenu-item-disabled.over{background-color:inherit;border-top:1px solid transparent;border-bottom:1px solid transparent}.leaflet-contextmenu-icon{margin:2px 8px 0 0;width:16px;height:16px;float:left;border:0}.leaflet-contextmenu-separator{border-bottom:1px solid #ccc;margin:5px 0}
|
7
static/leafletContextmenu/leaflet.contextmenu.min.js
vendored
Normal file
41
static/manifest.json
Normal file
@ -0,0 +1,41 @@
|
||||
{
|
||||
"name": "App",
|
||||
"icons": [
|
||||
{
|
||||
"src": "\/favicon\/android-icon-36x36.png",
|
||||
"sizes": "36x36",
|
||||
"type": "image\/png",
|
||||
"density": "0.75"
|
||||
},
|
||||
{
|
||||
"src": "\/favicon\/android-icon-48x48.png",
|
||||
"sizes": "48x48",
|
||||
"type": "image\/png",
|
||||
"density": "1.0"
|
||||
},
|
||||
{
|
||||
"src": "\/favicon\/android-icon-72x72.png",
|
||||
"sizes": "72x72",
|
||||
"type": "image\/png",
|
||||
"density": "1.5"
|
||||
},
|
||||
{
|
||||
"src": "\/favicon\/android-icon-96x96.png",
|
||||
"sizes": "96x96",
|
||||
"type": "image\/png",
|
||||
"density": "2.0"
|
||||
},
|
||||
{
|
||||
"src": "\/favicon\/android-icon-144x144.png",
|
||||
"sizes": "144x144",
|
||||
"type": "image\/png",
|
||||
"density": "3.0"
|
||||
},
|
||||
{
|
||||
"src": "\/favicon\/android-icon-192x192.png",
|
||||
"sizes": "192x192",
|
||||
"type": "image\/png",
|
||||
"density": "4.0"
|
||||
}
|
||||
]
|
||||
}
|
41
static/offline.html
Normal file
@ -0,0 +1,41 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<!-- Basic Page Needs
|
||||
–––––––––––––––––––––––––––––––––––––––––––––––––– -->
|
||||
<meta charset="utf-8" />
|
||||
<title>Pointsight is offline</title>
|
||||
<meta name="description" content="This is the Pointsight fallback website." />
|
||||
<meta name="author" content="[Project-Name-Here]" />
|
||||
|
||||
<!-- Mobile Specific Metas
|
||||
–––––––––––––––––––––––––––––––––––––––––––––––––– -->
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
|
||||
<!-- CSS
|
||||
–––––––––––––––––––––––––––––––––––––––––––––––––– -->
|
||||
<link rel="stylesheet" href="/css/tailwindInclude.css" />
|
||||
|
||||
<!-- Favicon
|
||||
–––––––––––––––––––––––––––––––––––––––––––––––––– -->
|
||||
<link rel="icon" type="image/png" href="images/favicon-16.png" />
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div class="bg-gradient-to-r
|
||||
from-purple-400
|
||||
via-pink-500
|
||||
to-red-500
|
||||
animate-gradient-xy">
|
||||
<div class="flex items-center justify-center h-screen">
|
||||
|
||||
<div class="text-black rounded-lg shadow-lg p-10 bg-gray-50 dark:bg-gray-800 dark:text-white text-center">
|
||||
<h1 class="text-6xl">Offline</h1>
|
||||
<p class="text-4xl">That's not good</p>
|
||||
<p>Huh, it seems like one of us is offline.<br> If you are sure that you are only, maybe we have a problem. Please check later!</p><br>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|