tidy up zoom levels for most maps, and
make sure lines and areas work, and fixup css
This commit is contained in:
parent
e9c096b6d1
commit
132dd6758d
17
README.md
17
README.md
@ -8,7 +8,7 @@ map web page for plotting "things" on.
|
||||
- v1.0.x - now uses socket.io to connect to backend - means this node now has an input connection
|
||||
(like "proper" nodes should :-), and you no longer need a websocket node in parallel.
|
||||
Obviously this is a breaking change hence the major version number bump. Also thus adds a `worldmap in`
|
||||
node to handle events coming from the map interaction. (to be documented more fully but are fairly obvious).
|
||||
node to handle events coming from the map interaction.
|
||||
|
||||
### Install
|
||||
|
||||
@ -34,6 +34,7 @@ Optional properties include
|
||||
- **accuracy** : combined with bearing, draws a polygon of possible direction.
|
||||
- **icon** : <a href="http://fortawesome.github.io/Font-Awesome/icons/" target="_new">font awesome</a> icon name.
|
||||
- **iconColor** : Standard CSS color name or #rrggbb hex value.
|
||||
- **photoUrl** : adds an image pointed at by the url to the popup box.
|
||||
- **deleted** : set to <i>true</i> to remove the named marker. (default false)
|
||||
|
||||
Any other `msg.payload` properties will be added to the icon popup text box.
|
||||
@ -44,27 +45,29 @@ However there are several specials...
|
||||
- **plane** : a plane icon that aligns with the bearing of travel.
|
||||
- **ship** : a ship icon that aligns with the bearing of travel.
|
||||
- **car** : a car icon that aligns with the bearing of travel.
|
||||
- **locate** : a 4 corner outline to locate a point without obscuring it.
|
||||
- **friend** : pseudo Nato style blue rectangle.
|
||||
- **hostile** : pseudo Nato style red circle.
|
||||
- **neutral** : pseudo Nato style green square.
|
||||
- **unknown** : pseudo Nato style yellow square.
|
||||
- **earthquake** : black circle - diameter proportional to magnitude.
|
||||
|
||||
#### Areas
|
||||
#### Areas and Lines
|
||||
|
||||
If the payload contains an **area** property - that is an array of co-ordinates, e.g.
|
||||
|
||||
[ [51.05, -0.08], [51.5, -1], [51.2, -0.047] ]
|
||||
|
||||
then rather than draw a point and icon it draws the polygon
|
||||
then rather than draw a point and icon it draws the polygon. Likewise if it contains a
|
||||
**line** property it will draw the polyline.
|
||||
|
||||
- **iconColor** : can set the colour of the polygon
|
||||
- **name** : is used as the id key - so can be redrawn/moved
|
||||
- **layer** : declares which layer you put it on.
|
||||
- **iconColor** : can set the colour of the polygon or line.
|
||||
- **name** : is used as the id key - so can be redrawn/moved.
|
||||
- **layer** : declares which layer you put it on..
|
||||
|
||||
### Drawing
|
||||
|
||||
A single right click will allow you to add a point to the map - you must specify the `name` and optionally the `icon` and `layer`.
|
||||
A single *right click* will allow you to add a point to the map - you must specify the `name` and optionally the `icon` and `layer`.
|
||||
|
||||
Right-clicking on an icon will allow you to delete it.
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name" : "node-red-contrib-web-worldmap",
|
||||
"version" : "1.0.9",
|
||||
"version" : "1.0.10",
|
||||
"description" : "A Node-RED node to provide a web page of a world map for plotting things on.",
|
||||
"dependencies" : {
|
||||
"express": "4.*",
|
||||
|
@ -35,12 +35,14 @@
|
||||
<li><code>accuracy</code> : combined with bearing, draws a polygon of possible direction.</li>
|
||||
<li><code>icon</code> : <a href="http://fortawesome.github.io/Font-Awesome/icons/" target="_new">font awesome</a> icon name</li>
|
||||
<li><code>iconColor</code> : standard CSS color name or #rrggbb hex value.</li>
|
||||
<li><code>photoUrl</code> : adds an image pointed at by the url to the popup box.</li>
|
||||
<li><code>deleted</code> : set to <i>true</i> to remove the named marker. (default false)</li>
|
||||
</ul>
|
||||
<p>Any other sub-properties of <code>msg.payload</code> will be added to the icon popup text box as extra information.</p>
|
||||
<p>Icons of type <i>plane</i>, <i>ship</i> or <i>car</i> will use built in SVG icons that align to the
|
||||
<code>bearing</code> value.</p>
|
||||
<p>There are some <a href="https://www.npmjs.com/package/node-red-contrib-web-worldmap" target="_new">extra commands</a> to control the map.</p>
|
||||
<p>There are some <a href="https://www.npmjs.com/package/node-red-contrib-web-worldmap" target="_new">extra commands</a>
|
||||
for drawing <b>lines</b> and <b>areas</b>, and to <b>add layers</b> and to <b>control</b> the map remotely.</p>
|
||||
</script>
|
||||
|
||||
<script type="text/javascript">
|
||||
@ -76,7 +78,6 @@
|
||||
|
||||
<script type="text/x-red" data-help-name="worldmap in">
|
||||
<p>Receives events from a worldmap web page.</p>
|
||||
<p></p>
|
||||
</script>
|
||||
|
||||
<script type="text/javascript">
|
||||
|
@ -11,27 +11,39 @@ a {
|
||||
text-decoration:none;
|
||||
}
|
||||
|
||||
.topbar {
|
||||
font-size:16px;
|
||||
vertical-align:middle;
|
||||
}
|
||||
|
||||
#topbar {
|
||||
color:#999;
|
||||
color:#c7c7c7;
|
||||
background-color:black;
|
||||
position:fixed;
|
||||
top:0px;
|
||||
left:0px;
|
||||
height:41px;
|
||||
height:40px;
|
||||
line-height:40px;
|
||||
width:100%;
|
||||
}
|
||||
|
||||
#topbar img {
|
||||
padding-left:12px;
|
||||
padding-right:8px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
#results {
|
||||
position:fixed;
|
||||
background-color:black;
|
||||
top:6px;
|
||||
right:8px;
|
||||
height:41px;
|
||||
height:40px;
|
||||
}
|
||||
|
||||
#map {
|
||||
position:fixed;
|
||||
top:41px;
|
||||
top:40px;
|
||||
bottom:0px;
|
||||
min-width:100%;
|
||||
display:block;
|
||||
@ -63,7 +75,7 @@ a {
|
||||
color:#fff;
|
||||
background-color:#000;
|
||||
position:fixed;
|
||||
top:41px;
|
||||
top:40px;
|
||||
right:0px;
|
||||
width:200px;
|
||||
z-index:9999;
|
||||
|
@ -58,8 +58,8 @@
|
||||
|
||||
<body onunload="ws.emit('end');">
|
||||
<div id="topbar">
|
||||
<a href="http://nodered.org"><img src="images/node-red.png" width="72px" height="28px" style="padding-top:4px; margin:4px; vertical-align: middle;"/></a>
|
||||
<span style="display:inline-block; padding-top:6px; vertical-align:middle;"><font size="+2"><b> Node-RED</b> map all the things</font></span>
|
||||
<a href="http://nodered.org"><img src="images/node-red.png" width="60px" height="24px"/></a>
|
||||
<span class="topbar"> Node-RED - map all the things</span>
|
||||
</div>
|
||||
<div id="results">
|
||||
<span id="searchRes"></span>
|
||||
@ -67,12 +67,12 @@
|
||||
</div>
|
||||
<div id="menu"><table>
|
||||
<tr><td><input type='text' name='search' id='search' size='20' style="width:150px;"/> <span onclick='doSearch();'><i class="fa fa-search fa-lg"></i></span></td></tr>
|
||||
<tr><td style="cursor:pointer"><i class="fa fa-spinner fa-lg fa-fw"></i> Set Max Age <input type='text' name='maxage' id='maxage' value="600" size="5" onchange='setMaxAge();'/>s</td></tr>
|
||||
<tr><td style="cursor:pointer"><i class="fa fa-search-plus fa-lg fa-fw"></i> Cluster at zoom <<input type='text' name='setclus' id='setclus' value="12" size="2" onchange='setCluster();'/></td></tr>
|
||||
<tr><td style="cursor:pointer"><input type='checkbox' name='panit' onclick='doPanit();'/> Auto Pan Map</td></tr>
|
||||
<tr><td style="cursor:pointer"><input type='checkbox' name='lockit' onclick='doLock();'/> Lock Map</td></tr>
|
||||
<tr><td style="cursor:pointer"><input type='checkbox' name='heatall' onclick='doHeatAll();'/> Heatmap all layers</td></tr>
|
||||
<tr><td style="cursor:pointer"><span id="showHelp" ><i class="fa fa-info fa-lg fa-fw"></i>Help</span></td></tr>
|
||||
<tr><td style="cursor:default"><i class="fa fa-spinner fa-lg fa-fw"></i> Set Max Age <input type='text' name='maxage' id='maxage' value="600" size="5" onchange='setMaxAge();'/>s</td></tr>
|
||||
<tr><td style="cursor:default"><i class="fa fa-search-plus fa-lg fa-fw"></i> Cluster at zoom <<input type='text' name='setclus' id='setclus' value="12" size="2" onchange='setCluster();'/></td></tr>
|
||||
<tr><td style="cursor:default"><input type='checkbox' name='panit' onclick='doPanit();'/> Auto Pan Map</td></tr>
|
||||
<tr><td style="cursor:default"><input type='checkbox' name='lockit' onclick='doLock();'/> Lock Map</td></tr>
|
||||
<tr><td style="cursor:default"><input type='checkbox' name='heatall' onclick='doHeatAll();'/> Heatmap all layers</td></tr>
|
||||
<tr><td style="cursor:default"><span id="showHelp" ><i class="fa fa-info fa-lg fa-fw"></i>Help</span></td></tr>
|
||||
</table></div>
|
||||
<div id="map"></div>
|
||||
<div id="foot"> © IBM 2015,2016</div>
|
||||
@ -142,6 +142,7 @@ ws.on('error', function() {
|
||||
ws.on('worldmapdata', function(data) {
|
||||
if (data.command) { doCommand(data.command); delete data.command; }
|
||||
if (data.hasOwnProperty("name") && data.hasOwnProperty("lat") && data.hasOwnProperty("lon")) { setMarker(data); }
|
||||
else if (data.hasOwnProperty("name") && (data.hasOwnProperty("area") || data.hasOwnProperty("line"))) { setMarker(data); }
|
||||
else { console.log("SKIP",data); }
|
||||
});
|
||||
|
||||
@ -355,6 +356,9 @@ map.on('popupclose', function(e) {
|
||||
});
|
||||
|
||||
map.on('overlayadd', function(e) {
|
||||
if (typeof overlays[e.name].bringToFront === "function") {
|
||||
overlays[e.name].bringToFront();
|
||||
}
|
||||
if (e.name == "satellite") {
|
||||
overlays["satellite"].bringToBack();
|
||||
}
|
||||
@ -398,7 +402,7 @@ map.on('baselayerchange', function(e) {
|
||||
|
||||
map.on('zoomend', function() {
|
||||
setTimeout( function() {
|
||||
//console.log("ZOOM=",map.getZoom());
|
||||
console.log("ZOOM :",map.getZoom());
|
||||
for (var key in markers) {
|
||||
if (polygons[key]) {
|
||||
var vis = layers[markers[key].lay].getVisibleParent(markers[key]);
|
||||
@ -459,9 +463,9 @@ map.on('contextmenu', function(e) {
|
||||
});
|
||||
|
||||
function onLocationFound(e) {
|
||||
//var radius = e.accuracy / 2;
|
||||
var radius = e.accuracy;
|
||||
//L.marker(e.latlng).addTo(map).bindPopup("You are within " + radius + " meters from this point").openPopup();
|
||||
//L.circle(e.latlng, radius).addTo(map);
|
||||
L.circle(e.latlng, radius, {color:"cyan", weight:3, opacity:0.8, fill:false, clickable:false}).addTo(map);
|
||||
}
|
||||
function onLocationError(e) { console.log(e.message); }
|
||||
map.on('locationfound', onLocationFound);
|
||||
@ -491,18 +495,18 @@ basemaps["Esri Satellite"] = Esri_WorldImagery;
|
||||
|
||||
var Esri_WorldShadedRelief = L.tileLayer('http://server.arcgisonline.com/ArcGIS/rest/services/World_Shaded_Relief/MapServer/tile/{z}/{y}/{x}', {
|
||||
attribution: 'Tiles © Esri — Source: Esri',
|
||||
maxZoom: 15
|
||||
maxNativeZoom: 13
|
||||
});
|
||||
basemaps["Esri Terrain"] = Esri_WorldShadedRelief;
|
||||
|
||||
var Esri_OceanBasemap = L.tileLayer('http://server.arcgisonline.com/ArcGIS/rest/services/Ocean_Basemap/MapServer/tile/{z}/{y}/{x}', {
|
||||
attribution: 'Tiles © Esri — Sources: GEBCO, NOAA, CHS, OSU, UNH, CSUMB, National Geographic, DeLorme, NAVTEQ, and Esri',
|
||||
maxZoom: 15
|
||||
maxNativeZoom: 10
|
||||
});
|
||||
basemaps["Esri Ocean"] = Esri_OceanBasemap;
|
||||
|
||||
var OpenMapSurfer_Roads = L.tileLayer('http://korona.geog.uni-heidelberg.de/tiles/roads/x={x}&y={y}&z={z}', {
|
||||
maxZoom: 20,
|
||||
maxZoom: 18,
|
||||
attribution: 'Imagery from <a href="http://giscience.uni-hd.de/">GIScience Research Group @ University of Heidelberg</a> — Map data © <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a>'
|
||||
});
|
||||
basemaps["Mapsurfer"] = OpenMapSurfer_Roads;
|
||||
@ -511,13 +515,14 @@ var MapQuestOpen_OSM = L.tileLayer('http://otile{s}.mqcdn.com/tiles/1.0.0/{type}
|
||||
type: 'map',
|
||||
ext: 'jpg',
|
||||
attribution: 'Tiles Courtesy of <a href="http://www.mapquest.com/">MapQuest</a> — Map data © <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a>',
|
||||
subdomains: '1234'
|
||||
subdomains: '1234',
|
||||
maxNativeZoom: 17
|
||||
});
|
||||
basemaps["MapQuest OSM"] = MapQuestOpen_OSM;
|
||||
|
||||
var Esri_NatGeoWorldMap = L.tileLayer('http://server.arcgisonline.com/ArcGIS/rest/services/NatGeo_World_Map/MapServer/tile/{z}/{y}/{x}', {
|
||||
attribution: 'Tiles © Esri — National Geographic, Esri, DeLorme, NAVTEQ, UNEP-WCMC, USGS, NASA, ESA, METI, NRCAN, GEBCO, NOAA, iPC',
|
||||
maxZoom: 16
|
||||
maxNativeZoom: 12
|
||||
});
|
||||
basemaps["Nat Geo"] = Esri_NatGeoWorldMap;
|
||||
|
||||
@ -525,7 +530,7 @@ var NLS_OS_opendata = L.tileLayer('http://geo.nls.uk/maps/opendata/{z}/{x}/{y}.p
|
||||
attribution: '<a href="http://geo.nls.uk/maps/">National Library of Scotland Historic Maps</a>',
|
||||
bounds: [[49.6, -12], [61.7, 3]],
|
||||
minZoom: 1,
|
||||
maxZoom: 18,
|
||||
maxNativeZoom: 16,
|
||||
subdomains: '0123'
|
||||
});
|
||||
basemaps["UK OS Opendata"] = NLS_OS_opendata;
|
||||
@ -609,13 +614,13 @@ overlays["roads"] = L.tileLayer('http://otile{s}.mqcdn.com/tiles/1.0.0/{type}/{z
|
||||
});
|
||||
|
||||
overlays["rain"] = L.tileLayer('http://{s}.tile.openweathermap.org/map/rain/{z}/{x}/{y}.png', {
|
||||
maxZoom: 19,
|
||||
maxZoom: 18,
|
||||
attribution: 'Map data © <a href="http://openweathermap.org">OpenWeatherMap</a>',
|
||||
opacity: 0.5
|
||||
});
|
||||
|
||||
overlays["pressure"] = L.tileLayer('http://{s}.tile.openweathermap.org/map/pressure_cntr/{z}/{x}/{y}.png', {
|
||||
maxZoom: 19,
|
||||
maxZoom: 18,
|
||||
attribution: 'Map data © <a href="http://openweathermap.org">OpenWeatherMap</a>',
|
||||
opacity: 0.5
|
||||
});
|
||||
@ -676,11 +681,17 @@ function setMarker(data) {
|
||||
if (data.deleted) { // remove markers we are told to
|
||||
delMarker(data.name);
|
||||
}
|
||||
else if (data.hasOwnProperty("area") && Array.isArray(data.area)) {
|
||||
else if (data.hasOwnProperty("line") && Array.isArray(data.line)) {
|
||||
var col = data.iconColor || "#910000";
|
||||
var polygon = L.polygon(data.area, {stroke:true, weight:2, color:col, fillColor:col, fillOpacity:0.2, clickable:false});
|
||||
polygons[data.name] = polygon;
|
||||
layers[lay].addLayer(polygon);
|
||||
var polyln = L.polyline(data.line, {stroke:true, weight:3, color:col, opacity:0.8, clickable:false});
|
||||
polygons[data.name] = polyln;
|
||||
layers[lay].addLayer(polyln);
|
||||
}
|
||||
else if (data.hasOwnProperty("area") && Array.isArray(data.area)) {
|
||||
var cola = data.iconColor || "#910000";
|
||||
var polyarea = L.polygon(data.area, {stroke:true, weight:2, color:cola, fillColor:cola, fillOpacity:0.2, clickable:false});
|
||||
polygons[data.name] = polyarea;
|
||||
layers[lay].addLayer(polyarea);
|
||||
}
|
||||
else if (data.hasOwnProperty("sdlat") && data.hasOwnProperty("sdlon")) {
|
||||
var ellipse = L.ellipse(new L.LatLng((data.lat*1), (data.lon*1)), [200000*data.sdlon*Math.cos(data.lat*Math.PI/180), 200000*data.sdlat], 0, {color:(data.iconColor || "blue"), weight:2} );
|
||||
@ -826,7 +837,7 @@ function setMarker(data) {
|
||||
if (polygons[data.name] != null) { map.removeLayer(polygons[data.name]); }
|
||||
var x = data.lon * 1; // X coordinate
|
||||
var y = data.lat * 1; // Y coordinate
|
||||
var ll = new L.LatLng(y,x);
|
||||
var ll1 = new L.LatLng(y,x);
|
||||
var angle = data.bearing * 1;
|
||||
var lengthAsDegrees = data.length / 110540; // metres in a degree..ish
|
||||
var polygon = null;
|
||||
@ -838,12 +849,12 @@ function setMarker(data) {
|
||||
var y3 = y + Math.sin((90-angle-data.accuracy)/180*Math.PI)*lengthAsDegrees*Math.cos(y/180*Math.PI);
|
||||
var x3 = x + Math.cos((90-angle-data.accuracy)/180*Math.PI)*lengthAsDegrees;
|
||||
var ll3 = new L.LatLng(y3,x3);
|
||||
polygon = L.polygon([ ll, ll2, ll3 ], {weight:2, color:'#f30', fillOpacity:0.06, clickable:false});
|
||||
polygon = L.polygon([ ll1, ll2, ll3 ], {weight:2, color:'#f30', fillOpacity:0.06, clickable:false});
|
||||
} else {
|
||||
var y2 = y + Math.sin((90-angle)/180*Math.PI)*lengthAsDegrees*Math.cos(y/180*Math.PI);
|
||||
var x2 = x + Math.cos((90-angle)/180*Math.PI)*lengthAsDegrees;
|
||||
var ll2 = new L.LatLng(y2,x2);
|
||||
polygon = L.polygon([ ll, ll2 ], {weight:2, color:'#f30', clickable:false});
|
||||
var ya = y + Math.sin((90-angle)/180*Math.PI)*lengthAsDegrees*Math.cos(y/180*Math.PI);
|
||||
var xa = x + Math.cos((90-angle)/180*Math.PI)*lengthAsDegrees;
|
||||
var lla = new L.LatLng(ya,xa);
|
||||
polygon = L.polygon([ ll1, lla ], {weight:2, color:'#f30', clickable:false});
|
||||
}
|
||||
if (typeof layers[lay].getVisibleParent === 'function') {
|
||||
var vis = layers[lay].getVisibleParent(marker);
|
||||
|
Loading…
Reference in New Issue
Block a user