Как нарисовать многоугольники на холсте HTML5?

95

Мне нужно знать, как рисовать многоугольники на холсте. Без использования jQuery или чего-то подобного.

CyanPrime
источник
10
Следует помнить, что все, что можно сделать без сторонней библиотеки, обычно следует делать именно так.
Родриго

Ответы:

165

Создайте путь с помощью 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();
Phihag
источник
100
@Gio Borje: AFAIK, jsFiddle не заботится о холсте, это ваш браузер. jsFiddle просто возвращает вам ваш HTML / CSS / JS.
mu слишком короткое
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 07
это здорово - я сижу и играю с ним, но не могу понять, как заставить выбранный многоугольник вращаться - есть идеи?
eskimomatt 06
1
Есть несколько способов получить желаемое. Один из вариантов - использовать встроенный метод cxt.rotate () [вместе с cxt.save () и cxt.restore ()] для поворота частей холста. В качестве альтернативы можно также добавить согласованное значение к функциям cos и sin. См. Этот jsfiddle для демонстрации: jsfiddle.net/kwyhn3ba
Эндрю Старощик,
спасибо за это - я наткнулся на то же решение, прочитав логику в предоставленной вами ссылке на учебник по науке. var angle = i * 2 * Math.PI / shape.currentSides + rotationдобавление к значениям cos и sin у меня сработало ... еще раз спасибо
eskimomatt 08
Если (как в моем случае) , вы просто хотите отправной точкой , чтобы быть в середине верхней части полигона , а не среднего права, переворачивать sinи cosвызовы и изменения Ycenter +в Ycenter -обеих местах (оставляя его в виде суммы , а не разности значений приводит к тому, что он начинается с точки внизу получившейся формы). Я не умный человек, когда дело касается триггеров, так что относитесь к этому с недоверием; но это достигло того, чего я хотел по крайней мере.
Джозеф Марикл
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()но его приложение гораздо менее универсально.
Александр Диксон
7
@AlexanderDixon Приведенный выше javascript - не лучший пример. Все необходимые переменные varв приведенном выше коде itemзагрязняют глобальное пространство имен. Все в одной строке, что снижает удобочитаемость. Если вас не волнует удобочитаемость, вы можете также удалить фигурные скобки.
AnnanFay
@canvastag Хорошая работа, динамичная работа. Для меня этот ответ лучше принятого. Я не понимаю "Query .each ()" ... это какая-то волшебная функция, которая забирает память. Также для глобального пространства имен;) забавно, это всего лишь пример, сделайте его как класс, если хотите.
Никола Лукич
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');
Джигнеш Вария
источник
Интересно ... На самом деле для первой точки есть moveTo И lineTo ... но теперь, когда я думаю об этом ... кого это волнует?
Джеймс Ньютон
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 и так много греха (простите меня, если он уже это делает, я не программист на 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 () вместо fill ()

Вы также можете проверить следующее: http://www.authorcode.com/draw-and-fill-a-polygon-and-triangle-in-html5/

Спасибо

Анкур
источник
1

В дополнение к @canvastag используйте whileцикл с, 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

Чтобы сделать простой шестиугольник без цикла, просто используйте функцию beginPath (). Убедитесь, что ваш canvas.getContext ('2d') равен ctx если нет, это не сработает.

Мне также нравится добавлять переменную с именем times, которую я могу использовать для масштабирования объекта, если мне нужно. Это то, что мне не нужно менять каждое число.

     // 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();
Azurethi
источник