adding geojson layer results in a grey background which covers base map - leaflet

Steps to reproduce
Steps to reproduce the behavior:
Go to https://virgilxw.github.io/Singapore_Election_1955/
Click on the top right button on the map
click on "data"
click on "constituencies"
Expected behavior
Polygons should overlay base map
Current behavior
base map covered by grey-colored layer
Leaflet version:1.51.1
Browser (with version):
OS/Platform (with version):
Additional context
``
// Default base Map
map.addLayer(LayerOSM);
// Add geojson
var Layer1955Wards = new L.GeoJSON.AJAX("data/wards1955.geojson");
// Styled Layer Control
var baseMaps = [
{
groupName: "Base Maps",
expanded: true,
layers: {
"OneMap": LayerOneMapSG_Default,
"OSM": LayerOSM
}
}];
var overlays = [
{
groupName: "data",
expaned: "true",
layers: {
"Constituencies": Layer1955Wards
}
},
{
groupName: "Map Overlays",
expanded: "true",
layers: {
"1953 Topological": Layer1953Topo,
"1953 Aerial Photographs": Layer1953Aerial
}
}];
var styledLayerControlOptions = {
container_width: "300px",
container_maxHeight: "350px",
group_maxHeight: "80px",
exclusive: false
};
var styledLayerControl = L.Control.styledLayerControl(baseMaps, overlays, styledLayerControlOptions);
map.addControl(styledLayerControl, overlays);

Related

Update style of individual feature from single geoJSON source on Mapbox map, when clicked

I'm working with Mapbox GL JS to plot geoJSON data on a map using their external geoJSON example as a starting point. The geoJSON file contains lots of features which are plotted as individual markers on the same layer. I would like to highlight the clicked marker by changing its colour from red to blue. I have adapted the example to show a pop-up with the point id when clicked (just as a proof of concept that the markers can fire events when clicked), however, I'm struggling to find a way to change the styling of the individual clicked marker.
The code is currently as follows:
mapboxgl.accessToken = 'pk.eyJ1IjoiZGFuYnJhbWFsbCIsImEiOiJjbDB3ODFveHYxOG5rM2pubWpwZ2R1Y2xuIn0.yatzJHqBTjQ6F3DHASlriw';
const map = new mapboxgl.Map({
container: 'map', // container ID
style: 'mapbox://styles/mapbox/satellite-v9', // style URL
zoom: 7, // starting zoom
center: [138.043, 35.201] // starting center
});
map.on('load', () => {
map.addSource('earthquakes', {
type: 'geojson',
data: 'https://docs.mapbox.com/mapbox-gl-js/assets/earthquakes.geojson'
});
map.addLayer({
'id': 'earthquakes-layer',
'type': 'circle',
'source': 'earthquakes',
'paint': {
'circle-radius': 8,
'circle-stroke-width': 2,
'circle-color': 'red',
'circle-stroke-color': 'white'
}
});
});
map.on('click', 'earthquakes-layer', (e) => {
new mapboxgl.Popup()
.setLngLat(e.lngLat)
.setHTML('Id: ' + e.features[0].properties.id)
.addTo(map);
});
Here is a codepen: https://codepen.io/danb1/pen/BaYjOyx
Is it the case that it's actually not possible to use this approach, and instead each feature from the geoJSON file needs to be plotted as a separate layer? I'm struggling to find any examples of this and am not able to modify the geoJSON source — it has to come from one single file (rather than loading multiple geoJSON files separately on separate layers).
This is possible using feature-state. The first thing to do is to ensure the layer data contains ids for each feature (in the example the source data doesn't so we need to add generateId: true to the map.addSource method).
We then need to add mousemove and mouseleave events to the map to store the moused-over feature id (if there is one, i.e. if the mouse is hovering over a feature):
let hoveredEarthquakeId = null;
map.on('mousemove', 'earthquakes-layer', (e) => {
map.getCanvas().style.cursor = 'pointer';
if (e.features.length > 0) {
map.setFeatureState(
{ source: 'earthquakes', id: e.features[0].id },
{ hover: true }
);
hoveredEarthquakeId = e.features[0].id;
}
});
map.on('mouseleave', 'earthquakes-layer', () => {
map.getCanvas().style.cursor = '';
if (hoveredEarthquakeId !== null) {
map.setFeatureState(
{ source: 'earthquakes', id: hoveredEarthquakeId },
{ hover: false }
);
}
hoveredEarthquakeId = null;
});
Finally, in the layer properties, the colour setting of the circle needs to be updated to reflect the hover value stored against the feature:
'circle-color': [
'case',
['boolean', ['feature-state', 'hover'], false],
'#00f',
'#f00'
],
The final thing can be seen in the modified pen. There is also a MapBox tutorial covering this kind of thing in a slightly more complicated way, which I hadn't come across until now: https://docs.mapbox.com/help/tutorials/create-interactive-hover-effects-with-mapbox-gl-js/.

Polygon layer has a white background which covers base maps

I am currently creating a webmap with leaflet. I used leaflet.ajax to import polygons from a geojson. But the new polygon layer covers the basemap, resulting in the polygons on a white background.
https://virgilxw.github.io/Singapore_Election_1955/
If you go the github page and navigate to the layer menu, you can find the polygon layer under "Data".
I have tried re-ordering the layers, but moving the base map above the polygons just result in the polygons being covered.
// Default base Map
map.addLayer(layerOneMapSG_Default);
// Add geojson
var Layer1955Wards = new L.GeoJSON.AJAX("data/wards1955.geojson");
// Styled Layer Control
var baseMaps = [
{
groupName: "Base Maps",
expanded: true,
layers: {
"OneMap": layerOneMapSG_Default
}
}];
var overlays = [
{
groupName: "data",
expaned: "true",
layers: {
"Constituencies": Layer1955Wards
}
},
{
groupName: "Map Overlays",
expanded: "true",
layers: {
"1953 Topological": Layer1953Topo,
"1953 Aerial Photographs": Layer1953Aerial
}
}];
var styledLayerControlOptions = {
container_width: "300px",
container_maxHeight: "350px",
group_maxHeight: "80px",
exclusive: false
};
var styledLayerControl = L.Control.styledLayerControl(baseMaps, overlays, styledLayerControlOptions);
map.addControl(styledLayerControl, overlays);

how to bring layer on top of another layer in leaflet map

my leaflet map has two layer: 1. temperature, 2. Wind-global
i want to bring layer 2 to top but my below code in javascript didn't work
var layerControl = L.control.layers(null, {
"temperature": bandsWindLayer,
}).addTo(map);
$.getJSON('wind-global.json', function (data) {
var velocityLayer = L.velocityLayer({
displayValues: true,
displayOptions: {
velocityType: 'Global Wind',
displayPosition: 'bottomleft',
displayEmptyString: 'No wind data'
},
data: data,
maxVelocity: 15
});
layerControl.addOverlay(velocityLayer, 'Wind-Global');
})
map.on("overlayadd", function (event) {
velocityLayer.bringToFront()
bandsWindLayer.bringToBack()
});
my error message is "velocityLayer is not defined"

Can I use Leaflet Draw to add layers to overlay layers?

Is it possible to add a "target overlay" for Leaflet Draw toolbar?
For example I could have two overlays such as Areas and Points of interest.
Now, I would like to add markers only to Points of Interest overlay and polygons on Areas overlay.
I've been trying to figure out that is it somehow possible to programmatically activate overlays or assign overlay for different draw toolbars but nothing seems to help.
All new layers are added to same overlay since I can't figure out which overlay toolbar is used.
And at least console log value of events don't seem to help and I cannot figure out that which toolbar was used (I could use it to force addLayer to use certain overaly), I cannot get anything regarding the target layer etc.
var poiLayer = new L.FeatureGroup();
var areaLayer = new L.FeatureGroup();
var options = {
polygon: {
allowIntersection: false,
drawError: {
color: "#e1e100",
message: "<strong>Lines of a polygon cannot overlap!</strong>"
},
shapeOptions: {
color: "#FF5656"
}
},
polygon: {
allowIntersection: false,
drawError: {
color: "#e1e100",
message: "<strong>Lines of a polygon cannot overlap!</strong>"
},
shapeOptions: {
color: "#FF5656"
}
},
edit: {
featureGroup: areaLayer,
poly: {
allowIntersection: false
},
poly: {
allowIntersection: false
},
poly: {
allowIntersection: false
}
},
draw: {
featureGroup: areaLayer,
name: "dafuq2",
polygon: {
allowIntersection: false,
showArea: true
},
},
name: "namne123123123"
};
//same for the poiLayer
var drawControl = new L.Control.Draw(options);
map.addControl(drawControl);
var drawControl2 = new L.Control.Draw(options2);
map.addControl(drawControl2);
map.on(L.Draw.Event.CREATED, function(e) {
console.log(e);
});

Openlayers 2.12 Select Feature when z index is set

I have three kml layers in a map: polygons, lines, points.
The map is modified from the mobile-wms-vienna example. I have changed the layers, and changed the "Labels" button to alter the opacity on the polygon layer.
To ensure that all features can be seen I need set z-indexing.
However I would also like to be able to display a pop-up on the polygon layer, which is set as the lowest. I do not want to see popups from lines or points. (Points can have labels, lines do not need labeling). I have read many posts about the problems with select on multiple layers, but could not find a solution to how to make anything selectable when z-indexing is set.
Is there a way to do this? Preferably draw the layers in the order they are added to the map.
Or a label layer that moves with the map and zoom changes? Unfortunately, kml polygon labels are fixed to a point and so might disappear when the map is moved or zoomed in.
The entire map code is given below, as I am not sure if there is something else in my map that is affecting this behaviour.
var map;
var linetyle = new OpenLayers.Style({'strokeWidth': 2, 'strokeColor':"red",});
function init() {
document.documentElement.lang = (navigator.userLanguage || navigator.language).split("-")[0];
var layerPanel = new OpenLayers.Control.Panel({
displayClass: "layerPanel",
autoActivate: true
});
var opButton = new OpenLayers.Control({
type: OpenLayers.Control.TYPE_TOGGLE,
displayClass: "opButton",
eventListeners: {
activate: function() {
if (polygon) {polygon.setOpacity(0.4);}
},
deactivate: function() {
if (polygon) {polygon.setOpacity(0.9);}
}
}
});
layerPanel.addControls([opButton]);
var zoomPanel = new OpenLayers.Control.ZoomPanel();
// Geolocate control for the Locate button - the locationupdated handler
// draws a cross at the location and a circle showing the accuracy radius.
var geolocate = new OpenLayers.Control.Geolocate({
type: OpenLayers.Control.TYPE_TOGGLE,
bind: false,
watch: true,
geolocationOptions: {
enableHighAccuracy: false,
maximumAge: 0,
timeout: 7000
},
eventListeners: {
activate: function() {
map.addLayer(vector);
},
deactivate: function() {
map.removeLayer(vector);
vector.removeAllFeatures();
},
locationupdated: function(e) {
vector.removeAllFeatures();
vector.addFeatures([
new OpenLayers.Feature.Vector(e.point, null, {
graphicName: 'cross',
strokeColor: '#f00',
strokeWidth: 2,
fillOpacity: 0,
pointRadius: 10
}),
new OpenLayers.Feature.Vector(
OpenLayers.Geometry.Polygon.createRegularPolygon(
new OpenLayers.Geometry.Point(e.point.x, e.point.y),
e.position.coords.accuracy / 2, 50, 0
), null, {
fillOpacity: 0.1,
fillColor: '#000',
strokeColor: '#f00',
strokeOpacity: 0.6
}
)
]);
map.zoomToExtent(vector.getDataExtent());
}
}
});
zoomPanel.addControls([geolocate]);
map = new OpenLayers.Map({
div: "map",
theme: null,
projection: new OpenLayers.Projection("EPSG:3857"),
displayProjection: new OpenLayers.Projection("EPSG:4326"),
layers: [new OpenLayers.Layer.Google( "Google Satellite", {type: google.maps.MapTypeId.SATELLITE, numZoomLevels: 22})],
center: new OpenLayers.LonLat(149.1, -35.3).transform('EPSG:4326', 'EPSG:3857'),
zoom: 10,
units: "m",
maxResolution: 38.21851413574219,
controls: [
new OpenLayers.Control.Navigation(),
new OpenLayers.Control.Attribution(),
zoomPanel,
layerPanel
],
});
layerPanel.activateControl(opButton);
// Vector layer for the location cross and circle
var vector = new OpenLayers.Layer.Vector("Vector Layer");
var point = new OpenLayers.Layer.Vector("points", {
// rendererOptions: {zIndexing: 'true'},
projection: map.displayProjection,
strategies: [new OpenLayers.Strategy.BBOX()],
protocol: new OpenLayers.Protocol.HTTP({
url: "kml/point.kml",
format: new OpenLayers.Format.KML({
extractStyles: true,
extractAttributes: true
}) }) });
var line = new OpenLayers.Layer.Vector("line", {
// rendererOptions: {zIndexing: 'true'},
projection: map.displayProjection,
strategies: [new OpenLayers.Strategy.BBOX({resFactor: 1})],
styleMap: linetyle,
protocol: new OpenLayers.Protocol.HTTP({
url: "kml/line.kml",
format: new OpenLayers.Format.KML({ extractStyles: false,
extractAttributes: true
}) }) });
var polygon = new OpenLayers.Layer.Vector("Geology", {
// rendererOptions: {zIndexing: 'true'},
projection: map.displayProjection,
strategies: [new OpenLayers.Strategy.BBOX({resFactor: 1})],
protocol: new OpenLayers.Protocol.HTTP({
url: "kml/polygon.kml",
format: new OpenLayers.Format.KML({extractStyles: true,extractAttributes: true})
}) });
map.addLayers([point, line, polygon]);
polygon.setOpacity(0.5);
// point.setZIndex(1400);
// line.setZIndex(1300);
// polygon.setZIndex(1200);
// Select Features/Popup
select = new OpenLayers.Control.SelectFeature (polygon, line, point);
polygon.events.on({
"featureselected": onFeatureSelect,
"featureunselected": onFeatureUnselect
}),
line.events.on({
"featureselected": onFeatureSelect,
"featureunselected": onFeatureUnselect
}),
point.events.on({
"featureselected": onFeatureSelect,
"featureunselected": onFeatureUnselect
}),
map.addControl(select);
select.activate();
function onPopupClose(evt) {
select.unselectAll();
}
function onFeatureSelect(event) {
var feature = event.feature;
// Since KML is user-generated, do naive protection against
// Javascript.
var content = "<h2>"+feature.attributes.name + "</h2>" + feature.attributes.description;
if (content.search("<script") != -1) {
content = "Content contained Javascript! Escaped content below.<br>" + content.replace(/</g, "<");
}
popup = new OpenLayers.Popup.FramedCloud("chicken",
feature.geometry.getBounds().getCenterLonLat(),
new OpenLayers.Size(100,100),
content,
null, false, onPopupClose);
feature.popup = popup;
map.addPopup(popup);
}
function onFeatureUnselect(event) {
var feature = event.feature;
if(feature.popup) {
map.removePopup(feature.popup);
feature.popup.destroy();
delete feature.popup;
}
};
};
The map can be seen at http://quartzspatial.net/act/map_v2.html
The closest answer that may solve my problem is here, but I could not understand how to use the solutions, and after many attempts at putting code in different places, I gave up.
I have just been looking at similar problem earlier. You probably figured this out yourself by now but I would like to share my jsFiddle in which I use event listener on the map object instead of a select control.
You cannot use an OpenLayers select control with layers index. The activation event will always put the layers on top and setting the z index on the layers will disable the select control. I also wasn't able to make the solution with disabling the moveontop in the activate event work (in jsFiddle).
Please have a look at the event listener solution:
var map = new OpenLayers.Map({
div: "map",
projection: new OpenLayers.Projection("EPSG:3857"),
displayProjection: new OpenLayers.Projection("EPSG:4326"),
layers: [
new OpenLayers.Layer.OSM()],
controls: [
new OpenLayers.Control.Navigation(),
new OpenLayers.Control.ArgParser() ],
eventListeners: {
featureover: function(e) { if (e.feature.layer != vectors2) {
e.feature.renderIntent = "temporary";
e.feature.layer.drawFeature(e.feature); }
},
featureout: function(e) { if (e.feature.layer != vectors2) {
e.feature.renderIntent = "default";
e.feature.layer.drawFeature(e.feature); }
},
featureclick: function(e) { if (e.feature.layer != vectors2) {
e.feature.renderIntent = "select";
e.feature.layer.drawFeature(e.feature); }
}
}
});