diff --git a/README.md b/README.md index c33c95f..f12b81a 100644 --- a/README.md +++ b/README.md @@ -16,14 +16,28 @@ Live Demo: https://danwild.github.io/leaflet-velocity/ var velocityLayer = L.velocityLayer({ displayValues: true, displayOptions: { + // label prefix velocityType: "Global Wind", + + // leaflet control position position: "bottomleft", + + // no data at cursor emptyString: "No velocity data", + + // see explanation below angleConvention: "bearingCW", - displayPosition: "bottomleft", - displayEmptyString: "No velocity data", - speedUnit: "kt", + + // display cardinal direction alongside degrees + showCardinal: false, + + // one of: ['ms', 'k/h', 'kt'] + speedUnit: "ms", + + // direction label prefix directionString: "Direction", + + // speed label prefix speedString: "Speed" }, data: data, // see demo/*.json, or wind-js-server for example data service diff --git a/demo/demo.js b/demo/demo.js index ce96961..f9c5f73 100644 --- a/demo/demo.js +++ b/demo/demo.js @@ -49,8 +49,9 @@ $.getJSON("wind-gbr.json", function(data) { displayValues: true, displayOptions: { velocityType: "GBR Wind", - displayPosition: "bottomleft", - displayEmptyString: "No wind data" + position: "bottomleft", + emptyString: "No wind data", + showCardinal: true }, data: data, maxVelocity: 10 @@ -64,8 +65,8 @@ $.getJSON("water-gbr.json", function(data) { displayValues: true, displayOptions: { velocityType: "GBR Water", - displayPosition: "bottomleft", - displayEmptyString: "No water data" + position: "bottomleft", + emptyString: "No water data" }, data: data, maxVelocity: 0.6, @@ -80,8 +81,8 @@ $.getJSON("wind-global.json", function(data) { displayValues: true, displayOptions: { velocityType: "Global Wind", - displayPosition: "bottomleft", - displayEmptyString: "No wind data" + position: "bottomleft", + emptyString: "No wind data" }, data: data, maxVelocity: 15 diff --git a/dist/leaflet-velocity.js b/dist/leaflet-velocity.js index 6aa81cd..65e23fb 100644 --- a/dist/leaflet-velocity.js +++ b/dist/leaflet-velocity.js @@ -151,6 +151,7 @@ L.Control.Velocity = L.Control.extend({ // Could be any combination of 'bearing' (angle toward which the flow goes) or 'meteo' (angle from which the flow comes) // and 'CW' (angle value increases clock-wise) or 'CCW' (angle value increases counter clock-wise) angleConvention: "bearingCCW", + showCardinal: false, // Could be 'm/s' for meter per second, 'k/h' for kilometer per hour or 'kt' for knots speedUnit: "m/s", directionString: "Direction", @@ -199,6 +200,45 @@ L.Control.Velocity = L.Control.extend({ return velocityDirToDegrees; }, + degreesToCardinalDirection: function degreesToCardinalDirection(deg) { + var cardinalDirection = ''; + + if (deg >= 0 && deg < 11.25 || deg >= 348.75) { + cardinalDirection = 'N'; + } else if (deg >= 11.25 && deg < 33.75) { + cardinalDirection = 'NNW'; + } else if (deg >= 33.75 && deg < 56.25) { + cardinalDirection = 'NW'; + } else if (deg >= 56.25 && deg < 78.75) { + cardinalDirection = 'WNW'; + } else if (deg >= 78.25 && deg < 101.25) { + cardinalDirection = 'W'; + } else if (deg >= 101.25 && deg < 123.75) { + cardinalDirection = 'WSW'; + } else if (deg >= 123.75 && deg < 146.25) { + cardinalDirection = 'SW'; + } else if (deg >= 146.25 && deg < 168.75) { + cardinalDirection = 'SSW'; + } else if (deg >= 168.75 && deg < 191.25) { + cardinalDirection = 'S'; + } else if (deg >= 191.25 && deg < 213.75) { + cardinalDirection = 'SSE'; + } else if (deg >= 213.75 && deg < 236.25) { + cardinalDirection = 'SE'; + } else if (deg >= 236.25 && deg < 258.75) { + cardinalDirection = 'ESE'; + } else if (deg >= 258.75 && deg < 281.25) { + cardinalDirection = 'E'; + } else if (deg >= 281.25 && deg < 303.75) { + cardinalDirection = 'ENE'; + } else if (deg >= 303.75 && deg < 326.25) { + cardinalDirection = 'NE'; + } else if (deg >= 326.25 && deg < 348.75) { + cardinalDirection = 'NNE'; + } + + return cardinalDirection; + }, meterSec2Knots: function meterSec2Knots(meters) { return meters / 0.514; }, @@ -215,7 +255,9 @@ L.Control.Velocity = L.Control.extend({ var htmlOut = ""; if (gridValue && !isNaN(gridValue[0]) && !isNaN(gridValue[1]) && gridValue[2]) { - htmlOut = " ".concat(this.options.velocityType, " ").concat(this.options.directionString, ": ").concat(self.vectorToDegrees(gridValue[0], gridValue[1], this.options.angleConvention).toFixed(2), " \xB0, ").concat(this.options.velocityType, " ").concat(this.options.speedString, ": ").concat(self.vectorToSpeed(gridValue[0], gridValue[1], this.options.speedUnit).toFixed(2), " ").concat(this.options.speedUnit); + var deg = self.vectorToDegrees(gridValue[0], gridValue[1], this.options.angleConvention); + var cardinal = this.options.showCardinal ? " (".concat(self.degreesToCardinalDirection(deg), ") ") : ''; + htmlOut = " ".concat(this.options.velocityType, " ").concat(this.options.directionString, ": ").concat(deg.toFixed(2), "\xB0").concat(cardinal, ", ").concat(this.options.velocityType, " ").concat(this.options.speedString, ": ").concat(self.vectorToSpeed(gridValue[0], gridValue[1], this.options.speedUnit).toFixed(2), " ").concat(this.options.speedUnit); } else { htmlOut = this.options.emptyString; } diff --git a/dist/leaflet-velocity.min.js b/dist/leaflet-velocity.min.js index c92cc12..4aa9567 100644 --- a/dist/leaflet-velocity.min.js +++ b/dist/leaflet-velocity.min.js @@ -1 +1 @@ -"use strict";L.DomUtil.setTransform||(L.DomUtil.setTransform=function(t,e,n){var i=e||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)")+(n?" scale("+n+")":"")}),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){console.log("canvas onAdd",this),this._map=t,this._canvas=L.DomUtil.create("canvas","leaflet-layer"),this.tiles={};var e=this._map.getSize();this._canvas.width=e.x,this._canvas.height=e.y;var n=this._map.options.zoomAnimation&&L.Browser.any3d;L.DomUtil.addClass(this._canvas,"leaflet-zoom-"+(n?"animated":"hide")),this.options.pane.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 e=this._delegate||this;e.onLayerWillUnmount&&e.onLayerWillUnmount(),this.options.pane.removeChild(this._canvas),t.off(this.getEvents(),this),this._canvas=null},addTo:function(t){return t.addLayer(this),this},drawLayer:function(){var t=this._map.getSize(),e=this._map.getBounds(),n=this._map.getZoom(),i=this._map.options.crs.project(this._map.getCenter()),o=this._map.options.crs.project(this._map.containerPointToLatLng(this._map.getSize())),a=this._delegate||this;a.onDrawLayer&&a.onDrawLayer({layer:this,canvas:this._canvas,bounds:e,size:t,zoom:n,center:i,corner:o}),this._frame=null},_setTransform:function(t,e,n){var i=e||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)")+(n?" scale("+n+")":"")},_animateZoom:function(t){var e=this._map.getZoomScale(t.zoom),n=L.Layer?this._map._latLngToNewLayerPoint(this._map.getBounds().getNorthWest(),t.zoom,t.center):this._map._getCenterOffset(t.center)._multiplyBy(-e).subtract(this._map._getMapPanePos());L.DomUtil.setTransform(this._canvas,n,e)}}),L.canvasLayer=function(t){return new L.CanvasLayer(t)},L.Control.Velocity=L.Control.extend({options:{position:"bottomleft",emptyString:"Unavailable",angleConvention:"bearingCCW",speedUnit:"m/s",directionString:"Direction",speedString:"Speed",onAdd:null,onRemove:null},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.options.leafletVelocity.options.onAdd&&this.options.leafletVelocity.options.onAdd(),this._container},onRemove:function(t){t.off("mousemove",this._onMouseMove,this),this.options.leafletVelocity.options.onRemove&&this.options.leafletVelocity.options.onRemove()},vectorToSpeed:function(t,e,n){var i=Math.sqrt(Math.pow(t,2)+Math.pow(e,2));return"k/h"===n?this.meterSec2kilometerHour(i):"kt"===n?this.meterSec2Knots(i):i},vectorToDegrees:function(t,e,n){n.endsWith("CCW")&&(e=0 ".concat(this.options.velocityType," ").concat(this.options.directionString,": ").concat(this.vectorToDegrees(n[0],n[1],this.options.angleConvention).toFixed(2)," °, ").concat(this.options.velocityType," ").concat(this.options.speedString,": ").concat(this.vectorToSpeed(n[0],n[1],this.options.speedUnit).toFixed(2)," ").concat(this.options.speedUnit):this.options.emptyString,this._container.innerHTML=i}}),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._paneName=this.options.paneName||"overlayPane";var e=t._panes.overlayPane;t.getPane&&(e=(e=t.getPane(this._paneName))||t.createPane(this._paneName)),this._canvasLayer=L.canvasLayer({pane:e}).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")},setOpacity:function(t){console.log("this._canvasLayer",this._canvasLayer),this._canvasLayer.setOpacity(t)},setOptions:function(t){this.options=Object.assign(this.options,t),t.hasOwnProperty("displayOptions")&&(this.options.displayOptions=Object.assign(this.options.displayOptions,t.displayOptions),this._initMouseHandler(!0)),t.hasOwnProperty("data")&&(this.options.data=t.data),this._windy&&(this._windy.setOptions(t),t.hasOwnProperty("data")&&this._windy.setData(t.data),this._clearAndRestart()),this.fire("load")},onDrawLayer:function(t,e){var n=this;this._windy?this.options.data&&(this._timer&&clearTimeout(n._timer),this._timer=setTimeout(function(){n._startWindy()},750)):this._initWindy(this)},_startWindy:function(){var t=this._map.getBounds(),e=this._map.getSize();this._windy.start([[0,0],[e.x,e.y]],e.x,e.y,[[t._southWest.lng,t._southWest.lat],[t._northEast.lng,t._northEast.lat]])},_initWindy:function(t){var e=Object.assign({canvas:t._canvasLayer._canvas,map:this._map},t.options);this._windy=new Windy(e),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(!1)},_initMouseHandler:function(t){if(t&&(this._map.removeControl(this._mouseControl),this._mouseControl=!1),!this._mouseControl&&this.options.displayValues){var e=this.options.displayOptions||{};(e.leafletVelocity=this)._mouseControl=L.control.velocity(e).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(b){function o(t,e,n,i,o,a){var s=1-t,r=1-e,l=s*r,h=t*r,c=s*e,d=t*e,p=n[0]*l+i[0]*h+o[0]*c+a[0]*d,u=n[1]*l+i[1]*h+o[1]*c+a[1]*d;return[p,u,Math.sqrt(p*p+u*u)]}function d(t){var e=null,n=null;return t.forEach(function(t){switch(t.header.parameterCategory+","+t.header.parameterNumber){case"1,2":case"2,2":e=t;break;case"1,3":case"2,3":n=t;break;default:t}}),function(t,e){var n=t.data,i=e.data;return{header:t.header,data:function(t){return[n[t],i[t]]},interpolate:o}}(e,n)}function a(i,o,t){function a(t,e){var n=i[Math.round(t)];return n&&n[Math.round(e)]||h}a.release=function(){i=[]},a.randomize=function(t){for(var e,n,i=0;null===a(e=Math.round(Math.floor(Math.random()*o.width)+o.x),n=Math.round(Math.floor(Math.random()*o.height)+o.y))[2]&&i++<30;);return t.x=e,t.y=n,t},t(o,a)}function s(t){return t/180*Math.PI}function r(i,r){var e,n,l=(e=x,n=C,W.indexFor=function(t){return Math.max(0,Math.min(W.length-1,Math.round((t-e)/(n-e)*(W.length-1))))},W),h=l.map(function(){return[]}),t=Math.round(i.width*i.height*O);/android|blackberry|iemobile|ipad|iphone|ipod|opera mini|webos/i.test(navigator.userAgent)&&(t*=T);for(var o="rgba(0, 0, 0, ".concat(R,")"),a=[],s=0;sP&&(r.randomize(t).age=0);var e=t.x,n=t.y,i=r(e,n),o=i[2];if(null===o)t.age=P;else{var a=e+i[0],s=n+i[1];null!==r(a,s)[2]?(t.xt=a,t.yt=s,h[l.indexFor(o)].push(t)):(t.x=a,t.y=s)}t.age+=1}),c.globalCompositeOperation="destination-in",c.fillRect(i.x,i.y,i.width,i.height),c.globalCompositeOperation="lighter",c.globalAlpha=0===R?0:.9*R,h.forEach(function(t,e){0 ").concat(o.toFixed(2),"°").concat(a,", ").concat(this.options.velocityType," ").concat(this.options.speedString,": ").concat(this.vectorToSpeed(e[0],e[1],this.options.speedUnit).toFixed(2)," ").concat(this.options.speedUnit)}else i=this.options.emptyString;this._container.innerHTML=i}}),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._paneName=this.options.paneName||"overlayPane";var n=t._panes.overlayPane;t.getPane&&(n=(n=t.getPane(this._paneName))||t.createPane(this._paneName)),this._canvasLayer=L.canvasLayer({pane:n}).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")},setOpacity:function(t){console.log("this._canvasLayer",this._canvasLayer),this._canvasLayer.setOpacity(t)},setOptions:function(t){this.options=Object.assign(this.options,t),t.hasOwnProperty("displayOptions")&&(this.options.displayOptions=Object.assign(this.options.displayOptions,t.displayOptions),this._initMouseHandler(!0)),t.hasOwnProperty("data")&&(this.options.data=t.data),this._windy&&(this._windy.setOptions(t),t.hasOwnProperty("data")&&this._windy.setData(t.data),this._clearAndRestart()),this.fire("load")},onDrawLayer:function(t,n){var e=this;this._windy?this.options.data&&(this._timer&&clearTimeout(e._timer),this._timer=setTimeout(function(){e._startWindy()},750)):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,map:this._map},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(!1)},_initMouseHandler:function(t){if(t&&(this._map.removeControl(this._mouseControl),this._mouseControl=!1),!this._mouseControl&&this.options.displayValues){var n=this.options.displayOptions||{};(n.leafletVelocity=this)._mouseControl=L.control.velocity(n).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(b){function o(t,n,e,i,o,a){var r=1-t,s=1-n,l=r*s,h=t*s,c=r*n,d=t*n,p=e[0]*l+i[0]*h+o[0]*c+a[0]*d,u=e[1]*l+i[1]*h+o[1]*c+a[1]*d;return[p,u,Math.sqrt(p*p+u*u)]}function d(t){var n=null,e=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:t}}),function(t,n){var e=t.data,i=n.data;return{header:t.header,data:function(t){return[e[t],i[t]]},interpolate:o}}(n,e)}function a(i,o,t){function a(t,n){var e=i[Math.round(t)];return e&&e[Math.round(n)]||h}a.release=function(){i=[]},a.randomize=function(t){for(var n,e,i=0;null===a(n=Math.round(Math.floor(Math.random()*o.width)+o.x),e=Math.round(Math.floor(Math.random()*o.height)+o.y))[2]&&i++<30;);return t.x=n,t.y=e,t},t(o,a)}function r(t){return t/180*Math.PI}function s(i,s){var n,e,l=(n=x,e=C,R.indexFor=function(t){return Math.max(0,Math.min(R.length-1,Math.round((t-n)/(e-n)*(R.length-1))))},R),h=l.map(function(){return[]}),t=Math.round(i.width*i.height*D);/android|blackberry|iemobile|ipad|iphone|ipod|opera mini|webos/i.test(navigator.userAgent)&&(t*=T);for(var o="rgba(0, 0, 0, ".concat(O,")"),a=[],r=0;rP&&(s.randomize(t).age=0);var n=t.x,e=t.y,i=s(n,e),o=i[2];if(null===o)t.age=P;else{var a=n+i[0],r=e+i[1];null!==s(a,r)[2]?(t.xt=a,t.yt=r,h[l.indexFor(o)].push(t)):(t.x=a,t.y=r)}t.age+=1}),c.globalCompositeOperation="destination-in",c.fillRect(i.x,i.y,i.width,i.height),c.globalCompositeOperation="lighter",c.globalAlpha=0===O?0:.9*O,h.forEach(function(t,n){0= 0 && deg < 11.25 || deg >= 348.75) { + cardinalDirection = 'N' + } + else if (deg >= 11.25 && deg < 33.75){ + cardinalDirection = 'NNW' + } + else if (deg >= 33.75 && deg < 56.25){ + cardinalDirection = 'NW' + } + else if (deg >= 56.25 && deg < 78.75){ + cardinalDirection = 'WNW' + } + else if (deg >= 78.25 && deg < 101.25){ + cardinalDirection = 'W' + } + else if (deg >= 101.25 && deg < 123.75){ + cardinalDirection = 'WSW' + } + else if (deg >= 123.75 && deg < 146.25){ + cardinalDirection = 'SW' + } + else if (deg >= 146.25 && deg < 168.75){ + cardinalDirection = 'SSW' + } + else if (deg >= 168.75 && deg < 191.25){ + cardinalDirection = 'S' + } + else if (deg >= 191.25 && deg < 213.75){ + cardinalDirection = 'SSE' + } + else if (deg >= 213.75 && deg < 236.25){ + cardinalDirection = 'SE' + } + else if (deg >= 236.25 && deg < 258.75){ + cardinalDirection = 'ESE' + } + else if (deg >= 258.75 && deg < 281.25){ + cardinalDirection = 'E' + } + else if (deg >= 281.25 && deg < 303.75){ + cardinalDirection = 'ENE' + } + else if (deg >= 303.75 && deg < 326.25){ + cardinalDirection = 'NE' + } + else if (deg >= 326.25 && deg < 348.75){ + cardinalDirection = 'NNE' + } + + return cardinalDirection; + }, + meterSec2Knots: function(meters) { return meters / 0.514; }, @@ -85,11 +141,12 @@ L.Control.Velocity = L.Control.extend({ !isNaN(gridValue[1]) && gridValue[2] ) { + var deg = self.vectorToDegrees(gridValue[0], gridValue[1], this.options.angleConvention); + var cardinal = this.options.showCardinal ? ` (${self.degreesToCardinalDirection(deg)}) ` : ''; + htmlOut = ` ${this.options.velocityType} ${ this.options.directionString - }: ${self - .vectorToDegrees(gridValue[0], gridValue[1], this.options.angleConvention) - .toFixed(2)} °, ${this.options.velocityType} ${ + }: ${deg.toFixed(2)}°${cardinal}, ${this.options.velocityType} ${ this.options.speedString }: ${self .vectorToSpeed(gridValue[0], gridValue[1], this.options.speedUnit)