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!
Related
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>
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've got these code. Using Google Maps API together with additional, self-written CSS-, JavaScript-code:
// [START region_initialization]
// This example creates a custom overlay called USGSOverlay, containing
// a U.S. Geological Survey (USGS) image of the relevant area on the map.
// Set the custom overlay object's prototype to a new instance
// of OverlayView. In effect, this will subclass the overlay class therefore
// it's simpler to load the API synchronously, using
// google.maps.event.addDomListener().
// Note that we set the prototype to an instance, rather than the
// parent class itself, because we do not wish to modify the parent class.
var overlay;
USGSOverlay.prototype = new google.maps.OverlayView();
// Initialize the map and the custom overlay.
function initMap() {
var map = new google.maps.Map(document.querySelector('#map'), {
zoom: 16,
center: {lat: 49.2164353, lng: 6.9752852},
mapTypeId: google.maps.MapTypeId.SATELLITE
});
var bounds = new google.maps.LatLngBounds(
new google.maps.LatLng(49.212860, 6.969140),
new google.maps.LatLng(49.219644, 6.982938)
);
// The photograph is courtesy of the U.S. Geological Survey.
var srcImage = 'imgs/ground_plan.jpg';
// The custom USGSOverlay object contains the USGS image,
// the bounds of the image, and a reference to the map.
overlay = new USGSOverlay(bounds, srcImage, map);
}
// [END region_initialization]
// [START region_constructor]
/** #constructor */
function USGSOverlay(bounds, image, map) {
// Initialize all properties.
this.bounds_ = bounds;
this.image_ = image;
this.map_ = map;
// Define a property to hold the image's div. We'll
// actually create this div upon receipt of the onAdd()
// method so we'll leave it null for now.
this.div_ = null;
// Explicitly call setMap on this overlay.
this.setMap(map);
}
// [END region_constructor]
// [START region_attachment]
/**
* onAdd is called when the map's panes are ready and the overlay has been
* added to the map.
*/
USGSOverlay.prototype.onAdd = function() {
var div = document.createElement('div');
div.style.borderStyle = 'none';
div.style.borderWidth = '0px';
div.style.position = 'absolute';
// Create the img element and attach it to the div.
var img = document.createElement('img');
img.src = this.image_;
img.style.width = '100%';
img.style.height = '100%';
img.style.position = 'absolute';
div.appendChild(img);
this.div_ = div;
// Add the element to the "overlayLayer" pane.
var panes = this.getPanes();
panes.overlayLayer.appendChild(div);
};
// [END region_attachment]
// [START region_drawing]
USGSOverlay.prototype.draw = function() {
// We use the south-west and north-east
// coordinates of the overlay to peg it to the correct position and size.
// To do this, we need to retrieve the projection from the overlay.
var overlayProjection = this.getProjection();
// Retrieve the south-west and north-east coordinates of this overlay
// in LatLngs and convert them to pixel coordinates.
// We'll use these coordinates to resize the div.
var sw = overlayProjection.fromLatLngToDivPixel(this.bounds_.getSouthWest());
var ne = overlayProjection.fromLatLngToDivPixel(this.bounds_.getNorthEast());
// Resize the image's div to fit the indicated dimensions.
var div = this.div_;
div.style.left = sw.x + 'px';
div.style.top = ne.y + 'px';
div.style.width = (ne.x - sw.x) + 'px';
div.style.height = (sw.y - ne.y) + 'px';
// Die CSS-property legt die Durchsichtigkeit eines Elementes fest.
// 1.0 => Keine Durchsichtigkeit.
// 0.0 => Vollkommene Durchsichtkeit.
div.style.opacity = '0.5';
// Positive Zahl => Dreht im Uhrzeigersinn.
div.style.transform = 'rotate(17deg)';
};
// [END region_drawing]
// [START region_removal]
// The onRemove() method will be called automatically from the API if
// we ever set the overlay's map property to 'null'.
USGSOverlay.prototype.onRemove = function() {
this.div_.parentNode.removeChild(this.div_);
this.div_ = null;
};
// [END region_removal]
USGSOverlay.prototype.hide = function() {
if (this.div_) {
// The visibility property must be a string enclosed in quotes.
this.div_.style.visibility = 'hidden';
}
};
USGSOverlay.prototype.show = function() {
if (this.div_) {
this.div_.style.visibility = 'visible';
}
};
USGSOverlay.prototype.toggle = function() {
if (this.div_) {
if (this.div_.style.visibility === 'hidden') {
this.show();
} else {
this.hide();
}
}
};
google.maps.event.addDomListener(window, 'load', initMap);
var toggleButton = document.querySelector('#toggleOverlay');
var increaseButton = document.querySelector('#increaseOpacity');
var decreaseButton = document.querySelector('#decreaseOpacity');
var opacityDisplay = document.querySelector('#current-opacity');
function updateDisplay() {
opacityDisplay.innerHTML =
parseFloat(overlay.div_.style['opacity']).toFixed(1);
}
function setOpacity(step, limit) {
let currentStyle = overlay.div_.style;
let opacity = parseFloat(currentStyle['opacity']); // currentStyle['opacity'] is a STRING !!
if (opacity !== limit) {
opacity += step // Calculation has to be done ONLY with numbers because STRING + NUMBER results in a string.
currentStyle['opacity'] = opacity; // The number will be converted into a string.
updateDisplay();
if (opacityDisplay.classList.contains('limit-reached')) {
opacityDisplay.classList.remove('limit-reached');
}
} else {
opacityDisplay.classList.add('limit-reached');
}
}
increaseButton.addEventListener('click', function() {
setOpacity(-0.1, 0.0);
});
decreaseButton.addEventListener('click', function() {
setOpacity(0.1, 1.0);
});
toggleButton.addEventListener('click', function() {
let current = overlay.div_.style.visibility;
let that = this;
function setValues(that, visibleVal, newButtonText) {
overlay.div_.style.visibility = visibleVal;
that.textContent = newButtonText;
}
current === 'hidden' ?
setValues(that, 'visible', 'hide overlay') :
setValues(that, 'hidden', 'show overlay');
});
opacityDisplay.addEventListener('load', updateDisplay);
html, body {
height: 100%;
margin: 0;
padding: 0; }
body {
background-color: #d9d9d9; }
.wrap {
width: 1000px;
height: 100%;
margin: 0 auto; }
nav {
margin: 5px 10px; }
#map {
height: 100%;
border-radius: 6px;
border: 1px solid black; }
a.default-button {
text-decoration: none; }
#current-opacity, .default-button {
font-family: Segoe UI, Frutiger, Frutiger Linotype, Dejavu Sans, Helvetica;
padding: 5px 10px;
color: #4367c5;
border: 3px solid #4367c5;
font-weight: 900;
display: inline-block;
text-align: center;
border-radius: 6px; }
#current-opacity {
width: 50px;
position: relative; }
#current-opacity:after {
content: attr(data-hint);
position: absolute;
display: none;
color: crimson;
left: 80%;
top: 5px;
background-color: white;
padding: 5px 10px;
white-space: nowrap;
border-radius: 20px;
border: 3px solid crimson;
box-shadow: 6px 6px 9px #646464;
z-index: 1000;
font-size: 0.9rem;
transform: rotate(5deg); }
#current-opacity.limit-reached:after {
display: block; }
.default-button {
text-transform: uppercase;
min-width: 150px; }
.default-button:hover {
color: #009e60;
border-color: #009e60; }
.default-button:active {
opacity: 0.6; }
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="initial-scale=1.0, user-scalable=no">
<meta charset="utf-8">
<title>Werk 1 - Saarbrücken</title>
<link rel="stylesheet" href="./css/main.css" />
</head>
<body>
<div class="wrap">
<nav class="nav">
Hide overlay
Increase opacity
Decrease opacity
<div id="current-opacity" data-hint="Limit reached">0.5</div>
</nav>
<div id="map"></div>
</div>
<script src="https://maps.googleapis.com/maps/api/js?key=AFDi434FSDFASFD343434af&signed_in=true"></script>
<script src="./js/main.js"></script>
</body>
</html>
The JPG, used as an overlay, the correct API-key I can't include. Could get me into trouble. Sorry.
My problem is: I make any changes to the code (changing the image-path, changing the coordinates for center / the overlay) and the whole thing stops to keep working.
After making changes: The map stays empty.
What is going on there? What I'm doing wrong?
Especially: What do I have to do to get it working with code-changes?
I removed the key because it was giving an invalid key error. I tried changing the center point and the bounds and the code seems to be working.
// [START region_initialization]
// This example creates a custom overlay called USGSOverlay, containing
// a U.S. Geological Survey (USGS) image of the relevant area on the map.
// Set the custom overlay object's prototype to a new instance
// of OverlayView. In effect, this will subclass the overlay class therefore
// it's simpler to load the API synchronously, using
// google.maps.event.addDomListener().
// Note that we set the prototype to an instance, rather than the
// parent class itself, because we do not wish to modify the parent class.
var overlay;
USGSOverlay.prototype = new google.maps.OverlayView();
// Initialize the map and the custom overlay.
function initMap() {
var map = new google.maps.Map(document.querySelector('#map'), {
zoom: 9,
center: {lat: 19.2164353, lng: 72.9752852},
mapTypeId: google.maps.MapTypeId.SATELLITE
});
var bounds = new google.maps.LatLngBounds(
new google.maps.LatLng(19.212860, 72.969140),
new google.maps.LatLng(19.219644, 72.982938)
);
// The photograph is courtesy of the U.S. Geological Survey.
var srcImage = 'imgs/ground_plan.jpg';
// The custom USGSOverlay object contains the USGS image,
// the bounds of the image, and a reference to the map.
overlay = new USGSOverlay(bounds, srcImage, map);
}
// [END region_initialization]
// [START region_constructor]
/** #constructor */
function USGSOverlay(bounds, image, map) {
// Initialize all properties.
this.bounds_ = bounds;
this.image_ = image;
this.map_ = map;
// Define a property to hold the image's div. We'll
// actually create this div upon receipt of the onAdd()
// method so we'll leave it null for now.
this.div_ = null;
// Explicitly call setMap on this overlay.
this.setMap(map);
}
// [END region_constructor]
// [START region_attachment]
/**
* onAdd is called when the map's panes are ready and the overlay has been
* added to the map.
*/
USGSOverlay.prototype.onAdd = function() {
var div = document.createElement('div');
div.style.borderStyle = 'none';
div.style.borderWidth = '0px';
div.style.position = 'absolute';
// Create the img element and attach it to the div.
var img = document.createElement('img');
img.src = this.image_;
img.style.width = '100%';
img.style.height = '100%';
img.style.position = 'absolute';
div.appendChild(img);
this.div_ = div;
// Add the element to the "overlayLayer" pane.
var panes = this.getPanes();
panes.overlayLayer.appendChild(div);
};
// [END region_attachment]
// [START region_drawing]
USGSOverlay.prototype.draw = function() {
// We use the south-west and north-east
// coordinates of the overlay to peg it to the correct position and size.
// To do this, we need to retrieve the projection from the overlay.
var overlayProjection = this.getProjection();
// Retrieve the south-west and north-east coordinates of this overlay
// in LatLngs and convert them to pixel coordinates.
// We'll use these coordinates to resize the div.
var sw = overlayProjection.fromLatLngToDivPixel(this.bounds_.getSouthWest());
var ne = overlayProjection.fromLatLngToDivPixel(this.bounds_.getNorthEast());
// Resize the image's div to fit the indicated dimensions.
var div = this.div_;
div.style.left = sw.x + 'px';
div.style.top = ne.y + 'px';
div.style.width = (ne.x - sw.x) + 'px';
div.style.height = (sw.y - ne.y) + 'px';
// Die CSS-property legt die Durchsichtigkeit eines Elementes fest.
// 1.0 => Keine Durchsichtigkeit.
// 0.0 => Vollkommene Durchsichtkeit.
div.style.opacity = '0.5';
// Positive Zahl => Dreht im Uhrzeigersinn.
div.style.transform = 'rotate(17deg)';
};
// [END region_drawing]
// [START region_removal]
// The onRemove() method will be called automatically from the API if
// we ever set the overlay's map property to 'null'.
USGSOverlay.prototype.onRemove = function() {
this.div_.parentNode.removeChild(this.div_);
this.div_ = null;
};
// [END region_removal]
USGSOverlay.prototype.hide = function() {
if (this.div_) {
// The visibility property must be a string enclosed in quotes.
this.div_.style.visibility = 'hidden';
}
};
USGSOverlay.prototype.show = function() {
if (this.div_) {
this.div_.style.visibility = 'visible';
}
};
USGSOverlay.prototype.toggle = function() {
if (this.div_) {
if (this.div_.style.visibility === 'hidden') {
this.show();
} else {
this.hide();
}
}
};
google.maps.event.addDomListener(window, 'load', initMap);
var toggleButton = document.querySelector('#toggleOverlay');
var increaseButton = document.querySelector('#increaseOpacity');
var decreaseButton = document.querySelector('#decreaseOpacity');
var opacityDisplay = document.querySelector('#current-opacity');
function updateDisplay() {
opacityDisplay.innerHTML =
parseFloat(overlay.div_.style['opacity']).toFixed(1);
}
function setOpacity(step, limit) {
let currentStyle = overlay.div_.style;
let opacity = parseFloat(currentStyle['opacity']); // currentStyle['opacity'] is a STRING !!
if (opacity !== limit) {
opacity += step // Calculation has to be done ONLY with numbers because STRING + NUMBER results in a string.
currentStyle['opacity'] = opacity; // The number will be converted into a string.
updateDisplay();
if (opacityDisplay.classList.contains('limit-reached')) {
opacityDisplay.classList.remove('limit-reached');
}
} else {
opacityDisplay.classList.add('limit-reached');
}
}
increaseButton.addEventListener('click', function() {
setOpacity(-0.1, 0.0);
});
decreaseButton.addEventListener('click', function() {
setOpacity(0.1, 1.0);
});
toggleButton.addEventListener('click', function() {
let current = overlay.div_.style.visibility;
let that = this;
function setValues(that, visibleVal, newButtonText) {
overlay.div_.style.visibility = visibleVal;
that.textContent = newButtonText;
}
current === 'hidden' ?
setValues(that, 'visible', 'hide overlay') :
setValues(that, 'hidden', 'show overlay');
});
opacityDisplay.addEventListener('load', updateDisplay);
html, body {
height: 100%;
margin: 0;
padding: 0; }
body {
background-color: #d9d9d9; }
.wrap {
width: 1000px;
height: 100%;
margin: 0 auto; }
nav {
margin: 5px 10px; }
#map {
height: 100%;
border-radius: 6px;
border: 1px solid black; }
a.default-button {
text-decoration: none; }
#current-opacity, .default-button {
font-family: Segoe UI, Frutiger, Frutiger Linotype, Dejavu Sans, Helvetica;
padding: 5px 10px;
color: #4367c5;
border: 3px solid #4367c5;
font-weight: 900;
display: inline-block;
text-align: center;
border-radius: 6px; }
#current-opacity {
width: 50px;
position: relative; }
#current-opacity:after {
content: attr(data-hint);
position: absolute;
display: none;
color: crimson;
left: 80%;
top: 5px;
background-color: white;
padding: 5px 10px;
white-space: nowrap;
border-radius: 20px;
border: 3px solid crimson;
box-shadow: 6px 6px 9px #646464;
z-index: 1000;
font-size: 0.9rem;
transform: rotate(5deg); }
#current-opacity.limit-reached:after {
display: block; }
.default-button {
text-transform: uppercase;
min-width: 150px; }
.default-button:hover {
color: #009e60;
border-color: #009e60; }
.default-button:active {
opacity: 0.6; }
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="initial-scale=1.0, user-scalable=no">
<meta charset="utf-8">
<title>Werk 1 - Saarbrücken</title>
<link rel="stylesheet" href="./css/main.css" />
</head>
<body>
<div class="wrap">
<nav class="nav">
Hide overlay
Increase opacity
Decrease opacity
<div id="current-opacity" data-hint="Limit reached">0.5</div>
</nav>
<div id="map"></div>
</div>
<script src="https://maps.googleapis.com/maps/api/js"></script>
<script src="./js/main.js"></script>
</body>
</html>
I answered my question with help from a friend - labels and building polygons with pop ups now display.
The code uses an external GeoJSON with two building coordinates, values for colors and building names. The GeoJSON is used to draw the buidling polygons, and populate infoBox window.
The labels are blank window boxes with coordinates and text hard coded. There are other examples of this on Stack Overflow, however, I was having trouble getting both functions to work. Thanks to everyone who helped.
<!DOCTYPE html>
<html>
<head>
<title>UT Campus Map</title>
<meta name="viewport" content="initial-scale=1.0, user-scalable=no">
<meta charset="utf-8">
<style>
html, body, #map-canvas {
height: 90%;
padding: 10px;
}
</style>
<script src="https://maps.googleapis.com/maps/api/js?v=3.exp"></script>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<script type="text/javascript" src="http://google-maps-utility-library-v3.googlecode.com/svn/trunk/infobox/src/infobox.js"></script>
<script>
// global variable
var map;
var mapData;
var dataURL = 'https://googledrive.com/host/0B9SE53Gvj0AsR3hyUDJ4Nk9ybG8/Bld.json';
var infoWindow = new google.maps.InfoWindow();
var colors = ["#9295ca", "#076bb6", "#e66665", "#666", "#333", "#456789"];
// create the map when the page loads
function initialize() {
var mapOptions = {
zoom: 16,
center: new google.maps.LatLng(30.284, -97.7325)
};
// build the map
map = new google.maps.Map(document.getElementById('map-canvas'),
mapOptions);
// get the data and draw the polygons
$.getJSON( dataURL, function( data ) {
loadGeoJSON(data);
});
// add colors
stylePolygons();
// add click listeners with info boxes
addClickListeners();
// finally add labels
addLabels();
};
// fetch the geojson data from the server
function loadGeoJSON (data) {
console.log(data);
map.data.addGeoJson(data,{idPropertyName:"id"});
};
// assign colors based on value property of each feature
function stylePolygons () {
map.data.setStyle(function(feature) {
var value = feature.getProperty('value');
var color = colors[value];
return {
fillColor: color,
strokeWeight: 1
};
});
};
//listen for click events
function addClickListeners () {
map.data.addListener('click', function(event) {
//show an infowindow on click
infoWindow.setContent('<div style="line-height:1.35;overflow:hidden;white-space:nowrap;"> <b>'+event.feature.getProperty("bldAbbrev") +"</b>"+"</br>" + event.feature.getProperty("GoogInfoWi") +"<br/>" + event.feature.getProperty("addressStr") +"</div>");
var anchor = new google.maps.MVCObject();
anchor.set("position",event.latLng);
infoWindow.open(map,anchor);
});
};
function buildMarkers(map, markerData) {
var newMarkers = [],
marker;
var blankMarker = {
path: 'M 0,0,0 z',
fillColor: 'yellow',
fillOpacity: 0.8,
scale: 0,
strokeColor: 'white',
strokeWeight: 4
};
for(var i=0; i<markerData.length; i++) {
marker = new google.maps.Marker({
map: map,
icon: blankMarker,
draggable: true,
position: markerData[i].latLng,
visible: true
}),
boxText = document.createElement("div"),
//these are the options for all infoboxes
infoboxOptions = {
content: boxText,
disableAutoPan: false,
maxWidth: 0,
pixelOffset: new google.maps.Size(40, 0),
zIndex: null,
boxStyle: {
background: "url('http://google-maps-utility-library-v3.googlecode.com/svn/trunk/infobox/examples/tipbox.gif') no-repeat",
opacity: 1,
width: "24px"
},
closeBoxMargin: "12px 4px 2px 2px",
closeBoxURL: "",
infoBoxClearance: new google.maps.Size(0, 0),
isHidden: false,
pane: "floatPane",
enableEventPropagation: false
};
newMarkers.push(marker);
//define the text and style for all infoboxes
boxText.style.cssText = "margin-top: 8px; background:#0xFFFFFF; color:#333; font-family:Arial; font-size:24px; padding: 0px; border-radius:0px; -webkit-border-radius:0px; -moz-border-radius:0px;";
boxText.innerHTML = markerData[i].label;
//Define the infobox
newMarkers[i].infobox = new InfoBox(infoboxOptions);
//Open box when page is loaded
newMarkers[i].infobox.open(map, marker);
}
return newMarkers;
};
function addLabels () {
var markerInfoArray =
[
{
latLng: new google.maps.LatLng(30.2848878, -97.7362857),
label:"SAC"
},
{
latLng: new google.maps.LatLng(30.2819835, -97.7404576),
label:"ATT"
}
];
var markerArray = buildMarkers(map, markerInfoArray);
};
google.maps.event.addDomListener(window, 'load', initialize);
</script>
</head>
<body>
<div id="map-canvas"></div>
</body>
</html>
I replaced the original question with the working code. Sorry for poor formatting and procedure, this was my first question.
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!