Image Zoom für Products-Listing

Produkte sind für Ihren Onlineshops eines der wichtigtsne Faktoren. Aus diesem Grund haben wir und ein Image-Zoom für das Produktlisting entwickelt, damit der Kunde ohne in die Produktdetails zu klicken eine Vergrößerung des Produktes betrachten kann. Zu sehen ist das unter www.demo-store.de (Bewegen Sie die Maus über ein Produktbild) .
Zur Umsetzung verwenden wir jQuery und mit installierter Extension jQuery-Base.
Wir benötigen die Dateinformationen zum base image, die wir im IMG-Tag mit dem Custom-Attribute zoom unterbringen.
Beispiel:
<img src="image_small.jpg" zoom="image_large.jpg" />
Das zoom-Tag wird ausgelesen und bei einem Mouse-Over kann das größere Bild nachgeladen werden – http://www.mxperts.de/examples/imagezoom/. Die Idee zu diesem Feature liefert mir die jQuery-Klasse miniZoomPan von Gian Carlo Mingati. Allerdings konnte ich seine Umsetzung für unser Zwecke, für Magento, nicht verwenden.
Umsetzung:
1. jQuery:
/*
* jQuery miniZoomPan 1.0
* 2009 Gian Carlo Mingati
* modified by Johannes Teitge
* Version: 1.0 (18-JUNE-2009)
* Dual licensed under the MIT and GPL licenses:
* http://www.opensource.org/licenses/mit-license.php
* http://www.gnu.org/licenses/gpl.html
*
* Requires:
* jQuery v1.3.2 or later
*
* To define large image use the zoom attribute
* Example: <img src="images/leaf_s.jpg" zoom="images/leaf_l.jpg"/>
*
*/
jQuery.fn.listZoom = function(settings) {
settings = jQuery.extend({
sW: 10, // small image width
sH: 10, // small image height
lW: 20, // large image width
lH: 20, // large image height
frameColor: "#cecece",
frameWidth: 1,
loaderContent: "loading..." // plain text or an image tag eg.: "<img src='yoursite.com/spinner.gif' />"
}, settings);
return this.each(function(){
var div = jQuery(this);
div.css({width: settings.sW, height: settings.sH, border: settings.frameWidth+"px solid "+settings.frameColor}).addClass("listzoom");
var ig = div.children();
var igs = jQuery(ig).attr('src'); // small image filename
var igl = jQuery(ig).attr('zoom'); // large image filename
ig.css({position: "relative"});
jQuery(window).bind("load", function() {
ig.width(settings.sW);
ig.height(settings.sH);
});
div.css({overflow: "hidden"});
jQuery("<span class='loader'>"+settings.loaderContent+"<\/span>").insertBefore(ig);
div.mousemove(function(e) {
var divWidth = div.width();
var divHeight = div.height();
var igW = ig.width();
var igH = ig.height();
var dOs = div.offset();
var leftPan = (e.pageX - dOs.left) * (divWidth - igW) / (divWidth+settings.frameWidth*2);
var topPan = (e.pageY - dOs.top) * (divHeight - igH) / (divHeight+settings.frameWidth*2);
ig.css({left: leftPan, top: topPan});
});
div.hover(
function () {
ig.css({ width: settings.lW, height: settings.lH});
div.children("span.loader").fadeIn(250);
ig.attr("src",igl).load(function(){ // set large image and fade out after loaded
div.children("span.loader").fadeOut(250);
});
},
function () {
ig.css({left: "0", top: "0", width: settings.sW, height: settings.sH});
ig.attr("src",igs); // set small image;
div.children("span.loader").fadeOut(250); // hide Loader
}
);
});
};
Die Verwendung im HTML-Code sieht dann wie folgt aus:
<div class="zoom">
<img src="images/image_small.jpg" zoom="images/image_large.jpg"/>
</div>
<script type= "text/javascript">/*<![CDATA[*/
$(function() {
$(".zoom").listZoom({
sW: 400,
sH: 400,
lW: 800,
lH: 800,
frameColor: "#cecece",
frameWidth: 1,
loaderContent: 'Bild wird geladen...'
})
});
/*]]>*/</script>
Als Parameter werden die Bildgröße der beiden Bilder übergeben, die Farbe und Breite des Bild-Rahmens sowie des Textes für den Bild-Loader. Das Hover-Event ersetzt die Image-Source durch das große Bild und zeigt den “Loading” Text an. Durch Verwendung von load, wir ein nach dem vollständigen laden des Bildes ein Event ausgelöst und der “Loading” Text ausgeblendet.
Mit dem Mousemove Event reagieren wir auf die Mausbwegung und der Benutzer kann sich das Produkt genauer ansehen.
Wir kopieren den Javascript-Code als jquery.listzoom.js in den Ordner
skin/frontend/default/[Ihr Theme]/js.
2. CSS:
.listzoom {
background: #fff;
position: relative;
border: 1px solid lightgray;
padding: 0;
margin: 0;
}
.listzoom span.loader {
position:absolute;
left:0;
top:0;
z-index: 1;
display: none;
color: #000;
background: #fff;
font: normal 9px Arial, Verdana;
padding: 3px;
}
Den Javascript-Code kopieren Sie als jquery.listzoom.css in den Ordner
skin/frontend/default/[Ihr Theme]/css.
3. Einbinden über jQuery-Base
Durch die Verwendung von jQuery-Base sparen wir uns das einbinden von css und javascript über XML. Tragen Sie im Backend unter xxx folgendes ein (roter Rahmen).

4. Layout
Magento stellt im Produkt-Listing nur eine begrenze Anzahl Datenfelder in der Products-Collcetion zur Verfügung. Über eine Anpassung der catalog.xml, können wir Magento mitteilen, dass wir auch das base image (image) im Produkt-Listing benötigen.
Öffnen Sie dazu die Datei app/design/frontend/default/[Ihr Theme]/layout/catalog.xml und suchen Sie als erstes die Stelle
<catalog_category_default>
...
<block type="catalog/category_view" name="category.products" template="catalog/category/view.phtml">
...
und fügen Sie folgende Zeile ein:
<action method="addAttribute"><name>image</name></action>
Genauso gehen Sie auch beim layered Navigation Layout vor.
<catalog_category_layered>
...
<block type="catalog/product_list" name="product_list" template="catalog/product/list.phtml">
...
und fügen Sie folgende Zeile ein:
<action method="addAttribute"><name>image</name></action>
Nun liefert uns die Funktion getLoadedProductCollection() die Daten inklusive dem zusätzlichen Attribut “Image”.
5. Template list.phtml anpassen
Öffnen Sie nun die Datei
app/design/frontend/default/[Ihr Theme]/template/catalog/product/list.phtml
In dieser Template-Datei erfolgt die Ausgabe des Produktlisting als Liste sowie auch als Grid. Beides müssen wir einbeziehen, wobei die Bildgrößen jeweils unterschidlich sein können.
Deshalb platzieren wir jeweils am Ende jeder Schleife über die Products-Collection den jQuery-Code. Die Image-Tags werden um das zoom-Attribute erweitert indem wir das “base image” als Attribut verwenden. Im default Theme sieht das dann in unserem Demo-Store wie folgt aus:
<?php
/**
* Magento
*
* NOTICE OF LICENSE
*
* This source file is subject to the Academic Free License (AFL 3.0)
* that is bundled with this package in the file LICENSE_AFL.txt.
* It is also available through the world-wide-web at this URL:
* http://opensource.org/licenses/afl-3.0.php
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@magentocommerce.com so we can send you a copy immediately.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade Magento to newer
* versions in the future. If you wish to customize Magento for your
* needs please refer to http://www.magentocommerce.com for more information.
*
* @category design_default
* @package Mage
* @copyright Copyright (c) 2008 Irubin Consulting Inc. DBA Varien (http://www.varien.com)
* @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0)
*/
?>
<?php
/**
* Product list template
*
* @see Mage_Catalog_Block_Product_List
*/
?>
<?php $_productCollection=$this->getLoadedProductCollection() ?>
<?php if(!$_productCollection->count()): ?>
<div class="note-msg">
<?php echo $this->__('There are no products matching the selection.') ?>
</div>
<?php else: ?>
<?php echo $this->getToolbarHtml() ?>
<?php // List mode ?>
<?php if($this->getMode()!='grid'): ?>
<?php $_iterator = 0; ?>
<div class="listing-type-list catalog-listing">
<?php foreach ($_productCollection as $_product): ?>
<div class="listing-item<?php if( ++$_iterator == sizeof($_productCollection) ): ?> last<?php endif; ?>">
<?php // Product Image ?>
<div class="product-image">
<a href="<?php echo $_product->getProductUrl() ?>" title="<?php echo $this->htmlEscape($_product->getSmallImageLabel()) ?>">
<div class="zoom">
<img src="<?php echo $this->helper('catalog/image')->init($_product, 'small_image')->resize(135, 135); ?>" zoom="<?php echo $this->helper('catalog/image')->init($_product, 'image')->resize(250, 250); ?>" width="135" height="135" alt="<?php echo $this->htmlEscape($this->getImageLabel($_product, 'small_image')) ?>" title="<?php echo $this->htmlEscape($this->getImageLabel($_product, 'small_image')) ?>" />
</div>
</a>
</div>
<?php // Product description ?>
<div class="product-shop">
<h5><a href="<?php echo $_product->getProductUrl() ?>" title="<?php echo $this->htmlEscape($_product->getName()) ?>"><?php echo $this->htmlEscape($_product->getName())?></a></h5>
<?php if($_product->getRatingSummary()): ?>
<?php echo $this->getReviewsSummaryHtml($_product) ?>
<?php endif; ?>
<?php echo $this->getPriceHtml($_product, true) ?>
<?php if($_product->isSaleable()): ?>
<button class="form-button" onclick="setLocation('<?php echo $this->getAddToCartUrl($_product) ?>')"><span><?php echo $this->__('Add to Cart') ?></span></button>
<?php else: ?>
<div class="out-of-stock"><?php echo $this->__('Out of stock') ?></div>
<?php endif; ?>
<div class="clear"></div>
<div class="description">
<?php echo nl2br($_product->getShortDescription()) ?>
<a href="<?php echo $_product->getProductUrl() ?>" title="<?php echo $this->htmlEscape($_product->getName()) ?>"><small><?php echo $this->__('Learn More') ?></small></a>
</div>
<p class="add-to">
<?php if ($this->helper('wishlist')->isAllow()) : ?>
<a href="<?php echo $this->helper('wishlist')->getAddUrl($_product) ?>" class="link-cart"><?php echo $this->__('Add to Wishlist') ?></a>
<?php endif; ?>
<?php if($_compareUrl=$this->getAddToCompareUrl($_product)): ?>
<span class="pipe">|</span>
<a href="<?php echo $_compareUrl ?>"><?php echo $this->__('Add to Compare') ?></a>
<?php endif; ?>
</p>
</div>
</div>
<?php endforeach; ?>
<script type= "text/javascript">/*<![CDATA[*/
jQuery(function() {
jQuery(".zoom").listZoom({
sW: 135,
sH: 135,
lW: 250,
lH: 250,
loaderContent: 'Bild wird geladen...'
})
});
/*]]>*/</script>
</div>
<?php else: ?>
<?php // Grid Mode ?>
<div class="listing-type-grid catalog-listing">
<?php $_collectionSize = $_productCollection->count() ?>
<?php
$_columnCount = $this->getColumnCount();
// $_columnCount = 5;
?>
<?php $i=0; foreach ($_productCollection as $_product): ?>
<?php if($i++%$_columnCount==0): ?>
<ol class="grid-row">
<?php endif; ?>
<li class="item">
<p class="product-image">
<a href="<?php echo $_product->getProductUrl() ?>" title="<?php echo $this->htmlEscape($this->getImageLabel($_product, 'small_image')) ?>">
<div class="zoom">
<img src="<?php echo $this->helper('catalog/image')->init($_product, 'small_image')->resize(80, 80); ?>" zoom="<?php echo $this->helper('catalog/image')->init($_product, 'small_image')->resize(250, 250); ?>" width="80" height="80" alt="<?php echo $this->htmlEscape($this->getImageLabel($_product, 'small_image')) ?>" title="<?php echo $this->htmlEscape($this->getImageLabel($_product, 'small_image')) ?>" />
</div>
</a>
</p>
<h5><a href="<?php echo $_product->getProductUrl() ?>" title="<?php echo $this->htmlEscape($_product->getName()) ?>"><?php echo $this->htmlEscape($_product->getName()) ?></a></h5>
<!--
<?php if($_product->getRatingSummary()): ?>
<?php echo $this->getReviewsSummaryHtml($_product, 'short') ?>
<?php endif; ?>
-->
<?php echo $this->getPriceHtml($_product, true) ?>
<?php if($_product->isSaleable()): ?>
<button type="button" class="form-button" onclick="setLocation('<?php echo $this->getAddToCartUrl($_product) ?>')"><span><?php echo $this->__('Kaufen') ?></span></button>
<?php else: ?>
<div class="out-of-stock"><?php echo $this->__('Out of stock') ?></div>
<?php endif; ?>
<!--
<?php if($_product->isSaleable()): ?>
<button type="button" class="form-button" onclick="setLocation('<?php echo $this->getAddToCartUrl($_product) ?>')"><span><?php echo $this->__('Add to Cart') ?></span></button>
<?php else: ?>
<div class="out-of-stock"><?php echo $this->__('Out of stock') ?></div>
<?php endif; ?>
-->
<!--
<p class="add-to">
<?php if ($this->helper('wishlist')->isAllow()) : ?>
<a href="<?php echo $this->helper('wishlist')->getAddUrl($_product) ?>" class="link-cart"><?php echo $this->__('Add to Wishlist') ?></a>
<?php endif; ?>
<?php if($_compareUrl=$this->getAddToCompareUrl($_product)): ?><br/>
<a href="<?php echo $_compareUrl ?>"><?php echo $this->__('Add to Compare') ?></a>
<?php endif; ?>
</p>
-->
</li>
<?php if($i%$_columnCount==0 || $i==$_collectionSize): ?>
</ol>
<?php endif; ?>
<?php endforeach ?>
<script type="text/javascript">decorateGeneric($$('.grid-row'), ['last', 'odd', 'even']);</script>
<script type= "text/javascript">/*<![CDATA[*/
jQuery(function() {
jQuery(".zoom").listZoom({
sW: 80,
sH: 80,
lW: 250,
lH: 250,
loaderContent: 'Bild wird geladen...'
})
});
/*]]>*/</script>
</div>
<?php endif; ?>
<?php echo $this->getToolbarHtml() ?>
<?php endif; ?>
Damit ist auch schon die ganze Arbeit getan und Sie haben im produkt-Listing eine Zoom-Funktion, welche die Textangaben nicht beinflußt und somt die ganzen Produktinfomationen lesbar bleiben.
An dieser Stelle möchten Daniel, Igor und ich uns bei all unseren treuen Lesern bedanken. Danke für die Tipps, Kritik und Anregungen und die vielen E-Mails sowie Kontakten.
Wir hoffen, dass wir im Rahmen unseres Mxperts-Projekts etwas Unterstützung bei der täglichen Arbeit mit Magento geben konnten und vor allem unsere Zielsetzung “Wege aus der Praxis für die Praxis aufzuzeigen” ein Stück weit erreichen konnten.
Wir freuen uns immer wieder über positives Feedback, wenn es unsere Modifikationen / Extensions so wie hier gezeigt, oder auch gerne in komplett anderer Form in Live-Projekte schaffen.
Auch aus euren Ideen ziehen wir neuen & frischen Input!
Nach diesem Ereignisreichen Jahr gönnen wir uns eine schöpferische Pause und melden uns mitte Januar mit neuen, spannenden Tutorials, Tipps & Extensions zurück.
Wir wünschen allen Lesern ein frohes Weihnachtsfest und einen guten Start ins kommende Jahr 2010.
Johannes Teitge,
Daniel Sasse,
Igor Jankovic
Hallo, ich versuche gerad dieses Super Tool zum laufen zu bekommen, leider ohne Erfolg. Hab alles nach Anweisung gemacht. Schritt 5.- Template list.phtml anpassen, hab ich den hier vorgegebenen Code übernommen.
Meine Seite: http://www.winterbekleidung.com
Über eine Antwort/Hilfe bei der Fehlersuche würde ich mich sehr freuen.
Danke!
War diese Antwort hilfreich?
LikeDislikeDas Problem liegt wohl in der doppelten Integration von jQuery. Vermutlich bindet Autocomplete jQuery nochmals ein, was aus dem layout-xml entfernt werden sollte – falls man mit jQuery-Base und jQuery-Tools arbeitet.
Viele Grüße
Johannes Teitge
War diese Antwort hilfreich?
LikeDislikeDanke für die schnelle Antwort. Mit dem entfernen aus der layout.xml – da kenn ich mich nicht so aus…
Nützt es mir was, wenn ich jQuery Toole desinstalliere und auch Autocomplete?
Danke!
War diese Antwort hilfreich?
LikeDislikeHab nun jQueryTolls und Autocomplete deinstlliert. Dieses Tutorial nochmal neu gemacht, Schritt für Schritt…
Leider ohne Erfolg.
War diese Antwort hilfreich?
LikeDislikeHuhu,
möchte mich auch mal bedanken für eure klasse Beiträge und Erklärungen zu Magento!
Hab den jquery zoom (jedenfalls den normalen für standard Artikelbilder) schonmal installiert. Läuft bisher sehr gut, wobei ich jetzt an einem kleinen Problem häng
Wenn man bei einem Produkt kein Bild hochlädt und stattdessen nur das ‘Ersatzbild’ drinlässt funktioniert der jquery zoom nicht und meine komplette Shopseite ist verbuggt(man kann nichtsmehr in den Warenkorb legen, Preis wird nicht aktualisiert usw.). Wenn man allerdings ein Bild hochlädt funktioniert alles optimal, auch der Zoom natürlich
ist das nur bei mir so?
Liebe Grüße, Jenny
War diese Antwort hilfreich?
LikeDislike