jquery.magnify
Version:
A jQuery plugin to view images just like in Windows
360 lines (315 loc) • 11 kB
JavaScript
/**
* --------------------------------------------------------------------------
* 1. Modal resizable
* 2. Keep image in stage center
* 3. Other image limitations
* --------------------------------------------------------------------------
*
* Resizable
* @param {Object} modal - The modal element
* @param {Object} stage - The stage element
* @param {Object} image - The image element
* @param {Number} minWidth - The option of modalWidth
* @param {Number} minHeight - The option of modalHeight
*/
var resizable = function (modal, stage, image, minWidth, minHeight) {
var self = this;
var resizableHandleE = $('<div class="magnify-resizable-handle magnify-resizable-handle-e"></div>'),
resizableHandleW = $('<div class="magnify-resizable-handle magnify-resizable-handle-w"></div>'),
resizableHandleS = $('<div class="magnify-resizable-handle magnify-resizable-handle-s"></div>'),
resizableHandleN = $('<div class="magnify-resizable-handle magnify-resizable-handle-n"></div>'),
resizableHandleSE = $('<div class="magnify-resizable-handle magnify-resizable-handle-se"></div>'),
resizableHandleSW = $('<div class="magnify-resizable-handle magnify-resizable-handle-sw"></div>'),
resizableHandleNE = $('<div class="magnify-resizable-handle magnify-resizable-handle-ne"></div>'),
resizableHandleNW = $('<div class="magnify-resizable-handle magnify-resizable-handle-nw"></div>');
var resizableHandles = {
e: resizableHandleE,
w: resizableHandleW,
s: resizableHandleS,
n: resizableHandleN,
se: resizableHandleSE,
sw: resizableHandleSW,
ne: resizableHandleNE,
nw: resizableHandleNW
};
$(modal).append(
resizableHandleE,
resizableHandleW,
resizableHandleS,
resizableHandleN,
resizableHandleSE,
resizableHandleSW,
resizableHandleNE,
resizableHandleNW
);
var isDragging = false;
var startX = 0,
startY = 0,
modalData = {
w: 0,
h: 0,
l: 0,
t: 0
},
stageData = {
w: 0,
h: 0,
l: 0,
t: 0
},
imageData = {
w: 0,
h: 0,
l: 0,
t: 0
};
// δ is the difference between image width and height
var δ = 0, imgWidth = 0, imgHeight = 0, direction = '';
// Modal CSS options
var getModalOpts = function (dir, offsetX, offsetY) {
// Modal should not move when its width to the minwidth
var modalLeft = -offsetX + modalData.w > minWidth
? offsetX + modalData.l
: modalData.l + modalData.w - minWidth;
var modalTop = -offsetY + modalData.h > minHeight
? offsetY + modalData.t
: modalData.t + modalData.h - minHeight;
var opts = {
e: {
width: Math.max(offsetX + modalData.w, minWidth) + 'px'
},
s: {
height: Math.max(offsetY + modalData.h, minHeight) + 'px'
},
se: {
width: Math.max(offsetX + modalData.w, minWidth) + 'px',
height: Math.max(offsetY + modalData.h, minHeight) + 'px'
},
w: {
width: Math.max(-offsetX + modalData.w, minWidth) + 'px',
left: modalLeft + 'px'
},
n: {
height: Math.max(-offsetY + modalData.h, minHeight) + 'px',
top: modalTop + 'px'
},
nw: {
width: Math.max(-offsetX + modalData.w, minWidth) + 'px',
height: Math.max(-offsetY + modalData.h, minHeight) + 'px',
top: modalTop + 'px',
left: modalLeft + 'px'
},
ne: {
width: Math.max(offsetX + modalData.w, minWidth) + 'px',
height: Math.max(-offsetY + modalData.h, minHeight) + 'px',
top: modalTop + 'px'
},
sw: {
width: Math.max(-offsetX + modalData.w, minWidth) + 'px',
height: Math.max(offsetY + modalData.h, minHeight) + 'px',
left: modalLeft + 'px'
}
};
return opts[dir];
};
// Image CSS options
var getImageOpts = function (dir, offsetX, offsetY) {
var $image = isIE8() ? $(stage).find(image) : $(image);
// In modern browser, the width and height of image won't change after rotated.
// But its position top and left will get values from the image rotated.
// In IE8 browser, due to the type of rotating, all the value will be the same.
var imgPosLeft = isIE8() ? $image.position().left + δ : $image.position().left;
var imgPosTop = isIE8() ? $image.position().top - δ : $image.position().top;
// Image should not move when modal width to the min width
// The minwidth is modal width, so we should clac the stage minwidth
var widthDiff = offsetX + modalData.w > minWidth
? stageData.w - imgWidth + offsetX - δ
: minWidth - (modalData.w - stageData.w) - imgWidth - δ;
var heightDiff = offsetY + modalData.h > minHeight
? stageData.h - imgHeight + offsetY + δ
: minHeight - (modalData.h - stageData.h) - imgHeight + δ;
var widthDiff2 = -offsetX + modalData.w > minWidth
? stageData.w - imgWidth - offsetX - δ
: minWidth - (modalData.w - stageData.w) - imgWidth - δ;
var heightDiff2 = -offsetY + modalData.h > minHeight
? stageData.h - imgHeight - offsetY + δ
: minHeight - (modalData.h - stageData.h) - imgHeight + δ;
// Get image position in dragging
var imgLeft = (widthDiff > 0 ? imgPosLeft : imgPosLeft < 0 ? imgPosLeft : 0) - δ;
var imgTop = (heightDiff > 0 ? imgPosTop : imgPosTop < 0 ? imgPosTop : 0) + δ;
var imgLeft2 = (widthDiff2 > 0 ? imgPosLeft : imgPosLeft < 0 ? imgPosLeft : 0) - δ;
var imgTop2 = (heightDiff2 > 0 ? imgPosTop : imgPosTop < 0 ? imgPosTop : 0) + δ;
var opts = {
e: {
left: widthDiff >= -δ
? (widthDiff - δ) / 2 + 'px'
: imgLeft > widthDiff
? imgLeft + 'px'
: widthDiff + 'px'
},
s: {
top: heightDiff >= δ
? (heightDiff + δ) / 2 + 'px'
: imgTop > heightDiff
? imgTop + 'px'
: heightDiff + 'px'
},
se: {
top: heightDiff >= δ
? (heightDiff + δ) / 2 + 'px'
: imgTop > heightDiff
? imgTop + 'px'
: heightDiff + 'px',
left: widthDiff >= -δ
? (widthDiff - δ) / 2 + 'px'
: imgLeft > widthDiff
? imgLeft + 'px'
: widthDiff + 'px'
},
w: {
left: widthDiff2 >= -δ
? (widthDiff2 - δ) / 2 + 'px'
: imgLeft2 > widthDiff2
? imgLeft2 + 'px'
: widthDiff2 + 'px'
},
n: {
top: heightDiff2 >= δ
? (heightDiff2 + δ) / 2 + 'px'
: imgTop2 > heightDiff2
? imgTop2 + 'px'
: heightDiff2 + 'px'
},
nw: {
top: heightDiff2 >= δ
? (heightDiff2 + δ) / 2 + 'px'
: imgTop2 > heightDiff2
? imgTop2 + 'px'
: heightDiff2 + 'px',
left: widthDiff2 >= -δ
? (widthDiff2 - δ) / 2 + 'px'
: imgLeft2 > widthDiff2
? imgLeft2 + 'px'
: widthDiff2 + 'px'
},
ne: {
top: heightDiff2 >= δ
? (heightDiff2 + δ) / 2 + 'px'
: imgTop2 > heightDiff2
? imgTop2 + 'px'
: heightDiff2 + 'px',
left: widthDiff >= -δ
? (widthDiff - δ) / 2 + 'px'
: imgLeft > widthDiff
? imgLeft + 'px'
: widthDiff + 'px'
},
sw: {
top: heightDiff >= δ
? (heightDiff + δ) / 2 + 'px'
: imgTop > heightDiff
? imgTop + 'px'
: heightDiff + 'px',
left: widthDiff2 >= -δ
? (widthDiff2 - δ) / 2 + 'px'
: imgLeft2 > widthDiff2
? imgLeft2 + 'px'
: widthDiff2 + 'px'
}
};
return opts[dir];
};
var dragStart = function (dir, e) {
e = e || window.event;
e.preventDefault();
var $image = isIE8() ? $(stage).find(image) : $(image);
isDragging = true;
PUBLIC_VARS['isResizing'] = true;
startX = e.type === 'touchstart' ? e.originalEvent.targetTouches[0].pageX : e.clientX;
startY = e.type === 'touchstart' ? e.originalEvent.targetTouches[0].pageY : e.clientY;
// Reclac the modal data when mousedown
modalData = {
w: $(modal).width(),
h: $(modal).height(),
l: $(modal).offset().left,
t: $(modal).offset().top
};
stageData = {
w: $(stage).width(),
h: $(stage).height(),
l: $(stage).offset().left,
t: $(stage).offset().top
};
imageData = {
w: $image.width(),
h: $image.height(),
l: $image.position().left,
t: $image.position().top
};
// δ is the difference between image width and height
δ = !self.isRotated ? 0 : (imageData.w - imageData.h) / 2;
imgWidth = !self.isRotated ? imageData.w : imageData.h;
imgHeight = !self.isRotated ? imageData.h : imageData.w;
direction = dir;
// Add resizable cursor
$('html,body,.magnify-modal,.magnify-stage,.magnify-button').css(
'cursor',
dir + '-resize'
);
$D.on(TOUCH_MOVE_EVENT + EVENT_NS, dragMove).on(
TOUCH_END_EVENT + EVENT_NS,
dragEnd
);
};
var dragMove = function (e) {
e = e || window.event;
e.preventDefault();
var $image = isIE8() ? $(stage).find(image) : $(image);
if (isDragging && !self.isMaximized) {
var endX = e.type === 'touchmove' ? e.originalEvent.targetTouches[0].pageX : e.clientX;
var endY = e.type === 'touchmove' ? e.originalEvent.targetTouches[0].pageY : e.clientY;
var relativeX = endX - startX;
var relativeY = endY - startY;
var modalOpts = getModalOpts(direction, relativeX, relativeY);
$(modal).css(modalOpts);
var imageOpts = getImageOpts(direction, relativeX, relativeY);
$image.css(imageOpts);
self.isDoResize = true;
}
};
var dragEnd = function (e) {
$D.off(TOUCH_MOVE_EVENT + EVENT_NS, dragMove).off(
TOUCH_END_EVENT + EVENT_NS,
dragEnd
);
// Set grab cursor
if (PUBLIC_VARS['isResizing']) {
setGrabCursor(
{ w: imgWidth, h: imgHeight },
{ w: $(stage).width(), h: $(stage).height() },
stage
);
}
isDragging = false;
PUBLIC_VARS['isResizing'] = false;
// Remove resizable cursor
$('html, body, .magnify-modal, .magnify-stage, .magnify-button').css('cursor', '');
// Update image initial data
var scale = self.getImageScaleToStage($(stage).width(), $(stage).height());
$.extend(self.imageData, {
initWidth: self.img.width * scale,
initHeight: self.img.height * scale,
initLeft: ($(stage).width() - self.img.width * scale) / 2,
initTop: ($(stage).height() - self.img.height * scale) / 2
});
};
$.each(resizableHandles, function (dir, handle) {
handle.on(TOUCH_START_EVENT + EVENT_NS, function (e) {
dragStart(dir, e);
});
});
};
// Add to Magnify Prototype
$.extend(Magnify.prototype, {
resizable: resizable
});