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&v=2&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&v=2&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/ henning@skiinfo.com henning@spjelkavik.net http://project.spjelkavik.net/2008/javazone/
© Copyright 2025