Center VueLeaflet view to all geoJson geometries from multiple layers - javascript

I have a variable list of geoJson layers (that I'm naming as sectors) on my map. I need to center the view to fit all geometries.
I'm using Vue2Leaflet (v2.5.2) and Leaflet (v1.6.0).
Each geoJson object is like this:
{
"type": "FeatureCollection",
"features":
[
{
"type": "Feature",
"properties":
{
"id": "4200051",
"name": "Abdon Batista",
"description": "Abdon Batista"
},
"geometry":
{
"type": "Polygon",
"coordinates": [[[-51.0378352721, -27.5044338231], ...]]
}
}
]
}
And it's stored directly in geoSectors: [ geoJson1, geoJson2, ... ].
Here's the code:
<template>
<div class="home">
<l-map ref="mapControl" :zoom="zoom" :center="center" :options="mapOptions">
<l-tile-layer :url="url" :attribution="attribution"/>
<l-control-zoom position="bottomright"/>
<!-- Sectors-->
<l-geo-json v-for="sector in geoSectors" :key="sector.id" :geojson="sector" :options="options"/>
</l-map>
</div>
</template>
<script>
import { latLng, latLngBounds } from "leaflet";
export default {
data() {
return {
zoom: 6,
center: latLng(-25.005973, -50.537109),
url: 'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png',
attribution: '© OpenStreetMap contributors',
mapOptions: {
zoomSnap: 0.1,
zoomControl: false
},
geoSectors: []
}
},
mounted(){
let list = [];
//Gets the list from a file.
this.geoSectors = list;
var bounds = this.geoSectors; //HERE: Get bounds of the list.
this.$refs.mapControl.mapObject.fitBounds(bounds);
},
computed: {
options() {
return {
onEachFeature: this.onEachFeatureFunction
};
},
onEachFeatureFunction() {
return (feature, layer) => {
layer.on('click', function (e) {
//Shows sector details.
});
//Tooltips.
layer.bindTooltip("<div><p>Sector: "feature.properties.name +"</p></div>", {
permanent: false,
sticky: true
});
};
}
},
}
</script>
How can I fit the map view to display all geoJson layers, with the maximum zoom level possible?

I managed to solve it. Here's the code:
//You need to import featureGroup from leaflet:
import { latLng, featureGroup } from "leaflet";
//After building your geoJson layers, just call this:
this.$nextTick().then(() => {
var group = new featureGroup();
this.$refs.mapControl.mapObject.eachLayer(function(layer) {
if (layer.feature != undefined)
group.addLayer(layer);
});
this.$refs.mapControl.mapObject.fitBounds(group.getBounds(), { padding: [20, 20] });
});

Related

Leaflet.js How to remove the selected layer in Map when map is re rendered with Drawn Items

I tried to render the polygon-shaped surfaces on the map whenever user clicks on polygon shape layer A popup
with polygon details is displayed and the layer can be edited.In the popup, there is option to delete the polygon. After Clicking on Delete on popup I tried reinitialize the map with new surfaces i.e(polygons) data but still, the selected surface is appearing.
componentDidUpdate(prevProps, prevState) {
const { user, surfaces } = this.props;
const { allLayers } = this.state;
const that = this;
let selectedSurface = null;
if (!prevProps.user.id && user.id) {
this.initializeMap();
}
if (this.props.deleteAction.success !== prevProps.deleteAction.success) {
this.props.actionFetch();
map.remove();
this.initializeMap();
}
if ((allLayers.length === 1 && surfaces.length) || (surfaces.length !==
prevProps.surfaces.length)) {
let allLayers = [{ key: -1, name: this.props.intl.formatMessage({ id:
'surface.allsurfaces' }), color: '#CCCCCC' }];
surfaces.forEach((o) => {
let l = L.geoJSON(o.geometry)._layers;
[l] = Object.keys(l).map(ob => l[ob]);
const customlayer = this.addPopupToLayer(o, l);
map.addLayer(drawnItems[o.surface_type.id].addLayer(customlayer));
l.on('click', (e) => {
if (selectedSurface) {
selectedSurface.editing.disable();
}
selectedSurface = e.target;
e.target.editing.enable();
that.setState({
popup: true,
detail: true,
surfaceDetail: o,
typeSelected: o.surface_type,
editSurface: selectedSurface
});
});
allLayers.push({
key: o.surface_type.id,
name: o.surface_type.name,
color: o.surface_type.color
});
});
allLayers = allLayers.filter(
(l, index, self) => self.findIndex(
t => t.key === l.key
) === index
);
this.setState({
allLayers,
counter: surfaces.length
});
}
}
initializeMap() {
const { user, actionFetch, actionFetchTypes } = this.props;
actionFetch();
actionFetchTypes();
map = L.map('map', {
center: [...user.airport.location.coordinates].reverse(),
zoom: 15,
editable: true,
});
L.gridLayer.googleMutant({ type: 'satellite', maxZoom: 20 }).addTo(map);
const that = this;
map.on(L.Draw.Event.CREATED, (e) => {
drawnItems[that.state.typeSelected.key].addLayer(e.layer);
utils.toggleZooming(map, 'disable');
that.setState({ popup: true, layer: e.layer });
});
map.on('draw:deleted', (e) => {
that.setState({ popup: false });
});
}
.In the popup, there is option to delete the polygon.
Please check below example.
// initialize the map
var map = L.map('map', {
center: [0.4, 102],
zoom: 7
});
// add map layer (OpenStreetMap)
L.tileLayer('https://{s}.tile.openstreetmap.fr/hot/{z}/{x}/{y}.png', {
maxZoom: 19,
attribution: '© OpenStreetMap, Tiles courtesy of Humanitarian OpenStreetMap Team'
}).addTo(map);
// load example GEOJSON (from Wikipedia)
var geojsonFeature = {
"type": "FeatureCollection",
"features": [
{
"type": "Feature",
"geometry": {
"type": "Point",
"coordinates": [102.0, 0.5]
},
"properties": {
"prop0": "A"
}
},{
"type": "Feature",
"geometry": {
"type": "LineString",
"coordinates": [
[102.0, 0.0], [103.0, 1.0], [104.0, 0.0], [105.0, 1.0]
]
},
"properties": {
"prop0": "B",
"prop1": 0.0
}
},{
"type": "Feature",
"geometry": {
"type": "Polygon",
"coordinates": [
[ [100.0, 0.0], [101.0, 0.0], [101.0, 1.0], [100.0, 1.0], [100.0, 0.0] ]
]
},
"properties": {
"prop0": "C",
"prop1": {"this": "that"}
}
}
]
};
// load GEOJSON object/array to map
L.geoJSON(geojsonFeature, {
// style features based on properties
style: function(feature) {
switch(feature.properties.prop0){
case 'B': return { color: "red" }
case 'C': return { color: "green" }
}
},
// replace default maker with circle for point feature
pointToLayer: function(feature, latlng) {
return L.circleMarker(latlng, {
radius: 14,
fillColor: "orange",
color: "orange",
weight: 2,
opacity: 1,
fillOpacity: 0.5
});
},
// bind tooltip to each feature
onEachFeature: function(feature, layer) {
var popupContent = "<button onclick='removeSelectedLayer(\""+feature.properties.prop0+"\")'>Click here to remove this polygon</button><p>";
if (feature.properties.prop0) {
popupContent += feature.properties.prop0;
}
layer.bindPopup(popupContent);
layer.myTag = feature.properties.prop0
}
}).addTo(map);
function removeSelectedLayer(layerName) {
map.eachLayer( function(layer) {
console.log(layer.myTag)
if ( layer.myTag && layer.myTag === layerName) {
map.removeLayer(layer)
}
});
}
#map {
height: 500px;
}
<link rel="stylesheet" href="https://unpkg.com/leaflet#1.6.0/dist/leaflet.css" crossorigin=""/>
<script src="https://unpkg.com/leaflet#1.6.0/dist/leaflet.js"crossorigin=""></script>
<div id="map"></div>
Hope this will helps you

Leaflet.js - Create layers and add markers depending on geojson category data?

I have a .js file with coordinates for internships:
var internships = [{
"features": [
{"type":"Feature","properties":{"category":"entretient","Name":"green"},"geometry":{"type":"Point","coordinates":[50.807149, 3.162994]}},
{"type":"Feature","properties":{"category":"securité","Name":"blue"},"geometry":{"type":"Point","coordinates":[50.334421, 3.290146]}},
{"type":"Feature","properties":{"category":"secretaria","Name":"red"},"geometry":{"type":"Point","coordinates":[50.744787, 2.256216]}}
]
}];
I've found this bit of code allowing me to create layers depending on a property and here what my JS looks like:
$.getScript("CoordinatesPdC.js");
function mapLoad() {
var sécuritéLayer = new L.LayerGroup();
var secrétariatLayer = new L.LayerGroup();
var entretientLayer = new L.LayerGroup();
var map = L.map('map').setView([50.2910, 2.7775], 8);
L.tileLayer('http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
maxZoom: 18,
attribution: 'Map data © OpenStreetMap contributors, ' +
'CC-BY-SA, '
}).addTo(map);
var marker = L.marker([50.2910, 2.7775]).addTo(map);
var entretientLayer = L.geoJson(internships, {
filter: function (feature, layer) {
return (feature.properties.category === "entretient");
}
}).addTo(map);
var sécuritéLayer = L.geoJson(internships, {
filter: function (feature, layer) {
return (feature.properties.category === "sécurité");
}
}).addTo(map);
var secrétariatLayer = L.geoJson(internships, {
filter: function (feature, layer) {
return (feature.properties.category === "secrétariat");
}
}).addTo(map);
}
window.onload = mapLoad;
But now I have to create the markes assigned to these layers, how can I achieve that?
Your markers are already assigned to each later. In your example, you create a layer (with all of its markers) and immediately add it to the map using .addTo(map); Here's the code responsible for it.
var sécurité = L.geoJson(internships, {
filter: function (feature, layer) {
return (feature.properties.category === "sécurité");
}
}).addTo(map);
Now, you probably want to only display a certain layer based on user input. If so, I suggest adding the related layer to the map on a click event. Then when the event is triggered a layer is added. Here's the code for doing that. sécurité.addTo(map)
A layer is removed using map.removeLayer(sécurité);
Below is a working example based on your initial code. (I did write it in jQuery as my vanilla JavaScript could be better) You can also view it on jsFiddle here.
I left some comments in the code to explain what each part does. I hope that helps you with your understanding.
var internships = [{
"features": [{
"type": "Feature",
"properties": {
"category": "entretient",
"Name": "green"
},
"geometry": {
"type": "Point",
"coordinates": [3.162994, 50.807149]
}
},
{
"type": "Feature",
"properties": {
"category": "securité",
"Name": "blue"
},
"geometry": {
"type": "Point",
"coordinates": [3.290146, 50.334421]
}
},
{
"type": "Feature",
"properties": {
"category": "secretaria",
"Name": "red"
},
"geometry": {
"type": "Point",
"coordinates": [2.256216, 50.744787]
}
}
]
}];
$(document).ready(function() {
// Create an object to keep track of active layers and each layer with its markers
const layers = {
active: [],
entretientLayer: new L.LayerGroup(),
sécuritéLayer: new L.LayerGroup(),
secrétariatLayer: new L.LayerGroup(),
};
// create the map
var map = L.map('map').setView([50.8010, 3.1675], 6,5);
L.tileLayer('http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
maxZoom: 18,
attribution: 'Map data © OpenStreetMap contributors, ' +
'CC-BY-SA, '
}).addTo(map);
// based on the category assign a marker to the layer
layers.entretientLayer = L.geoJson(internships, {
filter: function(feature, layer) {
return (feature.properties.category === "entretient");
}
})
layers.sécuritéLayer = L.geoJson(internships, {
filter: function(feature, layer) {
return (feature.properties.category === "securité");
}
})
layers.secrétariatLayer = L.geoJson(internships, {
filter: function(feature, layer) {
return (feature.properties.category === "secretaria");
}
})
// register click event
$('button').on('click', function(e) {
const layerName = e.target.name;
// if a layer is already active, remove it from the map and the active array
if (layers.active.includes(layerName)) {
layers.active = layers.active.filter(layer => layer !== layerName);
map.removeLayer(layers[layerName]);
} else {
// add the layer to the map and to the active array
layers.active.push(layerName);
layers[layerName].addTo(map);
}
});
});
#map {
height: 140px;
width: 100%;
}
<link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.3.3/leaflet.css" />
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<!--<script src="https://cdnjs.cloudflare.com/ajax/libs/leaflet/0.7.3/leaflet.js"></script> -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.3.3/leaflet-src.js"></script>
<div class="button-group">
<button name="entretientLayer">entretient</button>
<button name="sécuritéLayer">sécurité</button>
<button name="secrétariatLayer">secrétariat</button>
</div>
<p></p>
<div id="map"></div>
UPDATE: updated leaflet.js to version 1.3.3.
The difference with the update is that each layer needs to be initialised using the new key word. Code is updated to reflect the change.

Google Maps forEach with setMap to set polyline visiblity (error: setMap is not a function)

I am trying to set the visibility of polylines based on a property. I use forEach to iterate over the features in the GeoJson data but when I try and call setMap on the array, I get type error: setMap is not a function. I have also tried pushing the resulting features into a new array with the same result.
map.data.loadGeoJson(
'data/trails2018.geojson', {},
function(features) {
console.log("loadGeoJson callback "+features.length);
map.data.forEach(function(feature) {
var skill = feature.getProperty('skill_leve');
if (skill == 'ADVANCED'){
feature.setMap(null);
}
});
});
You control the visibility of features on a Data Layer with the style property visible.
map.data.setStyle(function(feature) {
var visible = false;
if (feature.getProperty('skill_level')) {
var skill = feature.getProperty('skill_level');
if (skill == 'ADVANCED') {
visible = true;
}
}
return /** #type {google.maps.Data.StyleOptions} */ ({
strokeColor: "blue",
visible: visible
});
});
proof of concept fiddle
code snippet:
function initialize() {
var map = new google.maps.Map(
document.getElementById("map_canvas"), {
center: new google.maps.LatLng(-23.55865, -46.65953),
zoom: 5,
mapTypeId: google.maps.MapTypeId.ROADMAP
});
var features = map.data.addGeoJson(geoJson);
console.log("addGeoJson returns " + features.length);
map.data.forEach(function(feature) {
var skill = feature.getProperty('skill_level');
if (skill == 'ADVANCED') {
// feature.setMap(null);
}
});
map.data.setStyle(function(feature) {
var visible = false;
if (feature.getProperty('skill_level')) {
var skill = feature.getProperty('skill_level');
if (skill == 'ADVANCED') {
visible = true;
}
}
return /** #type {google.maps.Data.StyleOptions} */ ({
strokeColor: "blue",
visible: visible
});
});
}
google.maps.event.addDomListener(window, "load", initialize);
var geoJson = {
"type": "FeatureCollection",
"features": [{
"type": "Feature",
"properties": {
"id": 1,
"skill_level": "ADVANCED"
},
"geometry": {
"type": "LineString",
"coordinates": [
[-43.48283, -23.02487],
[-43.65903, -23.55888]
]
}
},
{
"type": "Feature",
"properties": {
"id": 2,
"skill_level": "BEGINNER"
},
"geometry": {
"type": "LineString",
"coordinates": [
[-46.65953, -23.02487],
[-46.65903, -23.55888]
]
}
}
]
}
html,
body,
#map_canvas {
height: 100%;
width: 100%;
margin: 0px;
padding: 0px
}
<script src="https://maps.googleapis.com/maps/api/js"></script>
<div id="map_canvas"></div>

Loading GeoJSON into Mapbox

When I use GeoJSON inside the HTML it works, but when I try to load externally it doesn't.
My HTML file and GeoJSON file are in the same folder in site.
I try to open picture popups with markers.
Thanks a lot!
L.mapbox.accessToken = 'lalalalala';
var southWest = L.latLng(40.875557, 29.235992),
northEast = L.latLng(41.277226, 28.749847),
bounds = L.latLngBounds(southWest, northEast);
var map = L.mapbox.map('map', 'mapbox.light', {
maxBounds: bounds,
maxZoom: 19,
minZoom: 11
});
var myLayer = L.mapbox.featureLayer()
.loadURL('http://terkedilmisarabalar.mudurlugu.org/geojson/terkedilmisarabalar.geojson')
.on('ready', function() {
myLayer.eachLayer(function(layer) {
map.fitBounds(myLayer.getBounds());
layer.bindPopup(layer.features.properties.name);
});
})
.addTo(map);
myLayer.setGeoJSON(geojson);
myLayer.on('onclick', function(e) {
e.layer.openPopup();
});
myLayer.on('onrelease', function(e) {
e.layer.closePopup();
});
Here is an example GeoJSON file:
{
type: 'FeatureCollection',
features: [
{
"type": "Feature",
"properties": {
"name": "Acıbadem Cd. No:117",
"description": "<img src=\"https://lh3.googleusercontent.com/DkEl65k9kZAtvPdf9HuE22aIAJKUKBDtiL0m5vZBRqn9nVsgcQIQYdi03gt5yhOKcrEvTQpctu_xnLVfhzzt6Tr3fGtsxuIJSqPrf7R9p-0faSL-YRxTzyn44B8KVB8\" height=\"200\" width=\"auto\" /><br><br>",
"gx_media_links": "https://lh6.googleusercontent.com/fmIjm4ynkTWSkmzcOfoMCoVgnm6h9pQ8KINgHqhjx-ZNQMrT05NqsZo2Lv5d6FwFFakmqOzl_ruRKvu34jbC96U3nKaxlu0sul6W4qXU1ily4PNbLCQTsR2BGKOxervb"
},
"geometry": {
"coordinates": [
29.045881,
41.005992,
0
],
"type": "Point"
}
}

Google Maps API: getFeatureById for feature collection not working

I try to change the style of a specific feature of a feature collection data overlay. This is a snippet of my json:
{
"type": "FeatureCollection",
"features": [
{
"type": "Feature",
"id": 1,
"properties": {
"name": "1 CBD - Bankenviertel",
"color": "transparent",
"isHovered": false,
"isActive": false
},
"geometry": {
"type": "Polygon",
"coordinates": [
[
[
8.67279430349,
50.1143807311
],
[
8.67280054398,
50.1143975981
]
]
]
}
}
and this is the relevant snippet from my map.js
map.data.loadGeoJson('some.json');
console.log(map.data.getFeatureById(1));
And I am always getting "undefined" in the console.
What am I doing wrong here?
Thanks,
Robert
You need to call map.data.getFeatureById(1) inside the callback function (so it doesn't execute before the GeoJson has loaded).
from the documentation:
loadGeoJson(url:string, options?:Data.GeoJsonOptions, callback?:function(Array<Data.Feature>))
Return Value: None
Loads GeoJS
proof of concept fiddle
code snippet:
var geocoder;
var map;
function initialize() {
var map = new google.maps.Map(
document.getElementById("map_canvas"), {
zoom: 4,
center: {
lat: -28,
lng: 137
},
mapTypeId: google.maps.MapTypeId.ROADMAP
});
// map.data.addGeoJson(geoJson);
map.data.loadGeoJson(
'https://api.myjson.com/bins/1teyu', {},
function(features) {
console.log(map.data.getFeatureById(1));
console.log(map.data.getFeatureById(1).getProperty("letter"));
});
}
google.maps.event.addDomListener(window, "load", initialize);
html,
body,
#map_canvas {
height: 100%;
width: 100%;
margin: 0px;
padding: 0px
}
<script src="https://maps.googleapis.com/maps/api/js?key=AIzaSyCkUOdZ5y7hMm0yrcCQoCvLwzdM6M8s5qk"></script>
<div id="map_canvas"></div>

Categories

Resources