How to add a zoom effect in opencart product page? - javascript

I am trying to make theme for opencart, I need add zoom effect in the product page and also user can also adjust their setting as per their need. but the zoomer is not working
I added one javascript file in the js folder the codes are:
//////////////////////////////////////////////////////////////////////////////////
// Cloud Zoom V1.0.2
// (c) 2010 by R Cecco. <http://www.professorcloud.com>
// MIT License
//
// Please retain this copyright header in all versions of the software
//////////////////////////////////////////////////////////////////////////////////
(function ($) {
$(document).ready(function () {
$('.product-zoom, .product-zoom-gallery').ProductZoom();
});
function format(str) {
for (var i = 1; i < arguments.length; i++) {
str = str.replace('%' + (i - 1), arguments[i]);
}
return str;
}
function ProductZoom(jWin, opts) {
var sImg = $('img', jWin);
var img1;
var img2;
var zoomDiv = null;
var $mouseTrap = null;
var lens = null;
var $tint = null;
var softFocus = null;
var $ie6Fix = null;
var zoomImage;
var controlTimer = 0;
var cw, ch;
var destU = 0;
var destV = 0;
var currV = 0;
var currU = 0;
var filesLoaded = 0;
var mx,
my;
var ctx = this, zw;
// Display an image loading message. This message gets deleted when the images have loaded and the zoom init function is called.
// We add a small delay before the message is displayed to avoid the message flicking on then off again virtually immediately if the
// images load really fast, e.g. from the cache.
//var ctx = this;
setTimeout(function () {
// <img src="/images/loading.gif"/>
if ($mouseTrap === null) {
var w = jWin.width();
jWin.parent().append(format('<div style="width:%0px;position:absolute;top:75%;left:%1px;text-align:center" class="product-zoom-loading" >Loading...</div>', w / 3, (w / 2) - (w / 6))).find(':last').css('opacity', 0.5);
}
}, 200);
var ie6FixRemove = function () {
if ($ie6Fix !== null) {
$ie6Fix.remove();
$ie6Fix = null;
}
};
// Removes cursor, tint layer, blur layer etc.
this.removeBits = function () {
//$mouseTrap.unbind();
if (lens) {
lens.remove();
lens = null;
}
if ($tint) {
$tint.remove();
$tint = null;
}
if (softFocus) {
softFocus.remove();
softFocus = null;
}
ie6FixRemove();
$('.product-zoom-loading', jWin.parent()).remove();
};
this.destroy = function () {
jWin.data('zoom', null);
if ($mouseTrap) {
$mouseTrap.unbind();
$mouseTrap.remove();
$mouseTrap = null;
}
if (zoomDiv) {
zoomDiv.remove();
zoomDiv = null;
}
//ie6FixRemove();
this.removeBits();
// DON'T FORGET TO REMOVE JQUERY 'DATA' VALUES
};
// This is called when the zoom window has faded out so it can be removed.
this.fadedOut = function () {
if (zoomDiv) {
zoomDiv.remove();
zoomDiv = null;
}
this.removeBits();
//ie6FixRemove();
};
this.controlLoop = function () {
if (lens) {
var x = (mx - sImg.offset().left - (cw * 0.5)) >> 0;
var y = (my - sImg.offset().top - (ch * 0.5)) >> 0;
if (x < 0) {
x = 0;
}
else if (x > (sImg.outerWidth() - cw)) {
x = (sImg.outerWidth() - cw);
}
if (y < 0) {
y = 0;
}
else if (y > (sImg.outerHeight() - ch)) {
y = (sImg.outerHeight() - ch);
}
lens.css({
left: x,
top: y
});
lens.css('background-position', (-x) + 'px ' + (-y) + 'px');
destU = (((x) / sImg.outerWidth()) * zoomImage.width) >> 0;
destV = (((y) / sImg.outerHeight()) * zoomImage.height) >> 0;
currU += (destU - currU) / opts.smoothMove;
currV += (destV - currV) / opts.smoothMove;
zoomDiv.css('background-position', (-(currU >> 0) + 'px ') + (-(currV >> 0) + 'px'));
}
controlTimer = setTimeout(function () {
ctx.controlLoop();
}, 30);
};
this.init2 = function (img, id) {
filesLoaded++;
//console.log(img.src + ' ' + id + ' ' + img.width);
if (id === 1) {
zoomImage = img;
}
//this.images[id] = img;
if (filesLoaded === 2) {
this.init();
}
};
/* Init function start. */
this.init = function () {
// Remove loading message (if present);
$('.product-zoom-loading', jWin.parent()).remove();
/* Add a box (mouseTrap) over the small image to trap mouse events.
It has priority over zoom window to avoid issues with inner zoom.
We need the dummy background image as IE does not trap mouse events on
transparent parts of a div.
*/
$mouseTrap = jWin.parent().append(format("<div class='mousetrap' style='background-image:url(\".\");z-index:199;position:absolute;width:%0px;height:%1px;left:%2px;top:%3px;\'></div>", sImg.outerWidth(), sImg.outerHeight(), 0, 0)).find(':last');
//////////////////////////////////////////////////////////////////////
/* Do as little as possible in mousemove event to prevent slowdown. */
$mouseTrap.bind('mousemove', this, function (event) {
// Just update the mouse position
mx = event.pageX;
my = event.pageY;
});
//////////////////////////////////////////////////////////////////////
$mouseTrap.bind('mouseleave', this, function (event) {
clearTimeout(controlTimer);
//event.data.removeBits();
if(lens) { lens.fadeOut(299); }
if($tint) { $tint.fadeOut(299); }
if(softFocus) { softFocus.fadeOut(299); }
zoomDiv.fadeOut(300, function () {
ctx.fadedOut();
});
return false;
});
//////////////////////////////////////////////////////////////////////
$mouseTrap.bind('mouseenter', this, function (event) {
mx = event.pageX;
my = event.pageY;
zw = event.data;
if (zoomDiv) {
zoomDiv.stop(true, false);
zoomDiv.remove();
}
var xPos = opts.adjustX,
yPos = opts.adjustY;
var siw = sImg.outerWidth();
var sih = sImg.outerHeight();
var w = opts.zoomWidth;
var h = opts.zoomHeight;
if (opts.zoomWidth == 'auto') {
w = siw;
}
if (opts.zoomHeight == 'auto') {
h = sih;
}
//$('#info').text( xPos + ' ' + yPos + ' ' + siw + ' ' + sih );
var appendTo = jWin.parent(); // attach to the wrapper
switch (opts.position) {
case 'top':
yPos -= h; // + opts.adjustY;
break;
case 'right':
xPos += siw; // + opts.adjustX;
break;
case 'bottom':
yPos += sih; // + opts.adjustY;
break;
case 'left':
xPos -= w; // + opts.adjustX;
break;
case 'inside':
w = siw;
h = sih;
break;
// All other values, try and find an id in the dom to attach to.
default:
appendTo = $('#' + opts.position);
// If dom element doesn't exit, just use 'right' position as default.
if (!appendTo.length) {
appendTo = jWin;
xPos += siw; //+ opts.adjustX;
yPos += sih; // + opts.adjustY;
} else {
w = appendTo.innerWidth();
h = appendTo.innerHeight();
}
}
zoomDiv = appendTo.append(format('<div id="product-zoom-big" class="product-zoom-big" style="display:none;position:absolute;left:%0px;top:-5px;width:395px;height:310px;background-image:url(\'%4\');z-index:99;"></div>', xPos, yPos, w, h, zoomImage.src)).find(':last');
// Add the title from title tag.
if (sImg.attr('title') && opts.showTitle) {
zoomDiv.append(format('<div class="product-zoom-title">%0</div>', sImg.attr('title'))).find(':last').css('opacity', opts.titleOpacity);
}
// Fix ie6 select elements wrong z-index bug. Placing an iFrame over the select element solves the issue...
if ($.browser.msie && $.browser.version < 7) {
$ie6Fix = $('<iframe frameborder="0" src="#"></iframe>').css({
position: "absolute",
left: xPos,
top: yPos,
zIndex: 99,
width: w,
height: h
}).insertBefore(zoomDiv);
}
zoomDiv.fadeIn(500);
if (lens) {
lens.remove();
lens = null;
} /* Work out size of cursor */
cw = (sImg.outerWidth() / zoomImage.width) * zoomDiv.width();
ch = (sImg.outerHeight() / zoomImage.height) * zoomDiv.height();
// Attach mouse, initially invisible to prevent first frame glitch
lens = jWin.append(format("<div class = 'product-zoom-lens' style='display:none;z-index:98;position:absolute;width:%0px;height:%1px;'></div>", cw, ch)).find(':last');
$mouseTrap.css('cursor', lens.css('cursor'));
var noTrans = false;
// Init tint layer if needed. (Not relevant if using inside mode)
if (opts.tint) {
lens.css('background', 'url("' + sImg.attr('src') + '")');
$tint = jWin.append(format('<div style="display:none;position:absolute; left:0px; top:0px; width:%0px; height:%1px; background-color:%2;" />', sImg.outerWidth(), sImg.outerHeight(), opts.tint)).find(':last');
$tint.css('opacity', opts.tintOpacity);
noTrans = true;
$tint.fadeIn(500);
}
if (opts.softFocus) {
lens.css('background', 'url("' + sImg.attr('src') + '")');
softFocus = jWin.append(format('<div style="position:absolute;display:none;top:2px; left:2px; width:%0px; height:%1px;" />', sImg.outerWidth() - 2, sImg.outerHeight() - 2, opts.tint)).find(':last');
softFocus.css('background', 'url("' + sImg.attr('src') + '")');
softFocus.css('opacity', 0.5);
noTrans = true;
softFocus.fadeIn(500);
}
if (!noTrans) {
lens.css('opacity', opts.lensOpacity);
}
if ( opts.position !== 'inside' ) { lens.fadeIn(500); }
// Start processing.
zw.controlLoop();
return; // Don't return false here otherwise opera will not detect change of the mouse pointer type.
});
};
img1 = new Image();
$(img1).load(function () {
ctx.init2(this, 0);
});
img1.src = sImg.attr('src');
img2 = new Image();
$(img2).load(function () {
ctx.init2(this, 1);
});
img2.src = jWin.attr('href');
}
$.fn.ProductZoom = function (options) {
// IE6 background image flicker fix
try {
document.execCommand("BackgroundImageCache", false, true);
} catch (e) {}
this.each(function () {
var relOpts, opts;
// Hmm...eval...slap on wrist.
eval('var a = {' + $(this).attr('rel') + '}');
relOpts = a;
if ($(this).is('.product-zoom')) {
$(this).css({
'position': 'relative',
'display': 'block'
});
$('img', $(this)).css({
'display': 'block'
});
// Wrap an outer div around the link so we can attach things without them becoming part of the link.
// But not if wrap already exists.
if ($(this).parent().attr('id') != 'wrap') {
$(this).wrap('<div id="wrap" style="top:0px;z-index:199;position:relative;"></div>');
}
opts = $.extend({}, $.fn.ProductZoom.defaults, options);
opts = $.extend({}, opts, relOpts);
$(this).data('zoom', new ProductZoom($(this), opts));
} else if ($(this).is('.product-zoom-gallery')) {
opts = $.extend({}, relOpts, options);
$(this).data('relOpts', opts);
$(this).bind('click', $(this), function (event) {
var data = event.data.data('relOpts');
// Destroy the previous zoom
$('#' + data.useZoom).data('zoom').destroy();
// Change the biglink to point to the new big image.
$('#' + data.useZoom).attr('href', event.data.attr('href'));
// Change the small image to point to the new small image.
$('#' + data.useZoom + ' img').attr('src', event.data.data('relOpts').smallImage);
// Init a new zoom with the new images.
$('#' + event.data.data('relOpts').useZoom).ProductZoom();
return false;
});
}
});
return this;
};
$.fn.ProductZoom.defaults = {
zoomWidth: 'auto',
zoomHeight: 'auto',
position: 'right',
tint: false,
tintOpacity: 0.5,
lensOpacity: 0.5,
softFocus: false,
smoothMove: 3,
showTitle: true,
titleOpacity: 0.5,
adjustX: 0,
adjustY: 0
};
})(jQuery);
and then added few codes in the product.tpl file
<script type="text/javascript" src="catalog/view/theme/mytheme/js/product-zoom.js"></script>
<div class="product-info">
<?php if ($thumb || $images) { ?>
<div class="left">
<?php if ($thumb) { ?>
<div class="image"><img src="<?php echo $thumb; ?>" title="<?php echo $heading_title; ?>" alt="<?php echo $heading_title; ?>" id="image" /></div>
<?php } ?>
<?php if ($images) { ?>
<div class="image-additional">
<img src="<?php echo $thumb1; ?>" alt="<?php echo $heading_title; ?>" title="<?php echo $heading_title; ?>"/>
<?php foreach ($images as $image) { ?>
<img src="<?php echo $image['thumb1']; ?>" title="<?php echo $heading_title; ?>" alt="<?php echo $heading_title; ?>" />
<?php } ?>
</div>
<?php } ?>
</div>

Try this
Add this js file
//////////////////////////////////////////////////////////////////////////////////
// Cloud Zoom V1.0.2
// (c) 2010 by R Cecco. <http://www.professorcloud.com>
// MIT License
//
// Please retain this copyright header in all versions of the software
//////////////////////////////////////////////////////////////////////////////////
(function ($) {
$(document).ready(function () {
$('.cloud-zoom, .cloud-zoom-gallery').CloudZoom();
});
function format(str) {
for (var i = 1; i < arguments.length; i++) {
str = str.replace('%' + (i - 1), arguments[i]);
}
return str;
}
function CloudZoom(jWin, opts) {
var sImg = $('img', jWin);
var img1;
var img2;
var zoomDiv = null;
var $mouseTrap = null;
var lens = null;
var $tint = null;
var softFocus = null;
var $ie6Fix = null;
var zoomImage;
var controlTimer = 0;
var cw, ch;
var destU = 0;
var destV = 0;
var currV = 0;
var currU = 0;
var filesLoaded = 0;
var mx,
my;
var ctx = this, zw;
// Display an image loading message. This message gets deleted when the images have loaded and the zoom init function is called.
// We add a small delay before the message is displayed to avoid the message flicking on then off again virtually immediately if the
// images load really fast, e.g. from the cache.
//var ctx = this;
setTimeout(function () {
// <img src="/images/loading.gif"/>
if ($mouseTrap === null) {
var w = jWin.width();
jWin.parent().append(format('<div style="width:%0px;position:absolute;top:75%;left:%1px;text-align:center" class="cloud-zoom-loading" >Loading...</div>', w / 3, (w / 2) - (w / 6))).find(':last').css('opacity', 0.5);
}
}, 200);
var ie6FixRemove = function () {
if ($ie6Fix !== null) {
$ie6Fix.remove();
$ie6Fix = null;
}
};
// Removes cursor, tint layer, blur layer etc.
this.removeBits = function () {
//$mouseTrap.unbind();
if (lens) {
lens.remove();
lens = null;
}
if ($tint) {
$tint.remove();
$tint = null;
}
if (softFocus) {
softFocus.remove();
softFocus = null;
}
ie6FixRemove();
$('.cloud-zoom-loading', jWin.parent()).remove();
};
this.destroy = function () {
jWin.data('zoom', null);
if ($mouseTrap) {
$mouseTrap.unbind();
$mouseTrap.remove();
$mouseTrap = null;
}
if (zoomDiv) {
zoomDiv.remove();
zoomDiv = null;
}
//ie6FixRemove();
this.removeBits();
// DON'T FORGET TO REMOVE JQUERY 'DATA' VALUES
};
// This is called when the zoom window has faded out so it can be removed.
this.fadedOut = function () {
if (zoomDiv) {
zoomDiv.remove();
zoomDiv = null;
}
this.removeBits();
//ie6FixRemove();
};
this.controlLoop = function () {
if (lens) {
var x = (mx - sImg.offset().left - (cw * 0.5)) >> 0;
var y = (my - sImg.offset().top - (ch * 0.5)) >> 0;
if (x < 0) {
x = 0;
}
else if (x > (sImg.outerWidth() - cw)) {
x = (sImg.outerWidth() - cw);
}
if (y < 0) {
y = 0;
}
else if (y > (sImg.outerHeight() - ch)) {
y = (sImg.outerHeight() - ch);
}
lens.css({
left: x,
top: y
});
lens.css('background-position', (-x) + 'px ' + (-y) + 'px');
destU = (((x) / sImg.outerWidth()) * zoomImage.width) >> 0;
destV = (((y) / sImg.outerHeight()) * zoomImage.height) >> 0;
currU += (destU - currU) / opts.smoothMove;
currV += (destV - currV) / opts.smoothMove;
zoomDiv.css('background-position', (-(currU >> 0) + 'px ') + (-(currV >> 0) + 'px'));
}
controlTimer = setTimeout(function () {
ctx.controlLoop();
}, 30);
};
this.init2 = function (img, id) {
filesLoaded++;
//console.log(img.src + ' ' + id + ' ' + img.width);
if (id === 1) {
zoomImage = img;
}
//this.images[id] = img;
if (filesLoaded === 2) {
this.init();
}
};
/* Init function start. */
this.init = function () {
// Remove loading message (if present);
$('.cloud-zoom-loading', jWin.parent()).remove();
/* Add a box (mouseTrap) over the small image to trap mouse events.
It has priority over zoom window to avoid issues with inner zoom.
We need the dummy background image as IE does not trap mouse events on
transparent parts of a div.
*/
$mouseTrap = jWin.parent().append(format("<div class='mousetrap' style='background-image:url(\".\");z-index:999;position:absolute;width:%0px;height:%1px;left:%2px;top:%3px;\'></div>", sImg.outerWidth(), sImg.outerHeight(), 0, 0)).find(':last');
//////////////////////////////////////////////////////////////////////
/* Do as little as possible in mousemove event to prevent slowdown. */
$mouseTrap.bind('mousemove', this, function (event) {
// Just update the mouse position
mx = event.pageX;
my = event.pageY;
});
//////////////////////////////////////////////////////////////////////
$mouseTrap.bind('mouseleave', this, function (event) {
$('#zoomer').fadeIn(50);
clearTimeout(controlTimer);
//event.data.removeBits();
if(lens) { lens.fadeOut(299); }
if($tint) { $tint.fadeOut(299); }
if(softFocus) { softFocus.fadeOut(299); }
zoomDiv.fadeOut(300, function () {
ctx.fadedOut();
});
return false;
});
//////////////////////////////////////////////////////////////////////
$mouseTrap.bind('mouseenter', this, function (event) {
$('#zoomer').fadeOut(50);
mx = event.pageX;
my = event.pageY;
zw = event.data;
if (zoomDiv) {
zoomDiv.stop(true, false);
zoomDiv.remove();
}
var xPos = opts.adjustX,
yPos = opts.adjustY;
var siw = sImg.outerWidth();
var sih = sImg.outerHeight();
var w = opts.zoomWidth;
var h = opts.zoomHeight;
if (opts.zoomWidth == 'auto') {
w = siw;
}
if (opts.zoomHeight == 'auto') {
h = sih;
}
//$('#info').text( xPos + ' ' + yPos + ' ' + siw + ' ' + sih );
var appendTo = jWin.parent(); // attach to the wrapper
switch (opts.position) {
case 'top':
yPos -= h; // + opts.adjustY;
break;
case 'right':
xPos += siw; // + opts.adjustX;
break;
case 'bottom':
yPos += sih; // + opts.adjustY;
break;
case 'left':
xPos -= w; // + opts.adjustX;
break;
case 'inside':
w = siw;
h = sih;
break;
// All other values, try and find an id in the dom to attach to.
default:
appendTo = $('#' + opts.position);
// If dom element doesn't exit, just use 'right' position as default.
if (!appendTo.length) {
appendTo = jWin;
xPos += siw; //+ opts.adjustX;
yPos += sih; // + opts.adjustY;
} else {
w = appendTo.innerWidth();
h = appendTo.innerHeight();
}
}
zoomDiv = appendTo.append(format('<div id="cloud-zoom-big" class="cloud-zoom-big" style="display:none;position:absolute;left:%0px;top:%1px;width:%2px;height:%3px;background-image:url(\'%4\');z-index:99;"></div>', xPos, yPos, w, h, zoomImage.src)).find(':last');
// Add the title from title tag.
if (sImg.attr('title') && opts.showTitle) {
zoomDiv.append(format('<div class="cloud-zoom-title">%0</div>', sImg.attr('title'))).find(':last').css('opacity', opts.titleOpacity);
}
// Fix ie6 select elements wrong z-index bug. Placing an iFrame over the select element solves the issue...
if ($.browser.msie && $.browser.version < 7) {
$ie6Fix = $('<iframe frameborder="0" src="#"></iframe>').css({
position: "absolute",
left: xPos,
top: yPos,
zIndex: 99,
width: w,
height: h
}).insertBefore(zoomDiv);
}
zoomDiv.fadeIn(500);
if (lens) {
lens.remove();
lens = null;
} /* Work out size of cursor */
cw = (sImg.outerWidth() / zoomImage.width) * zoomDiv.width();
ch = (sImg.outerHeight() / zoomImage.height) * zoomDiv.height();
// Attach mouse, initially invisible to prevent first frame glitch
lens = jWin.append(format("<div class = 'cloud-zoom-lens' style='display:none;z-index:98;position:absolute;width:%0px;height:%1px;'></div>", cw, ch)).find(':last');
$mouseTrap.css('cursor', lens.css('cursor'));
var noTrans = false;
// Init tint layer if needed. (Not relevant if using inside mode)
if (opts.tint) {
lens.css('background', 'url("' + sImg.attr('src') + '")');
$tint = jWin.append(format('<div style="display:none;position:absolute; left:0px; top:0px; width:%0px; height:%1px; background-color:%2;" />', sImg.outerWidth(), sImg.outerHeight(), opts.tint)).find(':last');
$tint.css('opacity', opts.tintOpacity);
noTrans = true;
$tint.fadeIn(500);
}
if (opts.softFocus) {
lens.css('background', 'url("' + sImg.attr('src') + '")');
softFocus = jWin.append(format('<div style="position:absolute;display:none;top:2px; left:2px; width:%0px; height:%1px;" />', sImg.outerWidth() - 2, sImg.outerHeight() - 2, opts.tint)).find(':last');
softFocus.css('background', 'url("' + sImg.attr('src') + '")');
softFocus.css('opacity', 0.5);
noTrans = true;
softFocus.fadeIn(500);
}
if (!noTrans) {
lens.css('opacity', opts.lensOpacity);
}
if ( opts.position !== 'inside' ) { lens.fadeIn(500); }
// Start processing.
zw.controlLoop();
return; // Don't return false here otherwise opera will not detect change of the mouse pointer type.
});
};
img1 = new Image();
$(img1).load(function () {
ctx.init2(this, 0);
});
img1.src = sImg.attr('src');
img2 = new Image();
$(img2).load(function () {
ctx.init2(this, 1);
});
img2.src = jWin.attr('href');
}
$.fn.CloudZoom = function (options) {
// IE6 background image flicker fix
try {
document.execCommand("BackgroundImageCache", false, true);
} catch (e) {}
this.each(function () {
var relOpts, opts;
// Hmm...eval...slap on wrist.
eval('var a = {' + $(this).attr('rel') + '}');
relOpts = a;
if ($(this).is('.cloud-zoom')) {
$(this).css({
'position': 'relative',
'display': 'block'
});
$('img', $(this)).css({
'display': 'block'
});
// Wrap an outer div around the link so we can attach things without them becoming part of the link.
// But not if wrap already exists.
if ($(this).parent().attr('id') != 'wrap') {
$(this).wrap('<div id="wrap" style="top:0px;z-index:1000;position:relative;"></div>');
}
opts = $.extend({}, $.fn.CloudZoom.defaults, options);
opts = $.extend({}, opts, relOpts);
$(this).data('zoom', new CloudZoom($(this), opts));
} else if ($(this).is('.cloud-zoom-gallery')) {
opts = $.extend({}, relOpts, options);
$(this).data('relOpts', opts);
$(this).bind('click', $(this), function (event) {
var data = event.data.data('relOpts');
// Destroy the previous zoom
$('#' + data.useZoom).data('zoom').destroy();
// Change the biglink to point to the new big image.
$('#' + data.useZoom).attr('href', event.data.attr('href'));
// Change the ZOOM link to point to the new big image.
$('#zoomer').attr('href', event.data.attr('href'));
// Change the small image to point to the new small image.
$('#' + data.useZoom + ' img').attr('src', event.data.data('relOpts').smallImage);
// Init a new zoom with the new images.
$('#' + event.data.data('relOpts').useZoom).CloudZoom();
return false;
});
}
});
return this;
};
$.fn.CloudZoom.defaults = {
zoomWidth: 'auto',
zoomHeight: 'auto',
position: 'right',
tint: false,
tintOpacity: 0.5,
lensOpacity: 0.5,
softFocus: false,
smoothMove: 3,
showTitle: false,
titleOpacity: 0.5,
adjustX: 0,
adjustY: 0
};
})(jQuery);
add in the product.tpl file
<script type="text/javascript" src="catalog/view/theme/mytheme/js/product-zoom.js"></script>
<div class="product-info">
<?php if ($thumb || $images) { ?>
<div class="left">
<?php if ($thumb) { ?>
<div class="image"><img src="<?php echo $thumb; ?>" title="<?php echo $heading_title; ?>" alt="<?php echo $heading_title; ?>" id="image" /><span id="zoom-image"><i class="zoom_bttn"></i> Zoom</span></div>
<?php } ?>
<?php if ($images) { ?>
<div class="image-additional">
<img src="<?php echo $thumb; ?>" title="<?php echo $heading_title; ?>" alt="<?php echo $heading_title; ?>" />
<?php foreach ($images as $image) { ?>
<img src="<?php echo $image['thumb']; ?>" width="62" title="<?php echo $heading_title; ?>" alt="<?php echo $heading_title; ?>" />
<?php } ?>
</div>
<?php } ?>
</div>
<?php } ?>

Related

Trying to add ALT tag within popup lightbox Lightbox2 for ADA Compliance Standards

I am updating a client's site to include alt tags to bring their site to ADA compliance. I have a few pages that use Lightbox2 from https://lokeshdhakar.com/projects/lightbox2. I added the ALT attribute to my array, but it's not being called in the script, so didn't get added.
<img src="images/slide-show/at-the-beach-boys-th.jpg" alt="Small boys use sand toys on Long Sands Beach." width="256" height="176" />
I have tried to edit the lightbox.js to include the alt tag call, but have not been successful.
Contents of lightbox.js
// -----------------------------------------------------------------------------------
//
// Lightbox v2.03.3
// by Lokesh Dhakar - http://www.huddletogether.com
// 5/21/06
//
// For more information on this script, visit:
// http://huddletogether.com/projects/lightbox2/
//
// Licensed under the Creative Commons Attribution 2.5 License - http://creativecommons.org/licenses/by/2.5/
//
// Credit also due to those who have helped, inspired, and made their code available to the public.
// Including: Scott Upton(uptonic.com), Peter-Paul Koch(quirksmode.com), Thomas Fuchs(mir.aculo.us), and others.
//
//
// -----------------------------------------------------------------------------------
/*
Table of Contents
-----------------
Configuration
Global Variables
Extending Built-in Objects
- Object.extend(Element)
- Array.prototype.removeDuplicates()
- Array.prototype.empty()
Lightbox Class Declaration
- initialize()
- updateImageList()
- start()
- changeImage()
- resizeImageContainer()
- showImage()
- updateDetails()
- updateNav()
- enableKeyboardNav()
- disableKeyboardNav()
- keyboardAction()
- preloadNeighborImages()
- end()
Miscellaneous Functions
- getPageScroll()
- getPageSize()
- getKey()
- listenKey()
- showSelectBoxes()
- hideSelectBoxes()
- showFlash()
- hideFlash()
- pause()
- initLightbox()
Function Calls
- addLoadEvent(initLightbox)
*/
// -----------------------------------------------------------------------------------
//
// Configuration
//
var fileLoadingImage = "../lightbox_assets/images/loading.gif";
var fileBottomNavCloseImage = "../lightbox_assets/images/closelabel.gif";
var overlayOpacity = 0.8; // controls transparency of shadow overlay
var animate = true; // toggles resizing animations
var resizeSpeed = 7; // controls the speed of the image resizing animations (1=slowest and 10=fastest)
var borderSize = 10; //if you adjust the padding in the CSS, you will need to update this variable
// -----------------------------------------------------------------------------------
//
// Global Variables
//
var imageArray = new Array;
var activeImage;
if(animate == true){
overlayDuration = 0.2; // shadow fade in/out duration
if(resizeSpeed > 10){ resizeSpeed = 10;}
if(resizeSpeed < 1){ resizeSpeed = 1;}
resizeDuration = (11 - resizeSpeed) * 0.15;
} else {
overlayDuration = 0;
resizeDuration = 0;
}
// -----------------------------------------------------------------------------------
//
// Additional methods for Element added by SU, Couloir
// - further additions by Lokesh Dhakar (huddletogether.com)
//
Object.extend(Element, {
getWidth: function(element) {
element = $(element);
return element.offsetWidth;
},
setWidth: function(element,w) {
element = $(element);
element.style.width = w +"px";
},
setHeight: function(element,h) {
element = $(element);
element.style.height = h +"px";
},
setTop: function(element,t) {
element = $(element);
element.style.top = t +"px";
},
setLeft: function(element,l) {
element = $(element);
element.style.left = l +"px";
},
setSrc: function(element,src) {
element = $(element);
element.src = src;
},
setHref: function(element,href) {
element = $(element);
element.href = href;
},
setInnerHTML: function(element,content) {
element = $(element);
element.innerHTML = content;
}
});
// -----------------------------------------------------------------------------------
//
// Extending built-in Array object
// - array.removeDuplicates()
// - array.empty()
//
Array.prototype.removeDuplicates = function () {
for(i = 0; i < this.length; i++){
for(j = this.length-1; j>i; j--){
if(this[i][0] == this[j][0]){
this.splice(j,1);
}
}
}
}
// -----------------------------------------------------------------------------------
Array.prototype.empty = function () {
for(i = 0; i <= this.length; i++){
this.shift();
}
}
// -----------------------------------------------------------------------------------
//
// Lightbox Class Declaration
// - initialize()
// - start()
// - changeImage()
// - resizeImageContainer()
// - showImage()
// - updateDetails()
// - updateNav()
// - enableKeyboardNav()
// - disableKeyboardNav()
// - keyboardNavAction()
// - preloadNeighborImages()
// - end()
//
// Structuring of code inspired by Scott Upton (http://www.uptonic.com/)
//
var Lightbox = Class.create();
Lightbox.prototype = {
// initialize()
// Constructor runs on completion of the DOM loading. Calls updateImageList and then
// the function inserts html at the bottom of the page which is used to display the shadow
// overlay and the image container.
//
initialize: function() {
this.updateImageList();
// Code inserts html at the bottom of the page that looks similar to this:
//
// <div id="overlay"></div>
// <div id="lightbox">
// <div id="outerImageContainer">
// <div id="imageContainer">
// <img id="lightboxImage" alt="container for enlarged images">
// <div style="" id="hoverNav">
//
//
// </div>
// <div id="loading">
// <a href="#" id="loadingLink">
// <img src="images/loading.gif" alt"Waiting to load">
// </a>
// </div>
// </div>
// </div>
// <div id="imageDataContainer">
// <div id="imageData">
// <div id="imageDetails">
// <span id="caption"></span>
// <span id="numberDisplay"></span>
// </div>
// <div id="bottomNav">
// <a href="#" id="bottomNavClose">
// <img src="../images/close.gif" alt="X graphic to close lightbox">
// </a>
// </div>
// </div>
// </div>
// </div>
var objBody = document.getElementsByTagName("body").item(0);
var objOverlay = document.createElement("div");
objOverlay.setAttribute('id','overlay');
objOverlay.style.display = 'none';
objOverlay.onclick = function() { myLightbox.end(); }
objBody.appendChild(objOverlay);
var objLightbox = document.createElement("div");
objLightbox.setAttribute('id','lightbox');
objLightbox.style.display = 'none';
objLightbox.onclick = function(e) { // close Lightbox is user clicks shadow overlay
if (!e) var e = window.event;
var clickObj = Event.element(e).id;
if ( clickObj == 'lightbox') {
myLightbox.end();
}
};
objBody.appendChild(objLightbox);
var objOuterImageContainer = document.createElement("div");
objOuterImageContainer.setAttribute('id','outerImageContainer');
objLightbox.appendChild(objOuterImageContainer);
// When Lightbox starts it will resize itself from 250 by 250 to the current image dimension.
// If animations are turned off, it will be hidden as to prevent a flicker of a
// white 250 by 250 box.
if(animate){
Element.setWidth('outerImageContainer', 250);
Element.setHeight('outerImageContainer', 250);
} else {
Element.setWidth('outerImageContainer', 1);
Element.setHeight('outerImageContainer', 1);
}
var objImageContainer = document.createElement("div");
objImageContainer.setAttribute('id','imageContainer');
objOuterImageContainer.appendChild(objImageContainer);
var objLightboxImage = document.createElement("img");
objLightboxImage.setAttribute('id','lightboxImage');
objImageContainer.appendChild(objLightboxImage);
var objHoverNav = document.createElement("div");
objHoverNav.setAttribute('id','hoverNav');
objImageContainer.appendChild(objHoverNav);
var objPrevLink = document.createElement("a");
objPrevLink.setAttribute('id','prevLink');
objPrevLink.setAttribute('href','#');
objHoverNav.appendChild(objPrevLink);
var objNextLink = document.createElement("a");
objNextLink.setAttribute('id','nextLink');
objNextLink.setAttribute('href','#');
objHoverNav.appendChild(objNextLink);
var objLoading = document.createElement("div");
objLoading.setAttribute('id','loading');
objImageContainer.appendChild(objLoading);
var objLoadingLink = document.createElement("a");
objLoadingLink.setAttribute('id','loadingLink');
objLoadingLink.setAttribute('href','#');
objLoadingLink.onclick = function() { myLightbox.end(); return false; }
objLoading.appendChild(objLoadingLink);
var objLoadingImage = document.createElement("img");
objLoadingImage.setAttribute('src', fileLoadingImage);
objLoadingImage.setAttribute('alt', 'Image Loading icon');
objLoadingLink.appendChild(objLoadingImage);
var objImageDataContainer = document.createElement("div");
objImageDataContainer.setAttribute('id','imageDataContainer');
objLightbox.appendChild(objImageDataContainer);
var objImageData = document.createElement("div");
objImageData.setAttribute('id','imageData');
objImageDataContainer.appendChild(objImageData);
var objImageDetails = document.createElement("div");
objImageDetails.setAttribute('id','imageDetails');
objImageData.appendChild(objImageDetails);
var objCaption = document.createElement("span");
objCaption.setAttribute('id','caption');
objImageDetails.appendChild(objCaption);
var objNumberDisplay = document.createElement("span");
objNumberDisplay.setAttribute('id','numberDisplay');
objImageDetails.appendChild(objNumberDisplay);
var objBottomNav = document.createElement("div");
objBottomNav.setAttribute('id','bottomNav');
objImageData.appendChild(objBottomNav);
var objBottomNavCloseLink = document.createElement("a");
objBottomNavCloseLink.setAttribute('id','bottomNavClose');
objBottomNavCloseLink.setAttribute('href','#');
objBottomNavCloseLink.onclick = function() { myLightbox.end(); return false; }
objBottomNav.appendChild(objBottomNavCloseLink);
var objBottomNavCloseImage = document.createElement("img");
objBottomNavCloseImage.setAttribute('src', fileBottomNavCloseImage);
objBottomNavCloseImage.setAttribute('alt', 'CLOSE X');
objBottomNavCloseLink.appendChild(objBottomNavCloseImage);
},
//
// updateImageList()
// Loops through anchor tags looking for 'lightbox' references and applies onclick
// events to appropriate links. You can rerun after dynamically adding images w/ajax.
//
updateImageList: function() {
if (!document.getElementsByTagName){ return; }
var anchors = document.getElementsByTagName('a');
var areas = document.getElementsByTagName('area');
// loop through all anchor tags
for (var i=0; i<anchors.length; i++){
var anchor = anchors[i];
var relAttribute = String(anchor.getAttribute('rel'));
// use the string.match() method to catch 'lightbox' references in the rel attribute
if (anchor.getAttribute('href') && (relAttribute.toLowerCase().match('lightbox'))){
anchor.onclick = function () {myLightbox.start(this); return false;}
}
}
// loop through all area tags
// todo: combine anchor & area tag loops
for (var i=0; i< areas.length; i++){
var area = areas[i];
var relAttribute = String(area.getAttribute('rel'));
// use the string.match() method to catch 'lightbox' references in the rel attribute
if (area.getAttribute('href') && (relAttribute.toLowerCase().match('lightbox'))){
area.onclick = function () {myLightbox.start(this); return false;}
}
}
},
//
// start()
// Display overlay and lightbox. If image is part of a set, add siblings to imageArray.
//
start: function(imageLink) {
hideSelectBoxes();
hideFlash();
// stretch overlay to fill page and fade in
var arrayPageSize = getPageSize();
Element.setWidth('overlay', arrayPageSize[0]);
Element.setHeight('overlay', arrayPageSize[1]);
new Effect.Appear('overlay', { duration: overlayDuration, from: 0.0, to: overlayOpacity });
imageArray = [];
imageNum = 0;
if (!document.getElementsByTagName){ return; }
var anchors = document.getElementsByTagName( imageLink.tagName);
// if image is NOT part of a set..
if((imageLink.getAttribute('rel') == 'lightbox')){
// add single image to imageArray
imageArray.push(new Array(imageLink.getAttribute('href'), imageLink.getAttribute('title')));
} else {
// if image is part of a set..
// loop through anchors, find other images in set, and add them to imageArray
for (var i=0; i<anchors.length; i++){
var anchor = anchors[i];
if (anchor.getAttribute('href') && (anchor.getAttribute('rel') == imageLink.getAttribute('rel'))){
imageArray.push(new Array(anchor.getAttribute('href'), anchor.getAttribute('title')));
}
}
imageArray.removeDuplicates();
while(imageArray[imageNum][0] != imageLink.getAttribute('href')) { imageNum++;}
}
// calculate top and left offset for the lightbox
var arrayPageScroll = getPageScroll();
var lightboxTop = arrayPageScroll[1] + (arrayPageSize[3] / 10);
var lightboxLeft = arrayPageScroll[0];
Element.setTop('lightbox', lightboxTop);
Element.setLeft('lightbox', lightboxLeft);
Element.show('lightbox');
this.changeImage(imageNum);
},
//
// changeImage()
// Hide most elements and preload image in preparation for resizing image container.
//
changeImage: function(imageNum) {
activeImage = imageNum; // update global var
// hide elements during transition
if(animate){ Element.show('loading');}
Element.hide('lightboxImage');
Element.hide('alt');
Element.hide('hoverNav');
Element.hide('prevLink');
Element.hide('nextLink');
Element.hide('imageDataContainer');
Element.hide('numberDisplay');
imgPreloader = new Image();
// once image is preloaded, resize image container
imgPreloader.onload=function(){
Element.setSrc('lightboxImage', imageArray[activeImage][0]);
myLightbox.resizeImageContainer(imgPreloader.width, imgPreloader.height);
imgPreloader.onload=function(){}; // clear onLoad, IE behaves irratically with animated gifs otherwise
}
imgPreloader.src = imageArray[activeImage][0];
},
//
// resizeImageContainer()
//
resizeImageContainer: function( imgWidth, imgHeight) {
// get curren width and height
this.widthCurrent = Element.getWidth('outerImageContainer');
this.heightCurrent = Element.getHeight('outerImageContainer');
// get new width and height
var widthNew = (imgWidth + (borderSize * 2));
var heightNew = (imgHeight + (borderSize * 2));
// scalars based on change from old to new
this.xScale = ( widthNew / this.widthCurrent) * 100;
this.yScale = ( heightNew / this.heightCurrent) * 100;
// calculate size difference between new and old image, and resize if necessary
wDiff = this.widthCurrent - widthNew;
hDiff = this.heightCurrent - heightNew;
if(!( hDiff == 0)){ new Effect.Scale('outerImageContainer', this.yScale, {scaleX: false, duration: resizeDuration, queue: 'front'}); }
if(!( wDiff == 0)){ new Effect.Scale('outerImageContainer', this.xScale, {scaleY: false, delay: resizeDuration, duration: resizeDuration}); }
// if new and old image are same size and no scaling transition is necessary,
// do a quick pause to prevent image flicker.
if((hDiff == 0) && (wDiff == 0)){
if (navigator.appVersion.indexOf("MSIE")!=-1){ pause(250); } else { pause(100);}
}
Element.setHeight('prevLink', imgHeight);
Element.setHeight('nextLink', imgHeight);
Element.setWidth( 'imageDataContainer', widthNew);
this.showImage();
},
//
// showImage()
// Display image and begin preloading neighbors.
//
showImage: function(){
Element.hide('loading');
new Effect.Appear('lightboxImage', { duration: resizeDuration, queue: 'end', afterFinish: function(){ myLightbox.updateDetails(); } });
this.preloadNeighborImages();
},
//
// updateDetails()
// Display caption, image number, and bottom nav.
//
updateDetails: function() {
// if caption is not null
if(imageArray[activeImage][1]){
Element.show('caption');
Element.setInnerHTML( 'caption', imageArray[activeImage][1]);
}
// if image is part of set display 'Image x of x'
if(imageArray.length > 1){
Element.show('numberDisplay');
Element.setInnerHTML( 'numberDisplay', "Image " + eval(activeImage + 1) + " of " + imageArray.length);
}
new Effect.Parallel(
[ new Effect.SlideDown( 'imageDataContainer', { sync: true, duration: resizeDuration, from: 0.0, to: 1.0 }),
new Effect.Appear('imageDataContainer', { sync: true, duration: resizeDuration }) ],
{ duration: resizeDuration, afterFinish: function() {
// update overlay size and update nav
var arrayPageSize = getPageSize();
Element.setHeight('overlay', arrayPageSize[1]);
myLightbox.updateNav();
}
}
);
},
//
// updateNav()
// Display appropriate previous and next hover navigation.
//
updateNav: function() {
Element.show('hoverNav');
// if not first image in set, display prev image button
if(activeImage != 0){
Element.show('prevLink');
document.getElementById('prevLink').onclick = function() {
myLightbox.changeImage(activeImage - 1); return false;
}
}
// if not last image in set, display next image button
if(activeImage != (imageArray.length - 1)){
Element.show('nextLink');
document.getElementById('nextLink').onclick = function() {
myLightbox.changeImage(activeImage + 1); return false;
}
}
this.enableKeyboardNav();
},
//
// enableKeyboardNav()
//
enableKeyboardNav: function() {
document.onkeydown = this.keyboardAction;
},
//
// disableKeyboardNav()
//
disableKeyboardNav: function() {
document.onkeydown = '';
},
//
// keyboardAction()
//
keyboardAction: function(e) {
if (e == null) { // ie
keycode = event.keyCode;
escapeKey = 27;
} else { // mozilla
keycode = e.keyCode;
escapeKey = e.DOM_VK_ESCAPE;
}
key = String.fromCharCode(keycode).toLowerCase();
if((key == 'x') || (key == 'o') || (key == 'c') || (keycode == escapeKey)){ // close lightbox
myLightbox.end();
} else if((key == 'p') || (keycode == 37)){ // display previous image
if(activeImage != 0){
myLightbox.disableKeyboardNav();
myLightbox.changeImage(activeImage - 1);
}
} else if((key == 'n') || (keycode == 39)){ // display next image
if(activeImage != (imageArray.length - 1)){
myLightbox.disableKeyboardNav();
myLightbox.changeImage(activeImage + 1);
}
}
},
//
// preloadNeighborImages()
// Preload previous and next images.
//
preloadNeighborImages: function(){
if((imageArray.length - 1) > activeImage){
preloadNextImage = new Image();
preloadNextImage.src = imageArray[activeImage + 1][0];
}
if(activeImage > 0){
preloadPrevImage = new Image();
preloadPrevImage.src = imageArray[activeImage - 1][0];
}
},
//
// end()
//
end: function() {
this.disableKeyboardNav();
Element.hide('lightbox');
new Effect.Fade('overlay', { duration: overlayDuration});
showSelectBoxes();
showFlash();
}
}
// -----------------------------------------------------------------------------------
//
// getPageScroll()
// Returns array with x,y page scroll values.
// Core code from - quirksmode.com
//
function getPageScroll(){
var xScroll, yScroll;
if (self.pageYOffset) {
yScroll = self.pageYOffset;
xScroll = self.pageXOffset;
} else if (document.documentElement && document.documentElement.scrollTop){ // Explorer 6 Strict
yScroll = document.documentElement.scrollTop;
xScroll = document.documentElement.scrollLeft;
} else if (document.body) {// all other Explorers
yScroll = document.body.scrollTop;
xScroll = document.body.scrollLeft;
}
arrayPageScroll = new Array(xScroll,yScroll)
return arrayPageScroll;
}
// -----------------------------------------------------------------------------------
//
// getPageSize()
// Returns array with page width, height and window width, height
// Core code from - quirksmode.com
// Edit for Firefox by pHaez
//
function getPageSize(){
var xScroll, yScroll;
if (window.innerHeight && window.scrollMaxY) {
xScroll = window.innerWidth + window.scrollMaxX;
yScroll = window.innerHeight + window.scrollMaxY;
} else if (document.body.scrollHeight > document.body.offsetHeight){ // all but Explorer Mac
xScroll = document.body.scrollWidth;
yScroll = document.body.scrollHeight;
} else { // Explorer Mac...would also work in Explorer 6 Strict, Mozilla and Safari
xScroll = document.body.offsetWidth;
yScroll = document.body.offsetHeight;
}
var windowWidth, windowHeight;
// console.log(self.innerWidth);
// console.log(document.documentElement.clientWidth);
if (self.innerHeight) { // all except Explorer
if(document.documentElement.clientWidth){
windowWidth = document.documentElement.clientWidth;
} else {
windowWidth = self.innerWidth;
}
windowHeight = self.innerHeight;
} else if (document.documentElement && document.documentElement.clientHeight) { // Explorer 6 Strict Mode
windowWidth = document.documentElement.clientWidth;
windowHeight = document.documentElement.clientHeight;
} else if (document.body) { // other Explorers
windowWidth = document.body.clientWidth;
windowHeight = document.body.clientHeight;
}
// for small pages with total height less then height of the viewport
if(yScroll < windowHeight){
pageHeight = windowHeight;
} else {
pageHeight = yScroll;
}
// console.log("xScroll " + xScroll)
// console.log("windowWidth " + windowWidth)
// for small pages with total width less then width of the viewport
if(xScroll < windowWidth){
pageWidth = xScroll;
} else {
pageWidth = windowWidth;
}
// console.log("pageWidth " + pageWidth)
arrayPageSize = new Array(pageWidth,pageHeight,windowWidth,windowHeight)
return arrayPageSize;
}
// -----------------------------------------------------------------------------------
//
// getKey(key)
// Gets keycode. If 'x' is pressed then it hides the lightbox.
//
function getKey(e){
if (e == null) { // ie
keycode = event.keyCode;
} else { // mozilla
keycode = e.which;
}
key = String.fromCharCode(keycode).toLowerCase();
if(key == 'x'){
}
}
// -----------------------------------------------------------------------------------
//
// listenKey()
//
function listenKey () { document.onkeypress = getKey; }
// ---------------------------------------------------
function showSelectBoxes(){
var selects = document.getElementsByTagName("select");
for (i = 0; i != selects.length; i++) {
selects[i].style.visibility = "visible";
}
}
// ---------------------------------------------------
function hideSelectBoxes(){
var selects = document.getElementsByTagName("select");
for (i = 0; i != selects.length; i++) {
selects[i].style.visibility = "hidden";
}
}
// ---------------------------------------------------
function showFlash(){
var flashObjects = document.getElementsByTagName("object");
for (i = 0; i < flashObjects.length; i++) {
flashObjects[i].style.visibility = "visible";
}
var flashEmbeds = document.getElementsByTagName("embed");
for (i = 0; i < flashEmbeds.length; i++) {
flashEmbeds[i].style.visibility = "visible";
}
}
// ---------------------------------------------------
function hideFlash(){
var flashObjects = document.getElementsByTagName("object");
for (i = 0; i < flashObjects.length; i++) {
flashObjects[i].style.visibility = "hidden";
}
var flashEmbeds = document.getElementsByTagName("embed");
for (i = 0; i < flashEmbeds.length; i++) {
flashEmbeds[i].style.visibility = "hidden";
}
}
// ---------------------------------------------------
//
// pause(numberMillis)
// Pauses code execution for specified time. Uses busy code, not good.
// Help from Ran Bar-On [ran2103#gmail.com]
//
function pause(ms){
var date = new Date();
curDate = null;
do{var curDate = new Date();}
while( curDate - date < ms);
}
/*
function pause(numberMillis) {
var curently = new Date().getTime() + sender;
while (new Date().getTime();
}
*/
// ---------------------------------------------------
function initLightbox() { myLightbox = new Lightbox(); }
//Event.observe(window, 'load', initLightbox, false);
I've continued to work on this and have a temporary solution until the mainframe of Lightbox2 has a working alt tag on the overlay (tried up to current version 11.1 but they weren't working). I added a setAlt section after line 122
setAlt: function(element,alt) {
element = $(element);
element.alt = alt;
},
and then added the alt call in the image preloader section (around line 440). I tried calling a value for the ALT in this code, but best I could get was 'undefined', so I've set a static value.
imgPreloader = new Image();
// once image is preloaded, resize image container
imgPreloader.onload=function(){
Element.setSrc('lightboxImage', imageArray[activeImage][0]);
Element.setAlt('lightboxImage', 'Caption below');
// Element.setAlt ('lightboxImage', imageArray[activeImage][0].alt);
//which returned alt="undefined". Couldn't figure out setting VAR
myLightbox.resizeImageContainer(imgPreloader.width, imgPreloader.height);

How to make Coin Slider responsive?

After being created, the slider seems not to have a way to be resized, which is really bad for a responsive layout.
Is there a way to actually resize the Coin Slider plugin according to Twitter Bootstrap 3's media queries?
You might consider Coin Slider's demo as a fiddle.
Indeed, there is no way to resize it with the current plugin version. So, I wrote a script to resize the Coin Slider (you can test it on Coin Slider's demo site):
var resizeCoinSliderTo = function(coinSlider, toWidth, toHeight) {
var csColumns = 7;
var csRows = 5;
var imgWidth = toWidth;
var imgHeight = toHeight;
var cellWidth = imgWidth/csColumns;
var cellHeight = imgHeight/csRows;
var coinSliderId = coinSlider.attr("id");
coinSlider.css({
'width': imgWidth,
'height': imgHeight
});
$('.cs-'+coinSliderId).css({
'width': (cellWidth + 'px'),
'height': (cellHeight + 'px'),
'background-size': (imgWidth + 'px ' + imgHeight + 'px')
}).each(function() {
var cellOffsets = $(this).attr("id").replace("cs-"+coinSliderId,"");
var hOffSet = cellHeight * (Math.floor(parseInt(cellOffsets[0])-1) % csRows);
var wOffSet = cellWidth * (parseInt(cellOffsets[1])-1);
$(this).css({
"left": (wOffSet + 'px'),
"top": (hOffSet + 'px'),
"background-position": ((-wOffSet) + 'px ' + (-hOffSet) + 'px')
});
});
$('#cs-navigation-'+coinSliderId).children("a").css("top", (((imgHeight/2)-15)+'px'));
};
So, we just need to call the created resizeCoinSliderTo after each media queries breakpoints, handling the resize, without losing its ratio, to fit the screen properly:
<span id="mq-detector">
<span class="visible-xs"></span>
<span class="visible-sm"></span>
<span class="visible-md"></span>
<span class="visible-lg"></span>
</span>
#mq-detector {
visibility: hidden;
}
var coinSlider = $("#coin-slider");
var baseWidthDisplay = undefined;
var baseHeightDisplay = undefined;
var currentRatio = undefined;
var mqRatios = [0.75, 0.95, 0.8, 1];
var mqDetector = $("#mq-detector");
var mqSelectors = [
mqDetector.find(".visible-xs"),
mqDetector.find(".visible-sm"),
mqDetector.find(".visible-md"),
mqDetector.find(".visible-lg")
];
var checkCoinSliderForResize = function() {
for (var i = 0; i <= mqSelectors.length; i++) {
if (mqSelectors[i].is(":visible")) {
if (currentRatio == undefined) {
baseWidthDisplay = parseInt(coinSlider.css("width"));
baseHeightDisplay = parseInt(coinSlider.css("height"));
}
if (i == 0) {
var specialWidth = Math.floor(parseInt($("body").css("width"))*0.75);
if (specialWidth < 300){
specialWidth = 300;
}
var specialHeight = Math.floor(baseHeightDisplay * specialWidth / baseWidthDisplay);
resizeCoinSliderTo(coinSlider, specialWidth, specialHeight);
}
if (currentRatio != mqRatios[i]) {
currentRatio = mqRatios[i];
if (i > 0) {
resizeCoinSliderTo(coinSlider, baseWidthDisplay*currentRatio, baseHeightDisplay*currentRatio);
}
}
break;
}
}
};
$(window).on('resize', checkCoinSliderForResize);
checkCoinSliderForResize();
Make sure to place all JavaScript code after the DOM is ready, and after the coinslider was created.

Creating a bouncing box animation on canvas

I need to create an animation of dropping box, which supposed to bounce 10 times when it reaches a certain Y point on canvas, each time twice lower that the previous. So I have the animation of the dropping box, but I can't make the bounce work. Here are the functions that I wrote:
function dropBox(y, width, height) {
var img_box = new Image();
img_box.src = 'images/gift_box_small.png';
var box_y_pos = y;
if(y==0)
box_y_pos = y-img_box.naturalHeight;
img_box.onload = function(){
ctx_overlay.save();
ctx_overlay.clearRect(0,0,width,height);
ctx_overlay.drawImage(img_box, (width/2)-(img_box.naturalWidth/2), box_y_pos);
ctx_overlay.restore();
}
box_y_pos += 3;
var box_bottom_position = box_y_pos - img_box.naturalHeight;
if(box_y_pos+img_box.naturalHeight<height-25)
var loopTimer = setTimeout(function() {dropBox(box_y_pos, width, height)},24);
else
bounceBox(img_box, box_y_pos, box_y_pos, (height/2)-(img_box.naturalHeight/2), "up");
}
function bounceBox(img, img_final_pos, y, midway_pos, direction){
var midway = midway_pos;
var direction = direction;
var img_y_pos = y;
img.onload = function(){
ctx_overlay.save();
ctx_overlay.clearRect(0,0,docWidth,docHeight);
ctx_overlay.drawImage(img, (docWidth/2)-(img.naturalWidth/2), img_y_pos);
ctx_overlay.restore();
}
for(var i = 0; i < 10; i++){
if(direction=="up"){
//going up
if(img_y_pos>midway_){
img_y_pos -= 3;
var loopTimer = setTimeout(function() {bounceBox(img, img_final_pos, img_y_pos, midway_pos, "up")},24);
} else {
img_y_pos += 3;
midway = Math.floor(midway /= 2);
if(midway%2>0)
midway += 1;
var loopTimer = setTimeout(function() {bounceBox(img, img_final_pos, img_y_pos, midway_pos, "down")},24);
}
} else {
//going down
if(img_y_pos < img_final_pos){
img_y_pos += 3;
var loopTimer = setTimeout(function() {bounceBox(img, img_final_pos, img_y_pos, midway_pos, "down")},24);
}
}
}
}
JSFiddle: http://jsfiddle.net/n2derqgw/3/
Why isn't it working and how can I make it work?
To avoid getting a headache, you've better handle the animation within a single function called with a setInterval.
And keep all animation-related data in one object.
So the code below does not exactly what you want, but should get you started :
http://jsfiddle.net/n2derqgw/4/
Setup :
var canvas_overlay, ctx_overlay, docWidth, docHeight;
var img_box = new Image();
img_box.src = 'http://corkeynet.com/test/images/gift_box_small.png';
var mustBeReadyCount = 2; // must load image and window
img_box.onload = launchWhenReady;
window.onload = launchWhenReady;
var animationStep = '';
var boxAnimationData = {
animationStep: '',
y: 0,
maxY: 0,
bounceCount: 6,
direction: -1,
bounceHeight: 0
};
function launchWhenReady() {
mustBeReadyCount--;
if (mustBeReadyCount) return;
docWidth = window.innerWidth;
docHeight = window.innerHeight;
canvas_overlay = document.getElementById('canvas_overlay');
ctx_overlay = canvas_overlay.getContext('2d');
resizeCanvas(docWidth, docHeight);
boxAnimationData.animationStep = 'falling';
boxAnimationData.bounceHeight = docHeight / 2 - img_box.height;
setInterval(animateBox, 30);
};
More interesting code is here :
function animateBox() {
if (boxAnimationData.animationStep == 'falling') dropBox();
else if (boxAnimationData.animationStep == 'bouncing') bounceBox();
}
function dropBox() {
ctx_overlay.clearRect(0, 0, docWidth, docHeight);
boxAnimationData.y += 3;
if (boxAnimationData.y + img_box.height > docHeight) {
boxAnimationData.animationStep = 'bouncing';
}
ctx_overlay.drawImage(img_box, (docWidth / 2) - (img_box.width / 2), boxAnimationData.y);
}
function bounceBox() {
ctx_overlay.clearRect(0, 0, docWidth, docHeight);
boxAnimationData.y += boxAnimationData.direction * 3;
if (boxAnimationData.y + img_box.height > docHeight) {
// reached floor ? swap direction
boxAnimationData.direction *= -1;
// and reduce jump height
boxAnimationData.bounceHeight *= 3 / 2;
boxAnimationData.bounceCount--;
if (!boxAnimationData.bounceCount) boxAnimationData.animationStep = '';
} else if (boxAnimationData.y < boxAnimationData.bounceHeight) {
boxAnimationData.direction *= -1;
}
ctx_overlay.drawImage(img_box, (docWidth / 2) - (img_box.width / 2), boxAnimationData.y);
}

Need help in displaying selection handles on rectangle using javascript

I am trying to add something to my code so as to select the image after drawing ( the selection handler should appear in the corners and in the middle of edge) and then drag or increase/decrease the height and width?
My sample code is in the fiddle , in this I am drawing a rectangle using the mouse event handlers. I want to select the rectangle and modify/alter it using the selection handlers instead of drawing it again.
Click the button ROI, metrics and then you can draw it using the mouse events.
http://jsfiddle.net/AhdJr/53/
var oImageBuffer = document.createElement('img');
var oCanvas=document.getElementById("SetupImageCanvas");
var o2DContext=oCanvas.getContext("2d");
var oRect = {};
var oROI = {};
var oMetrics ={};
var oLayers = new Array();
var bDragging = false;
var bSetROI = false;
var bSetLayers = false;
InitMouseEvents();
var oSelect = document.getElementById("ImageList");
oSelect.onchange=function() {
changeCanvasImage(oSelect[oSelect.selectedIndex].value);
}
// Canvas event handlers (listeners).
function InitMouseEvents() {
oCanvas.addEventListener('mousedown', MouseDownEvent, false);
oCanvas.addEventListener('mouseup', MouseUpEvent, false);
oCanvas.addEventListener('mousemove', MouseMoveEvent, false);
oCanvas.addEventListener('mouseout', MouseOutEvent, false);
}
function MouseDownEvent(e) {
oRect.startX = e.pageX - this.offsetLeft;
oRect.startY = e.pageY - this.offsetTop;
bDragging = true;
}
function MouseUpEvent() {
bDragging = false;
}
function MouseOutEvent() {
document.getElementById("MouseCoords").innerHTML="";
}
function MouseMoveEvent(e) {
if (bDragging) {
oRect.w = (e.pageX - this.offsetLeft) - oRect.startX;
oRect.h = (e.pageY - this.offsetTop) - oRect.startY;
oCanvas.getContext('2d').clearRect(0,0,oCanvas.width, oCanvas.height);
var oROI = document.getElementById("btnROI");
if (oROI.checked) {
SetROI();
}
var oLayer = document.getElementById("btnLAYER");
if (oLayer.checked) {
SetLayer();
}
var oMetrics = document.getElementById("btnMetrics");
if (oMetrics.checked) {
SetMetrics();
}
}
if (bSetROI) {
DrawROI();
}
if (bSetLayers) {
DrawLayers();
}
if(bSetMetrics){
DrawMetrics();
}
// Display the current mouse coordinates.
ShowCoordinates(e);
}
function ShowCoordinates(e) {
x=e.clientX;
y=e.clientY;
document.getElementById("MouseCoords").innerHTML="(" + x + "," + y + ") " + document.getElementById('txtPatchCount').value;
}
// Interactively draw ROI rectangle(s) on the canvas.
function SetROI() {
bSetROI = true;
oROI.startX = oRect.startX;
oROI.startY = oRect.startY;
oROI.w = oRect.w;
oROI.h = oRect.h;
}
function DrawROI() {
o2DContext.lineWidth=1.5;
o2DContext.strokeStyle = '#0F0';
o2DContext.strokeRect(oROI.startX, oROI.startY, oROI.w, oROI.h);
var iPatches = document.getElementById('txtPatchCount').value;
o2DContext.beginPath();
var iTop = oROI.startY;
var iBottom = oROI.startY + oROI.h;
var iLeft = oROI.startX;
var iX = iLeft;
for (var iPatch=1; iPatch<iPatches; ++iPatch) {
iX = iLeft + iPatch*oROI.w/iPatches;
o2DContext.moveTo(iX, iTop);
o2DContext.lineTo(iX, iBottom);
}
o2DContext.lineWidth=0.25;
o2DContext.stroke();
}
function SetMetrics() {
bSetMetrics = true;
oMetrics.startX = oRect.startX;
oMetrics.startY = oRect.startY;
oMetrics.w = oRect.w;
oMetrics.h = oRect.h;
}
function DrawMetrics(){
o2DContext.strokeStyle = 'black';
o2DContext.strokeRect(oMetrics.startX, oMetrics.startY, oMetrics.w, oMetrics.h);
o2DContext.beginPath();
var iTop = oMetrics.startY;
var iBottom = oMetrics.startY + oMetrics.h;
var iLeft = oMetrics.startX;
var iX = iLeft;
o2DContext.moveTo(iX, iTop);
o2DContext.lineTo(iX, iBottom);
o2DContext.stroke();
}
// Interactively draw layer boundaries on the canvas.
function SetLayer() {
bSetLayers = true;
oLayers.length = 0;
oLayers.push(oRect.startY);
oLayers.push(oRect.startY + oRect.h);
}
function DrawLayers() {
o2DContext.lineWidth=0.25;
o2DContext.strokeStyle = '#F00';
o2DContext.beginPath();
var iY = oLayers[0];
var iLeft = 0;
var iRight = oCanvas.width;
for (var iLayer=0; iLayer<oLayers.length; ++iLayer) {
iY = oLayers[iLayer];
o2DContext.moveTo(iLeft, iY);
o2DContext.lineTo(iRight, iY);
o2DContext.stroke();
}
}
The below blog is doing the same thing but I am not sure how to add this functionality in my code.
http://simonsarris.com/blog/225-canvas-selecting-resizing-shape
Please guide me how to add the same in mine.
Really appreciate the help.
try the following link.
It is doing somewhat you want to achieve.
http://simonsarris.com/blog/225-canvas-selecting-resizing-shape

Apply drag and drop/attach feature to JSTreegraph using Jquery draggable

I am using JSTreegraph plugin to draw a tree structure.
But now I need a drag, drop and attach feature wherein I can drag any node of the tree and attach to any other node and subsequently all the children of the first node will be now the grand-children of the new node (to which it is attached).
As far as I know this plugin doesnt seem to have this feature. It simply draws the structure based on the data object passed to it.
The plugin basically assigns a class Node to all the nodes(divs) of the tree and another class NodeHover to a node on hover. No id is assigned to these divs.
So I tried using JQuery Draggable just to see if any of the node can be moved by doing this
$('.Node').draggable();
$('.NodeHover').draggable();
But it doesnt seem to work. So can anyone help me with this.
How can I get drag and attach functionality?
*EDIT:: Pardon me am not so great with using Fiddle, so am sharing a sample code here for your use:*
HTML file: which will draw the sample tree
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml">
<head>
<link href="css/JSTreeGraph.css" rel="stylesheet" type="text/css" />
<script src="js/JSTreeGraph.js" type="text/javascript"></script>
<script src="js/jquery-1.7.1.min.js" type="text/javascript"></script>
<script src="js/jquery.ui.position.js" type="text/javascript"></script>
<style type="text/css">
.Container {
position: absolute;
top: 100px;
left: 50px;
id: Container;
}
</style>
</head>
<body>
<div id="tree">
Ctrl+Click to Add Node
<br />
Double Click to Expand or Collapse
<br />
Shift+Click to Delete Node
<br />
<select id="dlLayout" onchange="ChangeLayout()">
<option value="Horizontal">
Horizontal
</option>
<option value="Vertical" selected>
Vertical
</option>
</select>
<div class="Container" id="dvTreeContainer"></div>
<script type="text/javascript">
var selectedNode;
// Root node
var rootNode = { Content: "Onida", Nodes:[] };
// First Level
rootNode.Nodes[0] = { Content: "Employee Code", navigationType: "0"};
rootNode.Nodes[1] = { Content: "Problem Area", navigationType: "1" };
// Second Level
rootNode.Nodes[1].Nodes = [{ Content : "ACC-HO", Collapsed: true /* This node renders collapsed */ },
{ Content : "ACC-SALES" },
{ Content : "BUSI. HEAD", /*This node looks different*/ ToolTip: "Click ME!" },
{ Content : "CEO"},
{ Content : "HO-ADMIN"},
{ Content : "HO-FACTORY"},
{ Content : "SALES"}];
// Third Level
rootNode.Nodes[1].Nodes[0].Nodes = [{ Content: "Billing" },
{ Content: "Credit Limit" },
{ Content: "Reconciliation" }];
rootNode.Nodes[1].Nodes[1].Nodes = [{ Content: "Billing" },
{ Content: "Others" }];
rootNode.Nodes[1].Nodes[2].Nodes = [{ Content: "AC" },
{ Content: "CTV" },
{ Content: "DVD" },
{ Content: "Washing Machine" }];
rootNode.Nodes[1].Nodes[6].Nodes = [{ Content: "Appointments" },
{ Content: "Resignations" },
{ Content: "Others" }];
// Draw the tree for the first time
RefreshTree();
function RefreshTree() {
DrawTree({ Container: document.getElementById("dvTreeContainer"),
RootNode: rootNode,
Layout: document.getElementById("dlLayout").value,
OnNodeClickFirefox: NodeClickFF,
OnNodeClickIE: NodeClickIE,
OnNodeDoubleClick: NodeDoubleClick
});
}
//function
function NodeClickFF(e) {
if (e.shiftKey){
// Delete Node
if (!this.Node.Collapsed) {
for(var index=0; index<this.Node.ParentNode.Nodes.length; index++) {
if(this.Node.ParentNode.Nodes[index].Content == this.Node.Content) {
this.Node.ParentNode.Nodes.splice(index, 1);
break;
}
}
RefreshTree();
}
// return false;
}
else if (e.ctrlKey) {
// Add new Child if Expanded
if (!this.Node.Collapsed) {
if (!this.Node.Nodes) this.Node.Nodes = new Array();
var newNodeIndex = this.Node.Nodes.length;
this.Node.Nodes[newNodeIndex] = new Object();
this.Node.Nodes[newNodeIndex].Content = this.Node.Content + "." + (newNodeIndex + 1);
RefreshTree();
}
// return false;
}
else{
fnNodeProperties(this.Node);
}
}
function NodeClickIE() {
if (typeof(event) == "undefined" && event.ctrlKey) {
// Add new Child if Expanded
if (!this.Node.Collapsed) {
if (!this.Node.Nodes) this.Node.Nodes = new Array();
var newNodeIndex = this.Node.Nodes.length;
this.Node.Nodes[newNodeIndex] = new Object();
this.Node.Nodes[newNodeIndex].Content = this.Node.Content + "." + (newNodeIndex + 1);
RefreshTree();
}
}
else if (typeof(event) == "undefined" && event.shiftKey) {
// Delete Node
if (!this.Node.Collapsed) {
for(var index=0; index<this.Node.ParentNode.Nodes.length; index++) {
if(this.Node.ParentNode.Nodes[index].Content == this.Node.Content) {
this.Node.ParentNode.Nodes.splice(index, 1);
break;
}
}
RefreshTree();
}
}
else{
fnNodeProperties(this.Node);
}
}
function NodeDoubleClick() {
if (this.Node.Nodes && this.Node.Nodes.length > 0) { // If has children
this.Node.Collapsed = !this.Node.Collapsed;
RefreshTree();
}
}
function ChangeLayout() {
RefreshTree();
}
</script>
</div>
</body>
</html>
JSTreeGraph JS file: plugin js file
function DrawTree(options) {
// Prepare Nodes
PrepareNode(options.RootNode);
// Calculate Boxes Positions
if (options.Layout == "Vertical") {
PerformLayoutV(options.RootNode);
} else {
PerformLayoutH(options.RootNode);
}
// Draw Boxes
options.Container.innerHTML = "";
DrawNode(options.RootNode, options.Container, options);
// Draw Lines
DrawLines(options.RootNode, options.Container);
}
function DrawLines(node, container) {
if ((!node.Collapsed) && node.Nodes && node.Nodes.length > 0) { // Has children and Is Expanded
for (var j = 0; j < node.Nodes.length; j++) {
if(node.ChildrenConnectorPoint.Layout=="Vertical")
DrawLineV(container, node.ChildrenConnectorPoint, node.Nodes[j].ParentConnectorPoint);
else
DrawLineH(container, node.ChildrenConnectorPoint, node.Nodes[j].ParentConnectorPoint);
// Children
DrawLines(node.Nodes[j], container);
}
}
}
function DrawLineH(container, startPoint, endPoint) {
var midY = (startPoint.Y + ((endPoint.Y - startPoint.Y) / 2)); // Half path between start en end Y point
// Start segment
DrawLineSegment(container, startPoint.X, startPoint.Y, startPoint.X, midY, 1);
// Intermidiate segment
var imsStartX = startPoint.X < endPoint.X ? startPoint.X : endPoint.X; // The lower value will be the starting point
var imsEndX = startPoint.X > endPoint.X ? startPoint.X : endPoint.X; // The higher value will be the ending point
DrawLineSegment(container, imsStartX, midY, imsEndX, midY, 1);
// End segment
DrawLineSegment(container, endPoint.X, midY, endPoint.X, endPoint.Y, 1);
}
function DrawLineV(container, startPoint, endPoint) {
var midX = (startPoint.X + ((endPoint.X - startPoint.X) / 2)); // Half path between start en end X point
// Start segment
DrawLineSegment(container, startPoint.X, startPoint.Y, midX, startPoint.Y, 1);
// Intermidiate segment
var imsStartY = startPoint.Y < endPoint.Y ? startPoint.Y : endPoint.Y; // The lower value will be the starting point
var imsEndY = startPoint.Y > endPoint.Y ? startPoint.Y : endPoint.Y; // The higher value will be the ending point
DrawLineSegment(container, midX, imsStartY, midX, imsEndY, 1);
// End segment
DrawLineSegment(container, midX, endPoint.Y, endPoint.X, endPoint.Y, 1);
}
function DrawLineSegment(container, startX, startY, endX, endY, lineWidth) {
var lineDiv = document.createElement("div");
lineDiv.style.top = startY + "px";
lineDiv.style.left = startX + "px";
if (startX == endX) { // Vertical Line
lineDiv.style.width = lineWidth + "px";
lineDiv.style.height = (endY - startY) + "px";
}
else{ // Horizontal Line
lineDiv.style.width = (endX - startX) + "px";
lineDiv.style.height = lineWidth + "px";
}
lineDiv.className = "NodeLine";
container.appendChild(lineDiv);
}
function DrawNode(node, container, options) {
var nodeDiv = document.createElement("div");
nodeDiv.style.top = node.Top + "px";
nodeDiv.style.left = node.Left + "px";
nodeDiv.style.width = node.Width + "px";
nodeDiv.style.height = node.Height + "px";
if (node.Collapsed) {
nodeDiv.className = "NodeCollapsed";
} else {
nodeDiv.className = "Node";
}
if (node.Class)
nodeDiv.className = node.Class;
if (node.Content)
nodeDiv.innerHTML = "<div class='NodeContent'>" + node.Content + "</div>";
if (node.ToolTip)
nodeDiv.setAttribute("title", node.ToolTip);
nodeDiv.Node = node;
// Events
if (options.OnNodeClickIE){
//alert('OnNodeClick');
nodeDiv.onclick = options.OnNodeClickIE;
}
// Events
if (options.OnNodeClickFirefox){
//alert('OnNodeClick');
nodeDiv.onmousedown = options.OnNodeClickFirefox;
}
//on right click
if (options.OnContextMenu){
//alert('OnContextMenu');
nodeDiv.oncontextmenu = options.OnContextMenu;
}
if (options.OnNodeDoubleClick)
nodeDiv.ondblclick = options.OnNodeDoubleClick;
nodeDiv.onmouseover = function () { // In
this.PrevClassName = this.className;
this.className = "NodeHover";
};
nodeDiv.onmouseout = function () { // Out
if (this.PrevClassName) {
this.className = this.PrevClassName;
this.PrevClassName = null;
}
};
container.appendChild(nodeDiv);
// Draw children
if ((!node.Collapsed) && node.Nodes && node.Nodes.length > 0) { // Has Children and is Expanded
for (var i = 0; i < node.Nodes.length; i++) {
DrawNode(node.Nodes[i], container, options);
}
}
}
function PerformLayoutV(node) {
var nodeHeight = 30;
var nodeWidth = 100;
var nodeMarginLeft = 40;
var nodeMarginTop = 20;
var nodeTop = 0; // defaultValue
// Before Layout this Node, Layout its children
if ((!node.Collapsed) && node.Nodes && node.Nodes.length > 0) {
for (var i = 0; i < node.Nodes.length; i++) {
PerformLayoutV(node.Nodes[i]);
}
}
if ((!node.Collapsed) && node.Nodes && node.Nodes.length > 0) { // If Has Children and Is Expanded
// My Top is in the center of my children
var childrenHeight = (node.Nodes[node.Nodes.length - 1].Top + node.Nodes[node.Nodes.length - 1].Height) - node.Nodes[0].Top;
nodeTop = (node.Nodes[0].Top + (childrenHeight / 2)) - (nodeHeight / 2);
// Is my top over my previous sibling?
// Move it to the bottom
if (node.LeftNode && ((node.LeftNode.Top + node.LeftNode.Height + nodeMarginTop) > nodeTop)) {
var newTop = node.LeftNode.Top + node.LeftNode.Height + nodeMarginTop;
var diff = newTop - nodeTop;
/// Move also my children
MoveBottom(node.Nodes, diff);
nodeTop = newTop;
}
} else {
// My top is next to my top sibling
if (node.LeftNode)
nodeTop = node.LeftNode.Top + node.LeftNode.Height + nodeMarginTop;
}
node.Top = nodeTop;
// The Left depends only on the level
node.Left = (nodeMarginLeft * (node.Level + 1)) + (nodeWidth * (node.Level + 1));
// Size is constant
node.Height = nodeHeight;
node.Width = nodeWidth;
// Calculate Connector Points
// Child: Where the lines get out from to connect this node with its children
var pointX = node.Left + nodeWidth;
var pointY = nodeTop + (nodeHeight/2);
node.ChildrenConnectorPoint = { X: pointX, Y: pointY, Layout: "Vertical" };
// Parent: Where the line that connect this node with its parent end
pointX = node.Left;
pointY = nodeTop + (nodeHeight/2);
node.ParentConnectorPoint = { X: pointX, Y: pointY, Layout: "Vertical" };
}
function PerformLayoutH(node) {
var nodeHeight = 30;
var nodeWidth = 100;
var nodeMarginLeft = 20;
var nodeMarginTop = 50;
var nodeLeft = 0; // defaultValue
// Before Layout this Node, Layout its children
if ((!node.Collapsed) && node.Nodes && node.Nodes.length>0) {
for (var i = 0; i < node.Nodes.length; i++) {
PerformLayoutH(node.Nodes[i]);
}
}
if ((!node.Collapsed) && node.Nodes && node.Nodes.length > 0) { // If Has Children and Is Expanded
// My left is in the center of my children
var childrenWidth = (node.Nodes[node.Nodes.length-1].Left + node.Nodes[node.Nodes.length-1].Width) - node.Nodes[0].Left;
nodeLeft = (node.Nodes[0].Left + (childrenWidth / 2)) - (nodeWidth / 2);
// Is my left over my left node?
// Move it to the right
if(node.LeftNode&&((node.LeftNode.Left+node.LeftNode.Width+nodeMarginLeft)>nodeLeft)) {
var newLeft = node.LeftNode.Left + node.LeftNode.Width + nodeMarginLeft;
var diff = newLeft - nodeLeft;
/// Move also my children
MoveRigth(node.Nodes, diff);
nodeLeft = newLeft;
}
} else {
// My left is next to my left sibling
if (node.LeftNode)
nodeLeft = node.LeftNode.Left + node.LeftNode.Width + nodeMarginLeft;
}
node.Left = nodeLeft;
// The top depends only on the level
node.Top = (nodeMarginTop * (node.Level + 1)) + (nodeHeight * (node.Level + 1));
// Size is constant
node.Height = nodeHeight;
node.Width = nodeWidth;
// Calculate Connector Points
// Child: Where the lines get out from to connect this node with its children
var pointX = nodeLeft + (nodeWidth / 2);
var pointY = node.Top + nodeHeight;
node.ChildrenConnectorPoint = { X: pointX, Y: pointY, Layout:"Horizontal" };
// Parent: Where the line that connect this node with its parent end
pointX = nodeLeft + (nodeWidth / 2);
pointY = node.Top;
node.ParentConnectorPoint = { X: pointX, Y: pointY, Layout: "Horizontal" };
}
function MoveRigth(nodes, distance) {
for (var i = 0; i < nodes.length; i++) {
nodes[i].Left += distance;
if (nodes[i].ParentConnectorPoint) nodes[i].ParentConnectorPoint.X += distance;
if (nodes[i].ChildrenConnectorPoint) nodes[i].ChildrenConnectorPoint.X += distance;
if (nodes[i].Nodes) {
MoveRigth(nodes[i].Nodes, distance);
}
}
}
function MoveBottom(nodes, distance) {
for (var i = 0; i < nodes.length; i++) {
nodes[i].Top += distance;
if (nodes[i].ParentConnectorPoint) nodes[i].ParentConnectorPoint.Y += distance;
if (nodes[i].ChildrenConnectorPoint) nodes[i].ChildrenConnectorPoint.Y += distance;
if (nodes[i].Nodes) {
MoveBottom(nodes[i].Nodes, distance);
}
}
}
function PrepareNode(node, level, parentNode, leftNode, rightLimits) {
if (level == undefined) level = 0;
if (parentNode == undefined) parentNode = null;
if (leftNode == undefined) leftNode = null;
if (rightLimits == undefined) rightLimits = new Array();
node.Level = level;
node.ParentNode = parentNode;
node.LeftNode = leftNode;
if ((!node.Collapsed) && node.Nodes && node.Nodes.length > 0) { // Has children and is expanded
for (var i = 0; i < node.Nodes.length; i++) {
var left = null;
if (i == 0 && rightLimits[level]!=undefined) left = rightLimits[level];
if (i > 0) left = node.Nodes[i - 1];
if (i == (node.Nodes.length-1)) rightLimits[level] = node.Nodes[i];
PrepareNode(node.Nodes[i], level + 1, node, left, rightLimits);
}
}
}
JSTreeGraph CSS file:
.NodeContent
{
font-family:Verdana;
font-size:small;
}
.Node
{
position:absolute;
background-color: #CCDAFF;
border: 1px solid #5280FF;
text-align:center;
vertical-align:middle;
cursor:pointer;
overflow:hidden;
}
.NodeHover
{
position:absolute;
background-color: #8FADFF;
border: 1px solid #5280FF;
text-align:center;
vertical-align:middle;
cursor:pointer;
overflow:hidden;
}
.NodeCollapsed
{
position:absolute;
background-color: #8FADFF;
border: 2px solid black;
text-align:center;
vertical-align:middle;
cursor:pointer;
overflow:hidden;
}
.NodeLine
{
background-color: #000066;
position:absolute;
overflow:hidden;
}
I supose that what you need is to stablish a mechanism to modify your tree logic structure on dragging and then reload the whole tree element. This way the plugin will render your new modified structure.
This is not an easy problem and you have not outlined the exact specifications.
When you move a node, should all child nodes move with it?
What happens to a node and its child elements when a node is dropped/attached?
The plugin that you are using works well for drawing static trees, but it is not written in such a way to allow for dynamically editing the tree.
I have to agree with #Bardo in that the easiest way to make this work for your needs is to understand how the tree has been manipulated. (Thankfully the plugin seems to provide an onNodeClick option which will allow you to understand which node you are intending to manipulate). Once the tree has been manipulated then it must be completely redrawn. (There doesn't appear to be a good way to partially draw a tree).

Categories

Resources