Aktuelle Version: 5.4.25 (Change Log)
Release Datum: November 8th, 2023
Download AJAX-ZOOM Software

Drehen der 360-Produktansicht beim Scrollen des Fensters

Gepostet am 2019-01-29

Dieser Artikel beschreibt die Entwicklung eines Codes, der die Drehung einer 360 Produktansicht mit Scrollen des Fensters synchronisiert. Das Ergebnis ist eine vollwertige JavaScript-Erweiterung für den AJAX-ZOOM 360-Objekt-Viewer, die zudem verschiedene Optionen für dieses Verhalten bietet. Die Demonstration der funktionierenden Erweiterung ist innerhalb des Artikel Textes eingebettet. Leser können die Optionen der Erweiterung ändern und die Auswirkungen testen.

Anfangs war es das Ziel dieses Artikels, ein kurzes Code-Snippet zur Verfügung zu stellen, welches das Scrollen des Fensters mit dem Drehen einer 360-Produktansicht synchronisiert. Es schien eine einfache Aufgabe zu sein und tatsächlich bedurfte es für eine funktionierende Prüfung des Konzepts nur ein paar Zeilen Code. AJAX-ZOOM verfügt über die jQuery.fn.axZm.spinBy Methode, mit der eine 360-Produktansicht um eine bestimmte Anzahl von Frames gedreht werden kann. Browser stellen das onscroll Ereignis bereit, das jedes Mal bzw. dauernd ausgelöst wird, wenn das Fenster gescrollt wird. Die Idee war also, die AJAX-ZOOM "spinBy" Methode an das Scroll-Ereignis des Browsers zu binden, dabei einige Berechnungen anzustellen und fertig.

Das Hauptproblem bei diesem Ansatz ist jedoch, dass insbesondere bei IOS Safari die Ergebnisse von den der Desktop-Browsern stark abweichen. Bei der Suche im Web wurde deutlich, dass die Ausführung verschiedener JavaScripts beim Scrollen der Seiten die Scrollanimation weniger flüssig macht. Die Hersteller von mobilen Browsern verwendeten daher in der Vergangenheit unterschiedliche Strategien in Bezug auf das Dilemma den Entwicklern Freiheiten zu gewähren oder den eigenen Browser beim User besser erscheinen zu lassen. Meist stimmten sie für reibungsloses Scrollen und gegen schlecht geschriebene JavaScripte. Diese Strategien führten dazu, dass die JavaScript-Ausführung blockiert bzw. verschoben wurde oder das Onscroll-Ereignis während der Scroll-Animation nicht ausgelöst wurde. Momentan löst der IOS 12.1 Safari das Scroll-Ereignis aus und blockiert die JavaScript-Ausführung nicht mehr. Die Häufigkeit des Ereignisaufrufs reicht jedoch nicht aus, um dabei etwas flüssig zu bewegen.

Um diese Einschränkung zu umgehen, haben wir beschlossen die Funktion, die die "spinBy" -Methode verwendet, innerhalb eines festen Intervalls auszuführen. Das Intervall ist auf 1000/60 Millisekunden eingestellt, was einen ziemlich niedrigen Wert ergibt. Im Allgemeinen ist ein solcher Ansatz ineffizient und kann eine Animation noch träger machen. Außerdem kann die Gesamtleistung der Seite dramatisch leiden und den Browser sogar zum Absturz bringen. Dies hängt jedoch stark vom Schwerfälligkeit des Codes ab, der 30 oder 60 Mal pro Sekunde in einer Schleife ausgeführt wird. Das Anwenden des requestAnimationFrame führt möglicherweise zu besseren Ergebnissen.

Die Ergebnisse der setInterval Methode stellten sich jedoch für die aktuelle Aufgabe als zufriedenstellend heraus und die Methode wurde beibehalten. Die Intervallschleife wird nach zwei Sekunden Inaktivität in den Leerlauf versetzt und durch das erste Scroll-Ereignis wieder aktiviert. Glücklicherweise feuert IOS das "onscroll" Ereignis sofort zu Beginn des Scroll-Vorgangs ab, sodass das gesamte Konzept funktionsfähig bleibt. Außerdem ist der Code in der Intervallfunktion nicht zu Schwerfällig. Alle Vorberechnungen werden noch vor der Anwendung der "spinBy" -Methode durchgeführt. Durch solche Einzelmaßnahmen wird die Gesamtleistung weiter verbessert.

Da die anfängliche Idee, ein kurzes Code-Snippet bereitzustellen, fehlgeschlagen ist, weil der Code länger als geplant wurde, schadete es weiterhin nicht ihn in eine Plugin-Struktur zu packen und einige Optionen hinzuzufügen. Die Option "numberSpins" erstellt beispielsweise eine Beziehung zwischen der Anzahl der vollen 360 Umdrehungen und der Höhe des Browserfensters. Das Ergebnis ist eine neue jQuery.fn.axZmSpinWhilePageScroll AJAX-ZOOM Erweiterung, die auch mit mehreren über Iframe eingebetteten AJAX-ZOOM-Viewern funktioniert!

Die AJAX-ZOOM "axZmSpinWhilePageScroll" Erweiterung

Die Erweiterung enthält einige Optionen, die über das Optionsobjekt übergeben werden:


jQuery("#yourSelector").axZmSpinWhilePageScroll({
	"numberSpins": 1.5,
	"viewport": "visible"
});
		
  • numberSpins: Anzahl der vollen 360 Umdrehungen, um die sich das Produkt relativ zur Höhe des Fensters drehen sollte. Float-Nummer > 0
  • viewport: das Drehen verhindern, wenn der Viewer nicht sichtbar ist. Mögliche Werte: false, "full" und "visible".
  • spinWhenZoomed: bei true dreht sich die 360-Produktansicht auch wenn sie vergrößert ist.
  • oneDirection: nur in eine Richtung drehen, unabhängig davon, ob der Benutzer nach oben oder unten scrollt. Mögliche Werte: false, 1, -1
  • debug: Protokollierungsfehler und andere Ereignisse in der Konsole aktivieren bzw. deaktivieren.

Sie können die obigen Optionen testen, indem Sie deren Werte unterhalb der Demo-Instanz auf dieser Seite ändern.

Der #yourSelector kann eine ID des übergeordneten Containers sein, der den AJAX-ZOOM-Viewer enthält. Für Implementierungen über iframe, z.B. die ID des iframe.

Verwenden Sie die Methoden "stop" oder "destroy", um das Verhalten zu deaktivieren:


jQuery("#yourSelector").axZmSpinWhilePageScroll("stop");
		

Demo normales Einbetten

Demo des AJAX-ZOOM-Viewers, der ein Objekt in Verbindung mit dem Scrollen des Benutzers dreht.

Wird geladen, bitte warten...

Für das normale Einbetten von AJAX-ZOOM (nicht über iframe), der beste Ort zum Einleiten der Erweiterung ist onSpinPreloadEnd Callback , z.B.

HTML


		<div class="az_embed-responsive" style="padding-top: 60%">
			<!-- Placeholder for AJAX-ZOOM player -->
			<div class="az_embed-responsive-item" id="axZmPlayerContainer">
				Loading, please wait...
			</div>
		</div>
		

JavaScript, das AJAX-ZOOM regulär lädt und axZmSpinWhilePageScroll im onSpinPreloadEnd -Callback einleitet:


var ajaxZoom = {};
ajaxZoom.path = "/axZm/"; 
ajaxZoom.divID = "axZmPlayerContainer";

ajaxZoom.opt = {
	onBeforeStart: function() {
		jQuery.axZm.spinReverse = false;
	}, 
	onSpinPreloadEnd: function() {
		jQuery('#' + ajaxZoom.divID).axZmSpinWhilePageScroll({
			"numberSpins": 1.8, // rotations relative to the height of the window
			"viewport": 'visible', // visible, full or false
			"spinWhenZoomed": false, // spin when 360 view is zoomed
			"oneDirection": false // spin only in one direction
		});
	}
};

ajaxZoom.parameter = "example=spinIpad&3dDir=/pic/zoom3d/Uvex_Occhiali"; 

jQuery.fn.axZm.openResponsive(
	ajaxZoom.path,
	ajaxZoom.parameter,
	ajaxZoom.opt,
	ajaxZoom.divID,
	false,
	true,
	false
);
		

Weitere wichtige Einstellungen, um die Konfiguration des Viewers auf dieser Seite zu reproduzieren, sind:


$zoom['config']['mouseScrollEnable'] = true;
$zoom['config']['scroll'] = false;
$zoom['config']['spinDemo'] = false;
		

Sie können diese Optionen in einer der AJAX-ZOOM-Konfigurationsdateien oder innerhalb des onBeforeStart-Callbacks über JavaScript festlegen ( weitere Informationen zu den Optionen zum Einstellen von Optionen in einem anderen Blogartikel). Wenn Sie die Optionen mouseScrollEnable und scroll einstellen, reagiert der Viewer nicht auf das Scrollen der Maus in Bezug auf das Vergrößern und Verkleinern, sondern scrollt stattdessen das Fenster.

Demo-Einbettung via iframe

Die Erweiterung funktioniert auch mit dem AJAX-ZOOM-Viewer, der über iframe eingebettet ist. Im aktuellen Zustand funktioniert es jedoch nicht für domänenübergreifende Implementierungen, aber im Allgemeinen ist es möglich.

Informationen zum Einbetten des AJAX-ZOOM-Viewers über iframe finden Sie in example13. Wenn das iframe embed nicht über "Lazy load" geladen wird, können Sie jederzeit jQuery.fn.axZmSpinWhilePageScroll für diesen iframe auslösen. Beim verzögerten Laden von iframes sollte das Lazy-jQuery-Plugin möglicherweise einen Rückruf für das src-Attribut des iframe enthalten. Wenn das src-Attribut nicht vorhanden ist, funktioniert das Ereignis onload des iframe nicht. Das jQuery.fn.axZmSpinWhilePageScroll wartet jedoch, bis der iframe mit einer reduzierten Häufigkeit von einer Überprüfung pro Sekunde geladen wird.

Code der Erweiterung

Bis diese Erweiterung nicht Teil des AJAX-ZOOM-Downloadpakets ist, können Sie den folgenden Code kopieren, in eine JavaScript-Datei einfügen und ihn zusammen mit AJAX-ZOOM verwenden.


		/*!
* Plugin: jQuery AJAX-ZOOM, jquery.axZm.spinWhilePageScroll.js
* Copyright: Copyright (c) 2010-2019 Vadim Jacobi
* License Agreement: http://www.ajax-zoom.com/index.php?cid=download
* Extension Version: 0.1b
* Extension Date: 2019-01-27
* URL: http://www.ajax-zoom.com
* Documentation: http://www.ajax-zoom.com/index.php?cid=docs
*/

;(function(j) {
	j = j || window.jQuery || {};

	// Console log
	var consoleLog = function(msg) {
		if (msg && window.console && window.console.log) {
			window.console.log(msg);
		}
	};

	if (!j.fn || !j.fn.jquery) {
		consoleLog('jQuery core is not loaded;');
		return;
	}
	var scrollTop = function() {
		return window.pageYOffset || document.documentElement.scrollTop;
	};

	var winHeight = function() {
		return window.innerHeight || document.documentElement.clientHeight;
	};

	var winWidth = function() {
		return window.innerWidth || document.documentElement.clientWidth;
	};

	// Check if an element is fully visible in viewport
	var isElementInViewportFull = function(ell) {
		var rect = ell.getBoundingClientRect();
		return (
			rect.top >= 0 &&
			rect.left >= 0 &&
			rect.bottom <= winHeight() &&
			rect.right <= winWidth()
		);
	};

	// Check if a part of an element is visible in viewport
	var isElementInViewportVisible = function(ell) {
		var rect = ell.getBoundingClientRect();
		return (
			rect.top <= winHeight() &&
			rect.top + rect.height >= 0 &&
			rect.left <= winWidth() &&
			rect.left + rect.width >= 0
		);
	};

	// Create random id
	var makeID = function(l) {
		l = l || 12;
		var t = '';
		var str = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";

		for (var i = 0; i < l; i++) {
			t += str.charAt(Math.floor(Math.random() * str.length));
		}

		return t + (new Date()).getTime();
	};

	// Plugin axZmSpinWhilePageScroll
	j.fn.axZmSpinWhilePageScroll = function(op) {
		// Options
		op = op || {};

		// Default options
		var o = {
			numberSpins: 1.5, // rotations per window height scroll
			viewport: 'visible', // visivle, full or false
			spinWhenZoomed: false, // spin when 360 view is zoomed
			oneDirection: false, // spin only in one direction
			debug: true
		};

		return this.each(function() {
			var el = this;
			var $el = j(this);

			// Internal variables
			var tPrev = 0;
			var spn = false;
			var idle = true;
			var jref = j; // reference to jQuery that may change
			var frame = $el.is('iframe');
			var dta = {};
			var cLog = consoleLog;

			// Stop method
			var stop = function(d) {
				if (dta.idleTo) {
					window.clearTimeout(dta.idleTo);
				}

				if (dta.intv) {
					window.clearInterval(dta.intv);
				}

				j(window).unbind('scroll.' + dta.id);

				if (d) {
					$el.removeData('spinAzWPS');
				}
			};

			// Destroy
			var destroy = function() {
				stop(1);
			};

			if (!$el.data('spinAzWPS')) {
				$el.data('spinAzWPS', {});
				dta = $el.data('spinAzWPS');
				dta.id = makeID();
				dta.wait = 0;
			} else {
				dta = $el.data('spinAzWPS');
			}

			dta.stop = stop;
			dta.destroy = destroy;

			// Disable logging to console
			if (j.isPlainObject(op) && op.debug === false) {
				cLog = function(msg) {
					return;
				};
			}

			if (typeof op == 'string') {
				if (j.isFunction(dta[op])) {
					dta[op].call();
				} else {
					cLog('Method "' + op + '" does not exist;');
				}

				return;
			}

			// Options
			var opt = j.extend(true, {}, o, op);
			opt.speed = opt.speed < 0.1 ? 0.1 : opt.speed;
			opt.numberSpins = parseFloat(opt.numberSpins);

			// iframe
			if (frame) {
				if (!el.contentWindow || !el.contentWindow.jQuery) {
					dta.wait++;
					var id = $el.attr('id') ? '#' + $el.attr('id') : '';
					cLog('Waiting for iframe ' + id + ' to load, count: ' + dta.wait);
					setTimeout(function() {
						$el.axZmSpinWhilePageScroll(op);
					}, dta.wait <= 10 ? 300 : 1000);

					return;
				}

				// Access jQuery of the iframe
				jref = el.contentWindow.jQuery;
			}

			// Function that spins a 360 product view on page scroll
			var spinBy = function() {
				if (idle) {
					return;
				}

				// Wait till AJAX-ZOOM 360 view is preloaded
				if (!jref.axZm || !jref.axZm.spinPreloaded) {
					return;
				}

				// Do not spin on page scroll when 360 view is zoomed
				if (opt.spinWhenZoomed === false && (jref.axZm.zmData || jref.axZm.zoomWIDTH)) {
					tPrev = scrollTop();
					return;
				}

				// The "viewport" option
				if (opt.viewport) {
					if (opt.viewport == 'visible') {
						if (!isElementInViewportVisible(el)) {
							return;
						}
					} else if (opt.viewport == 'full') {
						if (!isElementInViewportFull(el)) {
							return;
						}
					} else {
						stop();
						cLog('The value of the viewport option must be either "full", "visible" or false;');
						return;
					}
				}

				// Do not apply if AJAX-ZOOM is at full screen
				if (j('body').is('.axZm_body_fullscreen, .axZmLock')) {
					return;
				}

				// Do calculations and spin AJAX-ZOOM
				var tPos = scrollTop();
				var scrollDiff = tPrev - tPos;
				var sStep = winHeight() / jref.axZm.spinCount / opt.numberSpins;

				if (Math.abs(scrollDiff) > sStep) {
					var step = !spn ? 1 : Math.round(Math.abs(scrollDiff) / sStep);

					if (step > 0) {
						// $.fn.axZm.spinBy is AJAX-ZOOM method that you can use for other tasks as well
						// AJAX-ZOOM has many other methods such as, 
						// e.g. spinTo for spinning and optional zooming in the same time
						if (opt.oneDirection === false) {
							jref.fn.axZm.spinBy(tPrev > tPos ? -step : step);
						} else {
							jref.fn.axZm.spinBy(opt.oneDirection > 0 ? step : -step);
						}

						tPrev = tPos;
						spn = 1;
					}
				}

				return true;
			};

			stop();

			// This is only about idle
			j(window)
			.bind('scroll.' + dta.id, function() {
				idle = false;
				if (dta.idleTo) {
					window.clearTimeout(dta.idleTo);
				}

				// Set idle after 2 seconds of inactivity
				dta.idleTo = setTimeout(function() {
					idle = true;
				}, 2500);
			});

			// Binding spinBy to onscroll event only does not really work on IOS
			dta.intv = setInterval(spinBy, 1000/60);

			return this;
		});
	};

})(window.jQuery || {});		

Comments (1)

Lulu 2024-03-17 14:22:20
Lulu Working well, thanks!

Leave a Comment

Looking for a place to add a personal image? Visit www.gravatar.com to get Your own gravatar, a globally-recognized avatar. After you're all setup, your personal image will be attached every time you comment.

Um Live-Support-Chat nutzen zu können wird Skype vorausgesetzt.

Sollte Live-Support-Chat über Skype nicht sofort zu erreichen sein, dann hinterlassen Sie bitte im Skype eine Nachricht oder schreiben Sie uns eine Email über die Kontakt Seite.

Jede Anfrage wird beantwortet!

Live-Support-Chat