Canvas possède une API très puissante appelée drawImage() (w3c) :
Sa fonction principale est de dessiner des images, des vidéos et même d'autres toiles.
question:Il est venu là avec admiration, mais a raté le but. Lorsqu'il a baissé la tête, il a vu un grand trou au sol.
Le truc est comme ça, après avoir lu l'introduction de w3c et la démo très convaincante et pédagogique, j'ai décidé de l'essayer en me basant sur l'idée de s'entraîner pour acquérir de vraies connaissances. essayez-le ~
J'ai défini les tâches de base suivantes en fonction du projet de chaîne de montage :
1. balise de toile + identifiant
<identifiant du canevas=canvas1></canvas>
2. Obtenez la toile + définissez la largeur et la hauteur
var cav1 = document.getElementById('canvas1'), wWidth = 800, wHeight = 600 ; cav1.width = wWidth ;3. getContext('2d') prépare le canevas
var ctx1 = cav1.getContext('2d');4. Créez un nouvel objet Image() et donnez-lui les attributs des images que j'aime... (ne réfléchissez pas trop)
var bgImg = new Image();bgImg.src = 'images/background.jpg';
5. Enfin, il est temps de dessiner. J'ai écrit ce code avec enthousiasme :
ctx1.drawImage(bgImg,0,0,wWidth,wHeight);
Énervé, j'ai appuyé sur F5 sur le navigateur.
Puis il y eut un silence de mort...
Je pensais que le code était mal écrit, alors je suis revenu et je l'ai vérifié attentivement, et il était correct.
Copiez les noms d'attributs clés et les méthodes du w3c et vérifiez à nouveau que c'est bien correct.
Lorsque l’image est imprimée, il y a aussi cette image (d’une personne) !
Plus tard, lorsque j'ai observé le cas du W3C, la différence avec mon code est que ses images sont en HTML.
Puis j'ai appris à insérer des images en HTML,
<img src=./images/background.jpg id=imgs style=display:none></img>
Et utilisez getElementById pour obtenir cet élément,
var bgImg = document.getElementById('imgs')L'exécution du dessin a de nouveau fonctionné.
Il le peut réellement !
Je pense malheureusement, est-ce que ça doit être physique ? N'est-il pas simplement placé devant la balise canvas ? js chargement a également des entités, et j'en utilise toujours de nouvelles, comme c'est différent des vraies personnes !
C'est vrai, n'est-il pas simplement mis devant ? Cela implique un problème de séquence !
Il est vrai que l'image chargée en js est placée devant le dessin, mais le chargement de l'image prendra un certain temps. Il faut accorder du temps à la mise en mémoire tampon des images. Attendez que l'image soit chargée avec succès avant de pouvoir la dessiner. La méthode drawImage ne sera pas appelée lorsque l'image est utilisée avant son chargement. Le dessin échouera. Je vois!
Certaines personnes prétendent-elles que les images dans les balises img ne prennent pas de temps à se charger ? À l'heure actuelle, drawImage n'est pas restreint ? ! Mais n'ignorez pas le window.onload au début de js. Même si l'image est chargée lentement, même si l'ordre des balises d'image est après la balise canvas, mais que window.onload la recouvre, mon image ne peut pas être. chargé, et votre drawImage n'aura aucune chance, n'est-ce pas ?
L'ordre approximatif est le suivant :
<img src=>window.onload = function(){ drawImage}Si l'image n'avait pas été insérée dans la structure html, cette restriction aurait été contournée par ma négligence :
En tant que demande de ressources, lorsque l'image est chargée dans js, il y aura naturellement un temps de chargement de l'image.
Mais comme il n'y a pas de limite, dans la plupart des cas, drawImage est appelé lorsque l'image n'a pas été chargée, et cette méthode ne fonctionnera pas.
résoudre:Existe-t-il donc un bon moyen de résoudre le problème de l'échec du dessin drawImage en raison de la séquence de chargement de l'image ?
J'ai résumé les trois méthodes suivantes :
1. balise+window.onload <img src=>window.onload = function(){ context.drawImage()}La solution principale de cette approche est onload, qui charge l'image et drawImage séparément. L'img est chargé en premier pour garantir que le dessin est utilisé une fois le chargement terminé.
1-2. Insérer des balises plus tard ? Est-ce faisableUne situation est que lorsque vous utilisez la fonction de capture d'écran, vous pouvez également utiliser drawImage, et la capture d'écran ne prend pas une capture d'écran de votre propre image existante, mais utilise l'adresse d'une image comme paramètre.
Je pense que ce genre de chose nécessite que js crée une image et lui attribue l'adresse, puis génère l'image et prend une capture d'écran.
var monImg = document.createElement('img');myImg.src = '///';document.body.appendChild(myImg);ctx1.drawImage(myImg,0,0,wWidth,wHeight);Vous ne souhaitez pas ajouter de balises supplémentaires ? Dois-je utiliser js comme indiqué ci-dessous pour créer un nouvel objet image ?
var bgImg = new Image();bgImg.src = 'images/background.jpg';
Comme mentionné précédemment, ce type d'image créée à l'aide de new Image() nécessite du temps pour mettre l'image en mémoire tampon. Attendez que l'image soit chargée avec succès avant de pouvoir la dessiner.
L'objet image est prêt, mais comment savoir quand l'image est réellement chargée ? Eh bien, il existe un autre moyen :
Pendant que la tâche js est en cours d'exécution, pensez-vous que je suis trop proche de votre temps d'exécution ? Pouvez-vous me sortir seul et me mettre à nouveau en file d'attente, puis l'exécuter à nouveau plus tard ?
2. Implémentation asynchrone du minuteur setTimeout(function(){ ctx1.drawImage(bgImg,0,0,wWidth,wHeight);},10)Pourquoi le retard dans l'écriture de 10 ici au lieu du habituel 1000 ou 0 ?
Parce que sous le test de mon environnement wifi spécifique et de mon ordinateur de bureau spécifique, 10 peut juste sortir après le chargement de l'image, contrairement à 0 qui ne sort pas, et je ne veux pas attendre une demi-journée comme 1000.
Mais imaginez que si vous changez l’image pour une image plus grande, ce 10 s’appliquerait-il toujours ? Ce 10 s'appliquera-t-il toujours si le Wi-Fi passe à 2 G ?
Par conséquent, l'inconvénient de la minuterie est qu'il n'y a aucune garantie que l'image sera chargée une fois le temps écoulé, et elle raccrochera toujours si le réseau n'est pas rapide.
3. img.onloadwindow.onload nous donne une idée. Ne pouvons-nous pas surveiller directement l'achèvement du chargement ?
Utilisez l'événement de chargement de img pour surveiller le chargement réussi de l'image, puis exécutez l'effet de dessin du canevas. Et cette méthode est plus fiable.
bgImg.onload = function(){ console.log('Image chargée avec succès'); console.log(this); ctx1.drawImage(bgImg,0,0,wWidth,wHeight);En fait, ces trois méthodes ont toutes le même noyau, qui consiste à laisser l’image se charger en premier. C'est-à-dire le préchargement de l'image. Mais pour les images mises en cache, le préchargement des images doit également résoudre le problème de la surveillance des images mises en cache lorsque la page n'est pas actualisée.
J'ai trouvé un autre problème. . . . Tout d’abord, voici à quoi ressemble la peinture d’arrière-plan une fois terminée.
Puis l’image de fond est finalement sortie et j’ai continué joyeusement.
J'ai donc immédiatement tracé une ligne rouge Pour éviter de ne pas la voir, j'ai également augmenté la largeur à 20 :
bgImg.onload = function(){ ctx1.drawImage(bgImg,0,0,wWidth,wHeight); } /* Tracez la ligne rouge comme suit : */ ctx1.beginPath(); ctx1.moveTo(10,wHeight); ctx1.lineTo (10,wHauteur-100); ctx1.lineWidth = 20 ; ctx1.StrokeStyle = 'rouge'; ctx1.Stroke();Mais lorsque j’appuie sur F5, il n’y a toujours aucun changement et je ne vois toujours pas la ligne rouge.
Après avoir longtemps cherché, je ne l'ai vu que lorsque j'ai désactivé l'image d'arrière-plan :
Ah, il s'avère qu'il était couvert par l'image d'arrière-plan !
Mais pourquoi ?
Je pense qu'il y a deux possibilités
1. Problèmes de hiérarchie
2. Problèmes de séquence
Concernant 1, cela ressemble au z-index du CSS, où l'image d'arrière-plan recouvre la ligne rouge. Se pourrait-il que le niveau de l’image d’arrière-plan soit supérieur à la ligne rouge ?
Je n’avais aucun moyen de tester cette hypothèse, j’ai donc abandonné la deuxième révélation possible.
Mais pourquoi l’image d’arrière-plan est-elle en haut ? Est-ce parce que l’image d’arrière-plan est dessinée plus tard ?
Cela peut être plus facilement observé via l'impression console.log() pour observer la séquence d'exécution.
Il s'avère que le coupable est le rappel onload. Comme le timer, c'est une tâche asynchrone. Naturellement, il est classé derrière la tâche de synchronisation (traçage des lignes ci-dessous)
Le onload semble donc être une bonne solution, mais ses défauts sont également exposés ici.
Très bien, il semblerait que la promesse du plan d'apprentissage devrait être inscrite au planning au plus vite ! Hahaha
Ce qui précède représente l’intégralité du contenu de cet article. J’espère qu’il sera utile à l’étude de chacun. J’espère également que tout le monde soutiendra le réseau VeVb Wulin.