Реализация морфинга 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 дней.