How to make Stroke opacity work in OpenLayers 3 - openlayers-3

I cannot get Stroke opacity working in OpenLayers 3 no matter what I try. What I try to achieve is to draw a line to OSM tile map with 0.5 opacity.
Here is sample code:
var lineString = new ol.geom.LineString([
[4.9020, 52.3667],
[4.9030, 52.3667],
[4.9040, 52.3667],
[4.9050, 52.3667]
]);
lineString.transform('EPSG:4326', 'EPSG:3857');
var lineLayer = new ol.layer.Vector({
source: new ol.source.Vector({
features: [new ol.Feature({
geometry: lineString,
name: 'Line'
})]
}),
style: new ol.style.Style({
stroke: new ol.style.Stroke({
color: 'yellow',
opacity: 0.5,
width: 15
})
})
});
var view = new ol.View({
center: ol.proj.transform([4.9020, 52.3667], 'EPSG:4326','EPSG:3857'),
zoom: 18
});
var map = new ol.Map({
layers: [
new ol.layer.Tile({
source: new ol.source.OSM()
}),
lineLayer
],
target: 'map',
controls: ol.control.defaults({
attributionOptions: /** #type {olx.control.AttributionOptions} */ ({
collapsible: false
})
}),
view: view
});
You can see it here:
http://jsfiddle.net/abgcvqw3/1/

The opacity is set through the color option, as the fourth element of the color value (the A, for "Alpha" in RGBA).
For example here's how you can have a semi transparent yellow:
color: [255, 255, 0, 0.5]
And here is another notation:
color: 'rgba(255,255,0,0.5)'

Related

OpenLayers 6 on Rails target.addEventListener is not a function

i start from the scratch to build a Rails 6 Application with Openlayers 6.1.1. with Webpacker and Turbolinks. Many things are working fine, also with turbolinks.
But one thing will not work fine: Openlayers.
I add openlayers with yarn an it is basically working. So i can create a map as i expected, but i am not able to add a VectorLayer. If i do this i will get a console message with :
target.addEventListener is not a function
I mean i am importing all required libs. In my application.js
require("#openlayers/pepjs")
require("ol")
In my map.js
import 'ol/ol.css';
import Feature from 'ol/Feature';
import Map from 'ol/Map';
import MVT from 'ol/format/MVT';
import View from 'ol/View';
import GeoJSON from 'ol/format/GeoJSON';
import Circle from 'ol/geom/Circle';
import TileLayer from 'ol/layer/Tile';
import OSM from 'ol/source/OSM';
//import { Circle as CircleStyle, Fill, Stroke, Style } from 'ol/style';
import VectorLayer from 'ol/layer/Vector';
import VectorSource from 'ol/source/Vector';
And my map object:
var vectorLayer = new VectorLayer({
source: new VectorSource({
url: 'v1/track/journey',
format: new GeoJSON()
}),
});
var OSMMap = new TileLayer({
source: new OSM({
attributions: [
'(c) OpenStreetMap'
],
opaque: false,
url: 'http://10.232.200.17/tiles/osm/{z}/{x}/{y}.png'
})
});
// OL Test
var map = new Map({
layers: [
OSMMapHLC1,
VectorLayer
],
target: 'map',
view: new View({
center: [0, 0],
zoom: 2
})
});
I tried it without turbolinks
I added pepjs
I added jquery manually
I tried Leaflet. Result VectorLayers an Realtime Plugin working fine.
Hint. I have to use Openlayers not Leaflet.
Many thanks to everyone who can help.
Stacktrace
Regards Marco
try to replace this on your code:
var map = new Map({
layers: [
OSMMap,
vectorLayer
],
thank you so much for your answer. i thinks this was a copy-paste failure from my side. I had try so many things that my code was messed up. So i start from the scratch an now it is working, So i will show my code here:
It is mandatory to put all imports outside the turbolinks, everything else should be inside the turbolinks load() function:
import 'ol/ol.css';
import Feature from 'ol/Feature';
import Map from 'ol/Map';
import View from 'ol/View';
import GeoJSON from 'ol/format/GeoJSON';
import Circle from 'ol/geom/Circle';
import { Tile as TileLayer, Vector as VectorLayer } from 'ol/layer';
import { OSM, Vector as VectorSource } from 'ol/source';
import { Circle as CircleStyle, Fill, Stroke, Style } from 'ol/style';
//import { toPng } from 'html-to-image';
$(document).on('turbolinks:load', function() {
var exportOptions = {
filter: function(element) {
return element.className ? element.className.indexOf('ol-control') === -1 : true;
}
};
document.getElementById('export-png').addEventListener('click', function() {
map.once('rendercomplete', function() {
toPng(map.getTargetElement(), exportOptions)
.then(function(dataURL) {
var link = document.getElementById('image-download');
link.href = dataURL;
link.click();
});
});
map.renderSync();
});
var image = new CircleStyle({
radius: 5,
fill: null,
stroke: new Stroke({ color: 'red', width: 1 })
});
var styles = {
'Point': new Style({
image: image
}),
'LineString': new Style({
stroke: new Stroke({
color: 'green',
width: 1
})
}),
'MultiLineString': new Style({
stroke: new Stroke({
color: 'green',
width: 1
})
}),
'MultiPoint': new Style({
image: image
}),
'MultiPolygon': new Style({
stroke: new Stroke({
color: 'yellow',
width: 1
}),
fill: new Fill({
color: 'rgba(255, 255, 0, 0.1)'
})
}),
'Polygon': new Style({
stroke: new Stroke({
color: 'blue',
lineDash: [4],
width: 3
}),
fill: new Fill({
color: 'rgba(0, 0, 255, 0.1)'
})
}),
'GeometryCollection': new Style({
stroke: new Stroke({
color: 'magenta',
width: 2
}),
fill: new Fill({
color: 'magenta'
}),
image: new CircleStyle({
radius: 10,
fill: null,
stroke: new Stroke({
color: 'magenta'
})
})
}),
'Circle': new Style({
stroke: new Stroke({
color: 'red',
width: 2
}),
fill: new Fill({
color: 'rgba(255,0,0,0.2)'
})
})
};
var styleFunction = function(feature) {
return styles[feature.getGeometry().getType()];
};
var vectorLayer = new VectorLayer({
source: new VectorSource({
format: new GeoJSON(),
url: 'v1/track?journey=#####'
}),
style: styleFunction
});
var map = new Map({
layers: [
new TileLayer({
source: new OSM()
}),
vectorLayer
],
target: 'map',
view: new View({
center: [0, 0],
zoom: 2
})
});
});

Draw arrow without using any image in openlayers3

How do I draw an arrow over a vector layer in Openlayers 3 map?
I tried creating an arrow using canvaselement but don't know how to draw it over the ol3 map.
A canvas element is not necessary. You can take the arrow example from the Openlayers site and add 2 custom LineString elements instead of the icon. You already have in the example the rotation angle in radians and the event where you should add your code.
Hopefully the following snippet does the trick:
var source = new ol.source.Vector();
var styleFunction = function (feature) {
var geometry = feature.getGeometry();
var styles = [
// linestring
new ol.style.Style({
stroke: new ol.style.Stroke({
color: '#ffcc33',
width: 2
})
})
];
geometry.forEachSegment(function (start, end) {
var dx = end[0] - start[0];
var dy = end[1] - start[1];
var rotation = Math.atan2(dy, dx);
var lineStr1 = new ol.geom.LineString([end, [end[0] - 200000, end[1] + 200000]]);
lineStr1.rotate(rotation, end);
var lineStr2 = new ol.geom.LineString([end, [end[0] - 200000, end[1] - 200000]]);
lineStr2.rotate(rotation, end);
var stroke = new ol.style.Stroke({
color: 'green',
width: 1
});
styles.push(new ol.style.Style({
geometry: lineStr1,
stroke: stroke
}));
styles.push(new ol.style.Style({
geometry: lineStr2,
stroke: stroke
}));
});
return styles;
};
var map = new ol.Map({
layers: [
new ol.layer.Tile({
source: new ol.source.OSM()
}),
new ol.layer.Vector({
source: source,
style: styleFunction
})
],
target: 'map',
view: new ol.View({
center: [0, 0],
zoom: 3
})
});
map.addInteraction(new ol.interaction.Draw({
source: source,
type: ('LineString')
}));
<script src="https://openlayers.org/en/v3.20.1/build/ol.js"></script>
<link href="https://openlayers.org/en/v3.20.1/css/ol.css" rel="stylesheet"/>
<div id="map" class="map" tabindex="0"></div>
This is another customization of the Openlayers line-arrow Example.
It uses a RegularShape instead of an image. The arrow will keep its size independent of the current map zoom.
var source = new ol.source.Vector();
var styleFunction = function (feature) {
var geometry = feature.getGeometry();
var styles = [
// linestring
new ol.style.Style({
stroke: new ol.style.Stroke({
color: '#000',
width: 2
})
})
];
geometry.forEachSegment(function (start, end) {
var dx = end[0] - start[0];
var dy = end[1] - start[1];
var rotation = Math.atan2(dy, dx);
styles.push(new ol.style.Style({
geometry: new ol.geom.Point(end),
image: new ol.style.RegularShape({
fill: new ol.style.Fill({color: '#000'}),
points: 3,
radius: 8,
rotation: -rotation,
angle: Math.PI / 2 // rotate 90°
})
}));
});
return styles;
};
var map = new ol.Map({
layers: [
new ol.layer.Tile({
source: new ol.source.OSM()
}),
new ol.layer.Vector({
source: source,
style: styleFunction
})
],
target: 'map',
view: new ol.View({
center: [0, 0],
zoom: 3
})
});
map.addInteraction(new ol.interaction.Draw({
source: source,
type: ('LineString')
}));
<script src="https://openlayers.org/en/v3.20.1/build/ol.js"></script>
<link href="https://openlayers.org/en/v3.20.1/css/ol.css" rel="stylesheet"/>
<div id="map" class="map" tabindex="0"></div>

Multiselect features in OpenLayers 3 not working

I am new to OpenLayers and have made a simple example where I try to enable drawing of polygons on a map. After drawing I want to be able to multiselect the polygons pressing shift click for further processing. I can not make this work even though some examples on the OpenLayers example page are pretty close...
Here is my code (press Draw button and draw two polygons, press Stop button to exit drawing mode and try to multiselect holding shift key):
<body>
<div>
<img src="stop.png" class="fmsv_map_btn" id="fmsv_stop_elm" title="Stop drawing" alt="Stop drawing">
<img src="draw.png" class="fmsv_map_btn" id="fmsv_contour_elm" title="Contour" alt="Contour">
</div>
<div width="600" height="600" id="map" class="map"></div>
<script>
var engine = this;
var draw = null;
var map = new ol.Map({
target: "map",
layers: [
new ol.layer.Tile({
source: new ol.source.MapQuest({ layer: 'osm' })
})
],
view: new ol.View({
center: [0,0],
zoom: 2
})
});
var features = new ol.Collection();
var source = new ol.source.Vector({ features: features });
var featureOverlay = new ol.layer.Vector({
source: source,
style: new ol.style.Style({
fill: new ol.style.Fill({
color: 'rgba(255, 255, 255, 0.2)'
}),
stroke: new ol.style.Stroke({
color: '#000000',
width: 1
}),
image: new ol.style.Circle({
radius: 7,
fill: new ol.style.Fill({
color: '#000000'
})
})
})
});
featureOverlay.setMap(map);
$("#fmsv_contour_elm").click(function () {
addInteraction("Polygon");
});
$("#fmsv_stop_elm").click(function () {
if (draw)
map.removeInteraction(draw);
draw = null;
});
var selectClick = new ol.interaction.Select({
condition: ol.events.condition.click,
//addCondition: ol.events.condition.shiftKeyOnly,
//toggleCondition: ol.events.condition.never,
//removeCondition: ol.events.condition.altKeyOnly,
});
map.addInteraction(selectClick);
var selectedFeatures = select.getFeatures();
//selectClick.on('select', function (e) {
//});
function addInteraction(drawmode) {
if (draw)
map.removeInteraction(draw);
draw = new ol.interaction.Draw({
features: features,
type: /** #type {ol.geom.GeometryType} */ (drawmode)
});
map.addInteraction(draw);
}
</script>
</body>
Use map.addLayer(featureOverlay); instead of featureOverlay.setMap(map)

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/

Shadow Marker for Icons in OpenLayers 3

Is there any elegant method to add shadow markers to a loop of icons in OpenLayers 3 ?
I'm struggling with adding shadows to an icon in ol3...and there is no consistent materials about this matter.
Try (with example styles):
var iconStyle = new ol.style.Style({
image: new ol.style.Circle({
radius: 10,
snapToPixel: false,
fill: new ol.style.Fill({
color: 'rgba(77,135,254,0.4)'
})
}),
zIndex: 1
});
var shadowStyle = new ol.style.Style({
stroke: new ol.style.Stroke({
color: 'rgba(0,0,0,0.5)',
width: 6
}),
zIndex: 0
});
iconFeature.setStyle([iconStyle, shadowStyle]);
and then:
var iconSource = new ol.source.Vector(); // create an empty source
var icon = new ol.geom.Point(
// your point
);
var iconFeature = new ol.Feature({ // create a feature
geometry: icon
});
iconSource.addFeature(iconFeature); // add the feature to the source
var iconLayer = new ol.layer.Vector({ // create a layer with that source
source: iconSource
});
map.addLayer(iconLayer); // add the layer to the map

Resources