Страницы

Поиск по вопросам

суббота, 28 декабря 2019 г.

Как библиотека анимирует каплю svg?

#javascript #css #html5 #svg #svg_animation


Как библиотека анимирует каплю как на рисунке, если где пример?
На рисунке ниже зелёное  пятно, которое изменяет свои контуры.





Это состояния капли на картинках  состояние 1
 состояние 2
    


Ответы

Ответ 1



Как библиотека анимирует каплю вот так,если где пример? Есть скрипт, изменяя параметры которого можно получить интересные эффекты плавного перетекания из одной формы в другую. // инициировать canvas const canvas = document.querySelector("canvas"); const ctx = canvas.getContext("2d"); let cw = (canvas.width = 600), cx = cw / 2; let ch = (canvas.height = 400), cy = ch / 2; ctx.fillStyle = "white" // определить углы прямоугольника let corners = [[100, 100], [500, 100], [500, 300], [100, 300]]; let amplitud = 20;// амплитуда колебаний let speed = 0.01;// скорость колебаний let points = []; // массив точек для рисования кривой class Point { constructor(x, y, hv) { // точка колеблется вокруг этой точки (cx, cy) this.cx = x; this.cy = y; // текущий угол колебаний this.a = Math.random() * 2 * Math.PI; this.hv = hv;// переменная, чтобы знать, является ли колебание горизонтальным или вертикальным this.update(); } // функция для обновления значения угла update() { this.a += speed; if (this.hv == 0) { this.x = this.cx; this.y = this.cy + amplitud * Math.cos(this.a); } else { this.x = this.cx + amplitud * Math.cos(this.a); this.y = this.cy; } } } // функция, чтобы разделить линию, которая идет от a до b в n сегментах // Я использую полученные точки, чтобы создать новый точечный объект и вставить эту новую точку в массив точек function divide(n, a, b) { for (var i = 0; i <= n; i++) { let p = { x: (b[0] - a[0]) * i / n + a[0], y: (b[1] - a[1]) * i / n + a[1], hv: b[1] - a[1] }; points.push(new Point(p.x, p.y, p.hv)); } } divide(10, corners[0], corners[1]);points.pop(); divide(5, corners[1], corners[2]);points.pop(); divide(10, corners[2], corners[3]);points.pop(); divide(5, corners[3], corners[0]);points.pop(); // это функция, которая берет массив точек и рисует изогнутую линию через эти точки function drawCurves() { //найти первую середину и перейти к ней let p = {}; p.x = (points[points.length - 1].x + points[0].x) / 2; p.y = (points[points.length - 1].y + points[0].y) / 2; ctx.beginPath(); ctx.moveTo(p.x, p.y); //кривой через остальное, останавливаясь в каждой средней точке for (var i = 0; i < points.length - 1; i++) { let mp = {}; mp.x = (points[i].x + points[i + 1].x) / 2; mp.y = (points[i].y + points[i + 1].y) / 2; ctx.quadraticCurveTo(points[i].x, points[i].y, mp.x, mp.y); } //кривая через последнюю точку, обратно к первой средней точке ctx.quadraticCurveTo( points[points.length - 1].x, points[points.length - 1].y, p.x, p.y ); ctx.stroke(); ctx.fill(); } function Draw() { window.requestAnimationFrame(Draw); ctx.clearRect(0, 0, cw, ch); points.map(p => { p.update(); }); drawCurves(); } Draw(); canvas{border:1px solid; background:skyblue} Меняем координаты узловых точек. Помните, что у Y положительное направление вниз. определяем углы прямоугольника let corners = [[100, 100], [400, 100], [400, 150], [100, 200]]; // инициировать canvas const canvas = document.querySelector("canvas"); const ctx = canvas.getContext("2d"); let cw = (canvas.width = 600), cx = cw / 2; let ch = (canvas.height = 400), cy = ch / 2; ctx.fillStyle = "white" // определить углы прямоугольника let corners = [[100, 100], [400, 100], [400, 150], [100, 200]]; let amplitud = 20;// амплитуда колебаний let speed = 0.01;// скорость колебаний let points = []; // массив точек для рисования кривой class Point { constructor(x, y, hv) { // точка колеблется вокруг этой точки (cx, cy) this.cx = x; this.cy = y; // текущий угол колебаний this.a = Math.random() * 2 * Math.PI; this.hv = hv;// переменная, чтобы знать, является ли колебание горизонтальным или вертикальным this.update(); } // функция для обновления значения угла update() { this.a += speed; if (this.hv == 0) { this.x = this.cx; this.y = this.cy + amplitud * Math.cos(this.a); } else { this.x = this.cx + amplitud * Math.cos(this.a); this.y = this.cy; } } } // функция, чтобы разделить линию, которая идет от a до b в n сегментах // Я использую полученные точки, чтобы создать новый точечный объект и вставить эту новую точку в массив точек function divide(n, a, b) { for (var i = 0; i <= n; i++) { let p = { x: (b[0] - a[0]) * i / n + a[0], y: (b[1] - a[1]) * i / n + a[1], hv: b[1] - a[1] }; points.push(new Point(p.x, p.y, p.hv)); } } divide(10, corners[0], corners[1]);points.pop(); divide(5, corners[1], corners[2]);points.pop(); divide(10, corners[2], corners[3]);points.pop(); divide(5, corners[3], corners[0]);points.pop(); // это функция, которая берет массив точек и рисует изогнутую линию через эти точки function drawCurves() { //найти первую середину и перейти к ней let p = {}; p.x = (points[points.length - 1].x + points[0].x) / 2; p.y = (points[points.length - 1].y + points[0].y) / 2; ctx.beginPath(); ctx.moveTo(p.x, p.y); //кривой через остальное, останавливаясь в каждой средней точке for (var i = 0; i < points.length - 1; i++) { let mp = {}; mp.x = (points[i].x + points[i + 1].x) / 2; mp.y = (points[i].y + points[i + 1].y) / 2; ctx.quadraticCurveTo(points[i].x, points[i].y, mp.x, mp.y); } //кривая через последнюю точку, обратно к первой средней точке ctx.quadraticCurveTo( points[points.length - 1].x, points[points.length - 1].y, p.x, p.y ); ctx.stroke(); ctx.fill(); } function Draw() { window.requestAnimationFrame(Draw); ctx.clearRect(0, 0, cw, ch); points.map(p => { p.update(); }); drawCurves(); } Draw(); canvas{border:1px solid; background:#6ab150} Увеличиваем скорость колебаний let speed = 0.05; // инициировать canvas const canvas = document.querySelector("canvas"); const ctx = canvas.getContext("2d"); let cw = (canvas.width = 600), cx = cw / 2; let ch = (canvas.height = 400), cy = ch / 2; ctx.fillStyle = "white" // определить углы прямоугольника let corners = [[100, 100], [400, 100], [400, 150], [100, 200]]; let amplitud = 20;// амплитуда колебаний let speed = 0.05;// скорость колебаний let points = []; // массив точек для рисования кривой class Point { constructor(x, y, hv) { // точка колеблется вокруг этой точки (cx, cy) this.cx = x; this.cy = y; // текущий угол колебаний this.a = Math.random() * 2 * Math.PI; this.hv = hv;// переменная, чтобы знать, является ли колебание горизонтальным или вертикальным this.update(); } // функция для обновления значения угла update() { this.a += speed; if (this.hv == 0) { this.x = this.cx; this.y = this.cy + amplitud * Math.cos(this.a); } else { this.x = this.cx + amplitud * Math.cos(this.a); this.y = this.cy; } } } // функция, чтобы разделить линию, которая идет от a до b в n сегментах // Я использую полученные точки, чтобы создать новый точечный объект и вставить эту новую точку в массив точек function divide(n, a, b) { for (var i = 0; i <= n; i++) { let p = { x: (b[0] - a[0]) * i / n + a[0], y: (b[1] - a[1]) * i / n + a[1], hv: b[1] - a[1] }; points.push(new Point(p.x, p.y, p.hv)); } } divide(10, corners[0], corners[1]);points.pop(); divide(5, corners[1], corners[2]);points.pop(); divide(10, corners[2], corners[3]);points.pop(); divide(5, corners[3], corners[0]);points.pop(); // это функция, которая берет массив точек и рисует изогнутую линию через эти точки function drawCurves() { //найти первую середину и перейти к ней let p = {}; p.x = (points[points.length - 1].x + points[0].x) / 2; p.y = (points[points.length - 1].y + points[0].y) / 2; ctx.beginPath(); ctx.moveTo(p.x, p.y); //кривой через остальное, останавливаясь в каждой средней точке for (var i = 0; i < points.length - 1; i++) { let mp = {}; mp.x = (points[i].x + points[i + 1].x) / 2; mp.y = (points[i].y + points[i + 1].y) / 2; ctx.quadraticCurveTo(points[i].x, points[i].y, mp.x, mp.y); } //кривая через последнюю точку, обратно к первой средней точке ctx.quadraticCurveTo( points[points.length - 1].x, points[points.length - 1].y, p.x, p.y ); ctx.stroke(); ctx.fill(); } function Draw() { window.requestAnimationFrame(Draw); ctx.clearRect(0, 0, cw, ch); points.map(p => { p.update(); }); drawCurves(); } Draw(); canvas{border:1px solid; background:#6ab150} Амплитуду колебаний let amplitud = 50; // инициировать canvas const canvas = document.querySelector("canvas"); const ctx = canvas.getContext("2d"); let cw = (canvas.width = 600), cx = cw / 2; let ch = (canvas.height = 400), cy = ch / 2; ctx.fillStyle = "white" // определить углы прямоугольника let corners = [[100, 100], [400, 100], [400, 150], [100, 200]]; let amplitud = 50;// амплитуда колебаний let speed = 0.05;// скорость колебаний let points = []; // массив точек для рисования кривой class Point { constructor(x, y, hv) { // точка колеблется вокруг этой точки (cx, cy) this.cx = x; this.cy = y; // текущий угол колебаний this.a = Math.random() * 2 * Math.PI; this.hv = hv;// переменная, чтобы знать, является ли колебание горизонтальным или вертикальным this.update(); } // функция для обновления значения угла update() { this.a += speed; if (this.hv == 0) { this.x = this.cx; this.y = this.cy + amplitud * Math.cos(this.a); } else { this.x = this.cx + amplitud * Math.cos(this.a); this.y = this.cy; } } } // функция, чтобы разделить линию, которая идет от a до b в n сегментах // Я использую полученные точки, чтобы создать новый точечный объект и вставить эту новую точку в массив точек function divide(n, a, b) { for (var i = 0; i <= n; i++) { let p = { x: (b[0] - a[0]) * i / n + a[0], y: (b[1] - a[1]) * i / n + a[1], hv: b[1] - a[1] }; points.push(new Point(p.x, p.y, p.hv)); } } divide(10, corners[0], corners[1]);points.pop(); divide(5, corners[1], corners[2]);points.pop(); divide(10, corners[2], corners[3]);points.pop(); divide(5, corners[3], corners[0]);points.pop(); // это функция, которая берет массив точек и рисует изогнутую линию через эти точки function drawCurves() { //найти первую середину и перейти к ней let p = {}; p.x = (points[points.length - 1].x + points[0].x) / 2; p.y = (points[points.length - 1].y + points[0].y) / 2; ctx.beginPath(); ctx.moveTo(p.x, p.y); //кривой через остальное, останавливаясь в каждой средней точке for (var i = 0; i < points.length - 1; i++) { let mp = {}; mp.x = (points[i].x + points[i + 1].x) / 2; mp.y = (points[i].y + points[i + 1].y) / 2; ctx.quadraticCurveTo(points[i].x, points[i].y, mp.x, mp.y); } //кривая через последнюю точку, обратно к первой средней точке ctx.quadraticCurveTo( points[points.length - 1].x, points[points.length - 1].y, p.x, p.y ); ctx.stroke(); ctx.fill(); } function Draw() { window.requestAnimationFrame(Draw); ctx.clearRect(0, 0, cw, ch); points.map(p => { p.update(); }); drawCurves(); } Draw(); canvas{border:1px solid; background:#6ab150} Источник скрипта

Ответ 2



у Вас в codepen.io уже есть готовый код svg Каким образом это работает ? Я приведу пример из бесплатного векторного редактора Inkscape Весь фокус там в анимации path -т.е замкнутой области Для этого нарисуем обычный circle(смотрим скрины) дальше оконтурим объект выбираем редактировать узлы контуров и рычагов и меняем нашу фигуру как угодно не забываем о Редакторе XML который расположен в Пункте Правка и от туда берём наш path и сохраняем это в value="" но помним что любой path начинается с m и заканчивается на z, через точку с запятой вот так : values="m 171.60117,149.2113 c 0,41.12384 -28.18164,25.3244 -63.87797,25.32441 -35.696332,0 -64.334444,15.78589 -65.389879,-25.32441 -0.914858,-35.63468 24.326526,-46.79487 64.633929,-74.4613 29.43057,-20.200726 64.63392,33.33746 64.63392,74.4613 z; m 171.60117,149.2113 c 0,41.12384 -53.18832,-8.73377 -63.87797,25.32441 C 82.42654,255.13317 43.388756,190.3216 42.333321,149.2113 41.418463,113.57662 66.659847,102.41643 106.96725,74.75 c 29.43057,-20.200726 64.63392,33.33746 64.63392,74.4613 z; m 171.60117,149.2113 c 0,41.12384 -53.18832,-8.73377 -63.87797,25.32441 C 82.42654,255.13317 52.091032,189.16074 42.333321,149.2113 30.245529,99.72218 -12.711983,3.9953599 106.96725,74.75 c 30.72797,18.166446 64.63392,33.33746 64.63392,74.4613 z; m 171.60117,149.2113 c -0.0101,41.12384 -32.55393,42.4426 -63.87797,25.32441 C 40.200847,137.63559 51.571238,187.71436 42.333321,149.2113 30.447804,99.673212 -25.669232,116.42615 106.96725,74.75 c 135.40433,-42.545846 64.644,33.33161 64.63392,74.4613 z; m 171.60117,149.2113 c -0.0101,41.12384 -32.55393,42.4426 -63.87797,25.32441 C 40.200847,137.63559 51.571238,187.71436 42.333321,149.2113 30.447804,99.673212 163.75162,-22.482479 106.96725,74.75 c -71.576575,122.56132 64.644,33.33161 64.63392,74.4613 z; m 171.60117,149.2113 c -7.44959,40.44347 -35.89119,3.1666 -63.87797,25.32441 C 13.926348,248.79693 51.552055,187.79551 42.333321,149.2113 30.494747,99.661972 -5.6305653,75.343332 106.96725,74.75 c 74.96041,-0.395002 73.59304,25.82265 64.63392,74.4613 z Дальше по шагам 1) Заголовок и прочее берём с редактора Пишем smill svg в итоге получаем анимацию: Сама фишка в том что количество path в animate не имеет значение Что бы анимация была плавная надо увеличить время и после самого последнего пути добавить самый первый путь вот так : https://codepen.io/topicstarter/pen/mvwwZG

Ответ 3



Есть такая замечательная библиотека flubber. Она как раз решает проблему интерполяции между различными svg path, легка в использовании в паре с d3.js необходимо лишь задать начальное и конечное значение пути. var pathStrings = [...document.querySelectorAll("path")].map(d => d.getAttribute("d")); d3.selectAll("path").filter((d, i) => i).remove(); d3.select("path").style("display", "block").call(animate); function animate(sel) { var start = pathStrings.shift(); var end = pathStrings[0]; pathStrings.push(start); sel.datum({start, end}).transition().duration(1500) .attrTween("d", d => flubber.interpolate(d.start, d.end, {maxSegmentLength: 0.1})) .on("end", e => sel.call(animate)); } path { fill: #aa00ff; display: none; }

Комментариев нет:

Отправить комментарий