Norwegian Open 2011
1. og 2. oktober dro Team Rambo til Kongsvinger for å delta på det aller første Norwegian Open, et nytt storstevne dratt i gang av en gjeng ildsjeler innen agilityen (bla. vår egen Arne). Stevnet foregikk på kunstress innendørs, noe som funket fint for oss da vi deltok på Sortland.
Ellen og jeg delte på kjøringa, og vi skulle bo på Sigernessjøen Camping med Trine, Agnete, Kari, Tina, Helge, Julie, Anniken og Madlen. På veien nedover møtte vi også andre ekvipasjer med samme destinasjon. Et stykke før vi kom til Kongsvinger ble vi passert av en sykebil, og litt lenger fremme møtte vi en skummel elgpåkjørsel. Vi så to dyr i veikanten (et levende og et dødt), og en bil som var ganske knust. Ambulanser mm. var på plass. Ellen fant en artikkel om påkjørselen etter at vi var kommet hjem igjen. Skumle greier at vi bare var noen minutter bak, bekmørkt langs veien var det også. Fikk veldig lyst på svære 1000-metringer igjen.
Lørdagen startet Rambo med A2L, men det gikk ikke spesielt bra. Han luntet gjennom banen, men var mest opptatt av hva som skjedde utenfor ringbåndene. Tunnelcupen (bare tunneler som hindre) gikk bedre, men farten var ikke noe å skryte av da heller. Vi kom gjennom med én vegring og 6,54 tidsfeil, som ga oss 22.-plass. Deretter var det H2L, som var et lite løft i forhold til dagens to første løp. Feilfri gjennomføring og napp, men bare 8.-plass, hele 8 sekunder bak vinneren. Til slutt var det Norwegian Open-løpet, men da var det lite krefter å hente i puddelskrotten. Vegring + 6,31 feilpoeng = 26.-plass, 15. sekunder bak vinneren.
På ettermiddagen spiste vi middag med en del andre fra klubben, hyggelig med sosialt samvær! Den helt store festen ble det ikke, siden vi skulle opp tidlig igjen på søndag.
Søndagen begynte jeg å bli ganske snørrete. Om det var allergi eller forkjølelse er ikke godt å si, men kortisontablettene hjalp ikke særlig mye iallfall. Etter at vi hadde gått H2L (5,92 feilpoeng = 8.plass) skulle supertante Ellen hente Rambo i bilen, og da de kom tilbake hadde hun lagt merke til at han var halt på ene bakbeinet. Vi gikk løpet likevel, i håp om at han bare var litt støl etter å ha ligget, og det gikk greit. Men han var like halt etterpå, så jeg tenkte at det fikk være avslutningen på dagen. Greit å kunne kjøre hjem i riktig tid også, særlig siden min egen form ikke var på topp heller. Takk til Ellen som tok første etappe, slik at jeg fikk ligge med snørrhodet bakover og slappe av
Ingen av løpene fra stevnet ble filmet, siden de fleste var opptatte med egne løp og å bidra i ringene. Det var nok generelt høyt stressnivå for å rekke alt man skulle gjøre, om man ikke i tillegg skulle løpe rundt og filme
Selv om resultatene ble så som så, synes jeg stevnet var flott. Bra opplegg, og godt gjennomført. Det var et trangt tidsskjema, men jeg tror stort sett det holdt i alle ringene, takket være stram regi.
Team Rambo ser fram til å delta i 2012 også!
Status etter stevnet: 2 napp i A2, 6 napp (ferdignappet) i H2. I 2013 blir det H3
Agilitystevne på Sortland og Bodø/Tverlandet 2011
I år kombinerte vi to stevner med familiebesøk i Bø. Det er en liten times kjøring fra Bø til Sortland, så vi kjørte frem og tilbake på dagen. Morsomt å skulle konkurrere på «hjemmebane»
Sortland
Stevnet foregikk på kunstgress i Blåbyhallen. Vi har ikke konkurrert verken innendørs eller på kunstgress før, men det var en positiv opplevelse. Dekket kjentes mykt og behagelig å løpe på, og Rambo brydde seg ikke om støynivået i hallen. Det foregikk utstilling parallellt med agilityen, med mye bruk av speakeranlegg, men det bød ikke på noen problemer. Greit å vite før Norwegian Open.
Banene på lørdag bar preg av å ha blitt tegnet/bygget av en som ikke trener agility til vanlig. Ikke spesielt krevende, men til gjengjeld var det gjerne 12-14 meter mellom hindrene. Mye løping og lite handling. Søndag var det bedre, da de var satt av en utøver fra Narvik Trekk- og Brukshundklubb.
Resultatene var ikke så mye å skryte av. Det var et bittelite agilitystevne, med bare én hund i A2L og H2L (Rambo) så det var på et vis «vinn eller forsvinn». Vi fikk et napp i H2L lørdag, resten av løpene var så som så. Dessverre ble det mye fusk på slalomen i helga, og jeg mistenker at Rambo ble usikker og mistet rytmen fordi slalomføttene stakk ut på feil side, altså der han vanligvis lander når han spretter frem og tilbake. Ser en del tripping og rare taktskifter på opptakene iallfall.
Bodø/Tverlandet
På vei fra Bø til Trondheim stoppet vi hos Bjørn-Ruben for å være noen dager på besøk, pluss gå agilitystevne. Stevnet ble holdt utendørs på Tverlandet idrettsbane, og været var ganske grått. Det ble lite fokus og mye virring i løpene på lørdagen, så jeg bestemte meg for å droppe søndagen, og heller kjøre tidligere hjemover. Tross alt 9 timers kjøring fra Fauske til Trondheim, og det var greit å kunne komme hjem før leggetid.
Status etter helga
2 napp i A2, 5 napp (ferdignappet) i H2.
Bartebuss – the beginning
Tidlig i sommer snublet jeg over et prosjekt kalt BusBuddy, hvor noen studenter ved IDI hadde laget et kult busskart med sanntidsdata fra AtB. Men de hadde ikke bare stoppet der, de hadde også lagd et API for å dele rådataene. Siden AtB offisielt enda ikke hadde gjort dette selv, var det nesten som en liten «undergrunnsbevegelse» av bussnerder som begynte å mekke smarte løsninger, meg selv inkludert.
Jeg hadde lyst å lage en mobilvennlig webapp, heller enn noe som bare funket på Android eller iOS (iPhone etc). Trafikantens presentasjon av ruteinfo for buss/trikk i Oslo var utgangspunktet, og jeg satte i gang å leke. Det skulle bli en HTML5- og JavaScript-drevet «dings» som ikke krevde pageloads, som var rask, så bra ut og utnyttet nye HTML5-muligheter, som f.eks. å bufre data og hente brukerens posisjon.
Resultatet av det jeg beskriver under finnes på bartebuss.no, samt som Android-appen Bartebuss på Android Market.
Dette kommer til å bli en ekstremt nerdete, usammenhengende og lang bloggpost. Du er herved advart!
Rammeverket
En webapp bør se ut og oppføre seg litt annerledes enn en vanlig webside, blant annet ville jeg ikke ha mulighet til zooming siden appen likevel skulle bruke standard fontstørrelse og være full skjermbredde, og jeg ville kunne angi pene, store ikoner og splash-screens. iPhone kan kjøre sider i webappmodus (uten adresse- og verktøylinjer), det ville jeg også dra nytte av.
Til slikt finnes det mange fine meta-elementer man kan bruke.
<!-- Full bredde, ingen zooming --> <meta content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no" name="viewport"> <!-- Tillat å kjøre i fullskjermmodus i iOS --> <meta name="apple-mobile-web-app-capable" content="yes"> <!-- Ikoner og splashscreens for alle varianter av iOS (iPhone/iPad/iPhone retina) --> <link rel="apple-touch-icon" href="/img/icon-57x57.png" /> <link rel="apple-touch-icon" href="/img/icon-72x72.png" sizes="72x72" /> <link rel="apple-touch-icon" href="/img/icon-114x114.png" sizes="114x114" /> <link rel="apple-touch-startup-image" href="/img/splash-748x1024.png" media="screen and (min-device-width: 481px) and (max-device-width: 1024px) and (orientation:landscape)" /> <link rel="apple-touch-startup-image" href="/img/splash-768x1004.png" media="screen and (min-device-width: 481px) and (max-device-width: 1024px) and (orientation:portrait)" /> <link rel="apple-touch-startup-image" href="/img/splash-320x460.png" media="screen and (max-device-width: 320px)" />
For Android må man jukse litt for å unngå konflikt med iOS-ikonene.
if(navigator.userAgent.match(/Android/i))
$('head').append('<link rel="apple-touch-icon-precomposed" href="/img/icon-114x114.png" />');
Siden verktøylinjene i browseren forsvinner når man kjører i webappmodus, startet jeg med å bygge en verktøylinje med utgangspunkt i hvordan Seesmic og Facebook gjør det. All HTML for denne, pluss skjelett for alle undersidene, ble plassert i én HTML-fil, slik at lasting av undersider ble unødvendig. Målet var i tillegg å bruke minst mulig PHP i brukerens ende, slik at mest mulig kunne kjøres client-side.
HTML5 history
For å slippe pageloads, men samtidig ikke ødelegge tilbake-knappen tok jeg i bruk HTML5 history. Det fungerer slik at man dytter en URL og en sidetittel på en stack, sammen med et JSON-objekt som beskriver en tilstand (state). Man velger selv hvordan man ønsker å bygge state-objektet sitt, så lenge man greier å gjenskape den forrige siden basert på dataene det inneholder. Jeg valgte å ta vare på sidens ID, hvilken fane i appen det tilsvarte, og dobbeltlagre lenka.
var state = {
'page': page.attr('id'),
'tab': tab.attr('id'),
'link': link
};
history.pushState(state, null, link);
For hvert pushState man gjør, får man et ekstra innslag i historikken å gå tilbake til. Samtidig endres URLen i adressefeltet, akkurat som om man hadde lastet en ny side. For å unngå å skape et logginslag ved første sidelasting (men samtidig gjøre det mulig å gå tilbake dit), bruker man replaceState ved første pageload. Litt logikk for å finne ut hva som er første er naturligvis også nødvendig.
Når brukeren trykker tilbake-knappen trigges en popstate-event, denne må man knytte en handler til.
$(window).bind('popstate', function(e){
// Hent det gamle state-objektet fra eventen (eller originalEvent for jQuery)
var previousState = e.originalEvent.state;
// Gjør noe magisk, last riktig side, sett riktige variabler osv.
});
Handleren gjør det som er nødvendig for å gjenskape hvordan den forrige siden så ut.
Direktelenker til tilstand
Hvis man ønsker å la det være mulig å gå direkte til lenker/tilstander inni appen (direkte til en søkeside el.l.) må man sjekke sidens URL ved lasting, og gjøre de nødvendige tingene derfra. Jeg brukte JQuery URL Parser plugin, og trigget klikk/tap på lenkene/knappene som normalt fører brukeren til angitt tilstand/side.
var urlSegment = $.url().segment(1);
switch(urlSegment){
case 'alle':
case 'sok':
$('#searchTab a').trigger('tap');
break;
case 'orakel':
$('#oracleTab a').trigger('tap');
break;
case 'kart':
$('#mapTab a').trigger('tap');
break;
...
}
Det er en god grunn til at jeg ikke trigger en click-event, men heller den egendefinerte tap-eventen, mer om det under.
HTML5 localStorage
Å jobbe med ca 1400 holdeplasser for Trondheimsområdet betød at det ville være en fordel å mellomlagre alle på mobilen, heller enn å laste dem ned hver eneste gang. Jeg skrev derfor et script som lastet dem ned én gang, lagret dem i localStorage, og kun oppdaterte hvis lista var over en uke gammel – eller den fikk beskjed om å oppdatere seg (ved viktige endringer).
For å avsløre om brukerens enhet/browser støttet forskjellig «ny» funksjonalitet tok jeg i bruk Modernizr. Datoer tok jeg hånd om med date.js.
$.ajax({
url: 'http://api.busbuddy.no/api/1.2/busstops?callback',
dataType: 'jsonp',
jsonpCallback: 'busbuddyResponse',
data: {'apiKey': xxx},
timeout: 5000,
success: function(data){
if(Modernizr.localstorage){
localStorage.setItem(
'busStops',
JSON.stringify(data.busStops))
localStorage.setItem(
'lastUpdated',
Date.today().setTimeToNow().toString(bartebuss.timeformat));
}
stops = data.busStops;
},
error: function(){...},
complete: function(){...}
});
Tap delay
Selv gode webapps føles tregere enn native apps, og en av grunnene er at det i browseren er en forsinkelse på omkring 300 ms fra brukeren berører skjermen til en klikk-event sendes. Årsaken er at browseren venter på et evt. dobbelklikk, som brukes hvis man vil zoome inn på en bestemt del av siden.
Denne forsinkelsen får man ikke fjernet, men man kan velge å lytte til touchstart-eventen, heller enn click-eventen.
Det finnes forskjellige script som mener å løse problemet, men de fleste har mangler. Ulempen er at det i browsere på enheter uten touch-skjerm ikke fyres touchstart, bare click. Man trenger dermed en fallback i disse tilfellene. Man kan likevel ikke lytte til begge eventene på én gang, fordi Safari på iOS fyrer både touchstart og click (etter 300 ms), og man får da dobbelt opp. Først touchstart, og så click 300 ms senere. Hvis man rekker å endre til en ny side innen de 300 ms, havner click-eventen på den nye sida, heller enn på den opprinnelige knappen/lenka, og ting begynner å skje av seg selv. Veeeldig frustrerende å debugge.
Heldigvis løser jQuery.tappable plugin problemet rimelig greit. Android 2.1 hadde problem med at klikkene døde med mindre man var veldig lett på fingeren, fordi den trodde fingeren hadde flyttet seg mellom touchstart og touchend. Jeg løste det ved å hacke inn en buffersone på noen få piksler rundt berøringsstedet. Jeg la også til min egen tap-event, som jeg kunne trigge for å simulere en berøring eller et klikk – avhengig av hvilken enhet brukeren hadde.
$('#backButton').tappable(function(){
history.back();
});
Siste rest av weben
Fremdeles er det småting som avslører web vs. native app, f.eks. markeringen/outline browseren legger på områdene man berører/klikker, samt klipp-lime-funksjonen. Dette løser man enkelt i CSS.
/* Ingen klipp-lim */
-webkit-user-select: none;
/* Ingen popups på siden */
-webkit-touch-callout: none;
/* Ingen markering av "berørt" område */
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
/* Ingen automatisk tekstskalering */
-webkit-text-size-adjust: 100%;
/* Hvis man er dristig kan man fjerne outline på lenker/knapper osv også */
input[type=submit],
button,
a.knapp {
outline: none;
}
Det siste avslørende momentet overshoot på scrolling, altså at man kan trekke siden opp/ned og få en gummistrikkeffekt om der ikke er mer innhold å vise. Det kan skrus av ved å fikle med touchmove-eventen, men siden jeg ønsker å ha rulling på siden likevel (pga. lange lister) har jeg ikke tatt meg bryet med å ordne en «fast» side.
Installering
På iPhone/iPad er det veldig enkelt å «installere» en webapp. Alt man trenger gjøre er å legge til et bokmerke på hjem-skjermen, og vips får man et pent ikon med runde kanter og gloss. (Gitt at man har fulgt oppskriften over). Når man starter webappen derfra forsvinner verktøylinjene og appen vises i fullskjerm-/webappmodus. På Android må man først lage et bokmerke, og deretter plassere bokmerket på hjem-skjermen. Litt mer omstendelig, men man oppnår også da et pent ikon. Splash og fullskjermmodus må man dog være foruten.
Hvis man ønsker/tør å plage brukerne en ekstra gang for å få dem til å «installere» (dvs. bokmerke) appen, kan man legge til en «maseboble» (annen variant) som spretter opp og ber brukeren om å legge til et bokmerke.
Jeg brukte Googles variant i starten, men bestemte meg for å fjerne den i tilfelle den var til bry og irritasjon.
Da skulle basiskunnskapen være på plass for å lage en god og rask webapp, som det vil kreve et trent øye for å skille fra en native app.




