How to indicate polygon vertices with small circles using OpenLayers? - openlayers-3

I am using OpenLayers 3 and have more or less implemented everything in my requirements list, except one thing: I am asked to somehow make the polygon rendering indicate the polygon vertices with small circles.
In plain words, the desired polygon outline is not just a line - it is a line "adorned" with small circles in all the places where there is a vertex.
How can I do that in OL3? I searched in the ol.style.Style docs (that is, the style I pass via setStyle to the ol.layer.Vector containing my polygons), but didn't find anything relevant.

For reference, there is now an example showing how to display the vertices of a polygon with a custom style geometry:
http://openlayers.org/en/master/examples/polygon-styles.html
var styles = [
// style for the polygon
new ol.style.Style({
stroke: new ol.style.Stroke({
color: 'blue',
width: 3
}),
fill: new ol.style.Fill({
color: 'rgba(0, 0, 255, 0.1)'
})
}),
// style for the vertices
new ol.style.Style({
image: new ol.style.Circle({
radius: 5,
fill: new ol.style.Fill({
color: 'orange'
})
}),
geometry: function(feature) {
// return the coordinates of the first ring of the polygon
var coordinates = feature.getGeometry().getCoordinates()[0];
return new ol.geom.MultiPoint(coordinates);
}
})
];

The kind OL3 devs have provided the answer on the GitHub issue list. You basically use a style's geometry function, that transforms the geometry before projecting it - and in that function, you add your vertices to a MultiPoint geometry. #tsauerwein went as far as creating a working fiddle - many thanks to him for his work.
var styleFunction = function() {
var image = new ol.style.Circle({
radius: 5,
fill: null,
stroke: new ol.style.Stroke({color: 'orange', width: 2})
});
return [
new ol.style.Style({
image: image,
geometry: function(feature) {
var coordinates = feature.getGeometry().getCoordinates()[0];
return new ol.geom.MultiPoint(coordinates);
}
}),
new ol.style.Style({
stroke: new ol.style.Stroke({
color: 'blue',
width: 3
}),
fill: new ol.style.Fill({
color: 'rgba(0, 0, 255, 0.1)'
})
})
];
};

Related

Openlayers 3 : How to change Geojson Icon src so it won't override other geojson types?

I'm able to change src of an icon when loading Point/MultiPoint Geojson, in this way:
that.geojsonLayers[index] = new that.openlayers.ol.layer.Vector({
source: new that.openlayers.ol.source.Vector({
format: new that.openlayers.ol.format.GeoJSON(),
url: url
}),
style: new that.openlayers.ol.style.Style({
image: new that.openlayers.ol.style.Icon({
src: 'http://mapmip.webiks.com/assets/Markers/marker-icon-blue.png'
})
})
but then I can't load other types of Geojson - Polygons are not being loaded at all, and Geometry Collection (which composed from icon and lines) is load only the icon.
What is the way to change the icon src so it won't override the other geojson type ?
You may use a style function to verify the geometry type you need to style. Setting an icon for styling a polygon is not correct.
Check this
1.Declare your style
var myMultiStyle = {
//here replace with your icon style
'Point': new ol.style.Style({
image: new ol.style.Circle({
fill: new ol.style.Fill({
color: 'rgba(255,255,0,0.4)'
}),
radius: 5,
stroke: new ol.style.Stroke({
color: '#ff0',
width: 1
})
})
}),
'LineString': new ol.style.Style({
stroke: new ol.style.Stroke({
color: '#f00',
width: 3
})
}),
'Polygon': new ol.style.Style({
fill: new ol.style.Fill({
color: 'rgba(0,255,255,0.5)'
}),
stroke: new ol.style.Stroke({
color: '#0ff',
width: 1
})
})
};
Create a style function
function myStyleFunction(feature,resolution){
return myMultiStyle[feature.getGeometry().getType()];
}
Asign the style function to your vector source
that.geojsonLayers[index] = new that.openlayers.ol.layer.Vector({
source: new that.openlayers.ol.source.Vector({
format: new that.openlayers.ol.format.GeoJSON(),
url: url
}),
style: myStyleFunction
})
Check this official example to see the result.

GeoJSON data not displayed on a vector layer

I'm trying to display a vector layer to show a set of geojson features.
When I try and add the layer though I get an error in the ol.js library "k.xd is not a function"
var geoData = {"type":"FeatureCollection",
"features":
[
{"type":"Feature","properties":{"Name":"","Description":""},"geometry":{"type":"Point","coordinates":[0.0,0.0]}},
{"type":"Feature","properties":{"Name":"1","Description":""},"geometry":{"type":"Point","coordinates":[11.50728,3.87471,0.0]}},
]
};
// vector layer
var vector = new ol.layer.Vector({
source: new ol.source.Vector({
features: (new ol.format.GeoJSON()).readFeatures(geoData)
}),
style: new ol.style.Style({
stroke: new ol.style.Stroke({
color: 'red',
width: 2
}),
fill: new ol.style.Fill({
color: 'rgba(255,0,0,0.2)'
})
})
});
I've hacked together an example here http://jsfiddle.net/dxt95yt6/1/ that shows it not working but I can't figure out where this differs from the original tutorials.
Given style object is not correct for points and therefore features just don't show up. Try:
style: new ol.style.Style({
image: new ol.style.Circle({
radius: 8,
stroke: new ol.style.Stroke({
color: 'red',
width: 2
}),
fill: new ol.style.Fill({
color: 'rgba(255,0,0,0.2)'
})
})
})
Please note, in original code, there's another problem, too. Coordinates have to be transformed to EPSG:3857:
features: (new ol.format.GeoJSON()).readFeatures(
geoData,
{featureProjection: ol.proj.get('EPSG:3857')}
)
http://jsfiddle.net/zqx6644q/8/
Its always helpful to validate your geojson before using it. I can recommend geojsonlint which has alos an api to make sure your using a correct geojson.

OpenLayers3 - Style each Feature individually

I am adding features to a map by reading their WKT-String:
var feature = wkt.readFeature(entity.WellKnownText);
feature.bxObject = entity;
src.addFeature(feature);
Each feature has a bxObject-Property, and this Property contains the "radius"-Property.
I style the layer, to which the features are added like so:
var layer = new ol.layer.Vector({
source: src,
style: new ol.style.Style({
image: new ol.style.Circle({
radius: 6,
stroke: new ol.style.Stroke({
color: 'blue',
width: 1
}),
fill: new ol.style.Fill({ color: [0, 0, 255, 0.1] })
})
})
});
I want the radius-Property of the style to be dynamic. What I did and works as a workaround is the following:
var layer = new ol.layer.Vector({
source: src,
style: function (feature, resolution) {
return [
new ol.style.Style({
image: new ol.style.Circle({
radius: feature.bxObject.radius || 6,
stroke: new ol.style.Stroke({
color: 'blue',
width: 1
}),
fill: new ol.style.Fill({ color: [0, 0, 255, 0.1] })
})
})
];
}
});
But this creates a new style for each feature... I potentially draw 100s of features and I even have the subjective opinion, that it slows everything down. Is this really the way it is done?
I found this stackoverflow post. But I had no luck trying to interpolate with "${...}". I guess this is an openLayers 2 feature:
var layer = new ol.layer.Vector({
source: src,
style: new ol.style.Style({
image: new ol.style.Circle({
radius: "${bxObject.radius}",
stroke: new ol.style.Stroke({
color: 'blue',
width: 1
}),
fill: new ol.style.Fill({ color: [0, 0, 255, 0.1] })
})
})
});
Yes this is really the way, but you should keep a style cache and re-use when possible. See for instance: http://openlayers.org/en/v3.10.1/examples/kml-earthquakes.html

Feature with Icon, Text, and Line

I'd like to have features in a vector source layer that each have an icon, text, AND a line. I can get the icon and text to display but I can't get a line to draw. Using a different geometry I can get a line with a label to draw but no icon.
Is this possible without creating another feature? What geometry should I use for the feature?
Here's the code I'm using to draw an icon with text:
feature.setGeometry(new ol.geom.Point(
ol.proj.transform([lon, lat], 'EPSG:4326', 'EPSG:3857')
));
feature.setStyle([
new ol.style.Style({
image: new ol.style.Icon({
anchor: [0.5, 0.5],
anchorXUnits: 'fraction',
anchorYUnits: 'fraction',
opacity: 1.0,
scale: 0.75,
src: 'res/ship_a_flash.png',
rotation: 30.0
})
}),
new ol.style.Style({
text: new ol.style.Text({
text: feature.text,
font: 'bold 20px Times New Roman',
offsetY: -25,
fill: new ol.style.Fill({color: 'rgb(0,0,0)'}),
stroke: new ol.style.Stroke({color: 'rgb(255,255,255)', width: 1})
})
})
]);
So now I want to add a single line from the first point. I realize I need to add another point to the geometry so I tried MultiPoint and LineString like below.
feature.setGeometry(new ol.geom.MultiPoint([
ol.proj.transform([lon, lat], 'EPSG:4326', 'EPSG:3857'),
ol.proj.transform([lon+1, lat+1], 'EPSG:4326', 'EPSG:3857')]
));
feature.setStyle([
new ol.style.Style({
image: new ol.style.Icon({
anchor: [0.5, 0.5],
anchorXUnits: 'fraction',
anchorYUnits: 'fraction',
opacity: 1.0,
scale: 0.75,
src: 'res/ship_a_flash.png',
rotation: 30.0
})
}),
new ol.style.Style({
text: new ol.style.Text({
text: feature.text,
font: 'bold 20px Times New Roman',
offsetY: -25,
fill: new ol.style.Fill({color: 'rgb(0,0,0)'}),
stroke: new ol.style.Stroke({color: 'rgb(255,255,255)', width: 1})
})
}),
new ol.style.Style({
stroke: new ol.style.Stroke({
color: 'rgb(0,0,0)',
width: 2,
})
})
]);
I was hoping that the first point would be used for the Icon and Text and the 2 points would be used for the Stroke. With MultiPoint, the feature (icon and text) are drawn twice - once at each point in the geometry. With LineString, a line and text is drawn between the 2 points but the icon is not drawn.
It seems like I can either have an icon or a line in the feature, not both.
You could do the following: Use a geometry collection which contains a point and a line. Then use a StyleFunction which gets the point and the line and returns two separate styles for them:
var iconFeature = new ol.Feature({
geometry: new ol.geom.GeometryCollection([
new ol.geom.Point([0, 0]),
new ol.geom.LineString([[0,0], [1E6, 1.5E6]])
]),
...
});
var styleFunction = function(feature, resolution) {
var geometries = feature.getGeometry().getGeometries();
var point = geometries[0];
var line = geometries[1];
var iconStyle = new ol.style.Style({
geometry: point,
image: ...,
text: ...
});
var lineStyle = new ol.style.Style({
geometry: line,
stroke: ...
});
return [iconStyle, lineStyle];
};
http://jsfiddle.net/p8tzv9ms/11/

Resizing OL3 features programmatically

I have map with user drawn features. After the user custom enters a map scale, I need to be able to resize all the existing map features based on this scale.
What is the way to do this in OL 3? I've seen that in OL 2, there is a geometry.resize function.
Thanks.
You can accomplish this using a StyleFunction.
Look at the following example: http://openlayers.org/en/v3.4.0/examples/vector-layer.html
If you zoom the map, you'll see the labels appear at a certain resolution. This is controlled inside the style function. Here's a snippet:
var featureOverlay = new ol.FeatureOverlay({
map: map,
style: function(feature, resolution) {
// === SEE THIS NEXT LINE ===
var text = resolution < 5000 ? feature.get('name') : '';
if (!highlightStyleCache[text]) {
highlightStyleCache[text] = [new ol.style.Style({
stroke: new ol.style.Stroke({
color: '#f00',
width: 1
}),
fill: new ol.style.Fill({
color: 'rgba(255,0,0,0.1)'
}),
text: new ol.style.Text({
font: '12px Calibri,sans-serif',
text: text,
fill: new ol.style.Fill({
color: '#000'
}),
stroke: new ol.style.Stroke({
color: '#f00',
width: 3
})
})
})];
}
return highlightStyleCache[text];
}
});
So you could define the size you want the features to have for any resolution range. Note that the style property also applies to a ol.layer.Vector layer.
you can use API: map.updateSize().
Reference: http://openlayers.org/en/latest/apidoc/ol.Map.html#updateSize

Resources