Raphael.js - Quickstart and Practice - #FFF001
Эта статья - это текстовая версия нашего совместного доклада, авторами которого стали Александр Павловский и Олег Рудой. Собственно этот доклад и стал темой первой встречи нашего комьюнити.
Intro
И так начинаем...
Сегодня возможности CSS3 помогают реализовать почти любую UI прихоть дизайнеров и заказчиков. В виду чего наш интерфейс можно нарисовать одними лишь HTML элементами придав им динамику тем же CSS3. Но всё же почти любую прихоть, мы можем нарисовать и блок и превратить его в круг, но к сожалению CSS3 еще не научился рисовать сложные кривые и пути (path). В этом нам просто отличнейшим поможет маленькая и весьма развитая библиотека Raphael.js.
Сегодня возможности CSS3 помогают реализовать почти любую UI прихоть дизайнеров и заказчиков. В виду чего наш интерфейс можно нарисовать одними лишь HTML элементами придав им динамику тем же CSS3. Но всё же почти любую прихоть, мы можем нарисовать и блок и превратить его в круг, но к сожалению CSS3 еще не научился рисовать сложные кривые и пути (path). В этом нам просто отличнейшим поможет маленькая и весьма развитая библиотека Raphael.js.
Paphael.js – это
JavaScript библиотека которая простейшим способом реализовывает
векторную графику (SVG - Scaleble Vector Graphic)
в Web. Сегодня я вам
расскажу как быстро начать работать с Raphael.js.
Собственно почему же я выбрал Raphael.js. Так уж сложилось что до сих пор
время от времени приходится поддерживать десктоп с IE8 и одним из основных преимуществ Raphael –
это то что он у нас не Flash и он кроссбраузерный. А
именно заявлено что
это: Firefox 3.0+,
Safari 3.0+, Chrome 5.0+, Opera 9.5+ and Internet Explorer 6.0+. Естественно
это обусловлено хорошей поддержкой SVG caniuse.com демонстрирует
вот такие результаты
Результаты на лицо, проблемы лишь с IE8 ну и старыми версиями Android. Но в случае с IE8
Raphael отобразит наши графические элементы в экзотическом формате VML (Аналог SVG разрабатываемый Microsoft).
Чем же еще прелестен вектор? Я визуально попытался
изобразить разницу:
Да, современный пользователь не хочет на совей retina а
то и здоровенной плазме видеть эти угловатые кривые, SVG-вектор же нарисует же для нас идеальные
скругленные формы. Ведь в понимании круг он в браузере нарисует круг увеличивая
до бесконечности который он будет оставаться круглым.
Так же не стоит забывать почему же всё такие не трендовый Canvas? Сравнивать эти две
технологии можно очень долго и в итоге все равно будет сложно выбрать
победителя, ведь выбираем мы по потребности. Поэтому прежде всего явное отличие
в том что SVG это DOM-элементы
и все элементы SVG так же будут отображены как DOM-элементы на которые мы в дальнейшем
можем влиять не обязательно с помощью Raphael.js.
Вот пример SVG кода уже глазами браузера на котором отображены несколько
графических фигур с некой стилистикой.
Так же плюс в том что воспроизвести сложную фигуру которую
нам радостно и с легкостью нарисует нам дизайнер к примеру в Adobe Illustrator на
труда не составит, а более каждой составляющей части нашего векторного рисунка
мы сможем придать функционал и анимацию.
К тому же одним из немаловажных плюсов будет достаточно хорошая документация.
Ну и прежде чем пойти дальше хочется повторить слова разработчика
и идеолога Raphael.js Дмитрия
Барановского: «Raphael for SVG is like JQuery for DOM»
Действительно Raphael как и Великий Рафаэль Санти нам помогает оживить рисунок,
придать ему движения и практическую функциональность.
Practice
Пример 1
И так начнем с простого, нарисуем круг. Для удобства решили выложить примеры на jsfiddle.
Как мы видим для подключения Raphael достаточно только подключить его библиотеку которую можно взять с официального сайта. Наш документ содержит лишь один элемент это div#draw собственно в него мы и будем инициализировать наш SVG с помощью Raphael.
Первым делом нужно инициализровать холст делает это таким образом:
var paper = Raphael('draw', 400, 250);
Соответственно передавая в объект Rapael paper Dom-элемент с id draw и размеры холста.
Далее мы создаем объект нашего круга и помещаем на холст paper, задав ему параметры (позиция x, позиция y, радиус)
var circle = paper.circle(50, 50, 40);
Далее мы задаем стилистику нашего круга это делается передачей параметров свойству attr
circle.attr({ fill: 'yellow', stroke: 'gray', 'stroke-width': '3', 'stroke-dasharray': '.', cursor: 'pointer', });
Тут мы соответственно задали заливку пунктирную обводку ну и курсор. Подробнее об допустимых атрибутах можно легко узнать из документации
А теперь попробуем задать событие на клик, предварительно определив нашей ноде id
circle.node.id = "circle"; $('#circle').on('click', function(){ alert('I\'m a circle'); });
Я предпочел JQuery-way и уже навешал событие просто обратившись к объекту по id
Пример 2
В этом примере приведены базовые фигуры отрисованные с помощью Raphael:
rect = paper.rect(40, 40, 100, 50), // прямоугольник line = paper.path('M0 0L150 100'), // линия text = paper.text(100, 150, 'I\'m just a text'), // текст path = paper.path('M 0 200 L 200 200 L 100 300 z'), // путь image = paper.image('img/css.gif', 250, 0, 250, 200); // изображение
Но особое внимание хотелось бы уделить объекту path в котором собственно и таится вся прелесть векторной графики.
path = paper.path('M 0 200 L 200 200 L 100 300 z')
Этот path изображает треугольник, не сложно догадаться каким что рисуется он заданием координат конечных точек линий ну и в свою очередь z завершает рисунок соединяя последнюю точку с начальной. Подробнее о построении pathов можно узнать тут
Есть так же у Raphael некий аналог определения очередности объектов
rect.toBack(); // переместит rect на задний план rect.toBack(); // переместит rect на передний план
Ну наверно мое самое любимое, это метод animate, в данном случае мы анимируем атрибут transform, задавая новую трансформацию, соответственно t - translate(перемещение в определенную координату) s - scale(увеличение на пропорцию) r - radius(поворот на какой-то угол). Анимация длится 800ms с эфектом 'bounce', да в наше время имея возможность применять анимации без easing'ов просто грешно.
image.click(function(){ this.animate({'transform': 't40 40s1.2r5'}, 800, 'bounce'); });
Пример 3
Это не сложный пример создания множества фигур с рандомной трансформацией
var paper = Raphael('draw', $('#content').width(), 600), filler = { fill: 'red', stroke: 'gray', 'sctroke-width': 2 }, circles = [], size, angle; for (var i = 0; i < 50; i++) { size = Math.random() * 100 + 30; filler.fill = "rgb(" + Math.random() * 255 + "," + Math.random() * 255 + "," + Math.random() * 255 +")"; circles.push( paper.rect( Math.random() * paper.width, Math.random() * paper.height, size, size, Math.random() * 50 ) .attr(filler) .transform("r" + Math.random() * 90) ); };
Пример 4
Пример анимации, если кликнуть в примере на спираль она начнет крутится убеждая Вас в том что лучше Raphael.js в мире быть ничего не может)
Вы можете создавать анимацию в Raphael двумя способами либо передавая параметры непосредственно обработчику Element.animate либо создав объект Raphael.animation и уже в дальнейшем передавать его серии либо одному элементу
animInf = Raphael.animation({transform: 't200 200s10r-720'}, 4000, "easeInOut").repeat(Infinity);
В данном случае из новшеств только свойство repeat которое определяет число циклоп анимации в данном случая это удовольствие будет длится вечность)
Пример 5
И так Drug'n'Drop, реализация Raphael стандартна и слажено работающая.
Но для начала хочется рассказать про Paper.set() с его помощью мы получаем возможность объединять элементы Raphael в группы и с комфортом оперировать ими.
var paper = Raphael('draw', $('#content').width(), 600), catSet = paper.set(); catSet .push(paper.path("m69.598007,392.080017c1.085999,-14.994995 4.411011,-9.707031 6.544983,-17.026001c15.416016,-52.88501 -25.237,-100.822021 -4.346985,-151.776001c-9.787003,0.555969 -24.16301,-23.432983 -23.068008,-43.833008c1.096985,-20.446991 13.373993,-40.070984 24.039993,-65.162994c-45.321999,-109.63501 -22.305008,-67.993988 41.938019,-42.265991c67.174988,-45.722015 80.600952,-6.480011 92.202972,-14.40802c57.314987,-38.154999 43.955994,-57.608002 52.587997,31.328003c95.209015,77.821991 168.78302,157.10202 111.286011,273.677032c62.024017,5.997986 74.03595,-82.088013 56.391968,-155.812012c-12.394958,-35.309021 22.537018,-50.17099 25.552032,61.151001c-11.772003,90.749023 -35.586975,129.896973 -95.696014,136.859985c4.471008,3.617004 -84.898987,25.504028 -141.927994,12.819031c-4.311981,-0.959045 -12.492981,-10.453003 6.860016,-20.520996c7.192993,-3.742004 -15.424011,-11.28302 -25.899994,-9.485046c-12.377014,2.125 -13.226013,30.888 -14.891022,31.532043c-10.858978,4.203003 -18.873993,4.947998 -37.723999,0.502991c-3.635986,-0.856995 -3.754974,-11.048035 3.817017,-18.825012c6.520996,-6.697998 -11.511017,-19.202026 -14.688995,-22.528992c-6.355988,-6.653992 -17.797974,-10.775024 -21.122986,-8.841003c-8.925995,5.190002 7.856995,35.039978 -41.28598,23.325012").attr({stroke: '#000000','stroke-width': '0','stroke-opacity': '1','fill': '#000000'})) .push(paper.path("m171.171982,120.373047c14.716003,-1.785004 16.588989,-10.28299 -1.192993,-6.34201c-15.330017,-2.709991 -15.615021,7.016998 1.192993,6.34201z").attr({fill: '#FFFFFF','stroke-width': '0','stroke-opacity': '1'})) .push(paper.path("m159.049973,119.146027c3.35199,7.553986 16.674011,8.468994 21.717987,2.526001").attr({stroke: '#333333',fill: 'none','stroke-width': '0','stroke-opacity': '1'})) .push(paper.path("m158.039963,112.075043c1.528992,-12.05899 24.884003,-11.454987 26.264008,0").attr({stroke: '#333333',fill: 'none','stroke-width': '0','stroke-opacity': '1'})) .push(paper.path("m169.191971,116.620026c0,2.789001 -0.904999,5.050995 -2.019989,5.050995c-1.115997,0 -2.02002,-2.260986 -2.02002,-5.050995l0,0c0,-2.789001 0.904999,-5.050995 2.02002,-5.050995c1.11499,0.001007 2.019989,2.261993 2.019989,5.050995z").attr({id: '',parent: '','stroke-width': '0','stroke-opacity': '1','fill': '#000000'})) .push(paper.path("m91.099991,117.68103c-11.677002,-1.415985 -13.162994,-8.158997 0.946014,-5.031982c12.164001,-2.151001 12.389984,5.567993 -0.946014,5.031982z").attr({fill: '#FFFFFF','stroke-width': '0','stroke-opacity': '1'})) .push(paper.path("m100.718002,116.707031c-2.660004,5.993988 -13.230988,6.720001 -17.233002,2.003998").attr({"stroke-width": '0.79',stroke: '#333333',fill: 'none','stroke-opacity': '1'})) .push(paper.path("m101.520004,111.097046c-1.213989,-9.567993 -19.744995,-9.088989 -20.839996,0").attr({"stroke-width": '0.79',stroke: '#333333',fill: 'none','stroke-opacity': '1'})) .push(paper.path("m92.671005,114.704041c0,2.213013 0.717987,4.007996 1.602997,4.007996s1.602997,-1.794006 1.602997,-4.007996l0,0c0,-2.212982 -0.717987,-4.007996 -1.602997,-4.007996c-0.885986,0 -1.602997,1.793976 -1.602997,4.007996z").attr({id: '',parent: '','stroke-width': '0','stroke-opacity': '1','fill': '#000000'})) .push(paper.path("m98.966019,171.694031c1.238007,37.747009 67.011963,47.419983 81.185974,0.625").attr({"stroke-width": '2',stroke: '#808080',fill: 'none','stroke-opacity': '1'})) .push(paper.path("m98.272995,171.536011c-11.743011,24.702026 -31.454987,34.617004 -39.062027,0.634033").attr({"stroke-width": '2',stroke: '#808080',fill: 'none','stroke-opacity': '1'})) .push(paper.path("m89.899002,140.739044c9.838989,-2.843994 21.002991,-3.125 30.276001,1.703003c3.287994,1.885986 6.541992,4.540985 7.855957,8.191986c1.073029,4.391998 -2.536957,9.096008 -7.085968,8.988007c-3.379974,0.096008 -6.379974,-2.190002 -7.789001,-5.154999c-2.050995,-2.04599 -6.502991,-0.130005 -4.454987,2.903992c0.949005,3.451019 5.191986,4.804016 6.024994,7.959015c0.466003,4.373993 -3.856995,7.378021 -7.77298,7.839996c-5.090027,0.906006 -11.040009,-0.093994 -14.651001,-4.04303c-3.112,-4.016968 -1.653015,-9.317963 -1.896027,-13.984985c0.443024,-2.53598 -1.375,-6.013977 -4.133972,-3.740997c-1.275024,1.396027 -3.743011,2.932007 -3.677002,-0.300995c2.052979,-5.338989 3.078979,-6.623993 7.303986,-10.360992l0,0z").attr({stroke: '#000000',fill: '#999999','stroke-width': '0','stroke-opacity': '1'})) .push(paper.path("m73.692001,156.521027c-21.166016,-7.858002 -47.851997,-8.958008 -65.660015,7.070984").attr({stroke: '#808080',fill: 'none','stroke-width': '1','stroke-opacity': '1'})) .push(paper.path("m139.351974,164.603027c27.06601,-11.019012 55.700989,9.437988 68.690002,32.325012").attr({stroke: '#808080',fill: 'none','stroke-width': '1','stroke-opacity': '1'})) .push(paper.path("m73.692001,174.704041c-23.068008,-3.552979 -44.232002,13.190002 -51.517998,34.345032").attr({stroke: '#808080',fill: 'none','stroke-width': '1','stroke-opacity': '1'})) .push(paper.path("m130.259964,178.745056c19.740997,9.684998 31.493988,32.900024 28.283997,54.547974").attr({stroke: '#808080',fill: 'none','stroke-width': '1','stroke-opacity': '1'})) .push(paper.path("m59.460999,165.68103c-20.835999,-0.317993 -43.075996,2.538025 -59.460993,12.994995").attr({"stroke-width": '1.14',stroke: '#808080',fill: 'none','stroke-opacity': '1'})) .push(paper.path("m153.884964,179.896057c18.493988,9.327026 27.196014,31.562988 39.623993,48.205017").attr({"stroke-width": '1.15',stroke: '#808080',fill: 'none','stroke-opacity': '1'})) .draggable();
Таки да это наш WonderCat и path'ы из которых он состоит объедены в одно целое, и в итоге наречен рукописным методом draggable(). Рассмотрим его по подробнее.
Raphael.st.draggable = function() { var me = this, lx = 0, ly = 0, ox = 0, oy = 0, moveFnc = function(dx, dy) { lx = dx + ox; ly = dy + oy; me.transform('t' + lx + ',' + ly); }, startFnc = function() {}, endFnc = function() { ox = lx; oy = ly; }; me .attr('cursor', 'move') .drag(moveFnc, startFnc, endFnc); };
Свойство Raphael.st дает возможность нам создавать собственный методы и присваивать их set'ам. В данном случае было создано три функции которые в дальнейшем были использованы как callback'и метода Raphael Element.drag(). Element.drag() - в итоге получает три события соответственно на move, start и end процесса перетаскивания.
Пример 6
Ну и финальный пример это морфинг - трансформация одного path'а в другой.
var path = { fly: 'M75.749,25.338c-0.915,6.4.....677,152.489,119.883,154.234,115.147,156.411z', elephant: 'M178.205,3.24c1.68,01....857C173.437,4.804,175.877,4.13,178.205,3.24z', palm: 'M91.398,181.119c-0.587-2....90.769,181.372,91.083,181.245,91.398,181.119z', palmWinded: 'M92.292,180.733c-02...2C91.649,180.993,91.97,180.863,92.292,180.733z' }; Raphael.el.morfing = false; // Morhing detector with Raphael.el $(function(){ var paper = Raphael('draw'), animal = paper.path(path.fly), palm = paper.path(path.palm); // Animals morphing animal .attr({ 'stroke': 'gray', 'stroke-width': 3, cursor: 'pointer', }) .click(function(){ this.morfing = !this.morfing; this.animate({path: (this.morfing ? path.elephant : path.fly)}, 1000, 'easeInOut'); }); // Palm morphing var animPalm = Raphael.animation( { '50%': {path: path.palmWinded}, '100%': {path: path.palm} }, 4000, "easeInOut") .repeat(5); palm .attr({ fill: '#21251B', stroke: '#997402', transform: 't400 50s1.5', cursor: 'pointer' }) .click(function() { this.animate(animPalm); }); });
В нашем примере было создано две пары path'ов и по click событию происходит магическая трансформация из мухи в слона в первом случае и эмуляция ветра во втором случае.
Пример 7 (SVG карта областей Украины)
Олег Рудой радостно предоставил пример реализации карты Украины, которая была скачена в формате SVG с сайта Wikipedia (http://uk.wikipedia.org/wiki/%D0%A4%D0%B0%D0%B9%D0%BB:Map_of_Ukraine_Oblasts_DEMO.svg)
После не сложных манипуляций карта приобрела функциональность, теперь подведя на каждую из областей курсор мыши мы получаем симпатичный popup при этом область выделяется другим цветом.
клас! дякую, дуже цікава доповідь
ОтветитьУдалитьВсегда пожалуйста, будет еще!)
Удалить