Реалізація морфінгу SVG-фігур на сайті

Наша компанія займається розробкою, підтримкою та обслуговуванням сайтів будь-якої складності. Від простих односторінкових сайтів до масштабних кластерних систем, побудованих на мікро сервісах. Досвід розробників підтверджено сертифікатами від вендорів.

Розробка та обслуговування будь-яких видів сайтів:

Інформаційні сайти або веб-програми
Сайти візитки, landing page, корпоративні сайти, онлайн каталоги, квіз, промо-сайти, блоги, ресурси новин, інформаційні портали, форуми, агрегатори
Сайти або веб-програми електронної комерції
Інтернет-магазини, B2B-портали, маркетплейси, онлайн-обмінники, кешбек-сайти, біржі, дропшиппінг-платформи, парсери товарів
Веб-програми для управління бізнес-процесами
CRM-системи, ERP-системи, корпоративні портали, системи управління виробництвом, парсери інформації
Сайти або веб-програми електронних послуг
Дошки оголошень, онлайн-школи, онлайн-кінотеатри, конструктори сайтів, портали надання електронних послуг, відеохостинги, тематичні портали

Це лише деякі з технічних типів сайтів, з якими ми працюємо, і кожен із них може мати свої специфічні особливості та функціональність, а також бути адаптованим під конкретні потреби та цілі клієнта.

Пропоновані послуги
Показано 1 з 1 послугУсі 2065 послуг
Реалізація морфінгу SVG-фігур на сайті
Складна
~2-3 робочих дні
Часті питання

Наші компетенції:

Етапи розробки

Останні роботи

  • image_website-b2b-advance_0.png
    Розробка сайту компанії B2B ADVANCE
    1262
  • image_web-applications_feedme_466_0.webp
    Розробка веб-додатків для компанії FEEDME
    1171
  • image_websites_belfingroup_462_0.webp
    Розробка веб-сайту для компанії БЕЛФІНГРУП
    874
  • image_ecommerce_furnoro_435_0.webp
    Розробка інтернет магазину для компанії FURNORO
    1094
  • image_crm_enviok_479_0.webp
    Розробка веб-додатків для компанії Enviok
    831
  • image_bitrix-bitrix-24-1c_fixper_448_0.png
    Розробка веб-сайту для компанії ФІКСПЕР
    851

Реалізація морфінгу SVG-фігур на сайті

SVG-морфінг — анімація трансформації однієї векторної фігури в іншу. Технічно це анімація атрибута d (path data) — числових координат точок. Обмеження: початкова та кінцева фігури повинні мати однакову кількість точок та команд у path. Саме тому нативний SMIL та CSS погано підходять для довільного морфінгу — потрібні спеціалізовані бібліотеки, які інтерполюють точки.

Інструменти

  • GSAP MorphSVGPlugin — платний, частина Club GreenSock. Найпотужніший, сам вирівнює кількість точок
  • Flubber.js — MIT, хорошо для простих фігур
  • SVG.js + @svgdotjs/svg.filter.js — через вбудований морфінг
  • CSS/SMIL з однаковою кількістю точок — для простих випадків без бібліотек

GSAP MorphSVGPlugin (найбільш надійний підхід)

// lib/gsap-morph.ts
import { gsap } from 'gsap'
import { MorphSVGPlugin } from 'gsap/MorphSVGPlugin'

gsap.registerPlugin(MorphSVGPlugin)
export { gsap }
// components/MorphingIcon.tsx
import { useEffect, useRef, useState } from 'react'
import { gsap } from '../lib/gsap-morph'

const shapes = {
  circle: 'M 50,10 A 40,40 0 1,1 49.9,10',
  star: 'M50,5 L61,35 L95,35 L68,57 L79,91 L50,70 L21,91 L32,57 L5,35 L39,35 Z',
  heart: 'M50,85 C10,60 5,30 25,15 C35,7 45,10 50,18 C55,10 65,7 75,15 C95,30 90,60 50,85 Z',
  arrow: 'M 10,50 L 40,20 L 40,35 L 90,35 L 90,65 L 40,65 L 40,80 Z',
}

type ShapeKey = keyof typeof shapes

export function MorphingIcon() {
  const pathRef = useRef<SVGPathElement>(null)
  const [current, setCurrent] = useState<ShapeKey>('circle')

  const morphTo = (target: ShapeKey) => {
    if (!pathRef.current || target === current) return

    gsap.to(pathRef.current, {
      morphSVG: {
        shape: shapes[target],
        // Точка привязки для вирівнювання (0–1, обертання в градусах)
        origin: '50% 50%',
        // Тип вирівнювання: позиція або степінь відповідності
        type: 'rotational',
      },
      duration: 0.8,
      ease: 'power2.inOut',
    })

    setCurrent(target)
  }

  return (
    <div>
      <svg viewBox="0 0 100 100" className="w-32 h-32">
        <path
          ref={pathRef}
          d={shapes.circle}
          fill="none"
          stroke="#3b82f6"
          strokeWidth="2"
        />
      </svg>

      <div className="flex gap-2 mt-4">
        {(Object.keys(shapes) as ShapeKey[]).map(key => (
          <button
            key={key}
            onClick={() => morphTo(key)}
            className={`px-3 py-1 text-sm rounded ${
              current === key ? 'bg-blue-500 text-white' : 'bg-gray-100'
            }`}
          >
            {key}
          </button>
        ))}
      </div>
    </div>
  )
}

Flubber.js: безплатна альтернатива

npm install flubber
// components/FlubberMorph.tsx
import { useEffect, useRef, useState } from 'react'
import { interpolate, fromCircle, toCircle } from 'flubber'

// Flubber повертає функцію-інтерполятор: t(0) = початок, t(1) = кінець
export function FlubberMorph() {
  const pathRef = useRef<SVGPathElement>(null)
  const animFrameRef = useRef<number | null>(null)

  const morphBetween = (
    startPath: string,
    endPath: string,
    durationMs = 800
  ) => {
    const interpolator = interpolate(startPath, endPath, { maxSegmentLength: 2 })
    const start = performance.now()

    const animate = (now: number) => {
      const elapsed = now - start
      const t = Math.min(elapsed / durationMs, 1)
      const ease = t < 0.5 ? 2 * t * t : -1 + (4 - 2 * t) * t // easeInOut

      if (pathRef.current) {
        pathRef.current.setAttribute('d', interpolator(ease))
      }

      if (t < 1) {
        animFrameRef.current = requestAnimationFrame(animate)
      }
    }

    if (animFrameRef.current) cancelAnimationFrame(animFrameRef.current)
    animFrameRef.current = requestAnimationFrame(animate)
  }

  const squarePath =
    'M 20,20 L 80,20 L 80,80 L 20,80 Z'
  const blobPath =
    'M 50,10 C 80,10 90,30 90,50 C 90,70 70,90 50,90 C 30,90 10,70 10,50 C 10,30 20,10 50,10 Z'

  const [isBlob, setIsBlob] = useState(false)

  useEffect(() => {
    if (pathRef.current) {
      pathRef.current.setAttribute('d', squarePath)
    }
  }, [])

  const toggle = () => {
    morphBetween(
      isBlob ? blobPath : squarePath,
      isBlob ? squarePath : blobPath
    )
    setIsBlob(!isBlob)
  }

  return (
    <div>
      <svg viewBox="0 0 100 100" className="w-48 h-48">
        <path ref={pathRef} fill="#8b5cf6" />
      </svg>
      <button onClick={toggle} className="mt-4 px-4 py-2 bg-purple-500 text-white rounded">
        Морфінг
      </button>
    </div>
  )
}

SMIL-морфінг без бібліотек (однакові контури)

Коли обидві фігури мають однакову кількість точок — SMIL працює без додаткових інструментів:

// Квадрат → ромб → квадрат (4 точки, одна команда L)
export function SMILMorph() {
  return (
    <svg viewBox="0 0 100 100" className="w-32 h-32">
      <path fill="#f59e0b">
        <animate
          attributeName="d"
          dur="1.5s"
          repeatCount="indefinite"
          values="
            M 20,20 L 80,20 L 80,80 L 20,80 Z;
            M 50,10 L 90,50 L 50,90 L 10,50 Z;
            M 20,20 L 80,20 L 80,80 L 20,80 Z
          "
          keyTimes="0; 0.5; 1"
          calcMode="spline"
          keySplines="0.4 0 0.2 1; 0.4 0 0.2 1"
        />
      </path>
    </svg>
  )
}

Морфінг з кількома цільовими фігурами (GSAP timeline)

// components/MorphSequence.tsx
import { useEffect, useRef } from 'react'
import { gsap } from '../lib/gsap-morph'

const sequence = [
  'M 50,10 A 40,40 0 1,1 49.9,10',               // коло
  'M50,5 L61,35 L95,35 L68,57 L79,91 L50,70 Z',  // зірка
  'M10,50 L50,10 L90,50 L50,90 Z',               // ромб
]

export function MorphSequence() {
  const pathRef = useRef<SVGPathElement>(null)

  useEffect(() => {
    const tl = gsap.timeline({ repeat: -1, yoyo: false })

    sequence.forEach((shape, i) => {
      const next = sequence[(i + 1) % sequence.length]
      tl.to(pathRef.current, {
        morphSVG: next,
        duration: 1.2,
        ease: 'power1.inOut',
      }, `+=${i === 0 ? 0 : 0.5}`) // пауза між морфінгами
    })

    return () => { tl.kill() }
  }, [])

  return (
    <svg viewBox="0 0 100 100" className="w-40 h-40">
      <path
        ref={pathRef}
        d={sequence[0]}
        fill="none"
        stroke="#3b82f6"
        strokeWidth="2"
        strokeLinejoin="round"
      />
    </svg>
  )
}

Підготовка шляхів: інструменти

Для роботи з морфінгом фігури повинні бути оптимізовані:

  1. SVGO — мініфікація та нормалізація шляхів
  2. Inkscape → "Розширення > Змінити шлях > Додати вузли" — вирівнювання числа точок
  3. GSAP MorphSVGPlugin.convertToPath() — перетворює <circle>, <rect> тощо в <path>
import { MorphSVGPlugin } from 'gsap/MorphSVGPlugin'

// Конвертує всі примітиви перед реєстрацією морфінгу
MorphSVGPlugin.convertToPath('#my-circle, #my-rect')

Типові строки

Простий двостановий морфінг через SMIL — 4 години. Інтерактивний морфінг з виділенням фігур через GSAP — 1–2 робочих дні. Складна анімована ілюстрація з послідовностями, кольоровими переходами та інтерактивністю — 4–6 днів.