I want to make a pop-up on a mapbox marker responsive when veiwing on mobile devices - popup

I am making a map on mapbox which has markers imported from a data set. THe markers have a pop up which works perfectly on desktop but when viewing on mobile it bleeds off the edges of the screen. Below is the code I used to create this pop-up. how can I make this pop up change size when switching to mobile or adapt the size depending on the display screen?
map.on('click', function(e) {
var features = map.queryRenderedFeatures(e.point, {
layers: ['American Eats'] // replace this with the name of the layer
});
if (!features.length) {
return;
}
var feature = features[0];
var popup = new mapboxgl.Popup({ offset: [0, -15] })
.setLngLat(feature.geometry.coordinates)
.setHTML('<h3>' + feature.properties.Title + '</h3><h4>' + feature.properties.Adress + '</h4><p>' + feature.properties.Description + '</p>')
.setLngLat(feature.geometry.coordinates)
.addTo(map);
});

It's easy to do this using CSS. Something along these lines:
#media only screen and (max-width: 480px) {
.mapboxgl-popup-content {
max-width: 250px;
}
.mapboxgl-popup-content div {
padding:0em;
}
.mapboxgl-popup-content p {
margin: 0.5em 0.5em;
}
}
Adjust whatever settings you need in order to keep the popup small. I use this approach at the Hipster Map of Melbourne - try it with a very small browser window and see how the popups shrink.

Related

Leaflet Draw preventing click on elements while is active

I have several days fighting this with no luck. I'm using leaflet 1.4.0 along with leaflet.draw 1.0.4. Instead of using the L.control.draw UI, I'm using my own buttons to create polygons and rectangles. It works perfectly on desktop browsers (except IE, of course), but fails on iPads, Android tablets (I've not checked on phones), even if you switch the latest Chrome to emulate a mobile device (using the 'toogle device toolbar' on the dev tools) it fails.
I have created this jsfiddle to illustrate the problem: https://jsfiddle.net/fsv8jegd/2/
Using Chrome with the 'toggle device' off, click on the 'start poly' button. Cursor changes to a cross and a label 'click and drag to draw rectangle'. Click on the 'cancel' button, the cursor goes back to the regular arrow.
Now turn on 'toggle device' on Chrome dev tools and choose 'responsive' or any of the 'iPhone' or 'iPads'. Click on the 'start poly' button. Cursor changes to the cross. Try to click on the 'cancel' button. Nothing happens. It doesn't receive the click event. The only way to cancel this is actually drawing the rectangle.
Any ideas?
Thanks!
html:
<div id="map"> </div>
<button class='buttons' type="button" style="top:0" onclick="startpoly()">START POLY</button>
<button class='buttons' type="button" style="top:20px" onclick="cancelpoly()">CANCEL</button>
css:
#map { height: 200px !important; width: 80%; }
.buttons {position: absolute; left: 0; z-index: 999999}
JS:
polygon_query_options = { shapeOptions: { stroke: true, color: '#6e83f0', weight: 4, opacity: 0.9, fill: true, fillColor: null, fillOpacity: 0.2, clickable: false, dashArray: '10,10' } };
$(document).ready(function() {
map = L.map('map', { preferCanvas: true, zoomControl: true, zoom: 10, maxZoom: 20, center: [29.8, -95.5]});
var drawnItems = new L.FeatureGroup();
drawnItems.addTo(map);
drawnItems.bringToFront();
L.Browser.touch = true;
var baseMapGroup = new L.featureGroup();
basemapLayer = L.tileLayer('https://cartodb-basemaps-d.global.ssl.fastly.net/rastertiles/voyager_nolabels/{z}/{x}/{y}.png', { attribution: 'CartoDB', maxZoom: 20, maxNativeZoom: 20 });
basemapLabelLayer = L.tileLayer('https://cartodb-basemaps-d.global.ssl.fastly.net/rastertiles/voyager_only_labels/{z}/{x}/{y}.png', { attribution: 'CartoDB', maxZoom: 20, maxNativeZoom: 20 });
basemapLabelLayer.addTo(map);
basemapLabelLayer.bringToBack();
basemapLayer.addTo(map);
basemapLayer.bringToBack();
map.on('draw:created', function (e) {
var layer = e.layer;
drawnItems.addLayer(layer);
});
});
function startpoly() {
polygonDrawer = new L.Draw.Rectangle(map, polygon_query_options);
polygonDrawer.enable();
};
function cancelpoly() {
if (polygonDrawer != undefined) { polygonDrawer.disable(); }
};
I found this is a bug on the leaflet.draw library. So I followed the trail, and in the line 1260 of the leaflet.draw 1.0.4 the following code causes the problem:
document.addEventListener('touchstart', L.DomEvent.preventDefault, { passive: false });
I replaced that line with this code:
var tempMap = document.getElementById("map");
tempMap.addEventListener('touchstart', L.DomEvent.preventDefault, { passive: false });
Basically instead of preventing the touchstart event on the document, now is applied only to the map object.
Hope this helps anyone out there.

Leaflet.js: Use ctrl + scroll to zoom the map & Move map with two fingers on mobile

I'm using http://leafletjs.com/ ... is it possible to only:
Use ctrl + scroll to zoom the map
Move map with two fingers on mobile/tablet
... so similar what google maps does? With the comments ...
So far thats my setup:
// Leaflet Maps
var contactmap = L.map('contact-map', {
center: [41.3947688, 2.0787279],
zoom: 15,
scrollWheelZoom: false
});
There is an amazing library that does exactly that. Leaflet.GestureHandling
It is an add on to leaflet that works right of the box, it's also modular and can be installed using npm.
Here's a working example using leaflet and GestureHandling.
You can try it also on mobile.
P.S. It has multiple languages baked in:)
// Attach it as a handler to the map
const map = L.map('map', {
gestureHandling: true
}).setView([51.505, -0.09], 13);
// Add tile layer
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
attribution: '© OpenStreetMap contributors'
}).addTo(map);
#map {
height: 400px;
width: 400px;
}
<link rel="stylesheet" href="https://unpkg.com/leaflet#1.4.0/dist/leaflet.css"
integrity="sha512-puBpdR0798OZvTTbP4A8Ix/l+A4dHDD0DGqYW6RQ+9jxkRFclaxxQb/SJAWZfWAkuyeQUytO7+7N4QKrDh+drA=="
crossorigin=""/>
<link rel="stylesheet" href="//unpkg.com/leaflet-gesture-handling/dist/leaflet-gesture-handling.min.css"
type="text/css">
<script src="https://unpkg.com/leaflet#1.4.0/dist/leaflet.js"
integrity="sha512-QVftwZFqvtRNi0ZyCtsznlKSWOStnDORoefr1enyq5mVL4tmKB3S/EnC3rRJcxCPavG10IcrVGSmPh6Qw5lwrg=="
crossorigin=""></script>
<script src="//unpkg.com/leaflet-gesture-handling"></script>
<div id="map"></div>
zoom map using ctrl + zoom. I did in custom way .
html code is below
<div id="map"></div>
css
.map-scroll:before {
content: 'Use ctrl + scroll to zoom the map';
position: absolute;
top: 50%;
left: 50%;
z-index: 999;
font-size: 34px;
}
.map-scroll:after {
position: absolute;
left: 0;
right: 0;
bottom: 0;
top: 0;
content: '';
background: #00000061;
z-index: 999;
}
jQuery
//disable default scroll
map.scrollWheelZoom.disable();
$("#map").bind('mousewheel DOMMouseScroll', function (event) {
event.stopPropagation();
if (event.ctrlKey == true) {
event.preventDefault();
map.scrollWheelZoom.enable();
$('#map').removeClass('map-scroll');
setTimeout(function(){
map.scrollWheelZoom.disable();
}, 1000);
} else {
map.scrollWheelZoom.disable();
$('#map').addClass('map-scroll');
}
});
$(window).bind('mousewheel DOMMouseScroll', function (event) {
$('#map').removeClass('map-scroll');
})
In simple way when user scroll on map then detect ctrl button is pressed or not then just I add one class that will showing message on map. and prevent screen zoom-in and zoom-out outside of map.
I managed to solve your second problem.
I used css for displaying the message using a ::after pseudo selector.
#map {
&.swiping::after {
content: 'Use two fingers to move the map';
}
}
And javascript to capture the touch events.
mapEl.addEventListener("touchstart", onTwoFingerDrag);
mapEl.addEventListener("touchend", onTwoFingerDrag);
function onTwoFingerDrag (e) {
if (e.type === 'touchstart' && e.touches.length === 1) {
e.currentTarget.classList.add('swiping')
} else {
e.currentTarget.classList.remove('swiping')
}
}
It checks if the type is a touchevent and if you are using 1 finger, if so it adds the class to the map with the message. If you use more than one finger it removes the class.
Working demo I suggest you using a mobile device.
Code pen from the demo

How can I add an icon to switch the mapboxgl style dynamically?

I want to add an icon as below in the mapboxgl view. Working with Angular2
When I click the icon it should automatically switch the styles (streets-v9, satelllite-v9)
I am following the link mapboxgl example
Did you see this API method?
https://www.mapbox.com/mapbox-gl-js/api/#map#setstyle
With that you can set a new style for the map when you e.g. click an icon or press a button or what ever you wish.
Take this as a reference to build upon:
https://jsfiddle.net/andi_lo/706pot8L/
mapboxgl.accessToken = 'pk.eyJ1IjoiZmFyYWRheTIiLCJhIjoiTUVHbDl5OCJ9.buFaqIdaIM3iXr1BOYKpsQ';
let map = new mapboxgl.Map({
container: 'map',
style: 'mapbox://styles/mapbox/streets-v9',
center: [-1.77, 52.73],
zoom: 3,
});
let icon = document.getElementById('icon');
icon.addEventListener('click', function(e) {
map.setStyle('mapbox://styles/mapbox/light-v9');
}, false)
#icon {
position: absolute;
top: 15px;
left: 15px;
color: black;
}
#map {
height: 500px;
}
<link href="https://api.tiles.mapbox.com/mapbox-gl-js/v0.38.0/mapbox-gl.css" rel="stylesheet"/>
<script src="https://api.tiles.mapbox.com/mapbox-gl-js/v0.38.0/mapbox-gl.js"></script>
<div id="map"></div>
<button id="icon">
Switch layers
</button>
What you want is a "control" that switches layers. Mapbox-GL-JS doesn't include such a thing, nor is there one listed as a plugin (yet).
You should use Mapbox-GL-JS's iControl class to create the control, then add styling and behaviour following Mapbox's instructions:
function LayerSwitchControl() { }
LayerSwitchControl.prototype.onAdd = function(map) {
this._map = map;
this._container = document.createElement('div');
this._container.className = 'mapboxgl-ctrl';
// change this next line to include a layer-switching icon
this._container.textContent = 'Hello, world';
return this._container;
};
LayerSwitchControl.prototype.onRemove = function () {
this._container.parentNode.removeChild(this._container);
this._map = undefined;
};
You'll then need to add code to:
Add the control
Respond to click events as appropriate.
This is my working code,
This is zoom level control

infoWindow in google map not showing properly in an iPhone phonegap app

I am showing custom marker with click event on it. It shows information when I clicked but the info window is not showing well. I used some css in it. I also need to customize it further. This map is shown in phonegap app in iPhone (iOS 5). Every other thing working find (including direction, GPS).
I have used google map js v3 API.
I got this output.
How to show correct infoWindow? And customize as my need.
here is the code
function setMap(myLat, myLng){
// Define Marker properties
var image = new google.maps.MarkerImage('images/pick.png',
new google.maps.Size(30, 40),
// The origin for this image is 0,0.
new google.maps.Point(0,0),
// The anchor for this image is the base of the flagpole at 9,36.
new google.maps.Point(9, 36)
);
var my_place = new google.maps.LatLng(myLat, myLng);
var myOptions = {
zoom:14,
mapTypeId: google.maps.MapTypeId.ROADMAP,
mapTypeControl: false,
center: my_place
}
mer_map = new google.maps.Map(document.getElementById("mer_map_canvas"), myOptions);
mer_marker = new google.maps.Marker({
position: my_place,
map: mer_map,
clickable : true,
animation: google.maps.Animation.DROP,
icon: image
});
var contentString = '<div id="mer_map_info" style="border:3px solid red; color:#FFF; background-color:#000;"><p>this is just a test...</p></div>';
var infowindow = new google.maps.InfoWindow({
content: contentString
});
google.maps.event.addListener(mer_marker, 'click', function(event) {
infowindow.open(mer_map,mer_marker);
});}
Give this a try. I had a similar problem with phonegap and google maps.
#map_canvas img {
max-width: none;
}

Fancybox Positioning Inside Facebook Canvas iFrame

OK so I have a iframe canvas app with its height set to "Settable" with the facebook javascrip sdk calls to FB.Canvas.setSize(); and FB.Canvas.setAutoGrow();. These are working perfectly, as the iframe gets set to a certain pixel height based on its content.
The problem is that when I make a call to Fancybox, it positions itself based on this height. I know that's exactly what its supposed to do as the fancybox jQuery returns the viewport by:
(line 673 of latest version of jquery.fancybox-1.3.4.js):
_get_viewport = function() {
return [
$(window).width() - (currentOpts.margin * 2),
$(window).height() - (currentOpts.margin * 2),
$(document).scrollTop() + currentOpts.margin
];
},
But the problem is the iframe will, for a lot of viewers, be longer than their browser window. So the Fancybox centers itself in the iframe and ends up only partly visible to the majority of viewers. (i.e. iframe height is 1058px and users browser is say only 650px).
Is there a way to have fancybox just calculate the physical browser height? Or do I need to change some settings in my Facebook canvas app to make it work?
I like how the only scrollbar is the one on Facebook (the parent, if you will).
All suggestions GREATLY appreciated!
For fancybox 2 try:
find:
_start: function(index) {
and replace with:
_start: function(index) {
if ((window.parent != window) && FB && FB.Canvas) {
FB.Canvas.getPageInfo(
function(info) {
window.canvasInfo = info;
F._start_orig(index);
}
);
} else {
F._start_orig(index);
}
},
_start_orig: function (index) {
Then in function getViewport replace return rez; with:
if (window.canvasInfo) {
rez.h = window.canvasInfo.clientHeight;
rez.x = window.canvasInfo.scrollLeft;
rez.y = window.canvasInfo.scrollTop - window.canvasInfo.offsetTop;
}
return rez;
and finally in _getPosition function replace line:
} else if (!current.locked) {
with:
} else if (!current.locked || window.canvasInfo) {
As facebook js api provides page info, then we could use it, so
find
_start = function() {
replace with
_start = function() {
if ((window.parent != window) && FB && FB.Canvas) {
FB.Canvas.getPageInfo(
function(info) {
window.canvasInfo = info;
_start_orig();
}
);
} else {
_start_orig();
}
},
_start_orig = function() {
and also modify _get_viewport function
_get_viewport = function() {
if (window.canvasInfo) {
console.log(window.canvasInfo);
return [
$(window).width() - (currentOpts.margin * 2),
window.canvasInfo.clientHeight - (currentOpts.margin * 2),
$(document).scrollLeft() + currentOpts.margin,
window.canvasInfo.scrollTop - window.canvasInfo.offsetTop + currentOpts.margin
];
} else {
return [
$(window).width() - (currentOpts.margin * 2),
$(window).height() - (currentOpts.margin * 2),
$(document).scrollLeft() + currentOpts.margin,
$(document).scrollTop() + currentOpts.margin
];
}
},
I had the same problem, i used 'centerOnScroll' :true, and now it works fine...
Had the same problem. Thankfully fancybox is accessable through CSS. My solution was to overwrite fancybox's positioning in my CSS file:
#fancybox-wrap {
top: 20px !important;
}
This code places the fancybox always 20px from top of the iframe. Use a different size if you like. The !important sets this positioning even though fancybox sets the position dynamically at runtime.
Here's one way to do it by positioning the Fancybox relative to the position of another element, in my case an Uploadify queue complete div that displays a view link after the user uploads an image.
Have a style block with a set ID like so:
<style id="style-block">
body { background-color: #e7ebf2; overflow: hidden; }
</style>
Then the link to open the Fancybox calls a function with the image name, width, and height to set the content and sizes. The important part is the positioning. By getting the position of the queue complete div, generating a new class declaration (fancy-position), appending it to the style block BEFORE the fancybox loads (!important in class will override positioning from fancybox), then adding the new class using the wrapCSS parameter in the fancybox options, it positions the fancybox exactly where I want it.
function viewImage(image, width, height) {
var complete_pos = $('#image_queue_complete').position();
var css_code = '.fancy-position { top: ' + complete_pos.top.toString() + 'px !important; }';
$('#style-block').append(css_code);
var img_src = '<img src="images/' + image + '" width="' + width.toString() + '" height="' + height.toString() + '" />';
$.fancybox({
content: img_src,
type: 'inline',
autoCenter: false,
wrapCSS: 'fancy-position'
});
}