Comment dessiner des polygones sur un canevas HTML5?


95

J'ai besoin de savoir comment dessiner des polygones sur une toile. Sans utiliser jQuery ou quelque chose comme ça.


10
Il est bon de se rappeler que tout ce qui peut être fait sans bibliothèque tierce doit généralement l'être.
Rodrigo

Réponses:


165

Créez un chemin avec moveToet lineTo( démo en direct ):

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 ne se soucie pas du canevas, c'est votre navigateur. jsFiddle vous renvoie simplement votre HTML / CSS / JS.
mu est trop court le

2
Excellente solution. Code très soigné. merci @phihag. Quelque chose que je peux comprendre!
bytise

1
pouvez-vous remplacer c2 par ctx? Je pense que c'est une utilisation plus courante pour le contexte de canevas. bonne réponse au fait
gididaf

@ user1893354 Merci beaucoup pour l'avis. En effet, il semble y avoir un problème avec jsfiddle là-bas - le message d'erreur n'a aucun rapport avec le canevas. Remplacé par un site de démonstration en direct très simple.
phihag

35

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

Le code suivant dessinera un hexagone. Modifiez le nombre de côtés pour créer différents polygones réguliers.

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
C'était génial, très élégant aussi, si vous ajoutez: cxt.save(); cxt.fillStyle = "#FF000"; cxt.fill(); cxt.restore(); vous pouvez remplir la forme.
samuelkobe

c'est génial - je suis assis en train de jouer avec, mais je ne peux pas déterminer comment je pourrais faire pivoter le polygone choisi - des idées?
eskimomatt

1
Il existe plusieurs façons d'obtenir ce que vous voulez. Une option consiste à utiliser la méthode intégrée cxt.rotate () [avec cxt.save () et cxt.restore ()] pour faire pivoter des parties du canevas. Alternativement, l'ajout d'une valeur cohérente aux fonctions cos et sin fonctionnera également. Voir ce jsfiddle pour une démonstration: jsfiddle.net/kwyhn3ba
Andrew Staroscik

merci pour cela - je suis tombé sur la même solution après avoir lu la logique sur le lien d'amorce scientifique que vous avez fourni. var angle = i * 2 * Math.PI / shape.currentSides + rotationajouté aux valeurs cos et sin a fonctionné pour moi ... merci encore
eskimomatt

Si (comme dans mon cas) , vous voulez que le point de départ pour être le haut au milieu du polygone plutôt que le milieu à droite, retournez les sinet les cosappels et les changements Ycenter +à Ycenter -des deux endroits ( en laissant comme une somme plutôt qu'une différence des valeurs le fait commencer par un point au bas de la forme résultante). Je ne suis pas un homme intelligent quand il s'agit de trig, alors prenez avec un grain de sel; mais cela a réalisé ce que je voulais au moins.
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();

C'est pourquoi j'aurais aimé pouvoir comprendre fondamentalement la forméthode JavaScript vanilla . Cette seule ligne de code a tellement simplifié les choses. J'utilise généralement jQuery .each()mais son application est beaucoup moins polyvalente.
Alexander Dixon

7
@AlexanderDixon Le javascript ci-dessus n'est vraiment pas un bon exemple. Toutes les variables ont besoin var, dans le code ci-dessus, d' itemun espace de noms global polluant. Tout est sur une seule ligne, ce qui réduit la lisibilité. Si vous ne vous souciez pas de la lisibilité, vous pouvez également supprimer les accolades.
AnnanFay

@canvastag Beau travail dynamique. Cette réponse est meilleure de la réponse acceptée pour moi. Je ne comprends pas "Query .each ()" ... c'est une fonction magique qui prend de la mémoire. Aussi pour l'espace de noms global;) drôle c'est juste un exemple, faites-le comme une classe si vous le souhaitez.
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');

Intéressant ... En fait, un mouvement vers ET une ligne pour le premier point ... mais maintenant que j'y pense ... qui s'en soucie?
James Newton

3

Voici une fonction qui prend même en charge le dessin dans le sens horaire / anti-horaire pour contrôler les remplissages avec la règle d'enroulement non nulle.

Voici un article complet sur son fonctionnement et plus encore.

// 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();

Cet article est assez long pour dire "tu dessines un cercle avec moins d'arêtes". Vous voudrez peut-être mettre en cache les résultats pour éviter d'appeler trop cos et péché (pardonnez-moi si c'est déjà le cas, je ne suis pas un programmeur JavaScript).
QuantumKarl

1

Vous pouvez utiliser la méthode lineTo () de la même manière que: 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();

si vous ne voulez pas remplir le polygone, utilisez la méthode stroke () à la place de fill ()

Vous pouvez également vérifier les éléments suivants: http://www.authorcode.com/draw-and-fill-a-polygon-and-triangle-in-html5/

Merci


1

En plus de @canvastag, utilisez une whileboucle avec shiftje pense que c'est plus concis:

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

Pour créer un simple hexagone sans avoir besoin d'une boucle, utilisez simplement la fonction beginPath (). Assurez-vous que votre canvas.getContext ('2d') est égal à ctx sinon cela ne fonctionnera pas.

J'aime aussi ajouter une variable appelée times que je peux utiliser pour mettre à l'échelle l'objet si nécessaire, ce dont je n'ai pas besoin pour changer chaque nombre.

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

Pour les personnes recherchant des polygones réguliers:

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

Utilisation:

//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();
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.