diff --git a/CHANGELOG.md b/CHANGELOG.md
index f421a9b..9bfb1f6 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,7 +1,7 @@
### Change Log for Node-RED Worldmap
- v1.1.15 - Tidy of Info, Readme and NATO symbol options.
- - v1.1.14 - Add proper NATO symbology via milsymbol.js
+ - v1.1.14 - Add proper NATO symbology via milsymbol.js
- v1.1.13 - Add ability to set a building using a GeoJSON Feature set. {name:"MyTower":building:{...feature sets...}}
- v1.1.12 - README changes, split out CHANGELOG.md
- v1.1.11 - fix websocket multiple connections
diff --git a/README.md b/README.md
index af7ad88..5bfc047 100644
--- a/README.md
+++ b/README.md
@@ -9,6 +9,7 @@ map web page for plotting "things" on.
### Updates
+- v1.1.16 - Add Velocity layer - for velocity grid type overlays (eg wind, currrents, etc)
- v1.1.15 - Tidy of Info, Readme and NATO symbol options.
- v1.1.14 - Add proper NATO symbology via milsymbol.js
- v1.1.13 - Add ability to set a building using a GeoJSON Feature set. {name:"MyTower":building:{...feature sets...}}
@@ -237,6 +238,24 @@ Optional properties include
see http://leafletjs.com/examples/geojson/ for more details about options
+#### To add a Velocity Grid Overlay
+
+ msg.payload.command.map = {
+ overlay:"myWind",
+ velocity: {
+ displayValues: true,
+ displayOptions: {
+ velocityType: 'Global Wind',
+ displayPosition: 'bottomleft',
+ displayEmptyString: 'No wind data'
+ },
+ maxVelocity: 15,
+ data: [Array of data as per format referenced below]
+ }
+ };
+
+see https://github.com/danwild/leaflet-velocity for more details about options and data examples.
+
#### To add an Image Overlay
var imageBounds = [[40.712216, -74.22655], [40.773941, -74.12544]];
diff --git a/package.json b/package.json
index 2332e41..5e3b7be 100644
--- a/package.json
+++ b/package.json
@@ -3,9 +3,9 @@
"version": "1.1.15",
"description": "A Node-RED node to provide a web page of a world map for plotting things on.",
"dependencies": {
+ "cgi": "0.3.1",
"express": "^4.16.3",
- "sockjs": "^0.3.19",
- "cgi": "0.3.1"
+ "sockjs": "^0.3.19"
},
"repository": {
"type": "git",
diff --git a/worldmap/index.html b/worldmap/index.html
index 4bb9e7b..0b60426 100644
--- a/worldmap/index.html
+++ b/worldmap/index.html
@@ -29,7 +29,7 @@
-
+
@@ -51,6 +51,7 @@
+
@@ -1192,6 +1193,20 @@ function doCommand(cmd) {
}
overlays[cmd.map.overlay].addTo(map);
}
+ // Add a new velocity overlay layer
+ if (cmd.map && cmd.map.hasOwnProperty("overlay") && cmd.map.hasOwnProperty("velocity") ) {
+ console.log("M",cmd.map);
+ if (overlays.hasOwnProperty(cmd.map.overlay)) {
+ map.removeLayer(overlays[cmd.map.overlay]);
+ existsalready = true;
+ }
+ console.log("E",existsalready);
+ overlays[cmd.map.overlay] = L.velocityLayer(cmd.map.velocity);
+ if (!existsalready) {
+ layercontrol.addOverlay(overlays[cmd.map.overlay],cmd.map.overlay);
+ }
+ overlays[cmd.map.overlay].addTo(map);
+ }
// Add a new overlay layer
if (cmd.map && cmd.map.hasOwnProperty("overlay") && cmd.map.hasOwnProperty("url") && cmd.map.hasOwnProperty("opt")) {
console.log("New overlay:",cmd.map.overlay);
diff --git a/worldmap/leaflet/leaflet-velocity.min.css b/worldmap/leaflet/leaflet-velocity.min.css
new file mode 100755
index 0000000..27e0b77
--- /dev/null
+++ b/worldmap/leaflet/leaflet-velocity.min.css
@@ -0,0 +1 @@
+.leaflet-control-velocity{background-color:hsla(0,0%,100%,.7);padding:0 5px;margin:0!important;color:#333;font:11px/1.5 Helvetica Neue,Arial,Helvetica,sans-serif}.velocity-overlay{position:absolute;z-index:1}
\ No newline at end of file
diff --git a/worldmap/leaflet/leaflet-velocity.min.js b/worldmap/leaflet/leaflet-velocity.min.js
new file mode 100755
index 0000000..692dc98
--- /dev/null
+++ b/worldmap/leaflet/leaflet-velocity.min.js
@@ -0,0 +1 @@
+"use strict";L.DomUtil.setTransform||(L.DomUtil.setTransform=function(t,n,e){var i=n||new L.Point(0,0);t.style[L.DomUtil.TRANSFORM]=(L.Browser.ie3d?"translate("+i.x+"px,"+i.y+"px)":"translate3d("+i.x+"px,"+i.y+"px,0)")+(e?" scale("+e+")":"")}),L.CanvasLayer=(L.Layer?L.Layer:L.Class).extend({initialize:function(t){this._map=null,this._canvas=null,this._frame=null,this._delegate=null,L.setOptions(this,t)},delegate:function(t){return this._delegate=t,this},needRedraw:function(){return this._frame||(this._frame=L.Util.requestAnimFrame(this.drawLayer,this)),this},_onLayerDidResize:function(t){this._canvas.width=t.newSize.x,this._canvas.height=t.newSize.y},_onLayerDidMove:function(){var t=this._map.containerPointToLayerPoint([0,0]);L.DomUtil.setPosition(this._canvas,t),this.drawLayer()},getEvents:function(){var t={resize:this._onLayerDidResize,moveend:this._onLayerDidMove};return this._map.options.zoomAnimation&&L.Browser.any3d&&(t.zoomanim=this._animateZoom),t},onAdd:function(t){this._map=t,this._canvas=L.DomUtil.create("canvas","leaflet-layer"),this.tiles={};var n=this._map.getSize();this._canvas.width=n.x,this._canvas.height=n.y;var e=this._map.options.zoomAnimation&&L.Browser.any3d;L.DomUtil.addClass(this._canvas,"leaflet-zoom-"+(e?"animated":"hide")),t._panes.overlayPane.appendChild(this._canvas),t.on(this.getEvents(),this);var i=this._delegate||this;i.onLayerDidMount&&i.onLayerDidMount(),this.needRedraw();var o=this;setTimeout(function(){o._onLayerDidMove()},0)},onRemove:function(t){var n=this._delegate||this;n.onLayerWillUnmount&&n.onLayerWillUnmount(),t.getPanes().overlayPane.removeChild(this._canvas),t.off(this.getEvents(),this),this._canvas=null},addTo:function(t){return t.addLayer(this),this},LatLonToMercator:function(t){return{x:6378137*t.lng*Math.PI/180,y:6378137*Math.log(Math.tan((90+t.lat)*Math.PI/360))}},drawLayer:function(){var t=this._map.getSize(),n=this._map.getBounds(),e=this._map.getZoom(),i=this.LatLonToMercator(this._map.getCenter()),o=this.LatLonToMercator(this._map.containerPointToLatLng(this._map.getSize())),a=this._delegate||this;a.onDrawLayer&&a.onDrawLayer({layer:this,canvas:this._canvas,bounds:n,size:t,zoom:e,center:i,corner:o}),this._frame=null},_setTransform:function(t,n,e){var i=n||new L.Point(0,0);t.style[L.DomUtil.TRANSFORM]=(L.Browser.ie3d?"translate("+i.x+"px,"+i.y+"px)":"translate3d("+i.x+"px,"+i.y+"px,0)")+(e?" scale("+e+")":"")},_animateZoom:function(t){var n=this._map.getZoomScale(t.zoom),e=L.Layer?this._map._latLngToNewLayerPoint(this._map.getBounds().getNorthWest(),t.zoom,t.center):this._map._getCenterOffset(t.center)._multiplyBy(-n).subtract(this._map._getMapPanePos());L.DomUtil.setTransform(this._canvas,e,n)}}),L.canvasLayer=function(){return new L.CanvasLayer},L.Control.Velocity=L.Control.extend({options:{position:"bottomleft",emptyString:"Unavailable",angleConvention:"bearingCCW",speedUnit:"m/s"},onAdd:function(t){return this._container=L.DomUtil.create("div","leaflet-control-velocity"),L.DomEvent.disableClickPropagation(this._container),t.on("mousemove",this._onMouseMove,this),this._container.innerHTML=this.options.emptyString,this._container},onRemove:function(t){t.off("mousemove",this._onMouseMove,this)},vectorToSpeed:function(t,n,e){var i=Math.sqrt(Math.pow(t,2)+Math.pow(n,2));return"k/h"===e?this.meterSec2kilometerHour(i):"kt"===e?this.meterSec2Knots(i):i},vectorToDegrees:function(t,n,e){e.endsWith("CCW")&&(n=n>0?n=-n:Math.abs(n));var i=Math.sqrt(Math.pow(t,2)+Math.pow(n,2)),o=Math.atan2(t/i,n/i),a=180*o/Math.PI+180;return"bearingCW"!==e&&"meteoCCW"!==e||(a+=180,a>=360&&(a-=360)),a},meterSec2Knots:function(t){return t/.514},meterSec2kilometerHour:function(t){return 3.6*t},_onMouseMove:function(t){var n=this,e=this.options.leafletVelocity._map.containerPointToLatLng(L.point(t.containerPoint.x,t.containerPoint.y)),i=this.options.leafletVelocity._windy.interpolatePoint(e.lng,e.lat),o="";o=i&&!isNaN(i[0])&&!isNaN(i[1])&&i[2]?""+this.options.velocityType+" Direction: "+n.vectorToDegrees(i[0],i[1],this.options.angleConvention).toFixed(2)+"°, "+this.options.velocityType+" Speed: "+n.vectorToSpeed(i[0],i[1],this.options.speedUnit).toFixed(2)+this.options.speedUnit:this.options.emptyString,n._container.innerHTML=o,0==$(".leaflet-control-velocity").index()&&$(".leaflet-control-velocity").insertAfter(".leaflet-control-mouseposition")}}),L.Map.mergeOptions({positionControl:!1}),L.Map.addInitHook(function(){this.options.positionControl&&(this.positionControl=new L.Control.MousePosition,this.addControl(this.positionControl))}),L.control.velocity=function(t){return new L.Control.Velocity(t)},L.VelocityLayer=(L.Layer?L.Layer:L.Class).extend({options:{displayValues:!0,displayOptions:{velocityType:"Velocity",position:"bottomleft",emptyString:"No velocity data"},maxVelocity:10,colorScale:null,data:null},_map:null,_canvasLayer:null,_windy:null,_context:null,_timer:0,_mouseControl:null,initialize:function(t){L.setOptions(this,t)},onAdd:function(t){this._canvasLayer=L.canvasLayer().delegate(this),this._canvasLayer.addTo(t),this._map=t},onRemove:function(t){this._destroyWind()},setData:function(t){this.options.data=t,this._windy&&(this._windy.setData(t),this._clearAndRestart()),this.fire("load")},onDrawLayer:function(t,n){var e=this;return this._windy?void(this.options.data&&(this._timer&&clearTimeout(e._timer),this._timer=setTimeout(function(){e._startWindy()},750))):void this._initWindy(this)},_startWindy:function(){var t=this._map.getBounds(),n=this._map.getSize();this._windy.start([[0,0],[n.x,n.y]],n.x,n.y,[[t._southWest.lng,t._southWest.lat],[t._northEast.lng,t._northEast.lat]])},_initWindy:function(t){var n=Object.assign({canvas:t._canvasLayer._canvas},t.options);this._windy=new Windy(n),this._context=this._canvasLayer._canvas.getContext("2d"),this._canvasLayer._canvas.classList.add("velocity-overlay"),this.onDrawLayer(),this._map.on("dragstart",t._windy.stop),this._map.on("dragend",t._clearAndRestart),this._map.on("zoomstart",t._windy.stop),this._map.on("zoomend",t._clearAndRestart),this._map.on("resize",t._clearWind),this._initMouseHandler()},_initMouseHandler:function(){if(!this._mouseControl&&this.options.displayValues){var t=this.options.displayOptions||{};t.leafletVelocity=this,this._mouseControl=L.control.velocity(t).addTo(this._map)}},_clearAndRestart:function(){this._context&&this._context.clearRect(0,0,3e3,3e3),this._windy&&this._startWindy()},_clearWind:function(){this._windy&&this._windy.stop(),this._context&&this._context.clearRect(0,0,3e3,3e3)},_destroyWind:function(){this._timer&&clearTimeout(this._timer),this._windy&&this._windy.stop(),this._context&&this._context.clearRect(0,0,3e3,3e3),this._mouseControl&&this._map.removeControl(this._mouseControl),this._mouseControl=null,this._windy=null,this._map.removeLayer(this._canvasLayer)}}),L.velocityLayer=function(t){return new L.VelocityLayer(t)};var Windy=function(t){var n,e,i,o,a,r,s,h,l,c,u=t.minVelocity||0,d=t.maxVelocity||10,m=(t.velocityScale||.005)*(Math.pow(window.devicePixelRatio,1/3)||1),f=t.particleAge||90,y=t.lineWidth||1,_=t.particleMultiplier||1/300,p=Math.pow(window.devicePixelRatio,1/3)||1.6,v=t.frameRate||15,g=1e3/v,L=["rgb(36,104, 180)","rgb(60,157, 194)","rgb(128,205,193 )","rgb(151,218,168 )","rgb(198,231,181)","rgb(238,247,217)","rgb(255,238,159)","rgb(252,217,125)","rgb(255,182,100)","rgb(252,150,75)","rgb(250,112,52)","rgb(245,64,32)","rgb(237,45,28)","rgb(220,24,32)","rgb(180,0,35)"],M=t.colorScale||L,w=[NaN,NaN,null],x=t.data,C=function(t){x=t},b=function(t,n,e,i,o,a){var r=1-t,s=1-n,h=r*s,l=t*s,c=r*n,u=t*n,d=e[0]*h+i[0]*l+o[0]*c+a[0]*u,m=e[1]*h+i[1]*l+o[1]*c+a[1]*u;return[d,m,Math.sqrt(d*d+m*m)]},T=function(t,n){var e=t.data,i=n.data;return{header:t.header,data:function(t){return[e[t],i[t]]},interpolate:b}},D=function(t){var n=null,e=null,i=null;return t.forEach(function(t){switch(t.header.parameterCategory+","+t.header.parameterNumber){case"1,2":case"2,2":n=t;break;case"1,3":case"2,3":e=t;break;default:i=t}}),T(n,e)},P=function(t,c){n=D(t);var u=n.header;o=u.lo1,a=u.la1,r=u.dx,s=u.dy,h=u.nx,l=u.ny,i=new Date(u.refTime),i.setHours(i.getHours()+u.forecastTime),e=[];for(var d=0,m=Math.floor(h*r)>=360,f=0;f1e3)return void setTimeout(c,25);N(h,n,i)}()},B=function(n,e){function i(t,n){return M.indexFor=function(e){return Math.max(0,Math.min(M.length-1,Math.round((e-t)/(n-t)*(M.length-1))))},M}function o(){s.forEach(function(t){t.length=0}),m.forEach(function(t){t.age>f&&(e.randomize(t).age=0);var n=t.x,i=t.y,o=e(n,i),a=o[2];if(null===a)t.age=f;else{var h=n+o[0],l=i+o[1];null!==e(h,l)[2]?(t.xt=h,t.yt=l,s[r.indexFor(a)].push(t)):(t.x=h,t.y=l)}t.age+=1})}function a(){var t="lighter";L.globalCompositeOperation="destination-in",L.fillRect(n.x,n.y,n.width,n.height),L.globalCompositeOperation=t,L.globalAlpha=.9,s.forEach(function(t,n){t.length>0&&(L.beginPath(),L.strokeStyle=r[n],t.forEach(function(t){L.moveTo(t.x,t.y),L.lineTo(t.xt,t.yt),t.x=t.xt,t.y=t.yt}),L.stroke())})}var r=i(u,d),s=r.map(function(){return[]}),h=Math.round(n.width*n.height*_);R()&&(h*=p);for(var l="rgba(0, 0, 0, 0.97)",m=[],v=0;vg&&(w=t-n%g,o(),a())}()},q=function(t,n,e,i){var o={south:V(i[0][1]),north:V(i[1][1]),east:V(i[1][0]),west:V(i[0][0]),width:n,height:e};Z(),P(x,function(i){H(i,F(t,n,e),o,function(t,n){K.field=n,B(t,n)})})},Z=function(){K.field&&K.field.release(),c&&cancelAnimationFrame(c)},K={params:t,start:q,stop:Z,createField:N,interpolatePoint:z,setData:C};return K};window.cancelAnimationFrame||(window.cancelAnimationFrame=function(t){clearTimeout(t)});
\ No newline at end of file
diff --git a/worldmap/worldmap.appcache b/worldmap/worldmap.appcache
index 9eb5059..62c2072 100644
--- a/worldmap/worldmap.appcache
+++ b/worldmap/worldmap.appcache
@@ -1,5 +1,5 @@
CACHE MANIFEST
-# date: May 30th 2018 - v1.1.15
+# date: May 30th 2018 - v1.1.16
CACHE:
index.html
@@ -27,6 +27,8 @@ leaflet/leaflet-openweathermap.css
leaflet/leaflet-openweathermap.js
leaflet/leaflet-slider.css
leaflet/leaflet-slider.js
+leaflet/leaflet-velocity.min.css
+leaflet/leaflet-velocity.min.js
leaflet/leaflet.active-layers.min.js
leaflet/leaflet.boatmarker.js
leaflet/leaflet.css