Get absolute pixel coordinates from LatLng - leaflet

I need the absolute pixel coordinates from a LatLng coordinate in Leaflet. Just to make it clear, these coordinates are the pixel distance from the upper left corner till a LatLng coordinate on the map.
I read the The pixel origin chapter from the extending Leaflet Tutorial but I don't get it. latLngToLayerPoint or project conversion methods should do it - but I don't get the real pixel position:
const pixelPoint = map.project(feature.geometry.coordinates[0], map.getZoom());
const pixelOrigin = map.getPixelOrigin();
const pixelCoord = pixelPoint.subtract(pixelOrigin);
const layerPoint = map.latLngToLayerPoint(feature.geometry.coordinates[0]);
Here is the jsfiddle with my failed tests.

Your projection code is not the problem, it is the data format: leaflet assumes arrays as latlon, while in the geojson it is lonlat! Try swapping or use the L.latLng object.
var freeBus = {
"type": "FeatureCollection",
"features": [{
"type": "Feature",
"geometry": {
"type": "LineString",
"coordinates": [
[-105.00341892242432, 39.75383843460583],
[-105.0008225440979, 39.751891803969535]
]
},
"properties": {
"popupContent": "This is a free bus line that will take you across downtown.",
"underConstruction": false
},
"id": 1
},
{
"type": "Feature",
"geometry": {
"type": "LineString",
"coordinates": [
[-105.0008225440979, 39.751891803969535],
[-104.99820470809937, 39.74979664004068]
]
},
"properties": {
"popupContent": "This is a free bus line that will take you across downtown.",
"underConstruction": true
},
"id": 2
},
{
"type": "Feature",
"geometry": {
"type": "LineString",
"coordinates": [
[-104.99820470809937, 39.74979664004068],
[-104.98689651489258, 39.741052354709055]
]
},
"properties": {
"popupContent": "This is a free bus line that will take you across downtown.",
"underConstruction": false
},
"id": 3
}
]
};
var map = L.map('map', {
center: [39.74739, -105],
zoom: 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.light'
}).addTo(map);
function onEachFeature(feature, layer) {
layer.bindPopup(
function(layer) {
// get pixel coordinates from first LatLng coordinate
const latlon = L.latLng(feature.geometry.coordinates[0][1], feature.geometry.coordinates[0][0]);
const pixelPoint = map.project(latlon, map.getZoom());
const pixelOrigin = map.getPixelOrigin();
const pixelCoord = pixelPoint.subtract(pixelOrigin);
const layerPoint = map.latLngToLayerPoint(latlon);
var popupContent = "<h1>Pixel coordinates</h1>";
popupContent += "<p>Point: " + pixelPoint + "</p>";
popupContent += "<p>Origin: " + pixelOrigin + "</p>";
popupContent += "<p>Diff: " + pixelCoord + "</p>";
popupContent += "<p>layerPoint: " + layerPoint + "</p>";
return popupContent;
}
);
}
L.geoJSON(freeBus, {
filter: function(feature, layer) {
if (feature.properties) {
// If the property "underConstruction" exists and is true, return false (don't render features under construction)
return feature.properties.underConstruction !== undefined ? !feature.properties.underConstruction : true;
}
return false;
},
onEachFeature: onEachFeature
}).addTo(map);
html, body {
height: 100%;
margin: 0;
}
#map {
width: 600px;
height: 400px;
position: absolute;
}
<script src="https://unpkg.com/leaflet#1.2.0/dist/leaflet.js"></script>
<link href="https://unpkg.com/leaflet#1.2.0/dist/leaflet.css" rel="stylesheet"/>
<div id='map'></div>

Related

Display line in Mapbox GL from search result to nearest point on feature

I'd like to draw a line between two points: geocoder search result and nearest point on a featurecollection of points.
My geocoder search is working correctly and I can find the nearest point in my feature collection using turf.nearestPoint. I have tried to modify several different examples but
I cannot create a linestring from the two points and add it to the map.
My code:
https://jsfiddle.net/aventre/oxmkfh42/15/
`
<style>
#menu {
position: absolute;
background: #efefef;
padding: 10px;
font-family: 'Open Sans', sans-serif;
}
#info {
display: block;
position: relative;
margin: 0px auto;
width: 50%;
padding: 10px;
border: none;
border-radius: 3px;
font-size: 12px;
text-align: center;
color: #222;
background: #fff;
}
</style>
<pre id="info"></pre>
<div id='map' style='width: 100%; height: 700px;'></div>
<div id="menu">
<input id="cl8lwwv48002h14qidkgt1twz" type="radio" name="rtoggle" value="Map" checked="checked">
<label for="cl8lwwv48002h14qidkgt1twz">Map</label>
<input id="cl8m1m04n001l14o6gv40ynbf" type="radio" name="rtoggle" value="Sat">
<label for="cl8m1m04n001l14o6gv40ynbf">Satellite</label>
</div>
<script>
mapboxgl.accessToken = 'pk.eyJ1IjoiYXZlbnRyZSIsImEiOiJjazcwdTN1czkwMDY1M2xwc2Z1dDIxaWgwIn0.2a7GUY9_JPNpp4c0jDaMAA';
var map = new mapboxgl.Map({
container: 'map',
style: 'mapbox://styles/aventre/cl8lwwv48002h14qidkgt1twz', // stylesheet location
center: [-78.66839943, 38.39604638], // starting position [lng, lat]
zoom: 13.5 // starting zoom
});
const fence = {
"type": "FeatureCollection",
"name": "NectarFencePoints",
"features": [{
"type": "Feature",
"properties": {
"distance": 0.0,
"angle": 245.64902626829135
},
"geometry": {
"type": "Point",
"coordinates": [-78.666611972264633, 38.394739637005529, 0.0]
}
},
{
"type": "Feature",
"properties": {
"distance": 25.0,
"angle": 245.64902626829135
},
"geometry": {
"type": "Point",
"coordinates": [-78.666691366204603, 38.394711225055076, 0.0]
}
},
{
"type": "Feature",
"properties": {
"distance": 50.0,
"angle": 271.26325988216735
},
"geometry": {
"type": "Point",
"coordinates": [-78.666778146733265, 38.394711020361669, 0.0]
}
}
]
};
var layerList = document.getElementById('menu');
var inputs = layerList.getElementsByTagName('input');
map.addControl(new mapboxgl.FullscreenControl());
function switchLayer(layer) {
var layerId = layer.target.id;
map.setStyle('mapbox://styles/aventre/' + layerId);
}
for (var i = 0; i < inputs.length; i++) {
inputs[i].onclick = switchLayer;
}
map.on('click', function(e) {
var features = map.queryRenderedFeatures(e.point, {
layers: ['loblolly-labels'] // replace this with the name of the layer
});
if (!features.length) {
return;
}
var feature = features[0];
var popup = new mapboxgl.Popup({
offset: [25, 25]
})
.setLngLat(feature.geometry.coordinates)
.setHTML('<h4>' + feature.properties.title + '</h4><p>' + feature.properties.description + '</p>')
.addTo(map);
});
map.on('mouseenter', 'loblolly-labels', 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;
// 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);
});
map.on('mouseleave', 'loblolly-labels', function() {
map.getCanvas().style.cursor = '';
popup.remove();
});
var geocoder = new MapboxGeocoder({
accessToken: mapboxgl.accessToken,
mapboxgl: mapboxgl
});
map.addControl(geocoder, 'top-left');
geocoder.on('result', (event) => {
/* Get the coordinate of the search result */
const searchResult = event.result.geometry;
const nearest = turf.nearestPoint(searchResult, fence)
const marker = new mapboxgl.Marker()
.setLngLat(nearest.geometry.coordinates)
.addTo(map);
map.addLayer({
'id': 'route',
'type': 'line',
'source': {
'type': 'geojson',
'data': {
'type': 'Feature',
'properties': {},
'geometry': {
'type': 'LineString',
'coordinates': [
[nearest.lng, nearest.lat],
[searchResult.lng, searchResult.lat]
]
}
},
'layout': {
'line-join': 'round',
'line-cap': 'round'
},
'paint': {
'line-color': '#888',
'line-width': 8
}
}
});
});
</script>
`

How can I add icons to a map while using the function L.geoJSN on Leaflet?

I know I can add icons on Leaflet using the following logic:
const geojson = {
"name": "interseccao_circulo",
"type": "FeatureCollection",
"features": [
{
"type": "Feature",
"properties": {
},
"geometry": {
"type": "MultiPoint",
"coordinates": [
[
-46.62831244066412,
-23.551014464955063
]
]
}
},
{
"type": "Feature",
"properties": {
},
"geometry": {
"type": "MultiPoint",
"coordinates": [
[
-46.63242614612176,
-23.55277865770234
]
]
}
}
]
}
var mymap = L.map('mapdiv', {
center:[-23.552778, -46.632426],
zoom:16,
maxZoom:20,
zoomControl:false,
attributionControl:false
});
var lyrOSRHOT = L.tileLayer.provider('OpenStreetMap.HOT');
mymap.addLayer(lyrOSRHOT);
var icons = new L.Icon({
iconUrl: "https://i.imgur.com/ZcGeIVz.png",
iconSize: [40, 40],
});
let lat = geojson.features[0].geometry.coordinates[0][1]
let lng = geojson.features[0].geometry.coordinates[0][0]
let lat2 = geojson.features[1].geometry.coordinates[0][1]
let lng2 = geojson.features[1].geometry.coordinates[0][0]
L.marker([lat, lng], {icon: icons}).addTo(mymap);
L.marker([lat2, lng2], {icon: icons}).addTo(mymap);
<script src="https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.7.1/leaflet-src.min.js" integrity="sha512-XQr+/1RXvYozXiwrumwtu3lqQmVwZ8nkLUrC/mc3HBHw4Imh++RXjwtLQFuOz3i65j9CSfKt50x6w/uUY2ovOQ==" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/leaflet-providers/1.12.0/leaflet-providers.min.js" integrity="sha512-LixflAm9c0/qONbz9F1Ept+QJ6QBpb7wUlPuyv1EHloTVgwSK8j3yMV3elnElGQcv7Y5QTFlF/FqyeE/N4LnKQ==" crossorigin="anonymous"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.7.1/leaflet.css" integrity="sha512-xodZBNTC5n17Xt2atTPuE1HxjVMSvLVW9ocqUKLsCC5CXdbqCmblAshOMAS6/keqq/sMZMZ19scR4PsZChSR7A==" crossorigin="anonymous" />
<div id="mapdiv" style="height:100vh; width: 100vw"></div>
However, I'd like to make it work when I draw the points using the L.geoJSON function. Something like the following:
const geojson = {
"name": "interseccao_circulo",
"type": "FeatureCollection",
"features": [
{
"type": "Feature",
"properties": {
},
"geometry": {
"type": "MultiPoint",
"coordinates": [
[
-46.62831244066412,
-23.551014464955063
]
]
}
},
{
"type": "Feature",
"properties": {
},
"geometry": {
"type": "MultiPoint",
"coordinates": [
[
-46.63242614612176,
-23.55277865770234
]
]
}
}
]
}
var mymap = L.map('mapdiv', {
center:[-23.552778, -46.632426],
zoom:16,
maxZoom:20,
zoomControl:false,
attributionControl:false
});
var lyrOSRHOT = L.tileLayer.provider('OpenStreetMap.HOT');
mymap.addLayer(lyrOSRHOT);
var icons = new L.Icon({
iconUrl: "https://i.imgur.com/ZcGeIVz.png",
iconSize: [40, 40],
});
L.geoJSON(geojson, {icon: icons} ).addTo(mymap);
<script src="https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.7.1/leaflet-src.min.js" integrity="sha512-XQr+/1RXvYozXiwrumwtu3lqQmVwZ8nkLUrC/mc3HBHw4Imh++RXjwtLQFuOz3i65j9CSfKt50x6w/uUY2ovOQ==" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/leaflet-providers/1.12.0/leaflet-providers.min.js" integrity="sha512-LixflAm9c0/qONbz9F1Ept+QJ6QBpb7wUlPuyv1EHloTVgwSK8j3yMV3elnElGQcv7Y5QTFlF/FqyeE/N4LnKQ==" crossorigin="anonymous"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.7.1/leaflet.css" integrity="sha512-xodZBNTC5n17Xt2atTPuE1HxjVMSvLVW9ocqUKLsCC5CXdbqCmblAshOMAS6/keqq/sMZMZ19scR4PsZChSR7A==" crossorigin="anonymous" />
<div id="mapdiv" style="height:100vh; width: 100vw"></div>
I've tried running it with L.geoJSON(geojson, {icon: icons} ).addTo(mymap), but it doesn't seem to recognize {icon: icons} as the function L.marker does (it's plotting the default Leaflet marker instead)... Is there any way I can draw icons with the function L.geoJSON when I use LeafLet?
I ended up finding the solution to this problem using the pointToLayer object instead of trying to use the icon object inside L.geoJSON. As it's written on the Leaflet geoJSON documentation, the accepted options inside it are only: style, pointToLayer, onEachFeature and filter. The icon option is not accepted inside the Leaflet geoJSON function and it should be used inside the pointToLayer object instead... The solution is the following:
const geojson = {
"name": "interseccao_circulo",
"type": "FeatureCollection",
"features": [
{
"type": "Feature",
"properties": {
},
"geometry": {
"type": "MultiPoint",
"coordinates": [
[
-46.62831244066412,
-23.551014464955063
]
]
}
},
{
"type": "Feature",
"properties": {
},
"geometry": {
"type": "MultiPoint",
"coordinates": [
[
-46.63242614612176,
-23.55277865770234
]
]
}
}
]
}
var mymap = L.map('mapdiv', {
center:[-23.552778, -46.632426],
zoom:16,
maxZoom:20,
zoomControl:false,
attributionControl:false
});
var lyrOSRHOT = L.tileLayer.provider('OpenStreetMap.HOT');
mymap.addLayer(lyrOSRHOT);
L.geoJSON(geojson, {
pointToLayer: function (feature, latlng) {
const icons = new L.Icon({
iconUrl: "https://i.imgur.com/ZcGeIVz.png",
iconSize: [40, 40],
});
return L.marker(latlng, {icon: icons});
}
}).addTo(mymap);
<script src="https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.7.1/leaflet-src.min.js" integrity="sha512-XQr+/1RXvYozXiwrumwtu3lqQmVwZ8nkLUrC/mc3HBHw4Imh++RXjwtLQFuOz3i65j9CSfKt50x6w/uUY2ovOQ==" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/leaflet-providers/1.12.0/leaflet-providers.min.js" integrity="sha512-LixflAm9c0/qONbz9F1Ept+QJ6QBpb7wUlPuyv1EHloTVgwSK8j3yMV3elnElGQcv7Y5QTFlF/FqyeE/N4LnKQ==" crossorigin="anonymous"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.7.1/leaflet.css" integrity="sha512-xodZBNTC5n17Xt2atTPuE1HxjVMSvLVW9ocqUKLsCC5CXdbqCmblAshOMAS6/keqq/sMZMZ19scR4PsZChSR7A==" crossorigin="anonymous" />
<div id="mapdiv" style="height:100vh; width: 100vw"></div>

Issue with nested functions eachlayer and onEach feature of leaflet with geoson objects

I am practicing Leaflet to create maps.
In order to find the min value of a set of features I wish to browse the layers of a group layer with the function "eachLayer" then browse the features with the function "onEachFeature".
I think I have a problem with the scope of the variables.
My code is:
<!DOCTYPE html>
<html>
<head>
<title>Layers Control Tutorial - Leaflet</title>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="shortcut icon" type="image/x-icon" href="docs/images/favicon.ico" />
<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.js" integrity="sha512-/Nsx9X4HebavoBvEBuyp3I7od5tA0UzAxs+j83KgC8PU0kgB4XiK4Lfe4y4cgBtaRJQEIFCW+oC506aPT2L1zw==" crossorigin=""></script>
<style>
html, body { height: 100%;margin: 0; }
#map { width: 100%; height: 100%;}
</style>
<!-- jQuery - indispensable pour utiliser les fichiers geojson -->
<script src="https://code.jquery.com/jquery-3.1.1.min.js"></script>
<!-- Fichier(s) contenant les couches -->
<!-- <script src="troncons.geojson" type="text/javascript"></script> -->
</head>
<body>
<div id='map'></div>
<button id="button1">Station variable1</button>
<button id="button2">Station variable2</button>
<button id="button3">Troncons variable3</button>
<script>
// define the layers groups:
var stationsWait = L.layerGroup();
var GroupLayerTroncons = L.layerGroup();
// Load some stations
var Vincennes = L.circle([48.8473,2.43318], { color: 'red',fillColor: '#f03',fillOpacity: 0.5, radius: 750 }).bindPopup("Choisissez une variable").addTo(stationsWait);
var Nation = L.circle([48.8487,2.39626], { color: 'red',fillColor: '#f03', fillOpacity: 0.5,radius: 750 }).bindPopup("Choisissez une variable").addTo(stationsWait);
// Load some sections of the RERA:
var sections_RERA = {
"type": "FeatureCollection",
"crs": { "type": "name", "properties": { "name": "urn:ogc:def:crs:OGC:1.3:CRS84" } },
"features": [
{ "type": "Feature", "properties": { "id": 1 , "flow": 500 }, "geometry": { "type": "LineString", "coordinates": [ [ 2.22241227492659, 48.897131251501115 ], [ 2.237644924286148, 48.892430179977538 ] ] } },
{ "type": "Feature", "properties": { "id": 2 , "flow": 400 }, "geometry": { "type": "LineString", "coordinates": [ [ 2.237796534409823, 48.892431145089262 ], [ 2.277988160372222, 48.88068267218889 ], [ 2.291233854345376, 48.87646267502052 ], [ 2.295956684874181, 48.874690897366008 ] ] } },
{ "type": "Feature", "properties": { "id": 3 , "flow": 300 }, "geometry": { "type": "LineString", "coordinates": [ [ 2.295958036238904, 48.874590924832241 ], [ 2.308533488711002, 48.874964167617904 ], [ 2.315348461217771, 48.875403260408021 ], [ 2.329165082403959, 48.873581863436044 ], [ 2.330553508046893, 48.871690011018686 ], [ 2.330553508046893, 48.871690011018686 ] ] } },
{ "type": "Feature", "properties": { "id": 4 , "flow": 200}, "geometry": { "type": "LineString", "coordinates": [ [ 2.330554792932899, 48.871590037832199 ], [ 2.34106115320042, 48.867749099632711 ], [ 2.344584312147049, 48.864769023056539 ], [ 2.347801519250009, 48.861987132117697 ] ] } },
{ "type": "Feature", "properties": { "id": 5 , "flow": 100 }, "geometry": { "type": "LineString", "coordinates": [ [ 2.347801519250009, 48.861987132117697 ], [ 2.349954033166742, 48.859499314657278 ], [ 2.357872312519592, 48.856342662783582 ], [ 2.373020720593452, 48.844025242488712 ] ] } },
{ "type": "Feature", "properties": { "id": 6 , "flow": 500}, "geometry": { "type": "LineString", "coordinates": [ [ 2.373020720593452, 48.844025242488712 ], [ 2.375307175290527, 48.842837414357263 ], [ 2.378035989383918, 48.842651667917124 ], [ 2.379696184575886, 48.843160200223871 ], [ 2.384654536154551, 48.846585203162263 ], [ 2.38585340994371, 48.847691165562274 ], [ 2.390073858038943, 48.849512428852194 ], [ 2.397050398888572, 48.848847918381693 ] ] } },
{ "type": "Feature", "properties": { "id": 7, "flow": 250 }, "geometry": { "type": "LineString", "coordinates": [ [ 2.397050398888572, 48.848847918381693 ], [ 2.40254859872989, 48.844976207608681 ], [ 2.417864326491966, 48.843551984219573 ], [ 2.423292942257146, 48.845777878447315 ], [ 2.428427826130349, 48.847202264244189 ], [ 2.434335613031259, 48.847230342470212 ] ] } }
]
}
var sections_others = [{
"type": "Feature",
"properties": {
"id": 12,
"name": "Autres-Autres",
"flow": 500,
"popupContent": "Texte à changer",
"popupContent2": "Text de la nouvelle variable"
},
"geometry": {
"type": "LineString",
"coordinates": [ [2.373068996549787 , 48.844124177694574],[2.373068176412221 , 48.844124882353711]]
}
}
]
function onEachFeature(feature, layer) {
if (feature.properties && feature.properties.popupContent) {
layer.bindPopup(feature.properties.popupContent);
}
//console.log ( "The id of the feature is " + feature.properties.id)
}
function style (feature){// paramétrage de la symbologie de la couche "arrondissement"
//return { color: "#046380", weight: 1, fillColor: '#4BB5C1', fillOpacity: .5 };
}
L.geoJson(sections_RERA, { onEachFeature: onEachFeature, style: style }).addTo(GroupLayerTroncons);
sections_RERA.id = 10;
console.log(sections_RERA.id )
// Load sections of an other dummy lines:
function style2 (feature){// paramétrage de la symbologie de la couche "arrondissement"
return { color: "red", weight: 5, fillColor: '#4BB5C1', fillOpacity: .5 };
}
L.geoJson(sections_others, { onEachFeature: onEachFeature, style: style2 }).addTo(GroupLayerTroncons);
sections_others.id = 11;
console.log(sections_others.id )
// Load the map
var mbAttr = 'Map data © OpenStreetMap contributors, ' +
'CC-BY-SA, ' +
'Imagery © Mapbox',
mbUrl = 'https://api.tiles.mapbox.com/v4/{id}/{z}/{x}/{y}.png?access_token=pk.eyJ1IjoibWFwYm94IiwiYSI6ImNpejY4NXVycTA2emYycXBndHRqcmZ3N3gifQ.rJcFIG214AriISLbB6B5aw';
var grayscale = L.tileLayer(mbUrl, {id: 'mapbox.light', attribution: mbAttr}),
streets = L.tileLayer(mbUrl, {id: 'mapbox.streets', attribution: mbAttr});
var map = L.map('map', {
center: [48.8666, 2.333],
zoom: 13,
layers: [streets, GroupLayerTroncons, stationsWait]
});
var baseLayers = {"Grayscale": grayscale,"Streets": streets};
var overlays = { "Waiting Times": stationsWait,"Troncons" : GroupLayerTroncons};
L.control.layers(baseLayers, overlays).addTo(map);
//Objectif: Find the min value in a group layer according a given property
function onEachFeature2(feature, layer) {
if (feature.properties && feature.properties.flow) {
console.log ( "The value of the feature property is " + feature.properties.flow); // later we use the OneProperty variable
}
}
// Body of the GetMin function
function GetMin(GroupLayer, OneProperty){
GroupLayer.eachLayer(function (OneLayer) {
L.geoJson(OneLayer, { // it's work whith sections_RERA instead of OneLayer
onEachFeature: onEachFeature2
// onEachFeature : function onEachFeature3 (feature, layer) { console.log( feature.properties.flow); layer.bindPopup("feature.properties.flow"); }
})
console.log ( "theoretically we change layer----");
})};
// Call of the function
var OneProperty = "Flow";
GetMin(GroupLayerTroncons, OneProperty);
</script>
</body>
</html>
The web console return:
Error: Invalid GeoJSON object.
But, it works when I replace the local variable "OneLayer" by the global variables "sections_RERA" or "sections_others". (line 135)
"OneLayer" and "sections_RERA", is it the same type of object?
Leaflet's L.geoJSON factory takes a raw GeoJSON data object (like your sections_RERA variable) as first parameter, not a Leaflet already built layer (like the child layers of your GroupLayerTroncons variable that are looped through in your GetMin function).
It is unclear what you are trying to achieve. If you just want to read the original GeoJSON data from your layers, do so directly in your eachLayer callback. The properties are available on each layer as layer.feature.properties:
var groupLayer = L.layerGroup();
// Nesting a Leaflet GeoJSON Layer Group into groupLayer Layer Group.
var geoJsonGroupLayer = L.geoJSON(geoJsonRawData, options).addTo(groupLayer);
groupLayer.eachLayer(inspectLayer);
function inspectLayer(layer) {
if (layer.feature && layer.feature.properties) {
// layer is a non-group, built from GeoJSON data.
// inspect the layer...
} else if (layer instanceof L.LayerGroup) {
// layer is a nested Layer Group.
// Recursive call to inspectLayer function.
layer.eachLayer(inspectLayer);
}
}

Put a GeoJSON on a Leaflet map: Invalid GeoJSON object. throw new Error('Invalid GeoJSON object.');

I've some trouble with a Leaflet code that build a GeoJSON and put it on the map.
The GeoJSON is builded from an XML response of a service.
The error is
Invalid GeoJSON object. throw new Error('Invalid GeoJSON object.');
My code is ...
<html>
<head>
<title>Prova caricamento WMS Indirizzi del PCN</title>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="http://cdn.leafletjs.com/leaflet-0.7.2/leaflet.css"/>
</head>
<body>
<div id="map" style="width: 600px; height: 400px"></div>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
<script src="http://cdn.leafletjs.com/leaflet-0.7.2/leaflet-src.js"></script>
<script>
var browser = navigator.userAgent.toLowerCase();
var isIE = (browser.indexOf("msie")>-1 || browser.indexOf("trident")>-1);
if (isIE && window.XDomainRequest) {
if (window.XDomainRequest) {
var query = 'http://wms.pcn.minambiente.it/ogc?map=/ms_ogc/wfs/Numeri_Civici_2012.map&SERVICE=WFS&VERSION=1.0.0&REQUEST=GetFeature&TYPENAME=IN.NUMERICIVICI.2012&SRSNAME=EPSG:4326&bbox=7.719,44.849,7.72,44.85&outputFormat=GML2';
var xdr = new XDomainRequest();
if (xdr) {
xdr.onload = function () {
addressPCN(data);
}
xdr.onerror = function () {
alert("KO");
}
xdr.open('GET', query);
xdr.send();
}
}
}
else {
var query = 'http://wms.pcn.minambiente.it/ogc?map=/ms_ogc/wfs/Numeri_Civici_2012.map&SERVICE=WFS&VERSION=1.0.0&REQUEST=GetFeature&TYPENAME=IN.NUMERICIVICI.2012&SRSNAME=EPSG:4326&bbox=7.719,44.849,7.72,44.85&outputFormat=GML2';
$.ajax({
type: "GET",
url: query,
dataType: "text",
crossDomain: true,
success: function (data) {
addressPCN(data);
},
error: function (response, textStatus, errorThrown) {
alert("KO");
alert(errorThrown);
}
});
}
var map = L.map('map').setView([42, 12], 5);
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-20v6611k'
}).addTo(map);
function addressPCN (addressList) {
//alert("In function addressList");
//alert(addressList);
var addressPCN = '{"type": "FeatureCollection","features":[';
$xmlData = $.parseXML(addressList);
$features = $('gml\\:featureMember, featureMember', $xmlData);
//alert($features.length);
$features.each(function () {
var $this = $(this);
//alert($this.find('ms\\:nome, nome').text() + ' - ' + $this.find('ms\\:civico, civico').text());
addressPCN = addressPCN + '{"type": "Feature", "properties": { "popupContent": "' + $this.find('ms\\:nome, nome').text() + ' ' + $this.find('ms\\:civico, civico').text() + '", ' + '"show_on_map": true }, "geometry": { "type": "Point", "coordinates": [' + $this.find('gml\\:Point, Point').find('gml\\:coordinates, coordinates').text() + ']}},'
});
var addressPCN = addressPCN + ']}';
alert(addressPCN);
function onEachFeature(feature, layer) {
if (feature.properties && feature.properties.popupContent) {
layer.bindPopup(feature.properties.popupContent);
}
}
//var addressPCN = {"type": "FeatureCollection","features":[{"type": "Feature", "properties": { "popupContent": "Via Pegolo 9", "show_on_map": true }, "geometry": { "type": "Point", "coordinates": [7.719490,44.849197]}},{"type": "Feature", "properties": { "popupContent": "Via Pegolo 8", "show_on_map": true }, "geometry": { "type": "Point", "coordinates": [7.719490,44.849197]}},]};
L.geoJson(addressPCN, {
onEachFeature: onEachFeature
}).addTo(map);
}
</script>
You can copy/paste it and shoud work on your desktop/laptop.
Note that if you uncomment the row ....
//var addressPCN = {"type": "FeatureCollection","features":[{"type": "Feature", "properties": { "popupContent": "Via Pegolo 9", "show_on_map": true }, "geometry": { "type": "Point", "coordinates": [7.719490,44.849197]}},{"type": "Feature", "properties": { "popupContent": "Via Pegolo 8", "show_on_map": true }, "geometry": { "type": "Point", "coordinates": [7.719490,44.849197]}},]};
.... you've the GeoJSON I'm building (you can match it with the alert message ....).
In this case all it's working right.
NOTE: you've to use Firefox or Chrome at the momenti, my code still doesn't work foi IE.
Any suggestion is appreciated!!
Thank you in advance!!
Cesare
The problem was about I tried to use a string as a JSON object.
The solutions is to use jQuery.parseJSON function to convert my string with my JSON code (addressPCN1) to a Javascript JSON object.
Here you are code that works ...
<!DOCTYPE html>
<html>
<head>
<title>Prova caricamento WMS Indirizzi del PCN</title>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="http://cdn.leafletjs.com/leaflet-0.7.2/leaflet.css"/>
</head>
<body>
<div id="map" style="width: 600px; height: 400px"></div>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
<script src="http://cdn.leafletjs.com/leaflet-0.7.2/leaflet-src.js"></script>
<script>
var browser = navigator.userAgent.toLowerCase();
var isIE = (browser.indexOf("msie")>-1 || browser.indexOf("trident")>-1);
if (isIE && window.XDomainRequest) {
if (window.XDomainRequest) {
var query = 'service_url';
var xdr = new XDomainRequest();
if (xdr) {
xdr.onload = function () {
addressPCN(xdr.responseText);
}
xdr.onerror = function () {
alert("KO");
}
xdr.open('GET', query);
xdr.send();
}
}
}
else {
var query = 'service_url';
$.ajax({
type: "GET",
url: query,
dataType: "text",
crossDomain: true,
success: function (data) {
//alert("OK");
//alert(data);
addressPCN(data);
alert($this.find('ms\\:nome, nome').text() + ' - ' + $this.find('ms\\:civico, civico').text());
},
error: function (response, textStatus, errorThrown) {
alert("KO");
alert(errorThrown);
}
});
}
var map = L.map('map').setView([42, 12], 5);
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-20v6611k'
}).addTo(map);
function addressPCN (addressList) {
var addressPCN = '{"type": "FeatureCollection","features":[';
$xmlData = $.parseXML(addressList);
$features = $('gml\\:featureMember, featureMember', $xmlData);
$features.each(function () {
var $this = $(this);
//alert($this.find('ms\\:nome, nome').text() + ' - ' + $this.find('ms\\:civico, civico').text());
addressPCN = addressPCN + '{"type": "Feature", "properties": { "popupContent": "' + $this.find('ms\\:nome, nome').text() + ' ' + $this.find('ms\\:civico, civico').text() + '", ' + '"show_on_map": true }, "geometry": { "type": "Point", "coordinates": [' + $this.find('gml\\:Point, Point').find('gml\\:coordinates, coordinates').text() + ']}},'
});
var addressPCN = addressPCN + ']}';
alert(addressPCN);
var addressPCN1 = addressPCN.replace(',]}',']}');
alert(addressPCN1);
var addressPCN2 = jQuery.parseJSON(addressPCN1);
alert(addressPCN2);
function onEachFeature(feature, layer) {
if (feature.properties && feature.properties.popupContent) {
layer.bindPopup(feature.properties.popupContent);
}
}
L.geoJson(addressPCN2, {
onEachFeature: onEachFeature
}).addTo(map);
}
</script>
</body>
</html>
First, make sure the Geo JSON data is valid data with http://geojsonlint.com/ or any other service. Fix the errors if there are any.
And then parse your data which is in the text format with JSON.parse():
L.geoJSON(JSON.parse(data)).addTo(this.map);

addingand using marker variable with geoJsonData and markercluster with leaflet.js

I've been searching for hours and hours now, and i'm still stuck. I have a feeling it is something easy/stupid i'm missing.
I am using the example of markercluster from GitHub. I have 2 different markers (simply 2 different colors) that i would like to show which i would defined in the json format.
I have followed guide from leaflet site to define different markers.
I added my variable to the json part, but i can not figure out how to make the map load the different markers. It's either giving me no map or error; or it still uses the default blue marker.
here is my code:
<script type="text/javascript">
var geoJsonData = {
"type": "FeatureCollection",
"features": [
{ "type": "Feature", "id":"1", "properties": { "address": "2","marker": "cmIcon"}, "geometry": { "type": "Point", "coordinates": [175.2209316333,-37.8210922667 ] } },
{ "type": "Feature", "id":"2", "properties": { "address": "151","marker": "otherIcon" }, "geometry": { "type": "Point", "coordinates": [175.2238417833,-37.80975435 ] } },
{ "type": "Feature", "id":"3", "properties": { "address": "21","marker": "cmIcon" }, "geometry": { "type": "Point", "coordinates": [175.2169955667,-37.818193 ] } },
{ "type": "Feature", "id":"4", "properties": { "address": "14","marker": "otherIcon" }, "geometry": { "type": "Point", "coordinates": [175.2240856667,-37.8216963 ] } },
{ "type": "Feature", "id":"5", "properties": { "address": "38B","marker": "cmIcon" }, "geometry": { "type": "Point", "coordinates": [175.2196982333,-37.8188702167 ] } },
{ "type": "Feature", "id":"6", "properties": { "address": "38","marker": "otherIcon" }, "geometry": { "type": "Point", "coordinates": [175.2209942 ,-37.8192782833 ] } }
]
};
var cloudmade = L.tileLayer('http://{s}.tile.cloudmade.com/{key}/997/256/{z}/{x}/{y}.png', {
maxZoom: 18,
attribution: 'Map data © 2011 OpenStreetMap contributors, Imagery © 2011 CloudMade',
key: 'BC9A493B41014CAABB98F0471D759707'
});
var LeafIcon = L.Icon.extend({
options: {
shadowUrl: 'marker/marker-shadow.png',
iconSize: [32, 32],
shadowSize: [36, 20],
iconAnchor: [22, 94],
shadowAnchor: [4, 62],
popupAnchor: [-3, -76]
}
});
var cmIcon = new LeafIcon({iconUrl: 'marker/marker-cm.png'}),
otherIcon = new LeafIcon({iconUrl: 'marker/marker-others.png'});
var map = L.map('map')
.addLayer(cloudmade);
var markers = new L.MarkerClusterGroup();
var geoJsonLayer = L.geoJson(geoJsonData, {
onEachFeature: function (feature, layer) {
layer.bindPopup(feature.properties.address);
}
});
markers.addLayer(geoJsonLayer);
map.addLayer(markers);
map.fitBounds(markers.getBounds());
function onLocationFound(e) {
var radius = e.accuracy / 2;
L.marker(e.latlng).addTo(map)
.bindPopup("Vous etes ici").openPopup();
L.circle(e.latlng, radius).addTo(map);
}
function onLocationError(e) {
alert(e.message);
}
map.on('locationfound', onLocationFound);
map.on('locationerror', onLocationError);
map.locate({setView: true, maxZoom: 16});
</script>
I suspect that i need to tell leaflet to get the marker variable, probably in
var geoJsonLayer = L.geoJson(geoJsonData, {
onEachFeature: function (feature, layer) {
layer.bindPopup(feature.properties.address);
}
});
but i cannot make it work.
i even tried as suggested some where else:
var geoJsonLayer = L.geoJson(geoJsonData, {
onEachFeature: function (feature, layer) {
layer.bindPopup(feature.properties.address),
layer.setIcon(feature.properties.marker);
}
});
i'm still getting an error: Uncaught TypeError: Object cmIcon has no method 'createIcon'
does anybody have an idea on how to do that?
Any help would be greatly appreciated.
Thank you in advance.
You need to tell the MarkerClusterGroup how to create the icon. The marker cluster docs show an example with a DivIcon like this:
var markers = new L.MarkerClusterGroup({
iconCreateFunction: function(cluster) {
return new L.DivIcon({ html: '<b>' + cluster.getChildCount() + '</b>' });
}
});
You can use your custom icon instead like this:
var markers = new L.MarkerClusterGroup({
iconCreateFunction: function(cluster) {
// decide which icon you want to use
return (cluster.getChildCount() > 10) ? cmIcon : otherIcon;
}
});