I created a Leaflet Map with a Legend. The goal would be to hover over the text element in the legend area and show a tooltip with a image.
Problem: hover is not showing up! I tried very different version. The easiest way which should usually work is this one:
var map = L.map('map').setView([51.505, -0.09], 13);
L.tileLayer('http://{s}.tile.osm.org/{z}/{x}/{y}.png', {
attribution: '© OpenStreetMap contributors'}).addTo(map);
var marker = L.marker([51.5, -0.09]).addTo(map).bindPopup('Popup.');
var MyControl = L.Control.extend({
options: {
position: 'topleft'
},
onAdd: function (map) {
// create the control container with a particular class name
var container = L.DomUtil.create('div', 'my-custom-control');
container.innerHTML += '<div id="hoverhelp" title="">Image Hover Example Leaflet</div>';
L.DomEvent.disableClickPropagation(container);
return container;
}});
map.addControl(new MyControl());
$( "#hoverhelp" ).tooltip({ content: '<img src="https://www.google.com/logos/doodles/2020/mascha-kalekos-113th-birthday-6753651837108682-s.png" />' });
If someone wants to try:
jsfiddle
You have to use JQuery UI to get access to tooltip.
https://jqueryui.com/
Here is your code after editing in jsfiddle.
http://jsfiddle.net/2qrbzstu/
// Demo code from leafletjs.com
var map = L.map('map').setView([51.505, -0.09], 13);
L.tileLayer('http://{s}.tile.osm.org/{z}/{x}/{y}.png', {
attribution: '© OpenStreetMap contributors'
}).addTo(map);
var marker = L.marker([51.5, -0.09]).addTo(map).bindPopup('Popup.');
var MyControl = L.Control.extend({
options: {
position: 'topleft'
},
onAdd: function(map) {
// create the control container with a particular class name
var container = L.DomUtil.create('div', 'my-custom-control');
$(container).html('<div id="hoverhelp" title="so how">Image Hover Example Leaflet</div>');
L.DomEvent.disableClickPropagation(container);
return container;
}
});
map.addControl(new MyControl());
$("#hoverhelp").tooltip({ content: '<img src="https://www.google.com/logos/doodles/2020/mascha-kalekos-113th-birthday-6753651837108682-s.png" />' })
#map {
position: fixed;
left:0;
top: 0;
right: 0;
bottom: 0;
}
.my-custom-control {
background-color: white;
padding: 10px;
}
<div id="map" title="map"></div>
<script src="https://code.jquery.com/jquery-1.12.4.js"></script>
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
Related
I have a dataset with different points on a map, stored on GitHub as a GeoJSON. I would like to assign popups to each point of that dataset, that would display some of its data attributes when clicked. I managed to copy some code from Mapbox tutorials but I don't know how to connect my points from the GeoJSON file with the markers.
Here is my code:
<!DOCTYPE html>
<html>
<head>
<meta charset='utf-8' />
<title></title>
<meta name='viewport' content='initial-scale=1,maximum-scale=1,user-scalable=no' />
<link href="https://fonts.googleapis.com/css?family=Open+Sans" rel="stylesheet">
<script src='https://api.tiles.mapbox.com/mapbox-gl-js/v1.8.1/mapbox-gl.js'></script>
<link href='https://api.tiles.mapbox.com/mapbox-gl-js/v1.8.1/mapbox-gl.css' rel='stylesheet' />
<style>
body {
margin: 0;
padding: 0;
}
#map {
position: absolute;
top: 0;
bottom: 0;
width: 100%;
}
.marker {
background-image: url(https://placekitten.com/g/);
background-size: cover;
width: 50px;
height: 50px;
border-radius: 50%;
cursor: pointer;
}
.mapboxgl-popup {
max-width: 200px;
}
.mapboxgl-popup-content {
text-align: center;
font-family: 'Open Sans', sans-serif;
}
</style>
</head>
<body>
<div id='map'></div>
<script>
mapboxgl.accessToken = 'pk.eyJ1IjoiamFua29tYWciLCJhIjoiY2ozNmNhMXQyMDQ4czMybzl6YTN2cDM0ciJ9.naD_i9iNOl_CEZ3WkY8Nvg';
var map = new mapboxgl.Map({
container: 'map',
style: 'mapbox://styles/mapbox/light-v10',
center: [-96, 37.8],
zoom: 3
});
map.addSource('worldcities_points', {
type: 'geojson',
data: 'https://github.com/jankomag/worldcitiespopchange/blob/master/readycities_geojson.geojson'
});
// add markers to map
geojson.features.forEach(function(marker) {
// create a HTML element for each feature
var el = document.createElement('div');
el.className = 'marker';
el.style.backgroundImage = 'url(https://placekitten.com/g/' + marker.properties.iconSize.join('/') + '/)';
el.style.width = marker.properties.iconSize[0] + 'px';
el.style.height = marker.properties.iconSize[1] + 'px';
el.addEventListener('click', function() {
window.alert(marker.properties.message);
});
// make a marker for each feature and add to the map
new mapboxgl.Marker(el)
.setLngLat(marker.geometry.coordinates)
.setPopup(new mapboxgl.Popup({ offset: 25 }) // add popups
.setHTML('<h3>' + marker.properties.title + '</h3><p>' + marker.properties.description + '</p>'))
.addTo(map);
});
</script>
</body>
</html>
First off, I would recommend you not to share your access token. Others can use it and you will be billed. As you already have shared it, probably a good idea to disable it.
I have some comments to your code:
You are adding a source. In order to show it on the map, you would have to create a layer for it and add it to the map.
map.addSource('worldcities_points', {
type: 'geojson',
data: 'https://github.com/jankomag/worldcitiespopchange/blob/master/readycities_geojson.geojson'
});
--> To add it as a layer:
// Add a layer showing the places.
map.addLayer({
'id': 'worldcities_points',
'type': 'symbol',
'source': 'worldcities_points',
'layout': {
'icon-image': '{icon}-15',
'icon-allow-overlap': true
}
});
You can try to add the popups to the map after you have created them for your objects:
// Create a popup, but don't add it to the map yet.
var popup = new mapboxgl.Popup({
closeButton: false,
closeOnClick: false
});
// Open the popup when mouse hover over the position of the object
map.on('mouseenter', 'places', function(e) {
// Change the cursor style as a UI indicator.
map.getCanvas().style.cursor = 'pointer';
var coordinates = e.features[0].geometry.coordinates.slice();
var description = e.features[0].properties.description;// assuming your source geoJSON contains properties.descriptions
// Ensure that if the map is zoomed out such that multiple
// copies of the feature are visible, the popup appears
// over the copy being pointed to.
while (Math.abs(e.lngLat.lng - coordinates[0]) > 180) {
coordinates[0] += e.lngLat.lng > coordinates[0] ? 360 : -360;
}
// Populate the popup and set its coordinates
// based on the feature found.
popup
.setLngLat(coordinates)
.setHTML(description)
.addTo(map);
});
// remove the popup when the mouse leaves the position of the object
map.on('mouseleave', 'places', function() {
map.getCanvas().style.cursor = '';
popup.remove();
});
That should get you popups! Let me know if you have questions!
I want to show label/Text with polylines, Here is my code
function displayDottedLine(latA, longA, latB, longB, label) {
var pointA = new L.LatLng(latA, longA);
var pointB = new L.LatLng(latB, longB);
var pointList = [pointA, pointB];
var firstpolyline = new L.Polyline(pointList, {
color: 'white',
weight: 1.5,
opacity: 0.5,
dashArray: "10 10",
smoothFactor: 1
});
firstpolyline.addTo(map);
}
there is label parameter in the function, i need to attach this label with polylines.
Thanks in advance.
You can try leaflet.textpath.js plugin
window.addEventListener('load', function() {
var map = L.map('map').setView([51.328125, 42.2935], 18);
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
attribution: '© OpenStreetMap contributors'
}).addTo(map);
var plane = L.polyline([
[3.33984375, 46.6795944656402],
[29.53125, 46.55886030311719],
[51.328125, 42.293564192170095],
]).addTo(map);
map.fitBounds(plane.getBounds());
plane.setText('SAMPLE TEXT', {center: true});
});
#map {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%
}
<link rel="stylesheet" href="https://unpkg.com/leaflet#1.3.1/dist/leaflet.css" />
<script src="https://unpkg.com/leaflet#1.3.1/dist/leaflet.js"></script>
<script src="https://cdn.jsdelivr.net/npm/leaflet-textpath#1.2.0/leaflet.textpath.min.js"></script>
<div id="map"></div>
I have a Google Maps map inserted in a css-scaled container. Due to project specifics this cannot be avoided. I need to track clicks coords on this map, but being scaled map sets incorrect coordinates (see the snippet).
How can be this fixed? I have no ideas at the moment :(
const map = new google.maps.Map(document.querySelector('#map'), {
center: {lat: 48.7, lng: 31},
zoom: 6
});
google.maps.event.addListener(map, 'click', (event)=> {
const marker = new google.maps.Marker({
position: event.latLng,
map: map
});
});
html, body {
height: 100%;
}
.container {
width: 800px;
height: 600px;
transform: scale(1.2);
}
#map {
width: 100%;
height: 100%;
}
<script src="https://maps.googleapis.com/maps/api/js?.js"></script>
<div class="container">
<div id="map"></div>
</div>
Ok, figured out how to correct fix (this is when transformation center is 0,0)
function point2LatLng(point, transformScale, map) {
var topRight = map.getProjection().fromLatLngToPoint(map.getBounds().getNorthEast());
var bottomLeft = map.getProjection().fromLatLngToPoint(map.getBounds().getSouthWest());
var scale = Math.pow(2, map.getZoom());
var worldPoint = new google.maps.Point(point.x / transformScale / scale + bottomLeft.x, point.y / transformScale / scale + topRight.y);
return map.getProjection().fromPointToLatLng(worldPoint);
}
gmaps.event.addListener(this.map, 'click', (event)=> {
let transformMatrix = window.getComputedStyle(this.$el.closest('.container')).transform.match(/^matrix\((.+)\)$/)[1].split(', ');
let transformScale = parseFloat(transformMatrix[0]);
var marker = new gmaps.Marker({
position: point2LatLng(event.pixel, transformScale, this.map),
map: this.map
});
});
This answer works, but being scaled map works very bad, many coordinate-related functions don't wok correctly. But there is a workaround: place the map in a virtual iframe:
const iframe = this.$el.querySelector('iframe');
iframe.contentWindow.document.open();
iframe.contentWindow.document.write('<div id="map" style="width: 100%; height: 100%"></div>');
iframe.contentWindow.document.close();
const mapContainer = iframe.contentWindow.document.querySelector('#map');
const map = new gmaps.Map(mapContainer, {
center: {lat: 48.7, lng: 31},
zoom: 6
});
There are no x-origin restrictions and you can manipulate with iframe content how you want. And with it, even if parent container is scaled, everything works fine
I also had this issue and the above solutions didn't work for me because:
#Terion's "point2LatLng" function didn't seem to place the marker in the correct location
#Terion's use of a virtual iframe meant that you can't drag the map, which severely restricted the user experience.
However I did find a way to do it: I put the map div inside a container which I effectively un-scaled with this JS, loaded after all other JS:
//Function: Unscale the map Container
function unscaleMap(scale){
var unscale = Math.round(10000/(scale * 1))/10000,
rescale = Math.round(10000 * (100 / unscale))/10000;
document.getElementById("fs_mapContainer").style.transform = "scale("+unscale+")";
document.getElementById("fs_mapContainer").style.width = rescale + "%";
document.getElementById("fs_mapContainer").style.height = 80 * scale + "vh";
}
And CSS:
.map_container {position: relative; transform-origin: 0 0; box-sizing: border-box;}
#map {width: 100%; height: 100%}
I want the marker/pin to scroll around and be in the center of the map while the user is dragging around the map. I have a simple jsfiddle (http://jsfiddle.net/upsidown/5xd1Lbpc/6/) where the pin will drop to the center of the map when the user stops dragging, but I want the pin to move with the dragging.
Google Maps JS
var center = new google.maps.LatLng(-33.013803, -71.551498);
var map = new google.maps.Map(document.getElementById('mapBox'), {
zoom: 18,
center: center,
mapTypeId: google.maps.MapTypeId.HYBRID
});
var myMarker = new google.maps.Marker({
position: center,
draggable: true,
map: map
});
google.maps.event.addListener(myMarker, 'dragend', function () {
map.setCenter(this.getPosition()); // Set map center to marker position
updatePosition(this.getPosition().lat(), this.getPosition().lng()); // update position display
});
google.maps.event.addListener(map, 'dragend', function () {
myMarker.setPosition(this.getCenter()); // set marker position to map center
updatePosition(this.getCenter().lat(), this.getCenter().lng()); // update position display
});
function updatePosition(lat, lng) {
document.getElementById('dragStatus').innerHTML = '<p> Current Lat: ' + lat.toFixed(4) + ' Current Lng: ' + lng.toFixed(4) + '</p>';
}
HTML
<div id='mapBox'></div>
Any ideas or thoughts on how to do this?
JSFiddle
To reduce flicker, you can put an absolutely positioned marker over top of the map directly in the center. Then you can use getCenter() to retrieve the actual position on the map.
#wrapper {
position: relative;
display: inline-block;
}
#mapBox {
width: 400px;
height: 300px;
}
#marker {
position: absolute;
top: calc(50% - 40px);
left: calc(50% - 40px);
height: 80px;
width: 80px;
border: 3px solid blue;
border-radius: 50%;
background-color: rgba(30,144,255,0.5);
box-sizing: border-box;
pointer-events: none;
}
HTML:
<div id="wrapper">
<div id="mapBox"></div>
<div id="marker"></div>
</div>
<div id="dragStatus"></div>
JS:
var center = new google.maps.LatLng(-33.013803, -71.551498);
var map = new google.maps.Map(document.getElementById('mapBox'), {
zoom: 18,
center: center,
mapTypeId: google.maps.MapTypeId.HYBRID
});
google.maps.event.addListener(map, 'drag', function() {
loc(map);
});
google.maps.event.addListener(myMarker, 'dragend', function () {
loc(map);
});
function loc(map) {
var x = map.getCenter();
document.getElementById('dragStatus').innerHTML = x.lat() + ', ' + x.lng();
}
Other Useful Answers:
Is there a way to Fix a Google Maps Marker to the Center of its Map always?
add this
google.maps.event.addListener(map, 'drag', function () {
myMarker.setPosition(this.getCenter()); // set marker position to map center
updatePosition(this.getCenter().lat(), this.getCenter().lng()); // update position display
});
see http://jsfiddle.net/gbqqzonr/
//Dragable Marker In Google Map....
var center = new google.maps.LatLng(-33.013803, -71.551498);
var map = new google.maps.Map(document.getElementById('mapBox'), {
zoom: 18,
center: center,
mapTypeId: google.maps.MapTypeId.HYBRID
});
var myMarker = new google.maps.Marker({
position: center,
draggable: true,
map: map
});
google.maps.event.addListener(myMarker, 'dragend', function () {
map.setCenter(this.getPosition()); // Set map center to marker position
updatePosition(this.getPosition().lat(), this.getPosition().lng()); // update position display
});
google.maps.event.addListener(map, 'drag', function () {
myMarker.setPosition(this.getCenter()); // set marker position to map center
updatePosition(this.getCenter().lat(), this.getCenter().lng()); // update position display
});
google.maps.event.addListener(map, 'dragend', function () {
myMarker.setPosition(this.getCenter()); // set marker position to map center
updatePosition(this.getCenter().lat(), this.getCenter().lng()); // update position display
});
function updatePosition(lat, lng) {
document.getElementById('dragStatus').innerHTML = '<p> Current Lat: ' + lat.toFixed(4) + ' Current Lng: ' + lng.toFixed(4) + '</p>';
}
How can I customize the google maps api (v3 javascript) zoom buttons to my own image.
I am late at the party, but here is my two cents.
You have basically two options:
Option 1: You either create the controls using HTML/CSS yourself, which you can then place over the map to the correct position using position absolute or similar means. Even though this works in production, I don't like this, because your HTML/CSS for the element doesn't load at the same time than the map is displayed. Also you are separating your HTML/CSS code for the controls so it is harder to reuse the same map at different pages. e.g. "Did I forgot to add the controls?"
Option 2: You create a custom control which looks and feels the zoom controllers you like. Below is an code about this in practice.
In short, you need to first disable the normal UI controllers by calling:
var mapOptions = {
zoom: 12,
center: chicago,
/* Disabling default UI widgets */
disableDefaultUI: true // <-- see this line
}
And then you just create the controller and use it.
HTML:
...
<div id="map-canvas"></div>
...
CSS:
html, body, #map-canvas {
height: 100%;
margin: 0px;
padding: 0px;
}
JavaScript:
var map;
var chicago = new google.maps.LatLng(41.850033, -87.6500523);
/**
* The ZoomControl adds +/- button for the map
*
*/
function ZoomControl(controlDiv, map) {
// Creating divs & styles for custom zoom control
controlDiv.style.padding = '5px';
// Set CSS for the control wrapper
var controlWrapper = document.createElement('div');
controlWrapper.style.backgroundColor = 'white';
controlWrapper.style.borderStyle = 'solid';
controlWrapper.style.borderColor = 'gray';
controlWrapper.style.borderWidth = '1px';
controlWrapper.style.cursor = 'pointer';
controlWrapper.style.textAlign = 'center';
controlWrapper.style.width = '32px';
controlWrapper.style.height = '64px';
controlDiv.appendChild(controlWrapper);
// Set CSS for the zoomIn
var zoomInButton = document.createElement('div');
zoomInButton.style.width = '32px';
zoomInButton.style.height = '32px';
/* Change this to be the .png image you want to use */
zoomInButton.style.backgroundImage = 'url("http://placehold.it/32/00ff00")';
controlWrapper.appendChild(zoomInButton);
// Set CSS for the zoomOut
var zoomOutButton = document.createElement('div');
zoomOutButton.style.width = '32px';
zoomOutButton.style.height = '32px';
/* Change this to be the .png image you want to use */
zoomOutButton.style.backgroundImage = 'url("http://placehold.it/32/0000ff")';
controlWrapper.appendChild(zoomOutButton);
// Setup the click event listener - zoomIn
google.maps.event.addDomListener(zoomInButton, 'click', function() {
map.setZoom(map.getZoom() + 1);
});
// Setup the click event listener - zoomOut
google.maps.event.addDomListener(zoomOutButton, 'click', function() {
map.setZoom(map.getZoom() - 1);
});
}
function initialize() {
var mapDiv = document.getElementById('map-canvas');
var mapOptions = {
zoom: 12,
center: chicago,
/* Disabling default UI widgets */
disableDefaultUI: true
}
map = new google.maps.Map(mapDiv, mapOptions);
// Create the DIV to hold the control and call the ZoomControl() constructor
// passing in this DIV.
var zoomControlDiv = document.createElement('div');
var zoomControl = new ZoomControl(zoomControlDiv, map);
zoomControlDiv.index = 1;
map.controls[google.maps.ControlPosition.TOP_LEFT].push(zoomControlDiv);
}
initialize();
Note: This code doesn't contain any fancy icons and a like, just placeholders. Therefore, you might need to tune it to fit your needs. Moreover, remember to add HTML5 normal tags and script include for the google maps api v3 javascript. I added only <div id="map-canvas"></div> because a need for rest of the body is pretty obvious.
To see it live: Here is working jsfiddle example
Cheers.
After hours searching I found the solution
Just make sure you replace your API ID!
Enjoy!
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="initial-scale=1.0, user-scalable=no" />
<style type="text/css">
html { height: 100% }
body { height: 100%; margin: 0; padding: 0 }
#map-canvas { height: 60%; width:60%; margin:20px auto; border:1px solid; padding-left:100px; }
</style>
<script type="text/javascript"
src="https://maps.googleapis.com/maps/api/js?key=YOUR-MAP_API-ID&sensor=false®ion=AU">
</script>
<script type="text/javascript">
function HomeControl(controlDiv, map) {
google.maps.event.addDomListener(zoomout, 'click', function() {
var currentZoomLevel = map.getZoom();
if(currentZoomLevel != 0){
map.setZoom(currentZoomLevel - 1);}
});
google.maps.event.addDomListener(zoomin, 'click', function() {
var currentZoomLevel = map.getZoom();
if(currentZoomLevel != 21){
map.setZoom(currentZoomLevel + 1);}
});
}
var map;
var markersArray = [];
function initialize() {
var mapDiv = document.getElementById('map-canvas');
var myLatlng = new google.maps.LatLng(-33.90224, 151.20215);
var mapOptions = {
zoom: 15,
center: myLatlng,
Marker: true,
panControl: false,
zoomControl: false,
streetViewControl: false,
overviewMapControl: false,
mapTypeControl: false,
mapTypeControl: false,
mapTypeId: google.maps.MapTypeId.ROADMAP
}
map = new google.maps.Map(mapDiv, mapOptions);
var marker = new google.maps.Marker({
position: myLatlng,
map: map,
title:"Hello World!"
});
// Create the DIV to hold the control and
// call the HomeControl() constructor passing
// in this DIV.
var homeControlDiv = document.createElement('div');
var homeControl = new HomeControl(homeControlDiv, map);
}
google.maps.event.addDomListener(window, 'load', initialize);
</script>
</head>
<body>
<div id="map-canvas"></div>
<div id="zoomout" style="border:1px solid; width:150px; cursor:pointer; margin-bottom:20px;">ZOOM ME OUT</div>
<div id="zoomin" style="border:1px solid; width:150px; cursor:pointer; ">ZOOM ME IN</div>
</body>
</html>
I did it in the CSS way:
#map-container .gm-style > .gmnoprint > .gmnoprint { background: url(/images/map-zoom-controls.png) no-repeat center center !important; width: 42px !important; height: 68px !important; }
#map-container .gm-style > .gmnoprint > .gmnoprint > div > img { display: none !important; }
#map-container .gm-style > .gmnoprint > .gmnoprint div[title="Zoom in"] { top: 2px !important; left: 2px !important; width: 38px !important; height: 31px !important; }
#map-container .gm-style > .gmnoprint > .gmnoprint div[title="Zoom out"] { top: 35px !important; left: 2px !important; width: 38px !important; height: 30px !important; }
This is for a image that has:
width: 42px;
height: 68px;
Make your own adjustments.
ATTENTION
This applies only if you are using English version because of the title attributes.
This isn't possible. You can tweak their appearance a bit using a set of predefined option parameters or you can implement your custom map control that provides the same functionality as the zoom control.
For more information see this page.
UPDATED: Link fixed. Thanks for the feedback!