7 июля 2013 в 00:01

jQuery plugin для использования SVG графики. Часть 1 tutorial

Для работы с SVG есть очень много библиотек для рисования. Мы рассмотрим плагин для jQuery.

Введение


Автор плагина Keith Wood, живёт в Сиднее, Австралия. Работает в Fairfax Media в качестве Java Developer. На протяжении многих лет вносит свой вклад в jQuery сообщество. Работает над книгой по разработке JQuery плагинов.

Плагин jquery.svg.js позволяет Вам манипулировать векторной графикой по спецификации SVG 1.1.
Примеры с описанием
Справочная документация

Для подключения плагина прописываем в head части файлы стилей и плагин.
<style type="text/css">@import "jquery.svg.css";</style> 
<script type="text/javascript" src="jquery.svg.js"></script>

Также при необходимости подключаем расширения плагина
<script type="text/javascript" src="jquery.svganim.js"></script>

SVG холст присоединяем к div в виде функции
$(selector).svg();

selector — свойство id тега div
svg() — функция плагина.

Возможны следующие манипуляции с холстом:
  • Получение обёртки для заданного контейнера
    $(selector).svg('get');

    пример
    var svg = $('#svgintro').svg('get'); 
    svg.circle(130, 75, 50, {fill: 'none', stroke: 'red', strokeWidth: 3});

  • Удаление функциональности для заданного контейнера
    $(selector).svg('destroy');

  • URL исходного документа для вставки
    $(selector).svg({loadURL: 'lion.svg'});

  • Вызов функции drawIntro с кодом построения рисунка методами плагина
    $(selector).svg({onLoad: drawIntro});

    пример функции drawIntro
    function drawIntro(svg) { 
        svg.circle(75, 75, 50, 
            {fill: 'none', stroke: 'red', strokeWidth: 3}); 
        var g = svg.group({stroke: 'black', strokeWidth: 2}); 
        svg.line(g, 15, 75, 135, 75); 
        svg.line(g, 75, 15, 75, 135); 
    }

    Результат



Для сравнения приведу код в SVG формате и код плагина jQuery.

код в SVG
<rect x="20" y="50" width="100" height="50" 
    fill="yellow" stroke="navy" stroke-width="5"  /> 
<rect x="150" y="50" width="100" height="50" rx="10" 
    fill="green" /> 
<g transform="translate(270 80) rotate(-30)"> 
  <rect x="0" y="0" width="100" height="500" rx="10" 
      fill="none" stroke="purple" stroke-width="3" /> 
</g> 
<circle cx="70" cy="220" r="50" 
    fill="red" stroke="blue" stroke-width="5"  /> 
<g transform="translate(175 220)"> 
  <ellipse rx="75" ry="50" fill="red"  /> 
</g> 
<ellipse transform="translate(300 220) rotate(-30)" 
    rx="75" ry="50" fill="none" stroke="blue" stroke-width="10"  /> 
<g stroke="green" > 
  <line x1="450" y1="120" x2="550" y2="20" stroke-width="5"  /> 
  <line x1="550" y1="120" x2="650" y2="20" stroke-width="10"  /> 
  <line x1="650" y1="120" x2="750" y2="20" stroke-width="15"  /> 
  <line x1="750" y1="120" x2="850" y2="20" stroke-width="20"  /> 
  <line x1="850" y1="120" x2="950" y2="20" stroke-width="25"  /> 
</g> 
<polyline fill="none" stroke="blue" stroke-width="5"  
    points="450,250 
            475,250 475,220 500,220 500,250 
            525,250 525,200 550,200 550,250 
            575,250 575,180 600,180 600,250 
            625,250 625,160 650,160 650,250 
            675,250" /> 
<polygon fill="lime" stroke="blue" stroke-width="10"  
    points="800,150 900,180 900,240 800,270 700,240 700,180" />

тот же рисунок, код в jQuery.SVG
svg.rect(20, 50, 100, 50, {fill: 'yellow', stroke: 'navy', strokeWidth: 5});
svg.rect(150, 50, 100, 50, 10, 10, {fill: 'green'});
var g = svg.group({transform: 'translate(270 80) rotate(-30)'}); 
   svg.rect(g, 0, 0, 100, 50, 10, 10, {fill: 'none', stroke: 'purple', strokeWidth: 3});
svg.circle(70, 220, 50, {fill: 'red', stroke: 'blue', strokeWidth: 5});
var g = svg.group({transform: 'translate(175 220)'}); 
   svg.ellipse(g, '', '', 75, 50, {fill: 'yellow'}); 
svg.ellipse('', '', 75, 50, {transform: 'translate(300 220) rotate(-30)', 
fill: 'none', stroke: 'blue', strokeWidth: 10}); 
var g = svg.group({stroke: 'green'}); 
   svg.line(g, 450, 120, 550, 20, {strokeWidth: 5}); 
   svg.line(g, 550, 120, 650, 20, {strokeWidth: 10}); 
   svg.line(g, 650, 120, 750, 20, {strokeWidth: 15}); 
   svg.line(g, 750, 120, 850, 20, {strokeWidth: 20}); 
   svg.line(g, 850, 120, 950, 20, {strokeWidth: 25}); 
svg.polyline([[450,250], [475,250],[475,220],[500,220],[500,250], 
    [525,250],[525,200],[550,200],[550,250], 
    [575,250],[575,180],[600,180],[600,250], 
    [625,250],[625,160],[650,160],[650,250],[675,250]],
     {fill: 'none', stroke: 'blue', strokeWidth: 5}); 
svg.polygon([[800,150],[900,180],[900,240],[800,270],[700,240],[700,180]],
     {fill: 'lime', stroke: 'blue', strokeWidth: 10});
Виталий @viklviv
карма
11,0
рейтинг 0,0
Похожие публикации
Самое читаемое Разработка

Комментарии (20)

  • +5
    А в чём фишка такого подключения стилей?:

    <style type="text/css">@import "jquery.svg.css";</style> 
    
  • 0
    Правило @ import позволяет импортировать содержимое CSS-файла в текущую стилевую таблицу.
    • +7
      А в чем плюсы такого подключения?
  • +1
    процетирую
    Расширенные возможности CSS, применяемые при разработке среднего современного сайта, скорее всего будут отображены старым броузером искаженно или вообще не позволят открыть страницу.
    Скрытие стилей с помощью метода @ import (Netscape 4, Internet Explorer 4 и другие старые броузеры не поддерживают возможность ссылки на таблицу стилей с помощью метода @ import, а благодаря особенностям CSS эта непонятная команда будет ими проигнорирована) позволит избежать таких сбоев. На самом деле даже не обязательно добавлять базовую таблицу стилей – если вы присоединяете свою таблицу стилей с помощью @ import, то в старых броузерах документ будет отображен в соответствии с их внутренней таблицей стилей.
    • +8
      Хм… и у кого же это сейчас можно найти IE4…
      Разве это кого-то беспокоит в 2013 году?)
    • +1
      цИтата
  • 0
    автора плагина беспокоит, хотя и не везде в примерах
  • +1
    По моему проще d3 взять.
  • 0
    Для работы с SVG есть очень много библиотек для рисования. Мы рассмотрим плагин для jQuery.

    Почему jquery.svg.js? Правильно ли я понимаю, что обзор делается в рамках разработки стандарта чертежей?

    Рекомендую посмотреть svg.js (http://www.svgjs.com), т.к. многие вещи, ранее написанные мной с использованием jquery.svg.js, стали выглядеть гораздо проще и лаконичнее будучи переписанными на svg.js, хотя, конечно, не без нюансов.
    • 0
      Почему jquery.svg.js? Правильно ли я понимаю, что обзор делается в рамках разработки стандарта чертежей?

      Описание чертежа на JavaScript тоже тестировал с использованием библиотеки jquery.svg.js. Для более компактного кода чертежа, взяв всё необходимое из jquery.svg.js переписываю в jquery.cad.js с методами более понятными для описания чертежа.

      Пример
      function drawIntro(cad) {
        var defs = cad.defs('defsCAD',['dimArrow','point']);  
        cad.title('SVG for CAD');
        var Draw = cad.group();
            var Shtamp = cad.group(Draw,'Shtamp');
                cad.rect(Shtamp,20,5,395,287);
                cad.line(Shtamp,230,237,415,237);
                cad.line(Shtamp,230,237,230,292);
                cad.line(Shtamp,90,5,90,19);
                cad.line(Shtamp,20,19,90,19);
                cad.rect(Shtamp,1,1,418,295,2);
      	  ...	
        var vsf = cad.view(50, 7, 170, 165, -25, -200, 680, 660);	
      	cad.title(vsf, 'View 1');
      	cad.line(vsf,0,325,500,325);
      	cad.line(vsf,0,225,0,325);
      	cad.line(vsf,0,225,250,225);
      	cad.line(vsf,140,225,190,0);
      	...
      	
      	cad.line(vsf,250,350,250,-25,3);
      	cad.line(vsf,50,350,50,200,3);
      	cad.line(vsf,450,350,450,200,3);	
      
      	cad.line(vsf,210,0,210,250,4);
      	cad.line(vsf,160,250,190,250,4);
      	cad.line(vsf,160,325,160,250,4);	
      	
      	cad.line(vsf,25,325,25,225,4);
      	cad.line(vsf,75,325,75,225,4);
      	cad.line(vsf,425,325,425,225);
      	cad.line(vsf,475,325,475,225);	
          
          var hatch1_45 = cad.pattern(defs, 'hatch1_45', 0, 0, 20, 20,
              0, 0, 20, 20, {patternUnits: 'userSpaceOnUse'});
                cad.line(hatch1_45,1,20,20,1,2);
                cad.line(hatch1_45,0,1,1,0,2);
      	  
      	cad.hatch(vsf,'hatch1_45','M475,225L475,325 500,325 500,225z');
      	cad.hatch(vsf,'hatch1_45','M290,0V250H340V325H425V225H360L310,0z');
      
      	var dimText = [0, 0, '325'];
      	var dimDrawing = [1, [310,0,'dimArrow1'],[500,325,'dimArrow2'],[275,0,1]];
      	cad.diml(vsf, dimDrawing, dimText);
      	
      	var dimText = [0, 0, '100'];
      	var dimDrawing = [1, [500,225,'dimArrow1'],[500,325,'dimArrow2'],[45,0,1]];
      	cad.diml(vsf, dimDrawing, dimText);
      	  
        var vsf = cad.view(25, 158, 200, 135, -100, -250, 800, 540);
      	cad.title(vsf, 'View 2');	
      	cad.circle(vsf,250,0,40);
      	cad.circle(vsf,250,0,60);
      	cad.circle(vsf,50,0,25);
      	cad.circle(vsf,450,0,25);	
      	cad.line(vsf,50,-30,50,30,3);
      	cad.line(vsf,450,-30,450,30,3);
      	cad.line(vsf,250,-150,250,200,3);
      	cad.line(vsf,-25,0,525,0,3);	
      	cad.line(vsf,27.5,44.6514,170,116.457);
      	cad.line(vsf,472.5,44.6514,330,116.457);
      	cad.line(vsf,27.5,-44.6514,187,-125.024);
      	cad.line(vsf,472.5,-44.6514,313,-125.024);
      	...
      
      	cad.arc(vsf,187,-125.024,313,-125.024,140,0,1);	
      	cad.arc(vsf,27.5,44.6514,27.5,-44.6514,50,0,1);
      	cad.arc(vsf,472.5,44.6514,472.5,-44.6514,50,0,0);
      	cad.arc(vsf,162.822,67.082,337.178,67.082,110,1,1);
      	cad.arc(vsf,180.459,57.132,319.54,57.132,90,0,0);
      
      	cad.cbezier(vsf, 'M140,101.34 C144.696,86.7859 152.303,75.3664 162.822,67.082C167.996,63.0066 174.363,58.9944 180.459,57.132C194.3626,52.8843 213.0561,57.1320 225.5589,67.082C232.5067,72.6114 241.8569,77.1221 250,77.9937C263.3438,79.4220 275.9399,63.2633 290.0,60C299.5142,57.7918 310.4253,54.6301 319.5409,57.132C325.7604,58.8390 332.0035,63.0066 337.1780,67.082C347.6966,75.3664 353.3294,89.2060 360,101.3405', 2);
      	
      	cad.hatch(vsf,'hatch1_45','M170,180L170,116.4576 140,101.3405C144.696,86.7859,152.303,75.3664,162.822,67.082C167.996,63.0066,174.363,58.9944,180.459,57.132A90,90,0,0,0,190,67.082L190,180z');
      	cad.hatch(vsf,'hatch1_45','M310,180L310,67.082A90,90,0,0,0,319.54,57.132C325.7604,58.839,332.0035,63.0066,337.1780,67.082C347.6966,75.3664,353.3294,89.206,360,101.3405L330,116.4576 330,180z');
      	
      	var dimText = [0, 0, '120'];
      	var dimDrawing = [0, [190,180,'dimArrow1'],[310,180,'dimArrow2'],[0,50,1]];
      	cad.diml(vsf, dimDrawing, dimText);
      
      	var dimText = [0, 0, '160'];
      	var dimDrawing = [0, [170,180,'dimArrow1'],[330,180,'dimArrow2'],[0,85,1]];
      	cad.diml(vsf, dimDrawing, dimText);
      
      	var dimText = [0, 0, '320'];
      	var dimDrawing = [1, [330,180,'dimArrow1'],[250,-140,'dimArrow2'],[230,0,1]];
      	cad.diml(vsf, dimDrawing, dimText);
      	  
        var vsf = cad.view(250, 45, 125, 100, -50, -50, 500, 400);
      	cad.title(vsf, 'View 3');
              cad.line(vsf,0,325,320,325);
      	cad.line(vsf,0,225,30,225);
      	cad.line(vsf,0,225,0,325);
              cad.line(vsf,320,325,320,225);
      	...
      	cad.line(vsf,140,350,140,-25,3);
      
      	cad.hatch(vsf,'hatch1_45','M230,290L230,325 320,325 320,290z');
      	cad.hatch(vsf,'hatch1_45','M0,325L0,225 30,225 80,0 100,0 100,250 50,250 50,325z');
      	cad.hatch(vsf,'hatch1_45','M180,250L180,0 200,0 250,225 320,225 320,250z');
      
      	var dimText = [0, 0, '40'];
      	var dimDrawing = [1, [320,250,'dimArrow2'],[320,290,'dimArrow1'],[50,0,1]];
      	cad.diml(vsf, dimDrawing, dimText);
      
      	var dimText = [0, 0, '75'];
      	var dimDrawing = [1, [320,250,'dimArrow1'],[320,325,'dimArrow2'],[100,0,1]];
      	cad.diml(vsf, dimDrawing, dimText); 
      };
      • 0
        Возможно, стоит предусмотреть вам свое описание предметной области для отрисовки чертежей. Некое подобие объектно-ориентированного формата, в котором будут методы, реализующие отрисовку тех или иных элементов формата в svg.

        В дальнейшем это сделает возможным отрисовку другими способами или через другие библиотеки. А у вас в текущей реализации очень жесткая привязка к svg, более того очень похоже на прародителя jquery.svg.js, что в определенный момент может выйти боком.

        Например, у вас есть чертеж — некий документ. В документе есть страницы. Страницы могут быть собственно чертежами либо страницей с текстом. Страница содержит рамку с описанием. Ну, а далее на странице расположены элементы разных типов.

        Но только это не примитивы svg, а свои элементы (в принципе вы и делаете эти элементы). В дальнейшем у вас будет библиотека элементов. Еще возможно внедрение областей и слоев на странице (возможно даже функциональных слоев — надписи в одном слое, блоки в другом). Все это реализуемо в рамках svg.

        Но svg может стать всего лишь одной из реализаций вашего объектно-ориентированного формата. В принципе, для каждого объекта вашего формата чертежей вам необходимо реализовать метод toSVG(), и должным образом упаковать.

        А от
        cad.line(vsf,50,-30,50,30,3);
        cad.line(vsf,450,-30,450,30,3);
        cad.line(vsf,250,-150,250,200,3);
        cad.line(vsf,-25,0,525,0,3);

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

        Хотелось бы в итоге увидеть что-то типа (набросал на скорую руку, прошу не ругать :):
        page = new Page();
        page.add(new Shtamp());
        block = new Block(0,100,80,90);
        block.add(new Circle({radius:100,x:10,y:10,show_dimensions:true}));
        block.add(new Text({x:10,y:10,text:''это типа круг'}))
        page.add(block);
        page.export(type:svg);
        • 0
          Ага, и получить то, что уже есть в d3.
          • 0
            D3 больше подходит для работы с данными и их визуализации, здесь viklviv вроде как хочет создать формат в svg.

            В D3 создается дополнительный уровень абстракции, который позволяет работать с данными, преобразовывать их. Данные это больше чем просто данные. Это и данные, и способ взаимодействия с ними — соответствующее представление, будь то график, таблица на основе svg.

            D3 — это развитие библиотеки Protovis, ее тоже написал Mike Bostock. Так ранее для Protovis'а использовался canvas для рисовки, а потом стал использоваться svg. Поэтому если завтра появится более удобная вещь нежели svg, d3 сможет перейти на нее, добавив новую схему представления данных.

            И может быть можно даже приспособить d3 для рисования чертежей, было бы желание.
            • 0
              d3 штука гибкая. Что я хотел сказать, это то что примеры вашего кода это практически то, что получится если писать его на d3. Но естественно возможности гораздо шире, например динамическая привязка параметров приметивов к данным, что в чертеже не очень и нужно.
              Кроме того, в d3 из коробке очень мощная поддержка шкал, что кстати очень нужно при отрисовке чертежей, особенно если необходимо обеспечить масштабирование и перемещение по листу ( pan & zoom )
        • 0
          Возможно, стоит предусмотреть вам свое описание предметной области для отрисовки чертежей. Некое подобие объектно-ориентированного формата, в котором будут методы, реализующие отрисовку тех или иных элементов формата в svg.

          Так и есть.
          Например описание вида на листе чертежа
          var vsf = cad.view(250, 45, 125, 100, -50, -50, 500, 400);
          

          Описание функции
          /* Add an embedded SVG element.
          	   Specify all of vx, vy, vwidth, vheight or none of them.
          	   @param  parent    (element or jQuery) the parent node for the new node (optional)
          	   @param  x         (number) the x-coordinate for the left edge of the node
          	   @param  y         (number) the y-coordinate for the top edge of the node
          	   @param  width     (number) the width of the node
          	   @param  height    (number) the height of the node
          	   @param  vx        (number) the minimum x-coordinate for view box (optional)
          	   @param  vy        (number) the minimum y-coordinate for the view box (optional)
          	   @param  vwidth    (number) the width of the view box (optional)
          	   @param  vheight   (number) the height of the view box (optional)
          	   @param  settings  (object) additional settings for the node (optional)
          	   @return  (element) the new node */
          	view: function(parent, x, y, width, height, vx, vy, vwidth, vheight, settings) {
          


          Например описание линейного размера в виде (не примитив svg)
              var dimText = [0, 0, '120'];
              var dimDrawing = [0, [190,180,'dimArrow1'],[310,180,'dimArrow2'],[0,50,1]];
              cad.diml(vsf, dimDrawing, dimText);
          

          Описание функции
          /* Draw a linear dimension
          	   @param  parent    (element or jQuery) the parent node for the new shape (optional)
          	   @param  dimDrawing (number and string[][]) the options drawing dimensions
          	   @param  dimText   (number and string[][]) the options drawing text
          	   @return  (element) the new shape node */
              diml: function(parent, dimDrawing, dimText) {
          

          Задаю два массива dimText — для текстовой части, dimDrawing — для графической.
          Функция cad.diml создаёт по заданным данным массива конструкцию в SVG в виде vsf.

          Например описание штриховки (не примитив svg)
          cad.hatch(vsf,'hatch1_45','M230,290L230,325 320,325 320,290z');

          Описание функции
          /* Draw a hatch
          	   @param  parent    (element or jQuery) the parent node for the new shape (optional)
          	   @param  nameHatch (string) the name hatch
          	   @param  contour   (string) the definition of the outline of a shape
          	   @return  (element) the new shape node */		
              hatch: function(parent, nameHatch, contour) {
          		return this.path(parent, contour, {fill: 'url(#'+nameHatch+')'});		
          	},

          Функция cad.hatch создаёт по заданным данным ( hatch1_45 — шаблон штриховки и контуру) конструкцию в SVG в виде vsf.

          Например описание дуги
             cad.arc(vsf,187,-125.024,313,-125.024,140,0,1);

          Описание функции
          /* Draw a arc.
          	   @param  parent    (element or jQuery) the parent node for the new shape (optional)
          	   @param  x1        (number) the x-coordinate for the start of the line
          	   @param  y1        (number) the y-coordinate for the start of the line
          	   @param  x2        (number) the x-coordinate for the end of the line
          	   @param  y2        (number) the y-coordinate for the end of the line	   
          	   @param  r         (number) the radius of the circle
          	   @param  large      (boolean) true to draw the large part of the arc,
          	                      false to draw the small part (omitted if rx is array)
          	   @param  clockwise  (boolean) true to draw the clockwise arc,
          	                      false to draw the anti-clockwise arc (omitted if rx is array)
          	   @param  type      (number) the type of the line (optional)
          	   @return  (element) the new shape node */	
          	arc: function(parent, x1, y1, x2, y2, r, large, clockwise, type) {
          
          • 0
            Oh! я читал код, я понял, что cad.view и cad.diml — это не функции из jquery.svg.js.
            Вы наследуетесь от SVG и начинаете его шпиговать своими функциями?
            Вы остаетесь на уровне svg, поднимитесь чуть выше. Например, svg-холст может быть лишь внутренним свойством вашего CAD. Вы заполняете свойства CAD, название, рамку и массив блоков. Блок — это множество линий, кругов и т.п. с их штриховками, указанием размеров и т.д. А затем все это render'ите. (Блин, идея мне нравится с чертежами, и даже представляю как это можно грамотно сделать, уж не запилить ли мне свое казино?: )

            vsf — wtf?

            "@ param dimDrawing (number and string[ ][ ])" — а может стоит пользоваться json-подобным набором параметров? как минимум будет читабельнее в использующем функцию коде (и не придется вставлять функцию и описание к ней).
            • 0
              "@ param dimDrawing (number and string[ ][ ])" — а может стоит пользоваться json-подобным набором параметров? как минимум будет читабельнее в использующем функцию коде (и не придется вставлять функцию и описание к ней).

              Может и стоит, размер файла описание чертежа вырастит. Может в функции проверять массив или объект и соответственно обрабатывать. Определённые части массива могут не заполнятся, соответственно и какой-то элемент графики не отображаться.
        • 0
          Например, у вас есть чертеж — некий документ. В документе есть страницы. Страницы могут быть собственно чертежами либо страницей с текстом. Страница содержит рамку с описанием. Ну, а далее на странице расположены элементы разных типов.

          Но только это не примитивы svg, а свои элементы (в принципе вы и делаете эти элементы). В дальнейшем у вас будет библиотека элементов. Еще возможно внедрение областей и слоев на странице (возможно даже функциональных слоев — надписи в одном слое, блоки в другом). Все это реализуемо в рамках svg.


          Есть документ. У него нет страниц. Это область листа определённого формата. Он может быть разного вида(типа): фрагмент, чертёж, спецификация, текстовый документ (он тоже имеет рамочку с штампом как и у чертежа и каждая страница текстовой документации рассматривается как отдельный документ). Чертёж детали может состоять из нескольких документов (листов) как и спецификация (страниц).
          Для вида(типа) чертёж в области листа размещаются виды (фрагмент вида детали с одной стороны) в определённом масштабе. В области вида кроме примитивов (линия, дуга, окружность) размещены объекты: размеры, обозначение линии разреза, обозначение шероховатости, лини-выноски. Графическая и текстовая части объекта (размера, позиции и др.) не может быть разнесена на разные слои.
          Набор слоёв размещается в каждом виде и могут быть слои в области листа. Слой — группа элементов отображенная одним цветом.

          Так как набрасываю черновик библиотеки для экспорта/импорта из Компас-график в SVG, то мне проще документ описать так
          cad.line(vsf,50,-30,50,30,3);
          cad.line(vsf,450,-30,450,30,3);
          cad.line(vsf,250,-150,250,200,3);
          cad.line(vsf,-25,0,525,0,3);

          чем так
          page = new Page();
          page.add(new Shtamp());
          block = new Block(0,100,80,90);
          block.add(new Circle({radius:100,x:10,y:10,show_dimensions:true}));
          block.add(new Text({x:10,y:10,text:''это типа круг'}))
          page.add(block);
          page.export(type:svg);

          И по мере изменений поддержки браузерами SVG вносить изменения в библиотеку на JavaScript, чем в библиотеку под Компас-график или другую CAD систему.
  • 0
    Проще raphaeljs.com пока не видел (для работы с SVG)…
    Буду сравнивать с этим плагином…
    • 0
      Да, Raphaёl гораздо проще, мощнее и к тому же от нашего соотечественника (он и на хабре кстати есть).

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