Подтвердить что ты не робот

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

Как указано в заголовке. Возможно ли это?

Изменить: Когда я говорю "пончик", я имею в виду верхний, двумерный вид

Единственная опция для рисования сегмента круга, затем нарисуйте сегмент меньшего круга с тем же самым происхождением и меньшим радиусом сверху, с цветом фона? Если бы это было так: (

4b9b3361

Ответ 1

Вы делаете это, создавая один путь с двумя дугами.

Вы рисуете один круг по часовой стрелке, затем нарисуйте второй круг против часовой стрелки. Я не буду вдаваться в подробности этого, но путь, который построены пути, знает, чтобы принять это как причину, чтобы разгрузить эту часть пути. Для более подробной информации о том, что он делает, вы можете эту статью wiki.

То же самое можно было бы использовать, если бы вы рисовали прямоугольник с рамкой. Вы рисуете коробку в одну сторону (по часовой стрелке), затем нарисуйте внутренний ящик другим способом (против часовой стрелки), чтобы получить эффект.

Здесь код для пончика:

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

// Pay attention to my last argument!
//ctx.arc(x,y,radius,startAngle,endAngle, anticlockwise);  

ctx.beginPath()
ctx.arc(100,100,100,0,Math.PI*2, false); // outer (filled)
ctx.arc(100,100,55,0,Math.PI*2, true); // inner (unfills it)
ctx.fill();

Пример:

http://jsfiddle.net/Hnw6a/

Рисование только "сегмента" этого может быть сделано путем уменьшения пути (вам может потребоваться использование безьеров вместо дуги) или с помощью области отсечения. Это действительно зависит от того, как именно вы хотите "сегмент"

Вот один пример: http://jsfiddle.net/Hnw6a/8/

// half doughnut
ctx.beginPath()
ctx.arc(100,100,100,0,Math.PI, false); // outer (filled)
ctx.arc(100,100,55,Math.PI,Math.PI*2, true); // outer (unfills it)
ctx.fill();

Ответ 2

Вы можете сделать "верхний вид пончика" (круг с полым центром), поглаживая дугу. Вы можете увидеть пример этого здесь: http://phrogz.net/tmp/connections.html

enter image description here

Круги (с nib) рисуются строками 239-245:

ctx.lineWidth = half*0.2;          // set a nice fat line width
var r = half*0.65;                 // calculate the radius
ctx.arc(0,0,r,0,Math.PI*2,false);  // create the circle part of the path
// ... some commands for the nib
ctx.stroke();                      // actually draw the path

Ответ 3

Да, я понимаю, сколько лет этот вопрос:)

Вот мои два цента:

(function(){
 var annulus = function(centerX, centerY,
                       innerRadius, outerRadius,
                       startAngle, endAngle,
                       anticlockwise) {
  var th1 = startAngle*Math.PI/180;
  var th2 = endAngle*Math.PI/180;
  var startOfOuterArcX = outerRadius*Math.cos(th2) + centerX;
  var startOfOuterArcY = outerRadius*Math.sin(th2) + centerY;

  this.beginPath();
  this.arc(centerX, centerY, innerRadius, th1, th2, anticlockwise);
  this.lineTo(startOfOuterArcX, startOfOuterArcY);
  this.arc(centerX, centerY, outerRadius, th2, th1, !anticlockwise);
  this.closePath();
 }
 CanvasRenderingContext2D.prototype.annulus = annulus;
})();

Что добавит функцию "ringulus()", аналогичную "arc()" в прототипе CanvasRenderingContext2D. Создание закрытого пути пригодится, если вы хотите проверить включение точки.

С помощью этой функции вы можете сделать что-то вроде:

var canvas = document.getElementById("canvas1");
var ctx = canvas.getContext("2d");
ctx.annulus(0, 0, 100, 200, 15, 45);
ctx.fill();

Или проверьте это: https://jsfiddle.net/rj2r0k1z/10/

Спасибо!

Ответ 4

С помощью WebGL (один из контекстов холста HTML5) это возможно. Есть даже некоторые JS-библиотеки для браузеров, которые еще не поддерживают/реализуют его - ознакомьтесь с этими ссылками:

Ответ 5

Учитывая требования, то, что @SimonSarris говорит, удовлетворяет этой проблеме. Но позвольте сказать, что вы похожи на меня, и вместо этого вы хотите "очистить" часть формы, которая может быть частично за пределами формы, которую вы очищаете. Если у вас есть это требование, его решение не даст вам желать. Он будет выглядеть как "xor" на изображении ниже.

enter image description here

Решение состоит в использовании context.globalCompositeOperation = 'destination-out' Синяя - первая форма, а красная - вторая. Как вы можете видеть, destination-out удаляет секцию из первой формы. Вот пример кода:

  explosionCanvasCtx.fillStyle = "red"
  drawCircle(explosionCanvasCtx, projectile.radius, projectile.radius, projectile.radius)
  explosionCanvasCtx.fill()

  explosionCanvasCtx.globalCompositeOperation = 'destination-out' #see https://developer.mozilla.org/samples/canvas-tutorial/6_1_canvas_composite.html
  drawCircle(explosionCanvasCtx, projectile.radius + 20, projectile.radius, projectile.radius)
  explosionCanvasCtx.fill()

Здесь потенциальная проблема с этим: вторая fill() очистит все под ней, включая фон. Иногда вам нужно только очистить первую фигуру, но вы все равно хотите видеть слои, находящиеся под ней.

Решение этого заключается в том, чтобы нарисовать это на временном холсте, а затем drawImage, чтобы нарисовать временный холст на ваш основной холст. Код будет выглядеть так:

  diameter = projectile.radius * 2
  console.log "<canvas width='" + diameter + "' height='" + diameter + "'></canvas>"
  explosionCanvas = $("<canvas width='" + diameter + "' height='" + diameter + "'></canvas>")
  explosionCanvasCtx = explosionCanvas[0].getContext("2d")

  explosionCanvasCtx.fillStyle = "red"
  drawCircle(explosionCanvasCtx, projectile.radius, projectile.radius, projectile.radius)
  explosionCanvasCtx.fill()

  explosionCanvasCtx.globalCompositeOperation = 'destination-out' #see https://developer.mozilla.org/samples/canvas-tutorial/6_1_canvas_composite.html
  durationPercent = (projectile.startDuration - projectile.duration) / projectile.startDuration
  drawCircle(explosionCanvasCtx, projectile.radius + 20, projectile.radius, projectile.radius)
  explosionCanvasCtx.fill()
  explosionCanvasCtx.globalCompositeOperation = 'source-over' #see https://developer.mozilla.org/samples/canvas-tutorial/6_1_canvas_composite.html

  ctx.drawImage(explosionCanvas[0], projectile.pos.x - projectile.radius, projectile.pos.y - projectile.radius) #center

Ответ 6

Адаптация/упрощение @Simon Sarris, чтобы легко работать с любым углом, дает следующее:

Чтобы создать сегмент дуги, вы рисуете внешнюю дугу (из n радианов) в одном направлении, а затем противоположную дугу (того же числа радианов) с меньшим радиусом и заполняете полученную область.

var can = document.getElementById('canvas1');
var ctx = can.getContext('2d');
 
var angle = (Math.PI*2)/8;

var outer_arc_radius = 100;
var inner_arc_radius = 50.;

ctx.beginPath()

//ctx.arc(x,y,radius,startAngle,endAngle, anticlockwise); 
ctx.arc(100,100,outer_arc_radius,0,angle, false); // outer (filled)
// the tip of the "pen is now at 0,100
ctx.arc(100,100,inner_arc_radius,angle,0, true); // outer (unfills it)
ctx.fill();
<canvas id="canvas1" width="200" height="200"></canvas>