How to implement a dynamic map in your web page FINN.no

How to implement a dynamic
map in your web page
(without marrying a vendor)
Lessons learned while upgrading
FINN.no
Henning Spjelkavik
JavaZone 2008
- Javazone 2008
Agenda
The history
Why?
How does it work?
How!
Source: Sesam / Norkart AS
In the beginning was...
...the sketch
FINN.no - bolig i utlandet
Where is it exactly?
Affordable
Overview
Don’t book a beach hotel...
Bergfex.at
...then we got the maps right
Complicated GUI code
Custom integration with a
map server
Response times / scalability
Map data costs (licensing)
are a barrier
Gule Sider uses 10 million
NOK yearly on licenses for
map data
(Computer World 2008-04-18,
http://www.idg.no/nyheter/article95167.ece )
...and at last (2004) – slippy maps
map.search.ch is completely
Javascript driven, there are no
Java or Flash components.
http://www.bernhardseefeld.ch/archives/000099.html
9th October 2004
...and at last (2004) – slippy maps
map.search.ch is completely
Javascript driven, there are no
Java or Flash components.
http://www.bernhardseefeld.ch/archives/000099.html
9th October 2004
The company, Endoxon, was bought by Google in 2006
Marry your vendor?
Client – how to display the map
Map server – custom data and API
Advantages
One vendor – consistent
One contact point
(support, development, complaints)
Changing is probably expensive
ArcGIS Server 9.3 delivers the full
stack
”Complete and integrated ServerBased GIS”
http://www.esri.com/software/arcgis/arcgisserver/
Why Open Source (Mapping)?
Build yourself, buy or use open source
Philosophy, principles, cost or best value?
Vendor policies may change
Competitive edge, competitors
Use your resources wisely
The technology:
How does it work?
Map client and map server
Not necessarily:
one-to-one mapping –
data
client
Example
NASA Blue Marble
Daily meteo-data from
GlobalSod (US NOAA)
ka-map client
http://clima.ominiverdi.org/ka-map/htdocs/
Map data
Free (beer) stacks by Microsoft,Google++
Check out the current terms of use;
Verify that they fit your organisation
MICROSOFT® VIRTUAL EARTH™
PLATFORM API TERMS OF USE
Google Maps API Terms of Service
From a local vendor (Norkart, Geodata,
Ugland IT, MapSolutions, ++)
Your own data
Buy vector data and publishing rights
Free data (Open Street Map, N5000,
Vmap0)
N5000 – Statens Kartverk, 2002
FINN.no – maps anno 2006
Quite good maps of Norway
FINN reise
International maps – based on GPS
navigation data
Maintaining a client
New integration points
Map Client
Buy, build or reuse
Browser support
Maintenance costs
Open standards
HTML, Javascript, Flash?
Google, Microsoft, Yahoo
ka-map
OpenLayers
hitta.se
Visualising map data
Vector data
Raw TIFF files
On demand or tile sets?
Some Map Servers
ESRI ArcGIS Server
UMN MapServer (Open)
Geoserver (Open)
Traditional architecture
Generate one map pr request
Seamless scale
Map extent can match the request exactly
Scalability?
Traditional system
How many requests pr second can we handle?
(with a decent response time)
Let’s assume 1000ms pr
request.
If each server can handle 2
parallell requests.
2 requests pr second
< 180 000 requests pr day
”Slippy” map – tile based
Layers in map.search.ch
Coordinates, projections and math
Example - Coordinate systems
How can these be pointing
to the same place?
6648970 N
255101 E
EPSG:32633
59.90530 N 10.61976 E EPSG:4326
8378684 N
1182185 E
900913
Ask for the coordinate
reference system!
http://spatialreference.org
”What can go wrong”
Utm33 as Mercator
Inverted axis (utm33) in
(mercator)
Beware! Axis Order Confusion
Mathematical
Axis Order (X,Y)
Positive axis to the right, and upward
Computer Graphics
Axis Order (X,Y)
Unsigned values increase to the bottom and to the right.
Geographical Coordinate Systems
Axis Order varies, sometimes (Y,X), other times (X,Y)
Signed values increase right and up limited to -180, -90, 180,
90 (a spheroid)
Also in common speak ”latlon” or ”lonlat”?!
Coordinate reference system
= CRS
1. Ocean
2. Ellipsoid
3. Local plumb line
4. Continent
5. Geoid
Source: Wikipedia
Geoid
”It is often described as the true physical figure of the Earth, in contrast to
the idealized geometrical figure of a reference ellipsoid. “
Reference Ellipsoid
a reference ellipsoid is a mathematically-defined surface that
approximates the geoid
Geographical CRS
Reference ellipsoid
(/spheroid)
+ coordinate frame
(Where is 0 degrees?)
=> Datum
Unit: Degrees
Projected CRS
A projection applied
to a geographical
CRS
Unit: Meter
Enables Pythagorean
Distance calculation
6650959 N, 253062 E
6650874 N, 253011 E
a=85m, b=51m
Projections – flattening the earth
Mollweide equal area
Projections – flattening the earth
Mollweide equal area
What’s wrong?
A geographic projection
(”equirectangular”) is
probably not what you want!
The School Map
Flattening the earth
You can keep some of these attributes:
Area
Shape
Distance/scale
Distance/angle
Useful projections
Mercator (epsg:54004,
900913)
Scale distortion = 1/cos(lat)
Oslo ~60 degrees N = 2:1!
Conformal (shape is ok in
small areas)
Used by global map data
sets today
More projections
UTM 33V (epsg:32633)
Covers Norway quite well
Miller (epsg:54003)
LAEA (epsg:3035)
RT90 2.5 gon V
(epsg:3021) - Sweden
http://www.radicalcartography.net
Coordinate Conversions and Transformations
including Formulas
EPSG Surveying and Positioning Guidance Note Number 7, part 2
How to convert latitude (degrees) into a Mercator projection
// http://www.epsg.org/guides/docs/G7-2.pdf
merc_y: function(lat) {
if (lat > 89.5)
lat = 89.5;
if (lat < -89.5)
lat = -89.5;
var phi = this.deg_rad(lat);
var sinphi = Math.sin(phi);
var con = _eccent * sinphi;
var com = .5 * _eccent;
con = Math.pow(((1.0-con)/(1.0+con)), com);
var ts = Math.tan(.5 * ((Math.PI*0.5) - phi)) / con;
var y = 0 - this.r_major * Math.log(ts);
return y;
},
Reprojection
Proj.4 (shell)
cs2cs +proj=latlong +datum=WGS84 +to +proj=utm +zone=33 +datum=WGS84
Proj4js (javascript)
var src = new Proj4js.Proj("EPSG:4326");
var dst = new Proj4js.Proj("EPSG:32633");
var p = new Proj4js.Point(10.9,59.9);
Proj4js.transform(src,dst,p);
Geotools (java)
CoordinateReferenceSystem crs33N =
crsFactory.createFromWKT(bwkt_UTM_33N);
CoordinateOperation opUtm2WGS = coFactory.createOperation(crs33N,
crsWGS84);
MathTransform transU2WGS = opUtm2WGS.getMathTransform();
The Client - OpenLayers
How!
OpenLayers
Active development (MetaCarta, TPP)
Nice code, good test suite
Object-oriented, client-side javascript
Open source license (BSD)
Supports open standards
Supports several commercial layers
Plays well with others – no integration problems
(YMMV)
OpenLayers – History
800
700
600
2.6
500
400
300
200
2.0
100
1.0
ju
l.
se 05
p.
0
no 5
v.
0
ja 5
n.
m 06
ar
.0
m 6
ai
.0
6
ju
l.0
se 6
p.
0
no 6
v.
0
ja 6
n.
m 07
ar
.0
m 7
ai
.0
7
ju
l.0
se 7
p.
0
no 7
v.
0
ja 7
n.
m 08
ar
.0
m 8
ai
.0
8
ju
l.0
se 8
p.
08
0
V2.6 was released in May 2008 – with a total of 548
files, of which 155 - 28% - are test related.
OpenLayers – Main Classes
Map
Layer subclasses (WMS, Google ++)
Control
Format
OpenLayers Map
map = new OpenLayers.Map( 'map' );
This projection is probably not what you want!
OpenLayers Map with a projection
var options = {
projection: new OpenLayers.Projection("EPSG:900913"),
units: "m",
maxResolution: 156543.0339,
maxExtent: new OpenLayers.Bounds(-20037508, -20037508,
20037508, 20037508.34)
};
map = new OpenLayers.Map('map', options);
The map server (or tile set) must support this projection.
OpenLayer.Layer
Base layer
Vector or raster
Only one visible
Overlay
Any number visible
Same projection or reproject
OpenLayers WMS
map = new OpenLayers.Map( 'map' );
layer = new OpenLayers.Layer.WMS(
"OpenLayers WMS",
"http://labs.metacarta.com/wms/vmap0",
{layers: 'basic'}
);
map.addLayer(layer);
OpenLayers Google
map = new OpenLayers.Map('map');
var gphy = new OpenLayers.Layer.Google(
"Google Physical",
{type: G_PHYSICAL_MAP}
);
map.addLayers([gphy]);
map.setCenter(new OpenLayers.LonLat(10.2, 48.9), 5);
You still need an API key! OpenLayers is just a wrapper around
Google’s client.
OpenLayers - Controls
Changing the state of
the map
Navigation
Drawing tools
Layer selector
Layer classes that use ”real” data
WFS (vector), KML,
GeoRSS
Watch out for browser
performance!
1000s of entries may
take minutes
GUI Elements
Fancy popups
Markers
Vector editing
Comparing OpenLayers and
Google
<script src='http://maps.google.com/maps?file=api&amp;v=2&amp;key=secret'></script>
<script src="../lib/OpenLayers.js"></script>
<script type="text/javascript">
var map; function init(){
map = new OpenLayers.Map('map');
var satellite = new OpenLayers.Layer.Google( "Google Satellite" , {type: G_SATELLITE_MAP} );
map.addLayer(satellite);
map.setCenter(new OpenLayers.LonLat(10.205188,48.857593), 5);
} </script>
<body onload="init()"> <div id="map"></div> </body>
<script src="http://maps.google.com/maps?file=api&amp;v=2&amp;key=abcdefg"
type="text/javascript"></script>
<script type="text/javascript">
function initialize() {
var map = new GMap2(document.getElementById("map_canvas"));
map.setMapType(G_SATELLITE_MAP);
map.setCenter(new GLatLng(37.4419, -122.1419), 13);
}
</script>
</head>
<body onload="initialize()" onunload="GUnload()">
<div id="map_canvas" ></div>
</body>
Tile cache
Proxy cache in front of
your WMS
(Pre)Generate tiles
http://tilecache.org/
Throttling of a slow
backend
Cache servers
Cache, pregeneration, throttling
Map server
String queryString = request.getQueryString();
String md5name = DigestUtils.md5Hex(queryString);
File tileFile = new File(createFileName(md5name));
ensureDir(tileFile);
byte[] result = null;
if (!tileFile.exists()) {
result = downloadAndStoreTile(queryString, tileFile);
} else {
result = readFileFromCache(tileFile);
}
if (result != null && result.length > 0) {
response.setContentType("image/jpeg");
response.setContentLength(result.length);
response.setDateHeader("Expires", new Date().getTime() +
1 * 1000);
IOUtils.write(result, response.getOutputStream());
return;
}
response.setStatus(404);
String queryString = request.getQueryString();
String md5name = DigestUtils.md5Hex(queryString);
File tileFile = new File(createFileName(md5name));
ensureDir(tileFile);
Add throttling!
byte[] result = null;
if (!tileFile.exists()) {
result = downloadAndStoreTile(queryString, tileFile);
} else {
result = readFileFromCache(tileFile);
}
if (result != null && result.length > 0) {
response.setContentType("image/jpeg");
response.setContentLength(result.length);
response.setDateHeader("Expires", new Date().getTime() +
1 * 1000);
IOUtils.write(result, response.getOutputStream());
return;
}
response.setStatus(404);
Demos
A tile cache
Adding resorts with GeoRSS
Flickr
Conclusion
It is possible to combine an open source mapping
client,
- with commercial map layers,
- with free map layers
- with your own data
Without the need to maintain a javascript map
client, and without buying the full stack.
http://kart.sesam.no/
http://www.finn.no/kart/
[email protected]
[email protected]
http://project.spjelkavik.net/2008/javazone/