Canvas ใน HTML5 ไม่ได้ให้วิธีการวาดรูปไข่โดยตรง ต่อไปนี้เป็นบทสรุปของวิธีการวาดหลายวิธี วิธีการต่าง ๆ มีข้อดีและข้อเสียของตนเองและได้รับการคัดเลือกตามสถานการณ์ พารามิเตอร์ของแต่ละวิธีเหมือนกัน:
บริบทคือวัตถุสภาพแวดล้อมการวาดภาพ 2D ของ Canvas
X คือพิกัดแนวนอนของศูนย์กลางของวงรี
y คือพิกัดแนวตั้งของศูนย์กลางของวงรี
A คือความยาวของแกนครึ่งแนวนอนของวงรี
B คือความยาวของแกนครึ่งแนวตั้งของวงรี
วิธีการสมการพารามิเตอร์วิธีนี้ใช้สมการพารามิเตอร์ของวงรีเพื่อวาดวงรี
-
// พารามิเตอร์ x และ y ของฟังก์ชั่นเป็นศูนย์กลางของวงรี A และ B เป็นแกนครึ่งแนวนอนของวงรีตามลำดับ
// ความยาวของแกนครึ่งแนวตั้งไม่สามารถเป็น 0 ในเวลาเดียวกัน
// ข้อเสียของวิธีนี้คือเมื่อ linwidth กว้างขึ้นและวงรีกำลังประจบ
// จุดสิ้นสุดแกนหลักของวงรีด้านในนั้นคมชัดไม่ราบรื่นและมีประสิทธิภาพต่ำ
ฟังก์ชั่น paramellipse (บริบท, x, y, a, b)
-
// สูงสุดคือค่าแกนหลักที่ใหญ่กว่า A และ B
// ฉันเพิ่ม 1/สูงสุดสำหรับแต่ละรอบแสดงการเพิ่มระดับ
// สิ่งนี้จะทำให้เส้นทาง (อาร์ค) วาดในแต่ละลูปใกล้กับ 1 พิกเซล
var step = (a> b)? 1 / a: 1 / b;
Context.BeginPath ();
Context.moveto (x + a, y); // วาดจากจุดสิ้นสุดด้านซ้ายของวงรี
สำหรับ (var i = 0; i <2 * math.pi; i += ขั้นตอน)
-
// สมการพารามิเตอร์คือ x = a * cos (i), y = b * sin (i)
// พารามิเตอร์คือฉันระบุระดับ (เรเดียน)
context.lineto (x + a * math.cos (i), y + b * math.sin (i));
-
บริบท closepath ();
Context.stroke ();
-
วิธีการบีบอัดแบบสม่ำเสมอวิธีนี้ใช้หลักการของการบีบอัดแบบสม่ำเสมอในคณิตศาสตร์เพื่อบีบอัดวงกลมอย่างสม่ำเสมอเป็นวงรีซึ่งในทางทฤษฎีสามารถรับวงรีมาตรฐานได้ รหัสต่อไปนี้จะมีปัญหาเกี่ยวกับความกว้างของเส้นที่ไม่สอดคล้องกัน ทางออกคือการดูความคิดเห็นของ Simonleung บนชั้น 5
-
// วิธีการวาดวงกลมโดยใช้วิธีการโค้งและรวมสเกลสำหรับ
// การปรับขนาดในทิศทางแกนแนวนอนหรือแนวตั้ง (แม้กระทั่งการบีบอัด)
// ขอบของวงรีที่วาดในวิธีนี้จะหนาขึ้นเนื่องจากขอบอยู่ใกล้กับปลายแกนหลักและความกว้างของเส้นของปลายแกนหลักเป็นเรื่องปกติ
// ยิ่งขอบใกล้กับแกนรอง, ประจบและทำให้เกิดวงรีและแม้แต่การหยุดชะงักก็เกิดขึ้น นี่คือผลลัพธ์ของมาตราส่วน
// ข้อเสียนี้บางครั้งก็เป็นข้อได้เปรียบเช่นเมื่อแสดงเอฟเฟกต์สามมิติของวงแหวน (รัศมีดาวเคราะห์)
// สำหรับกรณีที่พารามิเตอร์ A หรือ B เป็น 0 วิธีนี้ไม่สามารถใช้ได้
ฟังก์ชั่น evencompellipse (บริบท, x, y, a, b)
-
บริบท save ();
// เลือกหนึ่งใน A และ B ที่ใหญ่กว่าเป็นพารามิเตอร์ RADIUS ของวิธี ARC
var r = (a> b)? A: B;
var ratiox = a / r; // อัตราส่วนการปรับขนาดแกนนอน
var ratioy = b / r; // อัตราส่วนการปรับขนาดแกนมิติ
Context.scale (Ratiox, Ratioy); // การปรับสเกล (แม้แต่การบีบอัด)
Context.BeginPath ();
// วาดทวนเข็มนาฬิกาจากปลายซ้ายของวงรี
context.moveto ((x + a) / ratiox, y / ratioy);
context.arc (x / ratiox, y / ratioy, r, 0, 2 * math.pi);
บริบท closepath ();
Context.stroke ();
บริบท restore ();
-
Cubic Bezier Curve Method Oneการวาดเส้นโค้ง bezier ลูกบาศก์ของวงรีเป็นการประมาณเมื่อวาดจริงและในทางทฤษฎีมันก็เป็นการประมาณเช่นกัน อย่างไรก็ตามเนื่องจากมีประสิทธิภาพสูงจึงมักใช้ในการวาดรูปไข่ในกราฟิกเวกเตอร์คอมพิวเตอร์ แต่ฉันไม่ชัดเจนเกี่ยวกับทฤษฎีเฉพาะ การประมาณอยู่ในการเลือกตำแหน่งของจุดควบคุมทั้งสองจุด ตำแหน่งจุดควบคุมของวิธีนี้ได้มาจากตัวฉันเองและความแม่นยำก็โอเค
-
// วิธีนี้จะผลิตเมื่อ linewidth กว้างขึ้นและวงรีก็ประจบ
// ปลายแกนยาวนั้นคมและไม่ราบรื่น
ฟังก์ชั่น bezierellipse1 (บริบท, x, y, a, b)
-
// คีย์คือการตั้งค่าจุดควบคุมสองจุดใน BezierCurveto
//0.5 และ 0.6 เป็นค่าสัมประสิทธิ์สำคัญสองค่า (ได้รับสำหรับการทดลองในฟังก์ชั่นนี้)
var ox = 0.5 * a,
OY = 0.6 * B;
บริบท save ();
บริบทการแปล (x, y);
Context.BeginPath ();
// วาดทวนเข็มนาฬิกาจากปลายล่างของแกนระยะยาววงรีวงรี
Context.moveto (0, b);
Context.beziercurveto (ox, b, a, oy, a, 0);
Context.beziercurveto (a, -oy, ox, -b, 0, -b);
context.beziercurveto (-ox, -b, -a, -oy, -a, 0);
Context.beziercurveto (-a, Oy, -ox, B, 0, B);
บริบท closepath ();
Context.stroke ();
บริบท restore ();
-
Cubic Bezier Curve วิธีสองวิธีนี้เปลี่ยนจากการตอบกลับเป็นโพสต์ใน Stackoverflow ด้วยความแม่นยำสูงและยังเป็นวิธีที่ใช้กันทั่วไปในการวาดรูปไข่
-
// วิธีนี้จะผลิตเมื่อ linewidth กว้างขึ้นและวงรีกำลังประจบ
// ปลายแกนยาวนั้นคมและไม่ราบรื่น
// วิธีนี้มีความแม่นยำมากกว่าวิธี Bessel ก่อนหน้า แต่มีวิธีที่มีประสิทธิภาพน้อยกว่าเล็กน้อยเล็กน้อย
ฟังก์ชั่น bezierellipse2 (ctx, x, y, a, b)
-
var k = .5522848
ox = a * k, // จุดควบคุมแนวนอนชดเชย
oy = b * k; // จุดควบคุมแนวตั้งชดเชย
ctx.beginpath ();
// วาดเส้นโค้ง bezier สี่ลูกบาศก์ตามเข็มนาฬิกาจากจุดสิ้นสุดด้านซ้ายของวงรี
ctx.moveto (x - a, y);
ctx.beziercurveto (x - a, y - oy, x - ox, y - b, x, y - b);
ctx.beziercurveto (x + ox, y - b, x + a, y - oy, x + a, y);
ctx.beziercurveto (x + a, y + oy, x + ox, y + b, x, y + b);
ctx.beziercurveto (x - ox, y + b, x - a, y + oy, x - a, y);
ctx.closepath ();
ctx.stroke ();
-
วิธีการตะแกรงวิธีนี้สามารถวาดรูปไข่ได้ตามลักษณะของผืนผ้าใบที่สามารถใช้งานพิกเซลและใช้อัลกอริทึมพื้นฐานในกราฟิก ตัวอย่างเช่นอัลกอริทึมรูปวงรีของจุดกึ่งกลางเป็นต้น ฯลฯ
ตัวอย่างหนึ่งคือโพสต์บล็อกโดย Doudou เพื่อนในสวนคลาส HTML5 Canvas Improvement Class (I) - Raster Graphics (1) จุดกึ่งกลางและอัลกอริทึมวงกลม วิธีนี้ค่อนข้างดั้งเดิมยืดหยุ่นมีประสิทธิภาพและแม่นยำ แต่มีความซับซ้อนมากขึ้นในการตระหนักถึงฟังก์ชั่นที่มีประโยชน์สำหรับการวาดรูปวงรี ตัวอย่างเช่นเมื่อความกว้างของเส้นเปลี่ยนแปลงอัลกอริทึมจะซับซ้อนมากขึ้น แม้ว่ามันจะเป็นอัลกอริทึมสำหรับการวาดวงกลม แต่อัลกอริทึมสำหรับการวาดรูปไข่จะคล้ายกับมันดังนั้นคุณสามารถอ้างถึงได้ด้านล่าง
การสาธิต
ต่อไปนี้เป็นการสาธิตหลายฟังก์ชั่นการวาดรูปวงรีนอกเหนือจากวิธีแรสเตอร์ รหัสสาธิตมีดังนี้:
<div id = "canvaswrap" style = "พื้นหลัง: #ffff; width: 600px; ความสูง: 600px; border: 1px solid black;"> </div>
<script type = "text/javascript"> // <! [cdata [cdata [
var canvas,
บริบท;
var div = document.getElementById ("CanvasWrap");
div.innerhtml = "";
canvas = document.createElement ("Canvas");
canvas.style.width = "600px"
canvas.style.height = "600px"
Canvas.width = 600;
Canvas.Height = 600;
บริบท = canvas.getContext ("2d");
Div.AppendChild (ผ้าใบ);
ฟังก์ชั่น ExecDraw ()
-
// แก้ปัญหาความกว้างของเส้นน้อยกว่าหรือเท่ากับ 1 ในโครเมี่ยม
Context.lineWidth = 1.1;
Context.strokestyle = "Black"
Paramellipse (บริบท, 130, 80, 50, 50); //วงกลม
Paramellipse (บริบท, 130, 80, 100, 20); // ellipes
evencompellipse (บริบท, 130, 200, 50, 50); //วงกลม
evencompellipse (บริบท, 130, 200, 100, 20); // ellipe
Bezierellipse1 (บริบท, 470, 80, 50, 50); //วงกลม
Bezierellipse1 (บริบท, 470, 80, 100, 20); // Ellipe
BezierEllipse2 (บริบท, 470, 200, 50, 50); //วงกลม
BezierellipSe2 (บริบท, 470, 200, 100, 20); // Ellipe
// การตรวจจับความคล้ายคลึงกัน (ระดับการทับซ้อน)
Paramellipse (บริบท, 300, 450, 250, 50);
Context.strokestyle = "Yellow";
Bezierellipse1 (บริบท, 300, 450, 250, 50);
Context.strokestyle = "Blue";
BezierEllipse2 (บริบท, 300, 450, 250, 50);
-
ฟังก์ชั่น clearcavnas ()
-
context.clearRect (0, 0, 600, 600);
-
//]> </script>
<p>
<ปุ่ม onclick = "ExecDraw ();" type = "ปุ่ม"> เรียกใช้งาน </button>
<ปุ่ม onclick = "clearcanvas ();" type = "ปุ่ม"> ทำความสะอาด </button>
</p>
โปรดทราบว่าในการเรียกใช้รหัสสำเร็จจะต้องใช้เบราว์เซอร์ที่รองรับผ้าใบที่เปิดใช้งาน HTML5
นี่เป็นครั้งแรกที่ฉันเขียนบล็อกและมันก็ไม่ใช่เรื่องง่ายที่จะทำทุกวัน! เทมเพลตผิวหนังเข้มในบล็อก Park ไม่แสดงรหัสที่แทรกได้ดี ฉันได้รับความเจ็บปวดอย่างมากเพื่อรับรูปแบบรหัส!