0

In this R Shiny app

https://github.com/DanielEWeeks/NWS_WeatherShinyApp

I have added the WMS Time animated weather radar map from this OpenLayers example

https://openlayers.org/en/latest/examples/wms-time.html

to the Radar tab, but the animated map does not load until after the tab window is resized.

Following these suggestions

I can't display the openlayer map properly until after a window resize

I tried inserting various combinations of

map.updateSize();

commands into a script block in the radar.html file, but that did not work.

Would appreciate any guidance you might be able to provide re how to make the OpenLayers Radar tab load properly when it is first loaded, without requiring a resize event.

This uses this main.js from https://openlayers.org/en/latest/examples/wms-time.html

import Map from 'ol/Map.js';
import Stamen from 'ol/source/Stamen.js';
import TileLayer from 'ol/layer/Tile.js';
import TileWMS from 'ol/source/TileWMS.js';
import View from 'ol/View.js';
import {getCenter} from 'ol/extent.js';
import {transformExtent} from 'ol/proj.js';

function threeHoursAgo() {
  return new Date(Math.round(Date.now() / 3600000) * 3600000 - 3600000 * 3);
}

const extent = transformExtent([-126, 24, -66, 50], 'EPSG:4326', 'EPSG:3857');
let startDate = threeHoursAgo();
const frameRate = 0.5; // frames per second
let animationId = null;

const layers = [
  new TileLayer({
    source: new Stamen({
      layer: 'terrain',
    }),
  }),
  new TileLayer({
    extent: extent,
    source: new TileWMS({
      attributions: ['Iowa State University'],
      url: 'https://mesonet.agron.iastate.edu/cgi-bin/wms/nexrad/n0r-t.cgi',
      params: {'LAYERS': 'nexrad-n0r-wmst'},
    }),
  }),
];
const map = new Map({
  layers: layers,
  target: 'map',
  view: new View({
    center: getCenter(extent),
    zoom: 5,
  }),
});

function updateInfo() {
  const el = document.getElementById('info');
  el.innerHTML = startDate.toISOString();
}

function setTime() {
  startDate.setMinutes(startDate.getMinutes() + 15);
  if (startDate > Date.now()) {
    startDate = threeHoursAgo();
  }
  layers[1].getSource().updateParams({'TIME': startDate.toISOString()});
  updateInfo();
}
setTime();

const stop = function () {
  if (animationId !== null) {
    window.clearInterval(animationId);
    animationId = null;
  }
};

const play = function () {
  stop();
  animationId = window.setInterval(setTime, 1000 / frameRate);
};

const startButton = document.getElementById('play');
startButton.addEventListener('click', play, false);

const stopButton = document.getElementById('pause');
stopButton.addEventListener('click', stop, false);

updateInfo();

Possible solutions tried:

  tabPanel("Radar",
           tags$script("setTimeout(() => {
  map.updateSize();
}, 10);"),
           includeHTML("radar.html"))
  )

This gave an error about map having a zero height or width.

--

Put this in end of the 'head' section or at the end of the 'body' section of 'radar.html':

  <script>
    setTimeout(() => {
       map.updateSize();
    }, 10);
  </script>

This gave this error

TypeError: map.updateSize is not a function

--

Solution

To get the animated weather map to load within an R Shiny tabPanel without requiring a manual window resize, this adjusted code works. Note that it uses two approaches suggested/discussed in other posts:

  1. Most of the code is lies within a $(document).ready(function() call.
  2. The code auto-resizes the map via a call to map.updateSize() when the tab panel is selected:
      $("a[data-toggle=\'tab\']").on("shown.bs.tab", function() {
        map.updateSize();
      }

Here's more of the code in context (complete code available at https://github.com/DanielEWeeks/NWS_WeatherShinyApp):

  tags$script(HTML('
    var startDate = new Date(Math.round(Date.now() / 3600000) * 3600000 - 3600000 * 3);
    var frameRate = 2; // frames per second
    var animationId = null;
    var tileLayer;
    var timeInfo;
    var currentAnimationFrame = null;
    var map;

    function updateInfo() {
      timeInfo.innerHTML = "Current Time: " + startDate.toISOString();
    }

    function setTime() {
      startDate.setMinutes(startDate.getMinutes() + 15);
      if (startDate > Date.now()) {
        startDate = new Date(Math.round(Date.now() / 3600000) * 3600000 - 3600000 * 3);
      }
      var timeParam = startDate.toISOString();
      tileLayer.getSource().updateParams({ TIME: timeParam });
      updateInfo();
    }

    function stop() {
      if (currentAnimationFrame !== null) {
        clearInterval(currentAnimationFrame);
        currentAnimationFrame = null;
      }
    }

    function play() {
      stop();
      currentAnimationFrame = setInterval(setTime, 1000 / frameRate);
    }

    $(document).ready(function() {
      tileLayer = new ol.layer.Tile({
        extent: ol.proj.transformExtent([-126, 24, -66, 50], "EPSG:4326", "EPSG:3857"),
        source: new ol.source.TileWMS({
          attributions: ["Iowa State University"],
          url: "https://mesonet.agron.iastate.edu/cgi-bin/wms/nexrad/n0r-t.cgi",
          params: { LAYERS: "nexrad-n0r-wmst" }
        })
      });

      map = new ol.Map({
        target: "map",
        layers: [
          new ol.layer.Tile({
            source: new ol.source.OSM()
          }),
          tileLayer
        ],
        view: new ol.View({
          center: ol.proj.fromLonLat([-98.5, 39.5]),
          zoom: 5
        })
      });

      timeInfo = document.getElementById("time-info");

      $("#play-button").on("click", function() {
        play();
      });

      $("#pause-button").on("click", function() {
        stop();
      });

      updateInfo();
      play();

      // Resize the map when the tab is selected
      $("a[data-toggle=\'tab\']").on("shown.bs.tab", function() {
        map.updateSize();
      });
    });
  ')

0 Answers0