I'm using the open source Leaflet.js library to create a simple map.
I'm trying to solve a specific problem though. Markers are tied to a specific lat/lng on a map, which makes sense, but I need to be able to make a marker have a fixed offset position from another marker, without it being tied to a lat/lng center.
So for example, the map may look like this:
But when you zoom out, it'll look like this:
What I actually want is for the right marker to be a fixed offset away from the left marker, instead of being tied to a latlng, as such:
I've tried experimenting with unproject but I believe I'm going down the wrong path of how to handle this. It's unconventional what I'm doing but if anyone has any insight into how I could do this, it would be greatly appreciated.
In addition to project() and unproject() methods to calculate position of second marker you can also listen to zoom events on the map and update the position of the second marker in order to keep the desired distance in pixels.
Have a look at the following example.
var marker;
var pos = L.latLng(28.478226,-16.313488);
var mymap = L.map('mapid').setView(pos, 13);
L.tileLayer('https://api.tiles.mapbox.com/v4/{id}/{z}/{x}/{y}.png?access_token=pk.eyJ1IjoibWFwYm94IiwiYSI6ImNpejY4NXVycTA2emYycXBndHRqcmZ3N3gifQ.rJcFIG214AriISLbB6B5aw', {
maxZoom: 18,
attribution: 'Map data © OpenStreetMap contributors, ' +
'CC-BY-SA, ' +
'Imagery © Mapbox',
id: 'mapbox.streets'
}).addTo(mymap);
L.marker(pos).addTo(mymap);
setLinkedMarkerAtDistance(180);
mymap.on('zoomstart', function() {
if (marker) {
mymap.removeLayer(marker);
}
});
mymap.on('zoomend', function() {
setLinkedMarkerAtDistance(180);
});
function setLinkedMarkerAtDistance(d) {
var p = mymap.project(pos, mymap.getZoom());
var p1 = p.add(L.point(d,0));
var pos1 = mymap.unproject(p1, mymap.getZoom());
if (marker) {
marker.setLatLng(pos1).addTo(mymap);
} else {
marker = L.marker(pos1).addTo(mymap);
}
}
<link rel="stylesheet" href="https://unpkg.com/leaflet#1.3.4/dist/leaflet.css" integrity="sha512-puBpdR0798OZvTTbP4A8Ix/l+A4dHDD0DGqYW6RQ+9jxkRFclaxxQb/SJAWZfWAkuyeQUytO7+7N4QKrDh+drA==" crossorigin=""/>
<script src="https://unpkg.com/leaflet#1.3.4/dist/leaflet.js" integrity="sha512-nMMmRyTVoLYqjP9hrbed9S+FzjZHW5gY1TWCHA5ckwXZBadntCNs8kEqAWdrb9O7rxbCaA4lKTIWjDXZxflOcA==" crossorigin=""></script>
<div id="mapid" style="width: 600px; height: 400px;">
I hope this helps!
This sounds like an XY problem to me: you want to display some extra info (possibly looking similar to a normal Marker) next to a Marker A (with some pixels offset), and you try with another Marker B; but Marker B is tied to Lat/Lng coordinates instead of pixels offset, so you ask for help on how to use unproject.
To achieve your original objective, a Leaflet DivIcon would indeed have been a more appropriate solution: a part of the <div> would contain your actual Marker Icon, and another part would contain your extra info. That way, it always stays at the desired position, without having to compute any (un)projection and without any JS event listener involved:
var paris = [48.86, 2.35];
var map = L.map('map').setView(paris, 11);
var divIcon = L.divIcon({
html: `
<img src="https://unpkg.com/leaflet#1.3.4/dist/images/marker-icon.png" />
<div class="extra-info">
Some extra info
</div>
`,
className: 'my-div-icon',
iconAnchor: [12, 41]
});
L.marker(paris, {
icon: divIcon
}).addTo(map);
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
attribution: '© OpenStreetMap contributors'
}).addTo(map);
html,
body,
#map {
height: 100%;
margin: 0;
}
.extra-info {
position: absolute;
left: 188px;
bottom: -20px;
min-width: 120px;
background: yellow;
border: 1px solid red;
}
<link rel="stylesheet" href="https://unpkg.com/leaflet#1.3.4/dist/leaflet.css" integrity="sha512-puBpdR0798OZvTTbP4A8Ix/l+A4dHDD0DGqYW6RQ+9jxkRFclaxxQb/SJAWZfWAkuyeQUytO7+7N4QKrDh+drA==" crossorigin="" />
<script src="https://unpkg.com/leaflet#1.3.4/dist/leaflet-src.js" integrity="sha512-+ZaXMZ7sjFMiCigvm8WjllFy6g3aou3+GZngAtugLzrmPFKFK7yjSri0XnElvCTu/PrifAYQuxZTybAEkA8VOA==" crossorigin=""></script>
<div id="map"></div>
An even more appropriate solution would have been to use a Leaflet Tooltip, typically with your predefined offset, permanent: true option, a specific direction and custom styling (with className):
var paris = [48.86, 2.35];
var map = L.map('map').setView(paris, 11);
L.marker(paris).bindTooltip('Some extra info', {
offset: [188, 0],
className: 'my-tooltip',
permanent: true,
direction: 'right',
interactive: true
}).addTo(map);
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
attribution: '© OpenStreetMap contributors'
}).addTo(map);
html,
body,
#map {
height: 100%;
margin: 0;
}
.leaflet-tooltip.my-tooltip {
background-color: yellow;
border: 1px solid red;
box-shadow: none;
}
.leaflet-tooltip.my-tooltip::before {
content: none;
}
<link rel="stylesheet" href="https://unpkg.com/leaflet#1.3.4/dist/leaflet.css" integrity="sha512-puBpdR0798OZvTTbP4A8Ix/l+A4dHDD0DGqYW6RQ+9jxkRFclaxxQb/SJAWZfWAkuyeQUytO7+7N4QKrDh+drA==" crossorigin="" />
<script src="https://unpkg.com/leaflet#1.3.4/dist/leaflet-src.js" integrity="sha512-+ZaXMZ7sjFMiCigvm8WjllFy6g3aou3+GZngAtugLzrmPFKFK7yjSri0XnElvCTu/PrifAYQuxZTybAEkA8VOA==" crossorigin=""></script>
<div id="map"></div>
Then if you really want your extra info to be styled and manipulated like a normal Leaflet Marker, another possible solution would be to use a custom Marker with modified iconAnchor, to account for your desired pixel offset:
var paris = [48.86, 2.35];
var map = L.map('map').setView(paris, 11);
var OffsetIcon = L.Icon.Default.extend({
options: {
// Subtract your desired offset.
iconAnchor: [12 - 188, 41]
}
});
L.marker(paris).addTo(map);
L.marker(paris, {
icon: new OffsetIcon()
}).addTo(map);
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
attribution: '© OpenStreetMap contributors'
}).addTo(map);
html,
body,
#map {
height: 100%;
margin: 0;
}
<link rel="stylesheet" href="https://unpkg.com/leaflet#1.3.4/dist/leaflet.css" integrity="sha512-puBpdR0798OZvTTbP4A8Ix/l+A4dHDD0DGqYW6RQ+9jxkRFclaxxQb/SJAWZfWAkuyeQUytO7+7N4QKrDh+drA==" crossorigin="" />
<script src="https://unpkg.com/leaflet#1.3.4/dist/leaflet-src.js" integrity="sha512-+ZaXMZ7sjFMiCigvm8WjllFy6g3aou3+GZngAtugLzrmPFKFK7yjSri0XnElvCTu/PrifAYQuxZTybAEkA8VOA==" crossorigin=""></script>
<div id="map"></div>
Related
I want to display the tooltip centered (inside) of the marker.
Background
I want to display a count for each marker (first -> last) and I've found out I could do that with tooltip (Any better suggestions)
so my marker looks like this now,
var marker = L.marker(latlng, {icon: blueIcon}).bindTooltip(feature.properties.count,
{
permanent: true,
direction: 'right'
});
I couldn't find any further documentation on direction centered or similar.
The tooltip provides the functionality to see which was the first and last marker however it seems not to be best practice.
So my questions:
Is there a better solution than tooltip?
how can I display the count centered in the marker?
Example
Current:
wanted:
(Here I would make the background invis so I could just see the text.)
I've found out you could add direction: center.
Ref: http://leafletjs.com/reference-1.0.0.html#tooltip-direction
I've solved my problem with DivIcon
var numberIcon = L.divIcon({
className: "number-icon-default",
iconSize: [25, 41],
iconAnchor: [10, 44],
popupAnchor: [3, -40],
html: feature.properties.count
});
with the css like
.number-icon-default
{
background-image: url("#{request.contextPath}/lib/leaflet/images/marker-icon.png");
text-align:center;
color:Black;
text-shadow: 1px 1px #000000;
font-size: large;
font-weight: bold;
}
Result
Is there a better solution than tooltip?
Not necessarily "better" (which depends on your exact requirements), but a more simple solution would be to use a Marker Icon with some HTML text in it.
Many Leaflet plugins can provide you with such feature, e.g. Leaflet.extra-markers:
var map = L.map('map').setView([48.86, 2.35], 11);
var redMarker = L.ExtraMarkers.icon({
number: '42',
icon: 'fa-number',
markerColor: 'red',
shape: 'square',
prefix: 'fa'
});
L.marker([48.86, 2.35], {
icon: redMarker
}).addTo(map);
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
attribution: '© OpenStreetMap contributors'
}).addTo(map);
<!-- Leaflet assets -->
<link rel="stylesheet" href="https://unpkg.com/leaflet#1.3.1/dist/leaflet.css" integrity="sha512-Rksm5RenBEKSKFjgI3a41vrjkw4EVPlJ3+OiI65vTjIdo9brlAacEuKOiQ5OFh7cOI1bkDwLqdLw3Zg0cRJAAQ==" crossorigin="" />
<script src="https://unpkg.com/leaflet#1.3.1/dist/leaflet-src.js" integrity="sha512-IkGU/uDhB9u9F8k+2OsA6XXoowIhOuQL1NTgNZHY1nkURnqEGlDZq3GsfmdJdKFe1k1zOc6YU2K7qY+hF9AodA==" crossorigin=""></script>
<!-- Leaflet.extramarkers assets -->
<link rel="stylesheet" href="https://unpkg.com/leaflet-extra-markers#1.0.6/src/assets/css/leaflet.extra-markers.css" />
<script src="https://unpkg.com/leaflet-extra-markers#1.0.6/src/assets/js/leaflet.extra-markers.js"></script>
<div id="map" style="height: 200px"></div>
I have a geojson file for various sites. The file has site name information and address details.
Although I am able to display all my makers I am not sure how to show the attribute data on the pop up for the markers.
How do I display different information for each marker? At the moment all my marks show "Hello World"
I have included my code below
<head>
<!-- title -->
<title>Sky Fibre Network</title>
<!-- Reference the Leaflet CSS and JavaScript Files -->
<link rel="stylesheet" href="http://cdn.leafletjs.com/leaflet-0.7.3/leaflet.css" />
<script src="http://cdn.leafletjs.com/leaflet-0.7.3/leaflet.js"></script>
<div id="map"></div>
<style>
html { height: 100% }
body { height: 100%; margin: 0; padding: 0;}
#map{ height: 100% }
</style>
<script src="data/sites.geojson"></script>
</head>
<!-- Webmap contents -->
<body>
<script>
<!-- long and lat for UK & Zoom level for whole of UK -->
var map = L.map('map',{ center:[54.038486, -1.948915], zoom: 5});
L.tileLayer('http://{s}.tile.osm.org/{z}/{x}/{y}.png', {
attribution: '© OpenStreetMap contributors'
}).addTo(map);
var sitesLayer = L.geoJson(sites).addTo(map);
sitesLayer.bindPopup("<b>Hello world!</b><br>I am a popup.").openPopup();
</script>
</body>
Here is my answer guys.
<script>
<!-- long and lat for UK & Zoom level for whole of UK -->
var map = L.map('map',{ center:[54.038486, -1.948915], zoom: 5});
L.tileLayer('http://{s}.tile.osm.org/{z}/{x}/{y}.png', {
attribution: '© OpenStreetMap contributors'
}).addTo(map);
function siteslabels (feature, layer){
layer.bindPopup("<p class='info header'>"+
"<b>" + feature.properties.SITE + "</b>" +
"</br>" + feature.properties.Address1 +
"</br>" + feature.properties.Address2 +
"</p>");
};
L.geoJson(sites,{
onEachFeature: siteslabels
}).addTo(map);
</script>
I am very new to leaflet so I am only just trying to grasp the basics. When following the tutorial online provided by Leaflet, I am struggling to get the map to load. If I use the coordinates provided I have no issues, however if I change the coordinates, nothing loads.
Can anyone help? Here's what I have:
<!DOCTYPE html>
<html>
<head>
<title>Leaflet Web Map</title>
<link rel="stylesheet" href="http://cdn.leafletjs.com/leaflet-0.7.3/leaflet.css" />
<script src="http://cdn.leafletjs.com/leaflet-0.7.3/leaflet.js"></script>
<style>
#map {
width: 960px;
height:500px;
}
</style>
</head>
<body>
<div id="map"></div>
<script>
var map = L.map('map',{
center: [43.64701, -79.39425],
zoom: 15
});
L.tileLayer('http://{s}.tile.osm.org/{z}/{x}/{y}.png', {
attribution: '© OpenStreetMap contributors'
}).addTo(map);
</script>
this loads no bother but if I change the coordinates at all it doesn't load.
To change the map center you should change it in the map property: center: [43.00, -79.00].
var map = L.map('map',{
center: [43.00, -79.00],
zoom: 15
});
You should remember that first coordinate, latitude, takes number in range (-90, 90), while second one, longitude should be set in range (-180, 180). But anyway if you excess that second coordinate application will just calculate it's value as if it was in given ranges.
Maybe you mixed something up and tried to change it here L.tileLayer('http://{s}.tile.osm.org/{z}/{x}/{y}.png',..? This line stands for loading basemap tiles, not centering the map.
Try to
var tileLayer = L.tileLayer('http://{s}.tile.osm.org/{z}/{x}/{y}.png',
{
attribution: false
});
var map = L.map('map',
{
zoomControl: true,
layers: [tileLayer],
maxZoom: 18,
minZoom: 6
})
.setView([43.64701, -79.39425], 15);
setTimeout(function () { map.invalidateSize() }, 800);
I wasn't able to reproduce your problem. Changing the center still loads a map. (Click [Run Code Snippet] button, below)
var map = L.map('map', {
//center: [43.64701, -79.39425], //comment out one of the centers
center: [40, -80],
zoom: 15
});
L.tileLayer('http://{s}.tile.osm.org/{z}/{x}/{y}.png', {
attribution: '© OpenStreetMap contributors'
}).addTo(map);
<!DOCTYPE html>
<html>
<head>
<title>Leaflet Web Map</title>
<link rel="stylesheet" href="http://cdn.leafletjs.com/leaflet-0.7.3/leaflet.css" />
<script src="http://cdn.leafletjs.com/leaflet-0.7.3/leaflet.js"></script>
<style>
#map {
width: 960px;
height: 500px;
}
</style>
</head>
<body>
<div id="map"></div>
</body>
</html>
I noticed that you didn't have an end body, end html tag, so I added those.
What coordinates were you trying to change?
The following JS script (CSS/HTML included for completeness) is intended to open the leaflet map tiles and mark the user location. While it opens the map, it doesn't mark the user location. Why not?
<!DOCTYPE html>
<html>
<head>
<title>Leaflet GeoLocation</title>
<link rel="stylesheet" href="http://cdn.leafletjs.com/leaflet-0.7.3/leaflet.css" />
<script src="http://cdn.leafletjs.com/leaflet-0.7.3/leaflet.js"></script>
<style>
body {
padding: 0;
margin: 0;
}
html, body, #map {
height: 100%;
}
</style>
</head>
<body>
<div id="map"></div>
<script>
var map = L.map('map').setView([43, -79], 18);
L.tileLayer('http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
attribution: 'Map data © OpenStreetMap contributors, CC-BY-SA',
maxZoom: 18
}).addTo(map);
var newMarker = new L.marker(e.latlng).addTo(map);
</script>
</body>
</html>
You are not trying to get the user location at any point in this code.
This line :
var newMarker = new L.marker(e.latlng).addTo(map);
e is not defined in the code you provide. So you need to give it a latitude/longitude value.
I used to use google maps for this but their library has given me CSP 'unsafe-eval' errors. I want to remain secure so I'm starting to look at Open Maps.
Here's a screencast of the functionality I want to port over to Open Maps - http://screencast.com/t/5f5LeAesRr. On map click I want a circle that is draggable with an adjustable radius. Using leaflet I was able to get a circle to show on the map but it isn't draggable and the radius can't be adjusted by dragging as shown in the GMaps screencast. Any help is appreciated.
Figured it out using Leaflet and this Circle Editor plugin
Here's a small example using dependencies from https://github.com/kartena/Leaflet.EditableHandlers
<!DOCTYPE html>
<html>
<head>
<title>maps</title>
<style type="text/css">
#map { width: 481px;height: 300px; }
</style>
<script type="text/javascript" src="http://code.jquery.com/jquery-2.0.3.js"></script>
<!-- Plugin dependecies -->
<link rel="stylesheet" href="../lib/leaflet-0.6.4/leaflet.css" />
<link rel="stylesheet" href="../css/marker-extend.css" />
<script src="../lib/leaflet-0.6.4/leaflet-src.js"></script>
<script src="../src/L.CircleEditor.js" ></script>
<!-- End plugin dependecies -->
</head>
<body>
<div id="map" style="width: 600px; height: 400px"></div>
<br>
<input id="lat" placeholder="lat" type="number"/>
<input id="lng" placeholder="lng" type="number"/>
<input id="radius" placeholder="radius" type="number"/>
<script>
var map = L.map('map').setView([40, -98.50], 4);
L.tileLayer('https://{s}.tiles.mapbox.com/v3/{id}/{z}/{x}/{y}.png', {
maxZoom: 18,
attribution: 'Map data © OpenStreetMap contributors, ' +
'CC-BY-SA, ' +
'Imagery © Mapbox',
id: 'examples.map-i875mjb7'
}).addTo(map);
var updateValues = function(circle) {
console.log(circle._latlng.lat, circle._latlng.lng ,circle._mRadius);
$('#lat').val(circle._latlng.lat);
$('#lng').val(circle._latlng.lng);
$('#radius').val(circle._mRadius);
}
// Set only one circle
var circleSet = false;
var onMapClick = function(e) {
if (!circleSet) {
var circleLocation = new L.LatLng(e.latlng.lat, e.latlng.lng),
circleOptions = {
color: '#0159E5',
fillColor: '#A8C5E4',
fillOpacity: 0.7,
extendedIconClass : 'extend-icon'
};
var circle = new L.CircleEditor(circleLocation, 786500, circleOptions);
map.addLayer(circle);
circleSet = true;
updateValues(circle);
circle.on('edit', function(){
updateValues(this);
});
}
}
map.on('click', onMapClick);
</script>
<!-- From https://github.com/kartena/Leaflet.EditableHandlers -->
</body>
</html>