2012-12-17 14 views
10

Muszę narysować wiele punktów na kanwie HTML5 i zajmuje to dość długo. Mój kod wygląda tak:Przyspieszenie rysowania wielu punktów na elemencie canvas HTML5

var points = getPoints() // Array of {x,y,color} 
var ctx = canvas.getContext("2d"); 

for (var i = 0; i < points.length; i++) { 
    ctx.fillStyle = points[i].color 
    ctx.beginPath() 
    ctx.arc(points[i].x, points[i].y, radius, 0, Math.PI * 2, true) 
    ctx.fill() } 

Zastanawiam się, jakie ulepszenia wydajności mogę zrobić, aby przyspieszyć ten proces. Mam tylko 5 różnych kolorów. Na przykład, czy mogę skorzystać z sortowania listy punktów "w locie", aby zmienić wartość tylko jeden raz na punkt?

+0

myślę, że to jest dość powolna linia: 'ctx.arc (points [i] .x, points [i] .y, radius, 0, Math.PI * 2, true) 'Spróbuj rysować proste prostokąty i zobacz, czy to przyspiesza. (IMHO, powinno ...) – ppeterka

+1

Spróbowałem i tak, przyspieszyło. Nie rozumiem jednak, jak to pomaga. – Nicolas

+1

Myślę, że jeśli ustawisz skrzypce, łatwiej będzie go poprawić, oto kilka modyfikacji, które mogę wymyślić, aby zrobić to trochę szybciej (być może) -> [** FIDDLE **] (http: // jsfiddle .net/4WTaQ /) ... – adeneo

Odpowiedz

13

Na przykład, chciałbym skorzystać formularz sortowanie listy punktów on-the-fly zmienić ctx.fillStyle tylko 5 razy zamiast jednorazowo za punkt?

Z mojego doświadczenia, tak - zmiana .fillStyle często jest dość droga.

Posiadałem kod, który wykreślał dużą liczbę prostokątów na płótnie, a czas rysowania prostokątów z tylko dwoma rzadko zmieniającymi się kolorami był znacznie lepszy niż wykreślanie z wieloma często zmieniającymi się kolorami.

Tak czy inaczej, skoro masz tylko pięć różnych kolorów:

  1. Załóż płótno poza ekranem, na których można wyciągnąć pięć okręgów
  2. Wpisz .drawImage() do Blit odpowiedni kolor kółko do docelowego płótnie, bez konieczności aby ponownie obliczyć współrzędne łuku
  3. Przypisz points[i] do zmiennej lokalnej wewnątrz pętli, aby uniknąć dereferencji w kółko.

na moim laptopie ten kod jest rysowanie 3000 kręgi na płótnie 400x400 w 7 milisekund:

var colours = ['red', 'green', 'blue', 'yellow', 'magenta']; 
var n = colours.length; 
var r = 10; 
var d = r * 2; 

var off = document.createElement('canvas'); 
off.width = n * d; 
off.height = d; 
var ctx = off.getContext('2d'); 

for (var i = 0; i < n; ++i) { 
    ctx.fillStyle = colours[i]; 
    ctx.beginPath(); 
    ctx.arc(i * d + r, r, r, 0, 2 * Math.PI); 
    ctx.closePath(); 
    ctx.fill(); 
} 

var canvas = document.getElementById('canvas'); 
var ctx2 = canvas.getContext('2d'); 
var t0 = Date.now(); 
for (var i = 0; i < 3000; ++i) { 
    var c = Math.floor(n * Math.random()); 
    var x = Math.floor(canvas.width * Math.random()); 
    var y = Math.floor(canvas.height * Math.random()); 
    ctx2.drawImage(off, c * d, d, d, x - r, y - r, d, d); 
} 
var t1 = Date.now(); 
alert((t1 - t0) + "ms"); 

Zobacz http://jsfiddle.net/alnitak/Dpgts/

+0

Wow, mój robi to w 3ms. Imponujący. Dziękuję Ci bardzo! – Nicolas

+0

@Stewie BTW, jeśli Twoje kręgi się nie nakładają, prawdopodobnie możesz przyspieszyć to za pomocą '.putImageData'. – Alnitak

+0

Nie robią tego. Masz na myśli zamiast .drawImage()? – Nicolas