I'd like to be able to tell what ol.layer.Group(s) a layer is part of during a user interaction, without going through all the groups on the map top-down.
Is there a way to do this? I'm currently using ol3 v3.10.2.
During initialising of your layers asign an attribute, on each layer, to verify the group this layer belongs to. like so:
var vector = new ol.layer.Vector({
GROUP : 'group1',
source: vectorSource,
style: new ol.style.Style({
image: new ol.style.Circle({
radius: 5,
fill: new ol.style.Fill({color: '#FFFFFF'}),
stroke: new ol.style.Stroke({
color: '#000000',
width: 3
})
})
})
});
and then you may get the group like so:
layer.get('GROUP');
Looking at the ol.layer.Group, ol.collection and goog.array, none of these set an backwards reference to the layer. So you'll have to dig down trough all the groups, as far as I can see.
Related
So here is one of my layers:
TurksAndCaicosLayer = L.geoJson(TurksAndCaicos, {
style: {
weight: 0.5,
color: 'white',
fillOpacity: 1,
fillColor: 'brown',
}})
I have 8 of these polygon layers for my Leaflet map. I am trying to construct a loop which will go through the array of my layers and add them to the map, but it doesn't seem to be working. Can anyone spot why?
let layers = [AnguillaLayer, BermudaLayer, BritishVirginIslandsLayer, GibraltarLayer, GuernseyLayer, IsleOfManLayer, JerseyLayer, TurksAndCaicosLayer]
for (let layer of layers) {
map.addLayer(layer)}
try
layers.forEach(addLayer);
function addLayer(item, index) {
map.addLayer(item);
}
An alternative approach would be to add your layers to a layerGroup and add the layerGroup to the map - saves writing an explicit loop.
let layers = [AnguillaLayer, BermudaLayer, BritishVirginIslandsLayer, GibraltarLayer, GuernseyLayer, IsleOfManLayer, JerseyLayer, TurksAndCaicosLayer];
let myLayerGroup = L.layerGroup(layers).addTo(map);
My server is statically serving several different PNG images of the same object, each taken with a different spectral filter (for example, just a red channel or just a blue channel). I'd like to show a slippy, false-colored map of that object. I do so by creating three separate images sources like so:
extent = [0, 0, ncols, nrows];
pixelProjection = new ol.proj.Projection({
code: 'some-image',
units: 'pixels',
extent: extent
});
rsource = new ol.source.ImageStatic({
url: "static/imgs/band_1.png",
projection: pixelProjection,
imageExtent: extent
});
gsource = new ol.source.ImageStatic({
url: "static/imgs/band_2.png",
projection: pixelProjection,
imageExtent: extent
});
bsource = new ol.source.ImageStatic({
url: "static/imgs/band_3.png",
projection: pixelProjection,
imageExtent: extent
});
Next, I use these sources as inputs to a raster source which can compose them:
rgbSources = [rsource, gsource, bsource];
raster = new ol.source.Raster({
sources: rgbSources,
operation: function(bands, data) {
var rband = bands[0];
var gband = bands[1];
var bband = bands[2];
var composed = [
rband[0],
gband[0],
bband[0],
255
];
return composed;
}
});
I then create a layer that uses this raster as its source:
colorLayer = new ol.layer.Image({
source: raster
});
Lastly, I can create a map and add my raster layer to the map:
var map = new ol.Map({
target: 'map',
view: new ol.View({
center:ol.extent.getCenter(extent),
projection: pixelProjection,
zoom: 1.5
})
});
map.addLayer(colorLayer);
So far so good! This displays a colorized version of the image as expected. The problem arises when the user triggers a change to a color channel by inputting a new channel index to pull from. I handle a blue channel change like this:
var index = 4; // actually gets passed in from user
bsource = new ol.source.ImageStatic({
url: "static/imgs/band_" + index + ".png",
projection: pixelProjection,
imageExtent: extent
});
rgbSources[2] = bsource; // this was in global scope from before
raster.sources = rgbSources; // as was this
Expected behavior is that the map would immediately change colors, or at least it would change when I zoom in or pan but neither of those things happens. I am unable to get the new colors to appear at all. Am I updating the wrong thing? Perhaps the raster.sources field has an associated setter function that I am unable to find?
Found a solution! It looks like setting a raster's source directly is not allowed, but setting a layer's source is. So unfortunately, I have to create a new raster object (new source entirely), but at least I don't need a new layer:
raster = new ol.source.Raster({
sources: rgbSources,
operation: composeBands
});
colorLayer.setSource(raster);
Accepting my own answer but willing to accept someone else's solution if it means I don't need to create a new source.
In OpenLayers 2 it was possible to extend the style definition with dynamic parts - special functions that calculates a specific style value at render time. Is there an equivalent in OpenLayers 3?
Here sample code from OpenLayers 2:
var stdStyleMap = new OpenLayers.StyleMap({
"default": new OpenLayers.Style({
/* fixed value */
fillOpacity: 0.8,
/* value from server response */
fillColor: "${fillcolor}",
/* value calculated at render time */
pointRadius: "${getPointRadius}",
}, {
context: {
/* function that calculates the point radius */
getPointRadius: function(feature) {
if (feature.attributes && feature.attributes.pointRadius)
return feature.attributes.pointRadius;
else
return 5;
}
}})
});
Here's a good example of using custom styles for polygons from the Openlayers site.
But the following is an example that answers a question i posted... so, yay for both of us... maybe.
// we'd normally pass feature & resolution parameters to the function, but we're going to
// make this dynamic, so we'll return a style function for later use which will take those params.
DynamicStyleFunction = ( function( /* no feat/res yet!*/ ) {
/**
you really only get style are rendered upon simple geometries, not features. features are made of different geometry types, and styleFunctions are passed a feature that has its geometries rendered. in terms of styling vector geometries, you have only a few options. side note: if there's some feature you expect to see on the the map and it's not showing up, you probably haven't properly styled it. Or, maybe it hasn't been put it in a collection that is included in the source layer... which is a hiccup for a different day.
*/
// for any geometry that you want to be rendered, you'll want a style.
var styles = {};
var s = styles;
/**
an ol.layer.Vector or FeatureOverlay, renders those features in its source by applying Styles made of Strokes, Fills, and Images (made of strokes and fills) on top of the simple geometries which make up the features
Stroke styles get applied to ol.geom.GeometryType.LINE_STRING
MULTI_LINE_STRING can get different styling if you want
*/
var strokeLinesWhite = new ol.style.Stroke({
color: [255, 255, 255, 1], // white
width: 5,
})
var whiteLineStyle new ol.style.Style({
stroke: strokeLinesWhite
})
styles[ol.geom.GeometryType.LINE_STRING] = whiteLineStyle
/**
Polygon styles get applied to ol.geom.GeometryType.POLYGON
Polygons are gonna get filled. They also have Lines... so they can take stroke
*/
var fillPolygonBlue = new ol.style.Style({
fill: new ol.style.Fill({
color: [0, 153, 255, 1], // blue
})
})
var whiteOutlinedBluePolygon = new ol.style.Style({
stroke: strokeLinesWhite,
fill: fillPolygonBlue,
})
styles[ol.geom.GeometryType.POLYGON] = fillPolygonBlue
/**
Circle styles get applied to ol.geom.GeometryType.POINT
They're made with a radius and a fill, and the edge gets stroked...
*/
var smallRedCircleStyle = new ol.style.Style({
image: new ol.style.Circle({
radius: 5,
fill: new ol.style.Fill({
color: '#FF0000', // red... but i had to look it up
})
})
})
var whiteBigCircleWithBlueBorderStyle = new ol.style.Style({
image: new ol.style.Circle({
radius: 10,
fill: new ol.style.Fill({
color: '#FFFFFF' // i guessed it
})
}),
stroke: new.ol.style.Stroke({
color: '#0000FF', // blue
width: 5
})
})
// render all points as small red circles
styles[ol.geom.GeometryType.POINT] = smallRedCircleStyle
// if you pass an array as the style argument, every rendering of the feature will apply every defined style style rendered with the geometry as the argument. that can be a whole lot of rendering in a FeatureOverlay...
smallRedCircleStyle.setZIndex(Infinity)
whiteBigCircleWithBlueBorderStyle.setZIndex(Infinity -1) // that prob wouldn't work, but i hope it's instructive that you can tinker with styles
// so...
var bullseyePointStyle = [ smallRedCircleStyle, whiteBigCircleWithBlueBorderStyle ];
return function dynamicStyleFunction (feature, resolution){
// this is the actual function getting invoked on each function call
// do whatever you want with the feature/resolution.
if (Array.indexOf(feature.getKeys('thisIsOurBullseyeNode') > -1) {
return bullseyePointStyle
} else if (feature.getGeometryName('whiteBlueBox')){
return whiteOutlinedBluePolygon
} else {
return styles[feature.getGeometryName()]
}
}
})()
Yes there is style function that takes a feature and the current resolution, see some examples in the workshop: http://openlayers.org/workshop/vector/style.html
I am looking to create simple markers in Openlayers 3 based on a two dimensional array which I pass via PHP containing the Geolocation of the marker and an attribute. Currently the attribute is the colour that I would like the layer to be:
//run external php script to grab all entries from the database; make an array and add to source vector
var latlong_marker = <?php require 'db_multiple_gps.php'; echo $ol_latlong;?>;
var latlong_array_length = latlong_marker.length;
var vectorSource = new ol.source.Vector({
//create empty vector
});
// cycle through all entries in the array
for (var i = 0; i < latlong_array_length; i++){
var iconFeature = new ol.Feature({
geometry: new ol.geom.Point(ol.proj.transform(latlong_marker[i][0], 'EPSG:4326', 'EPSG:3857'))});
vectorSource.addFeature(iconFeature);
var iconStyle = new ol.style.Style({
image: new ol.style.Circle({
radius: 5,
fill: new ol.style.Fill({color: latlong_marker[i][2]})
})
});
//add the feature vector to the layer vector, and apply a style to whole layer
var vectorLayer = new ol.layer.Vector({
source: vectorSource,
style: iconStyle
});
}
The vector layers are presented on the map in the correct locations but the issue is that the colour is that of the last entry in the array latlong_marker[i][2].
From my research I think it may be due to closure of functions but I'm not exactly sure how or where the functions are in play here.
Debugging show the entire array being passed through the loop and vectorSource looking good; however iconStyle appears to have many null values.
Am I going about this in the right fashion? I could pass another parameter other than the actual colour required (such as a integer) to then be used to create the different style.
In addition to the code snippet above, I have played around with with closing the loop earlier; this works fro creation of vectorSource but I always fall down with trying to pass an array of iconStyle to the Vector Layer.
Try this
var latlong_marker = <?php require 'db_multiple_gps.php'; echo $ol_latlong;?>;
var latlong_array_length = latlong_marker.length;
var vectorSource = new ol.source.Vector({
//create empty vector
});
// cycle through all entries in the array
for (var i = 0; i < latlong_array_length; i++){
var iconFeature = new ol.Feature({
geometry: new ol.geom.Point(ol.proj.transform(latlong_marker[i][0],
'EPSG:4326','EPSG:3857'))});
var iconStyle = new ol.style.Style({
image: new ol.style.Circle({
radius: 5,
fill: new ol.style.Fill({color: latlong_marker[i][2]})
})
});
// THIS IS NEW - add each style individually to the feature
iconFeature.setStyle(iconStyle);
// First add the feature when it has got its style
vectorSource.addFeature(iconFeature);
}
//add the feature vector to the layer vector, and apply a style to whole layer
var vectorLayer = new ol.layer.Vector({
source: vectorSource,
// remove this - > style: iconStyle
});
I would like to know if it is possible to change the z-index property of the shapes?
I'm making the route above the circle shape but the route remains behind.
What can i do?
You can do this by altering the zIndex property of the Polyline, like all MapObjects, the Polyline is derived from Object which is where the zIndex is defined.
If you have a Polyline like this:
var points = [
new nokia.maps.geo.Coordinate(50.2, 8.57),
new nokia.maps.geo.Coordinate(50.1299, 8.5680),
new nokia.maps.geo.Coordinate(50.0969, 8.4829),
new nokia.maps.geo.Coordinate(50.0819, 8.4856),
new nokia.maps.geo.Coordinate(50.0555, 8.4479),
new nokia.maps.geo.Coordinate(50.02, 8.43)
];
// Purple polyline
poly = new nokia.maps.map.Polyline(
points,
{
pen: {
strokeColor: "#22CA",
lineWidth: 5
}
}
);
And any geoshape (e.g. a Polygon) like this:
gon = new nokia.maps.map.Polygon(
[
new nokia.maps.geo.Coordinate(50.2001, 8.6381),
new nokia.maps.geo.Coordinate(50.2190, 8.5474),
new nokia.maps.geo.Coordinate(50.2001, 8.5337),
new nokia.maps.geo.Coordinate(50.1799, 8.4774),
new nokia.maps.geo.Coordinate(50.1693, 8.4664),
new nokia.maps.geo.Coordinate(50.1522, 8.4657),
new nokia.maps.geo.Coordinate(50.1205, 8.5310),
new nokia.maps.geo.Coordinate(50.1363, 8.5879),
new nokia.maps.geo.Coordinate(50.1882, 8.6168)
],
{
pen: { strokeColor: "#000", lineWidth: 1 },
brush: { color: "#C22A" }
}
);
Then the object that is placed on the map first will be at the back. By default both objects will have a zIndex of zero. If you increase the zIndex as shown:
poly.set("zIndex", 1)
Then it will move on top of all objects with the default zIndex