Jak narysować wielokąty na płótnie HTML5?

95

Muszę wiedzieć, jak narysować wielokąty na płótnie. Bez używania jQuery lub czegoś podobnego.

CyanPrime
źródło
10
Warto pamiętać, że cokolwiek można zrobić bez biblioteki innej firmy, należy to zwykle zrobić.
Rodrigo

Odpowiedzi:

165

Utwórz ścieżkę za pomocą moveToi lineTo( demo na żywo ):

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();
phihag
źródło
100
@Gio Borje: AFAIK, jsFiddle nie dba o płótno, to twoja przeglądarka. jsFiddle po prostu przesyła z powrotem twój HTML / CSS / JS.
mu jest za krótkie
2
Doskonałe rozwiązanie. Bardzo zgrabny kod. dziękuję @phihag. Coś, co rozumiem!
obejrzyj
1
czy możesz zamienić c2 na ctx? Myślę, że jest to bardziej powszechne użycie w kontekście płótna. tak przy okazji świetna odpowiedź
gididaf
@ user1893354 Dziękuję bardzo za powiadomienie. Rzeczywiście wydaje się, że jest tam problem z jsfiddle - komunikat o błędzie jest całkowicie niezwiązany z kanwą. Zastąpiona bardzo prostą witryną demonstracyjną na żywo.
phihag
36

z http://www.scienceprimer.com/drawing-regular-polygons-javascript-canvas :

Poniższy kod narysuje sześciokąt. Zmień liczbę boków, aby utworzyć różne regularne wielokąty.

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>

Andrew Staroscik
źródło
3
To było świetne, bardzo eleganckie, jeśli dodasz: cxt.save(); cxt.fillStyle = "#FF000"; cxt.fill(); cxt.restore(); Możesz wypełnić kształt.
samuelkobe
to jest świetne - siedziałem, bawiąc się tym, ale nie mogę wymyślić, w jaki sposób obrócić wybrany wielokąt - jakieś pomysły?
eskimomatt
1
Jest kilka sposobów na zdobycie tego, czego chcesz. Jedną z opcji jest użycie wbudowanej metody cxt.rotate () [wraz z cxt.save () i cxt.restore ()] do obracania części płótna. Alternatywnie, zadziała również dodanie stałej wartości do funkcji cos i sin. Zobacz to jsfiddle, aby zobaczyć demonstrację: jsfiddle.net/kwyhn3ba
Andrew
dzięki za to - natknąłem się na to samo rozwiązanie po przeczytaniu logiki w podanym przez Ciebie łączu do nauki. var angle = i * 2 * Math.PI / shape.currentSides + rotationdodane do wartości cos i sin zadziałały dla mnie ... jeszcze raz dziękuję
eskimomatt
Jeśli (tak jak w moim przypadku) chcesz po prostu, aby punktem początkowym był środkowy wierzchołek wielokąta, a nie środkowy prawy, odwróć sini coswywołaj i zmień Ycenter +na Ycenter -w obu miejscach (pozostawiając to jako sumę, a nie różnicę wartości powoduje, że zaczyna się od punktu na dole powstałego kształtu). Nie jestem mądrym człowiekiem, jeśli chodzi o trygonometrię, więc bierz to z przymrużeniem oka; ale to osiągnęło to, co chciałem przynajmniej.
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();
canvastag
źródło
Dlatego chciałbym zasadniczo zrozumieć formetodę waniliową JavaScript . Ta jedna linia kodu tak bardzo uprościła sprawę. Zwykle używam jQuery, .each()ale jego aplikacja jest znacznie mniej wszechstronna.
Alexander Dixon,
7
@AlexanderDixon Powyższy javascript nie jest dobrym przykładem. Wszystkie zmienne potrzebują var, w powyższym kodzie itemjest zanieczyszczenie globalnej przestrzeni nazw. Wszystko jest w jednej linii, co zmniejsza czytelność. Jeśli nie zależy Ci na czytelności, równie dobrze możesz usunąć nawiasy klamrowe.
AnnanFay,
@canvastag Dobra praca, dynamiczna praca. Ta odpowiedź jest lepsza od zaakceptowanej dla mnie odpowiedzi. Nie rozumiem "Query .each ()" ... to jest jakaś magiczna funkcja, która zajmuje pamięć. Również dla globalnej przestrzeni nazw;) zabawne, to tylko przykład uczynienia go podobnym do klasy, jeśli chcesz.
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');
Jignesh Variya
źródło
Ciekawe ... Właściwie to ruchTo ORAZ liniaTo na początek ... ale teraz, kiedy o tym myślę ... kogo to obchodzi?
James Newton,
3

Oto funkcja, która obsługuje nawet rysowanie zgodnie z ruchem wskazówek zegara / przeciwnie do ruchu wskazówek zegara, dzięki której kontrolujesz wypełnienia za pomocą niezerowej reguły nawijania.

Oto pełny artykuł o tym, jak to działa i nie tylko.

// 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();
John R.
źródło
Ten artykuł jest dość obszerny, by powiedzieć „rysujesz koło o mniejszych krawędziach”. Możesz chcieć zapisać wyniki w pamięci podręcznej, aby uniknąć wywoływania cos i sin tak często (wybacz mi, jeśli już to robi, nie jestem programistą JavaScript).
QuantumKarl
1

Możesz użyć metody lineTo () tak samo jak: 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();

jeśli nie chcesz wypełniać wielokąta, użyj metody stroke () zamiast wypełnienia ()

Możesz również sprawdzić: http://www.authorcode.com/draw-and-fill-a-polygon-and-triangle-in-html5/

dzięki

ankur
źródło
1

Oprócz @canvastag użyj whilepętli, która shiftmoim zdaniem jest bardziej zwięzła:

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();
Koen.
źródło
0

Aby utworzyć prosty sześciokąt bez potrzeby tworzenia pętli, wystarczy użyć funkcji beginPath (). Upewnij się, że plik canvas.getContext ('2d') jest równy ctx, jeśli nie, to nie zadziała.

Lubię też dodawać zmienną o nazwie czasy, której mogę użyć do skalowania obiektu, jeśli zajdzie taka potrzeba, ale nie muszę zmieniać każdej liczby.

     // 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();
Sabba Keynejad
źródło
0

Dla osób poszukujących regularnych wielokątów:

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);
}

Posługiwać się:

//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();
Azurethi
źródło