Рисуем эллипс на canvas

Рисуем эллипс на canvas

Создатели API для отрисовки различных графических примитивов не предусмотрели наличие встроенной функции для подобных целей. К счастью, ее реализация не очень сложна и, столкнувшись с необходимостью рисовать эллипс на canvas, я придумал следующее решение.

function drawEllipse(ctx, x, y, a, b) {
   // Запоминаем положение системы координат (CК) и масштаб
  ctx.save();
  ctx.beginPath();
 
  // Переносим СК в центр будущего эллипса
  ctx.translate(x, y);
 
  /*
   * Масштабируем по х.
   * Теперь нарисованная окружность вытянется в a / b раз
   * и станет эллипсом
   */
 
  ctx.scale(a / b, 1);
 
  // Рисуем окружность, которая благодаря масштабированию станет эллипсом
  ctx.arc(0, 0, b, 0, Math.PI * 2, true);
 
  // Восстанавливаем СК и масштаб
  ctx.restore();
 
  ctx.closePath();
  ctx.stroke();

Как видно, функция drawEllipse принимает пять аргументов.

  • ctx – контекст отрисовки
  • x, y – координаты центра эллипса (точки O на картинке)
  • a – большая полуось («горизонтальный радиус»)
  • b – малая полуось («вертикальный радиус»)

Перенос системы координат в центр эллипса необходим для того, чтобы избежать смещения его центра вправо. Наша окружность растягивается не влево и вправо одновременно а только вправо. Что произошло бы, не перенеси мы систему координат, вам пояснит картинка.

Как видно, центр окружности (точка O), координаты которого указываются при в аргументах функции, не совпадает с центром нарисованного эллипса (точка O1).

Для удобства функцию drawEllipse можно добавить в прототип объекта CanvasRenderingContext2D.

CanvasRenderingContext2D.prototype.drawEllipse = function (x, y, a, b) {
  // Запоминаем положение системы координат (CК) и масштаб
  this.save();
  this.beginPath();
 
  // Переносим СК в центр будущего эллипса
  this.translate(x, y);
 
  /*
   * Масштабируем по х.
   * Теперь нарисованная окружность вытянется в a / b раз
   * и станет эллипсом
   */
 
  this.scale(a / b, 1);
 
  // Рисуем окружность, которая благодаря масштабированию станет эллипсом
  this.arc(0, 0, b, 0, Math.PI * 2, true);
 
  // Восстанавливаем СК и масштаб
  this.restore();
 
  this.closePath();
}

Тогда её можно вызывать следующим образом:

ctx.drawEllipse(x, y, a, b);

Здесь ctx — контекст отрисовки.

В этой реализации я убрал из тела функции метод stroke(), поэтому чтобы эллипс появился на холсте необходимо ещё дописать

ctx.stroke();

Если есть желание, то можно с лёгкостью реализовать отрисовку закрашенных эллипсов просто заеменив cxt.stroke() на ctx.fill(), можно реализовать отрисовку повёрнутых на заданный угол эллипсов при помощи метода rotate контекста отрисовки. Я поленился и не стал добавлять в демо всех описанных мной дополнительных возможностей.

Скачать исходники

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *