Category Archives: Geomatikk

Javascript, GIS, testing, Maven, AJAX og andre småtricks

Jeg jobber, som kjent, endel med kartapplikasjoner på nett. I denne situasjonen har du et par valg. Google Maps APIet eller OpenLayers. Vil du ha full kontroll velger du OpenLayers. Kort og godt.

Dog, uansett om du havner på Google Maps eller OpenLayers (ja, det finnes vel også noe fra ESRI) for å lage kartapplikasjoner som skal kjøre i nettleseren trenger du å forholde deg til Javascript. Mye kan sies om Javascript, og mye av det er feil. Likevel: det er et språk som er misbrukt mer enn PHP. Derfor: skal du gjøre noe fornuftig med Javascript anbefaler jeg deg å se Douglas Crockfords videoforelesning “programming in javascript“. Og også eventuelt lese boka hans “JavaScript: the good parts“. Og kanskje også Stoyan Stefanovs bok: “Object-Oriented JavaScript“.

Dog, det var ikke det denne posten skulle handle om. Jeg tenkte å være enda litt mer spesifikk. Jeg tenkte å skrive litt om hvordan Javascript-utvikling kan integreres i utviklingen av en Java webapp.

Det er mange steder og angripe problemet fra, men vi kan starte med Maven, som jeg er fristet til å si at er et must for javautvikling. Det finnes flere plugins for å håndtere Javascript i Maven. Jeg liker godt maven-javascript-plugin. Jeg tror ikke den vedlikeholdes så godt, men det som finnes fungerer og fyller følgende oppgaver:

  • Pakke javascript-biblioteker som “dependencies”
  • Komprimering og konkatinering av javascript-filer

I tillegg kan det kjøre tester, men der foretrekker jeg et annet bibliotek: nemlig Jasmine. Jasmine er et rammeverk for drive skrive Behaviour Driven Development av Javascript, i teorien betyr det at du kan skrive unit-tester for javascript. Legg til jasmine-maven-plugin og du får støtte for å kjøre testene via Maven. Javascript kan dermed testes like lett som Java-kode.

Når det gjelder AJAX (eller AJAJ som jeg liker å kalle det), synes jeg DWR (Direct Web Remoting) er brilliant. Lag en Java-klasse, eksponer metoder og kall dem direkte fra Javascriptet ditt. Enklere blir det ikke, dropp å tenke på XMLHttpRequest-oppsett og ståk. Når vi først snakker om å gjøre ting på server-siden må jo også GeoTools nevnes. GeoTools er rammeverket GeoServer baserer seg på, og er kort og godt et GIS-rammeverk for Java. Lese shapefiler, koble seg til romlige databaser som PostGIS og Oracle Spatial, gjør GIS-operasjoner som bufferanalyser og transformer koordinater. Litt dårlig dokumentert, men klarer det meste.

Hva så med Javascript-rammeverk? Det finnes jo flust av dem. Prototype, jQuery, ext, etc etc. Vel, så langt har jeg funnet ut at OpenLayers gir meg støtte for mye av det jeg trenger, og har dermed ikke begynnt å se så mye på Javascript-rammeverk enda. Jeg vet det sikkert finnes endel smarte rammeverk som kan gjøre ting enklere her også.

Til slutt tenkte jeg å nevne log4javascript, som virker som et meget ålreit loggeverktøy for javascript, det mest spennende er kanskje å sende logg til serversiden via AJAX. Hvis du ikke trenger dette vil jeg påstå at Firebug gjør jobben den også. Kombinert med “web developer plugin” gjør den FireFox til den eneste fornuftige browseren å utvikle javascript i (så er det en annen sak at det skal fungere i andre nettlesere også).

Håper denne listen med ressurser kan være til hjelp for noen. Ikke nøl med å kommentere om du ønsker utdyping på noen områder, har spørsmål eller kommentarer. Og, har du flere ressurser å dele så tar jeg gjerne imot dem med takk. Jeg har på ingen måte fasiten, så jeg håper at jeg med denne posten når ut til noen som driver med noe av det samme som meg. Jeg tror ikke vi er så veldig mange?

GPX med Kartverkets bakgrunnskart

OBS: En nyere versjon av eksempelet her er tilgjengelig på http://www.atlefren.net/post/2011/02/kartverket-openlayers/. Se gjerne på koden der!

OBSOBS (mai 2015): Denne bloggposten ble skrevet for 5 år siden, og mye har endra seg siden da. Det betyr at denne bloggposten er utdatert og koden ikke funker mer, men ta en titt på https://github.com/atlefren/kartverket-gpx

Du har sikkert en GPS, eller en smarttelefon med GPS innebygd? Du liker kanskje også å gå på tur og logge den? Men du synes ikke det er så forbanna kult å legge ut et track fra en tur i den norske villmark over Google Maps (la oss innse det) elendige turkart eller kornete satelittbilder?

Du ønsker kanskje ikke å vise frem noe slik som dette til turvenner? Du skulle heller ønske du kunne lagt inn ruta di over “indrefileten” av norske data? Nemlig kartverkets kart? Du har sikkert fått med deg at disse er tilgjengelige for gratis bruk for privatpersoner?

Du har kanskje til og med kommet så langt at du har fått satt opp OpenLayers med kartverkets WMS på din hjemmeside?

Men der stopper du kanskje? Du skjønner ikke helt hvordan du skal få lagt GPX fila di over kartet? Eller du får kanskje lasta den inn, men den havner helt riv, ruskende, galt avsted? Eller kanskje ser hele Norge helt på trynet ut? Frykt ikke, siden kongeriket Norge har fått meg utdanna som IKT-Geomatiker tenkte jeg jeg skulle prøve å hjelpe deg.

Jeg vet folk lurer på dette. Jeg så tidligere en tweet fra Martin Bekkelund om temaet, og når har også søkefraser som “turkart egne gpx-filer” begynnt å dukke opp i søkeloggene her på bloggen. Derfor tenkte jeg å yte en innsats.

Så, hva tenkte jeg å gå gjennom? Først av alt en liten intro til å sette opp OpenLayers med Kartverkets WMS i Openlayers. Så tenkte jeg å gå gjennom hvordan man får inn GPX-data i OpenLayers, før jeg forklarer magien bak transformasjoner og dermed får alt til å passe sammen.

Kartoppsett

Først må du ha opp et kart, det gjøres ved å gjøre ca følgende:

1. Lag en HTML-side med en div med høyde og bredde 100%. Gi denne diven en id

<html>
<head>
<title>Kart</title>

<!-- sett opp en div til kartet -->
<style type="text/css">
#map { width: 100%; height: 100%;}
</style>
</head>

<body>

<div id="map"></div>

</body>
</html>

2. Så må du legge inn OpenLayers js-biblioteket. Det greieste er å hente den fra serveren deres direkte.
Dette gjør du ved å legge til en <script>-tag i headeren:

<!-- last inn OpenLayers js -->
<script src="http://openlayers.org/api/OpenLayers.js"></script>

3. Så må vi skrive litt JavaScript selv. Vi ønsker å ha en metode som startes når siden listes, og vi velger å legge all javascript-koden direkte inn i en script-blokk i headeren: Da får vi følgende skjelett:

<html>
<head>
<title>Kart</title>

<!-- sett opp en div til kartet -->
<style type="text/css">
#map { width: 100%; height: 100%;}
</style>
<!-- last inn OpenLayers js -->
<script src="http://openlayers.org/api/OpenLayers.js"></script>
<script type="text/javascript">
//her kommer JS-koden vår
function init(){
}
</script>
</head>

<body onload="init()">

<div id="map"></div>

</body>
</html>

4. Da er grunnlaget lagt, vi har importert OpenLayers-biblioteket, og vi har en (foreløpig) tom init-funksjon. Da gjenstår det å lage et Map-objekt, et layer objekt og legge til litt kontroller.

Gjør vi dette blir js-blokka vår seende slik ut (med beskrivende kommentarer):


<script type="text/javascript">
//selve kartet
var map;

//her starter vi ting
function init() {

OpenLayers.IMAGE_RELOAD_ATTEMPTS = 3; //reduserer problemet med "rosa" tiles (openlayers viser rosa tiles når den ikke får lastet en tile)

//sett opp kartet (EPSG:32633 er UTM sone 33N)
map = new OpenLayers.Map( 'map', {
projection: new OpenLayers.Projection('EPSG:32633'),
maxExtent: new OpenLayers.Bounds(-2500000.0,3500000.0,3045984.0,9045984.0),
units: "m",
maxResolution: 2708.0, // tilsvarer zoom level 3 (hele er 21664.0)
numZoomLevels: 18 // egentlig 21, men maxResolution tilsvarer zoom level 3 (følgelig er 0-3 skrudd av)
} );

//musenavigering
map.addControl(new OpenLayers.Control.MouseDefaults());

// Definer karttjenesten(e)
var topo2 = new OpenLayers.Layer.WMS(
"Topografisk norgeskart2","http://opencache.statkart.no/gatekeeper/gk/gk.open?",
{layers: 'topo2', format: 'image/png'},{attribution:''}
);

// Legg WMSen fra kartverket til kartet
map.addLayers([topo2]);

//sentrer kartet på besseggen
map.setCenter(new OpenLayers.LonLat(683589,7146336),0); //Besseggen

}

</script>

5. Har du kommet så langt skal du nå ha ett Norgeskart du kan zoome og panorere rundt i, slik som dette.

GPX-innlasting

Godt å vel det, men jeg ser jo fortsatt ikke noe track? Nei, det skal vi ta nå.

Første skritt er å lokalisere en .gpx-fil (min ser slik ut) og ligger i samme mappe som kartet mitt på webserveren.

En ting kan vi like godt notere oss først som sist: GPX filer er i et koordinatsystem kjent som WGS 84 Lat/Lon, mens kartet vårt er i WGS84 UTM Sone 33N. Derfor må vi transformere, men det kommer vi til. Først skal vi få lasta inn GPX-fila i JS-koden.

1. Innlasting. OpenLayers har støtte for GPX-formatet og støtte for å laste filer. I tilegg må vi ha et vector-layer å legge tracket vårt i.

Ved å legge inn dette får vi noe slikt som:

//openLayers GPX-leser
var format = new OpenLayers.Format.GPX();

//layeren vi hiver featurene fra GPX i
var featureLayer = null;

//selve kartet
var map;

//her starter vi ting
function init() {

//sett opp featurelayeren som en vector-layer
featureLayer = new OpenLayers.Layer.Vector("GPX");

//url til gpx-fila (må ligge på samme server)
var url = "track.gpx";

//OpenLayers har støtte for å lese inn filer
OpenLayers.loadURL(url, null, null, loadSuccess, loadFailure);

//sett opp kartet (EPSG:32633 er UTM sone 33N)
map = new OpenLayers.Map( 'map', {
projection: new OpenLayers.Projection('EPSG:32633'),
maxExtent: new OpenLayers.Bounds(-2500000.0,3500000.0,3045984.0,9045984.0),
units: "m",
maxResolution: 2708.0, // tilsvarer zoom level 3 (hele er 21664.0)
numZoomLevels: 18 // egentlig 21, men maxResolution tilsvarer zoom level 3 (følgelig er 0-3 skrudd av)
} );

//musenavigering
map.addControl(new OpenLayers.Control.MouseDefaults());

OpenLayers.IMAGE_RELOAD_ATTEMPTS = 3; //reduserer problemet med "rosa" tiles (openlayers viser rosa tiles når den ikke får lastet en tile)

// Definer karttjenesten(e)
var topo2 = new OpenLayers.Layer.WMS(
"Topografisk norgeskart2","http://opencache.statkart.no/gatekeeper/gk/gk.open?",
{layers: 'topo2', format: 'image/png'},{attribution:''}
);

// Legg WMSen fra kartverket og featureLayeren vår til kartet
map.addLayers([topo2,featureLayer]);

//sentrer kartet på besseggen
map.setCenter(new OpenLayers.LonLat(683589,7146336),0); //Besseggen

}

//denne kalles når GPX-fila er lastet
function loadSuccess(request) {
//les responsen her som GPX
var features = format.read(request.responseText);

}

//denne kalles hvis/når noe går galt ved lesing av fila
function loadFailure(request) {
alert("Kunne ikke lese GPX-fila...");
}

Vi ser vi har gjort endel nye ting:

  • Vi har definert et format og en featureLayer
  • Vi kjører et kall til OpenLayers.loadURL
  • Vi legger til et layer til til kartet
  • Vi har en funksjon loadSuccess som laster GPX-fila over i et feature-array

Men vi kommer forsatt ikke så veldig langt.

Neste, logiske skritt, ville være å legge til featurene i featureLayeret og zoome inn på disse. Dvs å legge til litt i loadSuccess:

function loadSuccess(request) {
//les responsen her som GPX
var features = format.read(request.responseText);
//vi får da en samling features, legg disse til vector-layeret
featureLayer.addFeatures(features);
//zoom kartet, denne gangen til område de lastede featurene dekker
map.zoomToExtent(featureLayer.getDataExtent());

}

Men dette vil ikke fungere, det ser vi her. Problemet er, som nevnt før, at vi har to forskjellige koordinatsystem. Hadde kartet vært i WGS84 Lon/Lat hadde det fungert (men det vil vi ikke, da ser ikke kartet bra ut), hadde GPX-fila vært i WGS84 UTM Sone 33N ville det fungert (men det er aldri GPX-filer).

Dermed må vi transformere. Her kommer OpenLayers til kort, men den kan støtte seg på Proj4js. Du må laste ned kildekoden, og legge “lib/proj4js-compressed.js” et sted der javascriptet ditt når den, samt inkludere den på samme måte som med OpenLayers.js. Hvis du legger den i samme mappe legger du til:

<script src="proj4js-compressed.js"></script>

i headeren.

I tillegg må du definere for Proj4Js hvilke parametere som gjelder for WGS84 UTM Sone 33N, da den ikke kjenner det. Dette gjør du ved å legge inn følgende i begynnelsen av JavaScriptet:

//Proj4js definisjon for WGS84 UTM Sone 33N
Proj4js.defs["EPSG:32633"] = "+proj=utm +zone=33 +ellps=WGS84 +datum=WGS84 +units=m +no_defs";

(Denne definisjonen finner du under “Proj4js” på http://spatialreference.org/ref/epsg/32633/.)

Da er vi nesten i mål, nå gjenstår bare selve transformasjonen. Det vi må gjøre i loadSuccess er å loope gjennom alle featurene og transformere geometriene fra WGS84 LatLon (som har kode EPSG:4326) til WGS84 UTM Sone 33N (som har kode EPSG:32633). Dette gjør vi med transform-metoden til geometri-objektet, og funskjonen vår blir slik:


function loadSuccess(request) {
//les responsen her som GPX
var features = format.read(request.responseText);

//loop gjennom alle features og transformer fra WGS84 Lat/Lon (EPSG4326) til WGS84 UTM Sone 33N (EPSG:32633)
for(var i = 0; i < features.length; i++){
features[i].geometry.transform(new OpenLayers.Projection('EPSG:4326'), new OpenLayers.Projection('EPSG:32633'));
}

//vi får da en samling features, legg disse til vector-layeret
featureLayer.addFeatures(features);
//zoom kartet, denne gangen til område de lastede featurene dekker
map.zoomToExtent(featureLayer.getDataExtent());
}

Nå ser vi et spor slynge seg oppover Skogshorn, men det er litt blasst. Vi må endre hvordan det tegnes!

Flikking og pussing

Vi har nå ting på plass, men det ser kanskje litt sært ut? Vi kan mens vi er i gang fikse litt på utseendet på lina vår, via et StyleMap på vektor-layeret. Dette gjør vi ganske enkelt slik (og tegner linja med 2px grønn strek):


//angi styling av features
var styleMap = new OpenLayers.StyleMap(OpenLayers.Util.applyDefaults({
strokeColor: "green",
strokeWidth: 2},
OpenLayers.Feature.Vector.style["default"]));

//sett opp featurelayeren som en vector-layer
featureLayer = new OpenLayers.Layer.Vector("GPX", {styleMap: styleMap});

Og får dette. (For mer om styling, se OpenLayers.Feature.Vector).

Eller kanskje du foretrekker å bruke N50-kartet som bakgrunn, og la brukeren få velge? Mulighetene er mange!

Konklusjon

Dette var bare en quick-and-dirty gjennomgang av prinsippene, koden fungerer greit til enkel bruk, men den kan lett kombineres med opplastingsrutiner for å laste opp GPX-filer via f.eks. php, eller du kan utvide ting til å bruke en romlig database for å lagre GPS-tracket? Muligehtene er mange.

Og, skulle du oppdage feil eller mangler, eller har spørsmål er det bare å si fra!

Kartapplikasjoner for Android

Etter at jeg fikk meg en Android-telefon har jeg begynnt å intressere meg for (sjokk, sjokk!) kartapplikasjoner på den. De fleste smart-telefoner har jo GPS og nett-tilgang, så her er det mange interessante måter å bruke kartdata på.

Android-telefonene baserer seg jo på Android-operativsystemet fra Google, så at Google Maps er forhåndsinstallert er ikke noe sjokk. Dog finnes det et vell av andre kartapplikasjoner og lignende. Tenkte jeg her skulle liste de jeg har testet, og håper såklart at mine lesere supplerer meg med egne forslag.

  • Compass: Et enkelt kompass, som viser deg hvor nord er, med forskjellige interfacer. Støtter også lagring av posisjon fra GPSen.
  • GPS Status: Gir deg status på GPSen, dvs hvor mange satelitter du har kontakt med og slikt. Greit for å få en oversikt.
  • gvSIG Mini Maps: Android-versjonen av desktop GISet gvSIG. Rimelig avansert, med bla.a. støtte for å legge inn egne WMSer (men jeg har ikke funnet ut hvordan man kan legge inn projeksjon)
  • MapDroyd: Kartklient som støtter offline kart. Last ned ferdige eller legg inn egne tiles. Ikke testet denne så mye egentlig, men greit å vite at det finnes noe som fungerer uten nett.
  • MyTracks: Fra Google, lar deg lagre GPS tracks som GPX-filer.
  • RMaps: kartkleint med _mange_ forskjellige kart å velge på: Google, Yahoo, Microsoft, Openstreetmap, Cloudmade, Ordonance Survey og Kartverkets åpne kart(!). Støtter også lagring av GPS-tracks.
  • SportyPal: treningsapp, som lar deg recorde GPS-spor, men statistikk og kart mens du beveger deg. Automatisk opplasting til nettside for mer statistikk.

Og det finnes sikkert flere, så tips meg gjerne. Det var for en stund siden snakk om en app fra Kartverket, men jeg misternker at den er for Android 2.0 og over, ikke 1.6 som jeg har..

Kartverket, kartdata og OpenStreetMap

I kommentarfeltet hos Martin Bekkelunds sak om GoOpen ble det ganske fort snakk om kartdata, kartverket og OpenStreetMap, et emne som opptar meg (av naturlige årsaker), og som jeg har skrevet om før. For ikke å kuppe kommentarfeltet der legger jeg heller ut fortsettelsen på kommentaren min her, slik at den kan diskuteres for seg om noen føler for det (forresten rart hvordan skrivemotivasjonen plutselig dukker opp!)

Så er det spørsmålet om OSM vs. kartverkets data. Jeg var ivrig inne i en debatt rundt dette ifm nrkbetas lansering av planene rundt ut.no, både på nrkbeta og egen blogg. Et poeng som randt meg i hu nå, som jeg ikke kom på da var følgende: Hvordan ser man for seg at OSM skal håndtere en nesten kontinuerlig oppdatering av data som kommer fra kartverkets (og kommunene, deres underleverandører)? Mye av dataene kartverket sitter på har også OSM i dag, her må det merges og jobbes mye for å få ting på plass. Har ikke noe imot OSM (tvert imot), men etter å ha vært borte i diverse fag som har med kartkonstruksjon (/innsamling av kartdata) å gjøre klarer jeg ikke helt å se hvordan et dugnadsprosjekt som OSM skal klare å konkurrere med profesjonellt insamlede data.

Man kan såklart trekke paraleller til debatten som går om Store Norske Leksikon i dag, satt opp mot Wikipedia. Her foreslår endel å frigi SNL-dataene til Wikipedia, slik at disse kan bygge vidre på dem, noe jeg forsåvidt er for. Spørsmålet er dog om en slik løsning mtp kartverksts data opp mot OSM er like grei. Jeg har mine tvil.

Nordisk Kartografikurs 2009, presentasjoner

Som jeg skrev om tidligere har jeg tidligere i uka vært på Nordisk Kartografikurs i Stavanger for å holde to foredrag, om henholdsvis prosjekt og masteroppgaven min. Tenkte jeg skulle her dele både slidene fra presentasjonene og de opprinnelige oppgavene, slik at alle som kommer hit etter min oppfordring finner dem her. Mine faste lesere har vel sett oppgavene før, men slidene skal være nye! I tillegg er det greit å samle ting på et sted.

Det første foredraget på ca 45 minutter hadde tittelen “Web 2.0 – Brukerinteraksjon”:

Dette er såklart basert på masteroppgaven “Map 2.0 – User Interaction in Web Mapping Sites”, denne finner du på dokumentsidene mine. Når det gjelder kildekoden utviklet her fikk jeg en forespørsel om denne. Den ligger tilgjengelig på kodesiden (som forøvrig snart skal oppdateres), under MIT-lisensen.

Det andre foredraget hadde tittelen “OpenSource GIS”, og er basert på prosjektoppgaven “Use of Free and Open Source GIS in Commercial Firms”, som også finnes på dokumentsidene mine. Jeg nevnte også for noen på kurset oversikten til Stefan Steiniger over FOSS Desktop GIS, denne finnes på http://www.spatialserver.net/osgis/

Jeg hadde desverre ikke mulighet til å ta opp lyd eller bilde, men jeg er selv fornøyd med presentasjonene. Det er første gang jeg snakker til over 50 personer, men jeg følte at alt gikk greit. Jeg gjorde også et forsøk på å følge endel av de tipsene om presentasjoner som deles av flinke folk på nett. Man må såklart finne sin egen stil, men det å få input er viktig. Jeg håper jeg får gjenta slikt som dette, for det var meget gøy og lærerikt.