-
Current Hazards
- Storm and Precipitation Reports
- Outlooks
- Submit a Storm Report
- Experimental Graphical Hazardous Weather Outlook
-
Current Conditions
- Satellite
- Snowfall Analysis
- Observations
- Local Storm Reports
- Local Snowfall Reports
- Local Ice Accumulation Reports
- Observed Precipitation
-
Radar
- Local Enhanced Radar
- Local Standard Radar (low bandwidth)
- Regional Standard Radar (low bandwidth)
-
Forecasts
- Hourly Forecasts
- Activity Planner
- User Defined Area Forecast
- Fire Weather
- Winter Weather
- Forecast Discussion
- Great Lakes Marine Forecasts
-
Rivers and Lakes
- National Water Prediction Service (NWPS)
- Rainy River Basin Observations and Forecasts
See AlsoThe Masters begins after weather delay, though high winds are still expected at Augusta NationalSevere storms ramp up in the South Wednesday, threatening strong tornadoes and flash floods | CNNSevere storms threaten Texas and the SouthSevere storms lash central and eastern US, dumping rain, softball-sized hail and threatening tornadoes | CNN -
Climate and Past Weather
- Local
- Drought
- NOAA Climate Service
- Event Summaries
-
Local Programs
- Blog
- Publications
- Aviation
- Beach Hazards
- Fire Weather Dashboard
- Local Area Forecasts
- Local Text Products
- Marine
- Memorable Winter Storms
- NOAA Weather Radio
- Our Office
- Prototype IDSS Forecast Points
- Severe Storm Tracker
- Skywarn
- Social Media
- Travel Conditions
- Top Ten Daily Weather Records
- Winter Monitor
Severe Storm Tracker v1.1
Help | Change Domain | Bookmark | Legend
×
Legend Radar
Storm Reports
Requests:
' 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("
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("
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
'; } catch (e) { // issue with decoding... } 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; }