Categoriearchief: Code tutorials

SVG animaties met snap.svg

SVG is bedoeld om vector illustraties op het web te tonen. De structuur van de taal bestaat namelijk uit xml. Daarom is het ook gemakkelijk om svg objecten te beïnvloeden met javascript.

Snap.svg is een javascript library die daar heel mooi gebruik van maakt. Zo kun je gemakkelijk zelf keigave animaties en ander interactieve applicaties bouwen.

http://snapsvg.io/

Voor mijn porftolio intro wilde ik een kameleon animeren die met zijn tong een duizendpoot vangt en vervolgens op eet. Het resultaat kun je bekijken op http://daniel-dewit.nl als je een paar keer naar beneden scrollt. Het eerste wat ik nodig had was een svg-illustratie van  een kameleon. Die heb ik in het programma Inkscape gemaakt.

https://inkscape.org/en/

chameleon_compiled

Inkscape is een handig programma omdat het gebaseerd is op het svg formaat. Illustraties die je maakt in Inkscape worden dus standaard opgeslagen als svg-afbeelding. Als je een svg-afbeelding voor het web wilt maken is het wel belangrijk om bij het opslaan te kiezen voor ‘geoptimaliseerde svg’. Er wordt dan leesbare code gegenereerd en je krijgt dan een aantal extra opties zoals het instellen van een viewbox. Viewbox is belangrijk bij het maken van responsive svg-afbeeldingen.

inkscape-export

Als je de afbeelding hebt opgeslagen kun je die openen in een tekst-editor en alle code er uithalen om in je webapplicatie te gebruiken. De volgende stap is om je svg-afbeelding met snap aan een javascript variabele te binden. Dat doe je met de functie Snap(). Daarna kun je onderdelen uit je svg-afbeelding aan aparte variabelen binden met select() zodat je die kunt animeren.

var chameleon = Snap("#chameleon");
var chameleonWrap = chameleon.select("#chameleon-wrap"); 
var chameleonMaw = chameleon.select("#chameleon #jaw"); 
var chameleonTongue = chameleon.select("#chameleon #tongue");
var chameleonHead = chameleon.select("#chameleon #head");

Nu heb ik een svg-afbeelding gemaakt en die verbonden met javascript variabelen. Er beweegt echter nog niets en dat is natuurlijk wel wat we willen doen. Snap.svg heeft daar een mooie functie voor, genaamd animate(). Met die functie kun je een nieuwe positie aangeven, de tijd die de animatie in beslag neemt en een versnellingsfunctie.

In mijn geval wil ik eerst de kaak openen voordat de tong uit de bek van de kameleon schiet. Daarvoor moet ik eerst weten hoe de functie animate() precies werkt. Die functie accepteert namelijk voor de nieuwe positie een array met svg-attributen. Om een vlak uit de svg-afbeelding te draaien moet ik het attribuut ‘transform’ aanpassen met de functie rotate(). En in die functie kun je de graden van de draaihoek en de x- en y-positie van de as aangeven. Bij mij wordt dat dan transform=”rotate(-20, 260, 110)”. In de snap functie animate() ziet dat er weer een klein beetje anders uit:

chameleonHead.animate({transform: 'r-20, 260, 110'}, 500, mina.easein);
chameleonMaw.animate({transform: 'r30, 260, 110'}, 500, mina.easein);
chameleonTongue.animate({transform: 'r20, 260, 110'}, 500, mina.easein);

Wanneer je dit script uitvoert in de browser zullen het hoofd en de tong en kaak van de kameleon in een halve seconde een draai maken. Maar nu wil ik ook nog de tong uit de bek laten schieten en tegen de duizendpoot laten botsen. Dat is iets ingewikkelder omdat ik daarvoor een pad moet aanpassen. In de code is dat niet te doen, maar met Inkscape is dat een stuk makkelijker.

Eerst draai ik ook in inkscape het hoofd, de kaak en de tong van de kameleon zodat de tong tevoorschijn komt op het canvas. Dat doe ik door de XML-editor te openen (bewerken > XML-editor) en de juiste elementen op te zoeken. Vervolgens kan ik in de editor het attribuut ‘transform’ toevoegen en de functie rotate() invullen.

inkscape xml editor rotate

Als ik dat heb toegepast kan ik op het canvas de tong bewerken door simpelweg pad-punten te verslepen. Tenslotte moet het pad weer terugvertaald worden naar een code. Die vind ik terug door in de XML-editor het pad van de tong op te zoeken en het attribuut ‘d’ aan te klikken. De code die dan tevoorschijn komt kan ik kopiëren en gebruiken met snap.svg.

inkscape xml editor

chameleonTongue.animate({d: 'm 254.142,105.465 c -0.91945,-4.73936 212.92389,-28.907989 374.41877,-26.893877 14.68355,0.183128 30.33905,15.332279 43.93075,15.714335 17.63322,0.495662 25.77761,-27.528571 41.00876,-25.899587 12.10879,1.295046 21.50394,13.74826 29.96377,19.69398 17.4323,12.251739 18.0602,-38.721554 26.41324,-35.997065 18.82566,6.140313 10.78299,32.752814 12.73743,45.135922 1.70453,10.799752 19.51626,40.672592 2.80281,46.348052 -5.31187,1.80377 -15.86623,-33.98243 -36.06211,-32.1603 -18.51088,1.6701 -24.00996,-14.403424 -36.34335,-12.354748 C 700.70693,101.0957 690.0714,117.01068 675.42381,116.11625 658.40639,115.07712 631.04537,95.873998 612.28816,95.29318 480.63912,91.216661 328.49376,115.83493 322.005,118.183 c -13.249,3.929 -66.362,-4.981 -67.863,-12.718 z'}, 100, mina.linear);

Handig om te weten is dat de animate() functie ook een callback accepteert. Op die manier kun je nadat je animatie klaar is een nieuwe animatie uitvoeren door opnieuw de animate() functie aan te roepen.

chameleonTongue.animate({transform: 'r0, 260, 110'}, 500, mina.easein,function() {
    chameleonTongue.animate({transform: 'r15, 260, 110'}, 500, mina.easein);
});

Responsive Font-size met ‘%’ ‘px’, ‘em’ of ‘rem’

Stel dat je een website bezoekt op je desktop. Het normale lettertype grootte op een desktop is 16 pixels, maar veel webdesigners schalen dat naar beneden omdat de website op meerdere types schermen bekeken moet worden. Het gevolg is dat je met je ogen veel te dicht op je scherm gaat zitten om de tekst nog te lezen. Dezelfde situatie maar dan andersom doet zich voor als je de website op een mobiel bekijkt. Omdat de letters nu supergroot zijn moet je je mobiel bijna een meter van je gezicht afhouden om comfortabel te kunnen lezen. Op dit moment denk je misschien, zou het niet veel mooier zijn als de grootte van het lettertype zich aanpast aan de grootte van het scherm dat je op dat moment gebruikt. Nou, dat kan.

Sinds versie 3 van css is het mogelijk om zogenaamde media-queries te gebruiken op je website. Je kunt dan per type scherm instellen wat de website moet laten zien. Hieronder een voorbeeld van hoe je stylesheet eruit zou kunnen zien als je een desktop, een tablet en een mobiel wilt ondersteunen, dat mobile-first doet, en je pixels gebruikt om je lettergrootte in te stellen.

h1 { font-size: 16px;}

h2 { font-size: 12px;}

p { font-size: 10px;}

 

@media all and (min-width: 980px) {

h1 { font-size: 20px;}

h2 { font-size: 14px;}

p { font-size: 12px;}

}

 

@media all and (min-width: 1260px) {

h1 { font-size: 24px;}

h2 { font-size: 18px;}

p { font-size: 16px;}

}

Probleem opgelost? Niet dus. Want versies 8 van Internet Explorer en lager ondersteunen geen pixels als eenheid om lettergroottes mee in te stellen. En anno 2014 zijn er nog steeds legio bedrijven die een verouderde versie van internet explorer gebruiken. En wie neemt hen dat kwalijk, met hun eigenwijze systeembeheerders die niets zien in vernieuwing (lees: extra werk).

Nu komt de eenheid ‘em’ in beeld. Em wordt gebruikt als relatieve eenheid, zodat Internet Explorer je webpagina netjes kan schalen. Wanneer je de standaard lettergrootte van het document op 16px laat staan, zal een h1 element met een lettergrootte van ‘1.5em’ anderhalf keer zo groot zijn als 16 pixels, 22 pixels dus. Alleen het vervelende em is dat het als basis lettergrootte niet de standaard lettergrootte van het document neemt, maar de lettergrootte van het omvattende element. Heb je dus een standaard lettergrootte van 16 pixels, een div element met een lettergrootte van 0.8em, en daarin een p element met een lettergrootte van nog eens 0.8 em, dan wordt je lettergrootte in pixels 16 * 0.8 * 0.8 = 10,24 pixels, en dat slaat natuurlijk nergens op. Laat staan dat het makkelijk is om mee te rekenen. Eigenlijk schiet je met ‘em’ dus niets meer op dan wanneer je procenten gebruikt om je lettertypes te schalen, wat net zo min is aan te raden.

En daarom is er in versie 3 van css nog iets nieuws uitgevonden. De eenheid ‘rem’, wat staat voor root-em. Met rem hoef je niet steeds rekening te houden met de lettergrootte van het omvattende element, maar hoef je maar één keer de lettergrootte van het document in te stellen waarna je dat rem overal x aantal keer kunt vergroten of verkleinen.

Als je bovendien de lettergrootte van het document op 62.5% instelt kun je heel gemakkelijk zien op welk aantal pixels de lettergrootte uitkomt,  want want 16px * 0,625 = 10 pixels. 2.4rem is dan gewoon 24 pixels als je het omrekent. Wanneer je je website vervolgens responsive maakt wordt alles nog makkelijker omdat je alleen de lettergrootte van je document hoeft aan te passen, de rest wordt automatisch mee geschaald. Hieronder laat ik zien hoe je stylesheet er dan uitziet. Speciaal voor browsers die rem niet ondersteunen heb ik nog wel het aantal pixels ingesteld. Daarna stel ik steeds het aantal rem in zodat nieuwe en moderne browsers een relatieve lettergrootte gebruiken.

 

html { font-size: 62.5%)

h1 { font-size: 16px; font-size: 1.6rem;}

h2 { font-size: 12px; font-size: 1.2rem;}

p { font-size: 10px; font-size: 1.0rem;}

 

@media all and (min-width: 980px) {

html { font-size: 80%; }

}

@media all and (min-width: 1260px) {

html {font-size: {font-size: 100%;}

}

Hieronder staat bij bron 3 een link naar een webpagina waarbij ik het lettertype op deze manier responsive heb gemaakt. Als je de pagina op een desktop opent kun je het venster verkleinen en vergroten om eens te kijken welk effect dat heeft op de grootte van het lettertype.

Bronnen

1. http://www.w3schools.com/css/css_font.asp
2. http://snook.ca/archives/html_and_css/font-size-with-rem
3. http://www.daniel-dewit.nl/wp-content/Responsive%20design/index.html

On scroll footer

Voor mijn werk liep ik tijdens het bouwen van een website voor een klant tegen een probleem met een footer aan. De klant wilde graag dat de footer altijd te zien was ondanks hoe groot of hoe klein het scherm van de gebruiker was. Hij kwam zelf met het voorstel om de gehele website te verkleinen, maar dat is natuurlijk niet mooi in verband met leesbaarheid en ruimtegebruik. Na wat hersenwerk bedacht ik me dat sommige website een dynamische header gebruiken, die kleiner wordt als je naar beneden scrollt op de webpagina, maar wel altijd bovenin zichtbaar blijft.

Het leek me de ideale oplossing omdat principe op de footer in de website van de klant te los te laten. Echter tot mijn verbazing bleek dat er talloze jquery scripts waren voor zulke dynamische headers, maar geen enkele voor een dynamische footer. Na wat zoekwerk bleek dat de oorzaak lag bij jquery, die wel een functie voor scrollTop hadden, maar geen functie voor scrollBotttom die nodig is voor een dynamische footer. Gelukkig was de oplossing zoals altijd op internet te vinden, en was er al iemand geweest die in één regeltje code een vervangen voor scrollBottom had geschreven. Met behulp van dat stukje code kon ik toen mijn eigen script schrijven, dat heel simpel de class van de footer aanpast zodra je de onderkant van de pagina hebt bereikt. Zo kun je de footer twee uiterlijken geven, een grote voor de onderkant van de pagina en een kleine voor als de gebruiker niet aan de onderkant van de pagina is en er weinig ruimte beschikbaar is.

$(document).ready(function() {
    if ($(document).height() > $(window).height()) {
        $("#footer").addClass("footersmall");
    }
    else {
        $("#footer").addClass("footerbig");
    }    
    $(window).scroll(function() {
        var scrollBottom = $(document).height() - $(window).height() - $(window).scrollTop();
        if (scrollBottom > 170) {    
            $("#footer").addClass('footersmall').removeClass('footerbig');
            $(".footerspace").css('display', 'block');        
        } else {  
            $("#footer").addClass('footerbig').removeClass('footersmall');
            $(".footerspace").css('display', 'none');        
        }
    });     
});

Een aantekening bij het script is wel dat de footer twee statische hoogtes nodig heeft wil dit script goed werken. Zodra de footer namelijk kleiner wordt zal er onzichtbare ruimte onder de pagina toegevoegd worden, en die moet hetzelfde zijn als de hoogte van de grote footer. Ook is er een vaste waarde die bepaald vanaf welk aantal pixels scrollen vanaf de onderkant de gebruiker een kleinere footer krijgt voorgeschoteld. Maar als je al die waarden goed hebt ingesteld krijg je een footer die vloeiend groter of kleiner wordt afhankelijk van hoever de gebruiker naar beneden scrollt, en dat loont.

Een werkend voorbeeld is te zien op http:www.vizoverwarming.nl/, de website van de klant waar ik het script voor geschreven heb.

Update: Inmiddels is de werking van het script niet meer te zien op de website van de klant.