I am building a image tiles based map using openlayer where I changed the projection to a custom one instead of default EPSG. I need the scale to show the correct scale according to my distance to pixel ratio and also need the measurements according to that scale.
I changed metersPerUnit
to match my need for scale but it seems to depend on the extents.
1. How exactly is extent used to in scale?
2. I can see the scale value change when moved vertically on my map which should not be the case since its a flat projection. (I have the global
set as true
which I assumed should have fixed that. Am I understanding something wrong about global
?
Measurements are still very different even after changing metersPerUnit
which I guess is because I need to change the getPointResolution
function also? But I added which does not seem to be working correctly. Measurements are still different.
getPointResolution = (projection, resolution, point, opt_units) => {
var pointResolution = resolution;
pointResolution /= projection.getMetersPerUnit();
return pointResolution;
};
proj = new Projection({
code: 'ZOOMIFY',
units: 'pixels',
extent: [0, 0, imgWidth, imgHeight],
metersPerUnit: (constant_micronsperpixel * 0.000001 / imgWidth),
global: true,
getPointResolution: getPointProjection
});
Another thing was, I needed to use imgWidth
in metersPerUnit
to correct the scale which seems to be a hack or I do not quite understand how extent is used for scale calculation. And whats really the difference between extent
and globalExtent
Update: 27 May
I managed to figure some things.Extents are not needed for scale. Fixing the resolutions and implementing the correct getPointResolution
for view ensure the measurements are correct along with scale. This also fixed my changing scale on moving vertically.
However, the View does not query for images now. Any idea why?
Updated Code
this.getPointResolution = (resolution, point) => {
var pointResolution = resolution;
return pointResolution;
}
this.proj = new Projection({
code: 'MORPHLE',
units: 'm',
metersPerUnit: 0.000001,
global: true,
getPointResolution: this.getPointResolution,
});
this.resolutions = [this.props.slide_data.uperpixel * 128,this.props.slide_data.uperpixel * 64,this.props.slide_data.uperpixel * 32, this.props.slide_data.uperpixel * 16, this.props.slide_data.uperpixel * 8, this.props.slide_data.uperpixel * 4, this.props.slide_data.uperpixel*2, this.props.slide_data.uperpixel];
this.viewer = new Map({
controls: [],
target: null,
overlays: [this.popup],
layers: [
new TileLayer({
source: new XYZ({
url: this.props.url,
maxZoom: this.props.max_zoom - 1,
minZoom: 0,
wrapX: false,
tileSize: [500, 500],
projection: this.proj
}),
minResolution: (this.props.slide_data.uperpixel),
maxResolution: (this.props.slide_data.uperpixel * 128)
})
],
view: new View({
projection: this.proj,
center: this.state.center,
resolutions: this.resolutions,
minZoom: 0,
zoom: this.state.zoom,
rotation: this.slideAngle
})
});
Images are not being queried though now as I see in Network Tab
of browser.
After a lot of playing around, I solved my problem. Here are some insights that I learnt and are missing/hard to understand in documentation:
imgHeight
and imgWidth
needs to be the size of full resolution image i.e. in the most zoomed level X-images * Tile-X-Width and Y-Images * Tile-Y-Width.TileGrid
define the image url query where as resolutions in View
only define the view resolutions. If they match(at some zooms), then images will be queries else the zoom will only be digital in nature.So, if someone wants to use a deep zoom using OpenLayer with custom projection and resolutions along with correct projection and measurements- The following would be the code:
this.imgWidth = this.stitched_tile_width * this.x_max;
this.imgHeight = this.tile_height * this.y_max;
this.resolutions = [];
let z_levels = this.props.slide_data.z_levels.split(",");
(z_levels).forEach((level, index) => {
this.resolutions.push(this.distperpixel * Math.pow(2, parseInt(level)));
});
this.resolutions = this.resolutions.reverse();
this.getPointResolution = (resolution, point) => {
var pointResolution = resolution;
return pointResolution;
}
this.proj = new Projection({
code: 'CUSTOM',
units: 'pixels',
extent: [0, 0, this.imgWidth, this.imgHeight],
metersPerUnit: 0.000001,
global: true,
getPointResolution: this.getPointResolution,
});
this.layer = new TileLayer({
extent: this.proj.getExtent(),
source: new TileImage({
tileGrid: new TileGrid({
extent: this.proj.getExtent(),
origin: [0, this.imgHeight],
resolutions: this.resolutions,
tileSize: [this.tile_width, this.tile_height],
}),
projection: this.proj,
url: this.props.url,
wrapX: false
}),
});
this.viewer = new Map({
layers: [
this.layer
],
view: new View({
projection: this.proj,
extent: this.proj.getExtent(),
center: this.state.center,
zoom: starting_zoom,
maxResolution: this.resolutions[0],
maxZoom: (this.resolutions.length - 1),
rotation: this.slideAngle
})
});