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 Erweiterung enthält einige Optionen, die über das Optionsobjekt übergeben werden:
jQuery("#yourSelector").axZmSpinWhilePageScroll({
"numberSpins": 1.5,
"viewport": "visible"
});
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 des AJAX-ZOOM-Viewers, der ein Objekt in Verbindung mit dem Scrollen des Benutzers dreht.
Für das normale Einbetten von AJAX-ZOOM (nicht über iframe),
der beste Ort zum Einleiten der Erweiterung ist onSpinPreloadEnd
Callback , z.B.
<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>
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.
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.
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 || {});
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!