Initial map support in tables

This commit is contained in:
Matteo Gheza 2021-04-25 17:19:48 +02:00
parent 896d65d2bc
commit 03b00c5826
9 changed files with 214 additions and 36 deletions

3
.gitignore vendored
View File

@ -524,4 +524,5 @@ deployment_remotes.php
adminer.php
/server/resources/images/logo.png
/server/resources/images/owner.png
/server/resources/images/owner.png
/server/resources/images/map_cache

View File

@ -11,7 +11,8 @@
"ezyang/htmlpurifier": "^4.13",
"brick/phonenumber": "^0.2.2",
"sentry/sdk": "^3.1",
"maximebf/debugbar": "^1.16"
"maximebf/debugbar": "^1.16",
"ministryofweb/php-osm-tiles": "^2.0"
},
"license": "GPL-3.0-or-later",
"authors": [

55
server/composer.lock generated
View File

@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "d71119a494bb5ab89a682d0b2aba49eb",
"content-hash": "990b7f16635b967bd1cafc536774530d",
"packages": [
{
"name": "brick/phonenumber",
@ -825,6 +825,59 @@
},
"time": "2020-12-07T11:07:24+00:00"
},
{
"name": "ministryofweb/php-osm-tiles",
"version": "2.0.0",
"source": {
"type": "git",
"url": "https://github.com/ministryofweb/php-osm-tiles.git",
"reference": "e0fc28ffbe5afc75f2ae40a834a1792cf3d725bf"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/ministryofweb/php-osm-tiles/zipball/e0fc28ffbe5afc75f2ae40a834a1792cf3d725bf",
"reference": "e0fc28ffbe5afc75f2ae40a834a1792cf3d725bf",
"shasum": ""
},
"require": {
"php": ">=7.3"
},
"require-dev": {
"ergebnis/composer-normalize": "^2.13",
"friendsofphp/php-cs-fixer": "^2.18",
"jakub-onderka/php-console-highlighter": "^0.4",
"jakub-onderka/php-parallel-lint": "^1.0",
"phpmd/phpmd": "^2.9",
"phpunit/phpunit": "^9.5",
"squizlabs/php_codesniffer": "^3.5",
"vimeo/psalm": "^4.0"
},
"type": "library",
"autoload": {
"psr-4": {
"MinistryOfWeb\\OsmTiles\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"description": "A library to convert map tile numbers to coordinates and vice versa.",
"keywords": [
"OpenStreetMap",
"coordinate",
"geographic",
"location",
"maptile",
"osm",
"tile"
],
"support": {
"issues": "https://github.com/ministryofweb/php-osm-tiles/issues",
"source": "https://github.com/ministryofweb/php-osm-tiles/tree/2.0.0"
},
"time": "2021-03-09T07:50:25+00:00"
},
{
"name": "nikic/fast-route",
"version": "dev-master",

View File

@ -1,6 +1,8 @@
<?php
require_once 'vendor/autoload.php';
use DebugBar\StandardDebugBar;
use MinistryOfWeb\OsmTiles\Converter;
use MinistryOfWeb\OsmTiles\LatLng;
if(!file_exists("config.php") && !file_exists("../../config.php")) {
header('Location: install/install.php');
@ -199,6 +201,47 @@ class tools
print("{}");
}
}
public function convertMapAddress($lat, $lng, $zoom){
$converter = new Converter();
$point = new LatLng($lat, $lng);
$tile = $converter->toTile($point, $zoom);
$tile_servers = ["a", "b", "c"];
$tileServer = $tile_servers[array_rand($tile_servers)];
return sprintf("https://{$tileServer}.tile.openstreetmap.org/{$zoom}/%d/%d.png", $tile->getX(), $tile->getY());
}
public function cachePreviewMap($filename, $lat, $lng, $zoom=16){
$url = $this->convertMapAddress($lat, $lng, $zoom);
$options = ['http' => [
'user_agent' => 'AllertaVVF dev version (cached map previews generator)'
]];
$context = stream_context_create($options);
$data = file_get_contents($url, false, $context);
try {
if (!file_exists('resources/images/map_cache')) {
mkdir('resources/images/map_cache', 0755, true);
}
return file_put_contents("resources/images/map_cache/".$filename.".png", $data);
} catch (\Throwable $th) {
return false;
}
}
public function checkPlaceParam($place){
if(preg_match('/[+-]?\d+([.]\d+)?[;][+-]?\d+([.]\d+)?/', $place)){
$lat = explode(";", $place)[0];
$lng = explode(";", $place)[1];
$mapImageID = \Delight\Auth\Auth::createUuid();
$this->cachePreviewMap($mapImageID, $lat, $lng);
$place = $place . "#" . $mapImageID;
}
return $place;
}
}
class database

View File

@ -7,7 +7,8 @@ if($tools->validate_form("mod", "add")) {
if($tools->validate_form(['date', 'code', 'beginning', 'end', 'place', 'notes', 'type', 'token'])) {
if($_POST["token"] == $_SESSION['token']) {
bdump("adding service");
$crud->add_service($_POST["date"], $_POST["code"], $_POST["beginning"], $_POST["end"], $_POST["chief"][0], $tools->extract_unique($_POST["drivers"]), $tools->extract_unique($_POST["crew"]), $_POST["place"], $_POST["notes"], $_POST["type"], $tools->extract_unique([$_POST["chief"],$_POST["drivers"],$_POST["crew"]]), $user->name());
$place = $tools->checkPlaceParam($_POST["place"]);
$crud->add_service($_POST["date"], $_POST["code"], $_POST["beginning"], $_POST["end"], $_POST["chief"][0], $tools->extract_unique($_POST["drivers"]), $tools->extract_unique($_POST["crew"]), $place, $_POST["notes"], $_POST["type"], $tools->extract_unique([$_POST["chief"],$_POST["drivers"],$_POST["crew"]]), $user->name());
$tools->redirect("services.php");
} else {
debug(); //TODO: remove debug info
@ -20,7 +21,8 @@ if($tools->validate_form("mod", "add")) {
if($_POST["token"] == $_SESSION['token']) {
bdump($_POST);
bdump("editing service");
$crud->edit_service($_POST["id"], $_POST["date"], $_POST["code"], $_POST["beginning"], $_POST["end"], $_POST["chief"][0], $tools->extract_unique($_POST["drivers"]), $tools->extract_unique($_POST["crew"]), $_POST["place"], $_POST["notes"], $_POST["type"], $tools->extract_unique([$_POST["chief"],$_POST["drivers"],$_POST["crew"]]), $user->name());
$place = $tools->checkPlaceParam($_POST["place"]);
$crud->edit_service($_POST["id"], $_POST["date"], $_POST["code"], $_POST["beginning"], $_POST["end"], $_POST["chief"][0], $tools->extract_unique($_POST["drivers"]), $tools->extract_unique($_POST["crew"]), $place, $_POST["notes"], $_POST["type"], $tools->extract_unique([$_POST["chief"],$_POST["drivers"],$_POST["crew"]]), $user->name());
$tools->redirect("services.php");
} else {
debug();

View File

@ -7,7 +7,8 @@ if($tools->validate_form("mod", "add")) {
if($tools->validate_form(['date', 'name', 'start_time', 'end_time', 'place', 'notes', 'token'])) {
if($_POST["token"] == $_SESSION['token']) {
bdump("adding training");
$crud->add_training($_POST["date"], $_POST["name"], $_POST["start_time"], $_POST["end_time"], $_POST["chief"][0], $tools->extract_unique($_POST["crew"]), $_POST["place"], $_POST["notes"], $tools->extract_unique([$_POST["chief"],$_POST["crew"]]), $user->name());
$place = $tools->checkPlaceParam($_POST["place"]);
$crud->add_training($_POST["date"], $_POST["name"], $_POST["start_time"], $_POST["end_time"], $_POST["chief"][0], $tools->extract_unique($_POST["crew"]), $place, $_POST["notes"], $tools->extract_unique([$_POST["chief"],$_POST["crew"]]), $user->name());
$tools->redirect("trainings.php");
} else {
debug(); //TODO: remove debug info
@ -20,7 +21,8 @@ if($tools->validate_form("mod", "add")) {
if($_POST["token"] == $_SESSION['token']) {
bdump($_POST);
bdump("editing training");
$crud->edit_training($_POST["id"], $_POST["date"], $_POST["name"], $_POST["start_time"], $_POST["end_time"], $_POST["chief"][0], $tools->extract_unique($_POST["crew"]), $_POST["place"], $_POST["notes"], $tools->extract_unique([$_POST["chief"],$_POST["crew"]]), $user->name());
$place = $tools->checkPlaceParam($_POST["place"]);
$crud->edit_training($_POST["id"], $_POST["date"], $_POST["name"], $_POST["start_time"], $_POST["end_time"], $_POST["chief"][0], $tools->extract_unique($_POST["crew"]), $place, $_POST["notes"], $tools->extract_unique([$_POST["chief"],$_POST["crew"]]), $user->name());
$tools->redirect("trainings.php");
} else {
debug();

View File

@ -35,7 +35,9 @@ function setMarker (LatLng) {
marker = L.marker(LatLng, { icon: iconDefault }).addTo(map);
}
export function loadMap (lat = undefined, lng = undefined, selectorId = undefined, select = true) {
var mapsList = [];
export function loadMap (lat = undefined, lng = undefined, selectorId = undefined, select = true, removeMap = false) {
console.log("Loading map...", [lat, lng, selectorId, select]);
console.trace();
if (lat === undefined && lng === undefined) {
@ -47,15 +49,25 @@ export function loadMap (lat = undefined, lng = undefined, selectorId = undefine
}
let container = L.DomUtil.get(selectorId);
if(container._leaflet_id){
console.log("Skipping map loading because already loaded...");
return true;
console.log(mapsList);
if(removeMap){
mapsList[0].off();
mapsList[0].remove();
mapsList.splice(0, 1);
} else {
console.log("Skipping map loading because already loaded...");
return true;
}
}
const zoom = select ? 10 : 17;
const latLng = new L.LatLng(lat, lng);
L.Map.addInitHook(function () {
mapsList.push(this); // Use whatever global scope variable you like.
});
map = new L.Map(selectorId, { zoomControl: true });
const osmUrl = "https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png";
const osmAttribution = "Map data &copy; 2012 <a href=\"http://openstreetmap.org\">OpenStreetMap</a> contributors";
const osmAttribution = '&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors';
const osm = new L.TileLayer(osmUrl, { maxZoom: 20, attribution: osmAttribution });
map.setView(latLng, zoom).addLayer(osm);
@ -213,4 +225,3 @@ export function addrSearch (stringResultsFound= undefined, stringResultsNotFound
return false;
}
}

View File

@ -21,15 +21,71 @@ export default async function fillTable ({ data, replaceLatLngWithMap = false, c
$.each(item, function (cellNum, i) {
if (i !== null) {
if (replaceLatLngWithMap && i.match(/[+-]?\d+([.]\d+)?[;][+-]?\d+([.]\d+)?/gm)) { /* credits to @visoom https://github.com/visoom */
const lat = i.split(";")[0];
const lng = i.split(";")[1];
let lat = i.split(";")[0];
let lng = i.split(";")[1];
let mapImageID = undefined;
if(lng.includes("#")){
lng = lng.split("#")[0];
mapImageID = i.split("#")[1];
}
const mapDiv = document.createElement("div");
mapDiv.className = "map";
mapDiv.id = "map-" + rowNum;
const mapScript = document.createElement("script");
console.log("Load map", [lat, lng, mapDiv.id]);
mapScript.appendChild(document.createTextNode("allertaJS.maps.loadMap(" + lat + ", " + lng + ", \"map-" + rowNum + "\", false)"));
mapDiv.appendChild(mapScript);
const mapModal = document.createElement("div");
mapModal.id = "map-modal-" + rowNum;
mapModal.classList.add("modal");
mapModal.classList.add("map-modal");
mapModal.setAttribute("role", "dialog");
mapModal.setAttribute("tabindex", "-1");
mapModal.innerHTML = `<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Map</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body" id="map-modal-${rowNum}-body">
<div id="map-container-${rowNum}" class="map"></div><br>
<p>Lat: <b id="map-${rowNum}-lat">${lat}</b></p>
<p>Lng: <b id="map-${rowNum}-lng">${lng}</b></p>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
</div>
</div>
</div>`;
document.body.appendChild(mapModal);
if(mapImageID !== undefined){
const mapPreview = document.createElement("figure");
const mapPreviewImage = document.createElement("img");
console.log("Adding map image", [lat, lng, mapImageID, mapDiv.id]);
mapPreviewImage.src = "resources/images/map_cache/" + mapImageID + ".png";
mapPreview.appendChild(mapPreviewImage);
const mapPreviewCaption = document.createElement("figcaption");
const mapPreviewModalOpener = document.createElement("a");
mapPreviewCaption.style.cursor = "pointer";
mapPreviewModalOpener.id = "map-opener-" + rowNum;
mapPreviewModalOpener.classList.add("map-opener");
mapPreviewModalOpener.classList.add("pjax_disable");
mapPreviewModalOpener.innerText = "Premi qui per aprire la mappa interattiva";
mapPreviewCaption.appendChild(mapPreviewModalOpener);
mapPreview.appendChild(mapPreviewCaption);
mapDiv.appendChild(mapPreview);
} else {
const mapModalOpener = document.createElement("a");
mapModalOpener.id = "map-opener-" + rowNum;
mapModalOpener.href = "#";
mapModalOpener.classList.add("map-opener");
mapModalOpener.classList.add("pjax_disable");
mapModalOpener.innerText = "Premi qui per aprire la mappa interattiva";
mapDiv.appendChild(mapModalOpener);
}
const cell = document.createElement("td");
cell.appendChild(mapDiv);
row.appendChild(cell);
@ -80,3 +136,26 @@ export default async function fillTable ({ data, replaceLatLngWithMap = false, c
}
window.tableDt = tableDt;
}
$(function() {
document.querySelector("tbody").addEventListener('click', function(e) {
if(e.target.classList.contains("map-opener")) {
console.log(e);
let id = e.target.id.replace("map-opener-", "");
console.log(id);
$("#map-modal-"+id).modal('show');
}
});
$('body').on('shown.bs.modal', function (e) {
console.log(e);
if(e.target.classList.contains("map-modal")) {
let id = e.target.id.replace("map-modal-", "");
console.log(id);
let lat = $("#map-"+id+"-lat").text();
let lng = $("#map-"+id+"-lng").text();
console.log(lat);
console.log(lng);
allertaJS.maps.loadMap(lat, lng, "map-container-"+id, false, true);
}
});
});

View File

@ -5,23 +5,9 @@ export default async function fillTable ({ data, replaceLatLngWithMap = false, c
row.id = "row-" + rowNum;
$.each(item, function (cellNum, i) {
if (i !== null) {
if (replaceLatLngWithMap && i.match(/[+-]?\d+([.]\d+)?[;][+-]?\d+([.]\d+)?/gm)) { /* credits to @visoom https://github.com/visoom */
const lat = i.split(";")[0];
const lng = i.split(";")[1];
const mapDiv = document.createElement("div");
mapDiv.className = "map";
mapDiv.id = "map-" + rowNum;
const mapScript = document.createElement("script");
mapScript.appendChild(document.createTextNode("allertaJS.maps.loadMap(" + lat + ", " + lng + ", \"map-" + rowNum + "\", false)"));
mapDiv.appendChild(mapScript);
const cell = document.createElement("td");
cell.appendChild(mapDiv);
row.appendChild(cell);
} else {
const cell = document.createElement("td");
cell.innerHTML = i;
row.appendChild(cell);
}
const cell = document.createElement("td");
cell.innerHTML = i;
row.appendChild(cell);
}
});
document.getElementById("table_body").appendChild(row);