Severe Storm Tracker (2024)

Severe Storm Tracker (1) Severe Storm Tracker v1.1

Severe Storm Tracker (2)Help | Severe Storm Tracker (3)Change Domain | Severe Storm Tracker (4)Bookmark | Severe Storm Tracker (5)Legend

Requests: Severe Storm Tracker (7)

' help_text += '

'; // Hazard priority - invert the priority scale hazardPriority = d3.scaleLinear().domain([1, 128]).range([128, 1]); // Make the web side clean d3.selectAll('.content').remove(); d3.selectAll('.full-width-bordertop').style('border-top', 'none'); d3.selectAll('.five-sixth-first').style('width', '930px').style('margin-top', '-10px'); d3.selectAll('#zipcity_news').remove(); d3.selectAll('#sidebar').remove(); var parent = $("#pagebody").children(); try { parent[1].remove(); parent[0].remove(); } catch (e) { } /** * Configuration * */ var ndfdFields = ['wx', 'WWA', 'WaveHeight', 'windspd', 'WindGust', 'T', 'ApparentT', 'ppi', 'qpf', 'sky', 'relativeHumidity']; var opacity = 55; // Table cells var skipHours = 1; var ndfdWMSwidth = 350; // 4:3 ratio var ndfdWMSheight = 288; window.count = 4; // Keeps track of where the seleted table cell is window.gridsources = {}; // Cache images in memory for fast display window.radarService = 'https://opengeo.ncep.noaa.gov/geoserver/conus/conus_bref_qcd/ows'; window.radarSourceArray = {}; window.lightningSourceArray = {}; window.wmsLayers = {}; var layers = getUrlParameter('layers'); if (layers == '') { layers = 'Radar|USStates|Hazards|SamplePoint|Domain|StormReports|'; } // Check to see if we should turn the layer on var activateLayers = layers.split('|').slice(0, -1); /** * Helpers * */ var wwa_keys = { "AS": "Air Stagnation", "FA": "Areal Flood", "AF": "Volcanic Ashfall", "AV": "Avalanche", "BH": "Beach Hazards", "BZ": "Blizzard", "DU": "Blowing Dust", "BS": "Blowing Snow", "BW": "Brisk Wind", "CF": "Coastal Flood", "FG": "Dense Fog", "SM": "Dense Smoke", "DS": "Dust Storm", "EH": "Excessive Heat", "EC": "Extreme Cold", "EW": "Extreme Wind", "FF": "Flash Flood", "FL": "Flood", "FZ": "Freeze", "ZF": "Freezing Fog", "ZR": "Freezing Rain", "UP": "Ice Accretion", "FR": "Frost", "GL": "Gale", "HZ": "Hard Freeze", "SE": "Hazardous Seas", "HT": "Heat", "HP": "Heavy Sleet", "HS": "Heavy Snow", "SU": "High Surf", "HW": "High Wind", "HU": "Hurricane", "HF": "Hurricane Force Wind", "HY": "Hydrologic", "IS": "Ice Storm", "HI": "Inland Hurricane Wind", "TI": "Inland Tropical Storm", "LE": "Lake Effect Snow", "LB": "Lake Effect Snow and ", "LW": "Lake Wind", "LS": "Lakeshore Flood", "LO": "Low Water", "MA": "Marine", "MF": "Marine Dense Fog", "RH": "Radiological Hazard", "FW": "Red Flag", "RP": "Rip Currents", "SV": "Severe Thunderstorm", "IP": "Sleet", "SC": "Small Craft", "SW": "Small Craft for Hazardous Seas", "RB": "Small Craft for Rough Bar", "SI": "Small Craft for Winds", "SN": "Snow", "SB": "Snow and Blowing Snow", "SR": "Storm", "TO": "Tornado", "TR": "Tropical Storm", "TS": "Tsunami", "TY": "Typhoon", "VO": "Volcano", "WI": "Wind", "WC": "Wind Chill", "WS": "Winter Storm", "WW": "Winter Weather" }; var wwa_significance = { 'W': 'Warning', 'Y': 'Advisory', 'A': 'Watch' }; /** * Grab url params * */ var clat = getUrlParameter('clat'); var clon = getUrlParameter('clon'); var mylat = getUrlParameter('lat'); var mylon = getUrlParameter('lon'); var bbox = getUrlParameter('bbox'); var zoom = getUrlParameter('zoom'); var layers = getUrlParameter('layers'); if (layers == '') { layers = 'FTTFTTTFT'; } // map center if (mylat) { window.clat = Number(clat); } else { window.clat = 39.102; } if (mylon != '') { window.clon = Number(clon); } else { window.clon = -94.666; } // Point center if (mylat) { window.lat = Number(mylat); } else { window.lat = 46.836; } if (mylon != '') { window.lon = Number(mylon); } else { window.lon = -92.214; } if (zoom != '') { window.zoom = Number(zoom); } else { window.zoom = 7; } if (bbox != '') { window.imageExtent = JSON.parse(bbox); } else { window.imageExtent = [-16250736.58, 2537385.09, -4825600.364, 6935192.134]; } //////////////////////////////// function getUrlParameter(name) { name = name.replace(/[\[]/, '\\[').replace(/[\]]/, '\\]'); var regex = new RegExp('[\\?&]' + name + '=([^]*)'); var results = regex.exec(location.search); return results === null ? '' : decodeURIComponent(results[1].replace(/\+/g, ' ')); } var world_imagery = new ol.layer.Tile({ type: 'base', title: 'World Imagery', source: new ol.source.XYZ({ attributions: 'Tiles © ArcGIS', url: ' https://services.arcgisonline.com/arcgis/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}' }), visible: false }) /** * Search option */ /** /*** Ajax Autocomplete for jQuery, version 1.2.22* (c) 2014 Tomas Kirda** Ajax Autocomplete for jQuery is freely distributable under the terms of an MIT-style license.* For details, see the web site: https://github.com/devbridge/jQuery-Autocomplete*/ !function (a) { "use strict"; "function" == typeof define && define.amd ? define(["jquery"], a) : a("object" == typeof exports && "function" == typeof require ? require("jquery") : jQuery) }(function (a) { "use strict"; function b(c, d) { var e = function () { }, f = this, g = { ajaxSettings: {}, autoSelectFirst: !1, appendTo: document.body, serviceUrl: null, lookup: null, onSelect: null, width: "auto", minChars: 1, maxHeight: 300, deferRequestBy: 0, params: {}, formatResult: b.formatResult, delimiter: null, zIndex: 9999, type: "GET", noCache: !1, onSearchStart: e, onSearchComplete: e, onSearchError: e, preserveInput: !1, containerClass: "autocomplete-suggestions", tabDisabled: !1, dataType: "text", currentRequest: null, triggerSelectOnValidInput: !0, preventBadQueries: !0, lookupFilter: function (a, b, c) { return -1 !== a.value.toLowerCase().indexOf(c) }, paramName: "query", transformResult: function (b) { return "string" == typeof b ? a.parseJSON(b) : b }, showNoSuggestionNotice: !1, noSuggestionNotice: "No results", orientation: "bottom", forceFixPosition: !1 }; f.element = c, f.el = a(c), f.suggestions = [], f.badQueries = [], f.selectedIndex = -1, f.currentValue = f.element.value, f.intervalId = 0, f.cachedResponse = {}, f.onChangeInterval = null, f.onChange = null, f.isLocal = !1, f.suggestionsContainer = null, f.noSuggestionsContainer = null, f.options = a.extend({}, g, d), f.classes = { selected: "autocomplete-selected", suggestion: "autocomplete-suggestion" }, f.hint = null, f.hintValue = "", f.selection = null, f.initialize(), f.setOptions(d) } var c = function () { return { escapeRegExChars: function (a) { return a.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&") }, createNode: function (a) { var b = document.createElement("div"); return b.className = a, b.style.position = "absolute", b.style.display = "none", b } } }(), d = { ESC: 27, TAB: 9, RETURN: 13, LEFT: 37, UP: 38, RIGHT: 39, DOWN: 40 }; b.utils = c, a.Autocomplete = b, b.formatResult = function (a, b) { var d = "(" + c.escapeRegExChars(b) + ")"; return a.value.replace(new RegExp(d, "gi"), "$1").replace(/&/g, "&").replace(//g, ">").replace(/"/g, """).replace(/<(\/?strong)>/g, "<$1>") }, b.prototype = { killerFn: null, initialize: function () { var c, d = this, e = "." + d.classes.suggestion, f = d.classes.selected, g = d.options; d.element.setAttribute("autocomplete", "off"), d.killerFn = function (b) { 0 === a(b.target).closest("." + d.options.containerClass).length && (d.killSuggestions(), d.disableKillerFn()) }, d.noSuggestionsContainer = a('

').html(this.options.noSuggestionNotice).get(0), d.suggestionsContainer = b.utils.createNode(g.containerClass), c = a(d.suggestionsContainer), c.appendTo(g.appendTo), "auto" !== g.width && c.width(g.width), c.on("mouseover.autocomplete", e, function () { d.activate(a(this).data("index")) }), c.on("mouseout.autocomplete", function () { d.selectedIndex = -1, c.children("." + f).removeClass(f) }), c.on("click.autocomplete", e, function () { d.select(a(this).data("index")) }), d.fixPositionCapture = function () { d.visible && d.fixPosition() }, a(window).on("resize.autocomplete", d.fixPositionCapture), d.el.on("keydown.autocomplete", function (a) { d.onKeyPress(a) }), d.el.on("keyup.autocomplete", function (a) { d.onKeyUp(a) }), d.el.on("blur.autocomplete", function () { d.onBlur() }), d.el.on("focus.autocomplete", function () { d.onFocus() }), d.el.on("change.autocomplete", function (a) { d.onKeyUp(a) }), d.el.on("input.autocomplete", function (a) { d.onKeyUp(a) }) }, onFocus: function () { var a = this; a.fixPosition(), 0 === a.options.minChars && 0 === a.el.val().length && a.onValueChange() }, onBlur: function () { this.enableKillerFn() }, abortAjax: function () { var a = this; a.currentRequest && (a.currentRequest.abort(), a.currentRequest = null) }, setOptions: function (b) { var c = this, d = c.options; a.extend(d, b), c.isLocal = a.isArray(d.lookup), c.isLocal && (d.lookup = c.verifySuggestionsFormat(d.lookup)), d.orientation = c.validateOrientation(d.orientation, "bottom"), a(c.suggestionsContainer).css({ "max-height": d.maxHeight + "px", width: d.width + "px", "z-index": d.zIndex }) }, clearCache: function () { this.cachedResponse = {}, this.badQueries = [] }, clear: function () { this.clearCache(), this.currentValue = "", this.suggestions = [] }, disable: function () { var a = this; a.disabled = !0, clearInterval(a.onChangeInterval), a.abortAjax() }, enable: function () { this.disabled = !1 }, fixPosition: function () { var b = this, c = a(b.suggestionsContainer), d = c.parent().get(0); if (d === document.body || b.options.forceFixPosition) { var e = b.options.orientation, f = c.outerHeight(), g = b.el.outerHeight(), h = b.el.offset(), i = { top: h.top, left: h.left }; if ("auto" === e) { var j = a(window).height(), k = a(window).scrollTop(), l = -k + h.top - f, m = k + j - (h.top + g + f); e = Math.max(l, m) === l ? "top" : "bottom" } if ("top" === e ? i.top += -f : i.top += g, d !== document.body) { var n, o = c.css("opacity"); b.visible || c.css("opacity", 0).show(), n = c.offsetParent().offset(), i.top -= n.top, i.left -= n.left, b.visible || c.css("opacity", o).hide() } "auto" === b.options.width && (i.width = b.el.outerWidth() - 2 + "px"), c.css(i) } }, enableKillerFn: function () { var b = this; a(document).on("click.autocomplete", b.killerFn) }, disableKillerFn: function () { var b = this; a(document).off("click.autocomplete", b.killerFn) }, killSuggestions: function () { var a = this; a.stopKillSuggestions(), a.intervalId = window.setInterval(function () { a.hide(), a.stopKillSuggestions() }, 50) }, stopKillSuggestions: function () { window.clearInterval(this.intervalId) }, isCursorAtEnd: function () { var a, b = this, c = b.el.val().length, d = b.element.selectionStart; return "number" == typeof d ? d === c : document.selection ? (a = document.selection.createRange(), a.moveStart("character", -c), c === a.text.length) : !0 }, onKeyPress: function (a) { var b = this; if (!b.disabled && !b.visible && a.which === d.DOWN && b.currentValue) return void b.suggest(); if (!b.disabled && b.visible) { switch (a.which) { case d.ESC: b.el.val(b.currentValue), b.hide(); break; case d.RIGHT: if (b.hint && b.options.onHint && b.isCursorAtEnd()) { b.selectHint(); break } return; case d.TAB: if (b.hint && b.options.onHint) return void b.selectHint(); if (-1 === b.selectedIndex) return void b.hide(); if (b.select(b.selectedIndex), b.options.tabDisabled === !1) return; break; case d.RETURN: if (-1 === b.selectedIndex) return void b.hide(); b.select(b.selectedIndex); break; case d.UP: b.moveUp(); break; case d.DOWN: b.moveDown(); break; default: return }a.stopImmediatePropagation(), a.preventDefault() } }, onKeyUp: function (a) { var b = this; if (!b.disabled) { switch (a.which) { case d.UP: case d.DOWN: return }clearInterval(b.onChangeInterval), b.currentValue !== b.el.val() && (b.findBestHint(), b.options.deferRequestBy > 0 ? b.onChangeInterval = setInterval(function () { b.onValueChange() }, b.options.deferRequestBy) : b.onValueChange()) } }, onValueChange: function () { var b = this, c = b.options, d = b.el.val(), e = b.getQuery(d); return b.selection && b.currentValue !== e && (b.selection = null, (c.onInvalidateSelection || a.noop).call(b.element)), clearInterval(b.onChangeInterval), b.currentValue = d, b.selectedIndex = -1, c.triggerSelectOnValidInput && b.isExactMatch(e) ? void b.select(0) : void (e.length < c.minChars ? b.hide() : b.getSuggestions(e)) }, isExactMatch: function (a) { var b = this.suggestions; return 1 === b.length && b[0].value.toLowerCase() === a.toLowerCase() }, getQuery: function (b) { var c, d = this.options.delimiter; return d ? (c = b.split(d), a.trim(c[c.length - 1])) : b }, getSuggestionsLocal: function (b) { var c, d = this, e = d.options, f = b.toLowerCase(), g = e.lookupFilter, h = parseInt(e.lookupLimit, 10); return c = { suggestions: a.grep(e.lookup, function (a) { return g(a, b, f) }) }, h && c.suggestions.length > h && (c.suggestions = c.suggestions.slice(0, h)), c }, getSuggestions: function (b) { var c, d, e, f, g = this, h = g.options, i = h.serviceUrl; if (h.params[h.paramName] = b, d = h.ignoreParams ? null : h.params, h.onSearchStart.call(g.element, h.params) !== !1) { if (a.isFunction(h.lookup)) return void h.lookup(b, function (a) { g.suggestions = a.suggestions, g.suggest(), h.onSearchComplete.call(g.element, b, a.suggestions) }); g.isLocal ? c = g.getSuggestionsLocal(b) : (a.isFunction(i) && (i = i.call(g.element, b)), e = i + "?" + a.param(d || {}), c = g.cachedResponse[e]), c && a.isArray(c.suggestions) ? (g.suggestions = c.suggestions, g.suggest(), h.onSearchComplete.call(g.element, b, c.suggestions)) : g.isBadQuery(b) ? h.onSearchComplete.call(g.element, b, []) : (g.abortAjax(), f = { url: i, data: d, type: h.type, dataType: h.dataType }, a.extend(f, h.ajaxSettings), g.currentRequest = a.ajax(f).done(function (a) { var c; g.currentRequest = null, c = h.transformResult(a, b), g.processResponse(c, b, e), h.onSearchComplete.call(g.element, b, c.suggestions) }).fail(function (a, c, d) { h.onSearchError.call(g.element, b, a, c, d) })) } }, isBadQuery: function (a) { if (!this.options.preventBadQueries) return !1; for (var b = this.badQueries, c = b.length; c--;)if (0 === a.indexOf(b[c])) return !0; return !1 }, hide: function () { var b = this, c = a(b.suggestionsContainer); a.isFunction(b.options.onHide) && b.visible && b.options.onHide.call(b.element, c), b.visible = !1, b.selectedIndex = -1, clearInterval(b.onChangeInterval), a(b.suggestionsContainer).hide(), b.signalHint(null) }, suggest: function () { if (0 === this.suggestions.length) return void (this.options.showNoSuggestionNotice ? this.noSuggestions() : this.hide()); var b, c = this, d = c.options, e = d.groupBy, f = d.formatResult, g = c.getQuery(c.currentValue), h = c.classes.suggestion, i = c.classes.selected, j = a(c.suggestionsContainer), k = a(c.noSuggestionsContainer), l = d.beforeRender, m = "", n = function (a, c) { var d = a.data[e]; return b === d ? "" : (b = d, '

' + b + "

") }; return d.triggerSelectOnValidInput && c.isExactMatch(g) ? void c.select(0) : (a.each(c.suggestions, function (a, b) { e && (m += n(b, g, a)), m += '

' + f(b, g) + "

" }), this.adjustContainerWidth(), k.detach(), j.html(m), a.isFunction(l) && l.call(c.element, j), c.fixPosition(), j.show(), d.autoSelectFirst && (c.selectedIndex = 0, j.scrollTop(0), j.children("." + h).first().addClass(i)), c.visible = !0, void c.findBestHint()) }, noSuggestions: function () { var b = this, c = a(b.suggestionsContainer), d = a(b.noSuggestionsContainer); this.adjustContainerWidth(), d.detach(), c.empty(), c.append(d), b.fixPosition(), c.show(), b.visible = !0 }, adjustContainerWidth: function () { var b, c = this, d = c.options, e = a(c.suggestionsContainer); "auto" === d.width && (b = c.el.outerWidth() - 2, e.width(b > 0 ? b : 300)) }, findBestHint: function () { var b = this, c = b.el.val().toLowerCase(), d = null; c && (a.each(b.suggestions, function (a, b) { var e = 0 === b.value.toLowerCase().indexOf(c); return e && (d = b), !e }), b.signalHint(d)) }, signalHint: function (b) { var c = "", d = this; b && (c = d.currentValue + b.value.substr(d.currentValue.length)), d.hintValue !== c && (d.hintValue = c, d.hint = b, (this.options.onHint || a.noop)(c)) }, verifySuggestionsFormat: function (b) { return b.length && "string" == typeof b[0] ? a.map(b, function (a) { return { value: a, data: null } }) : b }, validateOrientation: function (b, c) { return b = a.trim(b || "").toLowerCase(), -1 === a.inArray(b, ["auto", "bottom", "top"]) && (b = c), b }, processResponse: function (a, b, c) { var d = this, e = d.options; a.suggestions = d.verifySuggestionsFormat(a.suggestions), e.noCache || (d.cachedResponse[c] = a, e.preventBadQueries && 0 === a.suggestions.length && d.badQueries.push(b)), b === d.getQuery(d.currentValue) && (d.suggestions = a.suggestions, d.suggest()) }, activate: function (b) { var c, d = this, e = d.classes.selected, f = a(d.suggestionsContainer), g = f.find("." + d.classes.suggestion); return f.find("." + e).removeClass(e), d.selectedIndex = b, -1 !== d.selectedIndex && g.length > d.selectedIndex ? (c = g.get(d.selectedIndex), a(c).addClass(e), c) : null }, selectHint: function () { var b = this, c = a.inArray(b.hint, b.suggestions); b.select(c) }, select: function (a) { var b = this; b.hide(), b.onSelect(a) }, moveUp: function () { var b = this; if (-1 !== b.selectedIndex) return 0 === b.selectedIndex ? (a(b.suggestionsContainer).children().first().removeClass(b.classes.selected), b.selectedIndex = -1, b.el.val(b.currentValue), void b.findBestHint()) : void b.adjustScroll(b.selectedIndex - 1) }, moveDown: function () { var a = this; a.selectedIndex !== a.suggestions.length - 1 && a.adjustScroll(a.selectedIndex + 1) }, adjustScroll: function (b) { var c = this, d = c.activate(b); if (d) { var e, f, g, h = a(d).outerHeight(); e = d.offsetTop, f = a(c.suggestionsContainer).scrollTop(), g = f + c.options.maxHeight - h, f > e ? a(c.suggestionsContainer).scrollTop(e) : e > g && a(c.suggestionsContainer).scrollTop(e - c.options.maxHeight + h), c.options.preserveInput || c.el.val(c.getValue(c.suggestions[b].value)), c.signalHint(null) } }, onSelect: function (b) { var c = this, d = c.options.onSelect, e = c.suggestions[b]; c.currentValue = c.getValue(e.value), c.currentValue === c.el.val() || c.options.preserveInput || c.el.val(c.currentValue), c.signalHint(null), c.suggestions = [], c.selection = e, a.isFunction(d) && d.call(c.element, e) }, getValue: function (a) { var b, c, d = this, e = d.options.delimiter; return e ? (b = d.currentValue, c = b.split(e), 1 === c.length ? a : b.substr(0, b.length - c[c.length - 1].length) + a) : a }, dispose: function () { var b = this; b.el.off(".autocomplete").removeData("autocomplete"), b.disableKillerFn(), a(window).off("resize.autocomplete", b.fixPositionCapture), a(b.suggestionsContainer).remove() } }, a.fn.autocomplete = a.fn.devbridgeAutocomplete = function (c, d) { var e = "autocomplete"; return 0 === arguments.length ? this.first().data(e) : this.each(function () { var f = a(this), g = f.data(e); "string" == typeof c ? g && "function" == typeof g[c] && g[c](d) : (g && g.dispose && g.dispose(), g = new b(this, c), f.data(e, g)) }) } }); // $(function () { var categories = [ 'Land Features', 'Bay', 'Channel', 'Cove', 'Dam', 'Delta', 'Gulf', 'Lagoon', 'Lake', 'Ocean', 'Reef', 'Reservoir', 'Sea', 'Sound', 'Strait', 'Waterfall', 'Wharf', // Water Features 'Amusem*nt Park', 'Historical Monument', 'Landmark', 'Tourist Attraction', 'Zoo', // POI/Arts and Entertainment 'College', // POI/Education 'Beach', 'Campground', 'Golf Course', 'Harbor', 'Nature Reserve', 'Other Parks and Outdoors', 'Park', 'Racetrack', 'Scenic Overlook', 'Ski Resort', 'Sports Center', 'Sports Field', 'Wildlife Reserve', // POI/Parks and Outdoors 'Airport', 'Ferry', 'Marina', 'Pier', 'Port', 'Resort', // POI/Travel 'Postal', 'Populated Place' ], cats = categories.join(','), overrides = { '08736, Manasquan, New Jersey, USA': { x: -74.037, y: 40.1128 }, '32899, Orlando, Florida, USA': { x: -80.6774, y: 28.6143 }, '97003, Beaverton, Oregon, USA': { x: -122.8752489, y: 45.5050916 }, '99734, Prudhoe Bay, Alaska, USA': { x: -148.3372, y: 70.2552 }, 'Guam, Oceania': { x: 144.74, y: 13.46 }, 'Andover, Maine, United States': { x: -70.7525, y: 44.634167 }, 'Bear Creek, Pennsylvania, United States': { x: -75.772809, y: 41.204074 }, 'Bear Creek Village, Pennsylvania, United States': { x: -75.772809, y: 41.204074 }, 'New York City, New York, United States': { x: -74.0059, y: 40.7142 }, 'Pinnacles National Monument, San Benito County,California, United States': { x: -121.147278, y: 36.47075 }, 'Pinnacles National Park, CA-146, Paicines, California': { x: -121.147278, y: 36.47075 }, 'Welcome, Maryland, United States': { x: -77.081212, y: 38.4692469 } }, doRedirectToGeometry = function (geom) { var lon = geom.x; var lat = geom.y; getData(lat, lon); }; $('#inputsearch').devbridgeAutocomplete({ serviceUrl: '//geocode.arcgis.com/arcgis/rest/services/World/GeocodeServer/suggest', deferRequestBy: 300, paramName: 'text', params: { f: 'json', countryCode: 'USA,PRI,VIR,GUM,ASM', category: cats, maxSuggestions: 10 }, dataType: 'jsonp', transformResult: function (response) { return { suggestions: $.map(response.suggestions, function (i) { return { value: i.text, data: i.magicKey }; }) }; }, minChars: 3, showNoSuggestionNotice: true, noSuggestionNotice: window.noresults, onSelect: function (suggestion) { var request; if (overrides[suggestion.value]) { doRedirectToGeometry(overrides[suggestion.value]); } else { request = $.ajax({ url: '//geocode.arcgis.com/arcgis/rest/services/World/GeocodeServer/find', data: { text: suggestion.value, magicKey: suggestion.data, f: 'json' }, jsonp: 'callback', dataType: 'jsonp' }); request.done(function (data) { var loc = data.locations[0]; if (loc) { doRedirectToGeometry(loc.feature.geometry); } else { alert('An unexpected error occurred. Please try a different search string.'); } }); } }, width: 400 }); var ac = $('#inputsearch').devbridgeAutocomplete(); $("#inputsearch").on('keyup', function (e) { if (e.keyCode == 13) { if (d3.select('.autocomplete-no-suggestion').text() == window.noresults) { var lonlat = d3.select('#inputsearch').node().value.split(','); var lat = Number(lonlat[0].replace(/[^\d.-]/g, '')); var lon = Number(lonlat[1].replace(/[^\d.-]/g, '')); // Handle input as lon, lat if (lat < 0) { getData(lon, lat); } else { getData(lat, lon); } } } }); /** * The Map * */ var attribution = 'Tiles © ArcGIS'; var esridark = new ol.layer.Tile( { title: "ESRI Dark Gray", type: 'base', visible: false, source: new ol.source.XYZ({ attributions: attribution, url: 'https://server.arcgisonline.com/ArcGIS/rest/services/Canvas/World_Dark_Gray_Base/MapServer/tile/{z}/{y}/{x}' }) }); var title = "City Reference (For Dark Background)"; var esridark_reference = new ol.layer.Tile( { title: title, //type : 'base', visible: (activateLayers.includes(title.replace(/\W/g, ''))) ? true : false, source: new ol.source.XYZ({ attributions: attribution, url: 'https://server.arcgisonline.com/ArcGIS/rest/services/Canvas/World_Dark_Gray_Reference/MapServer/tile/{z}/{y}/{x}' }) }); var map = new ol.Map({ layers: [ new ol.layer.Group({ title: 'Base map', layers: [ new ol.layer.Tile({ type: 'base', title: 'Ocean Basemap', source: new ol.source.XYZ({ attributions: 'Tiles © ArcGIS', url: 'https://server.arcgisonline.com/ArcGIS/rest/services/' + 'Ocean_Basemap/MapServer/tile/{z}/{y}/{x}' }), visible: false }), new ol.layer.Tile({ source: new ol.source.OSM(), type: 'base', // visible: (basemap == "openstreetmap" || basemap == "osm" || basemap =="stamenterrain" || basemap =="stamentoner") ? true : false, title: 'Open Street Map', visible: true }), world_imagery, esridark ] }) ], interactions: ol.interaction.defaults({ altShiftDragRotate: false, rotate: false, pinchRotate: false }), controls: ol.control.defaults().extend([ new ol.control.FullScreen() ]), target: 'map', view: new ol.View({ center: ol.proj.transform([window.clon, window.clat], "EPSG:4326", "EPSG:3857"), zoom: window.zoom, zoomFactor: 1.5 }) }); // Mouse over lat/lon coords var mousePositionControl = new ol.control.MousePosition({ coordinateFormat: new ol.coordinate.createStringXY(4), projection: 'EPSG:4326' }); map.addControl(mousePositionControl); window.onresize = function () { setTimeout(function () { map.updateSize(); }, 200); }; // Create a group for overlays. Add the group to the map when it's created // but add the overlay layers later var hydroGroup = new ol.layer.Group({ title: 'Hydrology Layers', layers: [] }); map.addLayer(hydroGroup); var excessiveRainfallOutlookGroup = new ol.layer.Group({ title: 'Excessive Rainfall Risk', layers: [] }); map.addLayer(excessiveRainfallOutlookGroup); var convectiveOutlookGroup = new ol.layer.Group({ title: 'Severe Weather Risk', layers: [] }); map.addLayer(convectiveOutlookGroup); var referenceGroup = new ol.layer.Group({ title: 'Reference Layers', layers: [] }); map.addLayer(referenceGroup); var overlayGroup = new ol.layer.Group({ title: 'Overlays', layers: [] }); map.addLayer(overlayGroup); addToOverlayGroup(esridark_reference, referenceGroup); // Create a group for overlays. Add the group to the map when it's created // but add the overlay layers later // var overlayGroup = new ol.layer.Group({ // title: 'Overlays', // layers: [] // }); // map.addLayer(overlayGroup); // Create a LayerSwitcher instance and add it to the map var layerSwitcher = new ol.control.LayerSwitcher(); map.addControl(layerSwitcher); // Special function to handle sorting layers alphabetically // Trick is these are put into the array in reverse order, so sort reverse alphabetically first. function addToOverlayGroup(layer, group) { var added = false; // First element in array if (group.getLayersArray().length == 0) { group.getLayers().push(layer); return; } // Sort reverse alphabetically first, then loop and find where to stuff layer group.getLayersArray().sort(function (a, b) { if (a.get('title') > b.get('title')) { return -1; } if (a.get('title') < b.get('title')) { return 1; } return 0; }).forEach(function (obj, index) { var compare = layer.get('title') > obj.get('title'); if (compare && !added) { group.getLayers().insertAt(index, layer); added = true; } }) // End of array if (!added) { group.getLayers().push(layer); } } function updateWMSforExtent() { Object.keys(window.wmsLayers).forEach(function (obj) { if (obj.indexOf('.source') !== -1) { var url = window.wmsLayers[obj].url_; if (url.indexOf("?") > -1) { url = url.substr(0, url.indexOf("?")); } var special = false; if (window.restLayers.includes(obj.split('.')[0])) { special = true; } updateWMSExtent(obj.split('.')[0], url, window.wmsLayers[obj.split('.')[0]].get('layername'), special); } }) } function updateWMSExtent(name, wms, layer, special) { var sourcelabel = name + '.source'; var addListenerBool = false; if (!window.wmsLayers.hasOwnProperty(sourcelabel)) { addListenerBool = true; } if (special) { // Fixes a bug that cropped up with different bbox on initial load if (!window.domainHasBeenChanged) { var my_special_width = 435; var my_special_height = 890; } else { var my_special_width = map.getSize()[1]; var my_special_height = map.getSize()[0]; } window.wmsLayers[name + '.source'] = new ol.source.ImageStatic({ url: wms + '?f=image&format=png8&TRANSPARENT=true&LAYERS=show:' + layer + '&CRS=EPSG%3A3857&STYLES=' + '&BBOX=' + window.imageExtent.toString() + '&bboxSR=102100&imageSR=102100&size=' + my_special_height + '%2C' + my_special_width, imageExtent: window.imageExtent }); } else { window.wmsLayers[name + '.source'] = new ol.source.ImageStatic({ url: wms + '?SERVICE=WMS&VERSION=1.3.0&REQUEST=GetMap&FORMAT=image%2Fpng&TRANSPARENT=true&LAYERS=' + layer + '&CRS=EPSG%3A3857&STYLES=' + '&WIDTH=' + ndfdWMSwidth * 6 + '&HEIGHT=' + ndfdWMSheight * 6 + '&BBOX=' + window.imageExtent.toString(), imageExtent: window.imageExtent }); } if (addListenerBool) { addLoadingListeners(window.wmsLayers[name + '.source']); } window.wmsLayers[name].setSource(window.wmsLayers[name + '.source']); } window.restLayers = []; function addWMSLayer(name, wms, layer, overlayGroup, special) { var selector_string = name.replace(/ /g, '') + "legend"; var selector = "#" + selector_string; if (!window.wmsLayers.hasOwnProperty(name)) { if (special) { restLayers.push(name); } window.wmsLayers[name] = new ol.layer.Image({ title: name, layername: layer, visible: (activateLayers.includes(name.replace(/\W/g, ''))) ? true : false, opacity: 0.5 }); window.wmsLayers[name].on('change:visible', function (e) { if (window.wmsLayers[name].getVisible()) { d3.select(selector).style('display', 'block'); } else { d3.select(selector).style('display', 'none'); } }) addToOverlayGroup(window.wmsLayers[name], overlayGroup); updateWMSExtent(name, wms, layer, special); if (special) { // Excessive Rainfall if (name.indexOf('Excessive') !== -1) { var legend = "https://www.weather.gov/images/dlh/jonathan/er_outlook.PNG"; d3.select('#myNav').select('.overlay-content').append('span').attr('id', selector_string).append('a').html(name + '
').append('img').attr('src', legend); if (!(activateLayers.includes(name.replace(/\W/g, '')))) { d3.select(selector).style('display', 'none'); } } else { var legend = "https://www.weather.gov/images/dlh/jonathan/convective_outlook.PNG"; d3.select('#myNav').select('.overlay-content').append('span').attr('id', selector_string).append('a').html(name + '
').append('img').attr('src', legend); if (!(activateLayers.includes(name.replace(/\W/g, '')))) { d3.select(selector).style('display', 'none'); } } } else { var legend = wms + '?request=GetLegendGraphic%26version=1.3.0%26format=image/png%26layer=' + layer; d3.select('#myNav').select('.overlay-content').append('span').attr('id', selector_string).append('a').html(name + '
').append('img').attr('src', legend); if (!(activateLayers.includes(name.replace(/\W/g, '')))) { d3.select(selector).style('display', 'none'); } } } else { updateWMSExtent(name, wms, layer, special); } } var server = 'https://nowcoast.noaa.gov/arcgis/services/nowcoast/analysis_meteohydro_sfc_qpe_time/MapServer/WmsServer'; // addWMSLayer('Rainfall - Last 72 Hours', server, '1', hydroGroup); // addWMSLayer('Rainfall - Last 48 Hours', server, '5', hydroGroup); // addWMSLayer('Rainfall - Last 24 Hours', server, '9', hydroGroup); // addWMSLayer('Rainfall - Last 12 Hours', server, '13', hydroGroup); // addWMSLayer('Rainfall - Last 06 Hours', server, '17', hydroGroup); // addWMSLayer('Rainfall - Last 03 Hours', server, '21', hydroGroup); // addWMSLayer('Rainfall - Last 01 Hour', server, '25', hydroGroup); var co_server = 'https://idpgis.ncep.noaa.gov/arcgis/rest/services/NWS_Forecasts_Guidance_Warnings/SPC_wx_outlks/MapServer/export'; addWMSLayer('Day 1 Convective Outlook', co_server, '1', convectiveOutlookGroup, true); addWMSLayer('Day 2 Convective Outlook', co_server, '9', convectiveOutlookGroup, true); addWMSLayer('Day 3 Convective Outlook', co_server, '17', convectiveOutlookGroup, true); var er_server = 'https://idpgis.ncep.noaa.gov/arcgis/rest/services/NWS_Forecasts_Guidance_Warnings/wpc_precip_hazards/MapServer/export'; addWMSLayer('Day 1 Excessive Rainfall', er_server, '0', excessiveRainfallOutlookGroup, true); addWMSLayer('Day 2 Excessive Rainfall', er_server, '1', excessiveRainfallOutlookGroup, true); addWMSLayer('Day 3 Excessive Rainfall', er_server, '2', excessiveRainfallOutlookGroup, true); // // Convective Outlook // var co = new ol.layer.Image({ // title: 'Day 1 Convective Outlook', // visible: layers[0] == "T" ? true : false, // opacity: 0.7 // }); // overlayGroup.getLayers().push(co); // // if (layers[0] == "T") { // d3.select('#colegend').style('display', 'block'); // } else { // d3.select('#colegend').style('display', 'none'); // } // // co.on('change:visible', function(e) { // if (co.getVisible()) { // d3.select('#colegend').style('display', 'block'); // } else { // d3.select('#colegend').style('display', 'none'); // } // }); // // // function updateCO() { // var coSource = new ol.source.ImageStatic({ // url: 'https://idpgis.ncep.noaa.gov/arcgis/rest/services/NWS_Forecasts_Guidance_Warnings/SPC_wx_outlks/MapServer/WMSServer?SERVICE=WMS&VERSION=1.3.0&REQUEST=GetMap&FORMAT=image%2Fpng&TRANSPARENT=true&LAYERS=21&CRS=EPSG%3A3857&STYLES=' + '&WIDTH=' + ndfdWMSwidth * 6 + '&HEIGHT=' + ndfdWMSheight * 6 + '&BBOX=' + window.imageExtent.toString(), // + '&time=' + wms_time, // imageExtent: window.imageExtent // }); // addLoadingListeners(coSource); // co.setSource(coSource); // } // updateCO(); // Radar var title = 'Radar'; var radar = new ol.layer.Image({ title: title, visible: (activateLayers.includes(title.replace(/\W/g, ''))) ? true : false, opacity: 0.7 }); addToOverlayGroup(radar, overlayGroup); updateRadar(); // Event radar.on('change:visible', function (e) { if (radar.getVisible()) { window.radartimer.start(); } else { window.radartimer.stop(); } }); // Outlines var mystyle = new ol.style.Style({ stroke: new ol.style.Stroke({ color: '#000000', width: 1 }) }); var title = 'U.S. States'; var usStates = new ol.layer.Vector({ title: title, source: new ol.source.Vector({ //url: 'us-states.json', url: 'https://www.weather.gov/source/dlh/us-states.json', format: new ol.format.TopoJSON({}), overlaps: true //false }), style: mystyle, visible: (activateLayers.includes(title.replace(/\W/g, ''))) ? true : false }); usStates.setZIndex(999999); addToOverlayGroup(usStates, referenceGroup); // Observations // var obSource = new ol.source.Vector(); var title = 'Observations'; var obLayer = new ol.layer.Vector({ title: title, visible: (activateLayers.includes(title.replace(/\W/g, ''))) ? true : false // source: vectorSource }); addToOverlayGroup(obLayer, overlayGroup); function getContrast50(a) { return (luma(a.replace("#", "")) >= 165) ? "#000000" : "#FFFFFF"; } function luma(a) { var b = (typeof a === "string") ? hexToRGBArray(a) : a; return (0.2126 * b[0]) + (0.7152 * b[1]) + (0.0722 * b[2]); } function hexToRGBArray(a) { if (a.length === 3) { a = a.charAt(0) + a.charAt(0) + a.charAt(1) + a.charAt(1) + a.charAt(2) + a.charAt(2); } else { if (a.length !== 6) { try { return a.replace(/rgb|\(|\)/g, "").split(",").map(Number); } catch (d) { throw ("Invalid hex color: " + a); } } } var b = []; for (var c = 0; c <= 2; c++) { b[c] = parseInt(a.substr(c * 2, 2), 16); } return b; }; // https://api.weather.gov/alerts/active var title = 'Hazards'; var hazardLayer = new ol.layer.Vector({ title: title, visible: (activateLayers.includes(title.replace(/\W/g, ''))) ? true : false }); if (hazardLayer.getVisible()) { d3.select('#ibw').style('display', 'block'); } else { d3.select('#ibw').style('display', 'none'); } // Event hazardLayer.on('change:visible', function (e) { if (hazardLayer.getVisible()) { d3.select('#ibw').style('display', 'block'); } else { d3.select('#ibw').style('display', 'none'); } }); var hazStyleCache = {}; hazardLayer.setStyle( function (feature, resolution) { var color = hazColor[feature.get('event')].Color2; if (typeof color == "undefined") { color = hazColor[feature.get('event')].Color; } var label = feature.get('event'); var contrast = getContrast50(color); var textStroke = new ol.style.Stroke({ color: contrast, width: 5 }); var textFill = new ol.style.Fill({ color: color }); // console.log(feature.get('parameters').hailSize[0], feature.get('parameters').tornadoDetection[0], feature.get('parameters').windGust[0]) var strokeWidth = 4; // IBW var tornadoDetection = feature.get('parameters').tornadoDetection if (typeof tornadoDetection !== "undefined" && tornadoDetection.length > 0) { tornadoDetection = tornadoDetection[0]; } var hailSize = feature.get('parameters').hailSize; var windGust = feature.get('parameters').windGust; if (typeof tornadoDetection !== "undefined") { label += '\nTornado: ' + tornadoDetection; } if (typeof windGust !== "undefined") { label += '\nWind Gusts: ' + windGust; } if (typeof hailSize !== "undefined") { label += '\nHail: ' + hailSize; } var regex = /[+-]?\d*\.*\d+/g; var backgroundFillColor = color; // Handle tors differently if (feature.get('event').indexOf("Tornado") != -1) { if (tornadoDetection == "CATASTROPHIC") { strokeWidth = 20; } else if (tornadoDetection == "CONSIDERABLE") { strokeWidth = 14; } else if (tornadoDetection == "OBSERVED") { strokeWidth = 14; } else if (tornadoDetection == "POSSIBLE") { backgroundFillColor = 'red'; } else { strokeWidth = 4; } } else if (feature.get('event').indexOf("Special Marine") != -1) { if (typeof windGust !== "undefined" && windGust[0].match(regex).map(function (v) { return parseFloat(v); }) >= 50) { strokeWidth = 14; } else { strokeWidth = 7; } } else if (feature.get('event').indexOf("Flash Flood") != -1) { // Handle FFW Emergency if (typeof (feature.get('parameters')["NWSheadline"]) !== "undefined" && feature.get('parameters')["NWSheadline"][0].indexOf('EMERGENCY') !== -1) { strokeWidth = 14; } else { strokeWidth = 7; } } else if (feature.get('event').indexOf("Severe Thunderstorm") != -1) { if (tornadoDetection == "POSSIBLE") { backgroundFillColor = 'red'; } // SEVERE if (typeof (windGust) !== "undefined" && windGust[0].match(regex).map(function (v) { return parseFloat(v); }) >= 80) { strokeWidth = 14; //14 } else if (typeof (hailSize) !== "undefined" && hailSize[0] >= 2.5) { strokeWidth = 14; } else { strokeWidth = 7; } } backgroundFillColor = ol.color.asArray(backgroundFillColor); backgroundFillColor = backgroundFillColor.slice(); backgroundFillColor[3] = 0.4; var overflow = true; if (resolution > 100) { overflow = false; } // console.log(feature.get('event'), hazardPriority(hazColor[feature.get('event')].Priority)); return [ new ol.style.Style({ stroke: new ol.style.Stroke({ color: 'black', width: strokeWidth }), zIndex: hazardPriority(hazColor[feature.get('event')].Priority) }), new ol.style.Style({ stroke: new ol.style.Stroke({ color: color, width: 3 }), fill: new ol.style.Fill({ color: backgroundFillColor }), text: new ol.style.Text({ font: '20px Calibri,sans-serif', text: label, fill: textFill, stroke: textStroke, overflow: overflow }), zIndex: hazardPriority(hazColor[feature.get('event')].Priority) }) ]; } ); addToOverlayGroup(hazardLayer, overlayGroup); // Dot on map var title = 'Sample Point'; var dotSource = new ol.source.Vector(); var dotLayer = new ol.layer.Vector({ title: title, source: dotSource, visible: (activateLayers.includes(title.replace(/\W/g, ''))) ? true : false }); dotLayer.setZIndex(9999999); hazardLayer.setZIndex(9999997); addToOverlayGroup(dotLayer, referenceGroup); // Counties var title = 'U.S. Counties (low-resolution)'; var usCounties = new ol.layer.Vector({ title: title, source: new ol.source.Vector({ //url: 'counties.json', url: 'https://www.weather.gov/source/dlh/edd/counties.json', format: new ol.format.TopoJSON({ layers: ['counties'] }), overlaps: true //false }), // style : county_style, visible: (activateLayers.includes(title.replace(/\W/g, ''))) ? true : false }); usCounties.setZIndex(9999998); addToOverlayGroup(usCounties, referenceGroup); usCounties.setStyle( function (feature, resolution) { var color = '#000000'; var contrast = getContrast50(color); var textStroke = new ol.style.Stroke({ color: contrast, width: 5 }); var textFill = new ol.style.Fill({ color: color }); // var overflow = true; // if (resolution> 2000){ // overflow = false; // } var name = feature.get('name'); var stroke_color = 'rgba(50,50,50,0.25)' if (world_imagery.getVisible()) { stroke_color = 'rgba(255,255,255,0.25)' } return [ new ol.style.Style({ stroke: new ol.style.Stroke({ color: stroke_color, width: 1 }), text: new ol.style.Text({ font: '20px Calibri,sans-serif', text: name, fill: textFill, stroke: textStroke // , // overflow:overflow }) }) ]; } ); // // Lightning Density // var title = 'Lightning Density'; // var lightning = new ol.layer.Image({ // title: title, // visible: (activateLayers.includes(title.replace(/\W/g, ''))) ? true : false, // opacity: 0.7 // }); // if (activateLayers.includes(title.replace(/\W/g, ''))) { // d3.select('#lightninglegend').style('display', 'block'); // } else { // d3.select('#lightninglegend').style('display', 'none'); // } // addToOverlayGroup(lightning, overlayGroup); // updateLightning(); // // Event // lightning.on('change:visible', function(e) { // if (lightning.getVisible()) { // d3.select('#lightninglegend').style('display', 'block'); // } else { // d3.select('#lightninglegend').style('display', 'none'); // } // }); function make_domain() { var llx = window.imageExtent[0]; var lly = window.imageExtent[1]; var urx = window.imageExtent[2]; var ury = window.imageExtent[3]; var geojsonObject = { 'type': 'FeatureCollection', 'features': [{ 'type': 'Feature', 'geometry': { 'type': 'MultiPolygon', 'coordinates': [ // ll, ul, ur, lr [ [ [-20037508.3427892, -20037508.3427892], [-20037508.3427892, 20037508.3427892], [20037508.3427892, 20037508.3427892], [20037508.3427892, -20037508.3427892] ], // hole [ [llx, lly], [llx, ury], [urx, ury], [urx, lly] ] ] ] } }] }; var vectorSource = new ol.source.Vector({ features: (new ol.format.GeoJSON()).readFeatures(geojsonObject) }); window.domainLayer.setSource(vectorSource); } var domainstyleFunction = function (feature) { var color = '#000000'; var contrast = getContrast50(color); var textStroke = new ol.style.Stroke({ color: contrast, width: 5 }); var textFill = new ol.style.Fill({ color: color }); return new ol.style.Style({ stroke: new ol.style.Stroke({ color: 'black', width: 5 }), fill: new ol.style.Fill({ color: 'rgba(0, 0, 0, 0.5)' }), text: new ol.style.Text({ font: '20px Calibri,sans-serif', text: 'Click change domain to show values in this area', fill: textFill, stroke: textStroke }) }); }; // var vectorSource = new ol.source.Vector({ // features: (new ol.format.GeoJSON()).readFeatures(geojsonObject) // }); // vectorSource.addFeature(new ol.Feature(new Circle([5e6, 7e6], 1e6))); window.domainLayer = new ol.layer.Vector({ title: 'Domain', // source: vectorSource//, style: domainstyleFunction }); addToOverlayGroup(window.domainLayer, referenceGroup); make_domain(); function updateLsrs() { var format = 'YYYYMMDDHH:mm'; var start = new moment.utc().subtract(6, 'hours').format(format); var end = new moment.utc().format(format); d3.json('https://mesonet.agron.iastate.edu/geojson/lsr.php?sts=' + start + '&ets=' + end).then(function (data) { // Trick OL3 since Geojson has CRS defined data['crs'] = {}; data['crs']['properties'] = {}; data.crs.type = 'name'; data.crs.properties.name = 'EPSG:4326'; var features = new ol.format.GeoJSON().readFeatures(data, { featureProjection: 'EPSG:3857' }); var lsrSource = new ol.source.Vector({ features: features }); window.lsrLayer.setSource(lsrSource); }) } var lsrWindScale = d3.scaleLinear().domain([60, 100]).range([2, 9]); var lsrStyleFunction = function (feature) { var color, zIndex; var typetext = feature.get('typetext'); var radius = 4; if (typetext == "HAIL") { color = "#00C33B"; radius = Number(feature.get('magnitude')) * 3; zIndex = 1 } else if (typetext.indexOf('WIND') !== -1) { color = "#001EFF"; radius = lsrWindScale(Number(feature.get('magnitude'))) zIndex = 2; } else if (typetext.indexOf('TORNADO') !== -1) { color = "#FD0000"; radius = 5; zIndex = 3; } else { return; } if (radius < 0) { return; } var contrast = getContrast50(color); var textStroke = new ol.style.Stroke({ color: contrast, width: 4 }); var textFill = new ol.style.Fill({ color: color }); var styleObject = { zIndex: zIndex, image: new ol.style.Circle({ radius: radius, fill: new ol.style.Fill({ color: color }), stroke: new ol.style.Stroke({ color: 'rgba(0,0,0,1)', width: 1 }) }) }; if (map.getView().getZoom() >= 10) { styleObject['text'] = new ol.style.Text({ font: '20px Calibri,sans-serif', text: feature.get('magnitude'), fill: textFill, stroke: textStroke, offsetY: -20 }) } return new ol.style.Style(styleObject); }; var title = 'Storm Reports'; window.lsrLayer = new ol.layer.Vector({ title: title, visible: activateLayers.includes(title.replace(/\W/g, '')), style: lsrStyleFunction }); addToOverlayGroup(window.lsrLayer, overlayGroup); lsrLayer.setZIndex(99999999); updateLsrs(); if (lsrLayer.getVisible()) { d3.select('#lsr').style('display', 'block'); } else { d3.select('#lsr').style('display', 'none'); } // Event lsrLayer.on('change:visible', function (e) { if (lsrLayer.getVisible()) { d3.select('#lsr').style('display', 'block'); } else { d3.select('#lsr').style('display', 'none'); } }); map.on('click', function (evt) { var coords = ol.proj.toLonLat(evt.coordinate); var lat = coords[1]; var lon = coords[0]; getData(lat, lon); if (getLayerByName('Observations').getVisible()) { displayPopup(evt); } }); /** * Color scales * */ var jtColorScale = d3.scaleThreshold() .domain([-60, -55, -50, -45, -40, -35, -30, -25, -20, -15, -10, -5, 0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90, 95, 100, 105, 110, 115, 120, 140]) .range(["#91003f", "#ce1256", "#e7298a", "#df65b0", "#ff73df", "#ffbee8", "#ffffff", "#dadaeb", "#bcbddc", "#9e9ac8", "#756bb1", "#54278f", "#0d007d", "#0d339c", "#0066c2", "#299eff", "#4ac7ff", "#73d7ff", "#adffff", "#30cfc2", "#009996", "#125757", "#066d2c", "#31a354", "#74c476", "#a1d99b", "#d3ffbe", "#ffffb3", "#ffeda0", "#fed176", "#feae2a", "#fd8d3c", "#fc4e2a", "#e31a1c", "#b10026", "#800026", "#590042", "#280028"]); var ageScale = d3 //.scaleLinear() // .domain([60, 1200]) // .range([1.0,0.01]); .scaleThreshold() .domain([60, 120, 300, 600, 1200]) .range([1.0, 0.75, 0.5, 0.25, 0.1, 0.01]); var wxColorScale = d3.scaleThreshold() .domain([]) .range(["#ffffff"]); var tColorScale = d3.scaleThreshold() .domain([-999, 33, 140]) .range(["#4286f4", "#4286f4", "#ffffff"]); var tdColorScale = d3.scaleThreshold() .domain([0, 10, 20, 30, 40, 45, 50, 55, 60, 65, 70, 75, 80, 100]) .range(["#3b2204", "#543005", "#8c520a", "#bf812d", "#cca854", "#dfc27d", "#e6d9b5", "#d3ebe7", "#a9dbd3", "#72b8ad", "#318c85", "#01665f", "#003c30", "#002921"]); // var windColorScale = d3.scaleThreshold() // .domain([5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 60, 70, 80, 100, 120, 140, 999]) // .range(["#103f78", "#225ea8", "#1d91c0", "#41b6c4", "#7fcdbb", "#b4d79e", "#dfff9e", "#ffffa6", "#ffe873", "#ffc400", "#ffaa00", "#ff5900", "#ff0000", "#a80000", "#6e0000", "#ffbee8", "#ff73df"]); var windColorScale = d3.scaleThreshold() .domain([10, 20, 30, 35, 48, 999]) .range(['#ffffff', '#cbc9e2', '#9e9ac8', '#756bb1', '#ff7f00', "#ff0000"]); //]); var heatChillColorScale = d3.scaleThreshold() .domain([-40, -35, -30, -20, -10, 0, 10, 20, 30, 125]) .range(["#91003f", "#e7298a", "#ff73df", "#ffbee8", "#dadaeb", "#9e9ac8", "#54278f", "#0d339c", "#0066c2", "#ffffff"]); // var heatChillColorScale = d3.scaleThreshold() // .domain([-60, -55, -50, -45, -40, -35, -30, -25, -20, -15, -10, -5, 0, 5, 10, 15, 20, 25, 30, 35, 40, 75, 80, 85, 90, 95, 100, 105, 110, 115, 120, 125]) // .range(["#91003f", "#ce1256", "#e7298a", "#df65b0", "#ff73df", "#ffbee8", "#ffffff", "#dadaeb", "#bcbddc", "#9e9ac8", "#756bb1", "#54278f", "#0d007d", "#0d339c", "#0066c2", "#299eff", "#4ac7ff", "#73d7ff", "#adffff", "#30cfc2", "#009996", "#dcdcdc", "#ffeda0", "#fed176", "#feae2a", "#fd8d3c", "#fc4e2a", "#e31a1c", "#b10026", "#800026", "#590042", "#280028"]); var rhColorScale = d3.scaleThreshold() .domain([5, 10, 15, 20, 25, 40, 95, 100]) .range(["#910022", "#a61122", "#bd2e24", "#d44e33", "#e36d42", "#fa8f43", "#FFFFFF", "#afafaf", "#686868"]); var waveColorScaleValues = d3.scaleThreshold() .domain(['-', 5, 10, 15, 20, 30]) .range(['#000000', '#000000', '#ff7f00', '#ff0000']); var waveColorScale = d3.scaleThreshold() .domain(['-', 0, 5, 10, 15, 20, 30]) .range(['#ffffff', '#ffffff', '#ffffff', '#ffffb2', '#ff7f00', '#ff0000']); var jrhColorScale = d3.scaleThreshold() .domain([5, 10, 15, 20, 25, 30, 35, 40, 50, 60, 70, 80, 90, 100]) .range(["#910022", "#a61122", "#bd2e24", "#d44e33", "#e36d42", "#fa8f43", "#fcad58", "#fed884", "#fff2aa", "#e6f49d", "#bce378", "#71b55c", "#26914b", "#00572e"]); // var popColorScale = d3.scaleThreshold() // .domain([10, 20, 30, 40, 50, 60, 70, 80, 90, 100]) // .range(["#f5f5f5", "#e2f6da", "#d5f2ca", "#c0ebaf", "#98df7b", "#6fd349", "#43c634", "#23b70b", "#139e07", "#0b8403"]); var popColorScale = d3.scaleThreshold() .domain([10, 20, 30, 40, 50, 60, 70, 80, 90, 100]) .range(["#ffffff", "#e2f6da", "#d5f2ca", "#c0ebaf", "#98df7b", "#6fd349", "#43c634", "#23b70b", "#139e07", "#0b8403"]); var snowColorScale = d3.scaleThreshold() .domain([0.01, 1, 2, 3, 4, 6, 8, 12, 18, 24, 30, 36, 99.99]) .range(["#ffffff", "#bdd7e7", "#6baed6", "#3182bd", "#08519c", "#082694", "#ffff96", "#ffc400", "#ff8700", "#db1400", "#9e0000", "#690000", "#360000", "#360000"]); var qpfColorScale = d3.scaleThreshold() .domain([0.09, 0.24, 0.49, 0.99, 1.49, 1.99, 2.99, 3.99, 5.99, 7.99, 9.99, 14.99, 19.99, 29.99, 50, 99]) .range(["#ffffff", "#c7e9c0", "#a1d99b", "#74c476", "#31a353", "#006d2c", "#fffa8a", "#ffcc4f", "#fe8d3c", "#fc4e2a", "#d61a1c", "#ad0026", "#700026", "#3b0030", "#4c0073", "#ffdbff", "#ffdbff"]); var skyColorScale = d3.scaleThreshold() .domain([10, 20, 30, 40, 50, 60, 70, 80, 90, 100]) .range(["#24a0f2", "#4eb0f2", "#80b7f8", "#a0c8ff", "#d2e1ff", "#e1e1e1", "#c9c9c9", "#a5a5a5", "#6e6e6e", "#505050"]); var mixingHeightColorScale = d3.scaleThreshold() .domain([5, 15, 25, 100]) .range(['#ffffff', '#ffeda0', '#feb24c', '#f03b20'].reverse()); var hainesColorScale = d3.scaleThreshold() .domain([4, 5, 6, 7]) .range(['#ffffff', '#ffeda0', '#feb24c', '#f03b20']); var lalColorScale = d3.scaleThreshold() .domain([4, 5, 6, 7]) .range(['#ffffff', '#ffeda0', '#feb24c', '#f03b20']); var vsbyColorScale = d3.scaleThreshold() .domain([1, 3, 5, 10]) .range(['#ffffff', '#ffeda0', '#feb24c', '#f03b20'].reverse()); var hazColorScale = d3.scaleOrdinal() .domain(['-', 'Y', 'A', 'W']) .range(["#ffffff", "#ffff00", "FFAE00", "#ff0000"]); /** * Helper functions * */ function CtoF(c) { return Math.round(c * (9 / 5) + 32); } function m2mi(m) { return Math.round(m * 0.000621371); } function m2ft(ms) { return Math.round(ms * 3.28084); } function kttomph(kt) { return Math.round(kt * 1.15078); } function mstomph(ms) { return Math.round(ms * 2.23694); } function mstokt(ms) { return Math.round(ms * 1.94384); } function mmtoinsnow(mm) { return Number(mm * 0.0393701).toFixed(1); } function mmtoin(mm) { return Number(mm * 0.0393701).toFixed(2); } function none(val) { return Math.round(val); } function wx(val) { return val; } function getLayerByName(name) { var overlays = overlayGroup.getLayers().getArray(); for (var i = 0; i < overlays.length; i++) { if (name == overlays[i].get('title')) { return overlays[i]; }; } } function degToCompass(num) { var val = Math.floor((num / 22.5) + 0.5); var arr = ["N", "NNE", "NE", "ENE", "E", "ESE", "SE", "SSE", "S", "SSW", "SW", "WSW", "W", "WNW", "NW", "NNW"]; return arr[(val % 16)]; } function round10(x) { return Math.round(x / 10) * 10; } function round5(x) { return Math.ceil(x / 5) * 5; } /** * Go forward or backward programatically * */ document.onkeydown = checkKey; function goForward() { // if (window.ndfdTime.clone().add(1, 'hours').unix() >= new moment().add(168, 'hours').unix()) { // return; // } // updateNDFD(window.ndfdTime.add(1, 'hours'), window.ndfdField, window.label); } function goBack() { // if (window.ndfdTime.clone().add(-1, 'hours').unix() < new moment().add(-1, 'hours').unix()) { // return; // } // updateNDFD(window.ndfdTime.add(-1, 'hours'), window.ndfdField, window.label); } /** * Add keyboard bindings * */ function checkKey(e) { e = e || window.event; if (e.keyCode == '38') { // up arrow if (window.count > 0) { window.count--; } var newField = ndfdFields[window.count % ndfdFields.length]; updateNDFD(window.ndfdTime, newField, window.label); } else if (e.keyCode == '40') { // down arrow window.count++; var newField = ndfdFields[window.count % ndfdFields.length]; updateNDFD(window.ndfdTime, newField, window.label); } else if (e.keyCode == '37') { // left arrow goBack(); } else if (e.keyCode == '39') { // right arrow goForward(); } // e.preventDefault(); } window.layerrequests = 0; function addLoadingListeners(lyrSource) { lyrSource.on('imageloadstart', function (event) { // document.getElementById('throbber').style.display = 'block'; window.layerrequests++; d3.select('#throbber').style('visibility', 'visible'); d3.select('#layerrequests').html(window.layerrequests); }); lyrSource.on('imageloadend', function (event) { window.layerrequests--; d3.select('#throbber').style('visibility', 'visible'); d3.select('#layerrequests').html(window.layerrequests); if (window.layerrequests <= 0) { window.layerrequests = 0; d3.select('#throbber').style('visibility', 'hidden'); } }); lyrSource.on('imageloaderror', function (event) { window.layerrequests--; }); } function closePopup() { $.magnificPopup.close(); } function styles(styles) { return function (selection) { for (var property in styles) { selection.style(property, styles[property]); } }; } /** * Make the necessary calls to get the raw data from api.weather.gov * */ function getData(lat, lon) { window.lat = lat; window.lon = lon; var point = ol.proj.transform([lon, lat], 'EPSG:4326', 'EPSG:3857'); var feature = new ol.Feature( new ol.geom.Point(point) ); var iconStyle = new ol.style.Style({ image: new ol.style.Circle({ radius: 7, fill: new ol.style.Fill({ color: 'white' }), stroke: new ol.style.Stroke({ color: 'rgba(0,0,0,1)', width: 3 }) }) }); feature.setStyle(iconStyle); dotSource.clear(); dotSource.addFeature(feature); // Check values at a point d3.select("#container").selectAll("*").remove(); d3.select("#container").append("img").attr('src', "https://www.weather.gov/images/dlh/jonathan/ajax-loader.gif").attr('class', "centerImage"); d3.json("https://api.weather.gov/points/" + lat.toFixed(4) + ',' + lon.toFixed(4)).then(function (data) { if (data.properties.forecastGridData == null) { d3.select("#container").selectAll("*").remove(); d3.select("#container").insert("div").html("Severe Storm Tracker (9)
Data request did not return information for this point.").attr('class', 'warnings').style('text-align', 'center'); return; } var bearing = degToCompass(data.properties.relativeLocation.properties.bearing.value); var distance = m2mi(data.properties.relativeLocation.properties.distance.value); var city = data.properties.relativeLocation.properties.city; var state = data.properties.relativeLocation.properties.state; var location = distance + ' miles ' + bearing + ' of ' + city + ', ' + state; // Global window.zone = data.properties.forecastZone.split('/').slice(-1).pop(); d3.json(data.properties.forecastGridData).then(function (data) { // Clear out container d3.select("#container").selectAll("*").remove(); // Location d3.select("#container").insert("div", ":first-child").html('Sample Point Location:' + location); // AFD var forecastOffice = data.properties.forecastOffice.split('/').slice(-1).pop(); d3.select("#container").insert("div", ":first-child").attr('id', 'AFD') .html('' + forecastOffice + ' Forecast Discussion') .on('mousedown', function () { d3.json("https://api.weather.gov/products/types/afd/locations/" + forecastOffice.toLowerCase()).then(function (data) { d3.json(data['@graph'][0]["@id"]).then(function (data) { $.magnificPopup.open({ items: { src: '

' + data.productText.replace(/\n/g, '
') + '

', type: 'inline' }, modal: true, closeBtnInside: true }); }); setTimeout(function () { d3.select('.mfp-content').on('click', function () { $.magnificPopup.close(); }); }, 1000); }); }); // Back / Forward // d3.select("#container").insert("div", ":first-child").call(styles({ // 'text-align': 'right', // position: 'relative', // top: '18px', // height: '0px' // })).html(''); // d3.select("#container").insert("div", ":first-child").attr('id', 'TextForecast').html('Click for Text Forecast'); // Update table valid time var age = moment.duration(new moment().diff(new moment(data.properties.updateTime))).asMinutes().toFixed(0); var age_color = 'red'; if (age < 300) { age_color = 'green'; } // Table update // d3.select("#container").insert("div", ":first-child").attr('id', 'validTime').style('color', age_color).style('font-weight', "bold").html('Table updated: ' + new moment(data.properties.updateTime).tz(moment.tz.guess()).format('hmm a z ddd. M/D/Y') + ' (Last Update: ' + age + ' minutes ago)'); // Short fused d3.select("#ActiveWarnings").remove("*"); d3.json("https://api.weather.gov/alerts/active?point=" + lat + ',' + lon).then(function (data) { data.features.forEach(function (obj) { // Check to see if the alert is valid for the zone at the point // var found = false; // obj.properties.affectedZones.forEach(function(zone_str) { // if (window.zone == zone_str.split('/').slice(-1).pop()) { // found = true; // } // }); // // if (!found) { // return; // } var fromDate = new moment(obj.properties.onset); var from = fromDate.tz(moment.tz.guess()).format('hmm a z ddd. M/D/Y'); if (obj.properties.ends == null) { var to = new moment(obj.properties.expires).tz(moment.tz.guess()).format('hmm a z ddd. M/D/Y'); } else { var to = new moment(obj.properties.ends).tz(moment.tz.guess()).format('hmm a z ddd. M/D/Y'); } if (obj.properties.event.indexOf('Severe') !== -1 || obj.properties.event.indexOf('Tornado') !== -1 || obj.properties.event.indexOf('Special') !== -1 || obj.properties.event.indexOf('Flash') !== -1) { if (fromDate.unix() <= new moment().unix()) { d3.select("#container").insert("div", ":first-child").attr('id', 'ActiveWarnings').attr('class', "warnings").html(obj.properties.event + ' in effect until ' + to) .on('mousedown', function () { $.magnificPopup.open({ items: { src: '

' + obj.properties.description.replace(/\n/g, '
') + '

', type: 'inline' }, modal: true, closeBtnInside: true }); // Wait a smidge to render before adding close listener setTimeout(function () { d3.select('.mfp-content').on('click', function () { $.magnificPopup.close(); }); }, 1000); }); } else { d3.select("#container").insert("div", ":first-child").attr('id', 'ActiveWarnings').attr('class', "warnings").html(obj.properties.event + ' from ' + from + ' to ' + to) .on('mousedown', function () { $.magnificPopup.open({ items: { src: '

' + obj.properties.description.replace(/\n/g, '
') + '

', type: 'inline' }, modal: true, closeBtnInside: true }); // Wait a smidge to render before adding close listener setTimeout(function () { d3.select('.mfp-content').on('click', function () { $.magnificPopup.close(); }); }, 1000); }); } } }); }); }); }).catch(function (error) { // Could not find data :-() d3.select("#container").selectAll("*").remove(); d3.select("#container").insert("div").html("Severe Storm Tracker (10)
Unable to provide data for requested point").attr('class', 'warnings').style('text-align', 'center'); return; }); } // Convert a hexadecimal number to rgba (allows to apply opacity) function convertHex(hex, opacity) { hex = hex.replace('#', ''); var r = parseInt(hex.substring(0, 2), 16); var g = parseInt(hex.substring(2, 4), 16); var b = parseInt(hex.substring(4, 6), 16); var result = 'rgba(' + r + ',' + g + ',' + b + ',' + opacity / 100 + ')'; return result; } // Auto refresh setInterval(function () { getData(window.lat, window.lon); }, 1000 * 60 * 60); setInterval(function () { // getData(window.lat, window.lon); updateRadar(); // updateLightning(); updateObservations(); updateLsrs(); }, 1000 * 60 * 2); setInterval(function () { updateHazards(); }, 1000 * 20); window.radarIndex = 0; window.radarFrames = 20; window.radartimer = { running: false, iv: 5000, timeout: false, cb: function () { }, start: function (cb, iv) { var elm = this; clearInterval(this.timeout); this.running = true; if (cb) this.cb = cb; if (iv) this.iv = iv; this.timeout = setTimeout(function () { elm.execute(elm); }, this.iv); }, execute: function (e) { if (!e.running) return false; e.cb(); e.start(); }, stop: function () { this.running = false; }, set_interval: function (iv) { clearInterval(this.timeout); this.start(false, iv); } }; var findClosest = function (x, arr) { var indexArr = arr.map(function (k) { return Math.abs(k - x) }) var min = Math.min.apply(Math, indexArr) return arr[indexArr.indexOf(min)] } // setInterval(function() { // // window.radarSourceArray window.radartimer.start(function () { Object.keys(window.radarSourceArray).sort().forEach(function (obj, index) { if (window.radarIndex % window.radarFrames == index) { var radarLayer = getLayerByName('Radar'); radarLayer.setSource(window.radarSourceArray[obj]); // Handle Lightning // var lightningLayer = getLayerByName('Lightning Density'); // if (lightningLayer.getVisible()) { // var closest_index = findClosest(obj, Object.keys(window.lightningSourceArray)); // // console.log('Closest is:', new moment(Number(closest_index)).format('hmm a z ddd. M/D/Y') + ' for '+ new moment(Number(obj)).format('hmm a z ddd. M/D/Y')); // d3.select('#lightningtime').text(new moment(Number(closest_index)).format('hmm a z ddd. M/D/Y')); // lightningLayer.setSource(window.lightningSourceArray[closest_index]); // } // console.log(new moment(Number(obj)).format('hmm a z ddd. M/D/Y')); d3.select("#radartime").html('Radar valid at: ' + new moment(obj).format('hmm a z ddd. M/D/Y')); d3.select("#radartimelegend").html(new moment(obj).format('hmm a z ddd. M/D/Y')); //.classed('shadowme',true); } }); if (window.radarIndex % window.radarFrames == window.radarFrames - 1) { window.radartimer.set_interval(1500); } else { window.radartimer.set_interval(100); } window.radarIndex++; }, 300); if (!activateLayers.includes('Radar'.replace(/\W/g, ''))) { window.radartimer.stop(); } // timer.set_interval(500); // }, 300); // Clear out cache every hour so newest forecast data appears setInterval(function () { window.gridsources = {}; }, 1000 * 60 * 60); // Get your data for the original lat/lon getData(window.lat, window.lon); // function updateLightning() { // d3.json("https://nowcoast.noaa.gov/layerinfo?request=timestops&service=sat_meteo_emulated_imagery_lightningstrikedensity_goes_time&layers=3&format=json").then(function(data) { // data.layers[0].timeStops.forEach(function(obj, index) { // // Add a layer // if (!window.lightningSourceArray.hasOwnProperty(obj)) { // var wms_time = new moment(obj).utc().format(); // window.lightningSourceArray[obj] = new ol.source.ImageStatic({ // url: 'https://nowcoast.noaa.gov/arcgis/services/nowcoast/sat_meteo_emulated_imagery_lightningstrikedensity_goes_time/MapServer/WMSServer?SERVICE=WMS&VERSION=1.3.0&REQUEST=GetMap&FORMAT=image%2Fpng&TRANSPARENT=true&LAYERS=1&CRS=EPSG%3A3857&STYLES=' + '&WIDTH=' + ndfdWMSwidth * 6 + '&HEIGHT=' + ndfdWMSheight * 6 + '&BBOX=' + window.imageExtent.toString() + '&time=' + wms_time, // imageExtent: window.imageExtent // }); // addLoadingListeners(window.lightningSourceArray[obj]); // } // }); // // remove Old // while (Object.keys(window.lightningSourceArray).length > window.radarFrames - 1) { // var firstKey = Object.keys(window.lightningSourceArray).sort()[0]; // if (typeof firstKey !== "undefined") { // window.lightningSourceArray[firstKey] = null; // delete window.lightningSourceArray[firstKey]; // } else { // // Probably an empty object // break; // } // } // }); // } async function checkForRadarTimes(url) { var GetCaps = new ol.format.WMSCapabilities(); // debugger; var times = await fetch(url).then(function (response) { return response.text(); }).then(function (text) { var result = GetCaps.read(text); console.log(result); var times = result.Capability.Layer.Layer[0].Dimension; times[0].values.split(',').forEach(function (obj, index) { // Add a layer if (!window.radarSourceArray.hasOwnProperty(obj)) { var wms_time = new moment(obj).utc().format(); window.radarSourceArray[obj] = new ol.source.ImageStatic({ url: window.radarService + '?SERVICE=WMS&VERSION=1.3.0&REQUEST=GetMap&FORMAT=image%2Fpng&TRANSPARENT=true&LAYERS=conus_bref_qcd&CRS=EPSG%3A3857&STYLES=' + '&WIDTH=' + ndfdWMSwidth * 6 + '&HEIGHT=' + ndfdWMSheight * 6 + '&BBOX=' + window.imageExtent.toString() + '&time=' + wms_time, imageExtent: window.imageExtent }); addLoadingListeners(window.radarSourceArray[obj]); } }); // remove Old while (Object.keys(window.radarSourceArray).length > window.radarFrames - 1) { var firstKey = Object.keys(window.radarSourceArray).sort()[0]; if (typeof firstKey !== "undefined") { window.radarSourceArray[firstKey] = null; delete window.radarSourceArray[firstKey]; } else { // Probably an empty object break; } } }); } function updateRadar() { checkForRadarTimes(window.radarService + '?SERVICE=WMS&VERSION=1.3.0&REQUEST=GetCapabilities'); } // function updateRadar() { // d3.json("https://nowcoast.noaa.gov/layerinfo?request=timestops&service=radar_meteo_imagery_nexrad_time&layers=3&format=json").then(function(data) { // data.layers[0].timeStops.slice(-1 * window.radarFrames).forEach(function(obj, index) { // // Add a layer // if (!window.radarSourceArray.hasOwnProperty(obj)) { // var wms_time = new moment(obj).utc().format(); // window.radarSourceArray[obj] = new ol.source.ImageStatic({ // url: 'https://nowcoast.noaa.gov/arcgis/services/nowcoast/radar_meteo_imagery_nexrad_time/MapServer/WMSServer?SERVICE=WMS&VERSION=1.3.0&REQUEST=GetMap&FORMAT=image%2Fpng&TRANSPARENT=true&LAYERS=1&CRS=EPSG%3A3857&STYLES=' + '&WIDTH=' + ndfdWMSwidth * 6 + '&HEIGHT=' + ndfdWMSheight * 6 + '&BBOX=' + window.imageExtent.toString() + '&time=' + wms_time, // imageExtent: window.imageExtent // }); // addLoadingListeners(window.radarSourceArray[obj]); // } // }); // // remove Old // while (Object.keys(window.radarSourceArray).length > window.radarFrames - 1) { // var firstKey = Object.keys(window.radarSourceArray).sort()[0]; // if (typeof firstKey !== "undefined") { // window.radarSourceArray[firstKey] = null; // delete window.radarSourceArray[firstKey]; // } else { // // Probably an empty object // break; // } // } // }); // } // d3.json("https://api.mesowest.net/v2/stations/latest?&bbox="+ ol.proj.transformExtent(window.imageExtent, ol.proj.get('EPSG:3857'), ol.proj.get('EPSG:4326'))+"&network=1,14,96&within=60&varoperator=or&status=active&output=geojson&units=temp|F,speed|mph,precip|in,pres|mb,height|ft,alti|inhg&token=a13f6d0a32c842e6815c377e77a64e99").then(function(data) { // console.log(data); // }) function updateObservations() { window.gridsources['obs'] = new ol.source.Vector({ url: "https://api.mesowest.net/v2/stations/latest?&bbox=" + ol.proj.transformExtent(window.imageExtent, ol.proj.get('EPSG:3857'), ol.proj.get('EPSG:4326')) + "&network=1,14,96&within=60&varoperator=or&status=active&output=geojson&units=temp|F,speed|kt,precip|in,pres|mb,height|ft,alti|inhg&token=a13f6d0a32c842e6815c377e77a64e99", format: new ol.format.GeoJSON() }); obLayer.setSource(window.gridsources['obs']); } updateObservations(); function updateHazards() { window.gridsources['hazards'] = new ol.source.Vector({ url: 'https://api.weather.gov/alerts?active=true&event=Flash%20Flood%20Warning,Severe%20Thunderstorm%20Warning,Tornado%20Warning,Special%20Marine%20Warning,Special%20Weather%20Statement,Severe%20Thunderstorm%20Watch,Tornado%20Watch,Flash%20Flood%20Watch', //'https://api.weather.gov/alerts/active', format: new ol.format.GeoJSON() }); hazardLayer.setSource(window.gridsources['hazards']); // Future OL3 release //window.gridsources['hazards'].refresh(); } updateHazards(); var hoverInteraction = new ol.interaction.Select({ condition: ol.events.condition.pointerMove, layers: [obLayer, dotLayer, hazardLayer, lsrLayer] }); map.addInteraction(hoverInteraction); var popup = new Popup({ autoPan: false }); map.addOverlay(popup); function applySentenceCase(str) { return str.replace(/.+?[\.\?\!](\s|$)/g, function (txt) { return txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase(); }); } function displayPopup(e) { if (e.dragging) return; var pixel = map.getEventPixel(e.originalEvent); var hit = map.hasFeatureAtPixel(pixel); map.forEachFeatureAtPixel(pixel, function (feature, layer) { if (layer == null) { return; } if (layer.get('title') == "Observations" || layer.get('title') == "Sample Point" || layer.get('title') == "Hazards" || layer.get('title') == "Storm Reports") { //continue; } else { return; } var el = document.createElement("div"); var title = document.createElement("p"); el.appendChild(title); var content = document.createElement("p"); el.appendChild(content); if (feature == hoverInteraction.getFeatures().getArray()[0]) { if (layer.get('title') == "Observations") { title.innerHTML = '' + feature.get('name') + ''; var html = ''; var obtime = typeof (feature.get('date_time')) !== "undefined" ? new moment(feature.get('date_time')).format('hmm a z ddd. M/D/Y') : ''; var waveheight = typeof (feature.get('wave_height')) !== "undefined" ? feature.get('wave_height').toFixed(0) : ''; var waveperiod = typeof (feature.get('wave_period')) !== "undefined" ? feature.get('wave_period').toFixed(0) : ''; var slp = typeof (feature.get('sea_level_pressure_d')) !== "undefined" ? feature.get('sea_level_pressure_d').toFixed(0) : ''; var winddir = typeof (feature.get('wind_cardinal_direction_d')) !== "undefined" ? feature.get('wind_cardinal_direction_d') : ''; var wind = typeof (feature.get('wind_speed')) !== "undefined" ? feature.get('wind_speed').toFixed(0) : ''; var gust = typeof (feature.get('wind_gust')) !== "undefined" ? 'G' + feature.get('wind_gust').toFixed(0) : ''; var t = typeof (feature.get('air_temp')) !== "undefined" ? feature.get('air_temp').toFixed(0) : ''; var td = typeof (feature.get('dew_point_temperature')) !== "undefined" ? feature.get('dew_point_temperature').toFixed(0) : ''; var age = moment.duration(new moment().diff(new moment(feature.get('date_time')))).asMinutes().toFixed(0); if (age < 300) { html += 'Ob Time: '; } else { html += 'Ob Time: '; } html += obtime + '
'; if (waveheight != '') { html += 'Wave Height: ' + waveheight + ' ft
'; html += 'Wave Period: ' + waveperiod + ' sec
'; } html += 'Wind: ' + winddir + ' ' + wind + gust + ' kt
'; if (slp != '') { html += 'Pressure: ' + slp + ' mb
'; } if (t != '') { html += 'Temperature: ' + t + ' F
'; } if (td != '') { html += 'Dew pont: ' + td + ' F
'; } content.innerHTML = html; } else if (layer.get('title') == "Sample Point") { content.innerHTML = 'Sample Point...'; } else if (layer.get('title') == "Storm Reports") { var html = '' + feature.get('typetext') + ' ' + feature.get('magnitude') + ((feature.get('typetext') == "HAIL") ? '"' : (feature.get('typetext').indexOf("WIND") !== -1) ? ' kt' : ''); html += '
Reported at: ' + new moment(feature.get('valid')).format('hmm a z ddd. M/D/Y'); html += '
Location: ' + feature.get('city') + ', ' + feature.get('st'); html += '
Remarks: ' + applySentenceCase(feature.get('remark').toLowerCase()); content.innerHTML = html; } else if (layer.get('title') == "Hazards") { var text = '

' + feature.get('headline') + '

'; text += feature.get('description').replace(/(?:\r\n|\r|\n)/g, '
') text += '

'; if (feature.get('instruction') != null) { text += feature.get('instruction').replace(/(?:\r\n|\r|\n)/g, '
'); } // d3.select('#hazardtext').selectAll("*").remove(); // d3.select('#hazardtext').append('div').html(text); d3.select('#hazardtext').transition() .duration(0) .style('opacity', 0) .on("end", function () { d3.select(this) .html(text) .transition() .duration(0) .style('opacity', 1); }); var sent = new moment(feature.get('sent')).tz(moment.tz.guess()).format('hmm a z ddd. M/D/Y'); var expires = new moment(feature.get('expires')).tz(moment.tz.guess()).format('hmm a z ddd. M/D/Y'); var tornadoDetection = feature.get('parameters').tornadoDetection; var hailSize = feature.get('parameters').hailSize; var windGust = feature.get('parameters').windGust; var hazpopup = '' + feature.get('event') + '
'; if (typeof (feature.get('parameters')["NWSheadline"]) !== "undefined" && feature.get('parameters')["NWSheadline"][0].indexOf('EMERGENCY') !== -1) { hazpopup += '
This is an EMERGENCY
'; } if (typeof tornadoDetection !== "undefined") { hazpopup += '

Tornado: ' + tornadoDetection[0].charAt(0).toUpperCase() + tornadoDetection[0].slice(1).toLowerCase() + '
'; } if (typeof windGust !== "undefined") { hazpopup += 'Wind Gust: ' + windGust[0].toLowerCase() + '
'; } if (typeof hailSize !== "undefined") { hazpopup += 'Hail Size: ' + hailSize + '"
'; } // speed / dir try { var str = feature.get('parameters').eventMotionDescription[0]; var re = /(\d+)DEG\.{3}(\d+)KT/g; var match = re.exec(str); var direction = match[1]; var speed = kttomph(Number(match[2])); var heading = (Number(direction) + 180 > 360) ? Number(direction) + 180 - 360 : Number(direction) + 180; var heading_cardinal = degToCompass(heading); hazpopup += 'Storm moving: ' + heading_cardinal + ' at ' + speed + ' mph Severe Storm Tracker (11)
'; } catch (e) { // issue with decoding... } hazpopup += '

'; hazpopup += ''; hazpopup += '
Issued: ' + sent + '
Expires: ' + expires + '

'; hazpopup += 'Issued by: ' + feature.get('senderName') + ''; content.innerHTML = hazpopup; } popup.show(e.coordinate, el); } }); if (!hit) { popup.hide(); } } map.on('pointermove', function (e) { displayPopup(e); }); // Observations var styleCacheObLayer = {}; obLayer.setStyle(function style(f, resolution) { var wind, winddir, waveheight, age; var obtime = typeof (f.get('date_time')) !== "undefined" ? new moment.utc(f.get('date_time')).local().format('hmm a z ddd. M/D/Y') : ''; var age = moment.duration(new moment().diff(new moment.utc(f.get('date_time')))).asMinutes(); var t = f.get('air_temp'); var t = typeof (t) !== "undefined" ? t.toFixed(0) : ''; var wd = f.get('wind_direction'); var winddir = typeof (wd) !== "undefined" ? wd : ''; var wff = f.get('wind_speed'); var wind = typeof (wff) !== "undefined" ? wff.toFixed(0) : ''; var wfg = f.get('wind_gust'); var gust = typeof (wfg) !== "undefined" ? wfg.toFixed(0) : ''; var svgstring = plotWind(winddir, Number(wind), t, age, gust); var style = styleCacheObLayer[svgstring]; if (!style) { styleCacheObLayer[svgstring] = new ol.style.Style({ image: new ol.style.Icon({ src: 'data:image/svg+xml;charset=utf-8,' + encodeURIComponent(svgstring) }) }); } return styleCacheObLayer[svgstring]; }); /** * Bookmark * */ function bookmark() { var url = document.location.href; if (url.indexOf("?") > -1) { url = url.substr(0, url.indexOf("?")); } url = url.replace('#', ''); var zoom = map.getView().getZoom(); var center = ol.proj.transform(map.getView().getCenter(), 'EPSG:3857', 'EPSG:4326'); // var overlayToggle = ''; // overlayGroup.get('layers').getArray().forEach(function(obj) { // overlayToggle += obj.getVisible() ? 'T' : 'F'; // }); // Special method to grab layer names for bookmark var layerstring = ''; map.getLayers().getArray().forEach(function (obj, index) { if (index > 0) { obj.getLayersArray().forEach(function (obj2) { if (obj2.getVisible()) { layerstring += obj2.get('title').replace(/\W/g, '') + '|'; } }) } }) var params = '?lat=' + window.lat.toFixed(3); params += '&lon=' + window.lon.toFixed(3); params += '&clat=' + center[1].toFixed(3); params += '&clon=' + center[0].toFixed(3); params += '&zoom=' + zoom; // slim down url var x = 0; var len = window.imageExtent.length; while (x < len) { window.imageExtent[x] = Math.round(window.imageExtent[x] * 1000) / 1000; x++; } params += '&bbox=' + JSON.stringify(window.imageExtent); params += '&layers=' + layerstring; url += params; history.pushState(null, null, url); $.magnificPopup.open({ items: { // src: '

' + data.response.data.entry[0].short_url + '

', src: '

', type: 'inline' }, modal: true, closeBtnInside: true }); // d3.json("https://go.usa.gov/api/shorten.jsonp?login=edd&apiKey=4429d50bf53eb88bf65d9ff7507c9f1f&longUrl=" + encodeURIComponent(url)).then(function(data) { // $.magnificPopup.open({ // items: { // src: '

' + data.response.data.entry[0].short_url + '

', // type: 'inline' // }, // modal: true, // closeBtnInside: true // }); // }); } function copyTextToClipboard() { /* Get the text field */ var copyText = document.getElementById("bookmarkurl"); /* Select the text field */ copyText.select(); copyText.setSelectionRange(0, 99999); /* For mobile devices */ /* Copy the text inside the text field */ navigator.clipboard.writeText(copyText.value); } function changeDomain() { window.gridsources = {}; window.imageExtent = map.getView().calculateExtent(); goForward(); window.radarSourceArray = null; window.radarSourceArray = {}; window.lightningSourceArray = null; window.lightningSourceArray = {}; updateRadar(); // updateLightning(); updateObservations(); updateWMSforExtent(); // updateCO(); make_domain(); // getData(window.lat, window.lon); $.notify("Your domain has been changed", "success"); } if (localStorageAvailable()) { if (localStorage.DoNotShowMessageAgain && localStorage.DoNotShowMessageAgain === "true") { // user doesn't want to see the message again, so handle accordingly } else { //moreinfo(); } }; // For image times function moreinfo() { $.magnificPopup.open({ items: { src: '

' + help_text + '

', type: 'inline' }, modal: true, closeBtnInside: true }); // setTimeout(function() { // d3.select('.mfp-content').on('click', function() { // $.magnificPopup.close(); // }); // }, 1000); } function localStorageAvailable() { if (typeof (Storage) !== "undefined") { return true; } else { return false; } } $('#showagain').click(function () { if ($('#showagain').prop("checked")) { if (localStorageAvailable()) localStorage.DoNotShowMessageAgain = "true"; } }) hazColor = { "Tsunami Warning": { "Priority": 1, "Color": "#FD6347" }, "Tornado Warning": { "Priority": 2, "Color": "#FF0000" }, "Extreme Wind Warning": { "Priority": 3, "Color": "#FF8C00" }, "Severe Thunderstorm Warning": { "Priority": 4, "Color": "#FFA500", "Color2": "#FFFF00", }, "Flash Flood Warning": { "Priority": 5, "Color": "#8B0000", "Color2": "#54FF00", }, "Flash Flood Statement": { "Priority": 6, "Color": "#8B0000" }, "Severe Weather Statement": { "Priority": 7, "Color": "#00FFFF" }, "Shelter In Place Warning": { "Priority": 8, "Color": "#FA8072" }, "Evacuation - Immediate": { "Priority": 9, "Color": "#7FFF00" }, "Civil Danger Warning": { "Priority": 10, "Color": "#FFB6C1" }, "Nuclear Power Plant Warning": { "Priority": 11, "Color": "#4B0082" }, "Radiological Hazard Warning": { "Priority": 12, "Color": "#4B0082" }, "Hazardous Materials Warning": { "Priority": 13, "Color": "#4B0082" }, "Fire Warning": { "Priority": 14, "Color": "#A0522D" }, "Civil Emergency Message": { "Priority": 15, "Color": "#FFB6C1" }, "Law Enforcement Warning": { "Priority": 16, "Color": "#C0C0C0" }, "Storm Surge Warning": { "Priority": 17, "Color": "#B524F7" }, "Hurricane Force Wind Warning": { "Priority": 18, "Color": "#CD5C5C" }, "Hurricane Warning": { "Priority": 19, "Color": "#DC143C" }, "Typhoon Warning": { "Priority": 20, "Color": "#DC143C" }, "Special Marine Warning": { "Priority": 21, "Color": "#FFA500", "Color2": "#00FFFC" }, "Blizzard Warning": { "Priority": 22, "Color": "#FF4500" }, "Snow Squall Warning": { "Priority": 23, "Color": "#C71585" }, "Ice Storm Warning": { "Priority": 24, "Color": "#8B008B" }, "Winter Storm Warning": { "Priority": 25, "Color": "#FF69B4" }, "High Wind Warning": { "Priority": 26, "Color": "#DAA520" }, "Tropical Storm Warning": { "Priority": 27, "Color": "#B22222" }, "Storm Warning": { "Priority": 28, "Color": "#9400D3" }, "Tsunami Advisory": { "Priority": 29, "Color": "#D2691E" }, "Tsunami Watch": { "Priority": 30, "Color": "#FF00FF" }, "Avalanche Warning": { "Priority": 31, "Color": "#1E90FF" }, "Earthquake Warning": { "Priority": 32, "Color": "#8B4513" }, "Volcano Warning": { "Priority": 33, "Color": "#2F4F4F" }, "Ashfall Warning": { "Priority": 34, "Color": "#A9A9A9" }, "Coastal Flood Warning": { "Priority": 35, "Color": "#228B22" }, "Lakeshore Flood Warning": { "Priority": 36, "Color": "#228B22" }, "Flood Warning": { "Priority": 37, "Color": "#00FF00" }, "High Surf Warning": { "Priority": 38, "Color": "#228B22" }, "Dust Storm Warning": { "Priority": 39, "Color": "#FFE4C4" }, "Blowing Dust Warning": { "Priority": 40, "Color": "#FFE4C4" }, "Lake Effect Snow Warning": { "Priority": 41, "Color": "#008B8B" }, "Excessive Heat Warning": { "Priority": 42, "Color": "#C71585" }, "Tornado Watch": { "Priority": 43, "Color": "#FFFF00" }, "Severe Thunderstorm Watch": { "Priority": 44, "Color": "#DB7093" }, "Flash Flood Watch": { "Priority": 45, "Color": "#2E8B57" }, "Gale Warning": { "Priority": 46, "Color": "#DDA0DD" }, "Flood Statement": { "Priority": 47, "Color": "#00FF00" }, "Wind Chill Warning": { "Priority": 48, "Color": "#B0C4DE" }, "Extreme Cold Warning": { "Priority": 49, "Color": "#0000FF" }, "Hard Freeze Warning": { "Priority": 50, "Color": "#9400D3" }, "Freeze Warning": { "Priority": 51, "Color": "#483D8B" }, "Red Flag Warning": { "Priority": 52, "Color": "#FF1493" }, "Storm Surge Watch": { "Priority": 53, "Color": "#DB7FF7" }, "Hurricane Watch": { "Priority": 54, "Color": "#FF00FF" }, "Hurricane Force Wind Watch": { "Priority": 55, "Color": "#9932CC" }, "Typhoon Watch": { "Priority": 56, "Color": "#FF00FF" }, "Tropical Storm Watch": { "Priority": 57, "Color": "#F08080" }, "Storm Watch": { "Priority": 58, "Color": "#FFE4B5" }, "Hurricane Local Statement": { "Priority": 59, "Color": "#FFE4B5" }, "Typhoon Local Statement": { "Priority": 60, "Color": "#FFE4B5" }, "Tropical Storm Local Statement": { "Priority": 61, "Color": "#FFE4B5" }, "Tropical Depression Local Statement": { "Priority": 62, "Color": "#FFE4B5" }, "Avalanche Advisory": { "Priority": 63, "Color": "#CD853F" }, "Freezing Rain Advisory": { "Priority": 64, "Color": "#DA70D6" }, "Winter Weather Advisory": { "Priority": 65, "Color": "#7B68EE" }, "Lake Effect Snow Advisory": { "Priority": 66, "Color": "#48D1CC" }, "Wind Chill Advisory": { "Priority": 67, "Color": "#AFEEEE" }, "Heat Advisory": { "Priority": 68, "Color": "#FF7F50" }, "Urban And Small Stream Flood Advisory": { "Priority": 69, "Color": "#00FF7F" }, "Small Stream Flood Advisory": { "Priority": 70, "Color": "#00FF7F" }, "Arroyo And Small Stream Flood Advisory": { "Priority": 71, "Color": "#00FF7F" }, "Flood Advisory": { "Priority": 72, "Color": "#00FF7F" }, "Hydrologic Advisory": { "Priority": 73, "Color": "#00FF7F" }, "Lakeshore Flood Advisory": { "Priority": 74, "Color": "#7CFC00" }, "Coastal Flood Advisory": { "Priority": 75, "Color": "#7CFC00" }, "High Surf Advisory": { "Priority": 76, "Color": "#BA55D3" }, "Heavy Freezing Spray Warning": { "Priority": 77, "Color": "#00BFFF" }, "Dense Fog Advisory": { "Priority": 78, "Color": 708090 }, "Dense Smoke Advisory": { "Priority": 79, "Color": "#F0E68C" }, "Small Craft Advisory For Hazardous Seas": { "Priority": 80, "Color": "#D8BFD8" }, "Small Craft Advisory For Rough Bar": { "Priority": 81, "Color": "#D8BFD8" }, "Small Craft Advisory For Winds": { "Priority": 82, "Color": "#D8BFD8" }, "Small Craft Advisory": { "Priority": 83, "Color": "#D8BFD8" }, "Brisk Wind Advisory": { "Priority": 84, "Color": "#D8BFD8" }, "Hazardous Seas Warning": { "Priority": 85, "Color": "#D8BFD8" }, "Dust Advisory": { "Priority": 86, "Color": "#BDB76B" }, "Blowing Dust Advisory": { "Priority": 87, "Color": "#BDB76B" }, "Lake Wind Advisory": { "Priority": 88, "Color": "#D2B48C" }, "Wind Advisory": { "Priority": 89, "Color": "#D2B48C" }, "Frost Advisory": { "Priority": 90, "Color": "#6495ED" }, "Ashfall Advisory": { "Priority": 91, "Color": 696969 }, "Freezing Fog Advisory": { "Priority": 92, "Color": 8080 }, "Freezing Spray Advisory": { "Priority": 93, "Color": "#00BFFF" }, "Low Water Advisory": { "Priority": 94, "Color": "#A52A2A" }, "Local Area Emergency": { "Priority": 95, "Color": "#C0C0C0" }, "Child Abduction Emergency": { "Priority": 96, "Color": "#FFD700" }, "Avalanche Watch": { "Priority": 97, "Color": "#F4A460" }, "Blizzard Watch": { "Priority": 98, "Color": "#ADFF2F" }, "Rip Current Statement": { "Priority": 99, "Color": "#40E0D0" }, "Beach Hazards Statement": { "Priority": 100, "Color": "#40E0D0" }, "Gale Watch": { "Priority": 101, "Color": "#FFC0CB" }, "Winter Storm Watch": { "Priority": 102, "Color": "#4682B4" }, "Hazardous Seas Watch": { "Priority": 103, "Color": "#483D8B" }, "Heavy Freezing Spray Watch": { "Priority": 104, "Color": "#BC8F8F" }, "Coastal Flood Watch": { "Priority": 105, "Color": "#66CDAA" }, "Lakeshore Flood Watch": { "Priority": 106, "Color": "#66CDAA" }, "Flood Watch": { "Priority": 107, "Color": "#2E8B57" }, "High Wind Watch": { "Priority": 108, "Color": "#B8860B" }, "Excessive Heat Watch": { "Priority": 109, "Color": 800000 }, "Extreme Cold Watch": { "Priority": 110, "Color": "#0000FF" }, "Wind Chill Watch": { "Priority": 111, "Color": "#5F9EA0" }, "Lake Effect Snow Watch": { "Priority": 112, "Color": "#87CEFA" }, "Hard Freeze Watch": { "Priority": 113, "Color": 41700 }, "Freeze Watch": { "Priority": 114, "Color": "#00FFFF" }, "Fire Weather Watch": { "Priority": 115, "Color": "#FFDEAD" }, "Extreme Fire Danger": { "Priority": 116, "Color": "#E9967A" }, "911 Telephone Outage": { "Priority": 117, "Color": "#C0C0C0" }, "Coastal Flood Statement": { "Priority": 118, "Color": "#6B8E23" }, "Lakeshore Flood Statement": { "Priority": 119, "Color": "#6B8E23" }, "Special Weather Statement": { "Priority": 120, "Color": "#FFE4B5" }, "Marine Weather Statement": { "Priority": 121, "Color": "#FFDAB9" }, "Air Quality Alert": { "Priority": 122, "Color": 808080 }, "Air Stagnation Advisory": { "Priority": 123, "Color": 808080 }, "Hazardous Weather Outlook": { "Priority": 124, "Color": "#EEE8AA" }, "Hydrologic Outlook": { "Priority": 125, "Color": "#90EE90" }, "Short Term Forecast": { "Priority": 126, "Color": "#98FB98" }, "Administrative Message": { "Priority": 127, "Color": "#C0C0C0" }, "Test": { "Priority": 128, "Color": "#F0FFFF" } }; function ibw() { d3.select("#ibw").style("background-color", 'rgba(134, 134, 134, 0.5)').style('border-radius', '30px').style('margin', '8px'); //Make an SVG Container var svgContainer = d3.select("#ibw").append("svg") .attr("width", 320) .attr("height", 400); var fx = 100; var svry = 80; var tory = 150; var ltgy = 220; var marine = "#56d1ff"; var flash = "#7CFF2B"; var textLabels = svgContainer.append("text") .attr("x", 70) .attr("y", 30) .text("Hazard Legend") .attr("font-family", "auto") .attr("font-size", "26px") .attr("fill", "white"); // WARNINGS fx = fx + 0; // Warning Label var textLabels = svgContainer.append("text") .attr("x", fx - 20) .attr("y", 50) .text("Warning") .attr("font-family", "sans-serif") .attr("font-size", "12px") .attr("fill", "#dcdcdc"); var textLabels = svgContainer.append("text") .attr("x", fx - 25) .attr("y", tory - 30) .text("Warning") .attr("font-family", "sans-serif") .attr("font-size", "12px") .attr("fill", "#dcdcdc"); var textLabels = svgContainer.append("text") .attr("x", fx - 25) .attr("y", ltgy - 30) .text("Warning") .attr("font-family", "sans-serif") .attr("font-size", "12px") .attr("fill", "#dcdcdc"); // SVR Warning var circle = svgContainer.append("circle") .attr("cx", fx) .attr("cy", svry) .attr("r", 20) .attr("fill-opacity", 0.2) .attr("fill", "yellow") .attr('color', 'yellow') .attr("stroke-width", 7) .attr("stroke", "black"); // SVR Warning var circle = svgContainer.append("circle") .attr("cx", fx) .attr("cy", svry) .attr("r", 20) .attr("fill", "none") .attr('color', 'yellow') .attr("stroke-width", 4) //.attr("stroke-dasharray", "20, 5") .attr("stroke", "yellow"); // Tornado Warning var circle = svgContainer.append("circle") .attr("cx", fx) .attr("cy", tory) .attr("r", 20) .attr("fill-opacity", 0.2) .attr("fill", "red") .attr('color', 'red') .attr("stroke-width", 7) .attr("stroke", "black"); // Tornado Warning var circle = svgContainer.append("circle") .attr("cx", fx) .attr("cy", tory) .attr("r", 20) .attr("fill", "none") .attr('color', 'yellow') .attr("stroke-width", 4) //.attr("stroke-dasharray", "20, 5") .attr("stroke", "red"); // Flash Flood Warning var circle = svgContainer.append("circle") .attr("cx", fx) .attr("cy", ltgy) .attr("r", 20) .attr("fill-opacity", 0.2) .attr("fill", flash) .attr('color', flash) .attr("stroke-width", 7) .attr("stroke", "black"); // Flash Flood Warning var circle = svgContainer.append("circle") .attr("cx", fx) .attr("cy", ltgy) .attr("r", 20) .attr("fill", "none") .attr('color', 'yellow') .attr("stroke-width", 4) //.attr("stroke-dasharray", "20, 5") .attr("stroke", flash); fx = fx + 80; // SVR EXTREME // Extreme Label var textLabels = svgContainer.append("text") .attr("x", fx - 24) .attr("y", 50) .text("Extreme") .attr("font-family", "sans-serif") .attr("font-size", "12px") .attr("font-weight", "bold") .attr("fill", "#dcdcdc"); // SVR Extreme var circle = svgContainer.append("circle") .attr("cx", fx) .attr("cy", svry) .attr("r", 20) .attr("fill-opacity", 0.2) .attr("fill", "yellow") .attr('color', 'yellow') .attr("stroke-width", 14) .attr("stroke", "black"); // SVR Extreme var circle = svgContainer.append("circle") .attr("cx", fx) .attr("cy", svry) .attr("r", 20) .attr("fill", "none") .attr('color', 'yellow') .attr("stroke-width", 4) //.attr("stroke-dasharray", "20, 5") .attr("stroke", "yellow"); // SVR TOR possible var textLabels = svgContainer.append("text") .attr("x", fx - 24 + 60) .attr("y", 50) .text("Tornado Possible") .attr("font-family", "sans-serif") .attr("font-size", "12px") .attr("font-weight", "bold") .attr("fill", "#dcdcdc"); var circle = svgContainer.append("circle") .attr("cx", fx + 80) .attr("cy", svry) .attr("r", 20) .attr("fill-opacity", 0.6) .attr("fill", "red") .attr('color', 'yellow') .attr("stroke-width", 14) .attr("stroke", "black"); //Draw the colored foreground var circle = svgContainer.append("circle") .attr("cx", fx + 80) .attr("cy", svry) .attr("r", 20) .attr("fill", "none") .attr('color', 'yellow') .attr("stroke-width", 4) //.attr("stroke-dasharray", "20, 5") .attr("stroke", "yellow"); // Tornado Considerable var circle = svgContainer.append("circle") .attr("cx", fx) .attr("cy", tory) .attr("r", 20) .attr("fill-opacity", 0.2) .attr("fill", "red") .attr('color', 'red') .attr("stroke-width", 14) //.attr("stroke-dasharray", "20, 5") .attr("stroke", "black"); // Tornado Considerable var circle = svgContainer.append("circle") .attr("cx", fx) .attr("cy", tory) .attr("r", 20) .attr("fill", "none") .attr('color', 'yellow') .attr("stroke-width", 4) //.attr("stroke-dasharray", "20, 5") .attr("stroke", "red"); // Flash Flood Extreme var circle = svgContainer.append("circle") .attr("cx", fx) .attr("cy", ltgy) .attr("r", 20) .attr("fill-opacity", 0.2) .attr("fill", flash) .attr('color', 'red') .attr("stroke-width", 14) .attr("stroke", "black"); // Flash Flood Extreme var circle = svgContainer.append("circle") .attr("cx", fx) .attr("cy", ltgy) .attr("r", 20) .attr("fill", "none") .attr('color', 'yellow') .attr("stroke-width", 8) //.attr("stroke-dasharray", "20, 5") .attr("stroke", "#6aff00"); fx = fx + 70; // CATASTROPHIC Tornado var textLabels = svgContainer.append("text") .attr("x", fx - 25) .attr("y", tory - 30) .text("Catastrophic") .attr("font-family", "sans-serif") .attr("font-size", "12px") .attr("font-weight", "bold") .attr("fill", "#dcdcdc"); // Tornado observed var textLabels = svgContainer.append("text") .attr("x", fx - 100) .attr("y", tory - 30) .text("Observed") .attr("font-family", "sans-serif") .attr("font-size", "12px") .attr("font-weight", "bold") .attr("fill", "#dcdcdc"); // Flash Flood emergency var textLabels = svgContainer.append("text") .attr("x", fx - 102) .attr("y", ltgy - 30) .text("Emergency") .attr("font-family", "sans-serif") .attr("font-size", "12px") .attr("font-weight", "bold") .attr("fill", "#dcdcdc"); // Tornado Catastrophic var circle = svgContainer.append("circle") .attr("cx", fx + 10) .attr("cy", tory) .attr("r", 20) .attr("fill", "none") .attr('color', 'red') .attr("stroke-width", 14) .attr("stroke", "#000000"); // Tornado Catastrophic var circle = svgContainer.append("circle") .attr("cx", fx + 10) .attr("cy", tory) .attr("r", 20) .attr("fill-opacity", 0.2) .attr("fill", "red") .attr('color', 'yellow') .attr("stroke-width", 8) //.attr("stroke-dasharray", "20, 5") .attr("stroke", "red"); fx = fx + 70; //Wind/Hail Label var textLabels = svgContainer.append("text") .attr("x", 10) .attr("y", 85) .text("Severe") .attr("font-family", "sans-serif") .attr("font-size", "12px") .attr("fill", "white"); // Tornado Label var textLabels = svgContainer.append("text") .attr("x", 10) .attr("y", 155) .text("Tornado") .attr("font-family", "sans-serif") .attr("font-size", "12px") .attr("fill", "white"); // Flash Flood Label var textLabels = svgContainer.append("text") .attr("x", 10) .attr("y", 145 + 80) .text("Flash Flood") .attr("font-family", "sans-serif") .attr("font-size", "12px") .attr("fill", "white"); // Marine var textLabels = svgContainer.append("text") .attr("x", 10) .attr("y", 145 + 80 + 70) .text("Marine") .attr("font-family", "sans-serif") .attr("font-size", "12px") .attr("fill", "white"); ltgy += 70 // Marine Warning var circle = svgContainer.append("circle") .attr("cx", 100) .attr("cy", ltgy) .attr("r", 20) .attr("fill", "none") .attr('color', marine) .attr("stroke-width", 7) .attr("stroke", "black"); // Marine Warning var circle = svgContainer.append("circle") .attr("cx", 100) .attr("cy", ltgy) .attr("r", 20) .attr("fill-opacity", 0.2) .attr("fill", marine) .attr('color', 'yellow') .attr("stroke-width", 4) //.attr("stroke-dasharray", "20, 5") .attr("stroke", marine); // var textLabels = svgContainer.append("text") // .attr("x", 0) // .attr("y", 145 + 80 + 70) // .text("Marine") // .attr("font-family", "sans-serif") // .attr("font-size", "12px") // .attr("fill", "white"); fx = 100 + 80; // Marine Extreme var circle = svgContainer.append("circle") .attr("cx", fx) .attr("cy", ltgy) .attr("r", 20) .attr("fill-opacity", 0.2) .attr("fill", marine) .attr('color', '#008124') .attr("stroke-width", 14) .attr("stroke", "black"); // Marine Extreme var circle = svgContainer.append("circle") .attr("cx", fx) .attr("cy", ltgy) .attr("r", 20) .attr("fill", "none") .attr('color', 'yellow') .attr("stroke-width", 4) //.attr("stroke-dasharray", "20, 5") .attr("stroke", marine); var textLabels = svgContainer.append("text") .attr("x", fx - 100) .attr("y", ltgy - 30) .text("Warning") .attr("font-family", "sans-serif") .attr("font-size", "12px") // .attr("font-weight", "bold") .attr("fill", "#dcdcdc"); var textLabels = svgContainer.append("text") .attr("x", fx - 25) .attr("y", ltgy - 30) .text("Extreme") .attr("font-family", "sans-serif") .attr("font-size", "12px") .attr("font-weight", "bold") .attr("fill", "#dcdcdc"); // SPS var textLabels = svgContainer.append("text") .attr("x", 10) .attr("y", 145 + 80 + 70 + 80) .text("Special Weather Statement") .attr("font-family", "sans-serif") .attr("font-size", "12px") .attr("fill", "white"); var circle = svgContainer.append("circle") .attr("cx", fx + 20) .attr("cy", 145 + 80 + 70 + 80) .attr("r", 20) .attr("fill", "none") .attr('color', '#e2d17d') .attr("stroke-width", 4) //.attr("stroke-dasharray", "20, 5") .attr("stroke", '#FFE4B5'); // LSR var svg = d3.select('#lsr').append('svg').attr('width', 100).attr('height', 100); var circle = svg.append("circle") .attr("cx", 70) .attr("cy", 15) .attr("r", 8) .attr("fill", "#00C33B") .attr('color', 'black') .attr("stroke-width", 2) .attr("stroke", "black"); var circle = svg.append("circle") .attr("cx", 70) .attr("cy", 35) .attr("r", 8) .attr("fill", "#001EFF") .attr('color', 'black') .attr("stroke-width", 2) .attr("stroke", "black"); var circle = svg.append("circle") .attr("cx", 70) .attr("cy", 55) .attr("r", 8) .attr("fill", "red") .attr('color', 'red') .attr("stroke-width", 2) .attr("stroke", "black"); var textLabels = svg.append("text") .attr("x", 0) .attr("y", 20) .text("Hail") .attr("font-family", "sans-serif") .attr("font-size", "12px") .attr("font-weight", "bold") .attr("fill", "white"); var textLabels = svg.append("text") .attr("x", 0) .attr("y", 40) .text("Wind") .attr("font-family", "sans-serif") .attr("font-size", "12px") .attr("font-weight", "bold") .attr("fill", "white"); var textLabels = svg.append("text") .attr("x", 0) .attr("y", 60) .text("Tornado") .attr("font-family", "sans-serif") .attr("font-size", "12px") .attr("font-weight", "bold") .attr("fill", "white"); } setTimeout(function () { // $(".domainchange").notify("Change Domain to", "error"); }, 3000) function plotWind(bearing, speed, t, age, gust) { var was_calm = true; var last_rotation; var canvas_size = 100; var dot_radius = ~~(canvas_size / 20); var calm_radius = dot_radius;// + 5; var center = ~~(canvas_size / 2); var line_length = ~~(canvas_size / 2.5); var full_flag_length = ~~(line_length / 5); var half_flag_length = ~~(full_flag_length / 2); var animation_duration = 0; var svg = d3.select("#wind").append("svg").attr("width", canvas_size).attr("height", canvas_size); svg.append("circle").attr("cx", center) .attr("cy", center) .attr("r", dot_radius); var line = svg.append("line") .attr("x1", center) .attr("y1", center) .attr("x2", center) .attr("y2", center - line_length) .attr('stroke-width', 1) .attr('fill', '#838383') .attr('stroke', '#000'); var line_group = svg.selectAll("line"); var calm = svg.append("circle") .attr("cx", center) .attr("cy", center) .attr("r", calm_radius) .attr('stroke-width', 2) .attr('fill', jtColorScale(t))//'#838383') .attr('stroke', '#000'); // *************************************************************************** function tallyBarbs(speed) { // round to nearest 5 var remainder = 5 * Math.round(speed / 5); var pennant = 0; var full = 0; var half = 0; if (remainder >= 50) { pennant = ~~(remainder / 50); remainder -= (pennant * 50); } if (remainder >= 10) { full = ~~(remainder / 10); remainder -= (full * 10); } if (remainder >= 5) { half = ~~(remainder / 5); } return [pennant, full, half]; } function drawFlag(center, flag_start, flag_length) { var flag = svg.append("line") .attr("x1", center) .attr("y1", flag_start) .attr("x2", center + flag_length) .attr("y2", flag_start - flag_length); //svg.line(center, flag_start, //center + flag_length, flag_start - flag_length) flag.attr('stroke-width', 1); flag.attr('stroke', '#000'); return flag; } function drawPennant(center, flag_start, flag_length) { var points = [ center, flag_start, center + flag_length, flag_start, center, flag_start + flag_length ]; // console.log('points',points); var flag = svg.append("polygon") .attr("points", points); //function(d) { // console.log(d) // return d; // // return d.map(function(d) { // // return [scaleX(d.x),scaleY(d.y)].join(","); // // }).join(" "); // })//svg.polygon(points) return flag; } var barb; function drawBarbs(tally) { var flag_start = center - line_length; var flag_length; if (barb) { if (barb.selectAll('line')) barb.selectAll('line').remove(); if (barb.selectAll('polygon')) barb.selectAll('polygon').remove(); } var flag; var flags = []; tally.forEach(function (g_total, g_idx) { if (g_idx === 2) { flag_length = half_flag_length; // Special case: if there’s only a half flag, it’s pushed in from the // end to avoid confusion over whether it’s a half flag or full flag. if (!flags.length) flag_start += full_flag_length; } else { flag_length = full_flag_length; } for (var n = 0; n < g_total; n++) { if (g_idx === 0) { // console.log('start', flag_start); flag = drawPennant(center, flag_start, flag_length); } else { // Push the first flag in 1px from the end to avoid a minor visual gap if (!flags.length) flag_start += 1; flag = drawFlag(center, flag_start, flag_length); } flags.push(flag); if (g_idx === 0) { if (n === (g_total - 1)) { flag_start += (full_flag_length + half_flag_length); } else { flag_start += full_flag_length; } } else { flag_start += half_flag_length; } } }); if (barb) { flags.forEach(function (f) { barb.append(f); }); } else { // console.log(flags); flags.forEach(function (f) { // console.log('flags',f.node()); svg.node().append(f.node()); //barb = svg.append(f)//svg.group.apply(svg, flags) }); //barb = svg.append(flags)//svg.group.apply(svg, flags) } } function drawWind(speed, bearing) { var wind = {}; wind.bearing = bearing; wind.speed = speed; var antipode = wind.bearing; if (antipode > 360) antipode -= 360; if (wind.speed > 0) { if (was_calm) { calm.attr('r', dot_radius); } var barb_tally = tallyBarbs(wind.speed); drawBarbs(barb_tally); line_group.selectAll('g').remove(); line_group.append(barb); line_group .attr('transform', 'rotate(' + wind.bearing + ',' + center + ',' + center + ')') .attr('opacity', ageScale(age)); svg.selectAll('polygon') .attr('transform', 'rotate(' + wind.bearing + ',' + center + ',' + center + ')') .attr('opacity', ageScale(age)); svg.selectAll('line') .attr('transform', 'rotate(' + wind.bearing + ',' + center + ',' + center + ')') .attr('opacity', ageScale(age)); svg.selectAll('circle') .attr('opacity', ageScale(age)); // T svg.append('g').append("text") .text(t) .attr("text-anchor", "end") .style("font", "bold 18px sans-serif") .style("fill", jtColorScale(t)) .style("stroke", "black") .style("stroke-width", 1) .attr("x", center + 50) .attr("y", center); // Wind if (typeof (gust) !== "undefined" && gust >= 15) { // if (speed > 30) { var strokeWidth = 1; var stroke = 'yellow'; if (speed > 60) { strokeWidth = 5; } else if (speed > 48) { strokeWidth = 3; } else if (speed >= 35) { strokeWidth = 2; } // svg.selectAll('circle') // .attr('fill', windColorScale(speed)); // // } svg.selectAll('line') .attr('stroke-width', strokeWidth); svg.append('g').append("text") .text('G' + gust) .attr("text-anchor", "end") .style("font", "bold 14px sans-serif") .style("fill", windColorScale(speed)) .style("stroke", "black") .style("stroke-width", 1) .attr("x", center + 50) .attr("y", center + 20); } svg.selectAll('circle') .attr('opacity', ageScale(age)); } else { line_group.attr('opacity', 0); calm.attr('r', calm_radius); svg.selectAll('circle') .attr('opacity', ageScale(age)); } } drawWind(speed, bearing, t); // Turn the svg into an xml string for use in OpenLayers var xmlstring = (new XMLSerializer()).serializeToString(d3.select(svg.node()).node()); // Remove the svg from the display otherwise they accumulate svg.remove(); return xmlstring; }

Severe Storm Tracker (2024)
Top Articles
Latest Posts
Article information

Author: Jamar Nader

Last Updated:

Views: 6610

Rating: 4.4 / 5 (75 voted)

Reviews: 90% of readers found this page helpful

Author information

Name: Jamar Nader

Birthday: 1995-02-28

Address: Apt. 536 6162 Reichel Greens, Port Zackaryside, CT 22682-9804

Phone: +9958384818317

Job: IT Representative

Hobby: Scrapbooking, Hiking, Hunting, Kite flying, Blacksmithing, Video gaming, Foraging

Introduction: My name is Jamar Nader, I am a fine, shiny, colorful, bright, nice, perfect, curious person who loves writing and wants to share my knowledge and understanding with you.