2014-02-22, 03:10
  #1
Medlem
lasternassummas avatar
HTML5 canvas
Håller på att utvärdera möjligheten att realisera en
ide, bl.a. med hjälp av HTML5-canvas.
Har gjort två observationer som får mig att undra
om det finns bättre sätt.

Om jag kör mina ca 200 000 fillstyle, fillrect etc.
i ett enda script med stroke och </script> på
slutet så, dels tar det ganska lång tid och dels
ser jag ingenting innan allt är klart, på slutet.

Om jag i stället delar upp i "små" segment, t.ex.

Kod:
<script>
var canvas = document.getElementById('mycanvas');
var ctx = canvas.getContext('2d');
{
ctx.fillStyle = '#807000';
ctx.fillRect(593, 173, 1, 1);
ctx.fillStyle = '#B0A000';
ctx.fillRect(593, 173, 1, 1);
ctx.stroke();
}
</script>

men med kanska 10 000 kommandon i varje i stället
för ca 200 000, så ser jag vad som händer efter hand,
men det blir inte snabbare.

Mina frågor
1. Finns det något annat sätt att få canvasen synlig efter hand
än att gå ur skriptet? Jag har testat .stroke(), men det hjälper
inte.
2. Gör jag något fel, eftersom det går sakta?

De flesta punkter är en pixel, men även 2x2 och 3x3 förekommer.
Färgen och intensiteten kan också variera.

Tiden
ca 23 sekunder på en 2.8 GHz Intel Core 2 Duo
ca 1 sekund på en 2.7 GHz Intel Core i7 (Haswell)

Det går ju ganska snabbt på en hygglig klient, men jag vill att
det ska gå snabbare även på en lite äldre dator.

mvh/Bo S
Citera
2014-02-22, 11:21
  #2
Medlem
Povels avatar
Hm, har du ett sånt där scriptblock för varje stroke du vill göra?
Och varför har du måsvingar runt delen där du jobbar med ctx?

/p
Citera
2014-02-22, 12:33
  #3
Medlem
lasternassummas avatar
Citat:
Ursprungligen postat av Povel
Hm, har du ett sånt där scriptblock för varje stroke du vill göra?
Och varför har du måsvingar runt delen där du jobbar med ctx?

/p

Mitt första försök var ett enda scriptblock.
Då såg jag ingenting alls innan allt var klart.
Irriterande, när det kan ta uppåt 30 sekunder på en
halvgammal dator.

När jag delade upp i flera scriptblock, t.ex. 4 st
då ser jag att det börjar ritas efter ca 7 sekunder,
men hela resultatet är ju klart först efter ca 30 s.

Måsvingarna råkade slinka med när jag klippte ur
javascriptet som jag genererar, som jag ville klistra
in för att illustrera vad och hur jag gör det.

Jag kan visa ett exempel på vad jag gör, så blir det
lite mer verkligt.

Dialog - välj område
Resultat - Här finns människorna!

Informationen hämtas med en sökning i databasen.
Sökningen och hämtningen går snabbt.

mvh/Bo S
__________________
Senast redigerad av lasternassumma 2014-02-22 kl. 12:36. Anledning: korr
Citera
2014-02-22, 13:14
  #4
Medlem
Povels avatar

Visa koden istället, så blir det ännu mer verkligt

Jag misstänker att den går att optimera ganska mycket.


/p
Citera
2014-02-22, 13:34
  #5
Medlem
lasternassummas avatar
Citat:
Ursprungligen postat av Povel
Visa koden istället, så blir det ännu mer verkligt
Jag misstänker att den går att optimera ganska mycket.
/p

Det är drygt 200 000 rader med exakt samma som i OP,
som upprepas. Det som varierar är koordinater och
färger/intensitet.

Det bakomliggande "systemet" genererar en smula HTML
och långa (t.ex. 200 000 rader) javascript. För att testa
prestanda, har jag extraherat ut HTML inklusive javascript.
Om jag gör ett annat, mindre urval, t.ex. USA eller Spanien
så blir det mindre javascript och det går snabbare. Jag kan
packa ihop ett halvstort urval till zip och lägga någonstans.
Tror du att det hjälper?

Jag hade förhoppningen att det finns någon här som jobbat
med att skapa canvas, helst i realtid/interaktivt, och som
kanske visste något om prestanda hos de olika koder som
kan användas när man ritar i en canvas, eller om det t.ex.
har betydelse i viken ordning man ritar.

Som framgår i OP har jag i stort sett bara använt fillRect,
men blandat med fillStyle. Blir det snabbare om man
sorterar sina kommandon, så att man t.ex. kör alla
fillRect under samma fillStyle och sedan byter
fillStyle?

mvh/Bo S
Citera
2014-02-22, 15:14
  #6
Medlem
Povels avatar
Citat:
Ursprungligen postat av lasternassumma
Det är drygt 200 000 rader med exakt samma som i OP,
som upprepas. Det som varierar är koordinater och
färger/intensitet.

Det bakomliggande "systemet" genererar en smula HTML
och långa (t.ex. 200 000 rader) javascript. För att testa
prestanda, har jag extraherat ut HTML inklusive javascript.
Om jag gör ett annat, mindre urval, t.ex. USA eller Spanien
så blir det mindre javascript och det går snabbare. Jag kan
packa ihop ett halvstort urval till zip och lägga någonstans.
Tror du att det hjälper?

Jag hade förhoppningen att det finns någon här som jobbat
med att skapa canvas, helst i realtid/interaktivt, och som
kanske visste något om prestanda hos de olika koder som
kan användas när man ritar i en canvas, eller om det t.ex.
har betydelse i viken ordning man ritar.

Som framgår i OP har jag i stort sett bara använt fillRect,
men blandat med fillStyle. Blir det snabbare om man
sorterar sina kommandon, så att man t.ex. kör alla
fillRect under samma fillStyle och sedan byter
fillStyle?

mvh/Bo S

Det låter jättekonstigt om det skapas en scripttag per stroke eller så, och dessutom görs getElementById för att få tag på canvasen hela tiden. Det blir verkligen inte snabbt, vare sig man gör något med canvas eller ej.
Gör en funktion årminstone, och ha canvasen i cachad i en variabel ända från början.

Kod:
var cStroke = (function () {

  
// spara undan canvas och context
  
var document.getElementById("myCanvas")
     , 
ctx c.getContext('2d');
  
  
// funktion som används hädanefter
  
return function (draws) {
    for (var 
idx=0len=draws.lengthidx<len; ++idx) {
      var 
draw draws[idx];
      
ctx.fillStyle draw.style;
      
ctx.fillRect.apply(ctxdraw.rect); 
    }
    
ctx.stroke();
  };

})(); 

.. och sen skickar man in en array av instruktioner till den (var och en med en style och en rect):

Kod:
cStroke([
  {
style"#807000"rect: [59317311]}
  , {
style"#B0A000'"rect: [59317311]}
  
// etc etc.
]); 

/p
Citera
2014-02-22, 19:23
  #7
Medlem
Hej. Jag har erfarenhet av canvaselementet i spelsammanhang, har trixat en hel del med optimering.

Min första tanke är att du kanske bör rita punkterna på en off-screen canvas, brukar vara snällare mot processorn. När allt är klart gör du en enskild drawImage(minOffScreenCanvas,0,0)

Analysera koden med Chrome's CPU-profilerare (med high def aktiverat) så att du får en bild av vad varje moment kostar och vad du behöver optimera.

I ditt första inlägg ritar du 2st fillRect över varandra, samma koordinater. Om det förekommer denna typ av upprepning kan det bli billigare att köra en logik som förhindrar onödiga upprepningar. Att rita är generellt sett många gånger dyrare än logik.

Du använder även en stroke som jag inte ser poängen med.
Citera
2014-02-22, 22:11
  #8
Medlem
lasternassummas avatar
Skrev just ett ganska långt inlägg och…
Så här kommer en kortvariant…

Tack Povel och Stighjalmar för goda råd!

Ska testa med funktion/instuktionsarray!

Borde sett dubletten när jag skapade OP…

Jag har information om ett 6-siffrigt antal platser i databasen.
Data innehåller bl.a. lat., long., höjd, pop., nation, delstat (endast USA)
så att jag kan rita en befolkningsgraf över godtyckligt land (eller
delstat i USA).
Jag måste ha missat något med jämförelsen efter skalning eftersom
jag försöker rita dubletter…

Off-screen
Jag vill helst se när det ritas. Gäller ännu mer i en annan tillämpning
med liknande grafisk presentation i canvas, där det finns en koppling
till händelser i realtid.

Stroke
Jag trodde att det var stroke som verkställde ritandet i t.ex.
det här exemplet från w3schools:
Kod:
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
ctx.moveTo(0,0);
ctx.lineTo(200,100);
ctx.stroke();

Har jag fattat fel?

Chrome's CPU-profilerare
Måste jag titta på! Att veta vad som händer när man utför sin kod
är ju alltid en fördel!

Tack igen!

mvh/Bo S
Citera
2014-02-22, 22:27
  #9
Medlem
Citat:
Ursprungligen postat av lasternassumma

Stroke
Jag trodde att det var stroke som verkställde ritandet i t.ex.
det här exemplet från w3schools:
Kod:
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
ctx.moveTo(0,0);
ctx.lineTo(200,100);
ctx.stroke();

Har jag fattat fel?

Exemplet ovan ritar en linje. Om du bara vill rita en fylld rektangel med fillRect är det överflödigt. Stroke kan dock användas för rektanglar om du vill rita en kantlinje (strokeRect).

Intressant projekt för övrigt! Är nyfiken på hur du hämtar och lagrar datan samt sorterar bort dubbletter.

Hur många ritningar landar du på när du sorterat bort överlappande?
Citera
2014-02-22, 23:30
  #10
Medlem
lasternassummas avatar
Citat:
Ursprungligen postat av Stighjalmar
Exemplet ovan ritar en linje. Om du bara vill rita en fylld rektangel med fillRect är det överflödigt. Stroke kan dock användas för rektanglar om du vill rita en kantlinje (strokeRect).

Egentligen är de flesta av mina "rektanglar" en pixel. De flesta orter är småorter.

Citat:
Ursprungligen postat av Stighjalmar
Intressant projekt för övrigt! Är nyfiken på hur du hämtar och lagrar datan samt sorterar bort dubbletter.

Jag har och har haft turen i livet att ofta få ha roligt - även i detta projekt!
Jag har data i en (MySQL) databas. Scriptspråket på webbservern är PHP.
Jag väljer - Kontinent/världsdel - land - färgschema (t.ex. natt/dag) och
upplösning/storlek på bilden, t.ex. 1920 x 1080 pixlar ( ). Sorterar
i SQL-sökningen så att jag får positionerna sorterade. Skalar om högupplöst
position (med ca 8 siffrors precision) till pixeladress och kollar om jag redan
ritat på pixeladressen och i så fall hur stor rektangel (beror på befolkning).
Trodde att jag inte ritade där jag ritat förut, men där har jag en bug att fixa.

Citat:
Ursprungligen postat av Stighjalmar
Hur många ritningar landar du på när du sorterat bort överlappande?

Beror på urvalet. Sverige är inte många orter. Tyskland, Frankrike
och Spanien är en hel del. USA och Kina är många. Hela världen
är ett 6-siffrigt antal. Det är med stora länder eller hela planeten
som det blir tråkigt att sitta och titta på ett browserfönster som
det inte händer något alls i – upp till kanske 30 sekunder. Då kommer
ju en användare med normaltålamod att börja med något annat innan
det kommer upp något alls i fönstret!

mvh/Bo S
__________________
Senast redigerad av lasternassumma 2014-02-22 kl. 23:32. Anledning: korr
Citera
2014-02-23, 01:41
  #11
Medlem
Som ett komplement till CPU-profilering kan det vara bra att hålla sig uppdaterad på alternativa lösningar på jsperf.com. Canvas är ett så pass ungt element att det kontinuerligt skiftar vilket alternativ som fungerar bäst i de olika webbläsarna. Se relevant (men utdaterat) exempel:
http://jsperf.com/setting-canvas-pixel

När du kört CPU-profileraren bör du kunna ta ett informerat beslut kring om du tjänar på att undvika upprepade fillStyle. Kanske en sortering på färg innan ritning kan vara ett alternativ.

Svårt att säga vad som kan tänkas vara det bästa alternativet för din framväxande animation. I nuläget är du ju lite utanför ramarna för det tilltänkta användningsområdet. En normal animation eller spelmotor ligger ju och tuggar på 60 fps, alltså en bildruta per 16.6ms. Mellan bildrutorna har webbläsaren mer eller mindre andrum (beroende på hur lång tid en bildruta tar att rita inkl. logik). Möjligtvis blockerar du visualiseringen när du kontinuerligt överöser den med nya kommandon.

Jag tror det vore klokt att inte utesluta off-screen-canvas innan du har mätt prestandaskillnaden. Om det skulle löna sig kan du istället bestämma dig för en lämplig uppdateringsfrekvens (eller använda requestAnimationFrame) för din synliga canvas och hämta den framväxande kartan från off-screen.

Det kan som sagt vara extremt fördelaktigt, enligt detta exempel upp till 20 x snabbare beroende på webbläsare: http://jsperf.com/canvas-draw-off-dom
Dock svårt att förutspå innan test av din egen kod.
Citera
2014-02-23, 08:59
  #12
Medlem
lasternassummas avatar
Citat:
Ursprungligen postat av Stighjalmar
Som ett komplement till CPU-profilering kan det vara bra att hålla sig uppdaterad på alternativa lösningar på jsperf.com. Canvas är ett så pass ungt element att det kontinuerligt skiftar vilket alternativ som fungerar bäst i de olika webbläsarna. Se relevant (men utdaterat) exempel:
http://jsperf.com/setting-canvas-pixel

När du kört CPU-profileraren bör du kunna ta ett informerat beslut kring om du tjänar på att undvika upprepade fillStyle. Kanske en sortering på färg innan ritning kan vara ett alternativ.

Svårt att säga vad som kan tänkas vara det bästa alternativet för din framväxande animation. I nuläget är du ju lite utanför ramarna för det tilltänkta användningsområdet. En normal animation eller spelmotor ligger ju och tuggar på 60 fps, alltså en bildruta per 16.6ms. Mellan bildrutorna har webbläsaren mer eller mindre andrum (beroende på hur lång tid en bildruta tar att rita inkl. logik). Möjligtvis blockerar du visualiseringen när du kontinuerligt överöser den med nya kommandon.

Jag tror det vore klokt att inte utesluta off-screen-canvas innan du har mätt prestandaskillnaden. Om det skulle löna sig kan du istället bestämma dig för en lämplig uppdateringsfrekvens (eller använda requestAnimationFrame) för din synliga canvas och hämta den framväxande kartan från off-screen.

Det kan som sagt vara extremt fördelaktigt, enligt detta exempel upp till 20 x snabbare beroende på webbläsare: http://jsperf.com/canvas-draw-off-dom
Dock svårt att förutspå innan test av din egen kod.

Tack!
Tack för tips och länkar!
Skulle helst vilja att tiden, som på en av mina testburkar närmar sig
30 sekunder, aldrig gick över ca 1,5-2 sekunder, på en "halvgammal"
och "halvtrött" dator. Jag nämnde i OP hur mycket det kunde skilja
beroende på dator:

Tiden
ca 23 sekunder på en 2.8 GHz Intel Core 2 Duo
ca 1 sekund på en 2.7 GHz Intel Core i7 (Haswell)

Ska läsa på, testa off-screen och se hur mycket jag kan förbättra
prestanda med de förslag jag fått.

Tack igen!

mvh/Bo S
Citera

Skapa ett konto eller logga in för att kommentera

Du måste vara medlem för att kunna kommentera

Skapa ett konto

Det är enkelt att registrera ett nytt konto

Bli medlem

Logga in

Har du redan ett konto? Logga in här

Logga in