Add routing option to draw line

This commit is contained in:
Dave Conway-Jones 2020-11-19 11:48:54 +00:00
parent e95e7699f6
commit ab7bbbe34d
No known key found for this signature in database
GPG Key ID: 88BA2B8A411BE9FF
5 changed files with 108 additions and 15 deletions

View File

@ -1,5 +1,6 @@
### Change Log for Node-RED Worldmap
- v2.6.0 - Add route capability to draw line when online
- v2.5.9 - Fix handling of multiple hulls, tidy contextmenu handling
- v2.5.8 - Let node name be the full page map title
- v2.5.7 - Let fillColor set color of hulls

View File

@ -11,6 +11,7 @@ map web page for plotting "things" on.
### Updates
- v2.6.0 - Add route capability to draw line when online
- v2.5.9 - Fix handling of multiple hulls, tidy contextmenu handling
- v2.5.8 - Let node name be the full page map title
- v2.5.7 - Let fillColor set color of hulls
@ -111,18 +112,19 @@ There are also several special icons...
#### NATO Symbology
You can use NATO symbols from <a href="https://github.com/spatialillusions/milsymbol" target="mapinfo">milsymbol.js</a>.
To do this you need to supply a `msg.SIDC` instead of an icon, for example:
To do this you need to supply a `msg.payload.SIDC` instead of an icon, for example:
msg.payload = { "name": "Emergency Medical Operation",
msg.payload = {
"name": "Emergency Medical Operation",
"lat": 51.05,
"lon": -1.35,
"SIDC": "ENOPA-------",
"options": { "fillOpacity":0.8 }
"options": { "fillOpacity":0.8, "additionalInformation":"Extra info" }
}
SIDC codes can be generated using the online tool - https://spatialillusions.com/unitgenerator/
There are lots of extra options you can specify as `msg.options` - see the <a href="https://github.com/spatialillusions/milsymbol/tree/master/docs" target="mapinfo">milsymbol docs here</a>.
There are lots of extra options you can specify as `msg.payload.options` - see the <a href="https://spatialillusions.com/milsymbol/documentation.html" target="mapinfo">milsymbol docs here</a>.
### Areas, Lines and Rectangles

View File

@ -1,6 +1,6 @@
{
"name": "node-red-contrib-web-worldmap",
"version": "2.5.9",
"version": "2.6.0",
"description": "A Node-RED node to provide a web page of a world map for plotting things on.",
"dependencies": {
"cgi": "0.3.1",

View File

@ -143,7 +143,7 @@ then by default <code>⌘⇧m</code> - <code>ctrl-shift-m</code> will load the m
<p>Icons of type <i>plane</i>, <i>ship</i>, <i>car</i>, <i>uav</i> or <i>arrow</i> will use built in SVG icons that align to the
<code>bearing</code> value.</p>
<p>Font Awesome (<a href="https://fontawesome.com/v4.7.0/icons/" target="_new">fa-icons 4.7</a>) can also be used, as can
NATO symbology codes (SIDC), or <a href="https://github.com/dceejay/RedMap/blob/master/emojilist.md" target="_new">:emoji name:</a>,
NATO symbology codes (<a href="https://spatialillusions.com/unitgenerator/">SIDC</a>), or <a href="https://github.com/dceejay/RedMap/blob/master/emojilist.md" target="_new">:emoji name:</a>,
or the url of a small icon image (32x32)</p>
<p>See the <a href="https://www.npmjs.com/package/node-red-contrib-web-worldmap" target="_new">README</a> for further
details and examples of icons and commands for drawing <b>lines</b> and <b>areas</b>, and to <b>add layers</b> and

View File

@ -764,15 +764,6 @@ basemaps["Watercolor"] = L.tileLayer(watercolorUrl, {
// Now add the overlays
// Add the countries (world-110m) for offline use
var customTopoLayer = L.geoJson(null, {clickable:false, style: {color:"blue", weight:2, fillColor:"#cf6", fillOpacity:0.04}});
layers["_countries"] = omnivore.topojson('images/world-50m-flat.json',null,customTopoLayer);
overlays["countries"] = layers["_countries"];
// Add the day/night overlay
layers["_daynight"] = new L.LayerGroup();
overlays["day/night"] = layers["_daynight"];
// Add the drawing layer for fun...
layers["_drawing"] = new L.FeatureGroup();
overlays["drawing"] = layers["_drawing"];
@ -837,10 +828,100 @@ map.on('draw:created', function (e) {
layers["_drawing"].addLayer(shape.layer);
var rightmenuMarker = L.popup({offset:[0,-12]}).setContent("<input type='text' autofocus value='"+name+"' id='dinput' placeholder='name (,icon, layer)'/><br/><button onclick='editPoly(\""+name+"\",true);'>Edit points</button><button onclick='delMarker(\""+name+"\",true);'>Delete</button><button onclick='sendDrawing(\""+name+"\");'>OK</button>");
if (e.layer.options.fill === false && navigator.onLine) {
rightmenuMarker = L.popup({offset:[0,-12]}).setContent("<input type='text' autofocus value='"+name+"' id='dinput' placeholder='name (,icon, layer)'/><br/><button onclick='editPoly(\""+name+"\",true);'>Edit points</button><button onclick='delMarker(\""+name+"\",true);'>Delete</button><button onclick='sendRoute(\""+name+"\");'>Route</button><button onclick='sendDrawing(\""+name+"\");'>OK</button>");
}
rightmenuMarker.setLatLng(cent);
setTimeout(function() {map.openPopup(rightmenuMarker)},25);
});
var defaultOptions = function () {
var options = {};
options.precision = 5;
options.factor = Math.pow(10, options.precision);
options.dimension = 2;
return options;
};
var decode = function (encoded, options) {
options = defaultOptions(options);
var flatPoints = decodeDeltas(encoded);
var points = [];
for (var i = 0, len = flatPoints.length; i + (options.dimension - 1) < len;) {
var point = [];
for (var dim = 0; dim < options.dimension; ++dim) {
point.push(flatPoints[i++]);
}
points.push(point);
}
return points;
}
var decodeDeltas = function (encoded, options) {
options = defaultOptions(options);
var lastNumbers = [];
var numbers = decodeFloats(encoded, options);
for (var i = 0, len = numbers.length; i < len;) {
for (var d = 0; d < options.dimension; ++d, ++i) {
numbers[i] = Math.round((lastNumbers[d] = numbers[i] + (lastNumbers[d] || 0)) * options.factor) / options.factor;
}
}
return numbers;
}
var decodeFloats = function (encoded, options) {
options = defaultOptions(options);
var numbers = decodeSignedIntegers(encoded);
for (var i = 0, len = numbers.length; i < len; ++i) {
numbers[i] /= options.factor;
}
return numbers;
}
var decodeSignedIntegers = function (encoded) {
var numbers = decodeUnsignedIntegers(encoded);
for (var i = 0, len = numbers.length; i < len; ++i) {
var num = numbers[i];
numbers[i] = (num & 1) ? ~(num >> 1) : (num >> 1);
}
return numbers;
}
var decodeUnsignedIntegers = function (encoded) {
var numbers = [];
var current = 0;
var shift = 0;
for (var i = 0, len = encoded.length; i < len; ++i) {
var b = encoded.charCodeAt(i) - 63;
current |= (b & 0x1f) << shift;
if (b < 0x20) {
numbers.push(current);
current = 0;
shift = 0;
} else {
shift += 5;
}
}
return numbers;
}
var sendRoute = function(n) {
var p = (polygons[n]._latlngs.map(function(x) {
return x.lng+","+x.lat;
})).join(';');
fetch('https://router.project-osrm.org/route/v1/driving/'+p)
.then(response => response.json())
.then(data => {
if (data.code !== "Ok") { sendDrawing(n); }
var r = decode(data.routes[0].geometry).map( x => L.latLng(x[0],x[1]) );
polygons[n]._latlngs = r;
shape.m.line = r;
sendDrawing(n);
});
}
var sendDrawing = function(n) {
var thing = document.getElementById('dinput').value;
map.closePopup();
@ -854,6 +935,15 @@ var sendDrawing = function(n) {
ws.send(JSON.stringify(shape.m));
}
// Add the countries (world-110m) for offline use
var customTopoLayer = L.geoJson(null, {clickable:false, style: {color:"blue", weight:2, fillColor:"#cf6", fillOpacity:0.04}});
layers["_countries"] = omnivore.topojson('images/world-50m-flat.json',null,customTopoLayer);
overlays["countries"] = layers["_countries"];
// Add the day/night overlay
layers["_daynight"] = new L.LayerGroup();
overlays["day/night"] = layers["_daynight"];
// Add the heatmap layer
var heat = L.heatLayer([], {radius:60, gradient:{0.2:'blue', 0.4:'lime', 0.6:'red', 0.8:'yellow', 1:'white'}});
layers["_heat"] = new L.LayerGroup().addLayer(heat);