how to add markers with OpenLayers 3 - javascript

I'm trying to add makers on a OpenLayers 3 map.
The only example I have found is this one in the OpenLayers example list.
But the example uses ol.Style.Icon instead of something like OpenLayers.Marker in OpenLayers 2.
First Question
The only difference would be that you have to set the image Url but is it the only way to add a marker?
Also OpenLayers 3 doesn't seem to come with marker images so it would make sense if there's no other way than ol.Style.Icon
Second Question
It would be really nice if someone could give me an example of a function to add markers or icons after the map is loaded.
From what I understand in the example, they create a layer for the icon
var iconFeature = new ol.Feature({
geometry: new ol.geom.Point(ol.proj.transform([-72.0704, 46.678], 'EPSG:4326', 'EPSG:3857')),
name: 'Null Island',
population: 4000,
rainfall: 500
});
var iconStyle = new ol.style.Style({
image: new ol.style.Icon(/** #type {olx.style.IconOptions} */ ({
anchor: [0.5, 46],
anchorXUnits: 'fraction',
anchorYUnits: 'pixels',
opacity: 0.75,
src: 'data/icon.png'
}))
});
iconFeature.setStyle(iconStyle);
var vectorSource = new ol.source.Vector({
features: [iconFeature]
});
var vectorLayer = new ol.layer.Vector({
source: vectorSource
});
Then they set the icon layer when they initialize the map
var map = new ol.Map({
layers: [new ol.layer.Tile({ source: new ol.source.OSM() }), vectorLayer],
target: document.getElementById('map'),
view: new ol.View2D({
center: [0, 0],
zoom: 3
})
});
If I want to add many markers, do I have to create 1 layer for each marker?
How could I add many markers to a layer? I can't figure out how this part would look
like
var vectorSource = new ol.source.Vector({
features: [iconFeature]
});
var vectorLayer = new ol.layer.Vector({
source: vectorSource
});
Thank you

Q1. Markers are considered deprecated in OpenLayers 2, though this isn't very obvious from the documentation. Instead, you should use an OpenLayers.Feature.Vector with an externalGraphic set to some image source in its style. This notion has been carried over to OpenLayers 3, so there is no marker class and it is done as in the example you cited.
Q2. The ol.source.Vector takes an array of features, note the line, features: [iconFeature], so you would create an array of icon features and add features to that, eg:
var iconFeatures=[];
var iconFeature = new ol.Feature({
geometry: new ol.geom.Point(ol.proj.transform([-72.0704, 46.678], 'EPSG:4326',
'EPSG:3857')),
name: 'Null Island',
population: 4000,
rainfall: 500
});
var iconFeature1 = new ol.Feature({
geometry: new ol.geom.Point(ol.proj.transform([-73.1234, 45.678], 'EPSG:4326',
'EPSG:3857')),
name: 'Null Island Two',
population: 4001,
rainfall: 501
});
iconFeatures.push(iconFeature);
iconFeatures.push(iconFeature1);
var vectorSource = new ol.source.Vector({
features: iconFeatures //add an array of features
});
var iconStyle = new ol.style.Style({
image: new ol.style.Icon(/** #type {olx.style.IconOptions} */ ({
anchor: [0.5, 46],
anchorXUnits: 'fraction',
anchorYUnits: 'pixels',
opacity: 0.75,
src: 'data/icon.png'
}))
});
var vectorLayer = new ol.layer.Vector({
source: vectorSource,
style: iconStyle
});
Obviously, this could be more elegantly handled by putting all of the ol.Feature creation inside a loop based on some data source, but I hope this demonstrates the approach. Note, also, that you can apply a style to the ol.layer.Vector so that it will be applied to all features being added to the layer, rather than having to set the style on individual features, assuming you want them to be the same, obviously.
EDIT: That answer doesn't seem to work. Here is an updated fiddle that works by adding the features (icons) to the empty vector source in a loop, using vectorSource.addFeature and then adds the whole lot to the layer vector afterwards. I will wait and see if this works for you, before updating my original answer.

there's a good tutorial at: http://openlayersbook.github.io
not tested but may helpful
var features = [];
//iterate through array...
for( var i = 0 ; i < data.length ; i++){
var item = data[i]; //get item
var type = item.type; //get type
var longitude = item.longitude; //coordinates
var latitude = item.latitude;
/*....
* now get your specific icon...('..../ic_customMarker.png')
* by e.g. switch case...
*/
var iconPath = getIconPath(type);
//create Feature... with coordinates
var iconFeature = new ol.Feature({
geometry: new ol.geom.Point(ol.proj.transform([longitude, latitude], 'EPSG:4326',
'EPSG:3857'))
});
//create style for your feature...
var iconStyle = new ol.style.Style({
image: new ol.style.Icon(/** #type {olx.style.IconOptions} */ ({
anchor: [0.5, 46],
anchorXUnits: 'fraction',
anchorYUnits: 'pixels',
opacity: 0.75,
src: iconPath
}))
});
iconFeature.setStyle(iconStyle);
features.push(iconFeature);
//next item...
}
/*
* create vector source
* you could set the style for all features in your vectoreSource as well
*/
var vectorSource = new ol.source.Vector({
features: features //add an array of features
//,style: iconStyle //to set the style for all your features...
});
var vectorLayer = new ol.layer.Vector({
source: vectorSource
});
map.addLayer(vectorLayer);

var exampleLoc = ol.proj.transform(
[131.044922, -25.363882], 'EPSG:4326', 'EPSG:3857');
var map = new ol.Map({
target: 'map',
renderer: 'canvas',
view: new ol.View2D({
projection: 'EPSG:3857',
zoom: 3,
center: exampleLoc
}),
layers: [
new ol.layer.Tile({source: new ol.source.MapQuest({layer: 'osm'})})
]
});
map.addOverlay(new ol.Overlay({
position: exampleLoc,
element: $('<img src="resources/img/marker-blue.png">')
.css({marginTop: '-200%', marginLeft: '-50%', cursor: 'pointer'})
.tooltip({title: 'Hello, world!', trigger: 'click'})
}));
map.on('postcompose', function(evt) {
evt.vectorContext.setFillStrokeStyle(
new ol.style.Fill({color: 'rgba(255, 0, 0, .1)'}),
new ol.style.Stroke({color: 'rgba(255, 0, 0, .8)', width: 3}));
evt.vectorContext.drawCircleGeometry(
new ol.geom.Circle(exampleLoc, 400000));
});
var exampleKml = new ol.layer.Vector({
source: new ol.source.KML({
projection: 'EPSG:3857',
url: 'data/example.kml'
})
});
map.addLayer(exampleKml);

We just finished updating our website NUFOSMATIC from ol2 to ol6. Both the ol2 and ol3 code is on the site. This includes Matt Walker's ol-layerswitcher https://github.com/walkermatt replacing the missing ol2 layerswitcher. We actually updated three map applications; HEATMAP replaces the Patrick Wied (http://www.patrick-wied.at) ol2 heatmap with the native ol6 heatmap.
Only took 6 days. Wonder why we waited this long... oh, yeah, we have day jobs...

Related

Openlayers 6: Filter point vector layer by properties before point clustering

Following the examples on Openlayers.org I created a point vector layer (with overlays etc.). The points are displayed as cluster points as in the example here:
Openlayers Cluster Example
Now, I need to filter the points according to their properties, e.g. lab_data = 'yes', sampling_year > 1990. The filtering affects the number of points inside the clusters.
I have so far not found a method to exclude features from my Source or Layer objects. I was even unsuccesful in accessing the features and their properties. From there on I could build loops and conditions.
Does anyone maybe have an idea how it is done?
// Read GeoJson point locations
var pointLocations = new ol.source.Vector({
url: 'data/samplingLocations.json',
format: new ol.format.GeoJSON()
});
// create point cluster
var pointCluster = new ol.source.Cluster({
distance: 50,
source: pointLocations
});
// create simple style for single points and clusters
var getStyle = function(feature) {
var length = feature.get('features').length;
if (length > 1) {
style = new ol.style.Style({
image: new ol.style.Circle({
radius: 20,
fill: new ol.style.Fill({ color: "red" }),
}),
})
} else {
style = new ol.style.Style({
image: new ol.style.Circle({
radius: 10,
fill: new ol.style.Fill({ color: "black" }),
}),
})
}
return style;
};
// create a vector layer
var vectorLayer = new ol.layer.Vector({
id: "points",
source: pointCluster,
style: getStyle
});
// create the map
var map = new ol.Map({
layers: [vectorLayer],
target: 'map',
view: new ol.View({
center: [895571,5911157],
zoom: 8,
})
});
So far some of my unsuccessful attempts to access the properties:
console.log( pointLocations.getSource().getFeatures()[0].getProperties().values)
console.log( vectorLayer.getSource().getFeatures()[0].get('values') )
Every help is kindly appreciated!
You can filter with a geometry function, for example:
var pointCluster = new ol.source.Cluster({
distance: 50,
source: pointLocations,
geometryFunction: function(feature) {
if (feature.get('lab_data') == 'yes' && feature.get('sampling_year') > 1990) {
return feature.getGeometry();
} else {
return null;
}
}
});

OpenLayers - Set center and zoom based on multiple polygons

I'm using openlayers 6.5 and I want to set the center of the map and to fit all polygons drawned.
Here is what I have:
/*** Set the map ***/
var map = new ol.Map({
target: map_element,
layers: [
new ol.layer.Tile({
source: new ol.source.OSM()
})
],
view: new ol.View({
center: ol.proj.fromLonLat([
'24.6859325',
'45.9852429',
]),
zoom: 6
})
});
/*** Set counties polygon on the map ***/
for(var county_id in map_json_data)
{
map_json_data[county_id]['google_map_county_polygon'] = new ol.Feature({
geometry: new ol.geom.Polygon([map_json_data[county_id]['county_polygon_coordinates']])
});
map_json_data[county_id]['google_map_county_polygon'].getGeometry().transform('EPSG:4326', 'EPSG:3857');
map.addLayer(
new ol.layer.Vector({
source: new ol.source.Vector({
features: [ map_json_data[county_id]['google_map_county_polygon'] ]
})
})
);
}
/*** Here I want to set all polygons to be centered on the map and to fill the maximum zoom ***/
Some help based on code I have ?
You could build up a combined extent as you add features and then fit the view to that
var extent = ol.extent.createEmpty();
/*** Set counties polygon on the map ***/
for(var county_id in map_json_data)
{
map_json_data[county_id]['google_map_county_polygon'] = new ol.Feature({
geometry: new ol.geom.Polygon([map_json_data[county_id]['county_polygon_coordinates']])
});
map_json_data[county_id]['google_map_county_polygon'].getGeometry().transform('EPSG:4326', 'EPSG:3857');
ol.extent.extend(extent, map_json_data[county_id]['google_map_county_polygon'].getGeometry().getExtent());
map.addLayer(
new ol.layer.Vector({
source: new ol.source.Vector({
features: [ map_json_data[county_id]['google_map_county_polygon'] ]
})
})
);
}
map.getView().fit(extent);
It could be made simpler if you are able to have all your polygons in a single vector layer
var vectorSource = new ol.source.Vector();
map.addLayer(
new ol.layer.Vector({
source: vectorSource
})
);
/*** Set counties polygon on the map ***/
for(var county_id in map_json_data)
{
map_json_data[county_id]['google_map_county_polygon'] = new ol.Feature({
geometry: new ol.geom.Polygon([map_json_data[county_id]['county_polygon_coordinates']])
});
map_json_data[county_id]['google_map_county_polygon'].getGeometry().transform('EPSG:4326', 'EPSG:3857');
vectorSource.addFeature( map_json_data[county_id]['google_map_county_polygon']);
}
map.getView().fit(vectorSource.getExtent());

Openlayers Set property to KML vector layer markers?

I'm quite new to all of this and am sorry if this is painfully obvious, but I looked around for a solution as best I could and so nevertheless:
I am loading various KML files into a map, including ones of markers, none of which cause problems. I would like to have these markers change when the cursor hovers over them, which I was able to figure out as done by adapting these examples.
However, both use just one style, while I would like different styles for different KML layers. I tried defining and then calling the different styles that I would like to use as per this question.
But I wasn't returned the style that my parameters defined. n00b that I am it took me a while to trial and error what was going on, but console logging in my 'hoverStyler' function (where the styles would be chosen) my style parameter was being returned 'undefined', no matter where I tried defining it. Knowing that, I went into the KML itself and added extended data of my parameter ('hoverstyle'), and the function then worked for whatever marker (or route) I added that to.
The issue that I would like resolved is that it is a bit cumbersome to have to go into the KML and define this for every marker, and I assume that same as they're all loaded together that there must be a way to assign them all this property together, too.
I just have no idea what that is. Any advise is greatly appreciated!
Code:
(there is a certain deliberate redundancy in styles to better give me feedback as to what was and wasn't working)
var map = new ol.Map({
layers: [
new ol.layer.Tile({
source: new ol.source.OSM()
})
],
target: 'map',
view: new ol.View({
center: ol.proj.fromLonLat([132.4903, 34.0024]),
zoom: 4
})
});
var vectorLayer = new ol.layer.Vector({
source: new ol.source.Vector({
url: '../static/gpx/summer3.kml',
format: new ol.format.KML({
extractStyles: false
})
}),
style: function(feature) {
return routeStyle;
},
});
map.addLayer(vectorLayer);
var vectorLayer = new ol.layer.Vector({
source: new ol.source.Vector({
url: '../static/gpx/testmoo3.kml',
format: new ol.format.KML({
extractStyles: false,
}),
}),
style: function(feature) {
return iconStyle;
},
});
map.addLayer(vectorLayer);
var hoverStyles = {
'moo': new ol.style.Icon({
anchor: [0.5, 30],
anchorXUnits: 'fraction',
anchorYUnits: 'pixels',
src: '../static/GPX/icon/mooinb.png',
}),
'moo2': new ol.style.Icon({
anchor: [0.5, 30],
anchorXUnits: 'fraction',
anchorYUnits: 'pixels',
src: '../static/GPX/icon/moo2.png'
}),
'route1': new ol.style.Stroke({
color: 'rgba(236, 26, 201, 0.5)',
width: 5
})
};
var routeStyle = new ol.style.Style({
stroke: new ol.style.Stroke({
color: 'rgba(209,14,14,.6)',
width: 4
})
});
var defaultRouteStyle = new ol.style.Style({
stroke: new ol.style.Stroke({
color: 'rgba(130,188,35,.6)',
width: 4
})
});
var iconStyle = new ol.style.Style({
image: new ol.style.Icon({
anchor: [0.5, 30],
anchorXUnits: 'fraction',
anchorYUnits: 'pixels',
src: '../static/GPX/icon/moo7.png',
}),
});
var defaultIconStyle = new ol.style.Style({
image: new ol.style.Icon({
anchor: [0.5, 30],
anchorXUnits: 'fraction',
anchorYUnits: 'pixels',
src: '../static/GPX/icon/moo.png'
}),
});
var hoverStyleCache = {}
function hoverStyler(feature, resolution) {
var hover = feature.get('hoverstyle');
var geometry = feature.getGeometry().getType();
console.log(hover);
while (geometry === 'Point') {
if (!hover || !hoverStyles[hover]) {
return [defaultIconStyle];
}
if (!hoverStyleCache[hover]) {
hoverStyleCache[hover] = new ol.style.Style({
image:hoverStyles[hover],
})
}
return [hoverStyleCache[hover]];
}
while (geometry === 'LineString') {
if (!hover || !hoverStyles[hover]) {
return [defaultRouteStyle];
}
if (!hoverStyleCache[hover]) {
hoverStyleCache[hover] = new ol.style.Style({
stroke: hoverStyles[hover]
})
}
return [hoverStyleCache[hover]];
}
}
var featureOverlay = new ol.layer.Vector({
source: new ol.source.Vector(),
map: map,
style: hoverStyler
});
var highlight;
var hover = function(pixel) {
var feature = map.forEachFeatureAtPixel(pixel, function(feature) {
return feature;
});
if (feature !== highlight) {
if (highlight) {
featureOverlay.getSource().removeFeature(highlight);
}
if (feature) {
featureOverlay.getSource().addFeature(feature);
}
highlight = feature;
}
};
You can set properties as the features are loaded
var vectorLayer = new ol.layer.Vector({
source: new ol.source.Vector({
url: '../static/gpx/summer3.kml',
format: new ol.format.KML({
extractStyles: false
})
}),
style: function(feature) {
return routeStyle;
},
});
vectorLayer.getSource().on('addfeature', function(event) {
event.feature.set(('hoverstyle', 'moo');
});
map.addLayer(vectorLayer);

OpenLayers change color of feature on runtime

I use OpenLayers v6.3.1, including the following stylesheet and script: Scriptfile, Stylesheet
Goal:
My goal is to change the color of a feature (LineString) on runtime using javascript.
Setup:
I mainly used the code from this website: OpenLayers
var map = new ol.Map({
target: 'map', //<div id="map"></div>
layers: [
new ol.layer.Tile({
source: new ol.source.OSM()
})
],
view: new ol.View({
projection: 'EPSG:4326',
center: [11.592581, 47.241524],
zoom: 15
})
});
In this piece of code I create a line between two coordinates:
var lonlat1 = [11.592581, 47.241524];
var lonlat2 = [11.58554, 47.248958];
//create the line's style
var lineStyle = [
// linestring
new ol.style.Style({
stroke: new ol.style.Stroke({
color: '#000',
width: 2
})
})
];
//create the line
var line = new ol.layer.Vector({
source: new ol.source.Vector({
features: [
new ol.Feature({
geometry: new ol.geom.LineString([lonlat1, lonlat2])
})
]
}),
style: lineStyle
});
map.addLayer(line);
Which gives me this map:
I want to change the color of the line at runtime.
What I tried so far:
I tried to change the color using the following code:
line.style_[0].stroke_.color_ = '#123';
The value of the color did change, but the color of the line itself remains the same.
OK, i figured it out. The style can be changed with the setStyle() function which is part of the line object.
line.setStyle([
new ol.style.Style({
stroke: new ol.style.Stroke({
color: '#123',
width: 2
})
})
]);
This is definitely not the best solution so I am open to anything better.

Specifying a minimum cluster size with Open Layers Clustering

With OpenLayers 3, how can I specify a minimum cluster size so that clusters with 5 map markers or less will not get clustered, but will instead display the individual map markers? Is there a way to do this within the cluster layer's ol.layer.Vector object?
let clusterSource = new ol.source.Cluster({
distance: CLUSTER_DISTANCE,
source: features
});
let clusterLayer = new ol.layer.Vector({
source: source,
style: function(feature, resolution) { }
});
You can check in the code how many features are there. If you have too many, you can create a cluster source based on the vector source you already have to add it a to a new vector layer. If not, a vector layer can be created with your existing vector source.
Since there is no method to set the source dynamically to a layer, your vector layer should be created with the desired source. If you want to see how it works with more than 5 features, just uncomment the commented lines.
var features = [
new ol.Feature({
geometry: new ol.geom.Point([0,0])
}),
new ol.Feature({
geometry: new ol.geom.Point([100000,500000])
}),
new ol.Feature({
geometry: new ol.geom.Point([500000,100000])
}),
new ol.Feature({
geometry: new ol.geom.Point([5000000,1000000])
}),
new ol.Feature({
geometry: new ol.geom.Point([1000000,500000])
})
/*,new ol.Feature({
geometry: new ol.geom.Point([1800000,800000])
})*/
],
source = new ol.source.Vector({
features: features
});
var layer;
if (features.length > 5) {
var clusterSource = new ol.source.Cluster({
distance: parseInt(40, 10),
source: source
});
var styleCache = {};
layer = new ol.layer.Vector({
source: clusterSource,
style: function(feature) {
var size = feature.get('features').length;
var style = styleCache[size];
if (!style) {
style = new ol.style.Style({
image: new ol.style.Circle({
radius: 10,
stroke: new ol.style.Stroke({
color: '#AAA'
}),
fill: new ol.style.Fill({
color: '#DDD'
})
}),
text: new ol.style.Text({
text: size.toString(),
fill: new ol.style.Fill({
color: '#B144FF'
})
})
});
styleCache[size] = style;
}
return style;
}
});
} else {
layer = new ol.layer.Vector({
source: source
});
}
var map = new ol.Map({
layers: [
new ol.layer.Tile({
source: new ol.source.OSM()
}),
layer
],
target: 'clusterMap',
view: new ol.View({
center: [0, 0],
zoom: 2
})
});
<link href="https://openlayers.org/en/v3.20.1/css/ol.css" rel="stylesheet"/>
<script src="https://openlayers.org/en/v3.20.1/build/ol.js"></script>
<div id="clusterMap" class="map"></div>

Categories

Resources