Experimental Beach Forecast Webpage (2024)

', { 'class': 'beachForecastSidebarLinkTitle' }) .html(link.title) .appendTo($sidebarLinkAnchor); } } $sidebarLink.append($sidebarLinkAnchor); $sidebar.append($sidebarLink); }); $('#beachForecastContainer').prepend($sidebar); } } function checkKMLExpiration(jqXHR) { var serverTime = jqXHR.getResponseHeader("date"); //.toLowerCase(); var srfTime = jqXHR.getResponseHeader("last-modified"); //.toLowerCase(); log("Checking creation time " + srfTime); log("> against current time " + serverTime); var splitServerTime = serverTime.split(" ") var serverDate = new Date(splitServerTime[1] + " " + splitServerTime[2] + " " + splitServerTime[3] + " " + splitServerTime[4]); var serverEpoch = serverDate.getTime() / 1000.0; var splitSRFTime = srfTime.split(" ") var srfDate = new Date(splitSRFTime[1] + " " + splitSRFTime[2] + " " + splitSRFTime[3] + " " + splitSRFTime[4]); var srfEpoch = srfDate.getTime() / 1000.0; var diff = serverEpoch - srfEpoch; log("Expiration difference is " + (diff / 3600) + " hours"); return (diff / 3600) < 24 ? true : false; } function loadMap(validData) { log("Loading map (" + (validData?"enabled":"disabled") + ")"); $('#beachForecastMap').height(options.map.height); $('#beachForecastMapOL').empty(); // because CMS editor requires for empty tag var attribution = new ol.Attribution({ html: 'Tiles © ArcGIS' }); var beachPointStyle = new ol.style.Style({ image: new ol.style.Icon( /** @type {olx.style.IconOptions} */ ({ src: options.imagePath + options.map.marker.filename, anchor: [10,0], anchorXUnits: 'pixel', anchorYUnits: 'pixel', anchorOrigin: 'bottom-left' })) }); var beachPoints = []; if(validData) { $('#beachForecastMapLabel') .attr('src', options.siteImagePath + 'srfLabel.png') .show(); for (var i = 0; i < options.beachPoints.length; i++) { //var beachPointPos = [parseFloat(options.beachPoints[i][2]), parseFloat(options.beachPoints[i][1])]; var beachPoint = new ol.Feature({ geometry: new ol.geom.Point( ol.proj.fromLonLat([parseFloat(options.beachPoints[i][2]), parseFloat(options.beachPoints[i][1])]) ), name: options.beachPoints[i][0], id: options.beachPoints[i][0].toLowerCase().replace(/\s/g, ''), type: 'beachPoint', loc: [parseFloat(options.beachPoints[i][2]), parseFloat(options.beachPoints[i][1])] }); beachPoint.setStyle(beachPointStyle); beachPoints.push(beachPoint); } } /* var forecastLabel = function(opt_options) { var options = opt_options || {}; var $button = $('

').css({ 'background': '#f00' ,'width': 100 ,'height': 100 }) .text("BUTTON!"); ol.control.Control.call(this, { element: $button[0], target: options.target }); }; ol.inherits(forecastLabel, ol.control.Control);*/ var map = new ol.Map({/* controls: [ new forecastLabel(), ], controls: ol.control.defaults().extend([ new forecastLabel(), ]),*/ layers: [ new ol.layer.Tile({ source: new ol.source.XYZ({ attributions: [attribution], url: "https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}?appid=45ad401c-fa23-4a10-8b2f-a7ad29a3e2a0" }) }), new ol.layer.Tile({ source: new ol.source.XYZ({ attributions: [attribution], url: "https://server.arcgisonline.com/ArcGIS/rest/services/Reference/World_Boundaries_and_Places/MapServer/tile/{z}/{y}/{x}?appid=45ad401c-fa23-4a10-8b2f-a7ad29a3e2a0" }) })/*, new ol.layer.Tile({ source: new ol.source.XYZ({ attributions: [attribution], url: "https://server.arcgisonline.com/ArcGIS/rest/services/Reference/World_Transportation/MapServer/tile/{z}/{y}/{x}?appid=45ad401c-fa23-4a10-8b2f-a7ad29a3e2a0" }) })*/, new ol.layer.Vector({ source: new ol.source.Vector({ url: options.kmlUrl, format: new ol.format.KML() }) }), new ol.layer.Vector({ source: new ol.source.Vector({ features: beachPoints }) }) ], target: $('#' + options.map.canvasId)[0], controls: ol.control.defaults({ attributionOptions: /** @type {olx.control.AttributionOptions} */ ({ collapsible: false }) }), logo: false, view: new ol.View({ center: ol.proj.fromLonLat([parseFloat(options.map.lon), parseFloat(options.map.lat)], 'EPSG:3857'), zoom: options.map.zoom }) }); if (otherSites) { $.each(otherSites, function (i, item) { adjacentSite = otherSites[i][0]; log(otherSites[i][0].toUpperCase() + " is an adjacent site."); adjacentKmlUrl = "/source/" + adjacentSite + "/beachforecast/SRF.kml"; log("Checking " + adjacentSite.toUpperCase() + " KML expiration"); $.ajax({ url: adjacentKmlUrl, async: false }).done(function(data, status, jqXHR) { if (checkKMLExpiration (jqXHR)) { log("Loading KML at /source/" + otherSites[i][0] + "/beachforecast/SRF.kml"); var otherSitesKML = new ol.layer.Vector({ source: new ol.source.Vector({ url: "/source/" + otherSites[i][0] + "/beachforecast/SRF.kml", format: new ol.format.KML() }) }); map.addLayer(otherSitesKML); document.getElementById(otherSites[i][1]).innerHTML = ""; } else { log("Invalid KML expiration"); } }).fail(function(x, status) { log (adjacentSite.toUpperCase() + " KML failed to load"); }); }); } map.on('pointermove', function(e) { var pixel = map.getEventPixel(e.originalEvent); var hit = map.hasFeatureAtPixel(pixel); map.getTarget().style.cursor = hit ? 'pointer' : ''; }); map.on('click', function(evt) { var feature = map.forEachFeatureAtPixel(evt.pixel, function(feature, layer) { return feature; }); if (feature) { if (feature.get('type') === 'beachPoint') { displayForecast(feature.get('loc'), feature.get('id'), feature.get('name')); } else { // presume KML click var zoneDetails = '

National Weather Service '+siteTitle+'

'; zoneDetails += '

'+feature.get('description')+'

'; $('#riskDetailsModal').modal(); document.getElementById("riskDetailsModal").innerHTML = zoneDetails; } } }); if(!validData) { $('#beachForecastMapLabel') .attr('src', options.siteImagePath + 'srfLabel_expired.png') .show(); $('#beachForecastMapOL').css('opacity', .2); $('#riskDetails').html("Notice!
The beach foreach for this area is not valid or expired.") map.removeLayer(map.getLayers().item(2)); map.getInteractions().forEach(function(interaction) { map.removeInteraction(interaction); }, this); map.getControls().forEach(function(control) { map.removeControl(control); }, this); } } function displayForecast(loc, id, name) { log("Forecast for " + loc + ", " + id + " (" + name + ")"); $('#beachForecastOverlay') .click(function () { hideForecast(); }) .show(); $('#beachForecastOverlayContent').show(); var $forecast = $('#beachForecastTemplate'); // if different location than previous click if (id != currentForecastId) { currentForecastId = id; updateForecastMessage(0); // have to used secondary deferreds to because jQuery stops any one promise fails var $forecastDeferred = $.Deferred(); var $beachesDeferred = $.Deferred(); $.ajax({ url: '//forecast.weather.gov/MapClick.php', jsonp: 'callback', dataType: 'jsonp', data: { FcstType: 'json', lon: loc[0], lat: loc[1] } }).complete($forecastDeferred.resolve); $.ajax({ url: options.siteSourcePath + "/beaches.json", dataType: 'json' }).complete($beachesDeferred.resolve); $.when($forecastDeferred, $beachesDeferred) .done(function(forecast, beach) { if(forecast[1] == 'success') { forecast[0].done(function(data) { $forecast.find('#beachForecastTemplateWFO').text(data.productionCenter); $forecast.find('#beachForecastTemplateName').text(name); $forecast.find('#beachForecastTemplateUpdate').text(data.creationDateLocal); $forecast.find('#beachForecastTemplateExtendedContainer').html(buildForecastHTML(data)); }); if(beach[1] == 'success') { beach[0].done(function(data) { if(typeof data[id] !== 'undefined') { var beachData = data[id]; var $beachForecastTemplateSrfHTML = $forecast.find('#beachForecastTemplateSrf').append($('#beachForecastTemplateHTML-srf').clone()); $beachForecastTemplateSrfHTML.find('#beachForecastTemplateSrfSurf') .find('.beachForecastTemplateSrfTitle') .css({ 'background-color': rip[beachData.riprisk].color }) .end() .find('.beachForecastTemplateSrfLevel') .html($('#riskTable-' + beachData.riprisk + ' .riskTableLevel').html()) .end() .find('.beachForecastTemplateSrfContent') .html($('#riskTable-' + beachData.riprisk + ' .riskTableDescription').html()) .end() .find('.beachForecastTemplateSrfBackgrounds') .css({ 'border-color': rip[beachData.riprisk].color }); $beachForecastTemplateSrfHTML.find('#beachForecastTemplateSrfUV') .each(function() { var $template = $(this); if(typeof beachData.uvindex !== 'undefined') { $template .find('.beachForecastTemplateSrfTitle') .css({ 'background-color': uvindex[beachData.uvindex].color }) .end() .find('.beachForecastTemplateSrfLevel') .html($('#uvTable-' + beachData.uvindex + ' .uvTableRisk').html()) .end() .find('.beachForecastTemplateSrfContent') .html($('#uvTable-' + beachData.uvindex + ' .uvTableDescription').html()) .end() .find('.beachForecastTemplateSrfBackgrounds') .css({ 'border-color': uvindex[beachData.uvindex].color }); } else { $template.hide(); } }); $beachForecastTemplateSrfHTML.find('#beachForecastTemplateSrfTemperature') .each(function() { var $template = $(this); if(typeof beachData.surftemp !== 'undefined') { $template .find('.beachForecastTemplateSrfTitle') .css({ 'background-color': '#66CCFF' }) .end() .find('.beachForecastTemplateSrfContent') .html(beachData.surftemp) .end(); } else { $template.hide(); } }); $beachForecastTemplateSrfHTML.find('#beachForecastTemplateSrfQRCode').append($('Experimental Beach Forecast Webpage (2)', {src:options.siteImagePath + 'qrcode.png'})); } else { log("Cannot find beach information for " + id); } }); } updateForecastMessage(); $('#beachForecastTemplate').show(); } else { updateForecastMessage(1); } }) } else { $('#beachForecastTemplate').show(); } } var forecastMessages = [ 'Retrieving forecast, please wait...', 'Error retrieving forecast, please close this message and try again.' ]; function updateForecastMessage(messageNumber) { if (!isNaN(messageNumber)) { $('#beachForecastMessage') .html(forecastMessages[messageNumber]) .show(); } else { $('#beachForecastMessage').hide(); } } $('#beachForecastOverlay').click(function() { hideForecast(); }); function hideForecast() { $('#beachForecastOverlay').hide(); $('#beachForecastOverlayContent').hide(); $('#beachForecastTemplate').hide(); } function buildForecastHTML(json) { var numPeriods = 7; var bodyText = ""; bodyText += '

'; bodyText += ''; for (var i = 0; i < numPeriods; i++) { var validName = json.time.startPeriodName[i].replace(/ /g,"
"); bodyText += ''; } bodyText += ''; for (var i = 0; i < numPeriods; i++) { var iconLink = json.data.iconLink[i].replace("http:","https:"); bodyText += ''; } bodyText += ''; for (var i = 0; i < numPeriods; i++) { var weatherText = json.data.weather[i]; if (json.data.weather[i].match(/^[a-zA-Z]* [a-zA-Z]* [a-zA-Z]*$/)) { var rgExp = /([a-zA-Z]*) ([a-zA-Z]*) ([a-zA-Z]*)/ var weatherText = json.data.weather[i].replace(rgExp,"$1 $2
$3"); } else if (json.data.weather[i].match(/^[a-zA-Z]* [a-zA-Z]*$/)) { var rgExp = /([a-zA-Z]*) ([a-zA-Z]*)/ var weatherText = json.data.weather[i].replace(rgExp,"$1
$2"); } bodyText += ''; } bodyText += ''; for (var i = 0; i < numPeriods; i++) { if (json.time.tempLabel[i] == "High") { var hiloColor = "red"; var hilo = "Hi" } else if (json.time.tempLabel[i] == "Low") { var hiloColor = "blue"; var hilo = "Lo" } else { var hiloColor = "black"; } bodyText += ''; } bodyText += '
'+validName+'
Experimental Beach Forecast Webpage (3)
'+weatherText+'
'+hilo+''+json.data.temperature[i]+'°F

'; for (var i = 0; i < 7; i++) { bodyText += ''+json.time.startPeriodName[i]+':'+json.data.text[i]; bodyText += '

'; } bodyText += '

Point Forecast: '+json.location.areaDescription+'
'+json.location.latitude+''+json.location.longitude+'(Elev. '+json.location.elevation+' ft)

'; bodyText += 'Visit your local NWS office at https://www.weather.gov/'+json.location.wfo.toLowerCase()+'
'; //bodyText += 'or call us at '+phoneNum; //bodyText += ''; //bodyText += srfText; //bodyText += ''; return (bodyText); } function associateEvents() { $('#beachForecastTemplateAction-Print').click(function() { var divToPrint=document.getElementById('beachForecastTemplate'); newWin= window.open(""); newWin.document.write(divToPrint.outerHTML); var newWinHead = newWin.document.getElementsByTagName("head")[0]; var $arrStyleSheets = $('style, link'); $arrStyleSheets.each(function() { newWinHead.appendChild(this.cloneNode(true)); }); newWin.document.body.style.backgroundImage = "none"; newWin.document.body.style.backgroundColor = "#fff"; newWin.print(); newWin.close(); }); } function getParameterByName(name) { name = name.replace(/[\[]/, "\\[").replace(/[\]]/, "\\]"); var regex = new RegExp("[\\?&]" + name + "=([^]*)"), results = regex.exec(location.search); return results === null ? "" : decodeURIComponent(results[1].replace(/\+/g, " ")); } })();

UNDER DEVELOPMENT

The map below is color-coded to indicate the forecast rip current risk level. Click on the beach area of your choice for more information, or click a beach umbrella for the detailed, beach forecast.

View the product description document for more information on the rip current graphic. Comments are currently being accepted.

Experimental Beach Forecast Webpage (4)Experimental Beach Forecast Webpage (5)Experimental Beach Forecast Webpage (6)
Experimental Beach Forecast Webpage (7)Experimental Beach Forecast Webpage (8)ZoomOut
Experimental Beach Forecast Webpage (9)
Experimental Beach Forecast Webpage (10)
Experimental Beach Forecast Webpage (11)Experimental Beach Forecast Webpage (12)Experimental Beach Forecast Webpage (13)
Risk LevelDescription
LowThe risk of rip currents is low, however, life threatening rip currents may still occur especially near groins, jetties, reefs, and piers. Always swim near a lifeguard and remember to heed the advice of the local beach patrol and flag warning systems.
ModerateLife threatening rip currents are possible. Always swim near a lifeguard and remember to heed the advice of the local beach patrol and flag warning systems.
HighLife threatening rip currents are likely. The surf zone is dangerous for all levels of swimmers. Stay out of the water. Remember to heed the advice of the local beach patrol and flag warning systems.

The Danger of Rip Currents

Rip currents are powerful, channeled currents of water flowing away from shore. They typically extend from the shoreline, through the surf zone, and past the line of breaking waves. Rip currents can occur at any beach with breaking waves.

En Espanol

If you become caught in a rip current, yell for help and remain calm. Do not exhaust yourself and stay afloat while waiting for help. If you have to swim out of a rip current, swim parallel to shore and back toward the beach when possible. Do not attempt to swim directly against a rip current as you will tire quickly.

Never assume the ocean is safe, even if the weather is nice. Hurricanes that are far away can still create deadly rip currents and waves. For maximum safety, swim near a lifeguard.

Experimental Beach Forecast Webpage (16) Viewrip current safety videosat the National Weather Service YouTube channel.

Additional Resources

UV Index Scale
2 or lessLowLow danger from the sun's UV rays for the average person.

Wear sunglasses on bright days. If you burn easily, cover up and use sunscreen.

3 - 5ModerateModerate risk of harm from unprotected sun exposure.

Take precautions, such as covering up, if you will be outside. Stay in shade near midday when the sun is strongest.

6 - 7HighHigh risk of harm from unprotected sun exposure.

Protection against sunburn is needed. Reduce time in the sun between 10 a.m. and 4 p.m. Cover up, wear a hat and sunglasses, and use sunscreen.

8 - 10Very HighVery high risk of harm from unprotected sun exposure.

Take extra precautions. Unprotected skin will be damaged and can burn quickly. Minimize sun exposure between 10 a.m. and 4 p.m. Otherwise, seek shade, cover up, wear a hat and sunglasses, and use sunscreen.

11+ExtremeExtreme risk of harm from unprotected sun exposure.

Take all precautions. Unprotected skin can burn in minutes. Beachgoers should know that white sand and other bright surfaces reflect UV and will increase UV exposure. Try to avoid sun exposure between 10 a.m. and 4 p.m. Seek shade, cover up, wear a hat and sunglasses, and use sunscreen.

Thunderstorm Potential (definition)Waterspout Risk (definition)
NoneNo thunderstorms are expectedNoneNo risk of waterspout development
LowThunderstorms are only expected to be isolated in coverageLowLow risk of waterspout development
ModerateThunderstorms are forecast to be scattered in coverageModerateModerate risk of waterspout development
HighThunderstorms are forecast to be numerous or widespread in coverageHighHigh risk of waterspout development
Experimental Beach Forecast Webpage (2024)
Top Articles
Latest Posts
Article information

Author: Mrs. Angelic Larkin

Last Updated:

Views: 5727

Rating: 4.7 / 5 (67 voted)

Reviews: 90% of readers found this page helpful

Author information

Name: Mrs. Angelic Larkin

Birthday: 1992-06-28

Address: Apt. 413 8275 Mueller Overpass, South Magnolia, IA 99527-6023

Phone: +6824704719725

Job: District Real-Estate Facilitator

Hobby: Letterboxing, Vacation, Poi, Homebrewing, Mountain biking, Slacklining, Cabaret

Introduction: My name is Mrs. Angelic Larkin, I am a cute, charming, funny, determined, inexpensive, joyous, cheerful person who loves writing and wants to share my knowledge and understanding with you.