I was looking at the choropleth example.
https://leafletjs.com/examples/choropleth/
This is the data source they use
{
"type": "Feature",
"properties": {
"name": "Alabama",
"density": 94.65
},
"geometry": ...
...
}
My dataset is a feature collection of polygons so it looks like
{
"type": "Feature Collection",
"Features": [
{
"type": "Feature",
"properties": {
"name": "Alabama",
"density": 94.65
},
"geometry": ...
...
},
{
"type": "Feature",
"properties": {
"name": "Ohio",
"density": 99.65
},
"geometry": ...
...
},
}
Anyway so its an array so when i make my style function I use
const finalLayer = L.geoJSON(currentLayer.layer, {
style: {this.styleData(currentLayer.layer)}
});
this.currentProjectLayers.push(finalLayer);
finalLayer.addTo(this.map);
getColor(data) {
return data > 1000000 ? '#800026' :
data > 800000 ? '#BD0026' :
data > 600000 ? '#E31A1C' :
data > 400000 ? '#FC4E2A' :
data > 200000 ? '#FD8D3C' :
'#FEB24C';
}
styleData(feature) {
return {
fillColor: this.getColor(feature.features[0].properties.totalHH),
weight: 2,
opacity: 1,
color: 'white',
dashArray: '3',
fillOpacity: 0.7
};
}
Obviously i don't want to use 0 as the index. When I use the index it colors them all according to the index of the one spot. I know how to do a forEach but I don't think that will work. I need to do the style in an onEachFeature i think.... But can I apply the style using OnEachFeature.. how would I do that?
You are probably trying to work around an issue that does not exist.
Although that may not be explicit, Leaflet GeoJSON factory also parses GeoJSON Feature Collection, as if it were directly an array of Features. As such, each of those Features will be modified by the style option, which receives as argument the Feature data:
L.geoJSON(geojsonFeatureCollectionObject, {
style: function (featureObject) {
return {
fill: featureObject.properties.totalHH
};
}
});
Related
I am trying to change the color of a marker which is a circle, that is being painted using the paint property on a layer.
Following this tutorial:
https://docs.mapbox.com/mapbox-gl-js/example/hover-styles/
I have set the circle-color to be dependent of a feature-state:
map.addLayer({
id: "singles",
type: "circle",
source: "users",
filter: ["!has", "point_count"],
paint: {
'circle-radius': {
'base': 10,
'stops': [[5, 20], [15, 500]]
},
'circle-color': ["case",
["boolean", ["feature-state", "hover"], false],
'#ddffc8',
'#ff0000'
],
}
});
Then when somebody hovers over a sidebar, I want to update the feature-state and change the color:
function highlightMarkersOnHoverOnSidebar (markers, map) {
let marks = markers
Array.from(document.querySelectorAll('.sideBarItems')).map( (x, i) => {
x.addEventListener('mouseenter', function(){
map.setFeatureState({source: 'users', id: marks.features[i].properties.id}, { hover: true});
}, false)
x.addEventListener('mouseleave', function(){
map.setFeatureState({source: 'users', id: marks.features[i].properties.id}, { hover: false});
}, false)
})
}
However, nothing happens when i hover the sidebar element.. and it doesnt even throw an error.
Is there anything im missing? thanks.
I also run into this issue.
It seems like you need an id at the feature level in your geojson. Not in the properties:
{
"type": "FeatureCollection",
"features": [
{
"id": 4459,
"type": "Feature",
"geometry": {
"type": "Point",
"coordinates": [
8.64543,
50.163105
]
},
"properties": {
"id": "NOT HERE",
"name": "Test",
"foo": "bar",
}
}
]
}
Moving the id to the feature solved the issue.
Are you using featureCollection in geoJson? That caused some problems for me.
I've created a map using mapbox and plotted multiple custom points that you can interact with. I am also using Wordpress and want to use advanced custom fields to create each point so they can easily be managed from a non-technical person. The fields are all setup, but I am having trouble passing them into the javascript in my php template.
I've tried using a loop but I can't use the loop inside javascript. Here is my Mapbox code that I am using to plot the points and want to use advanced custom fields with:
var map = new mapboxgl.Map({
container: 'map',
style: 'mapbox://styles/coptmarketing/cjvi7hc4602dk1cpgqul6mz0b',
center: [-76.615573, 39.285685],
zoom: 16 // starting zoom
});
var geojson = {
"type": "FeatureCollection",
"features": [{
"type": "Feature",
"properties": {
"title": "Shake Shack",
"id": "shake-shack"
},
"geometry": {
"type": "Point",
"coordinates": [-76.609844, 39.286894]
}
},
{
"type": "Feature",
"properties": {
"title": "Starbucks",
"id": "starbucks"
},
"geometry": {
"type": "Point",
"coordinates": [-76.619071, 39.286649]
}
}
]
};
I've stored the data in a JSON array:
[{"title":"Shake Shack","slug":"shake-shack","latitude":"-76.609844","longitude":"39.286894"},{"title":"Starbucks","slug":"starbucks","latitude":"-76.619071","longitude":"39.286649"}]
How do I insert this into the geoJSON?
Figured it out:
First I created a plugin that stored the custom post data in a JSON array and stored it on the server. This also updated every time I updated, saved or deleted a post. Here is the example JSON:
data = {"placeList": [{"title":"Shake Shack","slug":"shake-shack","latitude":"-76.609844","longitude":"39.286894"},{"title":"Starbucks","slug":"starbucks","latitude":"-76.619071","longitude":"39.286649"}]}
Then in the php file, I called the .json file and in my javascript, inserted the array into the GeoJSON:
var placeJson = data;
var geojson = {
type: "FeatureCollection",
features: [],
};
for (i = 0; i < placeJson.placeList.length; i++) {
geojson.features.push({
"type": "Feature",
"geometry": {
"type": "Point",
"coordinates": [placeJson.placeList[i].latitude, placeJson.placeList[i].longitude]
},
"properties": {
"id": placeJson.placeList[i].slug,
"title": placeJson.placeList[i].title
}
});
}
I am trying to show clusters using markerclustergroups with Polygons. Right now the polygons are shown but the clusters aren't. I have been trying to use center of mass for the polygons because it seems like markerclustergroup doesn't like polygons but that doesn't really work since the animation of markerclustergroup will be set on the centroids and not the actual polygon.
My polygons all vary in amount of coordinates. Some have +10 sets others have 3.
How would I use markerclustergroup for polygons?
Below my code can be seen:
// Create variable to hold map element, give initial settings to map
var map = L.map('map', {
center: [23.70489, 43.90137],
zoom: 5
});
L.tileLayer('http://{s}.tile.osm.org/{z}/{x}/{y}.png', {
}).addTo(map);
var ojStyle = {
"color": "#ff7800",
"weight": 5,
"opacity": 0.65
};
// Hardcoded polygons as GeoJSON
var polygons = {
"type": "FeatureCollection",
"features": [{
"type": "Feature",
"properties": {},
"geometry": {
"type": "Polygon",
"coordinates": [
[
[37.99896240234376, 21.55017532555692],
[39.39422607421876, 21.476073444092435],
[38.88336181640626, 22.56582956966297],
[38.023681640625, 22.611475436593366],
[37.43591308593751, 21.99908185836153],
[37.28485107421876, 21.624239377938288],
[37.28485107421876, 21.624239377938288],
[37.99896240234376, 21.55017532555692]
]
]
}
}, {
"type": "Feature",
"properties": {},
"geometry": {
"type": "Polygon",
"coordinates": [
[
[38.50708007812501, 21.453068633086783],
[39.20745849609376, 21.37124437061832],
[39.10858154296876, 20.876776727727016],
[38.80920410156251, 20.912700155617568],
[38.49884033203126, 20.94604992010052],
[38.50708007812501, 21.453068633086783]
]
]
}
}, {
"type": "Feature",
"properties": {},
"geometry": {
"type": "Polygon",
"coordinates": [
[
[50.57830810546875, 25.980268007469803],
[50.77606201171876, 25.956809920555312],
[50.780181884765625, 25.69970044378398],
[50.56457519531251, 25.822144306879686],
[50.56182861328126, 25.945696562830516],
[50.57830810546875, 25.980268007469803]
]
]
}
}, {
"type": "Feature",
"properties": {},
"geometry": {
"type": "Polygon",
"coordinates": [
[
[54.37408447265626, 24.51963836811676],
[54.29443359375001, 24.40963901896311],
[54.25872802734375, 24.449649897759667],
[54.32739257812501, 24.539627918861232],
[54.37133789062501, 24.559614286039903],
[54.37408447265626, 24.51963836811676]
]
]
}
}, {
"type": "Feature",
"properties": {},
"geometry": {
"type": "Polygon",
"coordinates": [
[
[54.40155029296876, 24.463400705082282],
[54.41940307617188, 24.489648077028683],
[54.45785522460938, 24.462150693715266],
[54.43450927734376, 24.43839812102505],
[54.40155029296876, 24.463400705082282]
]
]
}
}]
}
var polygonArray = []
for (i = 0; i < polygons.features.length; i++) {
polygonArray.push(polygons.features[i]);
}
var markers = L.markerClusterGroup().addTo(map);
var geoJsonLayer = L.geoJson(polygonArray);
markers.addLayer(geoJsonLayer);
map.fitBounds(markers.getBounds());
http://js.do/code/165930 - Shows how clustering doesn't work for the polygons
I am looking for a solution like this: http://jsfiddle.net/ve2huzxw/237/
You can do it very much like in this GIS post: Is it possible to cluster polygons in Leaflet?
// Compute a polygon "center", use your favourite algorithm (centroid, etc.)
L.Polygon.addInitHook(function() {
this._latlng = this._bounds.getCenter();
});
// Provide getLatLng and setLatLng methods for
// Leaflet.markercluster to be able to cluster polygons.
L.Polygon.include({
getLatLng: function() {
return this._latlng;
},
setLatLng: function() {} // Dummy method.
});
Updated live example: http://js.do/code/166021
I am trying to use PolyLineDecorator with Leaflet but I've hit a snag that I can't figure out even forgoing PolyLineDecorator when it comes to symbolizing a path/line based on attribute data.
var polyline = L.polyline([...]).addTo(map);
var decorator = L.polylineDecorator(polyline, {
patterns: [
// defines a pattern of 10px-wide dashes, repeated every 20px on the line
{offset: 0, repeat: 20, symbol: L.Symbol.dash({pixelSize: 10})}
]
}).addTo(map);
Works great for me however, I have 20 lines in a single GeoJSON file and i'd like to symbolize the lines based on the Name field in the JSON file. I can't seem to find an example anywhere covering this. Can someone point me to any relevant examples or documentation? I feel like there has to be a way vs exporting each line as its own GeoJSON file.
Thanks for any help.
You should use GeoJson onEachFeature() method for this. Let's asume that your geoJson structure is:
var geojsonFeatures = [
{
"type": "Feature",
"properties": {
"name": "Trail 1",
},
"geometry": {
"type": "Point",
"coordinates": [-104.99404, 39.75621]
}
},
{
"type": "Feature",
"properties": {
"name": "Trail 2",
},
"geometry": {
"type": "Point",
"coordinates": [-104.99404, 39.75621]
}
}
];
You can access feature's name properties by feature.properties.name:
L.geoJson(geojsonFeature, {
onEachFeature: function (feature, layer) {
if (feature.properties.name === '') {
L.polylineDecorator(layer, {
patterns: [
{offset: 0, repeat: 20, symbol: L.Symbol.dash({pixelSize: 10})}
]
}).addTo(map);
} else {
L.polylineDecorator(layer, {
patterns: [
{offset: 0, repeat: 30, symbol: L.Symbol.dash({pixelSize: 20})}
]
}).addTo(map);
}
})
})
Updated with a JSFIDDLE link
I am using LeafletJS to build a web map with a timeline slider. I am using the LeafletSlider plugin to show a group of markers based on a GEOJSON property named DATE_START. Here's an example of what my data object looks like:
var camps = {
"type": "FeatureCollection",
"features": [{
"type": "Feature",
"properties": {
"STATUS": "UNOCCUPIED",
"DATE_START": "2015-06-23",
"DATE_CLOSED": "2016-01-23"
},
"geometry": {
"type": "Point",
"coordinates": [64.6875, 34.97600151317591]
}
}, {
"type": "Feature",
"properties": {
"STATUS": "OCCUPIED",
"DATE_START": "2014-01-21",
"DATE_CLOSED": "2015-05-25"
},
"geometry": {
"type": "Point",
"coordinates": [65.335693359375, 36.26199220445664]
}
}, {
"type": "Feature",
"properties": {
"STATUS": "UNOCCUPIED",
"DATE_START": "2015-09-13",
"DATE_CLOSED": ""
},
"geometry": {
"type": "Point",
"coordinates": [67.587890625, 35.969115075774845]
}
}]
};
An example of my code:
//Create a marker layer (in the example done via a GeoJSON FeatureCollection)
var testlayer = L.geoJson(camps, {
onEachFeature: function(feature, layer) {
layer.bindPopup(feature.properties.DATE_START);
}
});
var sliderControl = L.control.sliderControl({
position: "topright",
layer: testlayer,
timeAttribute: 'DATE_START'
});
//Make sure to add the slider to the map ;-)
map.addControl(sliderControl);
//And initialize the slider
sliderControl.startSlider();
I've added the timeslider plugin to my map, and although it's functioning, I can't seem to get the slider to show the markers in a temporal order. For example, the marker with the DATE_START value of 2014-01-21 is shown second when in fact it should be shown first because it's the marker with the earliest date.
How can I get my timeslider/markers to appear in the correct order from earliest to latest? Thanks.
EDIT:
As ghybs mentions below (and shows in an example), the proper way to ensure that the slider returns data in the correct order is to sort the options.markers array of the sliderControl:
sliderControl.options.markers.sort(function(a, b) {
return (a.feature.properties.DATE_START > b.feature.properties.DATE_START);
});
My original answer (below) sorts the features of the GeoJSON, but this does not guarantee that Leaflet will return them in the correct order.
Original answer:
You can use the array.sort method to sort the features array in place:
camps.features.sort(function(a, b) {
return (a.properties.DATE_START > b.properties.DATE_START);
});
http://jsfiddle.net/nathansnider/ngeLm8c0/4/