How to draw more complex graphical objects in OpenLayers? - javascript

I'm beginner in OpenLayers and I'm wondering how to draw more complex graphical objects such as the following:
I've taken a look at their examples, but not found that kind of drawings. I'd like to use their primitives, not images.
UPDATE:
onDrawEnd (event) {
this.sizeFeature = event.feature
this.$refs.setSizeDialog.open()
},
onSizeSet (title) {
this.sizeFeature.set('graphics', true)
this.sizeFeature.set('style', sizeStyleId)
this.sizeFeature.set('title', title)
this.setFeatureStyle(this.sizeFeature)
// Save graphics after the line with title was drawn
developedDocumentsApi.saveDrawingGraphics(this.document.id, this.updateGraphicsObjList())
}
setFeatureStyle (feature) {
const styleId = feature.get('style')
let style = null
switch (styleId) {
case 0: {
style = this.getRedPoint()
break
}
...
case 11: {
const title = feature.get('title')
style = this.getSizeStyle(feature, title)
break
}
}
feature.setStyle(style)
}
getSizeStyle (feature, title) {
const pointStyle = new Style({
image: new Circle({
radius: width * 2,
fill: new Fill({ color: 'black' }),
stroke: new Stroke({ color: 'black', width: width / 2 })
}),
zIndex: Infinity
})
const lineStyle = new Style({
stroke: new Stroke({ color: 'black', width: 2 }),
text: new Text({
font: '12px Calibri,sans-serif',
overflow: true,
placement: 'line',
textBaseline: 'bottom',
fill: new Fill({ color: 'black' }),
stroke: new Stroke({ color: '#fff', width: 3 })
})
})
const startStyle = lineStyle.clone()
const endStyle = lineStyle.clone()
const resolution = this.devDocMap.getView().getResolution()
const styles = [pointStyle]
const geometry = feature.getGeometry()
if (geometry.getType() === 'LineString') {
console.log('LineString')
lineStyle.getText().setText((feature.getGeometry().getLength() / 1000).toFixed())
styles.push(lineStyle)
const pixels = 10
const start = geometry.getFirstCoordinate()
startStyle.setGeometry(LineString([[start[0], start[1] - pixels * resolution], [start[0], start[1] + pixels * resolution]]))
styles.push(startStyle)
const end = geometry.getLastCoordinate()
endStyle.setGeometry(LineString([[end[0], end[1] - pixels * resolution], [end[0], end[1] + pixels * resolution]]))
styles.push(endStyle)
return styles
}
}

You could do something similar to this example https://openlayers.org/en/v4.6.5/examples/line-arrows.html but instead of using icon images you should style the line ends as linestrings
var raster = new ol.layer.Tile({
source: new ol.source.OSM()
});
var source = new ol.source.Vector();
var white = [255, 255, 255, 1];
var blue = [0, 153, 255, 1];
var width = 3;
var pointStyle = new ol.style.Style({
image: new ol.style.Circle({
radius: width * 2,
fill: new ol.style.Fill({
color: blue
}),
stroke: new ol.style.Stroke({
color: white,
width: width / 2
})
}),
zIndex: Infinity
});
var lineStyle = new ol.style.Style({
stroke: new ol.style.Stroke({
color: 'black',
width: 2
}),
text: new ol.style.Text({
font: '12px Calibri,sans-serif',
overflow: true,
placement: 'line',
textBaseline: 'bottom',
fill: new ol.style.Fill({
color: 'black'
}),
stroke: new ol.style.Stroke({
color: '#fff',
width: 3
})
})
});
var startStyle = lineStyle.clone();
var endStyle = lineStyle.clone();
var styleFunction = function(feature, resolution) {
var styles = [pointStyle];
var geometry = feature.getGeometry();
if (geometry.getType() == 'LineString') {
lineStyle.getText().setText((feature.getGeometry().getLength()/1000).toFixed());
styles.push(lineStyle);
var pixels = 10;
var start = geometry.getFirstCoordinate();
startStyle.setGeometry(new ol.geom.LineString([[start[0], start[1] - pixels*resolution], [start[0], start[1] + pixels*resolution]]));
styles.push(startStyle);
var end = geometry.getLastCoordinate();
endStyle.setGeometry(new ol.geom.LineString([[end[0], end[1] - pixels*resolution], [end[0], end[1] + pixels*resolution]]));
styles.push(endStyle);
}
return styles;
};
var vector = new ol.layer.Vector({
source: source,
style: styleFunction
});
var map = new ol.Map({
layers: [raster, vector],
target: 'map',
view: new ol.View({
center: [-11000000, 4600000],
zoom: 4
})
});
map.addInteraction(new ol.interaction.Draw({
source: source,
type: 'LineString',
style: styleFunction
}));
html, body, .map {
margin: 0;
padding: 0;
width: 100%;
height: 100%;
}
<link href="https://cdn.rawgit.com/openlayers/openlayers.github.io/master/en/v5.3.0/css/ol.css" rel="stylesheet" />
<script src="https://cdn.rawgit.com/openlayers/openlayers.github.io/master/en/v5.3.0/build/ol.js"></script>
<div id="map" class="map"></div>
In your case getSizeStyle should return a style function, you cannot use a static style as it changes with resolution:
getSizeStyle (feature, title) {
const pointStyle = new Style({
image: new Circle({
radius: width * 2,
fill: new Fill({ color: 'black' }),
stroke: new Stroke({ color: 'black', width: width / 2 })
}),
zIndex: Infinity
})
const lineStyle = new Style({
stroke: new Stroke({ color: 'black', width: 2 }),
text: new Text({
font: '12px Calibri,sans-serif',
overflow: true,
placement: 'line',
textBaseline: 'bottom',
fill: new Fill({ color: 'black' }),
stroke: new Stroke({ color: '#fff', width: 3 })
})
})
const startStyle = lineStyle.clone()
const endStyle = lineStyle.clone()
return function(feature, resolution) {
const styles = [pointStyle]
const geometry = feature.getGeometry()
if (geometry.getType() === 'LineString') {
console.log('LineString')
lineStyle.getText().setText((feature.getGeometry().getLength() / 1000).toFixed())
styles.push(lineStyle)
const pixels = 10
const start = geometry.getFirstCoordinate()
startStyle.setGeometry(new LineString([[start[0], start[1] - pixels * resolution], [start[0], start[1] + pixels * resolution]]))
styles.push(startStyle)
const end = geometry.getLastCoordinate()
endStyle.setGeometry(new LineString([[end[0], end[1] - pixels * resolution], [end[0], end[1] + pixels * resolution]]))
styles.push(endStyle)
return styles
}
}
}
title doesn't appear to be used, and pointStyle in only needed in a Draw interaction which uses a Point feature to highlight the mouse position.

Related

Draw a polygon with Maptiler and OpenLayers

I want to draw a polygon on a map (MapTiler) using Open Layers.
When I only draw the map and the circle (parts 1 and 2) it looks okay. But if I add part 3 (the polygon) I only see the map. Neither the circle or the polygon are drawn on the map. I guess there is something wrong in the definition of the polygon, but I can't figure it out.
Part 3 updated in accordance with comments posted
/***********************************************************
Part 1: initializing the map
********************************************************* */
var styleJson = 'https://api.maptiler.com/maps/openstreetmap/style.json?key=MyPrivateKey';
var map = new ol.Map({
target: 'map',
view: new ol.View({
constrainResolution: true,
center: ol.proj.fromLonLat([5.8, 51.34]),
zoom: 14
})
});
olms.apply(map, styleJson);
/***********************************************************
Part 2: Draw a circle
********************************************************* */
var centerLongitudeLatitude = ol.proj.fromLonLat([5.8, 51.34]);
var viewProjection = map.getView().getProjection();
var pointResolution = ol.proj.getPointResolution(viewProjection, 1, centerLongitudeLatitude);
var radius = 20;
var Circle = new ol.layer.Vector({
source: new ol.source.Vector({
features: [new ol.Feature(new ol.geom.Circle(centerLongitudeLatitude, radius))]
}),
style: [
new ol.style.Style({
stroke: new ol.style.Stroke({
color: 'red',
width: 2
}),
fill: new ol.style.Fill({
color: 'red'
})
})
],
zIndex: 6,
});
map.addLayer(Circle);
/***********************************************************
UPDATE
- the map is displayed, and
- the circle is drawn,
- but the polygon is still not showing.
Part 3: Drawing a polygon
***********************************************************/
var Line = new ol.layer.Vector({
source: new ol.source.Vector({
features: [new ol.Feature(new ol.geom.Polygon([
[
[5.81, 51.33],
[6.93, 52.44],
[6.93, 52.33],
[5.81, 51.33]
]
])).transform('EPSG:4326', 'EPSG:3857')]
}),
style: [
new ol.style.Style({
stroke: new ol.style.Stroke({
color: 'black',
width: 20
}),
fill: new ol.style.Fill({
color: 'black'
})
})
],
zIndex: 6,
});
map.addLayer(Line);

How can I plot Point type geometry in OpenLayers from a JSON file

I have a web page which contains a MAP instance which is created using OpenLayers. It is supposed to display all straits in the world by Point type geometry. The data (Latitude,Longitude) is available in JSON format. I was able to draw a single Point on map and give it a Style like red dot etc. but since I am naive in openlayers I quiet couldn't figure out a way to do the same for all the Points in JSON file. So my question is how can I draw all the points from JSON file on the map and provide some styling to them like coloring and showing the name beside the point from JSON data.
I am using OpenLayers 5.1.3 with jQuery 2.3, my code
<body>
<div id="map" class="map"></div>
<script type="text/javascript">
var raster = new ol.layer.Tile({
source: new ol.source.OSM()
});
var vectorSource = new ol.source.Vector({
wrapX: false
});
function styleFunction(feature) {
var geometry = feature.getGeometry();
console.log(feature);
var styles = [
new ol.style.Style({
image: new ol.style.Circle({
radius: 3,
stroke: new ol.style.Stroke({
color: [180, 0, 0, 1]
}),
fill: new ol.style.Fill({
color: [180, 0, 0, 0.3]
})
})
})
];
return styles;
}
var vectorPoints = new ol.layer.Vector({
source: vectorSource,
style: styleFunction
});
const map = new ol.Map({
layers: [raster,vectorPoints],
target: 'map',
view: new ol.View({
center: [0, 0],
zoom: 2
})
});
</script>
</body>
and the json data
[{
"gazetteerSource": "ASFA thesaurus",
"placeType": "Strait",
"latitude": 67.259166666667,
"longitude": 26.082222222222,
"minLatitude": null,
"minLongitude": null,
"maxLatitude": null,
"maxLongitude": null,
"precision": 280000,
"preferredGazetteerName": "Denmark Strait",
"preferredGazetteerNameLang": "English",
"status": "standard"
},
{
"gazetteerSource": "ASFA thesaurus",
"placeType": "Strait",
"latitude": 55.31,
"longitude": 14.49,
"minLatitude": null,
"minLongitude": null,
"maxLatitude": null,
"maxLongitude": null,
"precision": 35000,
"preferredGazetteerName": "Bornholm Strait",
"preferredGazetteerNameLang": "English",
"status": "standard"
}]
How to show the preferredGazetteerName along marker
var features = data.map(item => { //iterate through array...
let longitude = item.longitude,
latitude = item.latitude,
iconFeature = new ol.Feature({
geometry: new ol.geom.Point(ol.proj.transform([longitude, latitude], 'EPSG:4326',
'EPSG:3857')),
name: item.preferredGazetteerName
}),
iconStyle = new ol.style.Style({
image: new ol.style.Icon ({
anchor: [0.3, 10],
anchorXUnits: 'fraction',
anchorYUnits: 'pixels',
src: '//openlayers.org/en/v3.20.1/examples/data/icon.png'
}),
text: new ol.style.text({
text: "sample"
})
});
iconFeature.setStyle(iconStyle);
return iconFeature;
For this you need to use ol.Feature() and also need to do looping for your json data.
DEMO
var raster = new ol.layer.Tile({
source: new ol.source.OSM()
}),
vectorSource = new ol.source.Vector({
wrapX: false
}),
json = [{
"gazetteerSource": "ASFA thesaurus",
"placeType": "Strait",
"latitude": 67.259166666667,
"longitude": 26.082222222222,
"minLatitude": null,
"minLongitude": null,
"maxLatitude": null,
"maxLongitude": null,
"precision": 280000,
"preferredGazetteerName": "Denmark Strait",
"preferredGazetteerNameLang": "English",
"status": "standard"
}, {
"gazetteerSource": "ASFA thesaurus",
"placeType": "Strait",
"latitude": 55.31,
"longitude": 14.49,
"minLatitude": null,
"minLongitude": null,
"maxLatitude": null,
"maxLongitude": null,
"precision": 35000,
"preferredGazetteerName": "Bornholm Strait",
"preferredGazetteerNameLang": "English",
"status": "standard"
}],
/**
* Elements that make up the popup.
*/
container = document.getElementById('popup'),
content = document.getElementById('popup-content'),
closer = document.getElementById('popup-closer'),
/**
* Create an overlay to anchor the popup to the map.
*/
overlay = new ol.Overlay({
element: container,
autoPan: true,
autoPanAnimation: {
duration: 250
}
});
/**
* Add a click handler to hide the popup.
* #return {boolean} Don't follow the href.
*/
closer.onclick = function() {
overlay.setPosition(undefined);
closer.blur();
return false;
};
function styleFunction(feature) {
var geometry = feature.getGeometry();
console.log(feature);
var styles = [
new ol.style.Style({
image: new ol.style.Circle({
radius: 3,
stroke: new ol.style.Stroke({
color: [180, 0, 0, 1]
}),
fill: new ol.style.Fill({
color: [180, 0, 0, 0.3]
})
})
})
];
return styles;
}
var vectorPoints = new ol.layer.Vector({
source: vectorSource,
style: styleFunction
});
const map = new ol.Map({
layers: [raster, vectorPoints],
target: 'map',
view: new ol.View({
center: [0, 0],
zoom: 1
}),
overlays: [overlay]
});
/**
* Add a click handler to the map to render the popup.
*/
map.on('singleclick', function(evt) {
let f = map.forEachFeatureAtPixel(
evt.pixel,
function(ft, layer) {
return ft;
}
);
if (f && f.get('type') == 'click') {
let coordinate = evt.coordinate;
content.innerHTML = '<p>You clicked here:</p><code>' + f.get('desc');
overlay.setPosition(coordinate);
}
});
function addMarker(data) {
var features = data.map(item => { //iterate through array...
let longitude = item.longitude,
latitude = item.latitude,
iconFeature = new ol.Feature({
geometry: new ol.geom.Point(ol.proj.transform([longitude, latitude], 'EPSG:4326',
'EPSG:3857')),
type: 'click',
desc: item.preferredGazetteerName,
}),
iconStyle = new ol.style.Style({
image: new ol.style.Icon( /** #type {module:ol/style/Icon~Options} */ ({
anchor: [0.5, 46],
anchorXUnits: 'fraction',
anchorYUnits: 'pixels',
src: '//openlayers.org/en/v3.20.1/examples/data/icon.png'
})),
text: new ol.style.Text({
text: item.preferredGazetteerName
})
});
iconFeature.setStyle(iconStyle);
return iconFeature;
});
var vectorSource = new ol.source.Vector({
features: features //add an array of features
});
var vectorLayer = new ol.layer.Vector({
source: vectorSource
});
map.addLayer(vectorLayer);
}
addMarker(json);
.ol-popup {
position: absolute;
background-color: white;
-webkit-filter: drop-shadow(0 1px 4px rgba(0, 0, 0, 0.2));
filter: drop-shadow(0 1px 4px rgba(0, 0, 0, 0.2));
padding: 15px;
border-radius: 10px;
border: 1px solid #cccccc;
bottom: 12px;
left: -50px;
min-width: 280px;
}
.ol-popup:after,
.ol-popup:before {
top: 100%;
border: solid transparent;
content: " ";
height: 0;
width: 0;
position: absolute;
pointer-events: none;
}
.ol-popup:after {
border-top-color: white;
border-width: 10px;
left: 48px;
margin-left: -10px;
}
.ol-popup:before {
border-top-color: #cccccc;
border-width: 11px;
left: 48px;
margin-left: -11px;
}
.ol-popup-closer {
text-decoration: none;
position: absolute;
top: 2px;
right: 8px;
}
.ol-popup-closer:after {
content: "✖";
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/openlayers/4.6.5/ol-debug.js"></script>
<link href="https://cdnjs.cloudflare.com/ajax/libs/openlayers/4.6.5/ol-debug.css" rel="stylesheet" />
<script src="https://cdn.polyfill.io/v2/polyfill.min.js?features=requestAnimationFrame,Element.prototype.classList,URL"></script>
<div id="map" class="map"></div>
<div id="popup" class="ol-popup">
<div id="popup-content"></div>
</div>
For showing popup on click of marker follow this popup.html
I got it, I was missing use of style class
text : new ol.style.Text({
font: '10px Verdana',
text: item.preferredGazetteerName,
fill: new ol.style.Fill({
color: [64, 64, 64, 1]
})
})

Openlayers directive angularjs layer-clustering

I used angular-openlayers-directive from this link: https://github.com/tombatossals/angular-openlayers-directive
I want to achieve this effect: http://tombatossals.github.io/angular-openlayers-directive/examples/059-layer-clustering.html
Unfortunately, only a map with no round points is displayed in my application. My code is the same as in the github example.
My code:
function createPointStyle(color, text) {
var options = {
image: new ol.style.Circle({
radius: 10,
fill: new ol.style.Fill({
color: color,
opacity: 0.6
}),
stroke: new ol.style.Stroke({
color: 'white',
opacity: 0.4
})
})
};
if (text) {
options.text = new ol.style.Text({
text: text,
fill: new ol.style.Fill({
color: 'white'
})
});
}
return new ol.style.Style(options);
}
function createIconStyle() {
return new ol.style.Style({
image: new ol.style.Icon({
anchor: [0.5, 1],
anchorXUnits: 'fraction',
anchorYUnits: 'fraction',
opacity: 0.90,
src: 'resource/img/mapin.png'
})
});
}
function getStyle(feature) {
// Take car we use clustering, thus possibly have multiple features in one
var features = feature.get('features');
var style = null;
// Icon base style ?
if ($scope.icon) {
style = createIconStyle();
}
// Circle + txt base style
// Add number of clustered item in this case
else if (features && features.length > 1) {
style = createPointStyle('blue', features.length.toFixed());
} else {
style = createPointStyle('blue');
}
return [style];
}
angular.extend($scope, {
center: {
lat: 43.88,
lon: 7.57,
zoom: 2
},
clusters: {
clustering: true,
clusteringDistance: 40,
source: {
type: 'KML',
projection: 'EPSG:3857',
url: 'resource/kml/earthquakes.kml'
},
style: getStyle
},
// Default to circles
icon: false
});
Someone knows why it does not work?

LineString direction arrows in Openlayers 4

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>

OpenLayers 3: Show vector labels on hover

I'm trying to find a way to display labels on OpenLayers vector features only when the mouse hovers over the feature's icon. I've found a few examples of similar things but nothing that quite does what I need to do. It seems to me like it would be fairly simple but I just can't work out how to start.
This is what my feature style code looks like (one example of several). Note that I'm bringing in the feature data from a few GeoJSON files, hence the feature.get(...)s in the color sections:
if (feature.get('level_pc') < 35 ) {
var style = new ol.style.Style({
fill: new ol.style.Fill({color: feature.get('shapefill')}),
stroke: new ol.style.Stroke({color: feature.get('shapestroke')}),
image: new ol.style.Icon(/** #type {olx.style.IconOptions} */ ({
anchor: [16, 16],
anchorXUnits: 'pixels',
anchorYUnits: 'pixels',
opacity: 0.75,
src: '/icons/aws-red.png'
})),
text: new ol.style.Text({
font: '12px Roboto',
text: feature.get('label'),
fill: new ol.style.Fill({
color: feature.get('textfill')
}),
stroke: new ol.style.Stroke({
color: feature.get('textstroke'),
width: 1
})
})
});
return style
} else { ...
I'm really hoping that there's a way to insert some code into the style definition that creates the hover interaction, rather than having to create a duplicate of every style and then write some extra code that switches between the hover/non-hover styles as necessary. Maybe it could be by way of setting the alpha value in the text color to 255 on mouseover and 0 at other times. Perhaps I'm being too optimistic.
Does anyone have any ideas or examples I could check out?
Thanks,
Gareth
EDIT: Thanks to Jose I'm much closer to the goal now. My original code has changed somewhat since I first asked the question. I'm now applying styles to each feature through a function which reads the name of the icon file from GeoJSON data. For example gates are displayed with a 'gate-open' or 'gate-closed' icon and silos with a 'silo-high', 'silo-medium' or 'silo-low' icon. The correct icons and text are displaying on hover for all features, which is great - it's just that when I'm not hovering over the icons, the incorrect icon is displaying - it's showing the 'silo-low' icon for all features. When I hover over an icon it shows the correct icon, then reverts back when I'm no longer hovering.
Here's (the important bits of) my updated code:
var structuresStyleHover = function(feature, resolution) {
style = new ol.style.Style({
fill: new ol.style.Fill({color: feature.get('shapefill')}),
stroke: new ol.style.Stroke({color: feature.get('shapestroke')}),
image: new ol.style.Icon(/** #type {olx.style.IconOptions} */ ({
anchor: [16, 16],
anchorXUnits: 'pixels',
anchorYUnits: 'pixels',
opacity: 1,
src: '/icons/'+feature.get('icon')+'-'+feature.get('status').toLowerCase()+'.png'
})),
text: new ol.style.Text({
font: '12px Roboto',
text: feature.get('label'),
fill: new ol.style.Fill({
color: feature.get('textfill')
}),
stroke: new ol.style.Stroke({
color: feature.get('textstroke'),
width: 1
})
})
})
return style;
};
var styleCache = {};
var styleFunction = function(feature,resolution) {
var radius = 16;
var style = styleCache[radius];
if (!style) {
style = new ol.style.Style({
image: new ol.style.Icon(/** #type {olx.style.IconOptions} */ ({
anchor: [16, 16],
anchorXUnits: 'pixels',
anchorYUnits: 'pixels',
opacity: 0.5,
src: '/icons/'+feature.get('icon')+'-'+feature.get('status').toLowerCase()+'.png'
})),
});
styleCache[radius] = style;
}
return style;
};
var structuresLayer = new ol.layer.Vector({
source: structuresSource,
style: styleFunction
});
...
var map = new ol.Map({
layers: [paddocksLayer,structuresLayer],
interactions: ol.interaction.defaults({
altShiftDragRotate: false,
dragPan: false,
rotate: false
}).extend([new ol.interaction.DragPan({kinetic: null})]),
target: olMapDiv,
view: view
});
...
map.on('pointermove', function(evt) {
if (evt.dragging) {
return;
}
structuresLayer.getSource().getFeatures().forEach(f=>{
f.setStyle(styleFunction);
});
var pixel = map.getEventPixel(evt.originalEvent);
map.forEachFeatureAtPixel(pixel,function(feature,resolution) {
feature.setStyle(structuresStyleHover(feature,resolution));
return feature;
});
});
I'm not getting any errors - it's just not showing the correct icon unless the mouse is hovering over the icon.
I'm sure I'm missing something really obvious, but I can't work it out. Any ideas please?
You can use setStyle:
var mystyle = new ol.style.Style({
fill: new ol.style.Fill({color: '#00bbff'}),
stroke: new ol.style.Stroke({color: '#fff'}),
image: new ol.style.Icon(/** #type {olx.style.IconOptions} */ ({
anchor: [16, 16],
anchorXUnits: 'pixels',
anchorYUnits: 'pixels',
scale : 0.1,
opacity: 1,
src: 'http://2.bp.blogspot.com/_Sdh3wYnDKG0/TUiIRjXEimI/AAAAAAAAQeU/bGdHVRjwlhk/s1600/map+pin.png'
})),
text: new ol.style.Text({
font: '12px Roboto',
text: 'AAAAAAAAAAAAAAA',
fill: new ol.style.Fill({
color: '#ffbb00'
}),
stroke: new ol.style.Stroke({
color: '#000',
width: 1
})
})
});
var styleCache = {};
var styleFunction = function(feature) {
var radius = 3;
var style = styleCache[radius];
if (!style) {
style = new ol.style.Style({
image: new ol.style.Circle({
radius: radius,
fill: new ol.style.Fill({
color: 'rgba(255, 153, 0, 0.4)'
}),
stroke: new ol.style.Stroke({
color: 'rgba(255, 204, 0, 0.2)',
width: 1
})
})
});
styleCache[radius] = style;
}
return style;
};
var vector = new ol.layer.Vector({
source: new ol.source.Vector({
url: 'http://openlayers.org/en/v3.17.1/examples/data/kml/2012_Earthquakes_Mag5.kml',
format: new ol.format.KML({
extractStyles: false
})
}),
style: styleFunction
});
var raster = new ol.layer.Tile({
source: new ol.source.Stamen({
layer: 'toner'
})
});
var map = new ol.Map({
layers: [raster, vector],
target: 'map',
view: new ol.View({
center: [0, 0],
zoom: 2
})
});
map.on('pointermove', function(evt) {
if (evt.dragging) {
return;
}
vector.getSource().getFeatures().forEach(f=>{
f.setStyle(styleFunction);
});
var pixel = map.getEventPixel(evt.originalEvent);
map.forEachFeatureAtPixel(pixel,function(feature) {
feature.setStyle(mystyle);
return feature;
});
});
#map {
position: relative;
}
<title>Earthquakes in KML</title>
<link rel="stylesheet" href="http://openlayers.org/en/v3.17.1/css/ol.css" type="text/css">
<script src="http://openlayers.org/en/v3.17.1/build/ol.js"></script>
<script src="https://code.jquery.com/jquery-2.2.3.min.js"></script>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css">
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/js/bootstrap.min.js"></script>
<div id="map" class="map"></div>

Categories

Resources