WIP WIP WIP ** first git - markers work as expected
This commit is contained in:
@@ -0,0 +1,2 @@
|
||||
node_modules
|
||||
log
|
||||
Generated
+8
@@ -0,0 +1,8 @@
|
||||
# Default ignored files
|
||||
/shelf/
|
||||
/workspace.xml
|
||||
# Editor-based HTTP Client requests
|
||||
/httpRequests/
|
||||
# Datasource local storage ignored files
|
||||
/dataSources/
|
||||
/dataSources.local.xml
|
||||
Generated
+6
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="JavaScriptLibraryMappings">
|
||||
<includedPredefinedLibrary name="Node.js Core" />
|
||||
</component>
|
||||
</project>
|
||||
Generated
+8
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="WEB_MODULE" version="4">
|
||||
<component name="NewModuleRootManager">
|
||||
<content url="file://$MODULE_DIR$" />
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
</component>
|
||||
</module>
|
||||
Generated
+6
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="MarkdownSettingsMigration">
|
||||
<option name="stateVersion" value="1" />
|
||||
</component>
|
||||
</project>
|
||||
Generated
+8
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectModuleManager">
|
||||
<modules>
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/laerm_web_sensorapi.iml" filepath="$PROJECT_DIR$/.idea/laerm_web_sensorapi.iml" />
|
||||
</modules>
|
||||
</component>
|
||||
</project>
|
||||
Generated
+19
@@ -0,0 +1,19 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="MessDetectorOptionsConfiguration">
|
||||
<option name="transferred" value="true" />
|
||||
</component>
|
||||
<component name="PHPCSFixerOptionsConfiguration">
|
||||
<option name="transferred" value="true" />
|
||||
</component>
|
||||
<component name="PHPCodeSnifferOptionsConfiguration">
|
||||
<option name="highlightLevel" value="WARNING" />
|
||||
<option name="transferred" value="true" />
|
||||
</component>
|
||||
<component name="PhpStanOptionsConfiguration">
|
||||
<option name="transferred" value="true" />
|
||||
</component>
|
||||
<component name="PsalmOptionsConfiguration">
|
||||
<option name="transferred" value="true" />
|
||||
</component>
|
||||
</project>
|
||||
Generated
+11
@@ -0,0 +1,11 @@
|
||||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="bin/www" type="NodeJSConfigurationType" node-parameters="--experimental-json-modules" path-to-js-file="bin/www.js" working-dir="$PROJECT_DIR$">
|
||||
<envs>
|
||||
<env name="DEBUG" value="laerm-web-sensorapi:*" />
|
||||
</envs>
|
||||
<EXTENSION ID="com.jetbrains.nodejs.run.NodeStartBrowserRunConfigurationExtension">
|
||||
<browser url="http://localhost:3000/" />
|
||||
</EXTENSION>
|
||||
<method v="2" />
|
||||
</configuration>
|
||||
</component>
|
||||
Generated
+25
@@ -0,0 +1,25 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectTasksOptions">
|
||||
<TaskOptions isEnabled="true">
|
||||
<option name="arguments" value="$FileName$:$FileNameWithoutExtension$.css" />
|
||||
<option name="checkSyntaxErrors" value="true" />
|
||||
<option name="description" />
|
||||
<option name="exitCodeBehavior" value="ERROR" />
|
||||
<option name="fileExtension" value="sass" />
|
||||
<option name="immediateSync" value="false" />
|
||||
<option name="name" value="Sass" />
|
||||
<option name="output" value="$FileNameWithoutExtension$.css:$FileNameWithoutExtension$.css.map" />
|
||||
<option name="outputFilters">
|
||||
<array />
|
||||
</option>
|
||||
<option name="outputFromStdout" value="false" />
|
||||
<option name="program" value="$PROJECT_DIR$/node_modules/sass/sass.js" />
|
||||
<option name="runOnExternalChanges" value="false" />
|
||||
<option name="scopeName" value="Project Files" />
|
||||
<option name="trackOnlyRoot" value="true" />
|
||||
<option name="workingDir" value="$FileDir$" />
|
||||
<envs />
|
||||
</TaskOptions>
|
||||
</component>
|
||||
</project>
|
||||
@@ -0,0 +1,47 @@
|
||||
import createError from 'http-errors'
|
||||
import logger from 'morgan'
|
||||
import express from 'express'
|
||||
import cookieParser from 'cookie-parser'
|
||||
import path from 'path'
|
||||
import { fileURLToPath } from 'url';
|
||||
const app = express()
|
||||
|
||||
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = path.dirname(__filename);
|
||||
|
||||
import indexRouter from './routes/index.js'
|
||||
// import getdataRouter from './routes/getdata.js'
|
||||
// import putdataRouter from './routes/putdata.js'
|
||||
|
||||
// view engine setup
|
||||
app.set('views', path.join(__dirname, 'views'));
|
||||
app.set('view engine', 'pug');
|
||||
|
||||
app.use(logger('dev'));
|
||||
app.use(express.json());
|
||||
app.use(express.urlencoded({ extended: false }));
|
||||
app.use(cookieParser());
|
||||
app.use(express.static(path.join(__dirname, 'public')));
|
||||
|
||||
app.use('/', indexRouter);
|
||||
// app.use('/users', usersRouter);
|
||||
|
||||
// catch 404 and forward to error handler
|
||||
app.use(function(req, res, next) {
|
||||
next(createError(404));
|
||||
});
|
||||
|
||||
// error handler
|
||||
app.use(function(err, req, res, next) {
|
||||
// set locals, only providing error in development
|
||||
res.locals.message = err.message;
|
||||
res.locals.error = req.app.get('env') === 'development' ? err : {};
|
||||
|
||||
// render the error page
|
||||
res.status(err.status || 500);
|
||||
res.render('error');
|
||||
});
|
||||
|
||||
|
||||
export default app
|
||||
Executable
+97
@@ -0,0 +1,97 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
import app from '../app.js'
|
||||
import Debug from 'debug'
|
||||
import http from 'http'
|
||||
const debug = Debug('laerm-web-sensorapi:server')
|
||||
|
||||
|
||||
/* var app = require('../app');
|
||||
var debug = require('debug')('laerm-web-sensorapi:server');
|
||||
var http = require('http');
|
||||
*/
|
||||
|
||||
/**
|
||||
* Get port from environment and store in Express.
|
||||
*/
|
||||
|
||||
var port = normalizePort(process.env.PORT || '3000');
|
||||
app.set('port', port);
|
||||
|
||||
/**
|
||||
* Create HTTP server.
|
||||
*/
|
||||
|
||||
var server = http.createServer(app);
|
||||
|
||||
/**
|
||||
* Listen on provided port, on all network interfaces.
|
||||
*/
|
||||
|
||||
server.listen(port);
|
||||
server.on('error', onError);
|
||||
server.on('listening', onListening);
|
||||
|
||||
/**
|
||||
* Normalize a port into a number, string, or false.
|
||||
*/
|
||||
|
||||
function normalizePort(val) {
|
||||
var port = parseInt(val, 10);
|
||||
|
||||
if (isNaN(port)) {
|
||||
// named pipe
|
||||
return val;
|
||||
}
|
||||
|
||||
if (port >= 0) {
|
||||
// port number
|
||||
return port;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Event listener for HTTP server "error" event.
|
||||
*/
|
||||
|
||||
function onError(error) {
|
||||
if (error.syscall !== 'listen') {
|
||||
throw error;
|
||||
}
|
||||
|
||||
var bind = typeof port === 'string'
|
||||
? 'Pipe ' + port
|
||||
: 'Port ' + port;
|
||||
|
||||
// handle specific listen errors with friendly messages
|
||||
switch (error.code) {
|
||||
case 'EACCES':
|
||||
console.error(bind + ' requires elevated privileges');
|
||||
process.exit(1);
|
||||
break;
|
||||
case 'EADDRINUSE':
|
||||
console.error(bind + ' is already in use');
|
||||
process.exit(1);
|
||||
break;
|
||||
default:
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Event listener for HTTP server "listening" event.
|
||||
*/
|
||||
|
||||
function onListening() {
|
||||
var addr = server.address();
|
||||
var bind = typeof addr === 'string'
|
||||
? 'pipe ' + addr
|
||||
: 'port ' + addr.port;
|
||||
debug('Listening on ' + bind);
|
||||
}
|
||||
Generated
+1394
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"name": "laerm-web-sensorapi",
|
||||
"version": "3.0.0",
|
||||
"date": "2023-03-14 16:30 UTC",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"start": "node bin/www.js >>log/laerm_web.log 2>&1"
|
||||
},
|
||||
"type": "module",
|
||||
"bin": {
|
||||
"www": "./bin/www.js"
|
||||
},
|
||||
"dependencies": {
|
||||
"cookie-parser": "~1.4.4",
|
||||
"cors": "^2.8.5",
|
||||
"debug": "~2.6.9",
|
||||
"express": "~4.16.1",
|
||||
"http-errors": "~1.6.3",
|
||||
"morgan": "~1.9.1",
|
||||
"pug": "2.0.0-beta11",
|
||||
"sass": "^1.58.3"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
// all date and time functions
|
||||
import { DateTime } from './luxon.min.js'
|
||||
|
||||
// Show date and time (every minute)
|
||||
export const showDate = (sofort) => {
|
||||
let d = DateTime.now()
|
||||
if(sofort || d.second === 0) {
|
||||
$('#h1datum').text(d.toFormat('yyyy-MM-dd HH:mm'))
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export const formatJSDate = (d) => {
|
||||
return DateTime.fromJSDate(d).toFormat('yyyy-LL-dd HH:mm:ss')
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
// Client side javascript
|
||||
"use strict"
|
||||
|
||||
import * as map from './map.js'
|
||||
import * as dt from './datetime.js'
|
||||
|
||||
$(async() => {
|
||||
// global constants
|
||||
const Stuttgart = [48.779, 9.16]
|
||||
const MAXROWS_IN_TABLE = 1000
|
||||
const defaultStartime = '2023-01-01 00:00'
|
||||
// END global constants
|
||||
|
||||
// global variables
|
||||
let params = { // set defaults
|
||||
drawlines: false,
|
||||
nbrentries: 0,
|
||||
device: '',
|
||||
coordinates: false,
|
||||
center: Stuttgart,
|
||||
zoom: 13,
|
||||
refresh: 0,
|
||||
starttime: '2023-01-01T00:00:00Z', //date2ISO(defaultStartime),
|
||||
endtime: '2023-03-01T00:00:00Z' //date2ISO(emptyTimes.emptyHMtime)
|
||||
}
|
||||
// END global variables
|
||||
|
||||
|
||||
|
||||
async function main() {
|
||||
// show dat/time at start
|
||||
dt.showDate(true)
|
||||
// and show date/time every minute
|
||||
setInterval(() => dt.showDate(false), 1000)
|
||||
|
||||
// show version and version-date
|
||||
$('#versn').text(`Version: ${sysparams.version} vom ${sysparams.date.slice(0,10)}`)
|
||||
|
||||
// show the map
|
||||
map.showMap(params)
|
||||
await map.buildMarkers()
|
||||
}
|
||||
main().catch(console.error)
|
||||
|
||||
})
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Vendored
+1
File diff suppressed because one or more lines are too long
@@ -0,0 +1,300 @@
|
||||
// all function related to the map
|
||||
|
||||
import * as dt from './datetime.js'
|
||||
|
||||
let map
|
||||
let bounds
|
||||
let popuptext = ''
|
||||
|
||||
const colorscale = ['#d53e4f', '#fc8d59', '#fee08b', '#e6f598', '#99d594', '#3288bd', '#808080'];
|
||||
const dba = [100, 80, 60, 40, 20, 0, -999];
|
||||
|
||||
export const showMap = (params) => {
|
||||
map = L.map('map',{ scrollWheelZoom: false}).setView(params.center, parseInt(params.zoom))
|
||||
L.tileLayer('https://tile.openstreetmap.org/{z}/{x}/{y}.png', {
|
||||
maxZoom: 19,
|
||||
attribution: '© <a href="http://www.js.openstreetmap.org/copyright">OpenStreetMap</a>'
|
||||
}).addTo(map)
|
||||
bounds = map.getBounds();
|
||||
|
||||
map.on('moveend', async function () {
|
||||
bounds = map.getBounds()
|
||||
await buildMarkers(bounds)
|
||||
});
|
||||
|
||||
let legend = L.control({position: 'bottomright'})
|
||||
legend.onAdd = function (map) {
|
||||
let div = L.DomUtil.create('div', 'info legend')
|
||||
let div_color = L.DomUtil.create('div', 'info legend inner', div)
|
||||
div_color.innerHTML += 'dbA<br />';
|
||||
// loop through our density intervals and generate a label with a colored square for each interval
|
||||
for (let i = 0; i < dba.length - 1; i++) {
|
||||
div_color.innerHTML +=
|
||||
'<i style="background:' + colorscale[i] + '"></i>' +
|
||||
' ' + dba[i] + (i == 0 ? '+' : '') + '<br />'
|
||||
}
|
||||
div_color.innerHTML += ' <i style="background:' + getColor(dba[dba.length - 1]) + '"></i> offline'
|
||||
return div
|
||||
};
|
||||
legend.addTo(map)
|
||||
|
||||
}
|
||||
|
||||
|
||||
function getColor(d) {
|
||||
let val = parseInt(d);
|
||||
for (let i = 0; i < dba.length; i++) {
|
||||
if (val >= dba[i]) {
|
||||
return (colorscale[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function calcPolygon(bounds) {
|
||||
return L.polygon([[bounds.getNorth(), bounds.getWest()], [bounds.getNorth(), bounds.getEast()], [bounds.getSouth(), bounds.getEast()], [bounds.getSouth(), bounds.getWest()]], {
|
||||
color: 'black',
|
||||
fillOpacity: 0.5
|
||||
});
|
||||
;
|
||||
}
|
||||
|
||||
async function plotMap(cid, poly) {
|
||||
// if sensor nbr is give, find coordinates, else use Stuttgart center
|
||||
debug_log('plotMap()');
|
||||
let myLatLng;
|
||||
if (cid != -1) {
|
||||
myLatLng = await getSensorKoords(cid);
|
||||
} else {
|
||||
let stgt = await getCoords('Stuttgart');
|
||||
myLatLng = {lat: parseFloat(stgt.lat), lng: parseFloat(stgt.lon)};
|
||||
}
|
||||
|
||||
// generate map centered on Stuttgart
|
||||
map = L.map('map').setView(myLatLng, firstZoom);
|
||||
|
||||
L.tileLayer('https://{s}.tile.openstreetmap.de/{z}/{x}/{y}.png', {
|
||||
maxZoom: 17,
|
||||
attribution: '© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
|
||||
}).addTo(map);
|
||||
|
||||
bounds = map.getBounds();
|
||||
|
||||
map.scrollWheelZoom.disable();
|
||||
|
||||
map.on('moveend', async function () {
|
||||
bounds = map.getBounds();
|
||||
await buildMarkers(bounds)
|
||||
});
|
||||
|
||||
|
||||
let legend = L.control({position: 'bottomright'});
|
||||
legend.onAdd = function (map) {
|
||||
let div = L.DomUtil.create('div', 'info legend');
|
||||
let div_color = L.DomUtil.create('div', 'info legend inner', div);
|
||||
div_color.innerHTML += 'dbA<br />';
|
||||
// loop through our density intervals and generate a label with a colored square for each interval
|
||||
for (let i = 0; i < dba.length - 1; i++) {
|
||||
div_color.innerHTML +=
|
||||
'<i style="background:' + colorscale[i] + '"></i>' +
|
||||
' ' + dba[i] + (i == 0 ? '+' : '') + '<br />';
|
||||
}
|
||||
div_color.innerHTML += ' <i style="background:' + getColor(dba[dba.length - 1]) + '"></i> offline';
|
||||
return div;
|
||||
};
|
||||
legend.addTo(map);
|
||||
|
||||
let infobutton = L.control({position: 'topright'});
|
||||
infobutton.onAdd = function (map) {
|
||||
let div = L.DomUtil.create('div');
|
||||
div.innerHTML = '<button class="cb centerbutt">neu zentrieren</button>';
|
||||
div.onclick = function () {
|
||||
dialogCenter.dialog('open');
|
||||
console.log('Clicked on Zentrieren');
|
||||
}
|
||||
return div;
|
||||
}
|
||||
infobutton.addTo(map);
|
||||
|
||||
if (useStgtBorder) {
|
||||
fetchStuttgartBounds();
|
||||
}
|
||||
|
||||
if (myLatLng.error != undefined) {
|
||||
showError(3, "Kein Lärmsensor", cid);
|
||||
} else {
|
||||
await buildMarkers(bounds);
|
||||
map.on('popupopen', function () {
|
||||
$('.speciallink').click(function (x) {
|
||||
showGrafik(clickedSensor);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
// With all Markers in cluster (markers) calculate the median
|
||||
// of the values. With this median fetch the color and return it.
|
||||
// If there are 'offline' sensors (value == -1) strip then before
|
||||
// calculating the median. If there are only offline sensor, return
|
||||
// color of value==-1 (dark gray).
|
||||
function getMedian(markers) {
|
||||
markers.sort(function (a, b) { // first sort, the lowest first
|
||||
let y1 = a.options.value;
|
||||
let y2 = b.options.value;
|
||||
if (y1 < y2) {
|
||||
return -1;
|
||||
}
|
||||
if (y2 < y1) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
});
|
||||
console.log(markers);
|
||||
let i = 0; // now find the 'offlines' (value == -1)
|
||||
for (i = 0; i < markers.length; i++) {
|
||||
if (markers[i].options.value != -1) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
markers.splice(0, i); // remove these from array
|
||||
let lang = markers.length;
|
||||
if (lang > 1) { //
|
||||
if ((lang % 2) == 1) { // uneven ->
|
||||
return getColor(markers[(Math.floor(lang / 2))].options.value); // median is in the middle
|
||||
} else { // evaen ->
|
||||
lang = lang / 2; // median is mean of both middle values
|
||||
console.log(lang);
|
||||
let wert = (markers[lang - 1].options.value +
|
||||
markers[lang].options.value) / 2;
|
||||
return getColor(wert);
|
||||
}
|
||||
} else if (lang == 1) { // only one marker -> return its color
|
||||
return getColor(markers[0].options.value);
|
||||
}
|
||||
return getColor(-1); // only offlines
|
||||
}
|
||||
|
||||
|
||||
function buildIcon(color, n, indoor) {
|
||||
let x = 100;
|
||||
if (n < 10) {
|
||||
x = 200;
|
||||
} else if (n < 100) {
|
||||
x = 150;
|
||||
}
|
||||
let txtColor = "black";
|
||||
if (color == colorscale[5]) {
|
||||
txtColor = "white"
|
||||
}
|
||||
let circIcon = '<svg xmlns="http://www.w3.org/2000/svg" width="600" height="600">' +
|
||||
'<circle cx="300" cy="300" r="250" fill="' + color + '" stroke="black" stroke-width="20" />';
|
||||
if (n !== 0) {
|
||||
circIcon +=
|
||||
'<text id="marker_text" x="' + x + '" ' +
|
||||
'y="400" font-size="1500%" font-family="Verdana,Lucida Sans Unicode,sans-serif" ' +
|
||||
'fill="' + txtColor + '">' + n + '</text>';
|
||||
}
|
||||
if(indoor !== 0) {
|
||||
circIcon += '<line x1="125" y1="475" x2="475" y2="125" stroke="black" stroke-width="20" />'
|
||||
}
|
||||
circIcon += '</svg>';
|
||||
let circIconUrl = encodeURI("data:image/svg+xml," + circIcon).replace(new RegExp('#', 'g'), '%23');
|
||||
return circIconUrl;
|
||||
}
|
||||
|
||||
|
||||
export async function buildMarkers() {
|
||||
// debug_log('buildMarkers(bounds)');
|
||||
const box = {
|
||||
west: bounds.getWest(), south: bounds.getSouth(),
|
||||
east: bounds.getEast(), north: bounds.getNorth()
|
||||
}
|
||||
const url = `http://localhost:3004/getmapdata?type=noise&box=${bounds.toBBoxString()}`
|
||||
|
||||
let ret = await fetch(url)
|
||||
.catch(e => {
|
||||
console.log(e)
|
||||
});
|
||||
let sensors = await ret.json()
|
||||
let markers = L.markerClusterGroup({
|
||||
spiderfyOnMaxZoom: true,
|
||||
showCoverageOnHover: false,
|
||||
zoomToBoundsOnClick: true,
|
||||
// disableClusteringAtZoom: 14,
|
||||
iconCreateFunction: function (cluster) {
|
||||
let mymarkers = cluster.getAllChildMarkers();
|
||||
let color = getMedian(mymarkers);
|
||||
return new L.Icon({
|
||||
iconUrl: buildIcon(color, cluster.getChildCount(), 0),
|
||||
iconSize: [35, 35]
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
for (let x of sensors.values) {
|
||||
let marker = L.marker([x.location[1], x.location[0]], {
|
||||
icon: new L.Icon({
|
||||
iconUrl: buildIcon(getColor(parseInt(x.value)),0,x.indoor),
|
||||
iconSize: [35, 35],
|
||||
}),
|
||||
name: x.id,
|
||||
value: x.value,
|
||||
url: '/graph?sid=' + x.id,
|
||||
lastseen: dt.formatJSDate(x.lastseen),
|
||||
indoor: x.indoor
|
||||
})
|
||||
.on('click', e => onMarkerClick(e, true)) // define click- and
|
||||
.bindPopup(popuptext); // and bint the popup text
|
||||
markers.addLayer(marker);
|
||||
}
|
||||
map.addLayer(markers);
|
||||
showLastDate(sensors.lastDate);
|
||||
|
||||
}
|
||||
|
||||
async function onMarkerClick(e, click) {
|
||||
let item = e.target.options;
|
||||
let clickedSensor = item.name;
|
||||
|
||||
let offlinetext = `
|
||||
<tr><td colspan="2"><span style="color:red;">offline</span></td></tr>
|
||||
<tr><td>Last seen:</td><td>${item.lastseen}</td></tr>`
|
||||
let normaltext = `
|
||||
<tr></tr><tr><td>LA_max:</td><td>${item.value}</td></tr>`
|
||||
|
||||
let popuptext = `
|
||||
<div id="infoTitle">
|
||||
<h4>Sensor: ${item.name}</h4>
|
||||
<div id="infoTable">
|
||||
<table>
|
||||
<tr><td colspan="2"><span style="color:limegreen;">${item.indoor==1 ? "indoor" : ""}</span></td></tr>
|
||||
${item.value < 0 ? offlinetext : normaltext}
|
||||
</table>
|
||||
<div id="infoBtn">
|
||||
<a href="#" class="speciallink">Grafik anzeigen</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>`
|
||||
let popup = e.target.getPopup();
|
||||
popup.setContent(popuptext); // set text into popup
|
||||
e.target.openPopup(); // show the popup
|
||||
if (click == true) { // if we clicked
|
||||
e.target.closePopup(); // show the popup
|
||||
}
|
||||
}
|
||||
|
||||
async function getCoords(city) {
|
||||
let url = NOMINATIM_URL + city;
|
||||
const response = await axios.get(encodeURI(url));
|
||||
const data = response.data;
|
||||
return data[0];
|
||||
}
|
||||
|
||||
// Map auf Stadt setzen
|
||||
async function setCenter(adr) {
|
||||
let data = await getCoords(adr);
|
||||
map.setView([parseFloat(data.lat), parseFloat(data.lon)]);
|
||||
console.log(data);
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -0,0 +1,109 @@
|
||||
body {
|
||||
font-family: Verdana, "Lucida Sans Unicode", sans-serif;
|
||||
font-size: 16px;
|
||||
width: 100%;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
height: 100%;
|
||||
background-color: rgb(146, 154, 146);
|
||||
}
|
||||
|
||||
html {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
#wrapper {
|
||||
margin: auto;
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
background-color: #e9e9e9;
|
||||
margin-top: 5px;
|
||||
height: 100%;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
a {
|
||||
color: #0000EE;
|
||||
}
|
||||
|
||||
header {
|
||||
width: 98%;
|
||||
margin: auto;
|
||||
}
|
||||
header #hline1 {
|
||||
width: 98%;
|
||||
margin: 0px auto 0px;
|
||||
padding-top: 10px;
|
||||
}
|
||||
header #h1name {
|
||||
font-size: 148%;
|
||||
clear: both;
|
||||
float: left;
|
||||
text-align: left;
|
||||
}
|
||||
header #h1datum {
|
||||
float: right;
|
||||
}
|
||||
|
||||
#map {
|
||||
margin-left: 1vw;
|
||||
margin-top: 5px;
|
||||
width: 98vw;
|
||||
height: 66vh;
|
||||
border-radius: 10px;
|
||||
border: solid 1px seagreen;
|
||||
overflow: hidden;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
#author {
|
||||
font-size: 80%;
|
||||
width: 95%;
|
||||
margin: auto;
|
||||
padding-bottom: 30px;
|
||||
padding-top: 10px;
|
||||
}
|
||||
#author #mailadr {
|
||||
float: left;
|
||||
}
|
||||
#author #versn {
|
||||
float: right;
|
||||
}
|
||||
|
||||
.info {
|
||||
padding: 6px 8px;
|
||||
font: 12px Arial, Helvetica, sans-serif;
|
||||
background: rgba(255, 255, 255, 0.8);
|
||||
box-shadow: 0 0 15px rgba(0, 0, 0, 0.2);
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
.info h4 {
|
||||
margin: 0 0 5px;
|
||||
color: #777;
|
||||
}
|
||||
|
||||
.legend {
|
||||
line-height: 18px;
|
||||
color: #555;
|
||||
font-size: 110%;
|
||||
}
|
||||
|
||||
.legend i {
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
float: left;
|
||||
margin-right: 0px;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.leglabel {
|
||||
padding-top: 20px;
|
||||
}
|
||||
|
||||
.ndmarker {
|
||||
position: absolute;
|
||||
font-size: 24px;
|
||||
}
|
||||
|
||||
/*# sourceMappingURL=style.css.map */
|
||||
@@ -0,0 +1 @@
|
||||
{"version":3,"sourceRoot":"","sources":["style.sass"],"names":[],"mappings":"AAUA;EACE;EACA;EACA;EACA;EACA;EACA;EACA,kBAfW;;;AAiBb;EACE;;;AAEF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;;;AAEF;EACE;;;AAEF;EACE;EACA;;AAEA;EACE;EACA;EACA;;AAEF;EACE;EACA;EACA;EACA;;AAEF;EACE;;;AAGJ;EACE;EACA;EACA;EACA;EACA,eA1Dc;EA2Dd;EACA;EACA;;;AAEF;EACE;EACA;EACA;EACA;EACA;;AAEA;EACE;;AAEF;EACE;;;AAGJ;EACE;EACA;EACA;EACA;EACA;;;AAEF;EACE;EACA;;;AAEF;EACE;EACA;EACA;;;AAEF;EACE;EACA;EACA;EACA;EACA;;;AAEF;EACE;;;AAEF;EACE;EACA","file":"style.css"}
|
||||
@@ -0,0 +1,107 @@
|
||||
$corner-radius: 10px
|
||||
$border-color: seagreen
|
||||
$background: rgb(146, 154, 146)
|
||||
$divcolor: rgb(162, 227, 162)
|
||||
$table-stripes: rgb(157, 179, 157)
|
||||
$fieldset-color: rgb(208, 235, 208)
|
||||
$button-color: darkslategrey
|
||||
$checkboxsize: 1.5
|
||||
$inboxwidth: 70px
|
||||
|
||||
body
|
||||
font-family: Verdana, 'Lucida Sans Unicode', sans-serif
|
||||
font-size: 16px
|
||||
width: 100%
|
||||
margin-left: auto
|
||||
margin-right: auto
|
||||
height: 100%
|
||||
background-color: $background
|
||||
|
||||
html
|
||||
height: 100%
|
||||
|
||||
#wrapper
|
||||
margin: auto
|
||||
width: 100%
|
||||
text-align: center
|
||||
background-color: #e9e9e9
|
||||
margin-top: 5px
|
||||
height: 100%
|
||||
position: relative
|
||||
|
||||
a
|
||||
color: #0000EE
|
||||
|
||||
header
|
||||
width: 98%
|
||||
margin: auto
|
||||
|
||||
#hline1
|
||||
width: 98%
|
||||
margin: 0px auto 0px
|
||||
padding-top: 10px
|
||||
|
||||
#h1name
|
||||
font-size: 148%
|
||||
clear: both
|
||||
float: left
|
||||
text-align: left
|
||||
|
||||
#h1datum
|
||||
float: right
|
||||
|
||||
|
||||
#map
|
||||
margin-left: 1vw
|
||||
margin-top: 5px
|
||||
width: 98vw
|
||||
height: 66vh
|
||||
border-radius: $corner-radius
|
||||
border: solid 1px $border-color
|
||||
overflow: hidden
|
||||
z-index: 1
|
||||
|
||||
#author
|
||||
font-size: 80%
|
||||
width: 95%
|
||||
margin: auto
|
||||
padding-bottom: 30px
|
||||
padding-top: 10px
|
||||
|
||||
#mailadr
|
||||
float: left
|
||||
|
||||
#versn
|
||||
float: right
|
||||
|
||||
|
||||
.info
|
||||
padding: 6px 8px
|
||||
font: 12px Arial, Helvetica, sans-serif
|
||||
background: rgba(255,255,255,0.8)
|
||||
box-shadow: 0 0 15px rgba(0,0,0,0.2)
|
||||
border-radius: 5px
|
||||
|
||||
.info h4
|
||||
margin: 0 0 5px
|
||||
color: #777
|
||||
|
||||
.legend
|
||||
line-height: 18px
|
||||
color: #555
|
||||
font-size: 110%
|
||||
|
||||
.legend i
|
||||
width: 18px
|
||||
height: 18px
|
||||
float: left
|
||||
margin-right: 0px
|
||||
opacity: 1
|
||||
|
||||
.leglabel
|
||||
padding-top: 20px
|
||||
|
||||
.ndmarker
|
||||
position: absolute
|
||||
font-size: 24px
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
import express from 'express'
|
||||
import pkg from '../package.json' assert { type: "json" }
|
||||
|
||||
const router = express.Router()
|
||||
const { name, version, date } = pkg
|
||||
|
||||
/* GET home page. */
|
||||
router.get('/', function(req, res, next) {
|
||||
res.render('index', {
|
||||
title: name,
|
||||
version: version,
|
||||
date: date
|
||||
})
|
||||
})
|
||||
|
||||
export default router
|
||||
@@ -0,0 +1,9 @@
|
||||
var express = require('express');
|
||||
var router = express.Router();
|
||||
|
||||
/* GET users listing. */
|
||||
router.get('/', function(req, res, next) {
|
||||
res.send('respond with a resource');
|
||||
});
|
||||
|
||||
module.exports = router;
|
||||
@@ -0,0 +1,6 @@
|
||||
extends layout
|
||||
|
||||
block content
|
||||
h1= message
|
||||
h2= error.status
|
||||
pre #{error.stack}
|
||||
@@ -0,0 +1,10 @@
|
||||
extends layout
|
||||
|
||||
block content
|
||||
header
|
||||
#hline1
|
||||
#h1name Lärm-Messung
|
||||
#h1datum
|
||||
|
||||
|
||||
#map
|
||||
@@ -0,0 +1,48 @@
|
||||
doctype html
|
||||
html
|
||||
head
|
||||
title= title
|
||||
meta(name="viewport" content="width=device-width, initial-scale=1" charset="utf-8")
|
||||
link(href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/css/bootstrap.min.css"
|
||||
rel="stylesheet" integrity="sha384-rbsA2VBKQhggwzxH7pPCaAqO46MgnOM80zW1RWuH61DGLwZJEdK2Kadq2F9CUG65"
|
||||
crossorigin="anonymous")
|
||||
link(rel="stylesheet" href="https://unpkg.com/leaflet@1.9.3/dist/leaflet.css"
|
||||
integrity="sha256-kLaT2GOSpHechhsozzB+flnD+zUyjE2LlfWPgU04xyI="
|
||||
crossorigin="")
|
||||
link(rel='stylesheet', href='/stylesheets/MarkerCluster.css')
|
||||
link(rel='stylesheet', href='/stylesheets/style.css')
|
||||
|
||||
script.
|
||||
let sysparams = {
|
||||
version: '#{version}',
|
||||
date: '#{date}'
|
||||
}
|
||||
let urlParams = {
|
||||
// drawlines: '#{drawlines}' === 'true',
|
||||
// starttime: '#{starttime}',
|
||||
// endtime: '#{endtime}',
|
||||
// nbrentries: '#{nbrentries}',
|
||||
// device: '#{device}',
|
||||
// coordinates: '#{coordinates}' === 'true',
|
||||
// center: JSON.parse('#{center}'),
|
||||
// zoom: '#{zoom}',
|
||||
// refresh: '#{refresh}'
|
||||
}
|
||||
|
||||
body
|
||||
#wrapper
|
||||
block content
|
||||
#author
|
||||
#mailadr
|
||||
a(href="mailto:rexfue@gmail.com") mailto:rexfue@gmail.com
|
||||
#versn
|
||||
script(src="https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/js/bootstrap.bundle.min.js"
|
||||
integrity="sha384-kenU1KFdBIe4zVF0s0G1M5b4hcpxyD9F7jL+jjXkk+Q2h455rYXK/7HAuoJl+0I4"
|
||||
crossorigin="anonymous")
|
||||
script(src="https://code.jquery.com/jquery-3.6.4.min.js"
|
||||
integrity="sha256-oP6HI9z1XaZNBrJURtCoUT5SUnxFr8s3BzRl+cbzUq8=" crossorigin="anonymous")
|
||||
script(src="https://unpkg.com/leaflet@1.9.3/dist/leaflet.js"
|
||||
integrity="sha256-WBkoXOwTeyKclOHuWtc+i2uENFpDZ9YPdf5Hf+D7ewM="
|
||||
crossorigin="")
|
||||
script(src="/javascripts/leaflet.markercluster.js")
|
||||
script(type="module" src="/javascripts/global.js")
|
||||
Reference in New Issue
Block a user