จะวาดรูปหลายเหลี่ยมบนผ้าใบ HTML5 ได้อย่างไร?


96

ฉันต้องการรู้วิธีวาดรูปหลายเหลี่ยมบนผืนผ้าใบ โดยไม่ต้องใช้ jQuery หรืออะไรแบบนั้น


10
โปรดจำไว้ว่าสิ่งที่ทำได้โดยไม่ต้องใช้ไลบรารีของบุคคลที่สามควรทำเช่นนั้น
Rodrigo

คำตอบ:


167

สร้างเส้นทางด้วยmoveToและlineTo( การสาธิตสด ):

var ctx = canvas.getContext('2d');
ctx.fillStyle = '#f00';
ctx.beginPath();
ctx.moveTo(0, 0);
ctx.lineTo(100,50);
ctx.lineTo(50, 100);
ctx.lineTo(0, 90);
ctx.closePath();
ctx.fill();

100
@Gio Borje: AFAIK, jsFiddle ไม่สนใจผ้าใบนั่นคือเบราว์เซอร์ของคุณ jsFiddle เพียงแค่ดึง HTML / CSS / JS ของคุณกลับมาให้คุณ
สั้นเกินไป

2
ทางออกที่ยอดเยี่ยม รหัสเรียบร้อยมาก ขอบคุณนะ @phihag. สิ่งที่ฉันเข้าใจ!
bytise

1
คุณสามารถแทนที่ c2 ด้วย ctx ได้หรือไม่ ฉันคิดว่าเป็นการใช้งานทั่วไปสำหรับบริบทผ้าใบ คำตอบที่ดีโดยวิธี
gididaf

@ user1893354 ขอบคุณมากสำหรับคำบอกกล่าว อันที่จริงดูเหมือนว่าจะมีปัญหากับ jsfiddle ที่นั่น - ข้อความแสดงข้อผิดพลาดไม่เกี่ยวข้องกับผืนผ้าใบโดยสิ้นเชิง แทนที่ด้วยไซต์สาธิตสดที่เรียบง่ายมาก
phihag

36

จากhttp://www.scienceprimer.com/drawing-regular-polygons-javascript-canvas :

รหัสต่อไปนี้จะวาดรูปหกเหลี่ยม เปลี่ยนจำนวนด้านเพื่อสร้างรูปหลายเหลี่ยมปกติที่แตกต่างกัน

var ctx = document.getElementById('hexagon').getContext('2d');

// hexagon
var numberOfSides = 6,
    size = 20,
    Xcenter = 25,
    Ycenter = 25;

ctx.beginPath();
ctx.moveTo (Xcenter +  size * Math.cos(0), Ycenter +  size *  Math.sin(0));          

for (var i = 1; i <= numberOfSides;i += 1) {
  ctx.lineTo (Xcenter + size * Math.cos(i * 2 * Math.PI / numberOfSides), Ycenter + size * Math.sin(i * 2 * Math.PI / numberOfSides));
}

ctx.strokeStyle = "#000000";
ctx.lineWidth = 1;
ctx.stroke();
#hexagon { border: thin dashed red; }
<canvas id="hexagon"></canvas>


3
นี่เป็นสิ่งที่ยอดเยี่ยมหรูหรามากถ้าคุณเพิ่ม: cxt.save(); cxt.fillStyle = "#FF000"; cxt.fill(); cxt.restore(); คุณสามารถเติมเต็มรูปร่างได้
samuelkobe

มันยอดเยี่ยมมาก - ฉันนั่งเล่นกับมัน แต่คิดไม่ออกว่าฉันจะเอารูปหลายเหลี่ยมที่เลือกมาหมุนได้อย่างไร - มีความคิดอย่างไรบ้าง?
eskimomatt

1
มีสองสามวิธีที่จะได้รับสิ่งที่คุณต้องการ ทางเลือกหนึ่งคือใช้วิธี cxt.rotate () ในตัว [พร้อมกับ cxt.save () และ cxt.restore ()] เพื่อหมุนส่วนต่างๆของผืนผ้าใบ อีกวิธีหนึ่งคือการเพิ่มค่าที่สอดคล้องกันให้กับฟังก์ชัน cos และ sin ก็สามารถใช้ได้ ดูการสาธิตjsfiddle นี้
Andrew Staroscik

ขอบคุณสำหรับสิ่งนั้น - ฉันเจอวิธีแก้ปัญหาเดียวกันหลังจากอ่านตรรกะในลิงค์ไพรเมอร์วิทยาศาสตร์ที่คุณให้มา var angle = i * 2 * Math.PI / shape.currentSides + rotationเพิ่มค่า cos และค่า sin ได้ผลสำหรับฉัน ... ขอบคุณอีกครั้ง
eskimomatt

ถ้า (ในกรณีของฉัน) คุณแค่ต้องการให้จุดเริ่มต้นอยู่ตรงกลางด้านบนของรูปหลายเหลี่ยมแทนที่จะอยู่ตรงกลางด้านขวาให้พลิกsinและcosเรียกและเปลี่ยนYcenter +เป็นYcenter -ทั้งสองตำแหน่ง (ปล่อยให้เป็นผลรวมแทนที่จะเป็นความแตกต่างของค่า ผลลัพธ์จะเริ่มต้นด้วยจุดที่ด้านล่างของรูปร่างผลลัพธ์) ฉันไม่ใช่คนฉลาดในเรื่องการเรียกใช้ดังนั้นควรใช้เกลือสักเม็ด แต่สิ่งนี้ก็บรรลุสิ่งที่ฉันต้องการอย่างน้อยที่สุด
Joseph Marikle

34
//poly [x,y, x,y, x,y.....];
var poly=[ 5,5, 100,50, 50,100, 10,90 ];
var canvas=document.getElementById("canvas")
var ctx = canvas.getContext('2d');
ctx.fillStyle = '#f00';

ctx.beginPath();
ctx.moveTo(poly[0], poly[1]);
for( item=2 ; item < poly.length-1 ; item+=2 ){ctx.lineTo( poly[item] , poly[item+1] )}

ctx.closePath();
ctx.fill();

นี่คือเหตุผลที่ฉันหวังว่าฉันจะเข้าใจforวิธีการวานิลลา JavaScript โดยพื้นฐาน โค้ดบรรทัดเดียวทำให้สิ่งต่างๆง่ายขึ้นมาก โดยทั่วไปฉันใช้ jQuery .each()แต่แอปพลิเคชันมีความหลากหลายน้อยกว่ามาก
Alexander Dixon

8
@AlexanderDixon จาวาสคริปต์ด้านบนไม่ใช่ตัวอย่างที่ดีจริงๆ ตัวแปรทั้งหมดต้องการvarในโค้ดด้านบนitemเป็นการสร้างมลพิษให้กับเนมสเปซทั่วโลก ทุกอย่างอยู่ในบรรทัดเดียวซึ่งช่วยลดความสามารถในการอ่าน หากคุณไม่สนใจเกี่ยวกับความสามารถในการอ่านข้อมูลคุณอาจถอดวงเล็บปีกกาออกด้วย
AnnanFay

@canvastag งานดีแบบไดนามิก คำตอบนี้ดีกว่าจากคำตอบที่ยอมรับสำหรับฉัน ฉันไม่เข้าใจ "Query .each ()" ... นี่คือฟังก์ชันเวทย์มนตร์ที่ใช้ความจำ สำหรับเนมสเปซระดับโลกด้วย) ตลกดีนี่เป็นเพียงตัวอย่างที่ทำให้เหมือนคลาสถ้าคุณต้องการ
Nikola Lukic

9
//create and fill polygon
CanvasRenderingContext2D.prototype.fillPolygon = function (pointsArray, fillColor,     strokeColor) {
    if (pointsArray.length <= 0) return;
    this.moveTo(pointsArray[0][0], pointsArray[0][1]);
    for (var i = 0; i < pointsArray.length; i++) {
        this.lineTo(pointsArray[i][0], pointsArray[i][1]);
    }
    if (strokeColor != null && strokeColor != undefined)
        this.strokeStyle = strokeColor;

    if (fillColor != null && fillColor != undefined) {
        this.fillStyle = fillColor;
        this.fill();
    }
}
//And you can use this method as 
var polygonPoints = [[10,100],[20,75],[50,100],[100,100],[10,100]];
context.fillPolygon(polygonPoints, '#F00','#000');

น่าสนใจ ... จริง ๆ แล้วการย้ายไปยังบรรทัดและไปยังจุดแรก ... แต่ตอนนี้ที่ฉันคิดเกี่ยวกับมัน ... ใครจะสน?
James Newton

3

นี่คือฟังก์ชั่นที่รองรับแม้กระทั่งการวาดตามเข็มนาฬิกา / ทวนเข็มนาฬิกาซึ่งคุณควบคุมการเติมด้วยกฎการคดเคี้ยวที่ไม่ใช่ศูนย์

นี่คือบทความฉบับเต็มเกี่ยวกับวิธีการทำงานและอื่น ๆ

// Defines a path for any regular polygon with the specified number of sides and radius, 
// centered on the provide x and y coordinates.
// optional parameters: startAngle and anticlockwise

function polygon(ctx, x, y, radius, sides, startAngle, anticlockwise) {
  if (sides < 3) return;
  var a = (Math.PI * 2)/sides;
  a = anticlockwise?-a:a;
  ctx.save();
  ctx.translate(x,y);
  ctx.rotate(startAngle);
  ctx.moveTo(radius,0);
  for (var i = 1; i < sides; i++) {
    ctx.lineTo(radius*Math.cos(a*i),radius*Math.sin(a*i));
  }
  ctx.closePath();
  ctx.restore();
}

// Example using the function.
// Define a path in the shape of a pentagon and then fill and stroke it.
context.beginPath();
polygon(context,125,125,100,5,-Math.PI/2);
context.fillStyle="rgba(227,11,93,0.75)";
context.fill();
context.stroke();

บทความนั้นค่อนข้างยาวว่า "การวาดวงกลมที่มีขอบน้อยกว่า" คุณอาจต้องการแคชผลลัพธ์เพื่อหลีกเลี่ยงการเรียก cos และ sin มาก (ยกโทษให้ฉันถ้ามันทำไปแล้วฉันไม่ใช่โปรแกรมเมอร์ JavaScript)
QuantumKarl

1

คุณสามารถใช้ lineTo () วิธีเดียวกับ: var objctx = canvas.getContext ('2d');

        objctx.beginPath();
        objctx.moveTo(75, 50);
        objctx.lineTo(175, 50);
        objctx.lineTo(200, 75);
        objctx.lineTo(175, 100);
        objctx.lineTo(75, 100);
        objctx.lineTo(50, 75);
        objctx.closePath();
        objctx.fillStyle = "rgb(200,0,0)";
        objctx.fill();

หากคุณไม่ต้องการเติมรูปหลายเหลี่ยมให้ใช้วิธี stroke () แทนการเติม ()

คุณสามารถตรวจสอบสิ่งต่อไปนี้: http://www.authorcode.com/draw-and-fill-a-polygon-and-triangle-in-html5/

ขอบคุณ


1

นอกจาก @canvastag แล้วให้ใช้whileloop ด้วยshiftฉันคิดว่ากระชับกว่า:

var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');

var poly = [5, 5, 100, 50, 50, 100, 10, 90];

// copy array
var shape = poly.slice(0);

ctx.fillStyle = '#f00'
ctx.beginPath();
ctx.moveTo(shape.shift(), shape.shift());
while(shape.length) {
  ctx.lineTo(shape.shift(), shape.shift());
}
ctx.closePath();
ctx.fill();

0

ในการสร้างรูปหกเหลี่ยมอย่างง่ายโดยไม่จำเป็นต้องวนซ้ำเพียงใช้ฟังก์ชัน startPath () ตรวจสอบให้แน่ใจว่าcanvas.getContext ('2d')ของคุณเท่ากับctxหากไม่เป็นเช่นนั้นจะไม่ทำงาน

ฉันต้องการเพิ่มตัวแปรที่เรียกว่าเวลาที่ฉันสามารถใช้เพื่อปรับขนาดวัตถุได้หากต้องการสิ่งนี้ฉันไม่จำเป็นต้องเปลี่ยนตัวเลขแต่ละตัว

     // Times Variable 

     var times = 1;

    // Create a shape

    ctx.beginPath();
    ctx.moveTo(99*times, 0*times);
    ctx.lineTo(99*times, 0*times);
    ctx.lineTo(198*times, 50*times);
    ctx.lineTo(198*times, 148*times);
    ctx.lineTo(99*times, 198*times);
    ctx.lineTo(99*times, 198*times);
    ctx.lineTo(1*times, 148*times);
    ctx.lineTo(1*times,57*times);
    ctx.closePath();
    ctx.clip();
    ctx.stroke();

0

สำหรับผู้ที่มองหารูปหลายเหลี่ยมปกติ:

function regPolyPath(r,p,ctx){ //Radius, #points, context
  //Azurethi was here!
  ctx.moveTo(r,0);
  for(i=0; i<p+1; i++){
    ctx.rotate(2*Math.PI/p);
    ctx.lineTo(r,0);
  }
  ctx.rotate(-2*Math.PI/p);
}

ใช้:

//Get canvas Context
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");

ctx.translate(60,60);    //Moves the origin to what is currently 60,60
//ctx.rotate(Rotation);  //Use this if you want the whole polygon rotated
regPolyPath(40,6,ctx);   //Hexagon with radius 40
//ctx.rotate(-Rotation); //remember to 'un-rotate' (or save and restore)
ctx.stroke();
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.