I have a simple map with a static pixel image layer:
<!DOCTYPE html>
<html>
<head>
<title>Simple Map</title>
<link rel="stylesheet" href="http://openlayers.org/en/v3.13.0/css/ol.css" type="text/css">
<script src="http://openlayers.org/en/v3.13.0/build/ol.js"></script>
// reference to jquery here
</head>
<body>
<div id="map" class="map"></div>
<script>
var extent = [0, 0, 2000000, 2000000];
var projection = new ol.proj.Projection({
code: 'xkcd-image',
units: 'pixels',
extent: extent
});
var map = new ol.Map({
layers: [
new ol.layer.Tile({
source: new ol.source.OSM()
})
],
target: 'map',
view: new ol.View({
center: [0, 0],
zoom: 2
})
});
image = new ol.layer.Image({
source: new ol.source.ImageStatic({
url: 'http://imgs.xkcd.com/comics/online_communities.png',
projection: projection,
imageExtent: extent
})
});
map.addLayer(image);
image.on('singleclick', function(evt) {
var xy = evt.pixel;
console.log(xy);
var canvasContext = $('.ol-unselectable')[0].getContext('2d');
var pixelAtClick = canvasContext.getImageData(xy[0], xy[1], 1, 1).data;
var red = pixelAtClick[0]; // green is [1] , blue is [2] , alpha is [4]
});
</script>
</body>
</html>
When clicking on the image I want to get the color of the pixel that I clicked on. As far as I understand the raster source example (http://openlayers.org/en/v3.13.0/examples/raster.html), this is only possible with raster sources so I converted the image into a raster source. (When I add that raster source to the layer, I get the message that this operation is insecure, so I still use the image to show on the map.)
Here (How to get a pixel's color value from an Openlayers 3 layer?) the color is read from evt.context. However, with me evt.context is undefined.
Addendum: There might be several image layers overlaying each other. I need to get the color from a single specific image layer.
So this isn't ideal but might send you along the right lines:
You can use the pixel xy of the click event to query the canvas object that openlayers creates and puts your map data onto.
map.on('singleclick', function(evt) {
var xy = evt.pixel;
var canvasContext = $('.ol-unselectable')[0].getContext('2d');
var pixelAtClick = canvasContext.getImageData(xy[0], xy[1], 1, 1).data;
var red = pixeAtClick[0]; // green is [1] , blue is [2] , alpha is [4]
});
This assumes that you are using jQuery and that the canvas is the first DOM element using the class '.ol-unselectable'.
Hope it helps.
Related
Is there a way to enfore a just created Draw interaction to visualize itself before the first mousemouse event?
I use openlayers 4.6.5. The application creates an ol.interaction.Draw in response to a keyboard event. The type is a LineString.
After the first mousemove the expected circle is shown at the mouse position.
My problem is that the Draw interaction does not visualize anything until the first mouse move by the user.
Interactions are driven by mouse events so you will need to re-run the last event.
Add a listener for pointermove events to your map and save the last one
var lastEvent;
map.on('pointermove', function(event){ lastEvent = event; });
then when you add the interaction get it to handle the last event
map.addInteraction(draw);
draw.handleEvent(lastEvent);
Version 4.6.4 works for me. An interaction is added by after 5 seconds, then removed and new interaction added at 5 and 10 seconds intervals:
var raster = new ol.layer.Tile({
source: new ol.source.OSM()
});
var source = new ol.source.Vector();
var vector = new ol.layer.Vector({
source: source
});
var map = new ol.Map({
layers: [raster, vector],
target: 'map',
view: new ol.View({
center: [-11000000, 4600000],
zoom: 4
})
});
var draw; // global so we can remove it later
function addInteraction() {
draw = new ol.interaction.Draw({
source: source,
type: 'LineString'
});
map.addInteraction(draw);
}
var lastEvent;
map.on('pointermove', function(event){ lastEvent = event; });
var add = false;
setInterval(function(){
add = !add;
if (add) {
addInteraction();
draw.handleEvent(lastEvent);
} else {
map.removeInteraction(draw);
}
}, 5000);
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/openlayers/4.6.4/ol.css" type="text/css">
<!-- The line below is only needed for old environments like Internet Explorer and Android 4.x -->
<script src="https://cdn.polyfill.io/v2/polyfill.min.js?features=requestAnimationFrame,Element.prototype.classList,URL"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/openlayers/4.6.4/ol.js"></script>
<div id="map" class="map"></div>
I wanna ask how to make the marker show animated gif picture like openlayers 2 do...it can show the animated marker..what I want is show animated gif marker not make a marker move..it is possible or not?
style = {
anchorXUnits: 'fraction',
anchorYUnits: 'pixels',
anchor: anchor,
opacity: 1,
src: 'https://articulate-heroes.s3.amazonaws.com/uploads/rte/kgrtehja_DancingBannana.gif',
scale: 1,
};
var iconStyle = new ol.style.Style({
image: new ol.style.Icon(/** #type {olx.style.IconOptions} */ (style))
});
var iconFeature = new ol.Feature({
position: data.coordinate,
geometry: new ol.geom.Point([0,0]),
});
iconFeature.setStyle(iconStyle);
How to make https://articulate-heroes.s3.amazonaws.com/uploads/rte/kgrtehja_DancingBannana.gif displayed animated as a gif in a map? is it possible or not create animated features in openlayers 3..I don't find any article with contain this solving...thanks
Yes there is a way do it but is a bit tricky so I am not sure whether it fit to your needs.
You need to add a marker instead and use css to style the marker.
check this
your html with the dom element
<div id="map" class="map"></div>
<div id="marker" title="Marker"></div>
your js here
var layer = new ol.layer.Tile({
source: new ol.source.OSM()
});
var map = new ol.Map({
layers: [layer],
target: 'map',
view: new ol.View({
center: [0, 0],
zoom: 2
})
});
// the position of your marker
var pos = ol.proj.fromLonLat([23.3725, 35.208889]);
var marker = new ol.Overlay({
position: pos,
positioning: 'center-center',
element: document.getElementById('marker'),
stopEvent: false
});
map.addOverlay(marker);
and your css here
#marker {
width: 365px;
height: 360px;
background: url("https://articulate-heroes.s3.amazonaws.com/uploads/rte/kgrtehja_DancingBannana.gif") no-repeat scroll 0% 0% transparent;
}
and a fiddle here with the dancing banana (nice gif though :)))) )
This can definitely be done with a feature or layer style, with the help of a gif decoder that extracts the frames from the gif and controls an animation. Using gifler, the relevant code could look something like this:
const gifUrl = "./data/kgrtehja_DancingBannana.gif";
const gif = gifler(gifUrl);
gif.frames(
document.createElement("canvas"),
(ctx, frame) => {
if (!iconFeature.getStyle()) {
iconFeature.setStyle(
new Style({
image: new Icon({
img: ctx.canvas,
imgSize: [frame.width, frame.height]
})
})
);
}
ctx.clearRect(0, 0, frame.width, frame.height);
ctx.drawImage(frame.buffer, frame.x, frame.y);
map.render();
},
true
);
The above code sets an icon style with the animated gif on an existing feature. The feature is stored in a variable iconFeature.
See https://codesandbox.io/s/beautiful-fire-cdrou?file=/main.js for a working example.
An alternative is to use two png images. An effect similar to a gif image can be obtained if you apply two different styles to the same layer using the setStyle () method with a setInterval () function. Ej:
Style1 = {
...
src: '../image1.png',
...
};
Style2 = {
...
src: '../image2.png',
...
};
iconFeature.setStyle(Style1);
then
var n = 0; // global
function changeStyleEvery (){
if (n == 0){
n = 1;
iconFeature.setStyle(Style1);
}else{
n = 0;
iconFeature.setStyle(Style2);
};
};
function applyInterval (){
setInterval(function(){changeStyleEvery(); }, 500);
};
I am trying to display two layers using Openlayers 3, one is a map of Greenland, and the other one is an area of interest. Both layers are tiled.
It seems to be working, but all I get are transparent tiles, so somehow I am placing the view in an area where there is nothing. I am using a UTM 24 N projection (which is the original projection of the layers involved, so no transformation is needed).
Here is my code:
var utm24_projection = new ol.proj.Projection({
code: 'EPSG:32624',
extent: [-396882, 6394710, 1280839.6, 9750153.2],
units: 'm',
axisOrientation: 'neu'
});
ol.proj.addProjection(utm24_projection);
layer1 = new ol.layer.Tile({
source: new ol.source.TileWMS({
url: 'http://www.ourmapserver.gl/geoserver/wms',
params: {'LAYERS': 'ourcompany:greenland', 'TILED': true},
serverType: 'geoserver',
})
});
layer2 = new ol.layer.Tile({
//extent: [-13884991, 2870341, -7455066, 6338219],
source: new ol.source.TileWMS({
url: 'http://www.ourmapserver.gl/geoserver/wms',
params: {'LAYERS': 'ourcompany:interestarea', 'TILED': true},
//projection = ol.proj.get('EPSG:32624');
serverType: 'geoserver'
})
});
var layers = [
layer1,
layer2
];
var map = new ol.Map({
layers: layers,
target: 'map',
view: new ol.View({
projection: utm24_projection,
center: [-48864, 7491452],
zoom: 4
})
});
It worked fine when using Web Mercator.
So I have found a solution.
First of all, I removed the extent from my projection:
var utm24_projection = new ol.proj.Projection({
code: 'EPSG:32624',
units: 'm',
axisOrientation: 'neu'
});
Then when defining the view, I only configure the projection, but no center or zoom.
Finally, I adjust the view to the map size and bounds:
map.getView().fit(bounds, map.getSize());
The map is being displayed correctly.
According to a book I am reading about Openlayers 3 , all I have to do, to reset the renderer is to do this in the Map initialization
renderer: 'dom'
so my code is
var map = new ol.Map({
target: 'map',
layers: [layer],
renderer: 'dom',
view: view,
});
When I load the page, the console gives no errors, but the map does not load at all. I use Openlayers 3.9.0. What is going wrong here?
Thanks
EDIT
This is all the openlayers code
var layer = new ol.layer.Tile({
source: new ol.source.OSM()
});
var kbz = new ol.interaction.KeyboardZoom();
var dr = new ol.interaction.DragRotateAndZoom();
var control = new ol.control.FullScreen();
var center = ol.proj.transform([-1.812, 52.443], 'EPSG:4326', 'EPSG:3857');
var we = new ol.Overlay({
position: center,
element: document.getElementById('we')
});
var view = new ol.View({
center: center,
zoom: 6
});
var map = new ol.Map({
target: 'map',
layers: [layer],
renderer: 'dom',
view: view
});
map.addInteraction(kbz);
map.addInteraction(dr);
map.addControl(control);
map.addOverlay(we);
You have to set the size of the map target element, when using the dom renderer.
Canvas elements, which are used by the default renderer, has a default height of 150px, while normal divs don't have a default height. Setting the height of the target should make you map appear:
#map {
height: 200px;
}
I have a vector layer with a lot of close together data, each rendered by an icon. When rendered in Open Layers 3 using icons of any type/design I often get tearing of elements trying to get through others, I'm sure many people using Open Layers will have seen this happen.
Is there a way of solving this issue?
My code is fairly standard:
var styleCache2 = {};
var WFS_layer_Dangerous_Bends = new ol.layer.Vector({
source : new ol.source.GeoJSON({
projection : 'EPSG:3857',
url : "Vector_Data/A_Vector_Data_Set.geojson"
}),
style : function(feature, resolution) {
if (!styleCache2[path]) {
styleCache2[path] = [new ol.style.Style({
fill : new ol.style.Fill({
color : 'rgba(255, 255, 255, 0.1)'
}),
stroke : new ol.style.Stroke({
color : '#319FD3',
width : 1
}),
image: new ol.style.Icon(({
anchor: [x_anchor, y_anchor],
anchorXUnits: 'pixels',
anchorYUnits: 'pixels',
src: path
}))
}),
zIndex : 1
})];
}
return styleCache2[path];
}
});
/*Creating the map object linked to the map selector/div in the HTML */
map_object = new ol.Map({
target: 'map',
controls: controls_list,
interactions: interactions_list,
overlays: [overlay],
layers: [OSM_raster, WFS_layer_Dangerous_Bends],
view: view
});
Obviously overlay, controls_list, interactions_list and the OSM_raster are defined somewhere too, but I don't think they're relevant to the question so I haven't included them.
I tried to capture an example, it's quite difficult because its intermittent, this shows about 5 icons overlapping normally, but a couple in the middle are tearing through each other: