Canvas verfügt über eine sehr leistungsstarke API namens drawImage() (w3c):
Seine Hauptfunktion besteht darin, Bilder, Videos und sogar andere Leinwände zu zeichnen.
Frage:Er kam voller Bewunderung hierher, verfehlte aber das Ziel. Als er den Kopf senkte, sah er ein großes Loch im Boden.
Die Sache ist so: Nachdem ich die Einführung von w3c und die sehr überzeugende und lehrreiche Demo gelesen hatte, beschloss ich, es auszuprobieren, basierend auf der Idee, zu üben, um wahres Wissen zu erlangen Probieren Sie es aus
Ich habe die folgenden grundlegenden Aufgaben gemäß dem Fließbandprojekt festgelegt:
1. Canvas-Tag+ID
<canvas id=canvas1></canvas>
2. Leinwand abrufen + Breite und Höhe festlegen
var cav1 = document.getElementById('canvas1'), wWidth = 800, wHeight = 600;3. getContext('2d') bereitet die Leinwand vor
var ctx1 = cav1.getContext('2d');4. Erstellen Sie ein neues Image()-Objekt und geben Sie ihm die Attribute der Bilder, die mir gefallen ... (denken Sie nicht zu viel nach)
var bgImg = new Image();bgImg.src = 'images/background.jpg';
5. Endlich ist es Zeit zum Zeichnen. Ich habe aufgeregt diesen Code geschrieben:
ctx1.drawImage(bgImg,0,0,wWidth,wHeight);
Verwirrt drückte ich F5 im Browser.
Dann herrschte Totenstille...
Ich dachte, der Code sei falsch geschrieben, also ging ich zurück und überprüfte ihn sorgfältig, und er war korrekt.
Kopieren Sie die Schlüsselattributnamen und -methoden von w3c und überprüfen Sie sie erneut.
Wenn das Bild ausgedruckt ist, gibt es auch dieses Bild (einer Person)!
Als ich später den W3C-Fall beobachtete, bestand der Unterschied zu meinem Code darin, dass die Bilder in HTML vorliegen.
Dann habe ich gelernt, Bilder in HTML einzufügen,
<img src=./images/background.jpg id=imgs style=display:none></img>
Und verwenden Sie getElementById, um dieses Element abzurufen.
var bgImg = document.getElementById('imgs')Das erneute Ausführen der Zeichnung hat funktioniert.
Er kann es tatsächlich!
Ich denke leider, muss es körperlich sein? Wird es nicht einfach vor dem Canvas-Tag platziert? Das Laden von js hat auch Entitäten, und ich verwende immer noch neue Entitäten, wie anders als echte Menschen!
Das ist richtig, ist es nicht einfach vorne platziert? Dabei handelt es sich um ein Reihenfolgeproblem!
Das in js geladene Bild wird zwar vor der Zeichnung platziert, das Laden des Bildes dauert jedoch einige Zeit. Für die Bildpufferung muss Zeit eingeplant werden. Warten Sie, bis das Bild erfolgreich geladen wurde, bevor Sie es zeichnen können. Die Methode drawImage wird nicht aufgerufen, wenn das Bild verwendet wird, bevor es geladen wurde. Das Zeichnen wird fehlschlagen. Ich verstehe!
Argumentieren manche Leute, dass das Laden von Bildern in IMG-Tags keine Zeit in Anspruch nimmt? Zu diesem Zeitpunkt ist drawImage nicht eingeschränkt? ! Ignorieren Sie jedoch nicht window.onload am Anfang von js. Auch wenn das Bild langsam geladen wird, selbst wenn die Reihenfolge der Bild-Tags nach dem Canvas-Tag liegt, ich jedoch window.onload habe, das es abdeckt, kann mein Bild nicht geladen werden geladen, und Ihr drawImage wird keine Chance haben, oder?
Die ungefähre Reihenfolge ist diese:
<img src=>window.onload = function(){ drawImage}Wenn das Bild nicht in die HTML-Struktur eingefügt worden wäre, wäre diese Einschränkung durch meine Unachtsamkeit umgangen worden:
Wenn ein Bild als Ressource angefordert und in js geladen wird, gibt es natürlich eine Ladezeit für das Bild.
Da es jedoch keine Begrenzung gibt, wird drawImage in den meisten Fällen aufgerufen, wenn das Bild nicht geladen wurde, und diese Methode funktioniert nicht.
lösen:Gibt es also eine gute Möglichkeit, das Problem des Zeichnungsfehlers von drawImage aufgrund der Bildladesequenz zu lösen?
Ich habe die folgenden drei Methoden zusammengefasst:
1. tag+window.onload <img src=>window.onload = function(){ context.drawImage()}Die Kernlösung dieses Ansatzes ist Onload, das das Bild und das DrawImage separat lädt. Das IMG wird zuerst geladen, um sicherzustellen, dass die Zeichnung nach Abschluss des Ladevorgangs verwendet wird.
1-2. Tags später einfügen? Ist es machbar?Eine Situation besteht darin, dass Sie bei Verwendung der Screenshot-Funktion auch drawImage verwenden können und der Screenshot keinen Screenshot Ihres eigenen vorhandenen Bildes erstellt, sondern die Adresse eines Bildes als Parameter verwendet.
Ich denke, für so etwas ist es erforderlich, dass js ein Bild erstellt und ihm die Adresse zuweist. Anschließend muss das Bild generiert und ein Screenshot erstellt werden.
var myImg = document.createElement('img');myImg.src = '///';document.body.appendChild(myImg);ctx1.drawImage(myImg,0,0,wWidth,wHeight);Sie möchten keine zusätzlichen Tags hinzufügen? Muss ich js wie unten gezeigt verwenden, um ein neues Bildobjekt zu erstellen?
var bgImg = new Image();bgImg.src = 'images/background.jpg';
Wie bereits erwähnt, benötigt diese Art von Bild, das mit new Image() erstellt wird, Zeit zum Puffern des Bildes. Warten Sie, bis das Bild erfolgreich geladen wurde, bevor Sie es zeichnen können.
Das Bildobjekt ist fertig, aber woher wissen Sie, wann das Bild tatsächlich geladen ist?
Glauben Sie, dass ich während der Ausführung der js-Aufgabe zu nahe an Ihrer Ausführungszeit bin? Können Sie mich alleine herausnehmen, mich erneut in die Warteschlange stellen und sie später erneut ausführen?
2. Timer-asynchrone Implementierung setTimeout(function(){ ctx1.drawImage(bgImg,0,0,wWidth,wHeight);},10)Warum kommt es hier zu einer Verzögerung beim Schreiben von 10 statt der bekannten 1000 oder 0?
Denn beim Test meiner spezifischen WLAN-Umgebung und meines spezifischen Desktop-Computers kann 10 einfach angezeigt werden, nachdem das Bild geladen wurde, im Gegensatz zu 0, das nicht ausgegeben wird, und ich möchte nicht wie 1000 einen halben Tag warten.
Aber stellen Sie sich vor, wenn Sie das Bild in ein größeres ändern würden, würde diese 10 dann immer noch gelten? Gilt diese 10 weiterhin, wenn das WLAN auf 2G umgestellt wird?
Daher besteht der Nachteil des Timers darin, dass es keine Garantie dafür gibt, dass das Bild nach Ablauf der Zeit geladen wird. Wenn das Netzwerk nicht schnell ist, bleibt es trotzdem hängen.
3. img.onloadwindow.onload gibt uns eine Idee. Können wir den Ladevorgang nicht direkt überwachen?
Verwenden Sie das Ladeereignis von img, um das erfolgreiche Laden des Bildes zu überwachen und dann den Zeicheneffekt der Leinwand auszuführen. Diese Methode ist zuverlässiger.
bgImg.onload = function(){ console.log('Bild erfolgreich geladen'); ctx1.drawImage(bgImg,0,0,wWidth,wHeight);Tatsächlich haben diese drei Methoden alle den gleichen Kern, nämlich das Laden des Bildes zuerst. Das heißt, das Vorladen von Bildern. Bei zwischengespeicherten Bildern muss das Vorladen von Bildern jedoch auch das Problem der Überwachung zwischengespeicherter Bilder lösen, wenn die Seite nicht aktualisiert wird.
Habe ein anderes Problem gefunden. . . . Hier sehen Sie zunächst, wie das Hintergrundgemälde nach der Fertigstellung aussieht.
Dann kam endlich das Hintergrundbild heraus und ich machte glücklich weiter.
Also habe ich sofort eine rote Linie gezeichnet, um sie nicht zu sehen, habe ich auch die Breite auf 20 erhöht:
bgImg.onload = function(){ ctx1.drawImage(bgImg,0,0,wWidth,wHeight } /* Zeichnen Sie die rote Linie wie folgt: */ ctx1.moveTo(10,wHeight); ctx1.lineTo (10,wHeight-100); ctx1.lineWidth = 20; ctx1.StrokeStyle = 'red'; ctx1.Stroke();Aber wenn ich F5 drücke, gibt es immer noch keine Änderung und ich kann die rote Linie immer noch nicht sehen.
Nach langer Suche habe ich es erst gesehen, als ich das Hintergrundbild ausgeschaltet habe:
Ah, es stellt sich heraus, dass er vom Hintergrundbild verdeckt wurde!
Aber warum?
Ich denke, es gibt zwei Möglichkeiten
1. Hierarchieprobleme
2. Reihenfolgeprobleme
In Bezug auf 1 fühlt es sich an wie der Z-Index von CSS, bei dem das Hintergrundbild die rote Linie verdeckt. Könnte es sein, dass der Pegel des Hintergrundbilds höher als die rote Linie ist?
Ich hatte keine Möglichkeit, diese Hypothese zu testen, also gab ich die zweite mögliche Enthüllung auf.
Aber warum steht das Hintergrundbild oben? Liegt es daran, dass das Hintergrundbild später gezeichnet wird?
Dies kann am einfachsten durch Drucken von console.log() beobachtet werden, um die Ausführungssequenz zu beobachten.
Es stellt sich heraus, dass der Schuldige der Onload-Callback ist. Es handelt sich wie der Timer um eine asynchrone Aufgabe. Natürlich steht es hinter der Synchronisierungsaufgabe (Linien unten).
Onload scheint also eine gute Lösung zu sein, aber auch hier werden seine Mängel deutlich.
Sehr gut, es scheint, dass der versprochene Lernplan so schnell wie möglich in den Stundenplan aufgenommen werden sollte! Hahaha
Das Obige ist der gesamte Inhalt dieses Artikels. Ich hoffe, dass er für das Studium aller hilfreich ist. Ich hoffe auch, dass jeder das VeVb Wulin Network unterstützt.