I'm building a web-map layout for Jekyll based on a blog post, although I'm using Leaflet.js instead of Mapbox.js.
In the front matter of a post, markers are defined as a list of arrays. The format is as follows:
[ "lng, lat", "Popup Content", "Font-awesome Icon", "Color of Marker"]
Two markers might look like this:
markers:
- ["-84.312, 33.845", "Regional Office", "home", "red"]
- ["-84.393, 33.753", "Federal Building", "building", "blue"]
I take the options from the marker and add them to the GeoJSON representation as properties. In order to use Leaflet.awesome-markers each item must be represented as a Marker Layer instead of a GeoJSON Layer. Luckily the GeoJSON Layer provides a method to convert each point to a Marker Layer.
It seems that even though I have access to the feature (and therefore the features properties), I can't get the variable feature.properties.icon to evaluate. After Jekyll works it's magic and produces the static HTML files I see that the icon property is still set to "feature.properties.icon" instead of the value of that variable.
console.log(feature.properties.icon) evaluates to "home" as expected in this case.
Post Front-Matter:
---
title: "This is an Example of a Map-Centric Post"
layout: post
tags:
- Map
map: leaflet
center: "33.733784, -84.389369"
zoom: 9
map-background: terrain
markers: # [ Coordinates, Popup Content, Font-Awesome Icon, Color]
- ["-84.312, 33.845", "Office", "home", "red"]
- ["-84.393, 33.753", "Federal Building", "building", "blue"]
---
leaflet.html include:
<script>
var toner = L.tileLayer('http://{s}.tile.stamen.com/toner/{z}/{x}/{y}.png', {
attribution: 'Map tiles by Stamen Design, CC BY 3.0 — Map data © OpenStreetMap contributors, CC-BY-SA',
subdomains: 'abcd',
minZoom: 0,
maxZoom: 20
}),
terrain = L.tileLayer('http://{s}.tile.stamen.com/terrain/{z}/{x}/{y}.png', {
attribution: 'Map tiles by Stamen Design, CC BY 3.0 — Map data © OpenStreetMap contributors, CC-BY-SA',
subdomains: 'abcd',
minZoom: 4,
maxZoom: 18
}),
map = L.map('map', {
layers: [{{page.map-background}}]
}).setView([ {{page.center}} ], {{page.zoom}} );
map.touchZoom.disable();
map.scrollWheelZoom.disable();
if (map.tap) map.tap.disable();
{% if page.markers %}
var markers = [{
"type":"FeatureCollection",
"features":[
{% for marker in page.markers %}
{
"type":"Feature",
"properties":{
"popup": "{{marker[1]}}",
"icon": "{{marker[2]}}",
"color": "{{marker[3]}}"
},
"geometry":{
"type":"Point",
"coordinates":[ {{ marker[0] }} ]
}
}{% if forloop.last == false %},{% endif %}
{% endfor %}
]
}];
L.geoJson(markers, {
pointToLayer: function (feature, latlng) {
console.log(feature.properties.icon) // This works!
var mapMarker = L.AwesomeMarkers.icon({
icon: feature.properties.icon, // This doesn't work
prefix: 'fa',
markerColor: feature.properties.color
});
return L.marker(latlng, {
icon: mapMarker
});
},
onEachFeature: function (feature, layer) {
layer.bindPopup(feature.properties.popup);
}
}).addTo(map);
{% else %}
markerLayer.clearLayers();
{% endif %}
</script>
Developer Tools:
Edit:
Switching to bracket notation icon: feature['properties']['icon'] worked only on the index.html page, and not the blog-post page.
Related
I have Google Maps embedded on Vue JS code. But I want to show multiple markers using latitude and longitude on that map. Any idea on how to do that?
Here is my code.
Maps.vue
<template>
<card type="plain" title="Google Maps">
<div id="map" class="map">
</div>
</card>
</template>
<script>
export default {
mounted() {
let myLatlng = new window.google.maps.LatLng(40.748817, -73.985428);
let mapOptions = {
zoom: 13,
center: myLatlng,
scrollwheel: false, //we disable de scroll over the map, it is a really annoing when you scroll through page
styles: [{
"elementType": "geometry",
"stylers": [{
"color": "#1d2c4d"
}]
},
{
"elementType": "labels.text.fill",
"stylers": [{
"color": "#8ec3b9"
}]
},
{
"elementType": "labels.text.stroke",
"stylers": [{
"color": "#1a3646"
}]
},
{
"featureType": "water",
"elementType": "labels.text.fill",
"stylers": [{
"color": "#4e6d70"
}]
}
]
};
let map = new window.google.maps.Map(
document.getElementById("map"),
mapOptions
);
let marker = new window.google.maps.Marker({
position: myLatlng,
title: "Hello World!"
});
marker.setMap(map);
}
};
</script>
How can I display multiple markers on this google map? Any advice or tips would be really helpful. Thanks.
You can use the gmap-vue plugin for VueJS to add multiple markers by clicking on the map.
First, initialize your Google Map, and make sure to add an array of markers: [] that will contain all the markers that you will be adding on the map:
<template>
<div>
<gmap-map
:center="center"
ref="mmm"
:zoom="12"
style="width: 100%; height: 400px"
#click="addMarker"
>
<gmap-marker
:key="index"
v-for="(m, index) in markers"
/>
</gmap-map>
</div>
</template>
export default {
name: "GoogleMap",
data() {
return {
center: { lat: 45.508, lng: -73.587 },
markers: [],
};
},
};
You can add markers by calling the #click="addMarker" event on <gmap-map>. Then, on the your methods you can add the addMarker(event) function where you should be able to get the click coordinates from the map. You can now
Here is what it looks like:
methods: {
addMarker(event) {
const marker = {
lat: event.latLng.lat(),
lng: event.latLng.lng(),
};
console.log(marker);
this.markers.push({ position: marker });
this.$refs.mmm.panTo(marker);
//this.center = marker;
},
},
Here is a working codesandbox for your reference, just put your API key on the main.js file: https://codesandbox.io/s/gifted-fast-b41ps
You can use- but you don't need any plug-in. It doesn't really save time in this use-case imho.
With the standard implementation it would look something like that:
this.yourPOIs.forEach(poi => {
var myLatLng = { lat: poi.latitude, lng: poi.longitude };
var marker = new google.maps.Marker({
position: myLatLng,
map: this.myMap,
title: poi.annotation
// you can also add data here with key names that are not in use like for example "uuid: 1" so you can access that data later on if you click on markers or iterate through them
});
marker.addListener('click', function() {
console.log(marker.uuid); // if you want to react on clicking on a marker
});
this.addedMarkers.push(marker);
});
myMap being the map object written in a local variable instead of writing it in a let-variable (you will probably need to access the map later on so you better safe them in the local data of the component or your vuex store).
That's also why i pushed the markers in an array of the component. By that you can later on do this to delete the markers again (for e.g. updating the map):
this.addedMarkers.forEach(marker => {
marker.setMap(null);
});
I have a geoJSON object that is added to the map like this:
L.geoJSON(seine_mar).addTo(map)
Which creates the following:
I would like to add a text on hover of this zone. It is possible with markers, like this for example:
L.marker([value.lat, value.lon], { title: "Hi there"}).addTo(map);
How could I achieve the same with the geoJSON, resulting in displaying a text on hover ? According to the docs, there is no such property as title or label.
Example of desired result (fear my paint skills):
Try using bindTooltip() with permanent option
https://leafletjs.com/reference-1.7.1.html#tooltip
var map = L.map('map').setView([39.74739, -105], 13);
L.tileLayer('https://api.mapbox.com/styles/v1/{id}/tiles/{z}/{x}/{y}?access_token=pk.eyJ1IjoibWFwYm94IiwiYSI6ImNpejY4NXVycTA2emYycXBndHRqcmZ3N3gifQ.rJcFIG214AriISLbB6B5aw', {
maxZoom: 18,
attribution: 'Map data © OpenStreetMap contributors, ' +
'Imagery © Mapbox',
id: 'mapbox/light-v9',
tileSize: 512,
zoomOffset: -1
}).addTo(map);
var campus = {
"type": "Feature",
"geometry": {
"type": "Polygon",
"coordinates": [
[
[-105.00432014465332, 39.74732195489861],
[-105.00715255737305, 39.74620006835170],
[-105.00921249389647, 39.74468219277038],
[-105.01067161560059, 39.74362625960105],
[-105.01195907592773, 39.74290029616054],
[-105.00989913940431, 39.74078835902781],
[-105.00758171081543, 39.74059036160317],
[-105.00346183776855, 39.74059036160317],
[-105.00097274780272, 39.74059036160317],
[-105.00062942504881, 39.74072235994946],
[-105.00020027160645, 39.74191033368865],
[-105.00071525573731, 39.74276830198601],
[-105.00097274780272, 39.74369225589818],
[-105.00097274780272, 39.74461619742136],
[-105.00123023986816, 39.74534214278395],
[-105.00183105468751, 39.74613407445653],
[-105.00432014465332, 39.74732195489861]
]
]
}
};
L.geoJSON(campus)
.bindTooltip('Hi there', {
permanent: true,
direction: 'center'
})
.addTo(map);
<link rel="stylesheet" href="https://unpkg.com/leaflet#1.7.1/dist/leaflet.css" integrity="sha512-xodZBNTC5n17Xt2atTPuE1HxjVMSvLVW9ocqUKLsCC5CXdbqCmblAshOMAS6/keqq/sMZMZ19scR4PsZChSR7A==" crossorigin="" />
<script src="https://unpkg.com/leaflet#1.7.1/dist/leaflet.js" integrity="sha512-XQoYMqMTK8LvdxXYG3nZ448hOEQiglfqkJs1NOQV44cWnUrBc8PkAOcXy20w0vlaXaVUearIOBhiXZ5V3ynxwA==" crossorigin=""></script>
<div id='map'></div>
You can use the onEachFeature function of L.geoJSON() to loop through all layers and then add a Tooltip with layer.bindTooltip("HI") to it.
L.geoJSON(seine_mar,{
onEachFeature: function(feature, layer){
layer.bindTooltip('Hi there', {permanent: true}).openTooltip();
// or over a feature property layer.bindTooltip(feature.properties.customTitle)
}
}).addTo(map)
I'm looking for a way to use JSON instead of GeoJSON in leaflet using AJAX. Using JSON and AJAX are required.
I managed to call JSON file using AJAX. However, now I'm confused how I can use data in JSON to plot markers on map. I'm guessing I can't use L.geoJson().
HTML:
<div id="map" style="width: 800px; height: 500px"></div>
This is the JavaScript file:
var map;
var overlay;
var addPopupsFromLocations = function(locations) {
var popups = new Array();
locations.forEach(function(location){
console.log('creating popup for location ' + location.title);
console.log(location.latitude);
console.log(location.longitude);
}) ;
};
function init() {
var map = L.map('map').setView([51.505, -0.09], 13);
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-i86knfo3'
}).addTo(map);
}
$(document).ready(function(){
init();
$.ajax('locations.json', {
dataType: 'json',
success: addPopupsFromLocations,
error: function(xhr, st, et) {
console.warn(et);
}
});
});
This is the JSON file:
[
{
"title": "Weathertop",
"link": "http://en.wikipedia.org/wiki/Weathertop",
"latitude": 51.505,
"longitude": -0.09,
"imageUrl": "assets/img/location-images/Weathertop.jpg"
},
{
"title": "Rivendell",
"link": "http://lotr.wikia.com/wiki/Rivendell",
"latitude": -0.09,
"longitude": 51.505,
"imageUrl": "assets/img/location-images/Rivendell2.jpg"
},
{
"title": "Minas Tirith",
"link": "http://lotr.wikia.com/wiki/Minas_Tirith",
"latitude": 38.78,
"longitude": -77.18,
"imageUrl": "assets/img/location-images/320px-Minas_Tirith.jpg"
}
]
Console:
creating popup for location Weathertop
custom.js (line 7)
51.505
custom.js (line 9)
-0.09
custom.js (line 10)
creating popup for location Rivendell
custom.js (line 7)
-0.09
custom.js (line 9)
51.505
custom.js (line 10)
creating popup for location Minas Tirith
custom.js (line 7)
38.78
custom.js (line 9)
-77.18
I'm looking for a way to use JSON instead of GeoJSON in leaflet using AJAX.
Okay: to review some terms,
JSON is a basic data-interchange format. It doesn't contain anything in particular.
GeoJSON is a subset of JSON that is formatted to be map-friendly and understandable to things like Leaflet.
If you want to use L.geoJson, you need to reformat your data so that it fits the GeoJSON specification. You can do this with basic JavaScript.
var geojsonFormattedLocations = locations.map(function(location) {
return {
type: 'Feature',
geometry: {
type: 'Point',
coordinates: [location.longitude, location.latitude]
},
properties: {
location
}
};
});
I know it is a late answer but you definitely can use simple JSON format with Leaflet.
As you say, you receive the JSON with ajax and on success, you run a function that loops each JSON object and for each one, adds a marker on the map. For example:
var response = req.responseText;
var arr = JSON.parse(response);
for (var i=0 ; i<arr.length ; i++) {
L.marker([arr[i].latitude, arr[i].longitude]).addTo(map);
}
I am starting to use the Google Map Javascript API V3 and wish to display markers on a map, using GeoJSON. My GeoJSON is as follows:
{
"type": "FeatureCollection",
"features": [
{
"type": "Feature",
"geometry": {
"type": "Point",
"coordinates": [153.236112, -27.779627]
},
"properties": {
"name": "[153.236112, -27.779627]",
"description": "Timestamp: 16:37:16.293"
}
},
{
"type": "Feature",
"geometry": {
"type": "Point",
"coordinates": [153.230447, -27.777501]
},
"properties": {
"name": "[153.230447, -27.777501]",
"description": "Timestamp: 16:37:26.298"
}
}
]
}
And my JavaScript code to load the GeoJSON:
var map;
var marker;
function initialize() {
// Create a simple map.
map = new google.maps.Map(document.getElementById('map-canvas'), {
zoom: 14,
center: ${lastPosition}
});
// Load the associated GeoJSON
var url = 'fieldDataGeoJSON';
url += '?deviceId=' + deviceId + '&fieldId=' + fieldId;
map.data.loadGeoJson(url);
}
google.maps.event.addDomListener(window, 'load', initialize);
Note: the URL "fieldDataGeoJSON.." returns the GeoJSON, as you might have already figured out.
This works well: the markers are shown on the map, at the good location. But the fields "name" and "description" present in the GeoJSON are not linked to the markers, meaning that they are not displayed when I click on the marker.
I guess that the first question would be: "Is it supposed to be supported?". If not, does it mean that I have to parse the GeoJSON to add the names and descriptions? Do you have any hints on how to achieve this?
Thank you in advance for your help!
Normal Google Maps Javascript API v3 event listeners work, as do normal infowindows.
var map;
var infowindow = new google.maps.InfoWindow();
function initialize() {
// Create a simple map.
map = new google.maps.Map(document.getElementById('map-canvas'), {
zoom: 14,
center: new google.maps.LatLng(-27.779627,153.236112)
});
google.maps.event.addListener(map, 'click', function() {
infowindow.close();
});
// Load the associated GeoJSON
var url = 'http://www.geocodezip.com/fieldDataGeoJSON.txt';
map.data.loadGeoJson(url);
// Set event listener for each feature.
map.data.addListener('click', function(event) {
infowindow.setContent(event.feature.getProperty('name')+"<br>"+event.feature.getProperty('description'));
infowindow.setPosition(event.latLng);
infowindow.setOptions({pixelOffset: new google.maps.Size(0,-34)});
infowindow.open(map);
});
}
google.maps.event.addDomListener(window, 'load', initialize);
working example
I managed to create map with leaflet.js & jQuery mobile.
Now I need to get rid of jQuery mobile and just use jQuery instead.
Everything works just fine, but I can't click the polygons which I draw on the map anymore. It worked with jQuery mobile before.
Any hints?
here is my simplified code:
var map = L.map('map', {
zoomControl: false
});
L.tileLayer('http://{s}.tile.cloudmade.com/**apikey***/997/256/{z}/{x}/{y}.png', {
attribution: 'Map data © OpenStreetMap contributors, CC-BY-SA, Imagery © CloudMade',
maxZoom: 18
}).addTo(map);
For the polygons:
var geojsonFeature = { "type": "Polygon","coordinates": value.polygon};
var polycolor = getGebColor(value.geb_nr);
var geojsonStyle = {"color": polycolor};
polygons[i] = L.geoJson(geojsonFeature, {style: geojsonStyle}).addTo(map);
// make clickable
polygons[i].on('click', function(e) {
if (lastMarker) {
map.removeLayer(lastMarker);
}
var url = "http://*****/tugetherMap.php?callback=&id="+value.id+"&type=B";
markers[i] = L.marker([value.point[1], value.point[0]]).addTo(map);
gebName = value.nameLang;
markers[i].bindPopup("<a class='gebOnMap' href='gebaeude.html' >"+gebName+"</a>").openPopup();
lastMarker = markers[i];
});
the polygons[i].on('click',...) is the part which does not work anymore. It works for map.on('click',...)
You need to bind each of your polygons to a click event handler, like so.
L.geoJson(geojsonFeature, {
onEachFeature: function(feature, layer) {
layer.on('click', function(e) {
// Do whatever you want here, when the polygon is clicked.
});
}
}).addTo(map);
Had a issue with this and solved it with the following
function onEachFeature(feature, layer) {
// Do all your popups and other binding in here
// does this feature have a property named popupContent?
if (feature.properties && feature.properties.popupContent) {
layer.bindPopup(feature.properties.popupContent);
}
}
var geojsonFeature = {
"type": "Feature",
"properties": {
"name": "Coors Field",
"amenity": "Baseball Stadium",
"popupContent": "This is where the Rockies play!"
},
"geometry": {
"type": "Point",
"coordinates": [-104.99404, 39.75621]
}
};
L.geoJson(geojsonFeature, {
onEachFeature: onEachFeature
}).addTo(map);
In your code I guess it would be
polygons[i] = L.geoJson(geojsonFeature, {onEachFeature: onEachFeature,
style: geojsonStyle}).addTo(map);
function onEachFeature(feature, layer) {
// Some jazz and magic you need to do with your layer and feature objects
}
The solution for me was to downgrade Leaflet to 0.7.3 or upgrade to 1.0-beta2 (latest version at the time of writing).