Sync up drawing sessions across browsers

This commit is contained in:
Dave Conway-Jones 2023-10-06 15:31:24 +01:00
parent 964bbfcf66
commit 4f9956d474
No known key found for this signature in database
GPG Key ID: 1DDB0E91A28C2643
5 changed files with 63 additions and 28 deletions

View File

@ -1,5 +1,6 @@
### Change Log for Node-RED Worldmap ### Change Log for Node-RED Worldmap
- v3.2.0 - Sync up drawing sessions across browsers to same map
- v3.1.0 - Add esri overlay layers, and let geojson overlay rendering be customised - v3.1.0 - Add esri overlay layers, and let geojson overlay rendering be customised
- v3.0.0 - Bump to Leaflet 1.9.4 - v3.0.0 - Bump to Leaflet 1.9.4
Move to geoman for drawing shapes. Move to geoman for drawing shapes.

View File

@ -13,6 +13,7 @@ Feel free to [![](https://img.shields.io/static/v1?label=Sponsor&message=%E2%9D%
### Updates ### Updates
- v3.2.0 - Sync up drawing sessions across browsers to same map
- v3.1.0 - Add esri overlay layers, and let geojson overlay rendering be customised - v3.1.0 - Add esri overlay layers, and let geojson overlay rendering be customised
- v3.0.0 - Bump to Leaflet 1.9.4 - v3.0.0 - Bump to Leaflet 1.9.4
Move to geoman for drawing shapes. Move to geoman for drawing shapes.

View File

@ -1,6 +1,6 @@
{ {
"name": "node-red-contrib-web-worldmap", "name": "node-red-contrib-web-worldmap",
"version": "3.1.0", "version": "3.2.0",
"description": "A Node-RED node to provide a web page of a world map for plotting things on.", "description": "A Node-RED node to provide a web page of a world map for plotting things on.",
"dependencies": { "dependencies": {
"@turf/bezier-spline": "~6.5.0", "@turf/bezier-spline": "~6.5.0",

View File

@ -69,12 +69,22 @@ module.exports = function(RED) {
RED.httpNode.use(node.path, express.static(__dirname + '/worldmap')); RED.httpNode.use(node.path, express.static(__dirname + '/worldmap'));
// RED.httpNode.use(node.path, express.static(__dirname + '/worldmap', {maxage:3600000})); // RED.httpNode.use(node.path, express.static(__dirname + '/worldmap', {maxage:3600000}));
var sendToRest = function(m,id) {
for (var c in clients) {
if (clients.hasOwnProperty(c) && c !== id) {
// console.log("RESEND",m);
clients[c].write(JSON.stringify(m));
}
}
}
var callback = function(client) { var callback = function(client) {
if (!client.headers.hasOwnProperty("user-agent")) { client.close(); } if (!client.headers.hasOwnProperty("user-agent")) { client.close(); }
//client.setMaxListeners(0); //client.setMaxListeners(0);
clients[client.id] = client; clients[client.id] = client;
client.on('data', function(message) { client.on('data', function(message) {
message = JSON.parse(message); message = JSON.parse(message);
// console.log("ACTION",message.action,client.id,message)
if (message.action === "connected") { if (message.action === "connected") {
var m = {}; var m = {};
var c = {init:true}; var c = {init:true};
@ -113,6 +123,26 @@ module.exports = function(RED) {
o.map(v => delete v.tout); o.map(v => delete v.tout);
setTimeout(function() { client.write(JSON.stringify(o)) }, 250); setTimeout(function() { client.write(JSON.stringify(o)) }, 250);
} }
if (message.action === "draw") {
delete message.action;
delete message.type;
delete message.options?.pane;
allPoints[message.name] = RED.util.cloneMessage(message);
sendToRest(message,client.id);
}
if (message.action === "point") {
delete message.action;
sendToRest(message,client.id);
}
if (message.action === "move") {
delete message.action;
delete message.from;
sendToRest(message,client.id);
}
if (message.action === "delete") {
delete allPoints[message.name];
sendToRest(message,client.id);
}
}); });
client.on('close', function() { client.on('close', function() {
delete clients[client.id]; delete clients[client.id];

View File

@ -28,7 +28,7 @@ var heat;
var minimap; var minimap;
var sidebyside; var sidebyside;
var layercontrol; var layercontrol;
// var drawControl; var drawCount = 0;
var drawingColour = "#910000"; var drawingColour = "#910000";
var sendDrawing; var sendDrawing;
var colorControl; var colorControl;
@ -418,17 +418,17 @@ var Lgrid = L.latlngGraticule({
// Copyright (c) 2013 Måns Beckman, All rights reserved. // Copyright (c) 2013 Måns Beckman, All rights reserved.
var edgeAware = function() { var edgeAware = function() {
if (!edgeEnabled) { return; } if (!edgeEnabled) { return; }
map.removeLayer(edgeLayer) map.removeLayer(edgeLayer)
edgeLayer = new L.layerGroup(); edgeLayer = new L.layerGroup();
var mapBounds = map.getBounds(); var mapBounds = map.getBounds();
var mapBoundsCenter = mapBounds.getCenter(); var mapBoundsCenter = mapBounds.getCenter();
pSW = map.options.crs.latLngToPoint(mapBounds.getSouthWest(), map.getZoom()); pSW = map.options.crs.latLngToPoint(mapBounds.getSouthWest(), map.getZoom());
pNE = map.options.crs.latLngToPoint(mapBounds.getNorthEast(), map.getZoom()); pNE = map.options.crs.latLngToPoint(mapBounds.getNorthEast(), map.getZoom());
pCenter = map.options.crs.latLngToPoint(mapBoundsCenter, map.getZoom()); pCenter = map.options.crs.latLngToPoint(mapBoundsCenter, map.getZoom());
var viewBounds = L.latLngBounds(map.options.crs.pointToLatLng(L.point(pSW.x - (pCenter.x - pSW.x ), pSW.y - (pCenter.y - pSW.y )), map.getZoom()) , map.options.crs.pointToLatLng(L.point(pNE.x + (pNE.x - pCenter.x) , pNE.y + (pNE.y - pCenter.y) ), map.getZoom()) ); var viewBounds = L.latLngBounds(map.options.crs.pointToLatLng(L.point(pSW.x - (pCenter.x - pSW.x ), pSW.y - (pCenter.y - pSW.y )), map.getZoom()) , map.options.crs.pointToLatLng(L.point(pNE.x + (pNE.x - pCenter.x) , pNE.y + (pNE.y - pCenter.y) ), map.getZoom()) );
for (var id in markers) { for (var id in markers) {
if (allData[id] && allData[id].hasOwnProperty("SIDC")) { if (allData[id] && allData[id].hasOwnProperty("SIDC")) {
markerLatLng = markers[id].getLatLng(); markerLatLng = markers[id].getLatLng();
if ( viewBounds.contains(markerLatLng) && !mapBounds.contains(markerLatLng) ) { if ( viewBounds.contains(markerLatLng) && !mapBounds.contains(markerLatLng) ) {
@ -471,8 +471,8 @@ var edgeAware = function() {
edgeLayer.addLayer(L.marker([lat,lng],{icon:myicon})) edgeLayer.addLayer(L.marker([lat,lng],{icon:myicon}))
} }
} }
} }
edgeLayer.addTo(map) edgeLayer.addTo(map)
} }
// end of edge function // end of edge function
@ -814,7 +814,7 @@ var addThing = function() {
//popped = false; //popped = false;
var bits = thing.split(","); var bits = thing.split(",");
var icon = (bits[1] || "circle").trim(); var icon = (bits[1] || "circle").trim();
var lay = (bits[2] || "_drawing").trim(); var lay = (bits[2] || "unknown").trim(); // TODO: Do we want _drawing here or unknown ?
var colo = (bits[3] ?? "#910000").trim(); var colo = (bits[3] ?? "#910000").trim();
colo = colorKeywordToRGB(colo); colo = colorKeywordToRGB(colo);
var hdg = parseFloat(bits[4] || 0); var hdg = parseFloat(bits[4] || 0);
@ -1086,7 +1086,6 @@ var addOverlays = function(overlist) {
layers["_drawing"] = new L.FeatureGroup(); layers["_drawing"] = new L.FeatureGroup();
overlays["drawing"] = layers["_drawing"]; overlays["drawing"] = layers["_drawing"];
var drawCount = 0;
map.pm.addControls({ map.pm.addControls({
position: 'topleft', position: 'topleft',
drawMarker: false, drawMarker: false,
@ -1102,18 +1101,19 @@ var addOverlays = function(overlist) {
color: drawingColour, color: drawingColour,
fillColor: drawingColour, fillColor: drawingColour,
fillOpacity: 0.4 fillOpacity: 0.4
}); });
} }
var shape; var shape;
map.on("pm:create", (e) => { map.on("pm:create", (e) => {
var name = e.shape + drawCount;
drawCount = drawCount + 1; drawCount = drawCount + 1;
var name = e.shape + drawCount;
e.layer.on('contextmenu', function(e) { e.layer.on('contextmenu', function(e) {
L.DomEvent.stopPropagation(e); L.DomEvent.stopPropagation(e);
var name = e.target.name;
var rmen = L.popup({offset:[0,-12]}).setLatLng(e.latlng); var rmen = L.popup({offset:[0,-12]}).setLatLng(e.latlng);
rmen.setContent("<input type='text' value='"+e.target.name+"' id='dinput' placeholder='name (,icon, layer)'/><br/><button onclick='editPoly(\""+e.target.name+"\");'>Edit points</button><button onclick='editPoly(\""+e.target.name+"\",\"drag\");'>Drag</button><button onclick='editPoly(\""+e.target.name+"\",\"rot\");'>Rotate</button><button onclick='delMarker(\""+e.target.name+"\",true);'>Delete</button><button onclick='sendDrawing();'>OK</button>"); rmen.setContent("<input type='text' value='"+name+"' id='dinput' placeholder='name (,icon, layer)'/><br/><button onclick='editPoly(\""+name+"\");'>Edit points</button><button onclick='editPoly(\""+name+"\",\"drag\");'>Drag</button><button onclick='editPoly(\""+name+"\",\"rot\");'>Rotate</button><button onclick='delMarker(\""+name+"\",true);'>Delete</button><button onclick='sendDrawing();'>OK</button>");
map.openPopup(rmen); map.openPopup(rmen);
}); });
e.layer.bindPopup(name); e.layer.bindPopup(name);
@ -1127,7 +1127,7 @@ var addOverlays = function(overlist) {
else { else {
cent = e.layer.getBounds().getCenter(); cent = e.layer.getBounds().getCenter();
} }
var m = {action:"draw", name:name, type:e.shape, layer:"_drawing", options:e.layer.options, radius:e.layer._mRadius, lat:la, lon:lo}; var m = {action:"draw", name:name, type:e.shape, layer:"_drawing", options:e.layer.options, radius:e.layer._mRadius, lat:la, lon:lo, drawCount:drawCount};
if (e.layer.hasOwnProperty("_latlngs")) { if (e.layer.hasOwnProperty("_latlngs")) {
if (e.layer.options.fill === false) { m.line = e.layer._latlngs; } if (e.layer.options.fill === false) { m.line = e.layer._latlngs; }
else { m.area = e.layer._latlngs[0]; } else { m.area = e.layer._latlngs[0]; }
@ -1250,6 +1250,8 @@ var addOverlays = function(overlist) {
sendDrawing(n); sendDrawing(n);
}); });
} }
changeDrawColour("#4040F0"); // Set default drawing color to blue on start
} }
// Add the countries (world-110m) for offline use // Add the countries (world-110m) for offline use
@ -1496,15 +1498,15 @@ function setMarker(data) {
var ll; var ll;
var lli = null; var lli = null;
var opt = {}; var opt = data.options || {};
opt.color = data.color ?? data.lineColor ?? "#910000"; opt.color = opt.color ?? data.color ?? data.lineColor ?? "#910000";
opt.fillColor = data.fillColor ?? "#910000"; opt.fillColor = opt.fillColor ?? data.fillColor ?? "#910000";
opt.stroke = (data.hasOwnProperty("stroke")) ? data.stroke : true; opt.stroke = opt.stroke ?? (data.hasOwnProperty("stroke")) ? data.stroke : true;
opt.weight = data.weight; opt.weight = opt.weight ?? data.weight;
opt.opacity = data.opacity; opt.opacity = opt.opacity ?? data.opacity;
opt.fillOpacity = data.fillOpacity; opt.fillOpacity = opt.fillOpacity ?? data.fillOpacity;
opt.clickable = (data.hasOwnProperty("clickable")) ? data.clickable : false; opt.clickable = (data.hasOwnProperty("clickable")) ? data.clickable : false;
opt.fill = (data.hasOwnProperty("fill")) ? data.fill : true; opt.fill = opt.fill ?? (data.hasOwnProperty("fill")) ? data.fill : true;
if (data.hasOwnProperty("dashArray")) { opt.dashArray = data.dashArray; } if (data.hasOwnProperty("dashArray")) { opt.dashArray = data.dashArray; }
if (opt.fillOpacity === undefined) { opt.fillOpacity = 0.2; } if (opt.fillOpacity === undefined) { opt.fillOpacity = 0.2; }
if (opt.opacity === undefined) { opt.opacity = 1; } if (opt.opacity === undefined) { opt.opacity = 1; }
@ -1594,6 +1596,7 @@ function setMarker(data) {
map.fitBounds(polygons[data.name].getBounds(),{padding:[50,50]}) map.fitBounds(polygons[data.name].getBounds(),{padding:[50,50]})
} }
} }
if (data.hasOwnProperty("drawCount")) { drawCount = data.drawCount; }
if (data.hasOwnProperty("greatcircle") && Array.isArray(data.greatcircle) && data.greatcircle.length === 2) { if (data.hasOwnProperty("greatcircle") && Array.isArray(data.greatcircle) && data.greatcircle.length === 2) {
delete opt.fill; delete opt.fill;
opt.vertices = opt.vertices || 20; opt.vertices = opt.vertices || 20;
@ -2528,7 +2531,7 @@ function doCommand(cmd) {
} }
if (cmd.map.hasOwnProperty("fly") && (cmd.map.fly === true)) { map.flyToBounds(overlays[cmd.map.overlay].getBounds()); } if (cmd.map.hasOwnProperty("fly") && (cmd.map.fly === true)) { map.flyToBounds(overlays[cmd.map.overlay].getBounds()); }
else if (cmd.map.hasOwnProperty("fit") && (cmd.map.fit === true)) { map.fitBounds(overlays[cmd.map.overlay].getBounds()); } else if (cmd.map.hasOwnProperty("fit") && (cmd.map.fit === true)) { map.fitBounds(overlays[cmd.map.overlay].getBounds()); }
} }
catch(e) { console.log(e); } catch(e) { console.log(e); }
} }
// Add a new NVG XML overlay layer // Add a new NVG XML overlay layer