ก่อนที่เราจะเริ่มวาดรูปเราต้องพูดคุยเกี่ยวกับตารางผ้าใบหรือ พื้นที่พิกัด เทมเพลต HTML ในหน้าก่อนหน้ามีองค์ประกอบผืนผ้าใบกว้าง 150 พิกเซลและสูง 150 พิกเซล ฉันวาดภาพนี้ด้วยกริดเริ่มต้นที่ซ้อนทับ โดยปกติ 1 หน่วยในกริดจะสอดคล้องกับ 1 พิกเซลบนผืนผ้าใบ ที่มาของกริดนี้อยู่ในตำแหน่งที่มุมซ้ายบน (พิกัด (0,0)) องค์ประกอบทั้งหมดถูกวางไว้เมื่อเทียบกับแหล่งกำเนิดนี้ ดังนั้นตำแหน่งของมุมบนซ้ายของสี่เหลี่ยมสีน้ำเงินจึงกลายเป็น x พิกเซลจากด้านซ้ายและพิกเซล y จากด้านบน (พิกัด (x, y)) ต่อมาในบทช่วยสอนนี้เราจะเห็นว่าเราสามารถแปลต้นกำเนิดไปยังตำแหน่งที่แตกต่างกันหมุนกริดและปรับขนาดได้อย่างไร ตอนนี้เราจะยึดติดกับค่าเริ่มต้น
ก่อนที่เราจะเริ่มต้นจริงๆเราต้องสำรวจกริดหรือ พิกัด พื้นที่ของผืนผ้าใบ มีความกว้าง 150 พิกเซลและสูง 150 พิกเซลในเทมเพลต HTML ในหน้าก่อนหน้า ฉันซ้อนทับกริดเริ่มต้นบนหน้าจอดังที่แสดงในรูปภาพทางด้านขวา โดยปกติแล้วเซลล์หนึ่งของกริดจะสอดคล้องกับหนึ่งพิกเซลบนผืนผ้าใบ ต้นกำเนิดของกริดอยู่ในตำแหน่งที่มุมซ้ายบน (พิกัด (0,0)) ตำแหน่งของวัตถุทั้งหมดในภาพนั้นสัมพันธ์กับแหล่งกำเนิดนี้ ด้วยวิธีนี้ตำแหน่งของจัตุรัสสีน้ำเงินที่มุมซ้ายบนคือ x พิกเซล x จากซ้ายและพิกเซล y จากด้านบน (พิกัด (x, y)) ในบทช่วยสอนต่อไปนี้เราจะได้เรียนรู้วิธีการย้ายที่มาหมุนและปรับขนาดกริด แต่ตอนนี้เราจะใช้สถานะเริ่มต้น
ซึ่งแตกต่างจาก SVG, ผืนผ้าใบรองรับเพียงรูปแบบดั้งเดิมหนึ่งรูปแบบ - สี่เหลี่ยม รูปร่างอื่น ๆ ทั้งหมดจะต้องถูกสร้างขึ้นโดยการรวมเส้นทางอย่างน้อยหนึ่งเส้นทาง โชคดีที่เรามีคอลเลกชันของฟังก์ชั่นการวาดเส้นทางที่ทำให้สามารถเขียนรูปร่างที่ซับซ้อนมาก
ซึ่งแตกต่างจาก SVG, Canvas รองรับเพียงรูปทรงพื้นฐานหนึ่งรูปแบบ - รูปสี่เหลี่ยมดังนั้นรูปร่างอื่น ๆ จึงประกอบด้วยเส้นทางหนึ่งหรือมากกว่า โชคดีที่มีชุดของฟังก์ชั่นการวาดเส้นทางที่ช่วยให้เราสามารถวาดรูปร่างที่ค่อนข้างซับซ้อน
ก่อนอื่นลองดูที่สี่เหลี่ยม มีสามฟังก์ชั่นที่วาดรูปสี่เหลี่ยมบนผืนผ้าใบ:
ก่อนอื่นให้ดูที่สี่เหลี่ยม มีสามฟังก์ชั่นสำหรับการวาดรูปสี่เหลี่ยม:
Fillrect (x, y, ความกว้าง, ความสูง): วาดสี่เหลี่ยมผืนผ้าที่เติมเต็ม Strokerect (x, y, ความกว้าง, ความสูง): วาดโครงร่างรูปสี่เหลี่ยมผืนผ้า Clearrect (x, y, ความกว้าง, ความสูง): ล้างพื้นที่ที่ระบุและทำให้โปร่งใสอย่างเต็มที่แต่ละฟังก์ชั่นทั้งสามนี้ใช้พารามิเตอร์เดียวกัน X และ Y ระบุตำแหน่งบนผืนผ้าใบ (เทียบกับจุดกำเนิด) ของมุมบนซ้ายของสี่เหลี่ยม ความกว้างและความสูงค่อนข้างชัดเจน มาดูฟังก์ชั่นเหล่านี้ในการดำเนินการ
พวกเขาทั้งหมดยอมรับสี่พารามิเตอร์ x และ y ระบุตำแหน่งของมุมซ้ายบนของสี่เหลี่ยม (เทียบกับต้นกำเนิด) และความกว้างและความสูงคือความกว้างและความสูงของสี่เหลี่ยมผืนผ้า โอเคมาต่อสู้กันเถอะ
ด้านล่างคือฟังก์ชั่น Draw () จากหน้าก่อนหน้า แต่ตอนนี้ฉันได้เพิ่มฟังก์ชั่นทั้งสามด้านบน
ต่อไปนี้คือฟังก์ชั่น Draw () ในเทมเพลตในหน้าก่อนหน้า แต่มีการเพิ่มฟังก์ชั่นทั้งสามข้างต้น
ดูตัวอย่าง
ฟังก์ชั่นการวาด () {var canvas = document.getElementById ('การสอน'); if (canvas.getContext) {var ctx = canvas.getContext ('2d'); CTX.Fillrect (25,25,100,100); CTX.ClearRect (45,45,60,60); ctx.strokerect (50,50,50,50); -ผลลัพธ์ควรมีลักษณะเหมือนภาพทางด้านขวา ฟังก์ชั่น Fillrect ดึงสี่เหลี่ยมจัตุรัสขนาดใหญ่สีดำ 100x100 พิกเซล ฟังก์ชั่น ClearRect จะลบสี่เหลี่ยมจัตุรัส 60x60 พิกเซลออกจากศูนย์และในที่สุดก็มีการดึงรูปทรงสี่เหลี่ยม 50x50 พิกเซลภายในสี่เหลี่ยมจัตุรัส ในหน้าต่อไปนี้เราจะเห็นวิธีการทางเลือกสองวิธีสำหรับฟังก์ชั่น ClearRect และเราจะดูวิธีเปลี่ยนสีและสไตล์จังหวะของรูปร่างที่แสดงผล
ผลลัพธ์ควรเหมือนกับที่ด้านขวา ฟังก์ชั่น Fillrect ดึงสี่เหลี่ยมผืนผ้าสีดำขนาดใหญ่ (100x100) ฟังก์ชั่น ClearRect จะล้างสี่เหลี่ยมขนาด 60x60 ที่อยู่ตรงกลางจากนั้นฟังก์ชั่น Strokerect จะจัดทำเส้นขอบสี่เหลี่ยม 50x50 ในพื้นที่ล้าง ในหน้าถัดไปเราจะเห็นวิธีอื่นอีกสองวิธีที่คล้ายกับฟังก์ชั่น ClearRect รวมถึงวิธีการเปลี่ยนสีเติมและเส้นขอบของรูป
ซึ่งแตกต่างจากฟังก์ชั่นพา ธ ที่เราเห็นในส่วนถัดไปฟังก์ชั่นสี่เหลี่ยมทั้งสามจะวาดลงบนผืนผ้าใบทันที
ซึ่งแตกต่างจากฟังก์ชั่นพา ธ ในส่วนถัดไปผลกระทบของฟังก์ชั่นทั้งสามนี้จะสะท้อนลงบนผืนผ้าใบทันที
ในการสร้างรูปร่างโดยใช้เส้นทางเราต้องมีขั้นตอนพิเศษสองสามขั้นตอน
ซึ่งแตกต่างจากการวาดรูปสี่เหลี่ยมผืนผ้าการวาดเส้นทางต้องใช้ขั้นตอนพิเศษบางอย่าง
chartPath () ClosePath () จังหวะ () เติม ()ขั้นตอนแรกในการสร้างเส้นทางคือการเรียกใช้วิธีการเริ่มต้น ภายในเส้นทางจะถูกเก็บไว้เป็นรายการของเส้นทางย่อย (เส้น, อาร์ค, ฯลฯ ) ซึ่งรวมกันเป็นรูปร่าง ทุกครั้งที่มีการเรียกวิธีการนี้รายการจะถูกรีเซ็ตและเราสามารถเริ่มวาดรูปทรงใหม่
ขั้นตอนแรกคือการสร้างเส้นทางที่มี Beginpath ในหน่วยความจำเส้นทางจะถูกเก็บไว้ในรูปแบบของชุดของ subpaths (เส้น, ส่วนโค้ง ฯลฯ ) ซึ่งรวมกันเป็นกราฟ แต่ละครั้งเริ่มต้นการเริ่มต้นจะถูกเรียกกลุ่ม SubPath จะถูกรีเซ็ตและสามารถวาดกราฟใหม่ได้
ขั้นตอนที่สองคือการเรียกวิธีการที่ระบุเส้นทางที่จะวาด เราจะเห็นสิ่งเหล่านี้ในไม่ช้า
ขั้นตอนที่สองคือการวาดส่วนหนึ่งของเส้นทางซึ่งเราจะเห็นเร็ว ๆ นี้
ขั้นตอนที่สามและขั้นตอนเสริมคือการเรียกวิธีการ ClosePath วิธีนี้พยายามปิดรูปร่างโดยการวาดเส้นตรงจากจุดปัจจุบันไปยังจุดเริ่มต้น หากรูปร่างถูกปิดแล้วหรือมีเพียงจุดเดียวในรายการฟังก์ชั่นนี้จะไม่ทำอะไรเลย
ขั้นตอนที่สามคือการเรียกใช้วิธี ClosePath ซึ่งจะพยายามเชื่อมต่อจุดสิ้นสุดปัจจุบันเข้ากับจุดเริ่มต้นที่เริ่มต้นด้วยเส้นตรงเพื่อปิดเส้นทาง แต่ถ้ากราฟปิดอยู่แล้วหรือมีเพียงจุดเดียวก็จะไม่ทำอะไรเลย ขั้นตอนนี้ไม่จำเป็น
ขั้นตอนสุดท้ายคือการเรียกใช้จังหวะและ/หรือวิธีการเติม การเรียกหนึ่งในสิ่งเหล่านี้จะดึงรูปร่างไปยังผืนผ้าใบ Stroke ใช้เพื่อวาดรูปร่างที่ระบุไว้ในขณะที่การเติมจะถูกใช้เพื่อทาสีรูปร่างที่เป็นของแข็ง
ขั้นตอนสุดท้ายคือการเรียกใช้วิธีการสโตรกหรือการเติมและในเวลานี้กราฟจะถูกวาดบนผืนผ้าใบจริง ๆ Stroke เป็นเส้นขอบที่ดึงรูปเติมเต็มจะเติมด้วยรูปที่มั่นคง
หมายเหตุ: เมื่อเรียกใช้วิธีการเติมรูปร่างที่เปิดจะถูกปิดโดยอัตโนมัติและไม่จำเป็นต้องใช้วิธี ClosePath หมายเหตุ: เมื่อเรียกว่าการเติมพา ธ เปิดจะปิดโดยอัตโนมัติโดยไม่ต้องโทรไปที่ closepathรหัสสำหรับการวาดรูปแบบเรียบง่าย (สามเหลี่ยม) จะมีลักษณะเช่นนี้
รหัสสำหรับการวาดรูปเรียบง่าย (เช่นสามเหลี่ยม) มีดังนี้
ctx.beginpath (); ctx.moveto (75,50); ctx.lineto (100,75); ctx.lineto (100,25); ctx.fill ();
หนึ่งฟังก์ชั่นที่มีประโยชน์มากซึ่งไม่ได้วาดอะไรเลย แต่เป็นส่วนหนึ่งของรายการพา ธ ที่อธิบายไว้ข้างต้นคือฟังก์ชัน Moveto คุณอาจคิดได้ดีที่สุดในการยกปากกาหรือดินสอจากจุดหนึ่งบนกระดาษและวางไว้บนถัดไป
Moveto เป็นวิธีที่มีประโยชน์มาก แม้ว่ามันจะไม่สามารถใช้ในการวาดอะไรก็ได้ แต่ก็เป็นส่วนหนึ่งของวิธีการวาดเส้นทาง คุณสามารถคิดว่ามันเป็นกระบวนการยกปากกาและเคลื่อนย้ายจากจุดหนึ่งไปอีกจุดหนึ่ง
Moveto (x, y)ฟังก์ชั่น Moveto ใช้สองข้อโต้แย้งคือ X และ Y - ซึ่งเป็นพิกัดของจุดเริ่มต้นใหม่
มันยอมรับ X และ Y (ตำแหน่งพิกัดใหม่) เป็นพารามิเตอร์
เมื่อผืนผ้าใบเริ่มต้นหรือเรียกใช้วิธีการเริ่มต้นจุดเริ่มต้นจุดเริ่มต้นจะถูกตั้งค่าเป็นพิกัด (0,0) ในกรณีส่วนใหญ่เราจะใช้วิธี Moveto เพื่อวางจุดเริ่มต้นที่อื่น นอกจากนี้เรายังสามารถใช้วิธีการ Moveto เพื่อวาดเส้นทางที่ไม่ได้เชื่อมต่อ ลองดูที่ใบหน้าที่ยิ้มแย้มทางด้านขวา ฉันทำเครื่องหมายสถานที่ที่ฉันใช้วิธีการ Moveto (เส้นสีแดง)
เมื่อผ้าใบเริ่มต้นหรือเรียกใช้เริ่มต้นการตั้งค่าพิกัดเริ่มต้นคือจุดกำเนิด (0,0) ในกรณีส่วนใหญ่เราใช้วิธี Moveto เพื่อย้ายพิกัดเริ่มต้นไปยังสถานที่อื่นหรือเพื่อวาดเส้นทางที่ไม่ต่อเนื่อง ดูที่ใบหน้าที่ยิ้มแย้มทางด้านขวาเส้นสีแดงเป็นเส้นทางการเคลื่อนที่โดยใช้ Moveto
ในการลองทำด้วยตัวเองคุณสามารถใช้ตัวอย่างโค้ดด้านล่าง เพียงแค่วางลงในฟังก์ชั่นการวาดที่เราเห็นก่อนหน้านี้
ลองใช้รหัสต่อไปนี้และวางลงในฟังก์ชั่นการวาดที่คุณใช้ก่อนเพื่อดูเอฟเฟกต์
ctx.beginpath (); ctx.arc (75,75,50,0, math.pi*2, จริง); // Outer Circuitx.Moveto (110,75); CTX.ARC (75,75,35,0, Math.pi, False); // ปาก (ตามเข็มนาฬิกา) ctx.moveto (65,65); ctx.arc (60,65,5,0, math.pi*2, จริง); // left eyectx.moveto (95,65); ctx.arc (90,65,5,0, math.pi*2, จริง); // eyectx.stroke ();หมายเหตุ : ลบวิธีการ Moveto เพื่อดูเส้นเชื่อมต่อ หมายเหตุ : สำหรับคำอธิบายของฟังก์ชั่น ARC และพารามิเตอร์ของมันดูด้านล่าง หมายเหตุ: คุณสามารถแสดงความคิดเห็นวิธีการ Moveto เพื่อสังเกตบรรทัดที่เชื่อมต่อ หมายเหตุ: การใช้วิธี ARC แสดงอยู่ด้านล่าง
สำหรับการวาดเส้นตรงเราใช้วิธี Lineto
เราใช้วิธี Lineto ในการวาดเส้นตรง
lineto (x, y)วิธีนี้ใช้สองอาร์กิวเมนต์ - X และ Y - ซึ่งเป็นพิกัดของจุดสิ้นสุดของบรรทัด จุดเริ่มต้นขึ้นอยู่กับเส้นทางที่วาดก่อนหน้านี้ซึ่งจุดสิ้นสุดของเส้นทางก่อนหน้าคือจุดเริ่มต้นสำหรับสิ่งต่อไปนี้ ฯลฯ จุดเริ่มต้นยังสามารถเปลี่ยนแปลงได้โดยใช้วิธี Moveto
วิธี Lineto ยอมรับพิกัด (x, y) ของจุดสิ้นสุดเป็นพารามิเตอร์ พิกัดเริ่มต้นขึ้นอยู่กับเส้นทางก่อนหน้า จุดสิ้นสุดของเส้นทางก่อนหน้าคือจุดเริ่มต้นของเส้นทางปัจจุบัน พิกัดเริ่มต้นยังสามารถตั้งค่าผ่านวิธี Moveto
ในตัวอย่างด้านล่างรูปสามเหลี่ยมสองรูปมีการวาดหนึ่งอันและหนึ่งที่ระบุไว้ (ผลลัพธ์สามารถเห็นได้ในภาพทางด้านขวา) ก่อนอื่นวิธีการเริ่มต้นจะถูกเรียกให้เริ่มต้นเส้นทางรูปร่างใหม่ จากนั้นเราใช้วิธี Moveto เพื่อย้ายจุดเริ่มต้นไปยังตำแหน่งที่ต้องการ ด้านล่างสองบรรทัดนี้ถูกวาดซึ่งประกอบขึ้นเป็นสองด้านของสามเหลี่ยม
ตัวอย่าง (ดังที่แสดงในภาพทางด้านขวา) เป็นรูปสามเหลี่ยมสองรูปที่เต็มไปด้วยสีทึบและขอบที่วาดหนึ่งอัน ก่อนอื่นให้เรียกใช้วิธีการเริ่มต้นเพื่อสร้างเส้นทางใหม่จากนั้นใช้วิธี Moveto เพื่อย้ายพิกัดเริ่มต้นไปยังตำแหน่งที่ต้องการจากนั้นวาดเส้นตรงสองเส้นเพื่อสร้างทั้งสองด้านของสามเหลี่ยม
คุณจะสังเกตเห็นความแตกต่างระหว่างสามเหลี่ยมที่เต็มไปด้วยการลูบ นี่คือดังที่ได้กล่าวไว้ข้างต้นเพราะรูปร่างจะถูกปิดโดยอัตโนมัติเมื่อเต็มเส้นทาง ถ้าเราจะทำสิ่งนี้เพื่อสามเหลี่ยมที่ลูบเพียงสองบรรทัดเท่านั้นที่จะถูกวาดไม่ใช่สามเหลี่ยมที่สมบูรณ์
คุณสามารถสังเกตเห็นความแตกต่างระหว่างรูปสามเหลี่ยมการวาดแบบเติมและ Strok ดังที่ได้กล่าวไว้ข้างต้นเส้นทางที่ใช้การเติมจะปิดโดยอัตโนมัติ แต่จะไม่อยู่กับโรคหลอดเลือดสมอง หากเส้นทางไม่ปิดจะมีเพียงสองด้านเท่านั้น
ดูตัวอย่าง
// เติมสามเหลี่ยม ctx.beginpath (); ctx.moveto (25,25); ctx.lineto (105,25); ctx.lineto (25,105); ctx.fill (); ctx.beginpath (); ctx.moveto (125,125); ctx.lineto (125,45); ctx.lineto (45,125); ctx.closepath (); ctx.stroke ();
สำหรับการวาดส่วนโค้งหรือวงกลมเราใช้วิธีการโค้ง ข้อมูลจำเพาะยังอธิบายถึงวิธี Arcto ซึ่งได้รับการสนับสนุนโดย Safari แต่ยังไม่ได้นำไปใช้ในเบราว์เซอร์ตุ๊กแกปัจจุบัน
เราใช้วิธี ARC เพื่อวาดส่วนโค้งหรือวงกลม วิธี Arcto ยังรวมอยู่ในคำอธิบายมาตรฐาน ปัจจุบัน Safari ได้รับการสนับสนุน แต่เบราว์เซอร์ที่ใช้ตุ๊กแกยังไม่ได้ใช้งาน
อาร์ค (x, y, รัศมี, สตาร์ทแองเจิล, endangle, anticlockwise)วิธีนี้ใช้เวลาห้าพารามิเตอร์: X และ Y เป็นพิกัดของศูนย์กลางของวงกลม รัศมีคือคำอธิบายตนเอง พารามิเตอร์สตาร์ทแอนด์แอมป์กำหนดจุดเริ่มต้นและจุดสิ้นสุดของส่วนโค้งในเรเดียน มุมเริ่มต้นและการปิดวัดจากแกน x พารามิเตอร์ anticockwise เป็นค่าบูลีนซึ่งเมื่อ TRUE ดึง ARC anticockwise มิฉะนั้นในทิศทางตามเข็มนาฬิกา
วิธีการยอมรับห้าพารามิเตอร์: x, y คือพิกัดกลางรัศมีคือรัศมี, สตาร์ทแหนกและมังสวิรัติเป็นเรเดียนเริ่มต้นและสิ้นสุด (ขึ้นอยู่กับแกน x เป็นข้อมูลอ้างอิง), anticlockwise เป็นจริงซึ่งหมายถึงทวนเข็มนาฬิกา
คำเตือน : ใน Firefox Beta Builds พารามิเตอร์สุดท้ายคือตามเข็มนาฬิกา รีลีสสุดท้ายจะสนับสนุนฟังก์ชั่นตามที่อธิบายไว้ข้างต้น สคริปต์ทั้งหมดที่ใช้วิธีนี้ในแบบฟอร์มปัจจุบันจะต้องได้รับการอัปเดตเมื่อรุ่นสุดท้ายถูกปล่อยออกมาคำเตือน: ในรุ่นเบต้าของ Firefox พารามิเตอร์สุดท้ายคือตามเข็มนาฬิกาและรุ่นสุดท้ายไม่ได้ ดังนั้นหากคุณกำลังอัพเกรดจากเบต้าเป็นการกระจายคุณต้องทำการเปลี่ยนแปลงที่สอดคล้องกัน
หมายเหตุ : มุมในฟังก์ชันอาร์คถูกวัดในเรเดียนไม่ใช่องศา ในการแปลงองศาเป็นเรเดียนคุณสามารถใช้นิพจน์ JavaScript ต่อไปนี้: var radians = (math.pi/180)*องศาหมายเหตุ: มุมที่ใช้ในวิธี ARC อยู่ในหน่วยของเรเดียนมากกว่าองศา การแปลงโดยตรงขององศาและเรเดียนสามารถใช้กับการแสดงออกนี้: var radians = (math.pi/180)*องศา;
ตัวอย่างต่อไปนี้มีความซับซ้อนมากกว่าที่เราเห็นข้างต้นเล็กน้อย ฉันวาดส่วนโค้งที่แตกต่างกัน 12 แบบด้วยมุมที่แตกต่างกันและเติมเต็ม ถ้าฉันจะเขียนตัวอย่างนี้เหมือนกับใบหน้าที่ยิ้มแย้มด้านบนประการแรกนี่จะกลายเป็นรายการข้อความที่ยาวมากและประการที่สองเมื่อวาดอาร์คฉันจะต้องรู้ทุกจุดเริ่มต้น สำหรับอาร์คของ 90, 180 และ 270 องศาเช่นเดียวกับที่ฉันใช้ที่นี่นี่จะไม่เป็นปัญหามากนัก แต่สำหรับคนที่ซับซ้อนกว่านี้จะกลายเป็นวิธีที่ยากเกินไป
ตัวอย่างนี้ซับซ้อนกว่าที่คุณเคยเห็นมาก่อน มันดึงอาร์คที่แตกต่างกัน 12 แบบที่มีมุมที่แตกต่างกันและสถานะการเติม ถ้าฉันวาดส่วนโค้งเหล่านี้ด้วยวิธีการด้านบนของการวาดใบหน้าที่ยิ้มแย้มมันจะเป็นรหัสชิ้นใหญ่และเมื่อวาดส่วนโค้งแต่ละส่วนฉันต้องรู้ตำแหน่งของศูนย์กลางของวงกลม ตัวอย่างเช่นการวาดส่วนโค้งของ 90, 180 และ 270 องศาที่นี่ก็เป็นปัญหาเช่นกัน หากกราฟิกมีความซับซ้อนมากขึ้นยิ่งยากที่จะนำไปใช้
ทั้งสองสำหรับลูปนั้นใช้สำหรับการวนรอบแถวและคอลัมน์ของส่วนโค้ง สำหรับทุก ๆ อาร์คฉันเริ่มต้นเส้นทางใหม่โดยใช้ beginpath ด้านล่างนี้ฉันได้เขียนพารามิเตอร์ทั้งหมดเป็นตัวแปรดังนั้นจึงง่ายกว่าที่จะอ่านว่าเกิดอะไรขึ้น โดยปกตินี่จะเป็นเพียงคำสั่งเดียว พิกัด X และ Y ควรมีความชัดเจนเพียงพอ รัศมีและการเริ่มต้นได้รับการแก้ไข Endangle เริ่มต้นเป็น 180 องศา (คอลัมน์แรก) และเพิ่มขึ้นด้วยขั้นตอน 90 องศาเพื่อสร้างวงกลมที่สมบูรณ์ (คอลัมน์สุดท้าย) คำสั่งสำหรับพารามิเตอร์ตามเข็มนาฬิกาส่งผลให้แถวแรกและแถวที่สามถูกวาดเป็นส่วนโค้งตามเข็มนาฬิกาและแถวที่สองและแถวที่สี่เป็นส่วนโค้งทวนเข็มนาฬิกา ในที่สุดคำสั่ง IF ทำให้ครึ่งหนึ่งของการลูบโค้งและครึ่งล่างเต็มไปด้วยอาร์ค
ที่นี่เราใช้สองสำหรับลูปเพื่อวาดส่วนโค้งที่มีหลายแถวและคอลัมน์ แต่ละอาร์คสร้างเส้นทางใหม่โดยใช้วิธีการเริ่มต้น จากนั้นเพื่อการอ่านและความเข้าใจที่ง่ายฉันเขียนพารามิเตอร์ทั้งหมดลงในรูปแบบตัวแปร เห็นได้ชัดว่า X และ Y เป็นพิกัดกลาง ทั้งรัศมีและการเริ่มต้นได้รับการแก้ไขและ Endangle เริ่มต้นจากครึ่งวงกลม 180 องศาและเพิ่มขึ้นเป็นวงกลมในโหมด 90 องศา Antilockwise ขึ้นอยู่กับจำนวนของคี่และแม้กระทั่งแถว ในที่สุดคำสั่ง IF จะถูกใช้เพื่อตัดสินว่าสองบรรทัดแรกจะแสดงเป็นขอบและสองบรรทัดสุดท้ายจะเต็มไปด้วยเอฟเฟกต์
สำหรับ (i = 0; i <4; i ++) {สำหรับ (j = 0; j <3; j ++) {ctx.beginpath (); var x = 25+j*50; // x พิกัด var y = 25+i*50; // y พิกัด var radius = 20; // อาร์ครัศมี var startangle = 0; // จุดเริ่มต้นบนวงกลม var endangle = math.pi+(math.pi*j)/2; // จุดสิ้นสุดบนวงกลม var anticlockwise = i%2 == 0? เท็จ: จริง; // ตามเข็มนาฬิกาหรือ anticlockwise ctx.arc (x, y, รัศมี, starmangle, endangle, anticlockwise); if (i> 1) {ctx.fill (); } else {ctx.stroke (); -เส้นทางต่อไปที่มีอยู่คือเส้นโค้งbézierมีให้เลือกในรูปลูกบาศก์และสี่เหลี่ยมจัตุรัส โดยทั่วไปจะใช้ในการวาดรูปร่างอินทรีย์ที่ซับซ้อน
เส้นทางต่อไปที่จะแนะนำคือเส้นโค้ง Bezier ซึ่งสามารถอยู่ในรูปกำลังสองและลูกบาศก์และโดยทั่วไปจะใช้ในการวาดรูปทรงที่ซับซ้อนและปกติ
quadraticcurveto (cp1x, cp1y, x, y) // แตกใน firefox 1.5 (ดูการทำงานรอบ ๆ ด้านล่าง) BezierCurveto (CP1X, CP1Y, CP2X, CP2Y, X, Y)ความแตกต่างระหว่างสิ่งเหล่านี้สามารถอธิบายได้ดีที่สุดโดยใช้ภาพทางด้านขวา เส้นโค้งbézierกำลังสองมีจุดเริ่มต้นและจุดสิ้นสุด (จุดสีน้ำเงิน) และ จุดควบคุม เพียงจุดเดียว (จุดสีแดง) ในขณะที่เส้นโค้งbézierลูกบาศก์ใช้จุดควบคุมสองจุด
ดูรูปทางด้านขวาสำหรับความแตกต่างระหว่างรหัสสองบรรทัดด้านบน พวกเขาทั้งหมดมีจุดเริ่มต้นและจุดสิ้นสุด (จุดสีน้ำเงินในรูป) แต่เส้นโค้ง bezier กำลังสองมีจุดควบคุมเพียงหนึ่งจุด (สีแดง)) และเส้นโค้ง bezier ลูกบาศก์มีสองจุด
พารามิเตอร์ X และ Y ในทั้งสองวิธีนี้เป็นพิกัดของจุดสิ้นสุด CP1X และ CP1Y เป็นพิกัดของจุดควบคุมแรกและ CP2X และ CP2Y เป็นพิกัดของจุดควบคุมที่สอง
พารามิเตอร์ X และ Y เป็นพิกัดจุดสิ้นสุด CP1X และ CP1Y เป็นพิกัดของจุดควบคุมแรกและ CP2X และ CP2Y เป็นครั้งที่สอง
การใช้เส้นโค้งสมการกำลังกำลังสองและลูกบาศก์อาจเป็นเรื่องที่ค่อนข้างท้าทายเพราะไม่เหมือนกับซอฟต์แวร์การวาดภาพเวกเตอร์เช่น Adobe Illustrator เราไม่ได้รับผลตอบรับโดยตรงเกี่ยวกับสิ่งที่เรากำลังทำอยู่ สิ่งนี้ทำให้การวาดรูปร่างที่ซับซ้อนยาก ในตัวอย่างต่อไปนี้เราจะวาดรูปทรงออร์แกนิกที่เรียบง่าย แต่ถ้าคุณมีเวลาและที่สำคัญที่สุดคือความอดทนสามารถสร้างรูปร่างที่ซับซ้อนได้มากขึ้น
การใช้เส้นโค้ง bezier กำลังสองและลูกบาศก์นั้นค่อนข้างท้าทายเพราะไม่มีข้อเสนอแนะภาพทันทีเช่นในซอฟต์แวร์การวาดเวกเตอร์ Adobe Illustrator เพราะมันเป็นปัญหามากขึ้นในการวาดกราฟิกที่ซับซ้อน แต่ถ้าคุณมีเวลาและที่สำคัญที่สุดคุณสามารถวาดกราฟิกที่ซับซ้อนได้ มาวาดรูปที่เรียบง่ายและปกติด้านล่าง
ตัวอย่างเหล่านี้ไม่มีอะไรยากมาก ในทั้งสองกรณีเราเห็นการสืบทอดของเส้นโค้งที่ถูกดึงซึ่งในที่สุดก็ส่งผลให้รูปร่างสมบูรณ์
ตัวอย่างเหล่านี้ค่อนข้างง่าย สิ่งที่เราวาดคือกราฟิกที่สมบูรณ์
// เส้นโค้ง quadratric exmerm.beginpath (); ctx.moveto (75,25); ctx.quadraticcurveto (25,25,25,62.5); ctx.quadraticcurveto (25,100,50,100); Ctx.quadraticcurveto (50 120,30,125); CTX.QuadRaticCurveto (60,120,65,100); CTX.QuadRaticCurveto (125,100,125,62.5); CTX.quadraticCurveto (125,25,75,25);
มันเป็นไปได้ที่จะแปลงเส้นโค้งbézierกำลังสองเป็นเส้นโค้งลูกบาศก์bézierโดยการคำนวณจุดควบคุมBézierทั้งลูกบาศก์bézierจากจุดควบคุมbézierแบบสองส่วนเดียวแม้ว่าสิ่งที่ตรงกันข้ามจะไม่เป็นความจริง การแปลงที่แน่นอนของเส้นโค้งลูกบาศก์bézierเป็นเส้นโค้งbézierกำลังสองเป็นไปได้ก็ต่อเมื่อคำศัพท์ลูกบาศก์เป็นศูนย์โดยทั่วไปจะใช้วิธีการย่อยโดยทั่วไปจะใช้เพื่อประมาณลูกบาศก์bézierโดยใช้เส้นโค้งbézier
ผ่านการคำนวณจุดควบคุมสองจุดของเส้นโค้งลูกบาศก์ที่สอดคล้องกันสามารถได้มาจากจุดควบคุมเดียวของเส้นโค้งกำลังสองดังนั้นจึงเป็นไปได้ที่จะเปลี่ยนกำลังสองเป็นลูกบาศก์ แต่อย่างอื่น เป็นไปได้ที่จะแปลงเป็นเส้นโค้ง bezier กำลังสองเฉพาะในกรณีที่ลูกบาศก์เทอมในสมการลูกบาศก์เป็นศูนย์ โดยทั่วไปสามารถใช้เส้นโค้งกำลังสองหลายส่วนเพื่อประมาณการจำลองของเส้นโค้ง bezier ลูกบาศก์ผ่านอัลกอริทึมการแบ่งแยก
// bezier curves expliz.beginpath (); ctx.moveto (75,40); ctx.beziercurveto (75,37,70,25,50,25); ctx.beziercurveto (20,25,20,62.5,20,50,5); , 102,75,120); CTX.BezierCurveto (110,102,130,80,130,62.5); CTX.BEZIERCURVETO (130,62.5,130,25,100,25); CTX.BezierCurveto (85,25,75,37,75,40); CTX.Fill ();
มีข้อผิดพลาดในการใช้งาน Firefox 1.5 ของ quadatriccurveto () มันไม่ได้วาดเส้นโค้งกำลังสองเนื่องจากมันเป็นเพียงการเรียกใช้ฟังก์ชันลูกบาศก์เส้นโค้งเดียวกัน beziercurveto () และทำซ้ำจุดควบคุมกำลังสอง (x, y) สองครั้ง ด้วยเหตุนี้ quadraticcurveto () จะให้ผลลัพธ์ที่ไม่ถูกต้อง หากคุณต้องการการใช้ quadraticcurveto () คุณต้องแปลงเส้นโค้งbézierกำลังสองของคุณเป็นเส้นโค้งbézierลูกบาศก์ตัวเองเพื่อให้คุณสามารถใช้วิธี beziercurveto () ที่ใช้งานได้
ใน Firefox 1.5 การดำเนินการของ quadatriccurveto () คือ buggy มันไม่ได้วาดเส้นโค้งกำลังสองโดยตรง แต่เรียก beziercurveto () ซึ่งจุดควบคุมทั้งสองเป็นจุดควบคุมเดียวของเส้นโค้งกำลังสอง ดังนั้นจึงดึงเส้นโค้งที่ไม่ถูกต้อง หากคุณต้องใช้ quadraticcurveto () คุณต้องแปลงเส้นโค้งกำลังสองให้เป็นลูกบาศก์ด้วยตัวเองเพื่อให้คุณสามารถใช้วิธี beziercurveto ()
var currentx, currenty; // ตั้งค่าเป็นล่าสุด x, y ที่ส่งไปยัง lineto/moveto/beziercurveto หรือ quadraticcurvetofixed () quadraticcurvetofixed (cpx, cpy, x, y) {/* สำหรับสมการด้านล่าง lineto () หรือ beziercurveto ()) QP1 เป็นจุดควบคุมเส้นโค้งสี่เท่า (นี่คือ CPX, CPY ที่คุณจะส่งไปยัง QuadRaticCurveto ()) QP2 เป็นจุดสิ้นสุดของเส้นโค้งกำลังสอง (นี่คืออาร์กิวเมนต์ x, y ที่คุณจะส่งไปยัง quadraticcurveto ()) เราจะแปลงจุดเหล่านี้เพื่อคำนวณจุดควบคุมลูกบาศก์ที่จำเป็นสองจุด (จุดเริ่มต้น/จุดสิ้นสุดจะเหมือนกันสำหรับทั้งเส้นโค้งกำลังสองและลูกบาศก์สมการสำหรับจุดควบคุมสองลูกบาศก์สองจุดคือ: cp0 = qp0 และ cp3 = qp2 cp1 = qp0 + 2/3 *(qp1-qp0) และคำศัพท์สำหรับแต่ละจุด A) แทนที่ตัวแปร qp0x และ qp0y ด้วย currentx และ currenty (ซึ่ง * คุณ * ต้องเก็บสำหรับแต่ละ moveto/lineto/beziercurveto) b) แทนที่ตัวแปร qp1x และ qp1y ด้วย cpx และ cpy (ซึ่งเราจะผ่านไป ซึ่งทำให้เรามี: */ var cp1x = currentx + 2.0/ 3.0 *(cpx - currentx); var cp1y = currenty + 2.0/3.0*(cpy - currenty); var cp2x = cp1x + (x - currentx) /3.0; var cp2y = cp1y + (y - currenty) /3.0; // และตอนนี้เรียกเส้นโค้ง cubic bezier เพื่อใช้งาน beziercurveto (cp1x, cp1y, cp2x, cp2y, x, y); currentx = x; currenty = y;}นอกจากสามวิธีที่เราเห็นด้านบนซึ่งวาดรูปสี่เหลี่ยมผืนผ้าโดยตรงไปยังผืนผ้าใบเรายังมีวิธีการแก้ไขซึ่งเพิ่มเส้นทางสี่เหลี่ยมลงในรายการเส้นทาง
นอกเหนือจากสามวิธีที่กล่าวถึงข้างต้นซึ่งสามารถวาดรูปสี่เหลี่ยมผืนผ้าโดยตรงเรายังมีวิธีการแก้ไขที่ใช้ในการวาดเส้นทางสี่เหลี่ยมผืนผ้า
rect (x, y, ความกว้าง, ความสูง)วิธีนี้ใช้เวลาสี่อาร์กิวเมนต์ พารามิเตอร์ X และ Y กำหนดพิกัดของมุมซ้ายบนของเส้นทางสี่เหลี่ยมใหม่ ความกว้างและความสูงกำหนดความกว้างและความสูงของสี่เหลี่ยม
มันยอมรับพารามิเตอร์สี่ตัว X และ Y เป็นพิกัดซ้ายบนและความกว้างและความสูงคือความกว้างและความสูง
เมื่อวิธีการนี้ดำเนินการวิธีการ Moveto จะถูกเรียกโดยอัตโนมัติด้วยพารามิเตอร์ (0,0) (เช่นจะรีเซ็ตจุดเริ่มต้นไปยังตำแหน่งเริ่มต้น)
เมื่อมีการเรียกว่าวิธีการ Moveto จะถูกเรียกโดยอัตโนมัติดังนั้นพิกัดเริ่มต้นจะถูกกู้คืนไปยังแหล่งกำเนิด
ในตัวอย่างทั้งหมดในหน้านี้ฉันใช้ฟังก์ชันเส้นทางหนึ่งประเภทต่อรูปร่างเท่านั้น อย่างไรก็ตามไม่มีการ จำกัด จำนวนหรือประเภทของเส้นทางที่คุณสามารถใช้เพื่อสร้างรูปร่าง ดังนั้นในตัวอย่างสุดท้ายนี้ฉันพยายามรวมฟังก์ชั่นเส้นทางทั้งหมดเพื่อสร้างชุดตัวละครเกมที่มีชื่อเสียงมาก
ตัวอย่างที่ใช้ข้างต้นใช้เส้นทางเดียวเท่านั้นแน่นอนว่าผืนผ้าใบจะไม่ จำกัด จำนวนประเภทเส้นทางที่ใช้ ดังนั้นมาดูเส้นทางฮอดจ์พ็อดจ์กันเถอะ
ฉันจะไม่เรียกใช้สคริปต์ที่สมบูรณ์นี้ แต่สิ่งที่สำคัญที่สุดที่ควรทราบคือฟังก์ชั่นที่โค้งมนและการใช้คุณสมบัติ Fillstyle มันมีประโยชน์มากและประหยัดเวลาเพื่อกำหนดฟังก์ชั่นของคุณเองเพื่อวาดรูปร่างที่ซับซ้อนมากขึ้น ในสคริปต์นี้มันจะพาฉันไปสองเท่าของรหัสมากเท่าที่ฉันมีตอนนี้
เราจะดูคุณสมบัติ Fillstyle ในเชิงลึกมากขึ้นในภายหลังในบทช่วยสอนนี้ ที่นี่ฉันใช้มันเพื่อเปลี่ยนสีเติมจากสีดำเริ่มต้นเป็นสีขาวและกลับมาอีกครั้ง
ในตัวอย่างทั้งหมดสิ่งที่น่าสังเกตมากที่สุดคือการใช้ฟังก์ชัน RoundedRect และการตั้งค่าของคุณสมบัติ Fillstyle ฟังก์ชั่นที่กำหนดเองมีประโยชน์มากสำหรับการห่อหุ้มภาพวาดของกราฟิกที่ซับซ้อน การใช้ฟังก์ชั่นที่กำหนดเองในตัวอย่างนี้บันทึกประมาณครึ่งหนึ่งของรหัส
ในตัวอย่างต่อไปนี้เราจะสำรวจการใช้แอตทริบิวต์ Fillstyle เชิงลึก นี่คือการใช้เพื่อเปลี่ยนสีเติมจากสีดำเริ่มต้นเป็นสีขาวแล้วกลับเป็นสีดำ
ดูตัวอย่าง
ฟังก์ชั่นการวาด () {var ctx = document.getElementById ('canvas'). getContext ('2d'); RoundedRect (CTX, 12,12,150,150,15); Roundedrect (CTX, 19,19,150,150,9); RoundedRect (CTX, 53,53,49,33,10); RoundedRect (CTX, 53,119,49,16,6); RoundedRect (CTX, 135,53,49,33,10); RoundedRect (CTX, 135,119,25,49,10); ctx.beginpath (); ctx.arc (37,37,13, math.pi/7, -math.pi/7, จริง); ctx.lineto (31,37); ctx.fill (); สำหรับ (i = 0; i <8; i ++) {ctx.fillrect (51+i*16,35,4,4); } สำหรับ (i = 0; i <6; i ++) {ctx.fillrect (115,51+i*16,4,4); } สำหรับ (i = 0; i <8; i ++) {ctx.fillrect (51+i*16,99,4,4); } ctx.beginpath (); ctx.moveto (83,116); ctx.lineto (83,102); CTX.BEZIERCURVETO (83,94,89,88,97,88); CTX.BEZIERCURVETO (105,88,111,94,111,102); ctx.lineteto (111,116); ctx.lineteto (106.333,111.333); ctx.lineteto (101.666,116); ctx.lineteto (97,111.333); ctx.lineteto (92.333,116); ctx.lineteto (87.666,111.333); ctx.lineteto (83,116); ctx.fill (); ctx.fillstyle = สีขาว; ctx.beginpath (); ctx.moveto (91,96); CTX.BEZIERCURVETO (88,96,87,99,87,101); CTX.BEZIERCURVETO (87,103,88,106,91,106); CTX.BEZIERCURVETO (94,106,95,103,95,101); CTX.BEZIERCURVETO (95,99,94,96,91,96); ctx.moveto (103,96); CTX.BEZIERCURVETO (100,96,99,99,99,101); CTX.BEZIERCURVETO (99,103,100,106,103,106); CTX.BEZIERCURVETO (106,106,107,103,107,101); CTX.BEZIERCURVETO (107,99,106,96,103,96); ctx.fill (); ctx.fillstyle = ดำ; ctx.beginpath (); ctx.arc (101,102,2,0, math.pi*2, true); ctx.fill (); ctx.beginpath (); ctx.arc (89,102,2,0, math.pi*2, จริง); ctx.fill (); ctx.fill (); ctx.arc (89,102,2,0, math.pi*2, จริง); ctx.fill (); ctx.fill (); } ฟังก์ชั่น RoundedDerEct (CTX, X, Y, ความกว้าง, ความสูง, รัศมี) {ctx.beginpath (); ctx.moveto (x, y+รัศมี); ctx.lineto (x, y+ความสูง-radius); ctx.quadraticcurveto (x, y+ความสูง, x+รัศมี, y+ความสูง); ctx.lineto (x+width-radius, y+ความสูง); ctx.quadraticcurveto (x+ความกว้าง, y+ความสูง, x+ความกว้าง, y+ความสูง-radius); ctx.lineto (x+ความกว้าง, y+รัศมี); ctx.quadraticcurveto (x+width, y, x+width-radius, y); ctx.lineto (x+รัศมี, y); ctx.quadraticcurveto (x, y, x, y+รัศมี); ctx.stroke ();}