פיתוח תצוגת מוצר 360° למסחר אלקטרוני
בפרויקט לאחרונה, נתקלנו בבעיה טיפוסית: 72 פריימים במשקל 500 KB כל אחד נטענו בצורה אסינכרונית, אבל הדף עדיין שקל 36 MB, זמן ה-LCP הגיע ל-12 שניות, ומשתמשים עזבו לפני שסיים להיטען. לאחר מעבר ל-WebP עם טעינה פרוגרסיבית ותעדוף פריימים אי-זוגיים, ה-LCP ירד ל-1.8 שניות — שיפור של פי 6.7 — וההמרה עלתה ב-15%. התוצאה הזו מגיעה ישירות מאסטרטגיית טעינה חכמה, לא ממורכבות קוד.
תצוגת 360° היא רצף של תמונות מוצר (ראה צילום מוצר) שצולמו בזוויות שוות סביב האובייקט. המשתמש גורר את התמונה שמאלה-ימינה ורואה את המוצר מכל הצדדים. טכנית זה לא וידאו או תלת-ממד — רק אנימציה דרך מערך של פריימים סטטיים — אבל זה יוצר אשליה של סיבוב אינטראקטיבי. האתגר המרכזי הוא להבטיח סיבוב חלק ללא פגיעה בביצועים.
פורמט זה יעיל במיוחד עבור מוצרים שבהם המראה חשוב: ביגוד, נעליים, אלקטרוניקה, תכשיטים. עם זאת, היישום דורש תשומת לב לפרטים — מצילום ועד פורמט אחסון ואסטרטגיית טעינה. ללא זה, חוויית המשתמש נפגעת. קבלו ייעוץ ליישום תצוגת 360° בחנות שלכם — נעזור לכם להימנע מטעויות נפוצות.
מהן הדרישות הטכניות לצילום?
דרישות בסיסיות
- מספר פריימים: 24–72. 24 פריימים = צעד של 15° (מספק), 36 פריימים = צעד של 10° (חלק), 72 פריימים = צעד של 5° (חלק מאוד, אבל ~פי 3 יותר נתונים)
- שולחן סיבוב ממונע עם צעד אחיד — ציוד מפתח
- תאורה: קבועה, ללא צללים נעים בין פריימים
- רקע: לבן או שקוף (PNG עם אלפא) לשילוב בכל עיצוב דף
- רזולוציה: 1000–2000 px — איזון בין איכות למשקל
איך לבחור פורמט אחסון לפריימים?
שלוש גישות עיקריות — טבלת השוואה:
| פורמט | משקל | בקשות HTTP | מורכבות ניהול | המלצה |
|---|---|---|---|---|
| קבצים בודדים (WebP) | ~7 MB | 36 | נמוכה | לרוב הפרויקטים |
| גיליון ספרייט (תמונה אחת) | ~7.2 MB | 1 | בינונית | לקטלוגים קטנים |
| וידאו (MP4) | ~1–3 MB | 1 | גבוהה | לקטלוגים גדולים שבהם המשקל קריטי |
וידאו (MP4) קומפקטי פי 3–5 מקבצי WebP בודדים אך דורש שליטה מורכבת יותר בהפעלה. אם גמישות חשובה יותר ממשקל מינימלי, בחרו בקבצים בודדים.
יישום תצוגת 360° עם פריימים בודדים
הגישה הנפוצה ביותר היא מערך תמונות המוצג על Canvas. קוד הרכיב:
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);
}
} טעינה פרוגרסיבית קריטית לקטלוגים גדולים
7 MB מיד בטעינת הדף אינו מקובל. בפרויקט אחד עם קטלוג של 500 מוצרים, יישמנו את האסטרטגיה הבאה:
- הצגת תמונה סטטית (פריים ראשון) — היא כבר בגלריית המוצר
- במעבר עכבר / כניסה לאזור התצוגה (IntersectionObserver) — התחלת טעינת פריימים
- הצגת מחוון טעינה "טוען 360°: 45%"
- כשיותר מ-50% מהפריימים נטענו — הפעלת אינטראקטיביות
- המשך טעינת השאר ברקע
עדיפות טעינה: פריימים אי-זוגיים (0, 2, 4, 8, 16, 32...) — קודם אינטראקטיביות גסה, ואז מילוי פערים. גישה זו מפחיתה את נפח הטעינה הראשוני ב-70% לעומת טעינה מלאה, מה שהופך אותה למהירה פי 3.3. עבור קטלוג של 500 מוצרים, טעינה אופטימלית זו חסכה 15,000$ בשנה בעלויות רוחב פס.
טיפול באירועי מגע במכשירים ניידים
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);
}חשוב: 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); } } ו-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); } ב-touchmove — אחרת הדפדפן יגלול את הדף במקום לסובב את המוצר.
ספריות מוכנות לעומת פיתוח מותאם אישית
אם המשימה היא חד-פעמית ואין דרישות ספציפיות, ניתן להשתמש בספריות מוכנות: 360-image-viewer (vanilla JS, תומך במגע), Pannellum (לפנורמות), Three.js (לפנורמות כדוריות). עבור React קיימת react-360-image-viewer, אבל ההתאמה אישית מוגבלת.
השוואה:
| פרמטר | ספרייה מוכנה | יישום מותאם אישית |
|---|---|---|
| עלות יישום | נמוכה (רישיון) | גבוהה (פיתוח) |
| גמישות | מוגבלת | מלאה |
| ביצועים | ממוצעים | גבוהים (מותאם למשימה) |
| זמן יישום | 1–3 ימים | 1.5–2.5 שבועות |
| תמיכה | תלויה במפתח | פנימית |
עלות יישום מותאם אישית משתנה בהתאם לגודל הקטלוג ולדרישות הביצועים. יישום מותאם אישית עולה בדרך כלל בין 5,000$ ל-15,000$, בהתאם לגודל הקטלוג והמורכבות.
סיבוב אוטומטי
בכניסה ראשונה לאזור התצוגה — הפעל סיבוב אחד אוטומטית, ואז עצור. זה מדגים את התכונה ורומז למשתמש שהתמונה אינטראקטיבית.
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°" על התמונה הממוזערת בגלריה
- שכבת-על עם רמז "גרור לסיבוב" — נעלמת באינטראקציה הראשונה
- חצים שמאלה/ימינה בצדדים (שליטה חלופית לניווט בכפתורים)
- כפתורי השהה/הפעל לסיבוב אוטומטי
אינטגרציה עם הגלריה
תצוגת 360° היא משבצת אחת בגלריית המוצר. התמונה הממוזערת היא אייקון מיוחד, לא תמונה. בעת בחירת משבצת זו, ווידג'ט ה-360° מופעל במקום תמונה רגילה. במעבר למשבצת אחרת, הווידג'ט מוסר ומשחרר זיכרון (בטל את כל הטעינות הממתינות באמצעות AbortController).
מה כלול
- אינטגרציה של ספרייה מוכנה: 3–5 ימי עבודה. כולל הגדרה ושילוב בגלריה.
- יישום מותאם אישית (Canvas API, טעינה פרוגרסיבית, מגע): 1.5–2.5 שבועות. נכתב כולו עבור הפרויקט שלכם.
- תמיכה: תיעוד צילום, סקריפטים להמרת פריימים ל-WebP, אופטימיזציה.
- אחריות: אנו מתחזקים פונקציונליות בכל הדפדפנים והמכשירים המודרניים.
הצוות שלנו של 10+ מהנדסים בעל ניסיון של 8 שנים וביצע 200+ פרויקטים של מסחר אלקטרוני, כולל תצוגות 360° לקטלוגים של עד 10,000 מוצרים.
אם אתם מתכננים ליישם תצוגת מוצר 360° — צרו קשר להערכת הקטלוג שלכם ובחירת הפתרון האופטימלי. כבר יישמנו פרויקטים כאלה לקטלוגים מ-100 עד 5000 מוצרים ואנחנו יודעים איך להימנע מבעיות טיפוסיות. קבלו ייעוץ ליישום תצוגת 360° בחנות שלכם.







