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:
and 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 © 2011 OpenStreetMap contributors, Imagery © 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>
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">
Back
<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">
Leaflet Map data © 2011 OpenStreetMap contributors, Imagery © 2012 CloudMade
</div>
</div>
</div>
</div>
</body>
</html>
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
Related
I have an application with multiple stack of card, I would like to have a drag&drop ability between these stacks.
These stacks have a different layout in term of offset relative to the parent element.
I simplified to the max in this fiddle
https://jsfiddle.net/dtghbo7f/
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Crapette HTML 5 + jQuery</title>
<style type="text/css">
.card, .box {
width: 71px;
height: 96px;
position: absolute;
}
#box1 {
top:31px;
left:25px;
}
#box2 {
top:31px;
left:255px;
}
.card {
background-image: url[...]
}
.box {
background-position: -1px -1px;
background-image: url[...]
}
</style>
<script src="jquery.min.js"></script>
<script src="jquery-ui.js"></script>
<script>
$("body").ready(function() {
$('<div>').attr('id','card0').addClass('card').appendTo($('#box1'));
for(let i=1;i<7;i++){
$('<div>').attr('id','card'+i).addClass('card').appendTo($('#box1 div.card:not(:has(*))')).css('top',5).css('left',5);
}
$('<div>').attr('id','card7').addClass('card').appendTo($('#box2'));
for(let i=1;i<7;i++){
$('<div>').attr('id','card'+(i+7)).addClass('card').appendTo($('#box2 div.card:not(:has(*))')).css('top',15);
}
$(".card").draggable({
revert: true,//'invalid',
revertDuration: 500,
start: function(event, ui) {
$(this).parents(".box").css('z-index',2);
},
drag: function(event, ui) {
},
stop: function(event, ui) {
$(".box").css('z-index',1);
if($(this).parents('.box').attr('id') == 'box1') {
$(this).css('top',5).css('left',5);
} else {
$(this).css('top',15).css('left',0);
}
},
});
$(".box, .card").droppable({
activate: function( event, ui ) {return false;},
drop: function( event, ui ) {
let source_offset = ui.draggable.parent().offset();
let destination_offset = $(this).offset();
$(this)
.append(ui.draggable);
ui.draggable
.css('top', parseInt(ui.draggable.css('top')) + parseInt(source_offset.top) - parseInt(destination_offset.top))
.css('left', parseInt(ui.draggable.css('left')) + parseInt(source_offset.left) - parseInt(destination_offset.left));
console.log(ui.draggable.css('top'), ui.draggable.css('left'));
$('.card, .box').droppable('enable');
$('.card:has(*), .box:has(*)').droppable('disable');
},
});
$('.card, .box').droppable('enable');
$('.card:has(*), .box:has(*)').droppable('disable');
});
</script>
</head>
<body>
<div id='box1' class='box'>
</div>
<div id='box2' class='box'>
</div>
</body>
</html>
As you can see, when you drop a card on the other stack, the revert options move the card to the original position relative to the parent. As this offset change on different stack, I would like to be able to modify this originalPosition when the droppable stack is determined. Can you help me ?
I have a problem with input "range" and OSM Buildings for leaflet maps. I used basic example from official example which works fine but if I add jquery mobile to <head> section it breaks the range input. It's strange... I was using jquery mobile input to change the leaflet map opacity and it's working. Here is my basic example:
var map = new L.Map('map');
map.setView([52.52111, 13.40988], 16, false);
new L.TileLayer('http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
attribution: 'osm.org',
maxZoom: 18,
maxNativeZoom: 20
}).addTo(map);
var osmb = new OSMBuildings(map).load();
//************************************************************
var now,
date, time,
timeRange, dateRange,
timeRangeLabel, dateRangeLabel;
function changeDate() {
var Y = now.getFullYear(),
M = now.getMonth(),
D = now.getDate(),
h = now.getHours(),
m = 0;
timeRangeLabel.innerText = pad(h) + ':' + pad(m);
dateRangeLabel.innerText = Y + '-' + pad(M+1) + '-' + pad(D);
osmb.date(new Date(Y, M, D, h, m));
}
function onTimeChange() {
now.setHours(this.value);
now.setMinutes(0);
changeDate();
}
function onDateChange() {
now.setMonth(0);
now.setDate(this.value);
changeDate();
}
function pad(v) {
return (v < 10 ? '0' : '') + v;
}
timeRange = document.getElementById('time');
dateRange = document.getElementById('date');
timeRangeLabel = document.querySelector('*[for=time]');
dateRangeLabel = document.querySelector('*[for=date]');
now = new Date;
changeDate();
// init with day of year
var Jan1 = new Date(now.getFullYear(), 0, 1);
dateRange.value = Math.ceil((now-Jan1)/86400000);
timeRange.value = now.getHours();
timeRange.addEventListener('change', onTimeChange);
dateRange.addEventListener('change', onDateChange );
timeRange.addEventListener('input', onTimeChange);
dateRange.addEventListener('input', onDateChange);
body {
font-family: sans-serif;
padding: 5px;
margin: 0;
}
#map {
width: 300px;
height: 300px;
float: left;
margin: 0 15px 0 0;
}
label {
height: 20px;
}
<!DOCTYPE html>
<html >
<head>
<meta charset="UTF-8">
<title>Shadows</title>
<script src='http://cdn.leafletjs.com/leaflet-0.7.3/leaflet.js'></script>
<link rel="stylesheet" href="http://code.jquery.com/mobile/1.4.5/jquery.mobile-1.4.5.min.css">
<script src="http://code.jquery.com/jquery-1.11.3.min.js"></script>
<script src="http://code.jquery.com/mobile/1.4.5/jquery.mobile-1.4.5.min.js"></script>
<script src='http://cdn.osmbuildings.org/OSMBuildings-Leaflet.js'></script>
<link rel='stylesheet prefetch' href='http://cdn.leafletjs.com/leaflet-0.7.3/leaflet.css'>
</head>
<body>
<div id="map"></div>
<br><br><br><br><br><br><br><br><br><br><br><br><br><br><br>
<input id="date" type="range" min="1" max="365" step="1"><label for="date"></label><br>
<input id="time" type="range" min="0" max="23" step="1"><label for="time"></label>
</body>
</html>
For jQuery Mobile rangesliders you may use:
$(document).on("pagecreate", "#page-1", function() {
$("#date").on("change", onDateChange);
$("#time").on("change", onTimeChange);
});
Codepen: http://codepen.io/anon/pen/gLJRXb
I have a major issue with apache cordova. This is an iOS-specific issue. I am using jQuery-mobile. The issue appears whenever one does a search on a listview control then my fixed position header, footer and search input moves down.
Here is the markup of my page.
<!DOCTYPE HTML>
<html>
<head>
<title>Contacts</title>
<meta charset="utf-8" />
<meta name="format-detection" content="telephone=no" />
<meta name="msapplication-tap-highlight" content="no" />
<meta name="viewport" content="user-scalable=no, initial-scale=1, maximum-scale=1, minimum-scale=1, width=device-width, height=device-height" />
<link href="css/jquery.mobile-1.4.5.min.css" rel="stylesheet" />
<link href="css/jquery.mobile.icons.min.css" rel="stylesheet" />
<link href="css/jquery-ui.min.css" rel="stylesheet" />
</head>
<body>
<style>
#my-wrapper
{
padding-top: 81px;
background-color: rgb(250, 246, 246);
}
#my-wrapper form {
position: fixed;
left: 2%;
right :2%;
top: 35px;
width: 96%;
z-index: 2;
background-color: rgb(250, 246, 246);
border-color : rgb(120, 120, 120);
text-shadow:unset;
box-shadow:unset;
}
#ContactHeader
{
position: fixed;
top: 0px;
width: 100%;
z-index: 1;
}
</style>
<div id="employeeListPage" data-role="page" >
<div id="ContactHeader" data-role="header" style="height:32px ; ">
<a class="ui-btn-left" data-icon="arrow-l" href="#" onclick="window.location.replace('index.html');" style="vertical-align:text-top; height:8px"></a>
<h2>Contacts</h2>
</div>
<div id="my-wrapper" data-role="main">
<ul id="employeeList" data-role="listview" data-inset="true" data-filter="true" data-filter-theme="staticscroll" data-filter-placeholder="Search Contacts/Companies" ></ul>
</div>
<div data-role="footer" style="text-align:center; width: 100%;height: 25px;position:fixed;bottom: 0px;left: 0px;right: 0px;">My footer</div>
<div id="loadmoreajaxloader" style="display:none;"><center><img src="css/images/bw-loader.GIF" /></center></div>
</div>
<script type="text/javascript" src="cordova.js"></script>
<script src="js/jquery.js" type="text/javascript"></script>
<script src="js/jquery.mobile-1.4.5.min.js"></script>
<script src="js/contactlist.js"></script>
</body>
</html>
I also have an event that fire when a user starts typing in the search bar
$(document).on("pagecreate", "#employeeListPage", function () {
$("#employeeList").on("filterablebeforefilter", function (e, data) {
var URL = window.localStorage.getItem("ContactsForSearch");
URL = URL + '/' + nextNo + '/' + value;
$.getJSON(URL, function (info) {
if (info.length === 0) {
nomoredata = true;
//alert('no more data to display');
$('#employeeList').append('<br>');
$('#employeeList').append('<center><h2>No Data <h2> </center>');
}
else {
$('#employeeList').append('<li style="border-top: 1px solid #0189D0;"><a data-transition="slide" href="employeedetails.html?id=' + id + '&comnum=' + comNum + '&contactNum=' + contactNumber + '"><h2>' + companyName + '</h2> <small>' + name + ' - ' + designation + '</small>' + '</a>' + '</li>');
}
});
});
});
Whenever you search from the top of the list:
If you are scrolling down and you start to type in the search bar , this happens...These screenshots were taken from xcode’s emulator , on the phone it has the same result except it has a keyboard popping up at the bottom:
This would solve the problem with scrolling headers:
if (window.cordova.plugins.Keyboard) {
cordova.plugins.Keyboard.hideKeyboardAccessoryBar(true);
cordova.plugins.Keyboard.disableScroll(true);
}
unfortunately it removes the "done" button too!!!
I use Phaser to create a game but I found an problem for using it in for example facebook. When an redirect is done within an iframe the canvas is not responding after a click.
Example:
I have a IFrame and within the iframe I redirect to the game.html. When I click in the game.html everything freezes.
Everything works fine when using a computer (any browser), windows phone or android, but with an iphone or ipad it won't work.
Below are the example files to replay the problem...
index.html:
<html>
<body>
<iframe src="click.html" height="900" width="800"/>
</body>
</html>
click.html
<!DOCTYPE html>
<html>
<body>
CLICK HERE
</body>
</html>
Game.html
<!DOCTYPE html>
<html>
<head>
<style>
body{overflow:hidden;}
#game_div {
width: 760px;
height: 1100px;
margin: auto;
}
</style>
<script type="text/javascript" src="./Game/phaser.min.js"></script>
<script type="text/javascript" src="./Game/main.js"></script>
</head>
<body>
<div id="game_div"> </div>
</body>
</html>
main.js
var game = new Phaser.Game(760, 1100, Phaser.AUTO, 'game_div');
var overlay, countdownText;
var counter = 0;
var main_state = {
preload: function() {
},
create: function () {
//game overlay
overlay = game.add.graphics(0, 0);
overlay.beginFill(0x00A54F, 0.8);
overlay.drawRect(0, 0, game.width, game.height);
countdownText = game.add.text((game.width / 2), (game.height / 2), counter, { font: "65px Arial", fill: "#ffffff", align: "center" });
countdownText.anchor.set(0.5,0.5);
},
update: function() {
countdownText.setText(counter++);
}
}
game.state.add('main', main_state);
game.state.start('main');
TNX
Found the solution, with thanks to Rich Davey.
When I add the following code it works:
game.stage.disableVisibilityChange = true;
when i click the add image button a new image appears
when i click the new image can i revert it back to my previous state using jquery...showing the previous image with add image on hover
http://jsfiddle.net/6MmMe/37/
providing my js code below
$("div").hover(
function () {
$("<div>add image</div>").click(function() {
$(this).parent().unbind("hover").children("img").attr("src", "http://www.onlinegrocerystore.co.uk/images/goodfood.jpg");
$(this).remove();
}).appendTo(this);
},
function () {
$(this).find("div:last").remove();
}
);
The problem is that you are handling the first div, then removing it. There are a few ways to accomplish what I think are your goals.
I would recommend doing it with hide/show for easier management.
If you want to do this in jQuery, you can do it like this:
<!DOCTYPE html>
<html>
<head><script type='text/javascript' src='http://code.jquery.com/jquery-1.8.2.js'></script>
<style type='text/css'>
div div { color:red; display:none}
</style>
<script>
$(function(){
$('body > div').hover(function(){
// show "add image"
$('div', this).show();
}, function(){
// hide "add image" and reet image src.
$('div', this).hide();
$('img', this).attr("src", "http://imgs.zinio.com/magimages/500299032/2012/416238969_170.jpg");
})
// top-level click handler
.click(function(){
$('img', this).attr("src", "http://www.onlinegrocerystore.co.uk/images/goodfood.jpg");
});
});
</script>
</head>
<body>
<div>
<img src="http://imgs.zinio.com/magimages/500299032/2012/416238969_170.jpg" alt="Nov-12" title="Food Network Magazine" class="cover">
<div href="#">add image</div>
</div>
</body>
</html>
If you want to do this mostly in CSS, just toggling a class with jQuery, you can do this:
<!DOCTYPE html>
<html>
<head><script type='text/javascript' src='http://code.jquery.com/jquery-1.8.2.js'></script>
<style type='text/css'>
body > div {
background-image: url(http://imgs.zinio.com/magimages/500299032/2012/416238969_170.jpg);
width: 170px;
height:222px;
position:relative;
}
body > div.newImage:hover {
background-image: url(http://www.onlinegrocerystore.co.uk/images/goodfood.jpg);
width: 249px;
height:274px;
}
div div {
color:red;
position:absolute;
bottom:0;
margin-bottom:-16px;
display:none;
}
div:hover div {
display:block;
}
</style>
<script>
$(function(){
$('body > div').click(function(){
$(this).addClass('newImage');
}).hover(false, function(){
$(this).removeClass('newImage');
});
});
</script>
</head>
<body>
<div>
<div>add image</div>
</div>
</body>
</html>
If you really prefer to add/remove things, you can do it like this:
<!DOCTYPE html>
<html>
<head><script type='text/javascript' src='http://code.jquery.com/jquery-1.8.2.js'></script>
<style type='text/css'>
div div { color:red;}
</style>
<script>
$(function(){
$('body > div').hover(function(){
// show "add image"
$(this).append('<div>add image</div>');
}, function(){
// hide "add image" and reset image src.
$('div', this).remove();
$('img', this).attr("src", "http://imgs.zinio.com/magimages/500299032/2012/416238969_170.jpg");
})
// top-level click handler
.click(function(){
$('img', this).attr("src", "http://www.onlinegrocerystore.co.uk/images/goodfood.jpg");
});
});
</script>
</head>
<body>
<div>
<img src="http://imgs.zinio.com/magimages/500299032/2012/416238969_170.jpg" alt="Nov-12" title="Food Network Magazine" class="cover">
</div>
</body>
</html>