Mapbox fitbounds() - Invalid LngLat object: (NaN, NaN) - mapbox

I have been banging my head against the desk for the last few hours.
I am trying to get Mapbox to zoom in on load to the bounding area of all my markers.
However, this is the error I am getting for the code below.
This error comes after the console log image below, so the lat lng coordinates are definitely there.
Uncaught Error: Invalid LngLat object: (NaN, NaN)
const onLoad = () => {
let points = [];
props.cats.forEach(cat => (
points.push([ cat.lat, cat.lng ])
));
points.length > 0 && ref.current.getMap().fitBounds(points, {
padding: { top: 50, bottom: 50, left: 50, right: 50 },
easing(t) {
return t * (2 - t);
},
});
};

If you have more than a pair of coordinates, you should first reduce the array with coordinates.reduce, and then define the bounds through new mapboxgl.LngLatBounds. After that you can fly with map.fitBounds to the bounds, defining your favorite padding and easing function as you did in your code.
var coordinates = points;
var bounds = coordinates.reduce(function(bounds, coord) {
return bounds.extend(coord);
}, new mapboxgl.LngLatBounds(coordinates[0], coordinates[0]));
map.fitBounds(bounds, {
padding: { top: 50, bottom: 50, left: 50, right: 50 },
easing(t) {
return t * (2 - t);
}
});
I have prepared this fiddle with the solution how to fit bounds to a list of coords with an array of 3 coords, but you can apply easily to yours.
And this is the result
Then tap on Zoom to bounds

In my case, I was getting the same error when the padding value was high.
//this did not work
map.fitBounds(fitBounds, {padding: 150});
//this worked
map.fitBounds(fitBounds);

For the fitBounds() function you will need to pass your bounds as a LngLatBounds object, an array of LngLatLike objects in [South West, North East] order, or an array of numbers in [west, south, east, north] order. Mapbox has an example of this on their website here.
If you want to capture all of your markers you could calculate the most western, southern, eastern, and northern values of your coordinates and then pass them as an array. In your case: [-0.54664079, 51.38542169, -0.3735228, 51.45368209].
mapboxgl.accessToken = 'pk.eyJ1IjoicGxtYXBib3giLCJhIjoiY2s3MHkzZ3VnMDFlbDNmbzNiajN5dm9lOCJ9.nbbtDF54HIXo0mCiekVxng';
var map = new mapboxgl.Map({
container: 'map',
style: 'mapbox://styles/mapbox/streets-v11',
center: [-74.5, 40],
zoom: 9
});
document.getElementById('fit').addEventListener('click', function() {
map.fitBounds([-0.54664079, 51.38542169, -0.3735228, 51.45368209]);
});
body { margin: 0; padding: 0; }
#map { position: absolute; top: 0; bottom: 0; width: 100%; }
#fit {
display: block;
position: relative;
margin: 0px auto;
width: 50%;
height: 40px;
padding: 10px;
border: none;
border-radius: 3px;
font-size: 12px;
text-align: center;
color: #fff;
background: #ee8a65;
}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Fit a map to a bounding box</title>
<meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no" />
<script src="https://api.mapbox.com/mapbox-gl-js/v1.11.1/mapbox-gl.js"></script>
<link href="https://api.mapbox.com/mapbox-gl-js/v1.11.1/mapbox-gl.css" rel="stylesheet" />
</head>
<body>
<div id="map"></div>
<br />
<button id="fit">Fit to Box</button>
</body>
</html>

I don't know this is relevant with your problem but when I get this error in mobile browsers on my map work, I solved problem with this code:
if (/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|OperaMini/i.test(navigator.userAgent)) {
$('#mapContainer').css({ 'width': (($(window).width())) + 'px' });
}
#mapContainer width was 100% on default.

one option is to find the maximum lng and lat for north east and minimum lng and lat for south west like
function buildBounds(cords) {
const allLats = [];
const allLngs = [];
cords.forEach((cord) => {
allLats.push(cord.lat);
allLngs.push(cord.lng);
});
const ne = [Math.max(...allLngs), Math.max(...allLats)];
const sw = [Math.min(...allLngs), Math.min(...allLats)];
console.log(ne, sw);
return [sw, ne];
}

Related

Showing a leaflet portion centered on latitude/longitute coordinates [duplicate]

Please how can we set the map div to be height: 100% of its container?
I have tried this within a bootstrap template content section, but all I get is height of 0px. Even Google-Dev tools shows #map height as 0px.
body {
padding: 0;
margin: 0;
}
html, body, #map {
height: 100%;
}
Set
#map{
position: absolute;
top: 0;
bottom: 0;
width: 100%;
}
and give its container position: relative.
The above answer didn't work for me, but this did:
body {
padding: 0;
margin: 0;
}
html, body, #map {
height: 100%;
width: 100%;
}
..from A full screen leaflet.js map
Leaflet needs an absolute height, and height: 100% only refers to the height of the parent element - if this isn't set, it will default to 0.
If your map is the only element in the body, use height: 100vh to match the height of the viewport (Example).
If your map is inside a container, set height: 100vh on the container (or other desired height) and height: 100% on the map element (Example).

hide search box in iframe MapBox embedded map

I successfully followed the MapBox iframe tutorial (https://docs.mapbox.com/help/glossary/iframe/) to add a map in my website, now I need to hide the search box from the map, I suppose there is some additional parameter to add in the string but can't figure out how.
Thanks for the help.
this is the map with the search box that I need to hide
there is no Parameter to hide or show map-control box in case of iframe , i suggest use javascript Api to access a lot of parameters to control your embeded map
important : revoke your access token , because you should not public your secret keys
mapboxgl.accessToken = 'pk.eyJ1IjoiYXZpb3BvcnRvbGFubyIsImEiOiJja212cmRrd2QwN3dzMnZuMXV2d25xbWsxIn0.x3y36v9arY9wmBOCZlCXUA#15/37.771/-122.436';
var map = new mapboxgl.Map({
container: 'map', // container id
style: 'mapbox://styles/mapbox/streets-v11', // style URL
center: [-74.5, 40], // starting position [lng, lat]
zoom: 9 // starting zoom
});
body { margin: 0; padding: 0; }
#map { position: absolute; top: 0; bottom: 0; width: 100%; }
<link href="https://api.mapbox.com/mapbox-gl-js/v2.2.0/mapbox-gl.css" rel="stylesheet">
<script src="https://api.mapbox.com/mapbox-gl-js/v2.2.0/mapbox-gl.js"></script>
<div id="map"></div>

Using leaflet.FreeDraw with leaflet.path.drag

I am wondering if it's possible to use Leaflet.FreeDraw with leaflet.path.drag to be able to drag the polygon created by FreeDraw plugin.
jsfiddle
I tried to enable dragging plugin like this, but it doesn't work.
const map = new L.Map(document.querySelector('section.map'), { doubleClickZoom: false }).setView(LAT_LNG, 14);
L.tileLayer(TILE_URL).addTo(map);
const freeDraw = new FreeDraw({ mode: FreeDraw.ALL });
map.addLayer(freeDraw);
freeDraw.dragging.enable();
You could extract the bounds from the FreeDraw by listening to the markers event to create a polygon or other map object using leaflet enabled with dragging. See working example below.
You should consider whether you would like to disable the FreeDraw after this, using the option leaveModeAfterCreate:true as the user may get additional polygons when dragging
const LAT_LNG = [51.505, -0.09];
const TILE_URL = 'https://cartodb-basemaps-a.global.ssl.fastly.net/light_all/{z}/{x}/{y}#2x.png';
const map = new L.Map(document.querySelector('section.map'), { doubleClickZoom: false }).setView(LAT_LNG, 14);
L.tileLayer(TILE_URL).addTo(map);
const freeDraw = new FreeDraw({
mode: FreeDraw.ALL,
leaveModeAfterCreate:true //recommended to prevent undesired creation of multiple polygons
});
map.addLayer(freeDraw);
//freeDraw.dragging.enable();
//STEP 1: Listen to markers event raised by free draw whenever edits (create/edit/deletions are made to the map)
freeDraw.on("markers",function(event){
//we are only interested in create events
//we aim to extract the bounds and remove the existing
// freedraw references. If it is that you would like your
// user to edit the polygon, then you may keep these and do the // additional work to manage and update these references
if(event.eventType=='create' && event.latLngs.length > 0){
//capture the current polygon bounds (store in 1st position)
var latLngs = event.latLngs[0];
freeDraw.clear(); //clear freedraw markers
//create polygon from lat lng bounds retrieved
var polygon = L.polygon(
latLngs.map(function(latLng){
return [latLng.lat,latLng.lng];
}), {
color: 'red',
draggable: true //make polygon draggable
}).addTo(map);
}
})
* {
padding: 0;
margin: 0;
box-sizing: border-box;
}
.map {
width: 100vw;
height: 100vh;
}
.map.mode-create {
cursor: crosshair;
}
.leaflet-edge {
background-color: #95bc59;
box-shadow: 0 0 0 2px white, 0 0 10px rgba(0, 0, 0, .35);
border-radius: 50%;
cursor: move;
outline: none;
transition: background-color .25s;
}
.leaflet-polygon {
fill: #b4cd8a;
stroke: #50622b;
stroke-width: 2;
fill-opacity: .75;
}
<link href="https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.0.2/leaflet.css" rel="stylesheet"/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.0.2/leaflet-src.js"></script>
<script src="https://rawgit.com/Wildhoney/Leaflet.FreeDraw/master/dist/leaflet-freedraw.iife.js"></script>
<script src="https://npmcdn.com/leaflet.path.drag/src/Path.Drag.js"></script>
<section class="map"></section>
NB. Also see working example on js-fiddle here https://jsfiddle.net/ytevLbgs/

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 to add axis title in Chartist

I'm using Chartist for browser visualization.
The requirement here is that I need to add title to the X and Y axis, so that viewers know what does each axis represent. However I went through the online document of Chartist and found no documentation about this. Did I miss something, or this feature is not supported in Chartist? If it's not supported, is there any way to work this out?
You can download and use the Axis Title Plugin developed by Alex Stanbury. This is the code you must add to your existing chart options.
plugins: [
Chartist.plugins.ctAxisTitle({
axisX: {
axisTitle: 'X title',
axisClass: 'ct-axis-title',
offset: {
x: 0,
y: 50
},
textAnchor: 'middle'
},
axisY: {
axisTitle: 'Y title',
axisClass: 'ct-axis-title',
offset: {
x: 0,
y: 0
},
textAnchor: 'middle',
flipTitle: false
}
})
]
I used css for this, try if this help you.
HTML:
<div id="chartist" class="chartist" data-x-axis="X axis label" data-y-axis="Y axis label"></div>
CSS:
[data-x-axis]::before {
content: attr(data-x-axis);
position: absolute;
width: 100%;
text-align: center;
left: 0;
bottom: 0;
font-size: 11px;
color: #777;
}
[data-y-axis]::after {
content: attr(data-y-axis);
position: absolute;
top: 50%;
left: -20px;
font-size: 11px;
color: #777;
text-align: center;
transform: rotate(-90deg)translateY(50%);
}
Titles are currently (June 2015) not supported.
The issue for this suggests that the Chartist authors want you to label the graph outside of Chartist but does include a way to do this in your HTML though with some notable caveats.