Разработка 360°-просмотра товара для интернет-магазина

Наша компания занимается разработкой, поддержкой и обслуживанием сайтов любой сложности. От простых одностраничных сайтов до масштабных кластерных систем построенных на микро сервисах. Опыт разработчиков подтвержден сертификатами от вендоров.
Разработка и обслуживание любых видов сайтов:
Информационные сайты или веб-приложения
Сайты визитки, landing page, корпоративные сайты, онлайн каталоги, квиз, промо-сайты, блоги, новостные ресурсы, информационные порталы, форумы, агрегаторы
Сайты или веб-приложения электронной коммерции
Интернет-магазины, B2B-порталы, маркетплейсы, онлайн-обменники, кэшбэк-сайты, биржи, дропшиппинг-платформы, парсеры товаров
Веб-приложения для управления бизнес-процессами
CRM-системы, ERP-системы, корпоративные порталы, системы управления производством, парсеры информации
Сайты или веб-приложения электронных услуг
Доски объявлений, онлайн-школы, онлайн-кинотеатры, конструкторы сайтов, порталы предоставления электронных услуг, видеохостинги, тематические порталы

Это лишь некоторые из технических типов сайтов, с которыми мы работаем, и каждый из них может иметь свои специфические особенности и функциональность, а также быть адаптированным под конкретные потребности и цели клиента

Предлагаемые услуги
Показано 1 из 1 услугВсе 2065 услуг
Разработка 360°-просмотра товара для интернет-магазина
Средняя
~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

Разработка 360°-просмотра товара для интернет-магазина

360°-просмотр — это последовательность фотографий объекта, сделанных с равномерным шагом по кругу. Пользователь перетаскивает изображение влево-вправо и видит товар со всех сторон. Технически это не видео и не 3D — просто анимация через массив статических кадров, но эффект создаёт иллюзию интерактивного вращения.

Фотосъёмка для 360°

Результат зависит от съёмки, а не от кода. Технические требования:

  • Количество кадров: 24–72. 24 кадра = шаг 15° (достаточно), 36 кадров = шаг 10° (плавно), 72 кадра = шаг 5° (очень плавно, но ~3x больше данных)
  • Поворотный стол с равномерным шагом (motorized turntable) — ключевое оборудование
  • Освещение: постоянное, без движущихся теней между кадрами
  • Фон: белый или прозрачный (PNG с альфой), чтобы встроить в любой дизайн страницы
  • Разрешение: 1000–2000px — баланс качества и веса

Типовой объём: 36 кадров × 200KB = 7MB на один товар. Это много для страницы. Решается прогрессивной загрузкой.

Форматы хранения кадров

Три варианта хранения:

Отдельные файлы: /360/product-42/frame-{01..36}.webp. Просто, прозрачно для кеша CDN. При смене кадра — браузер загружает нужный файл (или берёт из кеша).

Спрайт (sprite sheet): все кадры собраны в одно изображение (6×6 grid для 36 кадров). Меньше HTTP-запросов, но один большой файл (36 × 200KB = 7.2MB). Отображение через background-position. Подходит, если все кадры нужны сразу.

Видеофайл: кадры конвертируются в MP4 без звука, воспроизводится через <video> с управлением через currentTime. Самый компактный вариант (H.264 компрессия). Управление:

const video = document.querySelector('video');
let isDragging = false;
let startX = 0;
let startTime = 0;

canvas.addEventListener('mousedown', e => {
  isDragging = true;
  startX = e.clientX;
  startTime = video.currentTime;
});

canvas.addEventListener('mousemove', e => {
  if (!isDragging) return;
  const delta = (e.clientX - startX) / canvas.offsetWidth;
  video.currentTime = Math.max(0, Math.min(
    video.duration,
    startTime - delta * video.duration
  ));
});

Реализация на отдельных кадрах

Наиболее распространённый подход — массив изображений:

class Product360Viewer {
  private frames: HTMLImageElement[] = [];
  private currentFrame = 0;
  private isDragging = false;
  private startX = 0;
  private startFrame = 0;

  constructor(
    private container: HTMLElement,
    private canvas: HTMLCanvasElement,
    private frameUrls: string[]
  ) {
    this.preloadFrames();
    this.bindEvents();
  }

  private preloadFrames() {
    // Загружаем первый кадр сразу, остальные в фоне
    const loadFrame = (index: number) => {
      const img = new Image();
      img.src = this.frameUrls[index];
      img.onload = () => {
        this.frames[index] = img;
        if (index === 0) this.render(0);
        if (index < this.frameUrls.length - 1) loadFrame(index + 1);
      };
    };
    loadFrame(0);
  }

  private render(frameIndex: number) {
    const ctx = this.canvas.getContext('2d')!;
    const img = this.frames[frameIndex];
    if (!img) return;
    ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
    ctx.drawImage(img, 0, 0, this.canvas.width, this.canvas.height);
  }

  private handleDrag(deltaX: number) {
    const sensitivity = 3; // пикселей на кадр
    const frameDelta = Math.round((this.startX - deltaX) / sensitivity);
    const totalFrames = this.frameUrls.length;
    this.currentFrame = ((this.startFrame + frameDelta) % totalFrames + totalFrames) % totalFrames;
    this.render(this.currentFrame);
  }
}

Прогрессивная загрузка

7MB сразу при открытии страницы — неприемлемо. Стратегия:

  1. Отображаем статичное изображение (первый кадр) — он уже в галерее товара
  2. При наведении / при попадании в viewport (IntersectionObserver) — начинаем загрузку кадров
  3. Показываем индикатор загрузки «Загрузка 360°: 45%»
  4. При загрузке >50% кадров — активируем интерактивность
  5. Продолжаем загружать остальные в фоне

Приоритет загрузки: нечётные кадры (0, 2, 4, 8, 16, 32...) — сначала грубая интерактивность, потом заполнение пропусков.

Touch-события для мобайла

private bindEvents() {
  // Mouse
  this.canvas.addEventListener('mousedown', e => this.startDrag(e.clientX));
  window.addEventListener('mousemove', e => { if (this.isDragging) this.handleDrag(e.clientX); });
  window.addEventListener('mouseup', () => this.isDragging = false);

  // Touch
  this.canvas.addEventListener('touchstart', e => {
    e.preventDefault(); // предотвращаем scroll страницы
    this.startDrag(e.touches[0].clientX);
  }, { passive: false });

  this.canvas.addEventListener('touchmove', e => {
    e.preventDefault();
    if (this.isDragging) this.handleDrag(e.touches[0].clientX);
  }, { passive: false });

  this.canvas.addEventListener('touchend', () => this.isDragging = false);
}

Важно: passive: false и e.preventDefault() на touchmove — иначе браузер будет скроллить страницу вместо вращения товара.

Готовые библиотеки

Если задача разовая и нет специфических требований:

  • 360-image-viewer (npm) — лёгкий, vanilla JS, поддерживает touch
  • Pannellum — для панорам (equirectangular), не для предметной съёмки
  • Three.js с equirectangular texture — для настоящей сферической панорамы

Для React: react-360-image-viewer — оборачивает базовую функциональность, но кастомизация ограничена.

Автозапуск вращения

При первом попадании в viewport — автоматически прокрутить один оборот, потом остановиться. Это демонстрирует возможность и подсказывает пользователю, что изображение интерактивное.

autoSpin(rotations = 1, fps = 30) {
  const totalFrames = this.frameUrls.length * rotations;
  let frame = 0;
  const interval = setInterval(() => {
    this.currentFrame = (this.currentFrame + 1) % this.frameUrls.length;
    this.render(this.currentFrame);
    if (++frame >= totalFrames) clearInterval(interval);
  }, 1000 / fps);
}

Подсказки для пользователя

Интерактивность должна быть очевидна. Стандартные решения:

  • Иконка «360°» поверх изображения в галерее (на тумбнейле)
  • Overlay с подсказкой «Перетащите для вращения» — исчезает при первом взаимодействии
  • Стрелочки влево-вправо по бокам (альтернативное управление для кнопочной навигации)
  • Кнопки «Пауза/Воспроизвести» для автовращения

Интеграция с галереей

360°-просмотр — один из слотов галереи товара. Тумбнейл — специальная иконка, не фото. При выборе этого слота — запускается 360°-виджет вместо обычного изображения. При переходе на другой слот — виджет размонтируется и освобождает память (отменяем все незавершённые загрузки через AbortController).

Сроки

  • Интеграция готовой библиотеки (react-360-image-viewer или аналог): 3–5 рабочих дней
  • Кастомная реализация (Canvas API, прогрессивная загрузка, touch): 1.5–2.5 недели
  • Настройка pipeline съёмки и конвертации (если нет): дополнительная задача вне разработки
  • Пакетная конвертация существующих кадров (WebP, оптимизация): 2–3 дня

Стоимость съёмки и подготовки контента часто превышает стоимость разработки виджета. Это нужно учитывать при планировании: 36 кадров для 500 товаров — это операционная задача, а не техническая.