Еще одно Canvas руководство [1]: Canvas элемент, прямоугольники, пути

    Зачем еще одно руководство?


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

    На эту страницу с поисковиков зашли

    Canvas элемент


    Canvas элемент имеет имя 'canvas' (ну кто бы мог подумать) и атрибуты 'width' и 'height', при чем стоит заметить что эти атрибуты не имеют отношения к CSS, они обозначают ширину и высоту canvas элемента в пикселях не на экране, а на координатной плоскости холста. К тому же текст внутри тега будет проигнорирован браузером с поддержкой canvas и показан в браузере без поддержки canvas.

    В дальнейшем в этом учебнике мы будем использовать следующую заготовку.
    <!doctype html>
    <html>
    		<head>
    			<title>Тупая демка</title>
    		</head>
    		<body>
    			<canvas id="cnv" width="600" height="600">Ставь нормальный браузер</canvas>
                            <script type="text/javascript" src='your_file.js'></script>
    		</body>
    </html>
    


    Рисование на canvas происходит через контекст, который может быть получен вызовом метода canvas элемента getContext с аргументом '2d'.
    Так что добавим в наш скрипт строку.
    var ctx = document.getElementById('cnv').getContext('2d')
    


    Прямоугольники


    Прямоугольники в canvas это единственный примитив. Для работы с прямоугольниками существует всего 3 метода.

    Заливаем прямоугольник


    fillRect — рисует залитый прямоугольник, рассмотрим его аргументы
    fillRect(float x, float y, float w, float h)

    Где x и y это координаты верхнего левого угла, а w и h это ширина и высота соответственно. Давайте рассмотрим пример. Добавим в скрипт строку.
    ctx.fillRect(200, 250, 200, 100)

    Как многие догадались, после выполнения в центре холста будет нарисован прямоугольник шириной 200 пикселей и высотой 100 пикселей.

    Обводим прямоугольник


    strokeRect — работает точно также как и fillRect, но в отличие от него не заливает прямоугольник, а рисует только контуры. Добавим в скрипт строку.
    ctx.strokeRect(150, 200, 300, 200)

    Теперь вокруг залитого прямоугольника мы нарисовали контуры еще одного.

    Отчищаем прямоугольник


    clearRect — принимает те же самые аргументы, но в отличии от своих братьев не рисует, а уничтожает все что было раньше, как будто мы там ничего и не рисовали. Давайте уберем часть залитого прямоугольника,
    для этого добавим в наш скрипт строку:
    ctx.clearRect(350, 300, 50, 50)

    Таким образом мы обрезали часть залитого прямоугольника.

    Пути


    В отличие от прямоугольников чтобы нарисовать или залить путь нужно выполнить несколько действия, для простоты мы рассмотрим основные методы, получив через несколько шагов готовый результат, а затем нарастим базу изученных методов. Для начала давайте отчистим наш скрипт и оставим только получение контекста.

    Начинаем путь


    Первым шагом к созданию пути является вызов метода beginPath, после его вызова мы добавляем под-пути (кривые, прямые) которые хранятся в специальном списке и после каждого вызова beginPath этот список обнуляется. Так что добавим в наш скрипт строчку:
    ctx.beginPath()

    Идем к точке


    moveTo(float x, float y)
    — перемещает положение курсора на (x;y).
    Добавим в наш скрипт строку:
    ctx.moveTo(200,200)

    Ведём линию к точке


    lineTo(float x, float y)
    — проводит линию от положения курсора к (x;y).
    Для примера добавим в наш скрипт строку:
    ctx.lineTo(400,400)

    Обводим


    Завершающим моментом будет вызов метода stroke чтобы показать линию на холсте. Так что добавим строку в скрипт:
    ctx.stroke()

    Теперь если открыть наш пример то мы увидим, что на холсте отрисовывается линия.

    Замыкаем


    Если мы рисуем какую нибудь фигуру и нам нужно сделать её замкнутой то мы можем применит метод closePath. Для примера нарисуем треугольник, для этого оставим в нашем файле только получение контекста и вставим туда следующие строки:
    ctx.beginPath()
    ctx.moveTo(200,200)
    ctx.lineTo(400,400)
    ctx.lineTo(200,400)
    ctx.closePath()
    ctx.stroke()
    

    Если мы откроем файл что отрисовывается треугольник. При этом мы провели только две линии, а closePath нарисовал третью чтобы замкнуть фигуру.

    Заливаем


    Кроме отрисовки контуров мы можем еще и залить фигуру, для этого просто заменим в нашем скрипте вызова функции stroke на вызов fill. При это если вы заливаете фигуру то не обязательно явно замыкать фигуру вызывая closePath, ведь при вызове fill фигура замкнется автоматически.

    Дуги



    arc(float x, float y, float r, float startAngle, float endAngle, bool anticlockwise)
    — нарисует дугу с центром в точке (x;y), радиусом — r, стартовым углом и конечным startAngle, endAngle соответственно и если anticlockwise = true то часть окружности идет против часовой стрелки, иначе по её направлению.
    Примечание: углы измеряются в радианах
    Давайте для примера нарисуем частично залитую окружность, для этого отчистим наш скрипт, оставим только получение контекста. Затем добавим следующие строки.
    ctx.beginPath()
    ctx.arc(200,300,70,0,Math.PI*0.85,false)
    ctx.stroke()
    
    ctx.beginPath()
    ctx.arc(200,300,70,0,Math.PI*0.85,true)
    ctx.fill()
    

    Немного другие дуги



    arcTo(float x1, float y1, float x2, float y2. float r)
    — нарисует дугу с радиусом r заключенную между двумя отрезками — AB и BC, где точка A это положение курсора, B = (x1;y1) C = (x2;y2)
    Давайте для примера оставим в скрипте только получение контекста и добавим следующие строки:

    ctx.beginPath()
    ctx.moveTo(200,300)
    ctx.arcTo(300,100,400,300,50)
    ctx.stroke()
    


    Квадратичные кривые



    quadraticCurveTo(float x1, float y1, float x2, float y2)
    — нарисует квадратичную кривую образованную тремя точками (положение курсора, (x1;y1), (x2;y2)).
    Для примера посмотрим что выполнить следующий код:

    ctx.beginPath()
    ctx.moveTo(100,100)
    ctx.quadraticCurveTo(200,200,50,200)
    ctx.stroke()
    


    Кривые Безье



    bezierCurveTo(float x1, float y1, float x2, float y2, float x3, float y3)
    — нарисует кубическу кривую Безье. Для примера добавим в наш скрипт следующий код:
    ctx.beginPath()
    ctx.moveTo(100,100)
    ctx.bezierCurveTo(200,200,100,300,50,100)
                       ctx.stroke()


    Опять о прямоугольниках


    rect(float x, float y, float w, float w)
    — работает абсолютно идентично fillRect и strokeRect, но в отличие от них только добавляет прямоугольник в путь.

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

    Это точка на фигуре?


    isPointInPath(float x, float y)
    — вернет true если точка с переданными координатами находится внутри. Это метод очень хорошо использовать для проверки нажатия по какой нибудь фигуре, но для примера мы зададим все величины вручную. Добавим в наш скрипт следующие строки:
    ctx.beginPath()
    ctx.rect(200,200,100,200)
    console.log(ctx.isPointInPath(250,250))
    console.log(ctx.isPointInPath(100,100))
    

    Данный скрипт должен вывести в отладочную консоль сначала true, а затем false.

    Ограничиваем область отрисовки



    Кроме функции stroke и fill для работы с путями существует еще и функция clip, она ничего не рисует но тем не менее выполняет важную роль, после её вызова любой объект будет рисоваться только когда он находится в области на которой определен путь, давайте рассмотрим небольшой пример:
    
    ctx.beginPath()
    ctx.arc(200,300,70,0,Math.PI*2,true)
    ctx.stroke()  //Нарисуем круг по которому определим область пути
    ctx.clip()       //Ограничим область для рисования областью путя
    
    ctx.beginPath()
    ctx.moveTo(100,320)
    ctx.lineTo(500,320)
    ctx.lineTo(100,250)
    ctx.stroke() //Нарисуем парочку линий, при чем они будут видны только внутри круга
    
    


    В ближайшем будущем (в теории по части в два дня)


    Стилизация, градиенты и тени
    Отрисовка картинок и текста
    Трансформация и композиция
    Анимация и манипуляция imageData

    Similar posts

    Ads
    AdBlock has stolen the banner, but banners are not teeth — they will be back

    More

    Comments 29

    • UFO just landed and posted this here
        +3
        За дуги большое спасибо. С нетерпением жду про imageData
          +2
          Если не пугает базовый английский, то есть на MDC с примером, как обрабатывать видео онлайн
          0
          Поддерживаю со страшной силой. Вероятно, я плохо гуглил, но интересуют, собственно, механизмы работы с imageData. Например, отличается ли выполнение drawImage от прямой работы с массивом пикселей — то есть, как будет быстрее. Туда же оправданность использования двойной буфферизации или отрисовки в скрытый canvas с последующим копированием на видимый.

          Все это в итоге сводится к вопросу: нужно ли лопатить код так, чтобы работа с canvas ограничивалась одноразовым выполнением putImageData при постоянной (20-50 Гц) перерисовке при условии, что большую часть времени большая часть изображения статична.

          Думается, что это все узнается прямыми тестами, но если кто-нибудь обладает уже подобной информацией — было бы замечательно поделиться.
          0
          Спасибо) Сижу второй раз перечитываю.
            0
            если вы не забудете своё обещание про ближайшее будущее, то я думаю многие вам будут благодарны
              0
              Отличный пример! Спасибо!
                0
                спасибо, буду ждать продолжения!
                  0
                  MDC » Docs » Обучение canvas » Рисование фигур

                  Ну и точно такая же статья была у shpaker'a

                  Зачем вы два раза проходите один и тот же путь?
                  ctx.beginPath()
                  ctx.arc(200,300,70,0,Math.PI*2,true)
                  ctx.stroke()  //Нарисуем круг по которому определим область пути
                  
                  ctx.beginPath()
                  ctx.arc(200,300,70,0,Math.PI*2,true)
                  ctx.clip()      //Ограничим область для рисования областью путя
                  
                  // =>
                  
                  ctx.beginPath()
                  ctx.arc(200,300,70,0,Math.PI*2,true)
                  ctx.stroke()  //Нарисуем круг по которому определим область пути
                  ctx.clip()    //Ограничим область для рисования областью путя
                  


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

                  У Вас есть статьи получше.
                    0
                    С одним и тем же путем я действительно ступил, а насчет копирования и изменения цифр то, во первых я этого не делал, а во вторых так можно сказать про любую строчку, практически любого кода.
                      0
                      Кстати, в том же MDN есть ссылка на хороший англоязычный ресурс html5canvastutorials.com. Все структурировано, просто и понятно.
                      +1
                      И кстати,

                      Отрисовка картинок от shpaker
                      Отрисовка картинок на MDC
                      Трансформации доступным языком от Nutochka

                      Трансформации, композиция, стилизация, градиенты, тени, манипуляция с imageData и даже анимация — всё есть на MDC » Canvas очень доступным и предельно понятным языком, на 90% ещё и на русском. А чего нет — лучше помочь с переводом MDC)

                      У меня вообще, по статье и плану, у меня сложилось впечатление, что вы просто прочитали вышеупомянутый MDC » Canvas и пересказываете его содержимое своими словами. Не хватает авторской информации, изюминки.

                      Моё имхо — интересное и более-менее актуальное из вашего всего плана — только анимация. И то, если это будет что-то интересно, а не пересказ MDC » Canvas » Animation

                      Повышайте уровень, хватит топтаться у порога, идите вперед!
                    • UFO just landed and posted this here
                        +2
                        Средненько, но с оптимизациями — вполне реально использовать даже на мобилках.
                        +3
                        Хотел поднять этот вопрос на FlashGamm 2011 Moscow, но времени не хватило. Надо пост написать.

                        Производительность прекрасная на самом деле, даже под мобилками.
                        • UFO just landed and posted this here
                        +1
                        Спасибо, но больше всего интересно, как сделать текст на canvas в IE. Будет здорово, если опишите.
                          –1
                          Потому что большинство уже существующих руководств рассматривают только основы, а все остальное приходится собирать по кусочкам поэтому я решил написать сжатое, полное руководство по canvas для программистов (а то часто пишут для простых людей которые изучают попутно и программирование).

                          В моем понимании руководство для рисования прямоугольников одинаково приятны и понятны для всех. Т.е. тот кто серьёзно занят этим вопросом ограничится просмотром документации и на туториал вообще не зайдет (а таких туторилов в рунете уже кстати не один десяток), а тем кто смотрит из интереса больше бы понравились интересные примеры. Вообщем жду последующие статьи )) Интересно что дальше будете описывать, только очередной пересказ о том как надо вырисовывать изображения, а как я понимаю по логике дальше должно быть это, нужно ли?
                            –1
                            О том что уже давно сказано я пишу кратко. Поэтому здесь и не было особо много примеров.

                          Only users with full accounts can post comments. Log in, please.