Canvas มี API ที่ทรงพลังมากชื่อ DrawImage() (w3c):
หน้าที่หลักของมันคือการวาดภาพ วิดีโอ และแม้กระทั่งผืนผ้าใบอื่นๆ
คำถาม:เขามาด้วยความชื่นชมแต่กลับพลาดเป้าไป เมื่อเขาก้มศีรษะลง ก็เห็นหลุมขนาดใหญ่อยู่บนพื้น
เป็นแบบนี้ หลังจากที่ฉันอ่านบทนำของ w3c และการสาธิตการสอนที่น่าเชื่อถือ ฉันตัดสินใจลองใช้แนวคิดในการฝึกฝนเพื่อให้ได้ความรู้ที่แท้จริง ไม่สำคัญหรอก ลองมัน~
ฉันวางงานพื้นฐานต่อไปนี้ตามโครงการสายการประกอบ:
1.แท็กแคนวาส+id
<canvas id=canvas1></canvas>
2.รับแคนวาส+กำหนดความกว้างและความสูง
var cav1 = document.getElementById('canvas1'), wWidth = 800, wHeight = 600; cav1.width = wWidth;3. getContext('2d') เตรียมผืนผ้าใบ
var ctx1 = cav1.getContext('2d');4. สร้างวัตถุ Image() ใหม่ และกำหนดคุณสมบัติของภาพที่ฉันชอบ... (อย่าคิดมาก)
var bgImg = รูปภาพใหม่();bgImg.src = 'รูปภาพ/พื้นหลัง.jpg';
5. ในที่สุดก็ถึงเวลาวาด ฉันเขียนโค้ดนี้อย่างตื่นเต้น:
ctx1.drawImage(bgImg,0,0,wWidth,wHeight);
ฉันกด F5 บนเบราว์เซอร์ด้วยความไม่สบายใจ
จากนั้นก็เกิดความเงียบงัน...
ฉันคิดว่ารหัสเขียนผิด ฉันจึงกลับไปตรวจสอบอย่างละเอียด และมันก็ถูกต้อง
คัดลอกชื่อแอตทริบิวต์คีย์และวิธีการของ w3c แล้วตรวจสอบอีกครั้งว่าถูกต้องจริงๆ
พอพิมพ์รูปออกมาก็มีรูปนี้(ของคน)ด้วย!
ต่อมาเมื่อฉันสังเกตเห็นกรณี W3C สิ่งที่แตกต่างจากโค้ดของฉันคือรูปภาพของมันอยู่ในรูปแบบ HTML
จากนั้นฉันก็เรียนรู้ที่จะแทรกรูปภาพลงใน html
<img src=./images/พื้นหลัง.jpg id=imgs style=display:none></img>
และใช้ getElementById เพื่อรับองค์ประกอบนี้
var bgImg = document.getElementById('imgs')การดำเนินการวาดภาพได้ผลอีกครั้ง
เขาทำได้จริงๆ!
ฉันคิดว่าน่าเศร้า มันจะต้องมีทางกายภาพหรือไม่? มันไม่ได้วางไว้หน้าแท็กแคนวาสใช่ไหม การโหลด js ก็มีเอนทิตีและฉันยังคงใช้ใหม่ แตกต่างจากคนจริงๆ มาก!
จริงสิ วางไว้ข้างหน้าไม่ใช่เหรอ? เรื่องนี้เกี่ยวข้องกับปัญหาลำดับ!
เป็นความจริงที่ว่ารูปภาพที่โหลดใน js จะถูกวางไว้ด้านหน้าภาพวาด แต่จะใช้เวลาสักครู่ในการโหลดรูปภาพ ต้องให้เวลาสำหรับการบัฟเฟอร์ภาพ รอจนกระทั่งโหลดรูปภาพสำเร็จก่อนจึงจะสามารถวาดได้ เมธอด DrawImage จะไม่ถูกเรียกเมื่อใช้รูปภาพก่อนที่จะโหลด การวาดภาพจะล้มเหลว ฉันเห็น!
บางคนแย้งว่ารูปภาพในแท็ก img ใช้เวลาโหลดไม่นานใช่หรือไม่ ในเวลานี้ DrawImage ไม่ถูกจำกัดใช่ไหม? - แต่อย่ามองข้าม window.onload ที่จุดเริ่มต้นของ js แม้ว่ารูปภาพจะโหลดช้า แม้ว่าแท็กรูปภาพจะอยู่หลังแท็ก canvas แต่ฉันมี window.onload บังอยู่ รูปภาพของฉันไม่สามารถ โหลดแล้ว และ DrawImage ของคุณจะไม่มีโอกาสใช่ไหม?
ลำดับโดยประมาณคือ:
<img src=>window.onload = function(){ DrawImage}หากรูปภาพไม่ได้ถูกแทรกในโครงสร้าง html ข้อจำกัดนี้คงผ่านไปได้ด้วยความประมาทของฉัน:
ตามคำขอทรัพยากร เมื่อโหลดรูปภาพใน js จะมีเวลาในการโหลดรูปภาพตามธรรมชาติ
แต่เนื่องจากไม่มีขีดจำกัด ในกรณีส่วนใหญ่ DrawImage จึงถูกเรียกเมื่อรูปภาพไม่ได้ถูกโหลด และวิธีนี้จะไม่ทำงาน
แก้ปัญหา:มีวิธีที่ดีในการแก้ไขปัญหาการวาดภาพ DrawImage ล้มเหลวเนื่องจากลำดับการโหลดรูปภาพหรือไม่
ฉันได้สรุปสามวิธีต่อไปนี้:
1. แท็ก + window.onload <img src=>window.onload = function(){ context.drawImage()}โซลูชันหลักของแนวทางนี้คือ onload ซึ่งจะโหลดรูปภาพและ DrawImage แยกกัน img จะถูกโหลดก่อนเพื่อให้แน่ใจว่าจะใช้ภาพวาดหลังจากการโหลดเสร็จสิ้น
1-2. ใส่แท็กทีหลัง? เป็นไปได้ไหมสถานการณ์หนึ่งคือเมื่อใช้ฟังก์ชันภาพหน้าจอ คุณยังสามารถใช้ DrawImage ได้ และภาพหน้าจอจะไม่จับภาพหน้าจอของภาพที่คุณมีอยู่ แต่ใช้ที่อยู่ของภาพเป็นพารามิเตอร์
ฉันคิดว่าสิ่งนี้ต้องการ js เพื่อสร้าง img และกำหนดที่อยู่ให้กับมัน จากนั้นสร้างภาพและถ่ายภาพหน้าจอ
var myImg = document.createElement('img');myImg.src = '///';document.body.appendChild(myImg);ctx1.drawImage(myImg,0,0,wWidth,wHeight);ไม่ต้องการที่จะเพิ่มแท็กพิเศษ? ฉันจำเป็นต้องใช้ js ดังที่แสดงด้านล่างเพื่อสร้างออบเจ็กต์รูปภาพใหม่หรือไม่
var bgImg = รูปภาพใหม่();bgImg.src = 'รูปภาพ/พื้นหลัง.jpg';
ตามที่กล่าวไว้ก่อนหน้านี้ รูปภาพประเภทนี้ที่สร้างขึ้นโดยใช้ new Image() ต้องใช้เวลาในการบัฟเฟอร์รูปภาพ รอจนกระทั่งโหลดรูปภาพสำเร็จก่อนจึงจะสามารถวาดได้
วัตถุรูปภาพพร้อมแล้ว แต่คุณจะรู้ได้อย่างไรว่ารูปภาพถูกโหลดจริงเมื่อใด มีวิธีอื่น:
ขณะที่กำลังดำเนินการงาน js คุณคิดว่าฉันใกล้เวลาดำเนินการของคุณมากเกินไปหรือไม่ คุณช่วยพาฉันออกไปคนเดียวแล้วจัดคิวให้ฉันอีกครั้ง แล้วดำเนินการอีกครั้งในภายหลังได้ไหม
2. การใช้งานแบบอะซิงโครนัสแบบจับเวลา setTimeout (ฟังก์ชั่น () { ctx1.drawImage (bgImg, 0,0, wWidth, wHeight);}, 10)เหตุใดความล่าช้าในการเขียน 10 ที่นี่แทนที่จะเป็น 1,000 หรือ 0 ที่คุ้นเคย
เนื่องจากภายใต้การทดสอบสภาพแวดล้อม wifi เฉพาะของฉันและคอมพิวเตอร์เดสก์ท็อปเฉพาะ 10 รายการสามารถออกมาได้หลังจากโหลดรูปภาพแล้ว ไม่เหมือน 0 ที่ไม่ออกมา และฉันไม่ต้องการรอครึ่งวันเช่น 1,000
แต่ลองนึกดูว่าถ้าเปลี่ยนภาพให้ใหญ่ขึ้น 10 นี้จะยังใช้อยู่ไหม? ถ้าเปลี่ยน wifi เป็น 2g แล้ว 10 นี่จะยังใช้อยู่ไหม?
ดังนั้นข้อเสียของการจับเวลาคือไม่มีการรับประกันว่าภาพจะถูกโหลดหลังจากหมดเวลาและจะยังคงวางสายหากเครือข่ายไม่เร็ว
3.img.onloadwindow.onload ให้แนวคิดแก่เรา เราไม่สามารถตรวจสอบความสำเร็จในการโหลดได้โดยตรงหรือ
ใช้เหตุการณ์การโหลด img เพื่อตรวจสอบการโหลดรูปภาพที่สำเร็จ จากนั้นดำเนินการเอฟเฟกต์การวาดของผืนผ้าใบ และวิธีนี้มีความน่าเชื่อถือมากกว่า
bgImg.onload = function(){ console.log('โหลดรูปภาพสำเร็จ'); console.log(สิ่งนี้); ctx1.drawImage(bgImg,0,0,wWidth,wHeight);ในความเป็นจริง ทั้งสามวิธีนี้ล้วนมีแกนหลักเดียวกัน ซึ่งก็คือให้โหลดรูปภาพก่อน นั่นคือการโหลดรูปภาพล่วงหน้า แต่สำหรับรูปภาพที่แคชไว้ การโหลดรูปภาพล่วงหน้ายังต้องแก้ปัญหาการตรวจสอบรูปภาพที่แคชไว้เมื่อเพจไม่ได้รับการรีเฟรช
พบปัญหาอื่น - - - ขั้นแรก ต่อไปนี้คือลักษณะของการทาสีพื้นหลังหลังจากเสร็จสิ้น
ในที่สุดก็มีภาพพื้นหลังออกมา และฉันก็พูดต่ออย่างมีความสุข
ดังนั้นฉันจึงวาดเส้นสีแดงทันทีเพื่อหลีกเลี่ยงไม่ให้มองเห็น ฉันจึงเพิ่มความกว้างเป็น 20 ด้วย:
bgImg.onload = function(){ ctx1.drawImage(bgImg,0,0,wWidth,wHeight); } /* วาดเส้นสีแดงดังนี้: */ ctx1.beginPath(); ctx1.moveTo(10,wHeight); ctx1.lineTo (10,wHeight-100); ctx1.lineWidth = 20; ctx1. strokeStyle = 'สีแดง';แต่พอกด F5 ก็ยังไม่มีการเปลี่ยนแปลงและยังไม่เห็นเส้นสีแดง
หลังจากค้นหาอยู่นานฉันก็ไม่เห็นมันจนกระทั่งฉันปิดภาพพื้นหลัง:
อ่า ปรากฎว่าเขาถูกภาพพื้นหลังบังไว้!
แต่ทำไม?
ฉันคิดว่ามีความเป็นไปได้สองประการ
1. ปัญหาลำดับชั้น
2. ปัญหาลำดับ
เกี่ยวกับ 1 มันให้ความรู้สึกเหมือนดัชนี z ของ CSS โดยที่ภาพพื้นหลังครอบคลุมเส้นสีแดง เป็นไปได้ไหมว่าระดับของภาพพื้นหลังสูงกว่าเส้นสีแดง?
ฉันไม่มีทางทดสอบสมมติฐานนี้ได้ ดังนั้นฉันจึงล้มเลิกการเปิดเผยครั้งที่สองที่เป็นไปได้
แต่ทำไมภาพพื้นหลังถึงอยู่ด้านบน? เป็นเพราะภาพพื้นหลังถูกวาดทีหลังหรือเปล่า?
สิ่งนี้สามารถสังเกตได้ง่ายที่สุดผ่านการพิมพ์ console.log() เพื่อสังเกตลำดับการดำเนินการ
ปรากฎว่าผู้ร้ายคือการเรียกกลับออนโหลด เช่นเดียวกับตัวจับเวลา มันเป็นงานแบบอะซิงโครนัส โดยปกติแล้ว มันถูกจัดอันดับอยู่เบื้องหลังงานการซิงโครไนซ์ (วาดเส้นด้านล่าง)
ดังนั้น onload ดูเหมือนจะเป็นวิธีแก้ปัญหาที่ดี แต่ก็มีข้อบกพร่องของมันก็ถูกเปิดเผยเช่นกัน
ดีมากดูเหมือนว่าควรจะวางแผนการเรียนรู้ตามสัญญาโดยเร็วที่สุด! ฮ่าๆๆ
ข้างต้นคือเนื้อหาทั้งหมดของบทความนี้ ฉันหวังว่ามันจะเป็นประโยชน์ต่อการศึกษาของทุกคน ฉันหวังว่าทุกคนจะสนับสนุน VeVb Wulin Network