Maak een Web­gl-da­ta­vi­su­a­li­sa­tie

Zet ex­ter­ne da­ta over aard­be­vin­gen met Three.js van­uit JSON op een drie­di­men­si­o­na­le aard­bol .

Web Designer Magazine - - Inhoud -

Zet ex­ter­ne aard­be­vings­da­ta van­uit JSON met three.js op een drie­di­men­si­o­na­le we­reld­bol.

Je ziet steeds meer da­ta­vi­su­a­li­sa­ties op in­ter­net. Veel on­li­ne kran­ten ma­ken in toe­ne­men­de ma­te ge­bruik van zul­ke ge­ge­vens. Ze pre­sen­te­ren da­ta re­gel­ma­tig op een in­ter­ac­tie­ve ma­nier om hun le­zers zo meer bij de ver­ha­len te be­trek­ken. Er zijn zelfs spe­ci­fie­ke bi­bli­o­the­ken ge­wijd aan het ma­ken van gra­fie­ken en het vi­su­eel weer­ge­ven van da­ta. Het eni­ge pro­bleem bij het ge­bruik van som­mi­ge van die bi­bli­o­the­ken is dat ze een be­perkt aan­tal ma­nie­ren heb­ben om de da­ta te la­ten zien. Daar­door zie je soms met­een pre­cies wel­ke bi­bli­o­theek ge­bruikt is, om­dat je het sja­bloon er dui­de­lijk in her­kent.

In de­ze tutorial ge­brui­ken we de mo­ge­lijk­he­den van Three.js voor het aan­stu­ren van Web­gl-con­tent om een ver­bluf­fen­de vi­su­a­li­sa­tie van de aar­de te ma­ken. We la­den ru­we da­ta via XHR om een Js­on­be­stand met da­ta over de lo­ca­tie en kracht van aard­be­vin­gen te krij­gen. De­ze da­ta be­vat­ten de leng­te­graad en de breed­te­graad van de be­ving. Die zet­ten we om naar een Xyz-ruim­te, zo­dat we ze op ons aar­de­mo­del kun­nen plaat­sen. Als je een­maal weet hoe je de leng­te- en breed­te­gra­den kunt over­zet­ten naar een bol, kun je die tech­niek ge­brui­ken om wel­ke lo­ca­tie­da­ta dan ook te vi­su­a­li­se­ren. Het is he­le­maal aan jou hoe je de aard­be­vin­gen er­uit laat zien. In de tutorial ge­brui­ken we lij­nen die van­af de aar­de om­hoog ko­men, maar je zou ook bol­len of an­de­re vor­men kun­nen ge­brui­ken. Je zou de lij­nen zelfs kun­nen om­ke­ren en de aar­de in la­ten gaan om de diep­te van de aard­be­ving aan te ge­ven. Als je be­grijpt hoe je da­ta toe­past op het mo­del, kun je ver­der zelf de weer­ga­ve ver­fij­nen. He­laas werk­te de vi­su­a­li­sa­tie bij on­ze tests niet goed in Chro­me.

1. Start het pro­ject

Open de map ‘start’ van de pro­ject­be­stan­den in je code-edi­tor. Als je de pa­gi­na in­dex.html opent, zie je dat al­le bi­bli­o­the­ken en CSS- en Html-con­tent al toe­ge­voegd zijn, com­pleet met de be­no­dig­de va­ri­a­be­len. Scrol door naar re­gel 109 en voeg de vol­gen­de twee func­ties toe om waar­den om te zet­ten naar een an­de­re ran­ge en om vast te stel­len hoe­veel ge­ge­vens er ge­la­den zijn: func­ti­on map(n, start1, stop1, start2, stop2) {

re­turn ((n - start1) / (stop1 - start1)) * (stop2 - start2) + start2; } func­ti­on lo­a­der() { lo­a­ded++; if (lo­a­ded >= toload) {

var co­ver = do­cu­ment. ge­tele­ment­by­id(“pre­lo­a­der”); co­ver.sty­le.vi­si­bi­li­ty = ‘hi­d­den’; ani­ma­te();

} }

2. Ini­ti­a­li­seer de 3D-scè­ne

De code ini­ti­a­li­seert de 3D-scè­ne in het brow­ser­ven­ster. Er wordt een nieu­we ca­me­ra aan­ge­maakt met in­stel­lin­gen om de scherm­breed­te en -hoog­te te ren­de­ren. We ge­ne­re­ren een nieu­we scè­ne en voe­gen wat mist toe zo­dat elementen ver­der van de ca­me­ra niet zicht­baar wor­den in de vie­w­port. func­ti­on init() { sta­tus.in­ner­ht­ml = “Loa­ding Ima­ges”; var con­tai­ner, par­ti­cles, par­ti­cle; con­tai­ner= do­cu­ment. c re a te ele­ment (‘ di v ’); do­cu­ment. bo­dy. a p pen d chi l d( con­tai­ner ); ca­me­ra= new T h ree. per spe ct i v e ca­me­ra (75, SCREEN_WIDTH / SCREEN_HEIGHT, 1, 10000); ca­me­ra. po sit ion. y =100; sce­ne = new THREE.SCE­NE(); sce­ne.fog = new THREE.FOGEXP2(0X000000, 0.004);

3. Zet de ren­de­rer op

Nu wordt de ren­de­rer aan­ge­maakt en de an­ti­a­li­a­sing op true ge­zet om de ran­den van modellen vloei­en­der te ma­ken. We ge­ven de ren­de­rer een don­ke­re blauw­groe­ne ach­ter­grond­kleur, stel­len hem weer in op de groot­te van het brow­ser­ven­ster en voe­gen hem dan toe aan de Html-pa­gi­na. ren­de r er= new T h ree. web g l ren­de r er ({

an­ti­a­li­as: true }); ren­de r er. set cl e ar­co lor (0 x 030 f 0 f ); ren­de r er. set pixel ra­tio( win dow. de­vi­ce­pixel­ra­tio); ren­de r er. sets i ze( s c reen_ w id t h, SCREEN_HEIGHT); con­tai­ner. a p pen d chi l d( ren­de r er. dom ele­ment );

4. Voeg fo­to’s in

We ge­brui­ken ver­schil­len­de sha­ders om het beeld nat e be­werk enen dat da nop het schermt e ren­de­ren. Hier zie je da­te r ver­schil­len­de ver­sto­ring sef­fec­ten a an­te pas ko­men, zo­als slech­te tv, Rg b ka­naal split­sin­gen film effecten zo­als scan l in esen ruis. ren­der­pass = new Three.ren­der­pass (sce­ne, ca­me­ra); badt­vpass = new Three.sha­der­pass (T H REE. BAD T VS H ADER ); rg­b­pass = new Three.sha­der­pass (T H REE. RGB SHIFT S HA DER ); film­pass = new Three.sha­der­pass (Three.film­s­ha­der); co­py­pass = new Three.sha­der­pass (Three.co­py­sha­der); film pass. uni­form s. g ray s c al e. val u e =0;

5. Stel beeld sa­men

Nu al­le sha­ders ge­maakt zijn, voe­gen we een ef-

fect-com­po­ser toe. Met de­ze com­po­ser wor­den de sha­ders stuk voor stuk toe­ge­voegd als los­se pas­ses, zo­dat ze uit­ein­de­lijk sa­men één beeld vor­men. We ma­ken een nieu­we le­ge groep aan om al­le scher­m­ele­men­ten sa­men te voe­gen, zo­dat je ze mak­ke­lijk kunt ro­te­ren. com­po­ser = new THREE. Ef­fect com­po­ser( ren­de r er ); com­po­ser. ad d pass( ren­de r pass ); com­po­ser. ad d pass( film pass ); com­po­ser. ad d pass( bad tv pass ); com­po­ser. ad d pass( rg b pass ); com­po­ser. ad d pass( c op y pass ); c op y pass. ren­de r tos c reen= true; pa­rams(); group = new THREE.GROUP(); sce­ne.add(group);

6. Ver­licht de scè­ne

We voe­gen ver­lich­ting van bo­ven­af toe aan de scè­ne om de ob­jec­ten zicht­baar te ma­ken. Er wordt een aar­de­tex­tuur ge­la­den om rond de bol te dra­pe­ren. De ge­o­me­trie van de bol wordt ge­maakt, het ma­te­ri­aal wordt ge­maakt van de aar­de­tex­tuur en de aar­de wordt toe­ge­voegd aan het groeps­ob­ject.

7. Een twee­de aar­de

We ma­ken een twee­de mo­del van de aar­de, net iets gro­ter dan het eer­ste, maar de­ze keer is de opa­ci­teit voor de tex­tuur iets­je la­ger. Dit maakt het sa­men­vloei­en van de tex­tu­ren net wat in­te­res­san­ter als ze rond­draai­en in de 3D-scè­ne. Merk op dat hier­voor ad­di­ti­ve-blen­ding wordt ge­bruikt.

ma­te­ri­al = new Three.me­sh­ba­sic­ma­te­ri­al({

map: pla­net­tex­tu­re, transpa­rent: true, opa­ci­ty: 0.95, si­de: Three.dou­ble­s­i­de, blen­ding: Three.ad­di­ti­ve­blen­ding }); earth = new Three.me­sh(ge­o­me­try, ma­te­ri­al); earth.sca­le.x = earth.sca­le.y = earth. sca­le.z = 1.02; group.add(earth); var me­sh = new THREE.OBJECT3D();

8. Lij­nen rond de aar­de

Net bo­ven de bui­ten­kant van de aar­de heb­ben we een icosa­ë­der (twin­tig­vlak) toe­ge­voegd voor een wat tech­ni­scher look. De­ze icosa­ë­der werkt met lijn­ma­te­ri­aal, zo­dat al­leen de ran­den van het mo­del zicht­baar zijn. Ver­vol­gens wordt een twee­de af­beel­ding ge­la­den voor de ster­ren die we wil­len toe­voe­gen aan de scè­ne.

9. Twee­dui­zend ster­ren

Met de for-loop ge­ne­re­ren we 2.000 ster­ren in de scè­ne door ze toe te wij­zen aan wil­le­keu­ri­ge po­si­ties in de Xyz-ruim­te. We ma­ken nieuw ma­te­ri­aal op ba­sis van de ster­tex­tuur. Aan­ge­zien de­ze scè­ne om da­ta draait, lij­ken ze meer op ‘flo­a­ting points’ dan op ster­ren, als knip­oog naar de weer­ge­ge­ven da­ta. f or( i =0; i <2000; i ++){ var ver­tex = new THREE.VECTOR3(); ver­tex.x = 400 * Math.random() - 200; ver­tex.y = 400 * Math.random() - 200; ver­tex.z = 400 * Math.random() - 200; ge ome try. ver tic es. push( ver tex );} ma­te ri­al= new T h ree. po int s ma­te ri­al ({ si­ze: 2, map: spri­te, transpa­rent: true, opa­ci­ty: 0.5, alp­ha­test: 0.5

});

10. Voeg de da­ta toe

Nu wor­den de par­ti­kels toe­ge­voegd aan de groep en dan volgt op­nieuw een for-loop. De­ze keer wordt de loop ge­bruikt om de leng­te­graad, breed­te­graad en kracht van de aard­be­vin­gen op te vra­gen. De­ze da­ta la­den we aan het eind van de tutorial uit een Json-be­stand en slaan we dan op in een glo­ba­le va­ri­a­be­le. par­ti­cles1 = new THREE.POINTS (ge­o­me­try, ma­te­ri­al); par­ti c les 1. s or t par­ti c les= true; gr o up. ad d( par­ti c les 1); f or( var i =0; i< da­ta. fea­tu­re s. lengt h; i++) { var ge­o­me­try = new Three.ge­o­me­try(); var lat= da­ta. fea­tu­re s[ i ]. ge ome try. coo­r­di­na­tes[1];

var l on= da­ta. fea­tu­re s[ i ]. ge ome try. coo­r­di­na­tes[0]; var mag= da­ta. fea­tu­re s[ i ]. pro­per t ie s. mag; var ra­di­us = 100;

11. Be­paal de kracht

Als de mag­ni­tu­de gro­ter is dan nul, wor­den lengteen breed­te­graad om­ge­zet naar Xyz-co­ör­di­na­ten op de bol. Dit punt wordt het start­punt voor een lijn die ver­trekt op de lo­ca­tie van de aard­be­ving. De­ze ver­tex slaan we op in de ge­o­me­trie.

12. Toon de kracht

Nu klo­nen we de ori­gi­ne­le ver­tex en ver­me­nig­vul­di­gen we hem op ba­sis van de waar­de voor de mag­ni­tu­de van de aard­be­ving. Door lijn­ma­te­ri­aal tus­sen de twee pun­ten toe te voe­gen, wordt er een lijn ge­te­kend. De kleur van de lijn wordt be­paald aan de hand van de waar­de voor de kracht. var ver­tex2 = ver­tex.clo­ne(); ver tex 2. mul tip l y sca­la r (( n mag *0.4)+1); ge ome try. ver tic es. push( ver tex 2); v arm y col= new T h ree. co lor (0x f f f f f f ); my col. set hsl (( mag /5),0.9,0.6); var line= new T h ree. line( ge ome try, new T h ree. line ba­sic ma­te ri­al ({ co lor: my­col,li­ne­width: 1 }));

group.add(line); } }

13. Luis­ter naar de brow­ser

We ro­te­ren de he­le groep een beet­je om te si­mu­le­ren dat de aar­de on­der een hoek staat. We voe­gen

een aan­tal event-lis­te­ners toe voor de muis en touch-in­put, zo­dat op het scherm kan wor­den in­ge­zoomd en het ge­zichts­punt ge­ba­seerd wordt op de muis- of touch­po­si­tie.

14. Touch

De vol­gen­de twee event-hand­lers zijn be­doeld voor ge­bruik met een tou­chs­creen – de va­ri­a­be­len mousex en mou­sey wor­den ge­üp­da­tet op ba­sis van de touch­po­si­tie. Al­leen de eer­ste touch in de ar­ray wordt mee­ge­no­men voor het ge­val ie­mand meer­de­re vin­gers op het scherm zet. func­ti­on on do­cu­ment to uch start( event ){ i f( event. tou­ches. lengt h >1){ event. pr event de­fault (); mou sex= event. tou­ches [0]. pa­ge x win­dow­halfx;

mou se y= event. tou­ches [0]. pa­ge y win­dow­hal­fy; } } func­ti­on on do­cu­ment to uc h mo­ve( event ){ i f( event. tou­ches. lengt h ==1){ event. pr event de­fault (); mou sex= event. tou­ches [0]. pa­ge x win­dow­halfx;

mou se y= event. tou­ches [0]. pa­ge y win­dow­hal­fy; } }

15. Stel pa­ra­me­ters in

In de vol­gen­de func­tie stel­len we de pa­ra­me­ters voor de sha­ders in. Zo wordt de ma­te van ver­sto­ring bij de sha­der badtv be­paald en ha­len we de Rgb-ka­na­len iets uit el­kaar. We voe­gen een klei­ne hoe­veel­heid ruis toe en de scan­li­nes wor­den op 1.000 ge­zet. func­ti­on pa­rams() {

bad tv pass. uni­form s [‘ dis tor t ion ’]. va­lue = 0.9;

bad tv pass. uni­form s [‘ dis tor t ion 2’]. va­lue = 0.5; bad tv pass. uni­form s [‘ speed ’]. val u e =0.05; bad tv pass. uni­form s [‘ roll speed ’]. val u e =0; rgb pass. uni­form s [‘ an gle ’]. val u e =0; rgb pass. uni­form s [‘ a mount ’]. val u e =0.003; film pass. uni­form s [‘ s co unt ’]. val u e =1000; film pass. uni­form s [‘ sin­ten sit y ’]. va­lue = 0.6;

film pass. uni­form s [‘ n in ten sit y ’]. va­lue = 0.4;}

16. Pas ven­ster­groot­te aan

Op mo­bie­le ap­pa­ra­ten kun­nen men­sen mak­ke­lijk de groot­te van het brow­ser­ven­ster ver­an­de­ren door het ap­pa­raat te kan­te­len, daar­om re­set­ten we de ca­me­ra en de ren­de­rer el­ke keer dat de brow­ser een an­der for­maat krijgt. De func­tie ani­ma­te roept zich­zelf aan met 60 fra­mes per se­con­de en ac­ti­veert ver­vol­gens de ren­der­func­tie.

17. Ren­der elk fra­me

De ren­de­rer ro­teert de groep modellen nu rond de y-as. Hij neemt de muis­po­si­tie en past de ca­me­ra daar­op aan, zo­dat je met links en rechts in- en uit­zoomt en met bo­ven en be­ne­den het ge­zichts­punt be­paalt. De sha­ders krij­gen ho­ge­re waar­den, zo­dat ze de scè­ne licht ver­sto­ren, en de com­po­ser ren­dert de scè­ne.

18. XHR

De func­tie ma­ker­equest wordt ge­bruikt om te kij­ken of de brow­ser een ex­tern be­stand kan la­den met XHR. Als dat suc­ces heeft, wordt de func­tie alert­con­tents aan­ge­roe­pen. Die ana­ly­seert de Json-da­ta ver­vol­gens. var htt­pre­quest; func­ti­on ma­ker­equest() { htt­pre­quest = new Xmlhtt­pre­quest(); if (!htt­pre­quest) {

alert(‘gi­ving up :( Can­not cre­a­te an XMLHTTP in­stan­ce’);

re­turn fal­se; } http re que s t. on rea­dy sta­te c han ge= alert­con­tents;

19. Roep de JSON aan

Nu vra­gen we het Json-be­stand met aard­be­vings­da­ta op van de si­te van de USGS, een we­ten­schap­pe­lijk bu­reau van de Ame­ri­kaan­se re­ge­ring. De func­tie alert­con­tents con­tro­leert of al­le Json­con­tent ge­la­den is. In dat ge­val wordt de code uit de vol­gen­de stap uit­ge­voerd. htt­pre­quest.open(‘get’, ‘htt­ps://earth­qua­ke. usgs.gov/earth­qua­kes/feed/v1.0/summary/ al­l_week.ge­oj­son’); htt­pre­quest.send(); } ma­ker­equest(); func­ti­on alert­con­tents() {

if (htt­pre­quest.rea­dysta­te === Xmlhtt­pre­quest.do­ne) {

if (htt­pre­quest.sta­tus === 200) {

20. Haal in­for­ma­tie uit JSON

Om te be­gin­nen wordt de ti­tel van de pa­gi­na aan­ge­past op de Json-da­ta en be­paalt de code de hui­di­ge da­tum om die weer te ge­ven. De ti­tel en het aan­tal aard­be­vin­gen wor­den toe­ge­voegd aan de bij­be­ho­ren­de div-tags, hier op­ge­sla­gen in va­ri­a­be­len. da­ta= J son. par se( http re que s t. res­pon­se tex t ); t i tl e= do­cu­ment. g et ele­ment by id (“t i tl e ”); a mount= do­cu­ment. g et ele­ment by id (“a mount ”); tit­le.in­ner­ht­ml = da­ta. met­a­da­ta. t i tl e; var d = new Da­te(); var y = d.get­ful­lyear(); var month = [“Ja­nu­a­ry”, “Fe­bru­a­ry”, “March”, “April”, “May”, “Ju­ne”, “Ju­ly”, “Au­gust”, “Sep­tem­ber”, “Oc­to­ber”, “No­vem­ber”, “De­cem­ber”, ]; var m = month[d.get­m­onth()];

21. Zet op het scherm

Het aan­tal aard­be­vin­gen in de af­ge­lo­pen ze­ven da­gen en de da­tum wor­den op het scherm ge­zet. Uit­ein­de­lijk roe­pen we de init-func­tie aan en daar­mee wordt al­le code uit­ge­voerd die we hier­bo­ven heb­ben be­spro­ken. Dit doen we pas als de Js­on­da­ta ge­la­den zijn, zo­dat die ge­bruikt kun­nen wor­den voor de vi­su­a­li­sa­tie.

amount.in­ner­ht­ml = m + ““+ y + “, Last 7 Days: “+ da­ta.met­a­da­ta.count + “Earth­qua­kes”;

init(); } el­se {

alert(‘the­re was a pro­blem with the re­quest.’); } } }

Au­teur Mark Shuf­fle­bottom

Newspapers in Dutch

Newspapers from Netherlands

© PressReader. All rights reserved.