Automagically center a Zoomify image - html

I am a newbie when it comes to programming and I was hoping y'all could help me. I am trying to automatically center a Zoomify image created through VIPS.
Unfortunately I am having a hard finding out how to center an image. If I use the example from openlayers . org
http://openlayers.org/en/v3.3.0/examples/zoomify.js
I end up centering in a weird way.
Is there anything I am doing wrong or a way I can automatically center the image and zoom that is based on varying image sizes?
Here is a snippet of the code I am using and funny center to make it half passable (but not robust: center: [-20000000,20000000])
var imgWidth = 41056;
var imgHeight = 16168;
var imgCenter = [imgWidth / 2, imgHeight / 2];
// Maps always need a projection, but layers are not geo-referenced, and
// are only measured in pixels. So, we create a fake projection that the map
// can use to properly display the layer.
var proj = new ol.proj.Projection({
code: 'pixel',
units: 'pixels',
extent: [0, 0, imgWidth, imgHeight]
});
var source = new ol.source.XYZ({
url: 'Zoomify_Image/1/{z}/{y}/{x}.jpg'
});
var map = new ol.Map({
target: 'map',
layers: [
new ol.layer.Tile({
source: source,
wrapX: false,
projection: proj
}),
new ol.layer.Tile({
source: new ol.source.TileDebug({tileGrid: new ol.tilegrid.XYZ({})}),
wrapX: false,
projection: proj
})
],
//renderer: exampleNS.getRendererFromQueryString(),
view: new ol.View({
projection: proj,
center: [-20000000,20000000],
zoom: 0
})
});

Your data structure does not follow the Zoomify specification, which demands URLs in '/TileGroup{g}/{z}-{x}-{y}.jpg' format. Your URL format, 'Zoomify_Image/1/{z}/{y}/{x}.jpg' is quite a bit different from that, and I guess this is why you are using ol.source.XYZ instead of ol.source.Zoomify.
To fix your code, you will have to use ol.source.TileImage instead of ol.source.XYZ, because ol.source.XYZ currently only supports the EPSG:3857 projection. Assuming you have 7 zoom levels and your directory structure otherwise follows the Zoomify standard, but does not use clipped tiles at the boundaries of the image, your source definition could look something like this:
var source = new ol.source.TileImage({
projection: proj,
tileUrlFunction: function(tileCoord, pixelRatio, projection) {
return url + 'Zoomify_Image/1/' + tileCoord[0] + '-' + tileCoord[1] +
'-' + (-tileCoord[2] - 1) + '.jpg';
},
tileGrid: new ol.tilegrid.Zoomify({
resolutions: [1, 2, 4, 8, 16, 32, 64].reverse()
})
});
Your Tile layer definition would look like this:
new ol.layer.Tile({
extent: [0, -imgHeight, imgWidth, 0],
source: source
})
And finally, your View definition would look like this:
new ol.View({
projection: proj,
center: imgCenter,
zoom: 0,
extent: [0, -imgHeight, imgWidth, 0]
})
If you have tiles that are not 256x256 pixels at the image boundaries, then this approach will not work correctly - the clipped tiles will not be displayed. In this case you should change your Zoomify_Image/ directory structure to match the Zoomify standard and use ol.source.Zoomify, which supports clipped tiles.

Related

OpenLayers 3 Style Function for dynamic feature font setting

I am using php and mySQL to generate javascript for the vector layers and features. All is functionally working except I need to be able to control the feature text with zoom, which from my searches requires the use of a style function.
My issue is how/where do I create a function to set what is currently fixed as "font: 140/10 + 'px arial' " tied to the map zoom setting ?
My current design uses a php loop using the database to create the features with unique location and properties:
1) create the feature
2) set the style
3) push into the array iconFeatures0
var iconFeature = new ol.Feature({
geometry: new ol.geom.Point(ol.proj.transform([-0.163741,51.507847], 'EPSG:4326', 'EPSG:3857')),
p_title: 'Hyde Park Title',
p_line1: 'Hyde Park',
p_line2: 'Park information ...',
lat: 51.507847,
long: -0.163741,
});
iconFeature.setStyle(
new ol.style.Style({
image: new ol.style.Icon(({
anchor: [0.5, 1.0],
anchorXUnits: 'fraction',
anchorYUnits: 'fraction',
opacity: 0.85,
src: 'test_map/marker_0.png',
size: [52,64],
scale:0.5,
})),
text: new ol.style.Text({
text: 'Hyde Park',
offsetY: -37.5,
fill: new ol.style.Fill({
color: '#FF3300'
}),
font: 140/10 + 'px arial'
})
}),
);
iconFeatures0.push(iconFeature);
//On completion of the loop:
var vectorSource0 = new ol.source.Vector({
features: iconFeatures0
});
vectorLayer0 = new ol.layer.Vector({
source: vectorSource0
});
//setting up the map
var myOSMLayer = new ol.layer.Tile({
source: new ol.source.OSM()
});
// Create latitude and longitude and convert them to default projection
var myMapcentre = ol.proj.transform([-0.140180,51.501811], 'EPSG:4326', 'EPSG:3857'); //$long,$lat
var myMapView = new ol.View({
center: myMapcentre,
zoom: 14
})
var myMap = new ol.Map({
controls: ol.control.defaults().extend([
new ol.control.FullScreen()
]),
layers: [myOSMLayer, vectorLayer0],
loadTilesWhileInteracting: true,
target: document.getElementById('demoMap1'),
view: myMapView
});
Thanks in advance.
There are several ways to accomplish this, here is one of them.
First, it would be more efficient if you prepare the styles and simply apply them at different scale, so OpenLayers doesn't have to re-create the styles each time the zoom changes.
Then, instead of styling each feature individually, you would style the entire layer (you can still discriminate by feature "category" within the layer).
At last, you would benefit from the the option to consider the resolution when styling the layer:
vectorLayer0.setStyle(function(feature, resolution) {
return [new ol.style.Style({
text: new ol.style.Text({
font: resolution/1000+'px Calibri,sans-serif',
text: "test",
fill: fill
})
})];
});
You would remove the code iconFeature.setStyle( ... from your code and put the above code after having created vectorLayer0

Trouble to set coordinates in OpenLayers when using Long and Lat from GoogleMaps

Here is the coordinates of Tehran on Google Maps.
https://www.google.com/maps/place/Tehran/#35.6964895,51.0696315,10z/data=!3m1!4b1!4m2!3m1!1s0x3f8e00491ff3dcd9:0xf0b3697c567024bc
35.6961° N, 51.4231° E
I'm trying to find this coordinate in OpenLayers but I had no luck, here is my code:
map = new ol.Map({
target: 'sample-map',
layers: [
new ol.layer.Tile({
source: new ol.source.OSM()
})
],
view: new ol.View({
center: [35.6961, 51.4231],
zoom: 4
})
});
I'm also trying to get current coordinates in degrees but I don't know how.
I'm not entirely sure what is the problem, but I can say this: you need to swap your parameters on center to [51.4231, 35.6961].
According to the Openlayers documentation the center is in the format [x-axis, y-axis] or in your case [East, North].
In your specific case your source projection is NOT lat/long so you have to convert. The following code should work for you:
map = new ol.Map({
target: 'sample-map',
layers: [ new ol.layer.Tile({
source: new ol.source.OSM()
})],
view: new ol.View({
center: ol.proj.transform([51.4231, 35.6961], 'EPSG:4326', new ol.source.OSM().getProjection()),
zoom: 10
})
});

How to prevent repeating content across all worlds

I am using KML layers in Google Maps. And when I load a layer into a map, it shows up in every world as far as you keep horizontally scrolling. For layers with content on a quite small area that doesn't pose a problem, as the map will automatically zoom to show only the relevant content from the layer. But for layers that show markers across the whole world, having them repeat again on the next world, it looks like a bunch of gibberish.
Take for example this sample code from Google Maps, but with a layer of Holocene volcanoes instead of their layer provided by default. If you want to see all of them, you see more than all of them, and you have no reference for when you've come to the place where they are repeating the ones you've already looked at.
Example: http://jsfiddle.net/eppptn2x/
Code:
var map;
var elevator;
var myOptions = {
zoom: 2,
center: new google.maps.LatLng(10, 0)
};
map = new google.maps.Map(document.getElementById('map'), myOptions);
var markers = [];
var georssLayer = new google.maps.KmlLayer({
url: 'http://www.volcano.si.edu/ge/GVPWorldVolcanoes.kml'
});
georssLayer.setMap(map);
How do I prevent this behavior? How do I make all layer content, and any markers, be limited to only one world?
I hope I understood your question. Try entering a value for minZOom in mapOptions like this:
var myOptions = {
zoom: 2,
minZoom:2,
center: new google.maps.LatLng(10, 0)
};
I know it's too late but may be it would be useful for someone.
To prevent repeating markers you can set optimized option to false
var marker = new google.maps.Marker({
position: myLatLng,
map: map,
title: 'Hello World!',
optimized: false
});
You can find related topic here.

OSM (Open Street Map) help for a newbie

I have a couple of issues:
I am trying to add my own marker to a map, but it does not seem to work.
Also when I try to refer the OpenLayer.js file locally the default red marker disappears.
I have found some examples on the net, but they have been unsuccessful I am afraid. So I thought to ask for some help here.
Now my code looks like this:
<div id="Map" style="height: 250px; width: 400px" ></div>
<script src="http://www.openlayers.org/api/OpenLayers.js"></script>
<%--<script src="js/osm/api/OpenLayers.js"></script>--%>
<script>
var lat = 55.676098;
var lon = 12.568337;
var zoom = 11;
var fromProjection = new OpenLayers.Projection("EPSG:4326"); // Transform from WGS 1984
var toProjection = new OpenLayers.Projection("EPSG:900913"); // to Spherical Mercator Projection
var position = new OpenLayers.LonLat(lon, lat).transform(fromProjection, toProjection);
map = new OpenLayers.Map("Map");
var mapnik = new OpenLayers.Layer.OSM();
map.addLayer(mapnik);
var markers = new OpenLayers.Layer.Markers("Markers");//("Images/Icons/map-marker.png");
map.addLayer(markers);
markers.addMarker(new OpenLayers.Marker(position));
map.setCenter(position, zoom);
</script>
and as you can see I have tried to refer to my own marker from 'Images/Icons/map-marker.png' without any luck.
Also you can see that I have tried to use a local copy of the 'OpenLayers.js', I don't know whether I should have it locally or always refer to 'www.openlayers.org', I believe referring local is good enough?
Also as I wrote earlier, if I refer the local .js file, the red marker, the zoom buttons and the OSM link disappears.
Can anyone help me out?
(You are actually asking a question about OpenLayers, not OpenStreetMap)
The OpenLayers Marker documentation provides an example for a custom marker icon. You have to create a OpenLayers.Icon object:
var size = new OpenLayers.Size(32,32);
var offset = new OpenLayers.Pixel(-(size.w/2), -size.h);
var icon = new OpenLayers.Icon("Images/Icons/map-marker.png", size, offset);
markers.addMarker(new OpenLayers.Marker(position, icon));
Where did you get your local OpenLayers.js copy from? It might be outdated if it doesn't work compared to the one version. And that's usually the reason why you want to keep a local copy of your libraries, because they won't change to a newer version automatically.
You should also make sure that the example you got from the web is up to date. Ideally you use one of the official OpenLayers examples.
Instead of OpenLayers you can also give the more modern and easier to use LeafLet library a try.
I found this at http://wiki.openstreetmap.org/wiki/Marker_API:
marker = new khtml.maplib.overlay.Marker({
position: new khtml.maplib.LatLng(0, 0),
icon: {
url: "http://maps.gstatic.com/intl/de_de/mapfiles/ms/micons/red-pushpin.png",
size: {width: 26, height: 32},
origin: {x: 0, y: 0},
anchor: {
x: "-10px",
y: "-32px"
}
},
shadow: {
url: "http://maps.gstatic.com/intl/de_de/mapfiles/ms/micons/pushpin_shadow.png",
size: {
width: "40px",
height: "32px"
},
origin: {x: 0, y: 0},
anchor: {x: 0, y: -32 }
},
draggable: true,
title: "moveable marker"
});

JQuery slider does not move when used with Google Fusion Table

I have a little problem regarding to JQuery Slider and Google Fusion Table.
This is a Google Map application. I have several locations stored in the Fusion Table, and they will be displayed on the map during the map initialization. Of course, this is not that interesting so I want to add a JQuery Slider so that the locations appeared on the map can dynamically change when user interacts with slider, by setting the event callback function. However, the slider does not move, even with the following piece of code, which should be very straightforward.
All I did is initializing the map and slider. There are two lines in the slider's callback function, the first one displays on the webpage the current value of slider, ranging from 0 to 100; the second one queries the fusion table again to reflect the updated data (here I just simplified the query so that it just selects all the entries and sends them back, so the data displayed on the map will not change even if one interacts with the slider).
In Chrome, what I got is the map initialized successfully, with all the data points shown. However, when I tried to move slider, it just stays there, but the value of the slider (what line 1 shows) does change. However, if I comment out line 2, everything is fine, the slider can move freely, though not sending any query...
Does anyone have any experience about using Maps, fusion table and JQuery slider at the same time? Any suggestion is appreciated.
Below is the code:
// initialize map
function initialize() {
var place = new google.maps.LatLng(30, -120);
map = new google.maps.Map(document.getElementById('map_canvas'), {
center: place,
zoom: 4,
mapTypeId: 'terrain'
});
var layer = new google.maps.FusionTablesLayer('132848');
layer.setMap(map);
}
// define the JQuery Slider
$(function(){
$('#slider').slider({
max: 100,
min: 0,
step: 1,
value: 0,
slide: function(event, ui) {
document.getElementById("slider-value").innerHTML = ui.value + " mi";// line 1
layer.setQuery('select Location from 132848');// line 2
}
});
});
As Eric already pointed out, layer must be in the global scope, so that the slider is able to access it. I slightly change your code, because I think it's easier to understand and read when using the layer.setOptions() syntax, but that's just a matter of taste. I used the slider filter for the distance field, change it to anything you like :-)
Here is a demo of my adapted code: http://jsfiddle.net/odi86/kb4TV/
var layer;
var tableId = '132848';
var map;
// initialize map
function initialize() {
var place = new google.maps.LatLng(30, -120);
map = new google.maps.Map(document.getElementById('map-canvas'), {
center: place,
zoom: 4,
mapTypeId: 'terrain'
});
layer = new google.maps.FusionTablesLayer({
query: {
select: "Location",
from: tableId
},
map: map
});
}
// define the JQuery Slider
$(function() {
$('#slider').slider({
max: 100,
min: 0,
step: 1,
value: 0,
slide: function(event, ui) {
document.getElementById("slider-value").innerHTML = ui.value + " mi";
layer.setOptions({
query: {
select: "Location",
from: tableId,
where: "distance <= " + ui.value
}
});
}
});
});​