Openlayers 4: Getting Pixeldata from Map appears to have an offset - javascript

I have written a function to retrieve pixel data from an openlayers map:
var imagery = new ol.layer.Tile({
source: new ol.source.OSM(),
crossOrigin: 'anonymous'
});
var context;
/**
* Apply a filter on "postcompose" events.
*/
imagery.on('postcompose', function(event) {
context = event.context;
});
function getPixel( latitude, longitude ){
let lat = parseFloat( latitude );
let lon = parseFloat( longitude );
var coord = ol.proj.transform( [lon, lat], 'EPSG:4326', 'EPSG:3857' );
var pixel = map.getPixelFromCoordinate( coord );
if( context == null )
return;
return context.getImageData(pixel[0], pixel[1], 1, 1).data;
}
var map = new ol.Map({
target: 'map',
layers: [imagery],
...
});
The code is based on this link. Also, the transformation from LatLon data to pixel coordinates is used quite extensively and does not provide any problems.
However, the pixel data that is retrieved is somehow offset from the coordinates, so that I see water where there is land and otherwise. As far as I can tell, the offset is a few hundred pixels (or a few meters in lonlat) in x and y direction, and probably the cause lies in the fact that the pixels from the map do not correspond to that of the canvas.
Does anyone have a clue on how to tackle this problem?

Mike's response indeed put me on the right track!
I have included the modified code for those who may run into the same issue:
var pixelRatio;
var context;
var imagery = new ol.layer.Tile({
source: new ol.source.OSM(),
crossOrigin: 'anonymous'
});
/**
* before rendering the layer, determine the pixel ratio
* and save the context
*/
imagery.on('precompose', function(event) {
context = event.context;
pixelRatio = event.frameState.pixelRatio;
context.save();
});
/**
* Restore the context
*/
imagery.on('postcompose', function(event) {
context = event.context;
context.restore();
});
/**
* Get the pixel's rgba data
*/
function getPixel( latitude, longitude, offx, offy ){
let lat = parseFloat( latitude );
let lon = parseFloat( longitude );
var coord = ol.proj.transform( [lon, lat], 'EPSG:4326', 'EPSG:3857' );
var pixel = map.getPixelFromCoordinate( coord );
if( context == null )
return;
var pixelAtClick = context.getImageData(pixel[0]*pixelRatio, pixel[1]*pixelRatio, 1, 1).data;
rgb = [0,0,0,0];
for( var i=0;i<pixelAtClick.length;i++ ){
rgb[i] = pixelAtClick[i];
}
return rgb;
}

Related

Here Maps polyline with altitude

I need to display different polylines from A to B. So, these lines should be distinguishable from each other. I haved tried to set polylines using pushpoint function with altitude parameter. However it is still on the ground level. And the last polyline I inserted overwrites the previous one.
Altitude value works on markers but I want to apply it on polyline.
I changed the sample code here markers with altitude as below. You can see the orange line is just on top of the gray line when you change the code with the below one. I would like both lines to be displayed like the markers you see above them.
/**
* Calculate the bicycle route.
* #param {H.service.Platform} platform A stub class to access HERE services
*/
function calculateRouteFromAtoB (platform) {
var router = platform.getRoutingService(),
routeRequestParams = {
mode: 'fastest;bicycle',
representation: 'display',
routeattributes : 'shape',
waypoint0: '-16.1647142,-67.7229166',
waypoint1: '-16.3705847,-68.0452683',
// explicitly request altitude values
returnElevation: true
};
router.calculateRoute(
routeRequestParams,
onSuccess,
onError
);
}
/**
* Process the routing response and visualise the descent with the help of the
* H.map.Marker
*/
function onSuccess(result) {
var lineString = new H.geo.LineString(),
lineString2 = new H.geo.LineString(),
routeShape = result.response.route[0].shape,
group = new H.map.Group(),
dict = {},
polyline,
polyline2;
routeShape.forEach(function(point) {
var parts = point.split(',');
var pp= new H.geo.Point(parts[0],parts[1],4000,"SL");
console.log(parts[2]);
lineString.pushLatLngAlt(parts[0], parts[1]);
lineString2.pushPoint(pp);
// normalize the altitude values for the color range
var p = (parts[2] - 1000) / (4700 - 1000);
var r = Math.round(255 * p);
var b = Math.round(255 - 255 * p);
// create or re-use icon
var icon;
if (dict[r + '_' + b]) {
icon = dict[r + '_' + b];
} else {
var canvas = document.createElement('canvas');
canvas.width = 4;
canvas.height = 4;
var ctx = canvas.getContext('2d');
ctx.fillStyle = 'rgb(' + r + ', 0, ' + b + ')';
ctx.fillRect(0, 0, 4, 4);
icon = new H.map.Icon(canvas);
// cache the icon for the future reuse
dict[r + '_' + b] = icon;
}
// the marker is placed at the provided altitude
var marker = new H.map.Marker({
lat: parts[0], lng: parts[1], alt: parts[2]
}, {icon: icon});
var marker2 = new H.map.Marker({
lat: parts[0], lng: parts[1], alt: parts[2]-800
}, {icon: icon});
group.addObject(marker);
group.addObject(marker2);
});
polyline = new H.map.Polyline(lineString, {
style: {
lineWidth: 6,
strokeColor: '#555555'
}
});
polyline2 = new H.map.Polyline(lineString2, {
style: {
lineWidth: 3,
strokeColor: '#FF5733'
}
});
// Add the polyline to the map
map.addObject(polyline);
map.addObject(polyline2);
// Add markers to the map
map.addObject(group);
// Zoom to its bounding rectangle
map.getViewModel().setLookAtData({
bounds: polyline.getBoundingBox(),
tilt: 60
});
}
/**
* This function will be called if a communication error occurs during the JSON-P request
* #param {Object} error The error message received.
*/
function onError(error) {
alert('Can\'t reach the remote server');
}
/**
* Boilerplate map initialization code starts below:
*/
// set up containers for the map + panel
var mapContainer = document.getElementById('map'),
routeInstructionsContainer = document.getElementById('panel');
//Step 1: initialize communication with the platform
// In your own code, replace variable window.apikey with your own apikey
var platform = new H.service.Platform({
apikey: window.apikey
});
var defaultLayers = platform.createDefaultLayers();
//Step 2: initialize a map - this map is centered over Berlin
var map = new H.Map(mapContainer,
defaultLayers.vector.normal.map,{
center: {lat:52.5160, lng:13.3779},
zoom: 13,
pixelRatio: window.devicePixelRatio || 1
});
// add a resize listener to make sure that the map occupies the whole container
window.addEventListener('resize', () => map.getViewPort().resize());
//Step 3: make the map interactive
// MapEvents enables the event system
// Behavior implements default interactions for pan/zoom (also on mobile touch environments)
var behavior = new H.mapevents.Behavior(new H.mapevents.MapEvents(map));
// Create the default UI components
var ui = H.ui.UI.createDefault(map, defaultLayers);
// Now use the map as required...
calculateRouteFromAtoB (platform);
Unfortunately, for now only markers support altitudes.
Polylines should follow in near future.

Google maps .fitBounds() and custom offsetCenter?

I was using this function, which given a latlong, it centers the google maps considering the offsetX and offsetY:
customCenter: function ( latlng, offsetx, offsety ) {
// latlng is the apparent centre-point
// offsetx is the distance you want that point to move to the right, in pixels
// offsety is the distance you want that point to move upwards, in pixels
var self = this;
var scale = Math.pow(2, self.map.getZoom());
google.maps.event.addListenerOnce(self.map,"projection_changed", function() {
var worldCoordinateCenter = self.map.getProjection().fromLatLngToPoint(latlng);
var pixelOffset = new google.maps.Point((offsetx/scale) || 0,(offsety/scale) ||0)
var worldCoordinateNewCenter = new google.maps.Point(
worldCoordinateCenter.x - pixelOffset.x,
worldCoordinateCenter.y + pixelOffset.y
);
var newCenter = self.map.getProjection().fromPointToLatLng(worldCoordinateNewCenter);
self.map.setCenter(newCenter);
});
}
Which I'm using like, so:
self.customCenter (marker.position, $('aside').width(), 0 );
But now they'are asking me to fitbounds with the offset ( so none of the Markers are out of the view
(usually used like so:)
var bounds = new google.maps.LatLngBounds();
bounds.extend(myPlace);
bounds.extend(Item_1);
bounds.extend(Item_2);
bounds.extend(Item_3);
self.map.fitBounds(bounds);
But I don't see a way to combine this two functionalities
( this is because I have an aside floating ( pos: absolute ) over the google maps, just like this image I found online:
)
Any ideas?
-I'm trying like this now:
customCenterWithBounds: function ( offsetx, offsety ) {
// offsetx is the distance you want that point to move to the right, in pixels
// offsety is the distance you want that point to move upwards, in pixels
var self = this;
self.map.fitBounds(self.bounds);
var mapCenter = self.map.getCenter();
var latlng = new google.maps.LatLng (mapCenter.lat(), mapCenter.lng() );
var scale = Math.pow(2, self.map.getZoom());
google.maps.event.addListenerOnce(self.map,"projection_changed", function() {
var worldCoordinateCenter = self.map.getProjection().fromLatLngToPoint(latlng);
var pixelOffset = new google.maps.Point((offsetx/scale) || 0,(offsety/scale) ||0)
var worldCoordinateNewCenter = new google.maps.Point(
worldCoordinateCenter.x - pixelOffset.x,
worldCoordinateCenter.y + pixelOffset.y
);
var newCenter = self.map.getProjection().fromPointToLatLng(worldCoordinateNewCenter);
self.map.setCenter(newCenter);
});
}
But the map would be over-zoomed.. and not even in the center of the visible area..
I ended up doing this
customCenter: function (offsetx, offsety, bounds_obj ) {
if ($(window).width() <= 1200 ) {
offsetx = 0;
}
var self = this;
google.maps.event.addListenerOnce(self.map,"projection_changed", function() {
var latlng;
var fbObj = self.map.fitBounds(self.bounds);
var mapCenter = self.map.getCenter();
latlng = new google.maps.LatLng(mapCenter.lat(), mapCenter.lng());
var scale = Math.pow(2, self.map.getZoom());
var worldCoordinateCenter = self.map.getProjection().fromLatLngToPoint(latlng);
var pixelOffset = new google.maps.Point((offsetx/scale) || 0,(offsety/scale) ||0)
var worldCoordinateNewCenter = new google.maps.Point(
worldCoordinateCenter.x - pixelOffset.x,
worldCoordinateCenter.y + pixelOffset.y
);
var newCenter = self.map.getProjection().fromPointToLatLng(worldCoordinateNewCenter);
self.map.setCenter(newCenter);
});
}

Create latLngBounds based on zoom level and a center point

I have a list of features/polygons that I need to run an operation on based on the maps bounding box relative to the feature, without moving the map.
To further explain my problem I can give an example of how I could do this if moving the map around wasn't an issue:
features.forEach(function (feature) {
var bbox,
ne,
sw,
fBounds,
zoom,
mBounds;
bbox = feature.geometry.bbox;
sw = L.latLng(bbox[1], bbox[0]);
ne = L.latLng(bbox[3], bbox[2]);
fBounds = L.latLngBounds(sw, ne);
map.fitBounds(bounds);
mBounds = map.getBounds();
zoom = map.getZoom();
//Execute operation based on mBounds and zoom
}
I have tested a lot and this is the closest thing I have to a working code snippet:
var self = this,
bbox,
sw,
ne,
bounds,
zoom,
swPoint,
nePoint,
center,
factor,
dw,
dh,
cpx;
bbox = feature.geometry.bbox;
sw = L.latLng(bbox[1], bbox[0]);
ne = L.latLng(bbox[3], bbox[2]);
bounds = L.latLngBounds(sw, ne);
zoom = self.map.getBoundsZoom(bounds, false); //maxZoom?
swPoint = self.map.project(bounds.getSouthWest(), zoom),
nePoint = self.map.project(bounds.getNorthEast(), zoom),
center = self.map.unproject(swPoint.add(nePoint).divideBy(2), zoom);
factor = self.map.options.crs.scale(zoom) / 8388608;
dw = self.map.getSize().x / 2*factor;
dh = self.map.getSize().y / 2*factor;
cpx = self.map.options.crs.latLngToPoint(center, zoom);
return {
ne: self.map.options.crs.pointToLatLng(L.point(cpx.x + dw, cpx.y - dh, false), zoom),
sw: self.map.options.crs.pointToLatLng(L.point(cpx.x - dw, cpx.y + dh, false), zoom),
center: center,
zoom: zoom
}
//Execute operation based on returned object, repeat for every feature
This 'works' but it doesn't give the same result as the first code snippet (i.e. the results are wrong).
Following snippet worked for me, in case anyone else should have the same question:
var self = this,
bbox,
sw,
ne,
bounds,
zoom,
center;
bbox = feature.geometry.bbox;
sw = L.latLng(bbox[1], bbox[0]);
ne = L.latLng(bbox[3], bbox[2]);
bounds = L.latLngBounds(sw, ne);
zoom = self.map.getBoundsZoom(bounds, false); //maxZoom?
sw = self.map.project(bounds.getSouthWest(), zoom),
ne = self.map.project(bounds.getNorthEast(), zoom),
center = self.map.unproject(sw.add(ne).divideBy(2), zoom);
bounds = self.map.getPixelBounds(center, zoom),
sw = self.map.unproject(b2.getBottomLeft()),
ne = self.map.unproject(b2.getTopRight());
return new L.LatLngBounds(sw, ne);

Convert xyz coordinate of a tile to longitude/latitude

I wanted to make a map using openlayers but center it a unique way. For example I have a z/x/y coordinate of 12/2045/-1362, how do I convert it to longitude/latitude? It's quite the polar opposite of this: How to get X Y Z coordinates of tile by click on Leaflet map
It's quite hard for me to get the logic of the above link and invert it. I hope someone here has an experience or a ready-made formula for this. Thanks
Later I'll this in rendering the center of my map like this:
var z = 12;
var x = 2045;
var y = -1362;
function convertXYZtoCoor(z, x, y) {
// code here
return [lng, lat];
}
var coor = convertXYZtoCoor(z, x, y);
var view = new ol.View({
center: ol.proj.transform(
[coor[0], coor[1]], 'EPSG:4326', 'EPSG:3857'),
zoom: z
});
var map = new ol.Map({
layers: [
new ol.layer.Tile({
source: new ol.source.OSM()
})
],
target: 'map',
view: view
});
Hope my question is understood more thanks.
Edit: Added code
var tileExtent = function(tileCoord){
var z = tileCoord[0];
var x = tileCoord[1];
var y = tileCoord[2];
var tileGridOrigin = tileGrid.getOrigin(z);
var tileSizeAtResolution = tileGrid.getTileSize(z) * tileGrid.getResolution(z);
return [
tileGridOrigin[0] + tileSizeAtResolution * x,
tileGridOrigin[1] + tileSizeAtResolution * y,
tileGridOrigin[0] + tileSizeAtResolution * (x + 1),
tileGridOrigin[1] + tileSizeAtResolution * (y + 1)
];
}
You can test/verify at http://jsfiddle.net/eurx57s7/
Note (stolen from the ol3 example, but it applies here to):
The tile coordinates are ol3 normalized tile coordinates (origin bottom left), not OSM tile coordinates (origin top left)

how can I set markers with different colours depending on the markertype, and how to determinate their coordinates?, Im using openlayers.org library

I am starting using openlayers javascript library from openlayers.org.
I want to set dinamic markers with diferent colours for each device type(cam marker, server marker and so on), and I tried different ways to set this, but it doesn't work actually.
This is the map that Im developing: http://manotazsoluciones.com/map/.
Another problem that Im facing is when I set coordinates. For example: if I set [0,0] coordinates on a marker, when I use click event, the marker get another coordinates like
[30000,-7.081154551613622e-10].
this is the code that Im using to display the map on manotazsoluciones.com/map
<!DOCTYPE html>
<html>
<head>
<title>Manotaz Soluciones</title>
<script src="https://code.jquery.com/jquery-1.11.2.min.js"></script>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/css/bootstrap.min.css">
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/js/bootstrap.min.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/ol3/3.6.0/ol.css" type="text/css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/ol3/3.6.0/ol.js"></script>
</head>
<body>
<div class="container-fluid">
<div class="row-fluid">
<div class="col-md-10 col-md-offset-1">
<div id="map" class="map">
<div id="popup">
<div id="popup-content"></div>
</div>
</div>
</div>
</div>
</div>
<script>
$( document ).ready(function() {
/**************** DRAG AND DROP EVENTS ****************/
/**
* Define a namespace for the application.
*/
window.app = {};
var app = window.app;
/**
* #constructor
* #extends {ol.interaction.Pointer}
*/
app.Drag = function() {
ol.interaction.Pointer.call(this, {
handleDownEvent: app.Drag.prototype.handleDownEvent,
handleDragEvent: app.Drag.prototype.handleDragEvent,
handleMoveEvent: app.Drag.prototype.handleMoveEvent,
handleUpEvent: app.Drag.prototype.handleUpEvent
});
/**
* #type {ol.Pixel}
* #private
*/
this.coordinate_ = null;
/**
* #type {string|undefined}
* #private
*/
this.cursor_ = 'pointer';
/**
* #type {ol.Feature}
* #private
*/
this.feature_ = null;
/**
* #type {string|undefined}
* #private
*/
this.previousCursor_ = undefined;
};
ol.inherits(app.Drag, ol.interaction.Pointer);
/**
* #param {ol.MapBrowserEvent} evt Map browser event.
* #return {boolean} `true` to start the drag sequence.
*/
app.Drag.prototype.handleDownEvent = function(evt) {
var map = evt.map;
var feature = map.forEachFeatureAtPixel(evt.pixel,
function(feature, layer) {
return feature;
});
if (feature) {
this.coordinate_ = evt.coordinate;
this.feature_ = feature;
}
return !!feature;
};
/**
* #param {ol.MapBrowserEvent} evt Map browser event.
*/
app.Drag.prototype.handleDragEvent = function(evt) {
var map = evt.map;
var feature = map.forEachFeatureAtPixel(evt.pixel,
function(feature, layer) {
return feature;
});
var deltaX = evt.coordinate[0] - this.coordinate_[0];
var deltaY = evt.coordinate[1] - this.coordinate_[1];
var geometry = /** #type {ol.geom.SimpleGeometry} */
(this.feature_.getGeometry());
geometry.translate(deltaX, deltaY);
this.coordinate_[0] = evt.coordinate[0];
this.coordinate_[1] = evt.coordinate[1];
};
/**
* #param {ol.MapBrowserEvent} evt Event.
*/
app.Drag.prototype.handleMoveEvent = function(evt) {
if (this.cursor_) {
var map = evt.map;
var feature = map.forEachFeatureAtPixel(evt.pixel,
function(feature, layer) {
return feature;
});
var element = evt.map.getTargetElement();
if (feature) {
if (element.style.cursor != this.cursor_) {
this.previousCursor_ = element.style.cursor;
element.style.cursor = this.cursor_;
}
} else if (this.previousCursor_ !== undefined) {
element.style.cursor = this.previousCursor_;
this.previousCursor_ = undefined;
}
}
};
/**
* #param {ol.MapBrowserEvent} evt Map browser event.
* #return {boolean} `false` to stop the drag sequence.
*/
app.Drag.prototype.handleUpEvent = function(evt) {
this.coordinate_ = null;
this.feature_ = null;
return false;
};
/*************** DRAG AND DROP EVENTS END *************/
You can ignore the drag and drop events above, because it works fine
var devices = [
{
'id' : 1,
'device' : 'cam',
'brand' : 'dahua',
'coordinates' : [0,0]
},
{
'id' : 2,
'device' : 'cam',
'brand' : 'vivotes',
'coordinates' : [0,1]
},
{
'id' : 3,
'device' : 'cam',
'brand' : 'dahua',
'coordinates' : [0, 2]
},
{
'id' : 4,
'device' : 'rack',
'brand' : 'dahua',
'coordinates' : [0, 3]
}
];
the code above is just an example of the resource that I want to display
var circle = [];
for (var i = 0; i < devices.length; i++) {
circle[i] = new ol.Feature(
new ol.geom.Circle(
ol.proj.transform(devices[i].coordinates, 'EPSG:4326', 'EPSG:3857'),//usar latitud, longitud, coord sys
30000
)
);
}
on var circle Im saving the coordinates and size for each marker.
var styles = [
new ol.style.Style({
image: new ol.style.Icon({ //#type {olx.style.IconOptions}
anchor: [0.5, 46],
anchorXUnits: 'fraction',
anchorYUnits: 'pixels',
opacity: 1,
population: 4000,
rainfall: 500
}),
fill: new ol.style.Fill({
color: [150, 150, 255, 1]
})
})
];
in styles im setting the color for all markers, but I want to change his values depending on the device type
// RENDER DEVICES
var objects = new ol.source.Vector({ features: circle })
var bullets = new ol.layer.Vector({
source : objects,
style: styles
});
above Im setting the markers and styles.
//layers-capaImagen, propiedades imagen principal
var extent = ol.proj.transformExtent([-50, 50, 50, -40], 'EPSG:4326', 'EPSG:3857');
var imgProjection = new ol.proj.Projection({
code: 'xkcd-image',
units: 'pixels',
extent: [0, 0, 1024, 968]
});
var capaImagen = new ol.layer.Image();
source = new ol.source.ImageStatic({
url: 'plano-vertical-knits.jpg',
imageExtent: extent,
projection: imgProjection,
center: ol.extent.getCenter(imgProjection.getExtent()),
extent: imgProjection.getExtent()
});
capaImagen.setSource(source);
//end propiedades imagen principal
//map features before render
var features = {
controls : ol.control.defaults({attribution : false}).extend([ new ol.control.FullScreen() ]),
interactions: ol.interaction.defaults().extend([new app.Drag()]),
layers : [capaImagen, bullets],
view: new ol.View({ center: [0, 0], zoom: 3 }),
target : 'map'
};
var map = new ol.Map(features);
above Im rendering the map with their features
// display popup on click
var pops = document.getElementById('popup');
var popupContent = document.getElementById('popup-content');
var popup = new ol.Overlay({/** #type {olx.OverlayOptions} */
element: pops,
autoPan: true,
stopEvent: false,
positioning: 'bottom-center',
autoPanAnimation: {
duration: 250
}
});
map.addOverlay(popup);
/* events ON map */
map.on('click', function(evt) {
var feature = map.forEachFeatureAtPixel(evt.pixel, function(feature, layer) {
return feature;
});
if (feature) {
var geometry = feature.getGeometry();
var firstCoord = geometry.getFirstCoordinate();
var lastCoord = geometry.getLastCoordinate();
popup.setPosition(firstCoord);
$(pops).popover({
'placement': 'top',
'html': true,
'content': feature.get('name')
});
//var latlong = ol.proj.transform([firstCoord, lastCoord], 'EPSG:4326', 'EPSG:3857');
popupContent.innerHTML = '<p>You clicked here:</p><p>'+lastCoord+'</p>';
$(pops).popover('show');
}
});
// change mouse cursor when over marker
map.on('pointermove', function(e) {
if (e.dragging) {
$('#popup-content').empty();
return;
}
});
/* events ON map END */
});
</script>
</body>
</html>
on click function Im trying to get the coordinates, and is where the coordinates shows me another values.
I extracted some of your codes and I added some modifications.
Style problem
Each feature needs to have a reference to the properties that you saved in array devices:
for (var i = 0; i < devices.length; i++) {
circle[i] = new ol.Feature(
{geometry: new ol.geom.Circle(
ol.proj.transform(devices[i].coordinates, ), 'EPSG:4326', 'EPSG:3857'),//usar latitud, longitud, coord sys
1
),
device: devices[i].device}
);
}
Additionally, it is necessary to set a different style for each desired property. Something like that should work:
var bullets = new ol.layer.Vector({
source: objects,
style: function (el, resolution) {//this is a style function
console.log(el, el.getProperties().device);
if (el.getProperties().device === 'cam')
return styles;
return styles2;
}
});
Problem with the coordinates
I think the problem in this case is due to the projection. You defined a custom projection (based on pixel) and applied it to the image. For the map view you don't define any projection (so it remains the default EPSG:3857). All the coordinates of the circle are converted from 'EPSG:4326' to 'EPSG:3857'. Therefore, the values that you see in the popup are in EPSG:3857 (not longitude and latitude). If you decide to continue to use EPSG:3857, you should also adapt the static image to this coordinates system via:
source = new ol.source.ImageStatic({
...............
imageExtent: .....
As you can find in the documentation imageExtent is the extent of the image in map coordinates. But in your code imageExtent is just the extent in pixel of the image.......

Categories