Como desenhar polígonos em uma tela HTML5?

95

Preciso saber desenhar polígonos em uma tela. Sem usar jQuery ou algo parecido.

CyanPrime
fonte
10
É bom lembrar que tudo o que pode ser feito sem uma biblioteca de terceiros, geralmente deve ser feito.
Rodrigo

Respostas:

165

Crie um caminho com moveToe lineTo( demonstração ao vivo ):

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
fonte
100
@Gio Borje: AFAIK, jsFiddle não liga para o canvas, esse é o seu navegador. jsFiddle apenas envia seu HTML / CSS / JS de volta para você.
mu é muito curto
2
Excelente solução. Código muito bom. obrigado @phihag. Algo que eu possa entender!
bytise
1
você pode substituir c2 por ctx? Acho que é o uso mais comum para o contexto do canvas. ótima resposta, por
falar
@ user1893354 Muito obrigado pelo aviso. Na verdade, parece haver um problema com o jsfiddle ali - a mensagem de erro não está totalmente relacionada ao canvas. Substituído por um site de demonstração ao vivo muito simples.
phihag
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
fonte
É por isso que eu gostaria de poder entender fundamentalmente o formétodo JavaScript vanilla . Essa única linha de código simplificou muito as coisas. Normalmente uso o jQuery, .each()mas seu aplicativo é muito menos versátil.
Alexander Dixon
7
@AlexanderDixon O javascript acima não é realmente um bom exemplo. Todas as variáveis ​​precisam var, no código acima itemestá poluindo o namespace global. Tudo está em uma linha, o que reduz a legibilidade. Se você não se preocupa com a legibilidade, pode também remover as chaves.
AnnanFay
@canvastag Bom trabalho, trabalho dinâmico. Esta resposta é melhor de uma resposta aceita por mim. Não entendo "Query .each ()" ... esta é uma função mágica que ocupa memória. Também para namespace global;) engraçado, este é apenas um exemplo, faça como uma classe se você quiser.
Nikola Lukic
34

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

O código a seguir desenhará um hexágono. Altere o número de lados para criar diferentes polígonos regulares.

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
fonte
3
Isso foi ótimo, muito elegante, também, se você adicionar: cxt.save(); cxt.fillStyle = "#FF000"; cxt.fill(); cxt.restore(); Você pode preencher a forma.
samuelkobe
isso é ótimo - estive sentado brincando com ele, mas não consigo descobrir como faria o polígono escolhido girar - alguma ideia?
eskimomatt
1
Existem algumas maneiras de obter o que deseja. Uma opção é usar o método cxt.rotate () embutido [junto com cxt.save () e cxt.restore ()] para girar partes da tela. Como alternativa, adicionar um valor consistente às funções cos e sin também funcionará. Veja este jsfiddle para uma demonstração: jsfiddle.net/kwyhn3ba
Andrew Staroscik
obrigado por isso - encontrei a mesma solução depois de ler a lógica no link de introdução científica que você forneceu. var angle = i * 2 * Math.PI / shape.currentSides + rotationadicionado aos valores de cos e sin funcionou para mim ... obrigado novamente
eskimomatt
Se (como no meu caso) você quiser apenas que o ponto de partida seja o topo do meio do polígono em vez do meio à direita, vire sine coschama e mude Ycenter +para Ycenter -em ambos os lugares (deixando como uma soma em vez de uma diferença de valores resulta em começar com um ponto na parte inferior da forma resultante). Não sou um homem inteligente quando se trata de trigonometria, então aceite com cautela; mas isso atingiu o que eu queria, pelo menos.
Joseph Marikle
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
fonte
Interessante ... Na verdade, moveTo AND lineTo para o primeiro ponto ... mas agora que penso nisso ... quem se importa?
James Newton
3

Aqui está uma função que suporta até mesmo o desenho no sentido horário / anti-horário que você controla os preenchimentos com a regra de contorno diferente de zero.

Aqui está um artigo completo sobre como funciona e muito mais.

// 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
fonte
Esse artigo é bastante longo para dizer "você está desenhando um círculo com menos arestas". Você pode querer armazenar em cache os resultados para evitar chamar tanto cos e sin (perdoe-me se já estou fazendo isso, não sou um programador de JavaScript).
QuantumKarl
1

Você pode usar o método lineTo () igual a: 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();

se você não quiser preencher o polígono, use o método stroke () no lugar do fill ()

Você também pode verificar o seguinte: http://www.authorcode.com/draw-and-fill-a-polygon-and-triangle-in-html5/

obrigado

Ankur
fonte
1

Além de @canvastag, use um whileloop com shiftacho que é mais conciso:

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.
fonte
0

Para fazer um hexágono simples sem a necessidade de um loop, basta usar a função beginPath (). Certifique-se de que seu canvas.getContext ('2d') seja igual a ctx, caso contrário, não funcionará.

Também gosto de adicionar uma variável chamada times que posso usar para dimensionar o objeto se precisar. Isso é o que não preciso alterar cada número.

     // 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
fonte
0

Para as pessoas que procuram polígonos regulares:

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

Usar:

//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
fonte