2009-06-11 4 views
12

Also ich arbeitete an diesem kleinen Javascript-Experiment und ich brauchte ein Widget, um die FPS davon zu verfolgen. Ich portierte ein Widget, das ich mit Actionscript 3 verwendet habe, in Javascript und es scheint gut mit Chrome/Safari zu funktionieren, aber auf Firefox wirft eine Ausnahme.Firefox wirft eine Ausnahme mit HTML Canvas PutImageData

Dies ist das Experiment:

Depth of Field

Dies ist der Fehler:

[Exception... "An invalid or illegal string was specified" code: "12" nsresult: "0x8053000c (NS_ERROR_DOM_SYNTAX_ERR)" location: "http://mrdoob.com/projects/chromeexperiments/depth_of_field__debug/js/net/hires/debug/Stats.js Line: 105"] 

Die Linie, die etwa ist complaning ist diese:

graph.putImageData(graphData, 1, 0, 0, 0, 69, 50); 

Welche a crappy code zum "scrollen" der Bitmap-Pixel. Die Idee ist, dass ich nur ein paar Pixel auf der linken Seite der Bitmap zeichne und dann auf dem nächsten Frame kopiere ich die ganze Bitmap und füge sie auf Pixel nach rechts ein. Dieser Fehler wird normalerweise ausgelöst, weil Sie eine Bitmap einfügen, die größer als die Quelle ist und die Grenzen überschreitet, aber in der Theorie sollte das nicht der Fall sein, da ich 69 als die Breite des Rechtecks ​​definiere, das eingefügt werden soll Bitmap 70px breit).

Und das ist voll Code:

var Stats = { 
baseFps: null, 

timer: null, 
timerStart: null, 
timerLast: null, 
fps: null, 
ms: null, 

container: null, 
fpsText: null, 
msText: null, 
memText: null, 
memMaxText: null, 

graph: null, 
graphData: null, 

init: function(userfps) 
{ 
    baseFps = userfps; 

    timer = 0; 
    timerStart = new Date() - 0; 
    timerLast = 0; 
    fps = 0; 
    ms = 0; 

    container = document.createElement("div"); 
    container.style.fontFamily = 'Arial'; 
    container.style.fontSize = '10px'; 
    container.style.backgroundColor = '#000033'; 
    container.style.width = '70px'; 
    container.style.paddingTop = '2px'; 

    fpsText = document.createElement("div"); 
    fpsText.style.color = '#ffff00'; 
    fpsText.style.marginLeft = '3px'; 
    fpsText.style.marginBottom = '-3px'; 
    fpsText.innerHTML = "FPS:"; 
    container.appendChild(fpsText); 

    msText = document.createElement("div"); 
    msText.style.color = '#00ff00'; 
    msText.style.marginLeft = '3px'; 
    msText.style.marginBottom = '-3px'; 
    msText.innerHTML = "MS:"; 
    container.appendChild(msText); 

    memText = document.createElement("div"); 
    memText.style.color = '#00ffff'; 
    memText.style.marginLeft = '3px'; 
    memText.style.marginBottom = '-3px'; 
    memText.innerHTML = "MEM:"; 
    container.appendChild(memText); 

    memMaxText = document.createElement("div"); 
    memMaxText.style.color = '#ff0070'; 
    memMaxText.style.marginLeft = '3px'; 
    memMaxText.style.marginBottom = '3px'; 
    memMaxText.innerHTML = "MAX:"; 
    container.appendChild(memMaxText); 

    var canvas = document.createElement("canvas"); 
    canvas.width = 70; 
    canvas.height = 50; 
    container.appendChild(canvas); 

    graph = canvas.getContext("2d"); 
    graph.fillStyle = '#000033'; 
    graph.fillRect(0, 0, canvas.width, canvas.height); 

    graphData = graph.getImageData(0, 0, canvas.width, canvas.height); 

    setInterval(this.update, 1000/baseFps); 

    return container; 
}, 

update: function() 
{ 
    timer = new Date() - timerStart; 

    if ((timer - 1000) > timerLast) 
    { 
     fpsText.innerHTML = "FPS: " + fps + "/" + baseFps; 
     timerLast = timer; 

     graph.putImageData(graphData, 1, 0, 0, 0, 69, 50); 
     graph.fillRect(0,0,1,50); 
     graphData = graph.getImageData(0, 0, 70, 50); 

     var index = (Math.floor(Math.min(50, (fps/baseFps) * 50)) * 280 /* 70 * 4 */); 
     graphData.data[index] = graphData.data[index + 1] = 256; 

     index = (Math.floor(Math.min(50, 50 - (timer - ms) * .5)) * 280 /* 70 * 4 */); 
     graphData.data[index + 1] = 256;    

     graph.putImageData (graphData, 0, 0); 

     fps = 0;    
    } 

    ++fps; 

    msText.innerHTML = "MS: " + (timer - ms); 
    ms = timer; 
} 

}

Irgendwelche Ideen? Danke im Voraus.

Antwort

0

Ich denke, Sie müssen zwei weitere Argumente putImageData angeben: Breite und Höhe.

See here

+0

Sie haben Recht, ich hatte die Parameter falsch. Dennoch habe ich sie so modifiziert, dass sie die richtigen Parameter verwendet und immer noch den gleichen Fehler gibt. –

1

I hatte den gleichen Fehler, da der Wert I zu graphData.data einzustellen versucht [index] eine Zeichenfolge und nicht eine ganze Zahl ist. Um es zu beheben, konvertierte ich die Zeichenfolge in einer Ganzzahl mit ParseInt().

4

Ja, scheint dieser Fehler passieren, wenn Sie ImageData von den Rändern der Zeichenfläche (get | put).

Um dieses Problem zu lösen, habe ich einfach eine Schnittlogik hinzugefügt, die die Kanten der zu zeichnenden Region an den Rändern der Zeichenfläche prüft und bei Bedarf nur den sichtbaren Bereich zeichnet. Es scheint das Problem behoben zu haben.

+0

Das war auch mein Problem. Anstatt meine Daten zu beschneiden, habe ich die Leinwand vergrößert und die Ausnahme gestoppt. –

0

Ich habe dieses Problem seit ein paar Tagen (in Firefox) behandelt. Die beste Idee, die ich mir vorstellen kann, ist das dynamische Entfernen der Pixel, die vom Bildschirm verschwinden. Ich bin besorgt, dass es zu viel CPU braucht, um dies zu tun. hoffentlich kommt jemand mit einer besseren Idee:/

aber um zu wiederholen, habe ich nur diesen Fehler gesehen, wenn putImageData versucht, ein beliebiges Pixel außerhalb der Leinwand Perimeter zu zeichnen. z.B. beliebiger x- oder y-Wert < 0.

- beim zweiten Lesen - Es sieht so aus, als würden Sie bereits die Größe Ihrer Bilddaten ändern. Sie könnten versuchen, Ihr Image auf 68px zu verkleinern, wenn Sie sich in einem 70px-Container befinden? Wahrscheinlich wird nicht funktionieren, aber einen Versuch wert ..

+0

Bei einem meiner Projekte habe ich einen try/catch um die Funktion putImageData hinzugefügt. Im schlimmsten Fall erhalten Sie einen Rahmen ohne Bild im Gegensatz zu einem defekten Programm. Es ist keine Lösung, aber yeah .. – Jacksonkr

0

Das ist alt, aber das NUR gibt mir Probleme auf FF auf Windows. FF auf Mac funktioniert wie es soll.

7

Es ist ein Fehler in Firefox. Mozilla knows about it.Hier ist die Lösung:

  1. Machen Sie eine neue In-Memory-Leinwand:

    var spriteCanvas = document.createElement('canvas'); 
    
  2. Stellen Sie die Höhe/Breite der Leinwand in die Höhe/Breite des Bildes:

    spriteCanvas.setAttribute('width', 20); 
    spriteCanvas.setAttribute('height', 20); 
    
  3. Setzen Sie die Bilddaten in die Leinwand an Position (0,0):

    spriteCanvas.getContext('2d').putImageData(imageData, 0, 0); 
    
  4. Im Kontext für Ihre Haupt-Leinwand, ziehen Sie Ihre Leinwand Sprite drawImage unter Verwendung eines beliebigen Position mit On-Screen oder Off-Screen:

    context.drawImage(spriteCanvas, 50, 100); // clipping is allowed 
    
+0

Diese Antwort rettete mich halbtags Arbeit. Vielen Dank. – donohoe

+0

Noch ein gültiger Fix, bei Mac FF4.0.1 ist gerade dieses Problem aufgetreten. –

1

ich mit drawImage ähnliches Problem hatte(), wenn versucht

var image = new Image(); 
    image.onload = function() { 
     context.drawImage(image, 0, 0, this.tileSize, this.tileSize); 
     } 
    image.src = this.baseURL + tileId; 

Das Problem verschwunden ist, wenn I Höhe entfernt und Breite Parameter aus dem Aufruf und verwendet, um dies: eine Fliese auf einer Leinwand von der gleichen Größe auf diese Weise zu ziehen

context.drawImage(image, 0, 0);