Tag Archive | Javascript

Programmering för Geoninjan

Efter veckans inlägg är det ganska tydligt att Python är ett programmeringsspråk som är väldigt användbart inom geosupport.

Oavsett om man är en etablerad specialist på GIS med uppgifter inom kartografi, analys och ”what ever”, eller sitter i skolbänken och lyssnar på föreläsningar om betydelsen av ”koroplet symbolik” eller skillnaden mellan 7- och 3-parameters transformationer, så kan man ha stor glädje av ett, eller två, programmeringsspråk.

Läs mer…

Annonser

Omvandla koordinater med javaskript

I detta inlägg tänker jag använda javaskript för att göra ett ”enkelt” formulär som översätter koordinater från ett system till ett annat.

Jag skall försöka hålla koden så enkel och ”ren” som möjligt, så att det senare går att inkludera den i andra sammanhang så smidigt som möjligt.

Det skall dock gå att använda formuläret fristående, just för att översätta koordinater ”on the go”. Det skall därför inte krävas några webbservrar eller installationer. En webbläsare är allt som skall behövas, plus lite skriptfiler. Läs mer…

Komprimera kod

När jag använde en javascriptkomprimerare för att minska ner mängden kod i min applikation för att mäta i panoramabilder så var det flera saker som hände.

Alla onödiga tabbar och mellanslag, samt alla kommentarer försvann. Dessa behövs inte och även om de inte exekveras i webbläsaren så tar de bandbredd att överföra.

Långa variabler byttes i en del fall ut mot betydligt kortare, av samma skäl som tidigare.

En hel del åtgärdades inte, vilket främst har att göra med att jag skrivit kod efter hand och inte själv gjort vad jag kunnat för att exempelvis reducera antalet funktioner.

Det som var mer intressant för mig var att en del saker, som är fullständigt korrekta och framför allt begripliga, ändrades till något som fortfarande är korrekt, men betydligt svårare att begripa när man inte är van.

Ett exempel:

var testdata = true; // sätt värde till sann
var testvariabel; // definiera variabel
if (testdata == true) { // prova om värdet är sann
   testvariabel = "sant"; // om sann lägg in "sant" i variabel
} else { // om vilkoret inte är sant
   testvariabel = "falskt"; // lägg in värdet "falskt" i variabeln
} // avsluta vilkoret
alert(testvariabel); // skriv ut värdet i variabeln

Och efter komprimeringen:

var testdata=!0,testvariabel;
testvariabel=1==testdata?"sant":"falskt",alert(testvariabel);

Från att ha varit 376 bytes så blev det 90, men vad står det egentligen?

Även utan kommentarerna i den första koden så är det inte så svårt att läsa sig till vad det är som händer. I den andra så börjar det bli lite överkurs för mig.

Jag antar att ”!0” är ett annat sätt att skriva sant, eller ”icke falskt” och då förstår jag den första delen (fram till semikolonet).

Nästa del får jag nog dela lite på för att förstå…

”testvariabel=” betyder att testvariabeln skall tilldelas ett värde, som är beroende av om testdata är lika med 1, eller ”sant”(”1==testdata”).

Om så är fallet (”?”) så tilldelas värdet ”sant”, om inte (”:”) ”falskt”. Det kommatecken som kommer före utskriften av resultatet hänger jag inte med på riktigt. Eftersom det inte är ett semikolon så hänger det ihop med det tidigare på något sätt, men det enda sätt jag kan få till kopplingen är att utskriften skall göras efter det att villkoret är kört?

Hur som helst, det finns funktioner för att komprimera kod och är det mycket kod så kan effekterna bli märkbara. Däremot så blir det inte mer läsbart, så se till att du skriver din kod betydligt mer överskådligt med massor av kommentarer. När du är nöjd så kan du använda exempelvis http://refresh-sf.com/ för att komprimera.

a!=b?"olika":"lika";

Är ni med? Om a är olik b så är de ”olika”, annars är de ”lika”.

villkor ? sant : falskt ;

På komprimeringssidan som jag länkat till ovan så går det att komprimera även CSS och HTML på samma sätt. En annan site som också baseras på UglifyJS är http://jscompress.com/.

Vad har jag gjort i jul?

Jaha då var jul och nyår över och de flesta av oss är väl tillbaka i normala rutiner igen.

Vad har ni gjort under ledigheten? Varit med familj och vänner utgår jag från, men mer då?

Själv har jag haft så många påbörjade projekt att jobba med, så jag hade kunnat fylla minst tre gånger så mycket ledig tid och ändå inte blivit färdig.

Vad är det då för projekt jag hållit på med. En del foto och filmprojekt har det blivit, men det kan vi lämna här och nu.

Jag har sedan börjat titta på panoramabilder och hur man kan skapa dessa så snabbt och enkelt som möjligt, utan att det för den skull blir dåligt. Och nej, en panorama app i telefonen duger inte.

Det blev en lång process med massor av experiment och 3D utskrifter. Resultatet blev en ”panoramarobot” som när den är helt klar tar de bilder som behövs för ett helt sfäriskt panorama på ungefär en minut. Bilderna skall sedan bearbetas, och detta har jag också skapat en process för så att det blir riktigt bra panoramabilder med drygt 50 megapixels upplösning. Jag har sedan tidigare en större mycket mera avancerad ”robot” som kan ta ännu mycket bättre bilder och med högre upplösning (gigapixel), men den har jag inte byggt själv.

Är du nyfiken på roboten jag byggt så finns en tidig prototyp på ”Thingiverse” och jag gjorde även en film på YouTube.

Den färdiga roboten har mindre elektronik och färre gummiband… Dessutom eftersom den är lättare så ”svajjar” den mycket mindre.

När jag nu kan skapa såväl ”ekvirektangulära” (standard 360×180) som ”stereografiska” (se bild nedan) panoraman, så blev nästa steg att se vad man kan göra sedan.

EKSJOchurchJag har tidigare använt lite olika javaskript för att visa panoraman på webbsidor, vilket fungerat bra även om det funnits en del problem och nackdelar.

Nu råkade jag på Pannellum.org som är öppen källkod för en panoramavisare i HTML5, vilket lät intressant att titta närmare på. En skillnad som jag gillar med pannellum jämfört med andra javaskript är navigeringen och panoreringen inne i panoramat (jämför PTviewer här). Det finns dessutom väldigt få javaskript för panoramavisning som är fria/öppen källkod.

I praktiken så är all nödvändig kod för panoramat inbakad i en html-fil och konfiguration görs antingen via URL-strängen eller en JSON-fil.

För att visa enkla panoraman så görs det enklast via URL-strängen (exempel).

Men det går som sagt att skapa ganska komplicerade rundturer med skräddarsydda JSON skript (exempel). Dessa rundturer skriver man koden till manuellt, vilket kan bli nog så krångligt inte minst när man skall placera ut alla hyperlänkar och info-symboler. Därför så skapade jag ett skriptprogram och lite metoder för att även detta skulle kunna göras smidigt.

Ett problem med HTML5 och Pannellum är att man måste vara lite försiktig med upplösningen i bilderna, då mobila klienter inte kan hantera bilder större än 4096 pixlar. Desktop klienter brukar klara minst 8192 pixlar, och några klienter med bra grafikhantering ännu större.

Mina bilder i exemplen ovan är 5000 pixlar, vilket innebär att om du använder en mobil klient, så kommer du inte att kunna se några panoraman, sorry! Jag hade redan skapat och skalat ned bilderna till 5000 pixlar, när jag fick reda på begränsningen för mobila klienter. Om du vill kan du testa samma panorama i olika upplösningar, inklusive för mobila klienter genom att klicka här. Dessutom så är den en skillnad mellan Android och iOS, som man också måste planera för.

Det går att komma runt det här med upplösning genom att använda en variant av ”tiles”, men detta har jag inte tittat närmare på än.

En annan begränsning är att några funktioner kräver en modern webbläsare för att exempelvis kunna köras i helskärmsläge. Dessutom så måste alla filer läsas från en webbserver och inte från en lokal, eller delad katalog… (säkerhetskrav).

Vad är då kopplingen till GIS?

Jo, det går ju att skapa en webbkarta, med exempelvis Leaflet eller OpenLayers och där lägga ut klickbara punkter som öppnar dessa panoraman. Kombinerar man exempelvis med mitt exempel på ”Story Map” så går det att bygga upp väldigt interaktiva rundturer i en mängd olika syften.

Allt som krävs är öppen källkod, lite javaskript, JSON, HTML5 och så förstås en panoramarobot…

Egen Street View

Nyligen lanserade Open Street Map möjligheten att använda Mapillary som stöd när man digitaliserar data med iD. Men vad är då Mapillary?

Kortfattat kan man säga att det är en simpel variant av Google Street View som är enkel att bidraga till själv och även smidig att baka in på egna hemsidor.

Jag passade på medan jag cyklade genom Gamla Stan i Eksjö igår att plocka fram telefonen och starta den app som krävs för att ta bilder.

IMG_1380I appen kan man titta på bilder i närheten, men framför allt ta nya serier med bilder. Man väljer om man promenerar eller åker bil eller cykel (typ) sedan är det bara att starta appen och peka kameran i färdriktningen. Om man vill kan man även stanna och fånga bilder runtom i ett panorama, vilket kan vara passande på många platser.

När man är klar så ansluter man helst via wifi och laddar upp bilderna till en server. Där processas bilderna och bland annat så letar man efter ansikten, som suddas ut, och andra bilder som kan vara mindre lämpliga. Dessutom så försöker programmet fastställa om man hållit kameran rak och om så inte varit fallet räta upp bilderna. Allt detta sker automatiskt så det kan naturligtvis ske missar.

När bearbetningen är klar så läggs bilderna ut offentligt och de går därmed att hitta på hemsidan, eller via något av de utvecklings API som finns tillgängliga.

Screenshot from 2014-10-22 16:59:11Appen finns till såväl iOS, Android som Windows Phone, men man kan även ladda upp bilder manuellt via hemsidan. Det som krävs är dock att ett antal EXIF taggar finns med i bilderna. Många GPS kameror tar med dessa taggar, men se upp med exempelvis ”Orientation” vilket kräver att kameran även har en inbyggd kompass, vilket inte är jättevanligt.

Vill man bakan in sina bilder på en hemsida så görs det med några få rader HTML. Först utforskar man Mapillary och letar reda på den bild man vill inleda med och kopierar ”koden” för denna bild:

Screenshot from 2014-10-22 17:21:26I mitt fall hade den första bilden koden: UPc_BoO7OWiJhkzUYjnT2Q

Denna använder man sedan längre ned i HTML koden.

<script src="//dga406zepc8gy.cloudfront.net/javascripts/mapillary.js" type="text/javascript"></script>

Koden ovan placeras i <HEAD> taggen och där man vill ha sin ”applet” placeras en <DIV> tag:

<div id='mapillary'></div>

Sedan skall det hela startas också, vilket görs med ett javascript som kan bakas in var som helst (nästan) men exempelvis i <BODY> taggen där man också använder den kod som representerar startbilden:

<body onload="javascript:Mapillary.init('mapillary', {image: 'UPc_BoO7OWiJhkzUYjnT2Q', width: 600});">

Resultatet då. Ja det kan du själv bedöma via länken här, men för att vara första gången och jag var lite slarvig med telefonen så var det förvånansvärt enkelt, suddiga bilder ursäktade.

Om man tränar och planerar lite så kan jag exempelvis tänka mig att man kan använda detta i marknadsföring av exempelvis naturområden som inte finns med i Google Street View. Det kostar ju heller inget egentligen, mer än tiden man lägger ner, vilket tilltalar en smålänning.

 

Webbkartor från Skogsstyrelsen

För ett tag sedan tittade jag lite på Länsstyrelsernas webbkartor, vilket inte fungerade alls eftersom man använder Silverlight, som inte stöds av Linux samt många mobila plattformar.

Nu tänkte jag titta lite kort på Skogsstyrelsens webbkartor (länk), där de bland annat publicerat en karta för den stora branden utanför Sala och Fagersta.

Screenshot from 2014-08-31 12:35:45Klicka på bilden ovan för att starta Brandkartan i ett nytt fönster

Det går att välja bland flera olika bakgrundskartor och flygbilder. Exempelvis finns en före-efter karta där man kan jämföra bilder före branden, men nytagna bilder efter (se bild nedan).

brand

Det går även att lägga på lager med utförda avverkningar samt natur- och kulturhänsyn, vilket i sammanhanget kan vara av intresse.

Om tjänsten då. Det mesta fungerar och man får fram det man önskar även om det inte är helt intuitivt. Sedan så verkar det vara något lite galet med en del lager som gör att kartan inte vill visas helt ut till kanten överallt. Kanske något med WMTS tjänsterna någonstans? Å andra sidan så med tanke på det jag beskriver härnäst så kanske det bara är en slump och om jag provar att ladda om sidan några gånger så kanske det blir bättre.

Det jag först reagerade på var nämligen att det tog en hiskelig tid att starta tjänsten och innan olika funktioner svarade på kommandon. Det kan bero på att servrar var i vila, men det kan finnas andra skäl också.

När jag tittar på tjänsten i Firebug (tillägg i Firefox) så framgår det tydligt att tjänsten är baserad på Open Layers (2.12) och GeoExt, men det som jag reagerar på är att det finns över 260 hänvisningar till javascriptfiler som skall läsas in, och då har jag bara räknat de som rör Open Layers!

Namnlös

När dessutom huvuddelen av dessa skriptfiler är många hundra rader långa så förstår man att det är fruktansvärt mycket kod som skall läsas in i datorn och sedan hanteras av webbläsaren för att allt skall fungera.

Jag kan inte tillräckligt mycket om javascript för att säga något definitivt, men det här känns fel.

Screenshot from 2014-08-31 17:05:08

När jag testkör sidan genom http://www.webpagetest.org så blir det lite intressanta resultat. Dels blir den initiala laddningstabellen otroligt lång och redovisas som 12,4 sekunder till ”document load” och drygt 21 sekunder tills sidan är klar, medan återbesök tar knappt två sekunder.

Det som sticker ut lite förutom att det är väldigt många skript som skall läsas in är ArcGIS 9.3 REST API som tar väldigt lång tid att läsa in (bild nedan).

Screenshot from 2014-08-31 17:13:14

Som avslutning så kan man utläsa från testet att av den totala mängden anrop vid första visningen så står javascript för 272 stycken, vilket utgör över 4 Mb i storlek.

Screenshot from 2014-08-31 17:17:12

Diagrammen ovan gäller för första visningen. Efterföljande visningar har betydligt lägre andel javascript (av naturliga skäl) och en större andel bildinnehåll även om mängden bilddata inte ökar.

Ladda upp bilder till geoservern

Ladda upp och visa var bilder är tagna är det många webbsidor som erbjuder som tjänst. Vill man kunna göra det själv så är det faktiskt inte så svårt.

I detta inlägg skall jag visa hur du gör detta med PHP och Javaskript.

PHP tillåter i grunden bara filer upp till 2 Mb att laddas upp med skripten. Detta kan man ändra genom att redigera en fil på servern:

sudo vi /etc/php5/apache2/php.ini

Din php.ini kanske finns någon annanstans, men om du skapar ett enkelt php dokument med nedanstående text och kör det genom servern i en webbläsare, så står det där var filen är sparad på servern.

<html>
 <body>
 <?php
 phpinfo( );
 ?>
 </body>
 </html>

Ändra upload_max_filesize: 2M till något mer passande, jag väljer 8 Mb. När du är klar så startar du om webbservern:

sudo service apache2 restart

Först så skapar man ett enkelt formulär som pekar ut filen man vill ladda upp.

<form action="ladda.php" method="post" enctype="multipart/form-data">
<label for="file">Bild: </label>
<input type="file" name="file" id="file"><br><br>
<input type="submit" name="submit" value="Ladda Upp">
</form>

Skärmbild från 2014-02-01 23:41:33

Sedan behöver man skapa ett PHP dokument som tar hand om filen, testar den och kopierar den till lämplig plats. Här har jag valt katalogen ”upload” på samma plats där webbsidan finns. För att det skall fungera så måste den mappen finnas och användaren måste ha skrivrättigheter i den ( chmod 777 upload/ ).

<html>
<body>
<p>Uppladdad bild...</p>
<?php

//Funktion för att beräkna GPS data
function getGps($exifCoord, $hemi) {
$degrees = count($exifCoord) > 0 ? dela($exifCoord[0]) : 0;
 $minutes = count($exifCoord) > 1 ? dela($exifCoord[1]) : 0;
 $seconds = count($exifCoord) > 2 ? dela($exifCoord[2]) : 0;
$flip = ($hemi == 'W' or $hemi == 'S') ? -1 : 1;
return $flip * ($degrees + $minutes / 60 + $seconds / 3600);
}
//Dela EXIF data med "bråk" värde
function dela($coordPart) {
$parts = explode('/', $coordPart);
if (count($parts) <= 0)
 return 0;
if (count($parts) == 1)
 return $parts[0];
 return floatval($parts[0]) / floatval($parts[1]);
 }

// Tillåtna extensions
$allowedExts = array("jpeg", "jpg", "JPG", "JPEG");
// Kontrollera att det är bilder och med rätt storlek
$temp = explode(".", $_FILES["file"]["name"]);
$extension = end($temp);
if ((($_FILES["file"]["type"] == "image/jpeg")
|| ($_FILES["file"]["type"] == "image/jpg"))
&& ($_FILES["file"]["size"] < 8000000)
&& in_array($extension, $allowedExts))
  {
  if ($_FILES["file"]["error"] > 0)
    {
    // Skriv felkod om något gick galet
    echo "Return Code: " . $_FILES["file"]["error"] . "<br>";
    }
  else
    {
    echo "Uppladdad: " . $_FILES["file"]["name"] . "<br>";
    echo "Typ: " . $_FILES["file"]["type"] . "<br>";
    echo "Storlek: " . ($_FILES["file"]["size"] / 1024) . " kB<br>";
    echo "Temp fil: " . $_FILES["file"]["tmp_name"] . "<br>";
    $newfile = "upload/" . $_FILES["file"]["name"];
    if (file_exists($newfile))
      {
      // Om filen redan finns
      echo $_FILES["file"]["name"] . " finns redan. ";
      }
    else
      {
      // Om allt fungerar
      //överför filen till den nya platsen med det nya namnet, visa felmeddelande om det inte gick.
      $copied = move_uploaded_file($_FILES['file']['tmp_name'],
      $newfile);
      if (!$copied)
      {
        echo '<h1>Kopiering misslyckades!</h1>';
      } else {
        echo "Sparat i: " . $newfile;
        //hämta EXIF informationen från filen
        $exif = read_exif_data( $newfile);
        $emake =$exif['Make'];
        $emodel = $exif['Model'];
        $eexposuretime = $exif['ExposureTime'];
        $efnumber = dela($exif['FNumber']);
        $eiso = $exif['ISOSpeedRatings'];
        $edate = $exif['DateTime'];
        $dir = dela($exif['GPSImgDirection']);
        $alt = dela($exif['GPSAltitude']);
        $lon = getGps($exif['GPSLongitude'], $exif['GPSLongitudeRef']);
        $lat = getGps($exif['GPSLatitude'], $exif['GPSLatitudeRef']);
        echo "<br />\n";
        echo "Bildfil: <a href='$newfile'>Visa bild</a><br />\n";
        echo "Longitud: $lon<br />\n";
        echo "Latitud: $lat<br />\n";
        echo "Höjd: $alt<br />\n";
        echo "Riktning: $dir<br /><br />\n";
        echo "Kamera tillverkare: $emake<br />\n";
        echo "Modell: $emodel<br />\n";
        echo "Exponering: $eexposuretime s<br />\n";
        echo "F-numer: $efnumber<br />\n";
        echo "ISO: $eiso<br />\n";
        echo "Tidpunkt: $edate<br />\n";

      }  
    }
  }
}
else
  {
  // Om det inte är rätt filtyp eller storlek...
  echo "Endast JPG/JPEG filer mindre än 8 Mb är tillåtna...";
  }

?> 
</body>
</html>

I filen ovan så finns även två funktioner som används för att räkna om GPS-information i EXIF data i filerna. Dessutom så kommer en hel del andra EXIF data läsas och skrivas ut på skärmen. Om det finns positionsdata så lagras dessa i variablerna $lat och $lon, vilket gör det enkelt att infoga en leafletkarta panorerade till rätt plats, kanske med en ”pin” som markör.

Lägg bara till html-kod, som i tidigare inlägg, för att skapa webbkartan och ”skjut in” koordinaterna från PHP-skriptet i Javaskriptet som JSON data:

<SCRIPT>
var map = L.map('map', {
  center: [<?php echo json_encode($lat); ?>, <?php echo json_encode($lon); ?>],
  zoom: 10
});
// Här läggs alla lager till
</SCRIPT>

Det är inte en komplett kod som visas ovan, utan endast hur du infogar PHP kod i Javascript. Vill du se ett exempel på hela koden så ladda hem exempelfilerna från GitHub längre ner.

Skärmbild från 2014-02-01 23:42:03

Om du följt med i serien med hur du skapar en egen server för geodatatjänster, eller om du har en linuxserver med PHP installerat så kan du snabbtesta det jag beskrivet här med nedanstående kommandon. Börja med att gå till en katalog på din webbserver (exempelvis: /var/www ).

sudo mkdir upload
sudo chmod 777 upload
sudo wget https://github.com/klakar/geosupportsystem/raw/master/ladda.htm
sudo wget https://github.com/klakar/geosupportsystem/raw/master/ladda.php

Öppna sidan ”ladda.htm” i webbläsaren Nu skall du förhoppningsvis kunna ladda upp bilder upp till 2 Mb utan felmeddelande och om du ändrar i php.ini enligt det som beskrivits ovan så kan du ladda upp 8 Mb. Jag har snyggat till koden lite i de filer du kan ladda hem ovan, och det ser även lite snyggare ut på skärmen.

Lycka till.