This blog shows you how to create a portlet to be able to zoom in and out of an image. This portlet is web content driven using Liferay 6.2, jquery and animate.css. I have included all the source code for this project at the bottom of this page.

How it Looks:

When you first bring up the portlet, you see an image in a scrollbar with various points defined. The scrollbar is required & important. The points are defined using x & y coordinates, so to ensure they always point to the same location on the image, the image is not resizable. If this is viewed in on a mobile device, the scrollbar will appear with points pointing to the same spot on the image.


After you click on a point, you’ll see more details, as shown below. To close the image, click ‘close’ and the portlet zooms back to the original image.


Technical Details

  • This portlet uses animate.css to animate the images as they float into the viewport.
  • The Java portlet code basically does the following:
    • Looks up the web content using a specified tag.
    • Pulls the required values out of the web content, using the Liferay XML parsing API.
    • Instantiates a zoomable class and puts it into the request.

The Web Content structure contains the following fields:

  1. Title
  2. MainImage
  3. Repeatable Points, including
    1. Title
    2. Description
    3. Image
    4. X coordinate
    5. Y coordinate

The src for this structure is also in the ZoomableStructure.xml file inside the zip file at the bottom of this page.

Java Portlet Code

JournalArticle wc = JournoalArticleLocalServiceUtil.getArticle(groupId, String.valueOf(ae.getClassPK() - 2));
Document journalDoc =;
Document titleDoc =;Node mainImageNode = journalDoc.selectSingleNode(String.format("root/dynamic-element[@name='%1$s']/dynamic-content[@language-id='%2$s']", "mainImage", locale));
Node mainTitleNode = titleDoc.selectSingleNode(String.format("//Title[@language-id='%1$s']", locale));

z = new Zoomable(mainTitleNode.getText(), mainImageNode.getText());

Node root = journalDoc.getRootElement();

List<Node> pointNodes = root.selectNodes("/root/dynamic-element[@name='pointEnabled']");

ZoomPoint point;
for (int i = 0; i < pointNodes.size(); i++) {
Node pointNode = pointNodes.get(i);

Node enabledNode = pointNode.selectSingleNode(String.format("dynamic-content[@language-id='%1$s'][last()]",locale));
Node titleNode = pointNode.selectSingleNode(String.format("dynamic-element[@name='%1$s']/dynamic-content[@language-id='%2$s']", "title", locale));

if (Boolean.valueOf(enabledNode.getText())) {
Node descNode = pointNode.selectSingleNode(String.format("dynamic-element[@name='%1$s']/dynamic-content[@language-id='%2$s']", "description", locale));
Node imageNode = pointNode.selectSingleNode(String.format("dynamic-element[@name='%1$s']/dynamic-content[@language-id='%2$s']", "image", locale));
Node xNode = pointNode.selectSingleNode(String.format("dynamic-element[@name='%1$s']/dynamic-content[@language-id='%2$s']", "x", locale));
Node yNode = pointNode.selectSingleNode(String.format("dynamic-element[@name='%1$s']/dynamic-content[@language-id='%2$s']", "y", locale));


JSP snippet:

<div class="carousel-container animated fadeIn" style="overflow:auto">
<div class="row-fluid">
<div class="span10">
<h3 class="outside-text">
Zoom to see Details: <c:out value='${requestScope.zoomable.title}'/>
<div class="row-fluid options" >
<div class="main-module animated slideInRight">
<div class="tooltips animated bounceInDown">
<c:forEach var="point" items="${requestScope.zoomable.points}">
<div id="point3" class="rotate point modulePoint"
data-img="<c:out value='${point.image}'/>" data-title="<c:out value='${point.title}'/>" data-desc="<c:out value='${point.desc}'/>"
style="top:<c:out value='${point.y}'/>px;left: <c:out value='${point.x}'/>px;"
onClick="var image = $(this).attr('data-img');
$('.main-module > img').animate({zoom:1.3, opacity:0.0 }, 500);
$('.zoomImage > img').attr('src', image);
$('.zoom-module').css({display: 'block'});
<i class="fa fa-search-plus"></i>
<image src="<c:out value='${requestScope.zoomable.mainImage}'/>" />
<div class="zoom-module">
<div onClick="var points = $('.tooltips');
var zoomModule = $('.zoom-module');
$('.main-module > img').animate({zoom:1, opacity:1.0}, 500);
zoomModule.removeClass('animated fadeIn');
zoomModule.css({display: 'none'});
points.toggle();" id="zoomOut" class="close">
<span class="smalltext">Close<i class="fa fa-search-minus"></i></span>
<div class="row-fluid">
<div class="zoomText animated fadeIn span6">
<h2 id="zoomTitle"></h2>
<p id="zoomDesc"></p>
<div class="zoomImage animated slideInRight span6">
<img src="" style="">

Src code
Download ZoomIn-portlet src code.

Share This