3

I have taken a working Leaflet map, but when I added a JQuery Mobile header and back button the formatting went crazy.

Initially loading the page all the contents is loaded in the upper-left-hand corner, but when the page is resized the smallest bit on a desktop, or rotated on a mobile, everything is fine.

This is what it looks like when opened:

This is what it looks like when opened

and what it looks like after rotating (and what it should be):

what it looks like after rotating, and what it should be

Here is the code for the page

<!DOCTYPE html>
<html>
<head>
<title>Toronto CAD Activity Map</title>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="../css/leaflet.css" />
 <meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="../css/tfscad.mobile.css" />
<link rel="stylesheet" href="../css/jquery.mobile-1.4.5.min.css">
<link rel="stylesheet" href="../css/font-awesome.min.css">
<script src="../js/jquery-1.11.1.min.js"></script>
<script src="../js/jquery.mobile-1.4.5.min.js"></script>
<script src="../js/iframeResizer.contentWindow.js"></script>

<!--[if lte IE 8]><link rel="stylesheet" href="../dist/leaflet.ie.css" /><![endif]-->
<style>
#mapPage {
  height: calc(100% - 42px);
}

#map {
  height: 100%;
}

#map-content{
  height: 100%;
  padding: 0px; 
  margin:0px;
  z-index: -1;
}
#curLoc{
  position: absolute;
  bottom: 0;
  left: 10px;
}
</style>
</head>


<body>
<body>
    <div data-role="page" id="mapPage" data-theme="a"> 
        <div data-role="header" data-position="fixed" data-theme="a">
            <a id="backButton" href="#" data-rel="back" 
                data-transition="slide" data-direction="reverse">Back</a>
            <h1>Toronto CAD Map</h1>
        </div> 

        <div id="map-content" data-role="content">
            <div id="map"></div>
        </div>
        <a id="curLoc" data-role="button" data-icon="location" data-iconpos="notext"></a>

    </div> 
<script src="../js/jquery-1.11.1.min.js"></script> 
<script src="../js/leaflet.js"></script> 

<script type="text/javascript">
 window.onload = function() {
getGeoJson();
getTPSJson();
};
 
    var map = L.map('map').setView([43.7178,-79.3762], 11);
        L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
            attribution: 'Map data &copy; 2011 OpenStreetMap contributors, Imagery &copy; 2012 CloudMade',
               }).addTo(map);



function getGeoJson(){
 
  // load GeoJSON from an external file
  $.getJSON("../appdata/geo.json",function(data){

      L.geoJson(data  ,{
    pointToLayer: function(feature,latlng){
       
       var TFS = new L.icon({
       iconUrl: '../images/tfs_logo.png',
      iconSize:     [22, 22],
      popupAnchor:  [0, -22]
      });

     var TPS = new L.icon({
       iconUrl: '../images/tps_logo.png',
      iconSize:     [22, 22],
      popupAnchor:  [0, -22]
      });

     var ESC = new L.icon({
       iconUrl: '../images/tps_logo.png',
      iconSize:     [22, 22],
      popupAnchor:  [0, -22]
      });         
 if(feature.properties.icon == 'TFS'){
    var marker = L.marker(latlng,{icon: TFS});
  marker.bindPopup('<strong>' + feature.properties.event_type + '</strong><br/>' + feature.properties.OPEN_DT);
  return marker; 
    
  }else if(feature.properties.icon == 'TPS'){
    var marker = L.marker(latlng,{icon: TPS});
  marker.bindPopup('<strong>' + feature.properties.event_type + '</strong><br/>' + feature.properties.OPEN_DT);
  return marker; 

  }else if(feature.properties.icon == 'ESC'){    
    var marker = L.marker(latlng,{icon: ESC});
  marker.bindPopup('<strong>' + feature.properties.event_type + '</strong><br/>' + feature.properties.OPEN_DT);
  return marker; 
  }
      }
  }  ).addTo(map);
  }); 
 
 
}

function getTPSJson(){
 
var myStyle = {
  "color": "#ff7800",
  "weight": 5,
  "opacity": 0,
  "offset": 1.5
};

  // load GeoJSON from an external file
  $.getJSON("../appdata/TPSDiv.json",function(myLines){

 L.geoJson(myLines, {
style: myStyle
}).addTo(map);
})
}


 setInterval(function()
{ 
 
getGeoJson();

}, 10000);//time in milliseconds  

    function onClick(e) {
        //console.log(this.options.win_url);
        window.open(this.options.win_url);
    }
 
    
</script>
</body>
ghybs
  • 47,565
  • 6
  • 74
  • 99
Victor
  • 103
  • 1
  • 11
  • 1
    `height: calc(100% - 42px);` map-content not mypage. Don't touch page's dimensions. https://stackoverflow.com/a/27617438/1771795 – Omar Jul 22 '17 at 08:46
  • Possible duplicate of [Data-toggle tab does not download Leaflet map](https://stackoverflow.com/questions/36246815/data-toggle-tab-does-not-download-leaflet-map) – ghybs Jul 22 '17 at 09:16
  • @ghybs not related to dupe question at all. – Omar Jul 22 '17 at 11:09

2 Answers2

1

jQuery Mobile manages the pages of your multi-pages document and resizes them appropriately when DOM is loaded.

The issue is that you have already instantiated your map with Leaflet before that event happens, so the map container (i.e. <div id="map"></div>) is not displayed yet by jQuery Mobile, and therefore its size is not computed yet by the browser.

This is a variant of map container size not being valid yet at map instantiation. See Data-toggle tab does not download Leaflet map

Since you already have a listener on window.onload, which executes after jQuery Mobile does its stuff, you could very simply call map.invalidateSize() at that moment:

window.onload = function() {

  // Request Leaflet to re-evaluate the map container size
  // AFTER jQuery Mobile displays the page.
  map.invalidateSize();

  getGeoJson();
  getTPSJson();
};

Demo: https://plnkr.co/edit/TigW44s5MlqMifimWkSw?p=preview

ghybs
  • 47,565
  • 6
  • 74
  • 99
1

jQuery Mobile has its own way to create pages from div's, so you may better stick to JQM events.

Here is a great post of Omar which explain how to solve this (typical) issue when loading Google Maps. You should wait for pagecontainershow or use a placeholder to pre-load the maps in advance.

In my example below, you will find a variation of this approach for Leaflet which uses the same canvasHeight() function (see also the answers here: set content height 100% jquery mobile).

I noticed you are about to implement a footer button for the geo-location feature, so for your convenience i show you also a possible way to do that (credits: Getting current user location automatically every “x” seconds to put on Leaflet map?).

Please note: i had to reposition the default map attribution so it won't overlap with the footer button.

var map, actualPosition, actualAccuracy, autoUpdate;

function canvasHeight(canvas) {
  var mapPage = $("#page-map"),
    screen = $.mobile.getScreenHeight(),
    header = $(".ui-header", mapPage).hasClass("ui-header-fixed") ? $(".ui-header", mapPage).outerHeight() - 1 : $(".ui-header", mapPage).outerHeight(),
    footer = $(".ui-footer", mapPage).hasClass("ui-footer-fixed") ? $(".ui-footer", mapPage).outerHeight() - 1 : $(".ui-footer", mapPage).outerHeight(),
    newHeight = screen - header - footer;
  $(canvas).height(newHeight);
}

$(window).on("throttledresize orientationchange", function() {
  canvasHeight("#map");
})

function onLocationFound(e) {
  var radius = e.accuracy / 2;
  actualPosition = L.marker(e.latlng).addTo(map);
  actualAccuracy = L.circle(e.latlng, radius).addTo(map);
}

function onLocationError(e) {
  alert(e.message);
}

function showLocation() {
  if (actualPosition) {
    map.removeLayer(actualPosition);
    map.removeLayer(actualAccuracy);
  }
  map.locate({setView: true,maxZoom: 16});
}

function loadMap(canvas) {
  map = L.map(canvas).setView([43.7178, -79.3762], 11);
  L.tileLayer("https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png").addTo(map);
  map.on('locationfound', onLocationFound);
  map.on('locationerror', onLocationError);
  // Your custom initialization
  //getGeoJson();
  //getTPSJson();
}

function toggleAutoUpdate() {
  if (autoUpdate) {
    $("#autoUpdate").removeClass("ui-btn-active");
    clearInterval(autoUpdate);
    autoUpdate = null;
    if (actualPosition) {
      map.removeLayer(actualPosition);
      map.removeLayer(actualAccuracy);
    }
  } else {
    $("#autoUpdate").addClass("ui-btn-active");
    showLocation();
    autoUpdate = setInterval(function() {
      showLocation();
      // Your custom Update
      //getGeoJson();
    }, 10 * 1000);
  }
}

$(document).on("pagecontainershow", function(e, ui) {
  if (ui.toPage.prop("id") == "page-map") {
    canvasHeight("#map");
    if (!map) {
      loadMap("map");
    }
  }
});
#map {
  margin: 0;
  padding: 0;
}

#page-map .footer {
  position: fixed;
  z-index: 1000;
  bottom: .1em;
  width: 100%;
}

#footer-button {
  width: 100%;
  text-align: center;
  background: transparent;
}

#map-attribution {
  text-align: center;
  background: rgba(255, 255, 255, 0.7);
}

.leaflet-control-attribution.leaflet-control {
  display: none;
}

/* Don't show scrollbars on SO code snippet */
.ui-mobile .ui-page {
  min-height: 100px !important;
}
<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no">
  <link rel="stylesheet" href="https://code.jquery.com/mobile/1.4.5/jquery.mobile-1.4.5.css">
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.1.0/leaflet.css">
  <script src="https://code.jquery.com/jquery-1.11.2.min.js"></script>
  <script src="https://code.jquery.com/mobile/1.4.5/jquery.mobile-1.4.5.min.js"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.1.0/leaflet.js"></script>
</head>
<body>
  <div data-role="page" id="page-map">
    <div data-role="header" data-position="fixed" data-theme="a">
      <a href="#" data-rel="back" data-transition="slide" data-direction="reverse">Back</a>
      <h1>Toronto CAD Map</h1>
    </div>

    <div id="map" data-role="content">
      <div class="footer">
        <div id="footer-button">
          <button id="autoUpdate" onclick="toggleAutoUpdate();" class="ui-btn ui-btn-inline ui-corner-all ui-icon-location ui-btn-icon-notext"></button>
        </div>
        <div id="map-attribution">
          <a href="http://leafletjs.com" title="A JS library for interactive maps">Leaflet</a> Map data &copy; 2011 OpenStreetMap contributors, Imagery &copy; 2012 CloudMade
        </div>
      </div>
    </div>
  </div>
</body>
</html>
Marcin Orlowski
  • 72,056
  • 11
  • 123
  • 141
deblocker
  • 7,629
  • 2
  • 24
  • 59