layers control and geojson on mapbox/leaflet - javascript

I'm mixing up the choropleth example
and the layes control example
Using layers control with tiles, i've no problems, it works perfectly, but i need to work with geojson and this is my problem:
the gejson layer is ever in foreground and tiles on background.
but i need that when selecting a "streets" tile in layercontrol it come in foreground and l.geojson in backgrnd.
i need it to show labels. Using trasparency is not good for my purposes.
any solution?
here a part of the code:
var mapdataviz = L.mapbox.map('map', 'andria.h41061in')
.setView([39.0981, 16.5619], 8);
mapdataviz.legendControl.addLegend(document.getElementById('legend-content').innerHTML);
L.control.layers({
'city': L.mapbox.tileLayer('andria.cal_com_ief1'),
'com_geojson': L.geoJson(comData, {
style: getStyle,
onEachFeature: onEachFeature
}).addTo(mapdataviz),
'streets': L.mapbox.tileLayer('andria.h41061in')
},
{
'streets': L.mapbox.tileLayer('andria.h41061in'),
'com_geojson': L.geoJson(comData, {
style: getStyle,
onEachFeature: onEachFeature
}).addTo(mapdataviz),
'bounds': L.mapbox.tileLayer('andria.cal_conf')
}).addTo(mapdataviz);
var popup = new L.Popup({ autoPan: false });
// comData comes from the 'us-states.js' script included above
var comLayer = L.geoJson(comData, {
style: getStyle,
onEachFeature: onEachFeature
})
function getStyle(feature) {
return {
weight: 0.7,
opacity: 0.5,
color: 'white',
fillOpacity: 0.8,
fillColor: getColor(feature.properties.IEF1_2008)
};
}

You mention that transparency is not good for your purposes but this MapBox tutorial demonstrates how to put the geoJson layer behind the street map layer.
https://www.mapbox.com/blog/neighborhood-mapping-with-dynamic-vector-data-layers/
Is that helpful?

Related

Styling individual markers in markercluster

I am trying to style individual markers, or clusters of size 1, based on some feature property.
var markers = L.markerClusterGroup();
function onEachFeature(feature, layer) {
if (feature.properties.EncounterType && feature.properties.Year) {
layer.bindPopup(feature.properties.EncounterType + " in " +
feature.properties.Year);
}
}
function style(feature) {
switch (feature.properties.EncounterType) {
case 'Shooting':
return {
color: "ff0000"
};
case 'Sighting':
return {
color: "0000ff"
};
case 'Hunting':
return {
color: "ff0000"
};
}
}
var geoJsonLayer = L.geoJSON(storer, {
onEachFeature: onEachFeature
}, {
style: style
});
markers.addLayer(geoJsonLayer);
map.addLayer(markers);
The onEachFeature function successfully creates the popups. However, the style function does not change the color of the clusters of size 1. I've tried using the iconCreateFunction when initializing the markerclustergroup, however, that did not work either.
Your style option is separated in a 3rd argument of your call to L.geoJSON factory, whereas it should have been placed within the 2nd argument, alongside onEachFeature option.
var geoJsonLayer = L.geoJSON(storer, {
onEachFeature: onEachFeature,
style: style
});
But that is probably not the only reason for your issue.
style option will apply to vector shapes (polylines, polygons, etc.), i.e. to non-point data. It may also apply to Circle Markers, which can be used for Point type geometries, but you have to explicitly create them (typically through the pointToLayer option).
Those non-point data cannot be handled by Leaflet.markercluster.
Therefore if you see "clusters of size 1" (I guess you mean markers), they come from unstyled Point type geometries in your storer GeoJSON data.
This is a normal marker:
It is a PNG image that cannot be styled.
If you want to customize the appearance of your Point geometries, use custom icons, a plugin that provide such custom icons, or Circle Markers which you can modify the colour easily (including through the style option).
For example, if you were to choose that last option, you could do something like:
var geoJsonLayer = L.geoJSON(storer, {
pointToLayer: function (geoJsonPoint, latlng) {
return L.circleMarker(latlng);
},
onEachFeature: onEachFeature,
style: style
});

Bring to front some circle markers in leaflet feature

I have a feature in a Leaflet map made up of many circle markers (L.circleMarker). The markers are symbolized to show whether a picture was taken at that location.
What I would like to do is bring all the markers that do have a photo at that location to the top of the layer, similar to how a marker can be raised with a mouse-over (but without mouse-over in this case).
Here is an illustration of the original version:
And this is what I would like them to be:
I've considered having different layers for photos vs. no photos, but due to some functions in the map, it's preferable that they are in a single layer.
Any ideas as to how this could be done with JavaScript and Leaflet?
In the style definition for the circle marker it's possible to specify the "map pane" to which the marker is rendered (http://leafletjs.com/reference-1.0.3.html#map-pane). It seems like this is the only way to specify the zIndex of circleMarkers (regular markers have a zindexOffset option).
My code looks like this:
var style = {
radius: 1.75,
fillColor: "darkred",
color: "darkred",
pane: 'overlayPane'
};
var picStyle = {
radius: 0.25,
fillColor: "blue",
color: "blue",
pane: 'shadowPane'
};
var site2 = new L.geoJSON(valuesSite2, {
onEachFeature: onEachFeature,
pointToLayer: function (feature, latlng) {
feature.properties.layer = "Site 2";
onEachFeature: onEachFeature;
if (<there is a picture>) {
return L.circleMarker(latlng, picStyle)
} else {
return L.circleMarker(latlng, style);
}
}
}).addTo(map);
The result looks like:

Draw radius in meters using Maps API v3 Data layer based on GeoJSON

I am using the Maps API v3 and added a GeoJSON file to create a circle (based on google.maps.Symbol objects) around each entry in the GeoJSON-file -- which works quite fine by using the setStyle-functionality:
map.data.addGeoJson('url_to_GeoJSON');
..
map.data.setStyle(function(feature) {
return /** #type {google.maps.Data.StyleOptions} */({
icon: {
path: google.maps.SymbolPath.CIRCLE,
scale: 5,
fillColor: '#f00',
fillOpacity: 0.5,
strokeWeight: 0
}
});
});
Now I would need to draw a circle with a static radius in meters around each point, like it is provided by the regular google.maps.CircleOptions with its 'radius'.
Is there any possibility to use the very comfortable data layer 'addGeoJson'- and 'setStyle'-features in combination with a geographically correct radius in meters around each point?
I would be very happy to avoid setting up each marker manually "the old way" by iterating through the whole GeoJSON-file with
new google.maps.Circle({radius: 20000});
Any help is greatly appreciated! Thanks in advance!
After adding the code of Dr. Molle, there seems to be an issue while using multiple google.maps.Data-Objects, that should be shown/hide by checking/unchecking a checkbox within the website. This is my actual code, which already shows the data layer with drawn circles, but does not hide the circles of the specific data layer when unchecking a checkbox:
var map;
var dataset1 = new google.maps.Data();
var dataset2 = new google.maps.Data();
var dataset3 = new google.maps.Data();
function initialize() {
// Create a new map.
map = new google.maps.Map(document.getElementById('map-canvas'), {
zoom: 6,
center: {lat: 50.678240, lng: 9.437256},
mapTypeId: google.maps.MapTypeId.TERRAIN
});
checkDataset();
}
function checkDataset() {
if (document.getElementById('chkDataset1').checked) {
// Define styles for dataPlug9 and apply to map-object.
dataset1.setStyle(function(feature) {
var geo = feature.getGeometry();
// Check for a point feature.
if(geo.getType().toLowerCase()==='point'){
//create a circle
feature.circle = new google.maps.Circle({
map: map,
center: geo.get(),
radius: 200000,
fillColor: '#FF0000',
fillOpacity: 0.05,
strokeColor: '#FF0000',
strokeOpacity: 0.4,
strokeWeight: 1
});
//trigger the dblclick-event of map.data on a dblclick on the circle
google.maps.event.addListener(feature.circle, 'dblclick',function(e){
e.stop();
google.maps.event.trigger(this.getMap().data,'dblclick', {feature:feature})
});
// Hide the marker-icon.
return {visible:false};
}});
// Remove feature on dblclick.
google.maps.event.addListener(dataset1,'dblclick',function(f){
this.remove(f.feature);
});
// Remove circle too when feature will be removed.
google.maps.event.addListener(dataset1,'removefeature',function(f){
try{f.feature.circle.setMap(null);}catch(e){}
});
dataset1.loadGeoJson('data/plug1.json');
dataset1.setMap(map);
} else {
dataset1.removefeature();
// This doesn't work either ..
dataset1.setMap(null);
}
}
I also added the above routine of function checkDataset() for the other 2 datasets (dataset2 and dataset3) and changed 'dataset1' to 'dataset2 / dataset3'.
You don't need to iterate "manually", setStyle already iterates over the features.
You may use it to execute additional code(e.g. create a google.maps.Circle):
map.data.setStyle(function(feature) {
var geo= feature.getGeometry();
//when it's a point
if(geo.getType().toLowerCase()==='point'){
//create a circle
feature.circle=new google.maps.Circle({map:map,
center: geo.get(),
radius: 20000,
fillColor: '#f00',
fillOpacity: 0.5,
strokeWeight: 0});
//and hide the marker when you want to
return {visible:false};
}});
Edit:
related to the comment:
The circles will be saved as a circle-property of the features(note: this property is not a property in the meaning of geoJSON, so it may not be accessed via getProperty).
You may add a listener for the removefeature-event and remove the circle there, so the circle will be removed when you remove the feature.
Sample code that will remove a feature(including the circle) on dblclick:
map.data.setStyle(function(feature) {
var geo= feature.getGeometry();
//when it's a point
if(geo.getType().toLowerCase()==='point'){
//create a circle
feature.circle=new google.maps.Circle({map:map,
center:geo.get(),
radius:200000,
fillColor: '#f00',
fillOpacity: 0.5,
strokeWeight: 0});
//trigger the dblclick-event of map.data on a dblclick on the circle
google.maps.event.addListener(feature.circle, 'dblclick',function(e){
e.stop();
google.maps.event.trigger(this.getMap().data,'dblclick',{feature:feature})
});
//and hide the marker
return {visible:false};
}});
//remove the feature on dblclick
google.maps.event.addListener(map.data,'dblclick',function(f){
this.remove(f.feature);
});
//remove the circle too when the feature will be removed
google.maps.event.addListener(map.data,'removefeature',function(f){
try{f.feature.circle.setMap(null);}catch(e){}
});

Google Maps: Polygon and Marker Z-Index

I have a Google Map with many markers (yellow circles), and I implemented a tool to draw polygons over the markers. However, the polygon is behind the markers while drawing (and stays behind when complete).
I tried changing the ZIndex in both markers and polygons, but it seems to alter the way in which markers are shown with respect to other markers, and not with respect to polygons. I also tried
polygon.setZIndex(google.maps.Marker.MAX_ZINDEX + 1);
How can I bring the polygon to the front?
This won't solve the problem, but it will explain why the things you tried didn't work.
The Maps API uses several layers known as MapPanes in a fixed Z order:
4: floatPane (infowindow)
3: overlayMouseTarget (mouse events)
2: markerLayer (marker images)
1: overlayLayer (polygons, polylines, ground overlays, tile layer overlays)
0: mapPane (lowest pane above the map tiles)
So the marker images in layer 2 are always above the polygons in layer 1. When you fiddle with the z-index on the markers, you're just adjusting them relative to each other. That doesn't do any good, because they are all in a layer above the polygons.
What can you do about this? The only solution I can think of is to create your own OverlayView for the polygons or the markers so you can put them in the MapPane you want.
Are your markers clickable, or are they just static images? If they aren't clickable, you could possibly get away with drawing them yourself in the mapPane. Then your polygons would be above them. Or the opposite: you could draw the polygons yourself in one of the higher layers, maybe in floatShadow.
The problem then is you have to do all of your own drawing, either with a canvas element or with DOM images. And your own mouse hit testing too if they are clickable.
There aren't a lot of good OverlayView examples out there, but I'll mention one of my own: a little library I wrote a while ago called PolyGonzo, where the polygonzo.js file has the OverlayView implementation. The code isn't great - I threw it together in too much of a hurry - but it may help give you some ideas.
I know this question is old but for future users I wanna share my approach:
Shapes with higher zIndex values displaying in front of those with lower values. For this example I am using Polygon but is similar for other shapes:
var globalZIndex = 1; //Be sure you can access anywhere
//... Other instructions for creating map, polygon and any else
polygon.setOptions({ zIndex: globalZIndex++ });
Notice that markers have a method setZIndex(zIndex:number).
I found this solution
To Create a Symbol use this code below
var lineSymbol = {
path: google.maps.SymbolPath.FORWARD_CLOSED_ARROW,
strokeColor: '#181727',
fillColor: '#50040B',
};
var dashedSymbol = {
path: 'M 0,-1 0,1',
strokeOpacity: 1,
scale: 4
};
[![function MakeMarker(pinColor){
var pinImage = new google.maps.MarkerImage("http://chart.apis.google.com/chart?chst=d_map_pin_letter&chld=%E2%80%A2|" + pinColor,
new google.maps.Size(21, 34),
new google.maps.Point(0,0),
new google.maps.Point(10, 34));
return pinImage;
}][1]][1]
FlowMarkersdashed(new google.maps.LatLng(positionorigin[0], positionorigin[1]),
new google.maps.LatLng(positiondestination[0], positiondestination[1]), myObject[i]['flowfluxphysique'][j]['colorFlux'], dashedSymbol, j);
function FlowMarkersdashed(latlngOrgin, latlngDest, ColorFlow, Symbol, indexvar){
var flightPlanCoordinates = [
latlngOrgin,
{lat: latlngOrgin.lat() + (indexvar) * 2, lng: latlngOrgin.lng()},
// {lat: -18.142, lng: 178.431},
latlngDest,
];
var line = new google.maps.Polyline({
path: flightPlanCoordinates,
strokeOpacity: 0,
icons: [{
icon: Symbol,
// offset: '100%',
offset: '0',
repeat: '20px'
// repeat: '20px'
}],
strokeColor: "#"+ColorFlow,
geodesic: true,
// editable: true,
map: map
});
}
And to Create a Flow Marker try this code
FlowMarkers(new google.maps.LatLng(positionorigin[0], positionorigin[1]),
new google.maps.LatLng(positiondestination[0], positiondestination[1]), myObject[i]['flowfluxinformation'][j]['colorFlux'], lineSymbol,j);
function FlowMarkersdashed(latlngOrgin, latlngDest, ColorFlow, Symbol, indexvar){
var flightPlanCoordinates = [
latlngOrgin,
{lat: latlngOrgin.lat() + (indexvar) * 2, lng: latlngOrgin.lng()},
// {lat: -18.142, lng: 178.431},
latlngDest,
];
var line = new google.maps.Polyline({
path: flightPlanCoordinates,
strokeOpacity: 0,
icons: [{
icon: Symbol,
// offset: '100%',
offset: '0',
repeat: '20px'
// repeat: '20px'
}],
strokeColor: "#"+ColorFlow,
geodesic: true,
// editable: true,
map: map
});
}
This is my result
Change this method call:
polygon.setZIndex(google.maps.Marker.MAX_ZINDEX + 1);
to this:
polygon.setZIndex(4);

Dynamically change the color of a polygon in leaflet?

For anyone who is familiar with Leaflet, do you know a way to dynamically change a polygon's color? For example, take a circle defined like this:
window.circle = L.circle([51.508, -0.11], 500, {
color: 'red',
fillColor: '#ffffff',
fillOpacity: 0.5
}).addTo(map);
Then later, after a user clicks a button somewhere on an interface (for example), I want to change the color of the circle like this:
window.circle.options.fillColor = "#dddddd";
The code changes the value for window.circle.options.fillColor, but the change is not reflected by a change to the color of the polygon on the map. I've searched around but haven't found anything. Any ideas?
Thanks.
L.Circle extends L.Path (http://leafletjs.com/reference.html#path), that have method setStyle( <Path options> object ), and you can apply new style as window.circle.setStyle({fillColor: '#dddddd'});
If you are looking for something like this:
const circle = L.circle([lat, lng], {
style: style,
onEachFeature: onEachFeature,
});
These options are available for geoJson data ie: L.geojson()..... :D
So, for polygon .
Try,
circle.setStyle({
color: 'red'
});
I have a set of polygons in my map, this code can change the fillcolor of each polygon dynamically :
// 'file' is a geojson layer
L.geoJSON(file, {
onEachFeature: colorlayer,
style: {
color: "#00008c",
opacity: 0.6,
fillColor: '#333333',
fillOpacity: 0
}
}).addTo(map);
function colorlayer(feature, layer) {
layer.on('mouseover', function (e) {
layer.setStyle({
fillOpacity: 0.4
});
});
layer.on('mouseout', function (e) {
layer.setStyle({
fillOpacity: 0
});
});
}

Categories