LineString direction arrows in Openlayers 4 - javascript

I'm trying to make a LineString which has arrows in the end of each line to show direction of the route. I use an example from the official site: https://openlayers.org/en/latest/examples/line-arrows.html
The example code creates arrows by user's drawing, but I need arrows for given LineString.
My code contains icons for end and finish of the route.
When I use
'route': new ol.style.Style({
stroke: new ol.style.Stroke({
width: 6, color: [23, 120, 22, 0.6]
})
}),
in styles, my code works. But when I put style for Linestring from the example, it gives me an error saying "Uncaught TypeError: c.Y is not a function".
Here is my code:
var points = [
[76.8412, 43.2245], [76.8405, 43.2210], [76.8479, 43.2200], [76.8512, 43.2220]
];
var route = new ol.geom.LineString(points);
route.transform('EPSG:4326', 'EPSG:3857');
var routeFeature = new ol.Feature({
type: 'route',
geometry: route
});
var startMarker = new ol.Feature({
type: 'icon-a',
geometry: new ol.geom.Point(ol.proj.fromLonLat(points[0]))
});
var endMarker = new ol.Feature({
type: 'icon-b',
geometry: new ol.geom.Point(ol.proj.fromLonLat(points[points.length - 1]))
});
var styles = {
'route': function(feature) {
var geometry = feature.getGeometry();
var styles = [
// linestring
new ol.style.Style({
stroke: new ol.style.Stroke({
color: '#ffcc33',
width: 2
}),
image: new ol.style.Icon({
anchor: [0.5, 1],
src: 'img/icon-a.png'
})
})
];
geometry.forEachSegment(function(start, end) {
var dx = end[0] - start[0];
var dy = end[1] - start[1];
var rotation = Math.atan2(dy, dx);
// arrows
styles.push(new ol.style.Style({
geometry: new ol.geom.Point(end),
image: new ol.style.Icon({
src: 'https://openlayers.org/en/v4.6.3/examples/data/arrow.png',
anchor: [0.75, 0.5],
rotateWithView: true,
rotation: -rotation
})
}));
});
return styles;
},
'icon-a': new ol.style.Style({
image: new ol.style.Icon({
anchor: [0.5, 1],
src: 'img/icon-a.png'
})
}),
'icon-b': new ol.style.Style({
image: new ol.style.Icon({
anchor: [0.5, 1],
src: 'img/icon-b.png'
})
})
};
var vectorLayer = new ol.layer.Vector({
source: new ol.source.Vector({
features: [routeFeature, startMarker, endMarker]
}),
style: function(feature) {
return styles[feature.get('type')];
}
});
var center = ol.proj.fromLonLat([76.8512, 43.2220]);
var map = new ol.Map({
target: document.getElementById('map'),
view: new ol.View({
center: center,
zoom: 15,
minZoom: 2,
maxZoom: 19
}),
layers: [
new ol.layer.Tile({
source: new ol.source.OSM()
}),
vectorLayer
]
});
#map {
/* just for testing purposes */
width: 100%;
min-width: 100px;
max-width: 500px;
margin-top: 50px;
height: 50px;
}
<link href="https://openlayers.org/en/v4.6.4/css/ol.css" rel="stylesheet"/>
<script src="https://openlayers.org/en/v4.6.4/build/ol-debug.js"></script>
<div id="map"></div>

Firstly, you can use ol-debug.js instead of ol.js, which is uncompressed and helps debugging. The exception you get is
TypeError: style.getImage is not a function (Line 30443)
You get that error because your styles object is mixed: some styles are functions, some are plain Style objects.
You might think that OL can handle both, and you are normally right. However, you provide a function to vectorLayer, so OL detects that you provided a function and calls it. The return value of that function is expected to be a style object. But for route, that returns a function instead!
So when OL calls
style: function(feature) {
return styles[feature.get('type')];
}
It gets styles for the types icon-a, icon-b, but an function for route.
You need to enhance your style function to handle that special case:
style: function(feature) {
const myStyle = stylesMap[feature.get('type')];
if (myStyle instanceof Function) {
return myStyle(feature);
}
return myStyle;
}
PS: Using the same name for a variable twice (styles) is bad practice and can lead to weird bugs.
Here is the runnable example:
var points = [
[76.8412, 43.2245],
[76.8405, 43.2210],
[76.8479, 43.2200],
[76.8512, 43.2220]
];
var route = new ol.geom.LineString(points);
route.transform('EPSG:4326', 'EPSG:3857');
var routeFeature = new ol.Feature({
type: 'route',
geometry: route
});
var startMarker = new ol.Feature({
type: 'icon-a',
geometry: new ol.geom.Point(ol.proj.fromLonLat(points[0]))
});
var endMarker = new ol.Feature({
type: 'icon-b',
geometry: new ol.geom.Point(ol.proj.fromLonLat(points[points.length - 1]))
});
var stylesMap = {
'route': function(feature) {
var geometry = feature.getGeometry();
var styles = [
// linestring
new ol.style.Style({
stroke: new ol.style.Stroke({
color: '#ffcc33',
width: 2
}),
image: new ol.style.Icon({
anchor: [0.5, 1],
src: 'img/icon-a.png'
})
})
];
geometry.forEachSegment(function(start, end) {
var dx = end[0] - start[0];
var dy = end[1] - start[1];
var rotation = Math.atan2(dy, dx);
// arrows
styles.push(new ol.style.Style({
geometry: new ol.geom.Point(end),
image: new ol.style.Icon({
src: 'https://openlayers.org/en/v4.6.5/examples/data/arrow.png',
anchor: [0.75, 0.5],
rotateWithView: true,
rotation: -rotation
})
}));
});
return styles;
},
'icon-a': new ol.style.Style({
image: new ol.style.Icon({
anchor: [0.5, 1],
src: 'img/icon-a.png'
})
}),
'icon-b': new ol.style.Style({
image: new ol.style.Icon({
anchor: [0.5, 1],
src: 'img/icon-b.png'
})
})
};
var vectorLayer = new ol.layer.Vector({
source: new ol.source.Vector({
features: [routeFeature, startMarker, endMarker]
}),
style: function(feature) {
const myStyle = stylesMap[feature.get('type')];
if (myStyle instanceof Function) {
return myStyle(feature);
}
return myStyle;
}
});
var center = ol.proj.fromLonLat([76.8512, 43.2220]);
var map = new ol.Map({
target: document.getElementById('map'),
view: new ol.View({
center: center,
zoom: 15,
minZoom: 2,
maxZoom: 19
}),
layers: [
new ol.layer.Tile({
source: new ol.source.OSM()
}),
vectorLayer
]
});
html,
body {
width: 100%;
height: 100%;
padding: 0px;
margin: 0px;
}
#map {
/* just for testing purposes */
width: 100%;
height: 100%;
}
<link href="https://openlayers.org/en/v4.6.5/css/ol.css" rel="stylesheet" />
<script src="https://openlayers.org/en/v4.6.5/build/ol-debug.js"></script>
<div id="map"></div>

Related

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);

how to add lines between point in openlayers

I'm trying to add a line between two points on my map. I have the following code but the web page only shows me a base map without the line that I want.
How do I add this line to an OpenLayers map?
var map = new ol.Map({
target: 'map',
layers: [
new ol.layer.Tile({
source: new ol.source.OSM()
})
],
view: new ol.View({
center: ol.proj.fromLonLat([ -95.36,29.75]),
zoom: 10
})
});
var coords = [[-95.36,29.75], [-96.36,30.75]];
var lineString = new ol.geom.LineString(coords);
// transform to EPSG:3857
lineString.transform('EPSG:4326', 'EPSG:3857');
// create the feature
var feature = new ol.Feature({
geometry: lineString,
name: 'Line'
});
var lineStyle = new ol.style.Style({
stroke: new ol.style.Stroke({
color: '#ffcc33',
width: 10
})
});
var raster = new ol.layer.Tile({
source: new ol.source.MapQuest({layer: 'sat'})
});
var source = new ol.source.Vector({
features: [feature]
});
var vector = new ol.layer.Vector({
source: source,
style: [lineStyle]
});
map.addLayer(vector);
</script>
`
Your code contains a javascript error in OpenLayers v5.x (and v4.6.5, which doesn't appear in v3.16.0):
Uncaught TypeError: ol.source.MapQuest is not a constructor
Remove the code that specifies that:
var raster = new ol.layer.Tile({
source: new ol.source.MapQuest({layer: 'sat'})
});
and the line displays.
proof of concept fiddle
code snippet:
var map = new ol.Map({
target: 'map',
layers: [
new ol.layer.Tile({
source: new ol.source.OSM()
})
],
view: new ol.View({
center: ol.proj.fromLonLat([-95.36, 29.75]),
zoom: 10
})
});
var coords = [
[-95.36, 29.75],
[-96.36, 30.75]
];
var lineString = new ol.geom.LineString(coords);
// transform to EPSG:3857
lineString.transform('EPSG:4326', 'EPSG:3857');
// create the feature
var feature = new ol.Feature({
geometry: lineString,
name: 'Line'
});
var lineStyle = new ol.style.Style({
stroke: new ol.style.Stroke({
color: '#ffcc33',
width: 10
})
});
var source = new ol.source.Vector({
features: [feature]
});
var vector = new ol.layer.Vector({
source: source,
style: [lineStyle]
});
map.addLayer(vector);
html,
body,
#map {
height: 100%;
width: 100%;
margin: 0px;
padding: 0px;
}
<link rel="stylesheet" href="https://openlayers.org/en/v5.2.0/css/ol.css" type="text/css">
<script src="https://cdn.rawgit.com/openlayers/openlayers.github.io/master/en/v5.2.0/build/ol.js"></script>
<div id="map" class="map"></div>

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>

Show hide marker using circle points openlayers 3

How to show hide markers (P icon) using circle points (something like point1.distanceTo(point2))
need to show markers If markers comes inside the circle another hide it (currently changing circle radius through slider)
// we change this on input change
var radius = 10;
longitude = 400000;
latitude = 300000;
var styleFunction = function() {
return new ol.style.Style({
image: new ol.style.Circle({
radius: radius,
stroke: new ol.style.Stroke({
color: [51, 51, 51],
width: 2
}),
fill: new ol.style.Fill({
color: [51, 51, 51, .3]
})
})
});
};
var update = function(value) {
// $('#range').val() = value;
radius = value;
vectorLayer.setStyle(styleFunction);
// $('#range').val(value)
// document.getElementById('range').value=value;
}
var feature = new ol.Feature(new ol.geom.Point([longitude, latitude]));
var vectorLayer = new ol.layer.Vector({
source: new ol.source.Vector({
features: [feature]
}),
style: styleFunction
});
var rasterLayer = new ol.layer.Tile({
source: new ol.source.TileJSON({
url: 'http://api.tiles.mapbox.com/v3/mapbox.geography-class.json',
crossOrigin: ''
})
});
// icon marker start here
var iconFeature5 = new ol.Feature({
geometry: new ol.geom.Point([longitude, latitude]),
name: 'Missing Person',
population: 4000,
rainfall: 500
});
var vectorSource5 = new ol.source.Vector({
features: [iconFeature5]
});
var vectorLayer5 = new ol.layer.Vector({
source: vectorSource5
});
var iconStyle5 = new ol.style.Style({
image: new ol.style.Icon(/** #type {olx.style.IconOptions} */ ({
anchor: [0.5, 46],
anchorXUnits: 'fraction',
anchorYUnits: 'pixels',
src: 'https://cloud.githubusercontent.com/assets/41094/2833021/7279fac0-cfcb-11e3-9789-24436486a8b1.png'
}))
});
iconFeature5.setStyle(iconStyle5);
// 2nd marker
longitude1 = 100000;
latitude1 = 100000;
var iconFeature1 = new ol.Feature({
geometry: new ol.geom.Point([longitude1, latitude1]),
name: 'Missing Person',
population: 4000,
rainfall: 500
});
var vectorSource1 = new ol.source.Vector({
features: [iconFeature1]
});
var vectorLayer1 = new ol.layer.Vector({
source: vectorSource1
});
iconFeature1.setStyle(iconStyle5);
var map = new ol.Map({
layers: [rasterLayer,vectorLayer,vectorLayer5,vectorLayer1],
target: document.getElementById('map'),
view: new ol.View({
center: [400000, 400000],
zoom: 4
})
});
html, body, #map {
height: 100%;
overflow: hidden;
}
.input {
margin: 5px 0;
}
<script src="http://openlayers.org/en/v3.16.0/build/ol.js"></script>
<div class="input">
<input type="range" id="range" min="10" max="50" onchange="update(this.value)">
<input type="text" id="range" value="10">
</div>
<div id="map" class="map"></div>
Since you are using a Point and not an actual circle geometry, as you said distanceTo is probably the solution for this, you have to add it in your update function :
var wgs84Sphere = new ol.Sphere(6378137);
var update = function(value) {
// $('#range').val() = value;
radius = value;
vectorLayer.setStyle(styleFunction);
if(wgs84Sphere.haversineDistance(feature.getGeometry().getCoordinates(),iconFeature5.getGeometry().getCoordinates())<=radius){
vectorLayer5.setVisible(true);
}
else{
vectorLayer5.setVisible(false);
}
if(wgs84Sphere.haversineDistance(feature.getGeometry().getCoordinates(),iconFeature1.getGeometry().getCoordinates())<=radius){
vectorLayer1.setVisible(true);
}
else{
vectorLayer1.setVisible(false);
}
}

OpenLayers Remove Layer from map

I'm using a OpenLayers to add dots on the map from a search result. I can add them just fine, but I want to clear/remove the layer when the user does another search. I've tried using RemoveFeature(), using Destroy(), etc but everything I tried doesn't work.
What am I doing wrong?
http://jsfiddle.net/9Lzc1uu2/6/
var USGSimagery = new ol.layer.Tile({
myattribute: 'USGSimagery',
source: new ol.source.TileWMS(({
url: 'http://raster.nationalmap.gov/arcgis/services/Orthoimagery/USGS_EROS_Ortho_SCALE/ImageServer/WMSServer',
params: {
'LAYERS': 0
}
}))
});
var view = new ol.View({
//projection:projection
center: ol.proj.transform(
[-12934933.3971171, 5405304.89115131], 'EPSG:3857', 'EPSG:3857'),
zoom: 18
})
var geolocStyle = new ol.style.Style({
image: new ol.style.Icon(({
anchor: [0.5, 46],
anchorXUnits: 'fraction',
anchorYUnits: 'pixels',
opacity: 1,
src: 'images/icon.png'
}))
});
var map = new ol.Map({
layers: [USGSimagery],
loadTilesWhileInteracting: true,
target: document.getElementById('map'),
view: view
});
var searchResultsStyle = new ol.style.Style({
image: new ol.style.Circle({
radius: 6,
fill: new ol.style.Fill({
color: '#3399CC'
}),
stroke: new ol.style.Stroke({
color: '#fff',
width: 2
})
})
});
var TestSearchResults = [{ 'Name': "R0045000030", 'X': "-12934933.3971171", 'Y': "5405304.89115131" },
{ 'Name': "R0238000050", 'X': "-12934887.0227854", 'Y': "5405285.39954225" },
{ 'Name': "R0310260660", 'X': "-12934830.2731638", 'Y': "5405249.69762986" }];
var SearchDots = [];
for (var i = 0; i < TestSearchResults.length; i++)
{
var item = TestSearchResults[i];
var positionFeature = new ol.Feature({
geometry: new ol.geom.Point([item["X"], item["Y"]]),
name: item['Name']
});
positionFeature.setStyle(searchResultsStyle);
SearchDots.push(positionFeature);
}
var featuresSearchResults = new ol.layer.Vector({
map: map,
source: new ol.source.Vector({
features: SearchDots
})
});
function DeleteResults()
{
// Delete Search Vectors from Map
featuresSearchResults.destroy();
}
The appropriate way to destroy features of a layer in OpenLayers 3 is to get the layer source, then clear the source:
function DeleteResults()
{
// Delete Search Vectors from Map
featuresSearchResults.getSource().clear();
};
Api Reference

Categories

Resources