Openlayers - ol.source.Zoomify based layer is not displayed on top of another layer - openlayers-3

I have 2 images of different sizes (but tile size is the same). Images correspond to each other and I want to display them one on another the way that second image is upscaled to correspond first one.
I use ol.source.Zoomify source for both of them and projections with transformations. But I even can't get second image displaying.
See the the sample http://jsfiddle.net/sk5cLj4n/37/.
const imWidth = 31871;
const imHeight = 17770;
const imWidthSmall = 19122.6;
const imHeightSmall = 10662;
// Primary image projection
const primaryImageProjection = new ol.proj.Projection({
code: 'PIXELS',
units: 'pixels',
extent: [0,0, imWidth, imHeight],
getPointResolution: function (resolution, point) { return resolution; }
});
ol.proj.addProjection(primaryImageProjection);
// Overlay image projection
const overlayProjection = new ol.proj.Projection({
code: 'OVERLAY',
units: 'pixels',
extent: [0,0, imWidth, imHeight],
getPointResolution: function (resolution, point) { return resolution; }
});
ol.proj.addProjection(overlayProjection);
// Transformations of projections
function TransformOverlayToPixel(coordinate) {
console.log('TransformOverlayToPixel');
return [
(coordinate[0]),
(coordinate[1])
];
}
function TransformPixelToOverlay(coordinate) {
console.log('TransformPixelToOverlay');
return [
(coordinate[0]),
(coordinate[1])
];
}
ol.proj.addCoordinateTransforms('PIXELS', overlayProjection,
TransformPixelToOverlay,
TransformOverlayToPixel);
var map = new ol.Map({
layers: [
new ol.layer.Tile({
opacity: 0.8,
source: new ol.source.Zoomify({
size: [imWidth, imHeight], // temp
url: "http://207.154.205.4/testers_numbers_borders_resized_zoomify_256/primary/",
projection: 'PIXELS'
})
}),
new ol.layer.Tile({
opacity: 0.8,
source: new ol.source.Zoomify({
size: [imWidth, imHeight], // temp
url: "http://207.154.205.4/testers_numbers_borders_resized_zoomify_256/overlay/",
projection: 'OVERLAY'
})
})
],
target: 'map',
renderer: "canvas",
view: new ol.View({
projection: 'PIXELS',
center: [imWidth / 2, imHeight / 2],
zoom: 0
})
});
Short explanation of the fiddle:
tiles with blue borders are for primary layer
tiles with black borders are for secondary layer (overlay)
only 3 zoom levels are available for zooming
currently projections transformation does nothing. That's just for simplification. There should be a mupliplication to stretch second image.

Here how it's solved
http://jsfiddle.net/sk5cLj4n/41/
const imWidth = 31871;
const imHeight = 17770;
const imWidthSmall = 19122.6;
const imHeightSmall = 10662;
const koef = imWidth / imWidthSmall;
// Primary image projection
const primaryImageProjection = new ol.proj.Projection({
code: 'PIXELS',
units: 'pixels',
extent: [0, -imHeight, imWidth, 0],
getPointResolution: function (resolution, point) { return resolution; }
});
ol.proj.addProjection(primaryImageProjection);
// Overlay image projection
const overlayProjection = new ol.proj.Projection({
code: 'OVERLAY',
units: 'pixels',
extent: [0,-imHeight, imWidth, 0],
getPointResolution: function (resolution, point) { return resolution; }
});
ol.proj.addProjection(overlayProjection);
// Transformations of projections
function TransformOverlayToPixel(coordinate) {
console.log('TransformOverlayToPixel');
return [
(coordinate[0]) * koef,
(coordinate[1]) * koef
];
}
function TransformPixelToOverlay(coordinate) {
console.log('TransformPixelToOverlay');
return [
(coordinate[0]) / koef,
(coordinate[1]) / koef
];
}
ol.proj.addCoordinateTransforms('PIXELS', overlayProjection,
TransformPixelToOverlay,
TransformOverlayToPixel);
var map = new ol.Map({
layers: [
new ol.layer.Tile({
opacity: 0.8,
source: new ol.source.Zoomify({
size: [imWidth, imHeight], // temp
url: "http://207.154.205.4/testers_numbers_borders_resized_zoomify_256/primary/",
projection: 'PIXELS'
})
}),
new ol.layer.Tile({
opacity: 0.8,
source: new ol.source.Zoomify({
size: [imWidth, imHeight], // temp
url: "http://207.154.205.4/testers_numbers_borders_resized_zoomify_256/overlay/",
projection: 'OVERLAY'
})
})
],
target: 'map',
renderer: "canvas",
view: new ol.View({
projection: 'PIXELS',
center: [imWidth / 2, imHeight / 2],
zoom: 0
})
});
See how extent is specified. And also coefficient should be set properly to make images matching each other.

Related

URL parameters for Openlayers 3 to zoom to location?

I have an OL3 web application and I am wondering if it is possible to include URL parameters (such as coordinate values) for which the application can parse and open up at a specific location?
For example http://mywebsiteaddress?x=longitudevalue&y=latitudevalue
Is this something that can be done using OL3?
Sure, see: http://openlayers.org/en/latest/examples/permalink.html for an example (uses an anchor instead of url parameters but the idea is the same).
I did not like the openlayers permalink example because it uses map units and not well-known latitudes and longitudes. Sp I wrote my own code to hand over latlon coordinates, zoom and set a marker to it:
function getURLParameter(name) {
return decodeURIComponent((new RegExp('[?|&]' + name + '=' + '([^&;]+?)(&|#|;|$)').exec(location.search) || [null, ''])[1].replace(/\+/g, '%20')) || null;
}
var mzoom=12;
var mlat = Number(getURLParameter('mlat'));
var mlon = Number(getURLParameter('mlon'));
var mzoom = Number(getURLParameter('zoom'));
var marker = 1
if (mlat == 0 || mlon == 0) {
mlat = 51.5; mlon = 7.0; mzoom=12; marker=0 //Default location
}
if (mzoom == 0 ) { mzoom=12 //Default zoom
}
var container = document.getElementById('popup');
var content = document.getElementById('popup-content');
var closer = document.getElementById('popup-closer');
closer.onclick = function() {
container.style.display = 'none';
closer.blur();
return false;
};
var overlayPopup = new ol.Overlay({
element: container
});
var expandedAttribution = new ol.control.Attribution({
collapsible: false
});
var map = new ol.Map({
controls: ol.control.defaults({attribution:false}).extend([
expandedAttribution
]),
target: document.getElementById('map'),
renderer: 'canvas',
overlays: [overlayPopup],
layers: layersList,
view: new ol.View({
center: ol.proj.fromLonLat([mlon, mlat]),
zoom: mzoom,
maxZoom: 18, minZoom: 8
})
});
if (marker == 1) {
var vectorLayer = new ol.layer.Vector({
source:new ol.source.Vector({
features: [new ol.Feature({
geometry: new ol.geom.Point(ol.proj.transform([parseFloat(mlon), parseFloat(mlat)], 'EPSG:4326', 'EPSG:3857')),
})]
}),
style: new ol.style.Style({
image: new ol.style.Icon({
anchor: [0.5, 0.5],
anchorXUnits: "fraction",
anchorYUnits: "fraction",
src: "marker.svg"
})
})
});
map.addLayer(vectorLayer);
}
I used the output of the qgis2web plugin and modified the file qgis2web.js as above.

Openlayers 3: Drawing grid lines (graticule) with predefined units on the custom static image

I am trying to draw custom x-y axes grid lines on top of a static image, i.e. image pixels rather than lattitude and longitudes. Ideally, the grid lines should be redrawn dynamically when I drag/zoom/scroll the image, just like the x-y ruler bars in Photoshop.
I came across the following code example, which provides a custom projection function to directly map image pixel coordinates to map coordinates.
http://openlayers.org/en/latest/examples/static-image.html
// Map views always need a projection. Here we just want to map image
// coordinates directly to map coordinates, so we create a projection that uses
// the image extent in pixels.
var extent = [0, 0, 1024, 968];
var projection = new ol.proj.Projection({
code: 'xkcd-image',
units: 'pixels',
extent: extent
});
I tried to append the following code to the script. However, the ol.Graticule class seems to be incompatible with the custom ol.proj.Projection definition.
http://openlayers.org/en/latest/examples/graticule.html
// Create the graticule component
var graticule = new ol.Graticule({
// the style to use for the lines, optional.
strokeStyle: new ol.style.Stroke({
color: 'rgba(255,120,0,0.9)',
width: 2,
lineDash: [0.5, 4]
})
});
graticule.setMap(map);
What's wrong with the above code?
P.S. I am aware of the Openseadragon API which provides a dynamic scalebar. However, I wish to stick to Openlayers API because I also have an extra map layer of anchor points at predefined locations on the static image.
I had the same problem. For this to work I created a Vector Layer, (where axis are drawn).
To draw the axis, I need to listen to View changes.
Whenever the view changes, calculate the actual extent for the view.
With extent information and ([width, height] of the image, you can then draw axis)
let listenerAxis = null,
w = 0,
h = 0
const xAxisStyle = new ol.style.Style({
stroke: new ol.style.Stroke({
color: 'red',
width: 2
})
})
const yAxisStyle = new ol.style.Style({
stroke: new ol.style.Stroke({
color: 'green',
width: 2
})
})
const ImageLayer = new ol.layer.Image()
const AxisLayer = new ol.layer.Vector({ source: new ol.source.Vector() })
AxisLayer.setStyle((feature, resolution) => {
if(feature.getProperties().axis == 'x') {
return xAxisStyle
}
return yAxisStyle
})
const renderer = new ol.Map({
target: 'map',
layers: [ImageLayer]
})
AxisLayer.setMap(renderer)
processFile('https://i2.wp.com/beebom.com/wp-content/uploads/2016/01/Reverse-Image-Search-Engines-Apps-And-Its-Uses-2016.jpg?resize=640%2C426')
function removeAxis() {
AxisLayer.getSource().clear()
ol.Observable.unByKey(listenerAxis)
listenerAxis = null
}
function drawAxis() {
function draw(){
AxisLayer.getSource().clear()
const extent = renderer.getView().calculateExtent()
const [xmin, ymin, xmax, ymax] = extent
// Eje X
const axisX = new ol.geom.LineString([ [xmin, h / 2], [xmax, h / 2] ])
const axisY = new ol.geom.LineString([ [w / 2, ymin], [w / 2, ymax] ])
const featureX = new ol.Feature({ geometry: axisX, axis: 'x' })
const featureY = new ol.Feature({ geometry: axisY, axis: 'y' })
AxisLayer.getSource().addFeatures([featureX, featureY])
}
listenerAxis = renderer.getView().on('change', draw)
draw()
}
async function processFile(path) {
ImageLayer.setSource()
removeAxis()
if(!path) {
return
}
const [wi, hi] = await readImage(path)
w = wi
h = hi
const source = getImageStatic(path, w, h)
const view = getViewForImage(w, h)
ImageLayer.setSource(source)
renderer.setView(view)
drawAxis()
}
// Some helpers
function readImage(localPath) {
const img = document.createElement('img')
return new Promise((res, rej) => {
img.src = localPath
img.addEventListener('load', (event) => {
const { naturalWidth, naturalHeight } = img
console.log('img', naturalWidth, naturalHeight)
res([naturalWidth, naturalHeight])
})
})
}
function getViewForImage(w, h) {
return new ol.View({
center: [w / 2, h / 2],
zoom: 2,
projection: new ol.proj.Projection({
extent: [0, 0, w, h],
units: 'pixels'
}),
extent: [0, 0, w, h]
})
}
function getImageStatic(path, w, h) {
return new ol.source.ImageStatic({
url: path,
imageExtent: [0, 0, w, h]
})
}
#map {
width: 100%;
height: 100%;
background: grey;
}
<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.js"></script>
<div id="map"></div>

setCenter always ends near southpole

I'm new at OpenLayers3 and trying to build a simple form that centers my map to a given spot. The problem is that i'm always landing somwhere near the south-pole. here is my code:
var map = new ol.Map({
target: 'map',
layers: [
new ol.layer.Tile({
source: new ol.source.OSM
})
],
view: new ol.View({
center: [0,0],
zoom: 8
})
search.addEventListener("change", searchChanged);
function searchChanged()
{
var searchVal = encodeURIComponent(search.value);
var geocode = 'http://open.mapquestapi.com/nominatim/v1/search.php?key=KEY&format=json&q=' + searchVal;
$.getJSON(geocode, function(data)
{
if(!data)
{
return;
}
map.getView().setCenter(ol.proj.transform([data[0].lon, data[0].lat], 'EPSG:4326', 'EPSG:3857'));
}
);
}
Make sure your coordinate will not be treated as string:
ol.proj.transform([parseFloat(data[0].lon), parseFloat(data[0].lat]), 'EPSG:4326', 'EPSG:3857')
Better, debug it:
var coord = ol.proj.transform([parseFloat(data[0].lon), parseFloat(data[0].lat]), 'EPSG:4326', 'EPSG:3857');
console.info(coord);

How to transform MapTile image to to view

I've created a tile set of an image using MapTiler. MapTiler generates a OL 2 script that centers the tiled image in the viewing window with the following code:
var map, layer;
var mapBounds = new OpenLayers.Bounds(0.000000, -9350.000000, 14450.000000, 0.000000);
var mapMinZoom = 0;
var mapMaxZoom = 6;
var mapMaxResolution = 1.000000;
var gridBounds = new OpenLayers.Bounds(0.000000, -9350.000000, 14450.000000, 0.000000);
function init() {
var options = {
controls: [],
maxExtent : gridBounds,
minResolution: mapMaxResolution,
numZoomLevels: mapMaxZoom+1
};
map = new OpenLayers.Map('map', options);
layer = new OpenLayers.Layer.XYZ( "MapTiler layer", "${z}/${x}/${y}.png", {
transitionEffect: 'resize',
tileSize: new OpenLayers.Size(256, 256),
tileOrigin: new OpenLayers.LonLat(gridBounds.left, gridBounds.top)
});
map.addLayer(layer);
map.zoomToExtent(mapBounds);
I want to use OL3 to display the tiled map but do not know how to implement equivalent OL3 methods to achieve this. Using the following script I can display the tiled image but I cannot figure out how to center the tiles to in the view.
map = new ol.Map({
target: 'map',
layers: [
new ol.layer.Tile({
source: new ol.source.OSM({
url: map_path + '{z}/{x}/{y}.png'
})
})
],
view: new ol.View({
center: [0, 0],
zoom: 2
})
});
I've inspected the map extent which turns out to be:
-20037508.342789244,-20037508.342789244,20037508.342789244,20037508.342789244
My tiled image extent is given in the OL2 code, but I don't known how to use this information in OL3. I think it might have something to do with a transformation or fitExtent but without further direction, it seems I'm just guessing at what to do.
You will have to create a pixel projection for this to work properly. Then you can use fit (replacement for the former fitExtent), as you already suspected, to zoom to the full extent of the image.
The whole OpenLayers 2 code translated to OpenLayers 3 would look like this:
var mapBounds = [0.000000, -9350.000000, 14450.000000, 0.000000];
var mapMaxZoom = 6;
var gridBounds = [0.000000, -9350.000000, 14450.000000, 0.000000];
var projection = new ol.proj.Projection({
code: 'pixels',
units: 'pixels',
extent: gridBounds
});
var map = new ol.Map({
target: 'map',
view: new ol.View({
extent: mapBounds,
projection: projection
})
});
var layer = new ol.layer.Tile({
source: new ol.source.XYZ({
url: '{z}/{x}/{y}.png',
projection: projection,
maxZoom: mapMaxZoom
})
});
map.addLayer(layer);
map.getView().fit(mapBounds, map.getSize());

Load local zoomify tileset in OL3

I produced a zoomify tileset from some digitized map image and would now like to use OL3 to display that map on a Website. However, my script currently fails loading that map from a local file uri (later, in production, I will upload the tiles on some Web Server and reference the tiles using HTTP). Here is what I have so far:
var url = 'file:///home/user/map_zoomfiy/';
var imgWidth = 17244;
var imgHeight = 9684;
var imgCenter = [imgWidth / 2, - imgHeight / 2];
var proj = new ol.proj.Projection({
code: 'ZOOMIFY',
units: 'pixels',
extend: [0, 0, imgWidth, imgHeight]
});
var source = new ol.source.Zoomify({
url: url,
size: [imgWidth, imgHeight],
crossOrigin: 'anonymous'
});
var map = new ol.Map({
target: 'map',
layers: [
new ol.layer.Tile({
source: source
})
],
view: new ol.View({
projection: proj,
center: imgCenter,
zoom: 1
})
});
</script>
Any ideas why this fails? Thx.
It's not right way e.g https://developer.mozilla.org/en-US/docs/WebGuide/API/File_System/Introduction#file
I don't see why you do not make a local server instead of fighting to access your file with local url.
Some times ago, I compiled some recipes to do so.
Open your command line, go to your code root dir and follow recipes depending of your favorite programming language.
If the tiles are in a subdirectory (e.g., tiles_zoomify) the following should work
var url = 'tiles_zoomify/';
var imgWidth = 17244;
var imgHeight = 9684;
var imgCenter = [imgWidth / 2, - imgHeight / 2];
var proj = new ol.proj.Projection({
code: 'ZOOMIFY',
units: 'pixels',
extend: [0, 0, imgWidth, imgHeight]
});
var source = new ol.source.Zoomify({
url: url,
size: [imgWidth, imgHeight],
crossOrigin: 'anonymous'
});
var map = new ol.Map({
target: 'map',
layers: [
new ol.layer.Tile({
source: source
})
],
view: new ol.View({
projection: proj,
center: imgCenter,
zoom: 1
})
});

Resources