import Windy from './windy'; declare var L: any; import velocitycss from './leaflet-velocity.css'; interface DisplayOptions { speedUnit: 'kt' | 'k/h' | 'mph' | 'm/s'; position: 'topleft' | 'topright' | 'bottomleft' | 'bottomright'; showCardinal: boolean; angleConvention: string; velocityType: string; emptyString: string; directionString: string; speedString: string; } export default class ControlVelocity { private options: DisplayOptions; private _windy: Windy = null; private _map: any = null; private _container: any = null; constructor() { this.options = { position: 'bottomleft', emptyString: 'Unavailable', velocityType: '', angleConvention: 'bearingCCW', speedUnit: 'm/s', directionString: "Direction", speedString: "Speed", showCardinal: false, }; } setWindy(_windy: any) { if (!this._windy && _windy) this._windy = _windy; } setOptions(options: any) { L.Util.setOptions(this, options); } onAdd(map: any) { this._map = map; this._container = L.DomUtil.create('div', velocitycss.leafletControlVelocity); L.DomEvent.disableClickPropagation(this._container); this._map.on('mousemove', this.drawWindSpeed, this); this._container.innerHTML = this.options.emptyString; return this._container; } onRemove(map: any) { this._map.off('mousemove', this.drawWindSpeed, this); } vectorToSpeed(uMs: number, vMs: number, unit: string) { var velocityAbs = Math.sqrt(Math.pow(uMs, 2) + Math.pow(vMs, 2)); // Default is m/s if (unit === "k/h") { return this.meterSec2kilometerHour(velocityAbs); } else if (unit === "kt") { return this.meterSec2Knots(velocityAbs); } else if (unit === "mph") { return this.meterSec2milesHour(velocityAbs); } else { return velocityAbs; } } vectorToDegrees(uMs: number, vMs: number, angleConvention: string) { // Default angle convention is CW if (angleConvention.endsWith('CCW')) { // vMs comes out upside-down.. vMs = vMs > 0 ? vMs = -vMs : Math.abs(vMs); } var velocityAbs = Math.sqrt(Math.pow(uMs, 2) + Math.pow(vMs, 2)); var velocityDir = Math.atan2(uMs / velocityAbs, vMs / velocityAbs); var velocityDirToDegrees = velocityDir * 180 / Math.PI + 180; if (angleConvention === 'bearingCW' || angleConvention === 'meteoCCW') { velocityDirToDegrees += 180; if (velocityDirToDegrees >= 360) velocityDirToDegrees -= 360; } return velocityDirToDegrees; } meterSec2Knots(meters: number) { return meters / 0.514 } meterSec2kilometerHour(meters: number) { return meters * 3.6 } meterSec2milesHour(meters: number) { return meters * 2.23694; } degreesToCardinalDirection(deg: number) { let 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; } drawWindSpeed(ev: any) { const pos = this._map.containerPointToLatLng(L.point(ev.containerPoint.x, ev.containerPoint.y)); const gridValue = this._windy.interpolate(pos.lng, pos.lat); var template = ""; if (gridValue && !isNaN(gridValue[0]) && !isNaN(gridValue[1]) && gridValue[2]) { const deg = this.vectorToDegrees(gridValue[0], gridValue[1], this.options.angleConvention); const cardinal = this.options.showCardinal ? ` (${this.degreesToCardinalDirection(deg)}) ` : ''; template = ` ${this.options.velocityType} ${this.options.directionString }: ${deg.toFixed(2)}°${cardinal}, ${this.options.velocityType} ${this.options.speedString }: ${this.vectorToSpeed(gridValue[0], gridValue[1], this.options.speedUnit).toFixed(2)} ${this.options.speedUnit}`; } else { if (this.options.emptyString) template = this.options.emptyString; } this._container.innerHTML = template; } }