效果图
支持上一张,下一张,放大,缩小和旋转。不依赖框架,纯js+css。
tips:需要引入jquery和jquery.rotate
html页面代码:
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"/>
<meta name="keywords" content=""/>
<meta name="description" content=""/>
<link rel="stylesheet" href="index.css">
</head>
<body>
<ul class="picView-magnify-list" style="padding: 30px">
<li>
<a href="javascript:void(0)" data-magnify="gallery" data-group="g1" data-src="https://liuqingwushui.top/usr/uploads/2024/10/09/1728443997466250.jpg" data-caption="测试图片1">
<img src="https://liuqingwushui.top/usr/uploads/2024/10/09/1728443997466250.jpg">
</a>
</li>
<li>
<a href="javascript:void(0)" data-magnify="gallery" data-group="g1" data-src="https://liuqingwushui.top/usr/uploads/2024/10/09/1728443808379316.jpg" data-caption="测试图片2">
<img src="https://liuqingwushui.top/usr/uploads/2024/10/09/1728443808379316.jpg">
</a>
</li>
<li>
<a href="javascript:void(0)" data-magnify="gallery" data-group="g1" data-src="https://liuqingwushui.top/usr/uploads/2024/10/09/1728443808679847.jpg" data-caption="测试图片3">
<img src="https://liuqingwushui.top/usr/uploads/2024/10/09/1728443808679847.jpg">
</a>
</li>
<li>
<a href="javascript:void(0)" data-magnify="gallery2" data-group="g2" data-src="https://liuqingwushui.top/usr/uploads/2024/10/09/1728443808722546.jpg" data-caption="测试图片4">
<img src="https://liuqingwushui.top/usr/uploads/2024/10/09/1728443808722546.jpg">
</a>
</li>
</ul>
<script src="js/jquery-2.0.2.min.js"></script>
<script src="index.js"></script>
<script src="js/jquery.rotate.min.js"></script>
<script type="text/javascript">
$(function () {
$('[data-magnify]').Magnify({
Toolbar: [
'prev',
'next',
'rotateLeft',
'rotateRight',
'zoomIn',
'actualSize',
'zoomOut'
],
keyboard:true,
draggable:true,
movable:true,
modalSize:[800,600],
beforeOpen:function (obj,data) {
console.log('beforeOpen')
},
opened:function (obj,data) {
console.log('opened')
},
beforeClose:function (obj,data) {
console.log('beforeClose')
},
closed:function (obj,data) {
console.log('closed')
},
beforeChange:function (obj,data) {
console.log('beforeChange')
},
changed:function (obj,data) {
console.log('changed')
}
});
})
</script>
</body>
</html>
index.css 图片预览模拟框样式
/*************************************************Rest Start*************************************************/
body{font:14px/1.5 "Microsoft YaHei","\5FAE\8F6F\96C5\9ED1,\9ED1\4F53","\5b8b\4f53",arial,Helvetica,Tahoma,sans-serif;margin:0 auto;color:#333;}
p,ul,ol,dl,dt,dd,h1,h2,h3,h4,h5,h6,form,input,select,button,textarea,iframe{margin:0;padding:0;}
img{border:0 none;vertical-align:top;}
ul,li,ol{list-style-type:none;}
table{border-collapse:collapse;border-spacing:0;}
i,em,address,caption,cite,code,dfn,var{font-style:normal;font-weight:normal;}
a{color:#333;text-decoration:none; }
a:hover{color:#777;}
a,a:hover{outline:0;}
input,button,textarea,select,optgroup,option{font-family:"Microsoft YaHei","\5FAE\8F6F\96C5\9ED1,\9ED1\4F53","\5b8b\4f53",arial,Helvetica,Tahoma,sans-serif; font-size: inherit; font-style: inherit; font-weight: inherit; outline: 0;}
body{background-color: #F5F5F5}
.cl:after,.clearfix:after{content:".";display:block;height:0;clear:both;visibility:hidden}
.cl,.clearfix{zoom:1}
@font-face {font-family: "picIcon";
src: url('../fonts/iconfont.eot?t=1527824986789'); /* IE9*/
src: url('../fonts/iconfont.eot?t=1527824986789#iefix') format('embedded-opentype'), /* IE6-IE8 */
url('data:application/x-font-woff;charset=utf-8;base64,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') format('woff'),
url('../fonts/iconfont.ttf?t=1527824986789') format('truetype'), /* chrome, firefox, opera, Safari, Android, iOS 4.2+*/
url('../fonts/iconfont.svg?t=1527824986789#iconfont') format('svg'); /* iOS 4.1- */
}
.picView-magnify-list{}
.picView-magnify-list li{float:left;display:inline-block;width:200px;border:1px solid #ccc;margin-right:10px;}
.picView-magnify-list li a{display:block;overflow:hidden;}
.picView-magnify-list li a img{width:200px;}
.magnify-toolbar .magnify-btn,.magnify-btn-close,.magnify-loader{
font-family: "picIcon" !important;
font-size: 25px;
font-style: normal;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
@-webkit-keyframes icon-spin {
0% {
-webkit-transform: rotate(0deg);
transform: rotate(0deg);
}
100% {
-webkit-transform: rotate(359deg);
transform: rotate(359deg);
}
}
@keyframes icon-spin {
0% {
-webkit-transform: rotate(0deg);
transform: rotate(0deg);
}
100% {
-webkit-transform: rotate(359deg);
transform: rotate(359deg);
}
}
.magnify-modal {
position: fixed;
z-index: 9999;
width: 800px;
height: 600px;
background-color: #333;
background-color: rgba(0, 0, 0, 0.85);
-webkit-box-shadow: 0 0 3px 1px rgba(0, 0, 0, 0.3);
-moz-box-shadow: 0 0 3px 1px rgba(0, 0, 0, 0.3);
box-shadow: 0 0 3px 1px rgba(0, 0, 0, 0.3);
cursor: default;
}
.magnify-header {
position: relative;
height: 40px;
z-index:9;
}
.magnify-footer {
height: 50px;
bottom: 0;
position: absolute;
width: 100%;
text-align: center;
color: #fff;
z-index:9;
}
.magnify-toolbar{
display: inline-block;
height: 50px;
background-color: rgba(0, 0, 0, .5);
-webkit-border-radius: 5px 5px 0 0;
-moz-border-radius: 5px 5px 0 0;
border-radius: 5px 5px 0 0;
}
.magnify-toolbar .magnify-btn{display:inline-block;width:50px;height:50px;margin:0;color:#999;line-height:50px;}
.magnify-btn-close{width:40px;height:40px;margin:0;color:#999;line-height:40px;position: absolute;right:0;top:0;font-size:15px;text-align:center;}
.magnify-toolbar .magnify-btn:hover,.magnify-btn-close:hover{color:#fff;}
.magnify-btn-close:before{content: "\ea4f"}
.magnify-btn-zoomIn:before{content: "\e7dd"}
.magnify-btn-zoomOut:before{content:'\e7dc'}
.magnify-btn-prev:before{content:'\e624'}
.magnify-btn-next:before{content:'\e9ce'}
.magnify-btn-fullScreen:before{content:'\e63f'}
.magnify-btn-actualSize:before{content:'\e615'}
.magnify-btn-rotateLeft:before{content:'\ece3'}
.magnify-btn-rotateRight:before{content:'\ece4'}
.magnify-loader:before{content:'\e600'}
.magnify-loader{
-webkit-animation: icon-spin 1s infinite steps(8);
-o-animation: icon-spin 1s infinite steps(8);
animation: icon-spin 1s infinite steps(8);
width:50px;
height:50px;
text-align:center;
line-height:50px;
color:#999;
font-size:35px;
position:absolute;
left:50%;
margin-left:-25px;
top:40%;
}
.magnify-title{font-size:14px;white-space: nowrap;text-overflow: ellipsis;user-select: none;overflow:hidden;color:#fff;padding:0 40px 0 15px;line-height:40px;}
.magnify-image{display:none;position:relative;}
.magnify-stage{position:absolute;left:0;right:0;bottom:0;top:0;border:none;overflow:hidden;}
.is-grab {
cursor: move;
cursor: -webkit-grab;
cursor: grab;
}
.is-grabbing {
cursor: move;
cursor: -webkit-grabbing;
cursor: grabbing;
}
index.js 自定义预览js代码,可以根据业务需求自主微调。
;(function (factory) {
if (typeof define === 'function' && define.amd) {
define(['jquery'], factory);
} else if (typeof exports === 'object') {
factory(require('jquery'));
} else {
factory(jQuery);
}
})(function ($) {
'use strict';
var $W = $(window), $D = $(document), jqEle = null, isMoving = false, isResizing = false;
var EVENTS = {
CLICK: 'click',
KEYDOWN: 'keydown',
RESIZE: 'resize',
WHEEL: 'wheel mousewheel DOMMouseScroll',
MOUSESTART: 'mousedown',
MOUSEMOVE: 'mousemove',
MOUSEEND: 'mouseup',
EVENT_NS: '.magnify'
};
var cssSelector = {
'modal': '.magnify-modal',
'header': '.magnify-header',
'footer': '.magnify-footer',
'toolbar': '.magnify-toolbar',
'stage': '.magnify-stage',
'title': '.magnify-title',
'image': '.magnify-image',
'close': '.magnify-btn-close',
'zoomIn': '.magnify-btn-zoomIn',
'zoomOut': '.magnify-btn-zoomOut',
'prev': '.magnify-btn-prev',
'next': '.magnify-btn-next',
'actualSize': '.magnify-btn-actualSize',
'rotateLeft': '.magnify-btn-rotateLeft',
'rotateRight': '.magnify-btn-rotateRight',
'loader': '.magnify-loader',
'btn': '.magnify-btn'
};
/*
* draggable 是否支持模态框拖动
* resizable 是否支持模态框改变弹窗大小
* movable 是否支持图片拖动
* keyboard 是否支持键盘操作
* title 是否显示图片标题
* Toolbar 底部工具选项
* i18n 中文说明
* callbacks 回调函数
* modalSize 默认弹层大小(width,height)
* modalOffset 弹层偏移量(x轴,y轴)
* ratioThreshold 缩放阈值
* dragHandle 拖拽选择器
* */
var defaults = {
draggable: false,
resizable: false,
movable: false,
keyboard: false,
title: true,
Toolbar: [
'prev',
'next',
'rotateLeft',
'rotateRight',
'zoomIn',
'actualSize',
'zoomOut'
],
i18n: {
close: '关闭',
zoomIn: '放大(+)',
zoomOut: '缩小(-)',
prev: '上一张(←)',
next: '下一张(→)',
actualSize: '实际尺寸(Ctrl+Alt+0)',
rotateLeft: '左旋转(Ctrl+,)',
rotateRight: '右旋转(Ctrl+.)'
},
modalSize: [800, 600],
modalOffset: [0, 0],
ratioThreshold: 0.1,
minRatio: 0.1,
maxRatio: 16,
dragHandle: false,
beforeOpen: null,
opened: null,
beforeClose: null,
closed: null,
beforeChange: null,
changed: null,
ieTransforms: {
/*'0': 'progid:DXImageTransform.Microsoft.Matrix(M11=1, M12=0, M21=0, M22=1, SizingMethod="auto expand")',
'90': 'progid:DXImageTransform.Microsoft.Matrix(M11=0, M12=-1, M21=1, M22=0, SizingMethod="auto expand")',
'180': 'progid:DXImageTransform.Microsoft.Matrix(M11=-1, M12=0, M21=0, M22=-1, SizingMethod="auto expand")',
'270': 'progid:DXImageTransform.Microsoft.Matrix(M11=0, M12=1, M21=-1, M22=0, SizingMethod="auto expand")'*/
'0': 'progid:DXImageTransform.Microsoft.BasicImage(rotation=0)',
'90': 'progid:DXImageTransform.Microsoft.BasicImage(rotation=1)',
'180': 'progid:DXImageTransform.Microsoft.BasicImage(rotation=2)',
'270': 'progid:DXImageTransform.Microsoft.BasicImage(rotation=3)'
}
};
var magnify = function (ele, opts) {
this.settings = $.extend(true, {}, defaults, opts);
if (opts && $.isArray(opts.Toolbar)) {
if (opts.Toolbar.length !== defaults.Toolbar.length) {
this.settings.Toolbar = opts.Toolbar;
} else {
this.settings.Toolbar = defaults.Toolbar;
}
}
this.$ele = $(ele);
this.isOpened = false;
this.isRotated = false;
this.rotateAngle = 0;
this.imageData = {};
this.modalData = {
width: null,
height: null,
left: null,
top: null
};
this.init(ele);
};
magnify.prototype = {
init: function (ele) {
var imgSrc = getImgSrc(ele);
this.groupName = null;
var currentGroupName = $(ele).data('group');
var groupList = $D.find('[data-group="' + currentGroupName + '"]');
if (currentGroupName !== undefined) {
this.groupName = currentGroupName;
this.getImgGroup(groupList, imgSrc);
} else {
this.getImgGroup(jqEle.not('[data-group]'), imgSrc);
}
this.open();
this.loadImg(imgSrc);
if (this.settings.draggable) {
this.draggable(this.$magnify, this.dragHandle, cssSelector.btn)
}
if (this.settings.movable) {
this.movable(this.$stage, this.$image);
}
if (this.settings.resizable) {
this.resizable(this.$magnify, this.$stage, this.$image, this.settings.modalSize);
}
},
open: function () {
if ($(cssSelector.modal)) {
$(cssSelector.modal).remove();
}
this.build();
this.triggerHook('beforeOpen', this.$ele);
$('body').append(this.$magnify);
this.addEvents();
this.setModalPos(this.$magnify);
this.triggerHook('opened', this.$ele);
},
build: function () {
var _html = this.createDOM();
var $magnify = $(_html);
//获取所有magnify DOM元素
this.$magnify = $magnify;
this.$header = $magnify.find(cssSelector.header);
this.$footer = $magnify.find(cssSelector.footer);
this.$toolbar = $magnify.find(cssSelector.toolbar);
this.$stage = $magnify.find(cssSelector.stage);
this.$title = $magnify.find(cssSelector.title);
this.$image = $magnify.find(cssSelector.image);
this.$close = $magnify.find(cssSelector.close);
this.$zoomIn = $magnify.find(cssSelector.zoomIn);
this.$zoomOut = $magnify.find(cssSelector.zoomOut);
this.$prev = $magnify.find(cssSelector.prev);
this.$next = $magnify.find(cssSelector.next);
this.$fullScreen = $magnify.find(cssSelector.fullScreen);
this.$actualSize = $magnify.find(cssSelector.actualSize);
this.$rotateLeft = $magnify.find(cssSelector.rotateLeft);
this.$rotateRight = $magnify.find(cssSelector.rotateRight);
if (!this.settings.dragHandle || this.settings.dragHandle === cssSelector.modal) {
this.dragHandle = this.$magnify;
} else {
this.dragHandle = this.$magnify.find(this.settings.dragHandle);
}
},
createDOM: function () {
var btnTpl = {
zoomIn: '<a href="javascript:void(0)" class="magnify-btn magnify-btn-zoomIn" title="' + this.settings.i18n.zoomIn + '"></a>',
zoomOut: '<a href="javascript:void(0)" class="magnify-btn magnify-btn-zoomOut" title="' + this.settings.i18n.zoomOut + '"></a>',
prev: '<a href="javascript:void(0)" class="magnify-btn magnify-btn-prev" title="' + this.settings.i18n.prev + '"></a>',
next: '<a href="javascript:void(0)" class="magnify-btn magnify-btn-next" title="' + this.settings.i18n.next + '"></a>',
actualSize: '<a href="javascript:void(0)" class="magnify-btn magnify-btn-actualSize" title="' + this.settings.i18n.actualSize + '"></a>',
rotateLeft: '<a href="javascript:void(0)" class="magnify-btn magnify-btn-rotateLeft" title="' + this.settings.i18n.rotateLeft + '"></a>',
rotateRight: '<a href="javascript:void(0)" class="magnify-btn magnify-btn-rotateRight" title="' + this.settings.i18n.rotateRight + '"></a>'
};
return '<div class="magnify-modal">' +
'<div class="magnify-header">' + this.createTitle() +
'<a href="javascript:void(0)" class="magnify-btn-close" title="' + this.settings.i18n.close + '"></a>' +
'</div>' +
'<div class="magnify-stage"><img src="" alt="" class="magnify-image" style="transform: rotate(0deg); transform-origin: 50% 50% 0px;"></div>' +
'<div class="magnify-footer"><div class="magnify-toolbar">' + this.createBtn(this.settings.Toolbar, btnTpl) + '</div></div>' +
'</div>';
},
createTitle: function () {
return this.settings.title ? '<div class="magnify-title"></div>' : '';
},
createBtn: function (toolbar, btns) {
var btnStr = '';
$.each(toolbar, function (index, item) {
btnStr += btns[item];
});
return btnStr;
},
setModalSize: function () {
var self = this;
var $modal = this.$magnify;
var winWidth = $W.width();
var winHeight = $W.height();
var newLeft = (winWidth - self.modalData.width) / 2;
var newTop = (winHeight - self.modalData.height) / 2;
$modal.css({
left: newLeft,
top: newTop
});
$.extend(self.modalData, {
left: newLeft,
top: newTop
})
},
setModalPos: function (modal) {
var winWidth = $W.width(),
winHeight = $W.height(),
modalSize = this.settings.modalSize,
modalWidth = modalSize[0],
modalHeight = modalSize[1];
modal.css({
width: modalWidth,
height: modalHeight,
left: (winWidth - modalWidth) / 2,
top: (winHeight - modalHeight) / 2
});
$.extend(this.modalData, {
width: modalWidth,
height: modalHeight,
left: (winWidth - modalWidth) / 2,
top: (winHeight - modalHeight) / 2
});
this.isOpened = true;
},
setImageSize: function (img, tag) {
var stageData = {
w: this.$stage.width(),
h: this.$stage.height()
};
var scale = 1;
if (!this.isRotated) {
scale = Math.min(stageData.w / img.width, stageData.h / img.height, 1);
} else {
scale = Math.min(stageData.w / img.height, stageData.h / img.width, 1);
}
/* this.$image.css({
width: Math.ceil(img.width * scale),
height: Math.ceil(img.height * scale),
left: (stageData.w - Math.ceil(img.width * scale)) / 2,
top: (stageData.h - Math.ceil(img.height * scale)) / 2
});*/
//console.log(stageData.w, this.$image.width(), img.width);
//如果进行了旋转
if (this.isRotated && tag === 'jump') {
this.$image.css({
left: (stageData.w - this.$image.width()) / 2,
top: (stageData.h - this.$image.height()) / 2
})
} else {
this.$image.css({
width: Math.ceil(img.width * scale),
height: Math.ceil(img.height * scale),
left: (stageData.w - Math.ceil(img.width * scale)) / 2,
top: (stageData.h - Math.ceil(img.height * scale)) / 2
});
}
$.extend(this.imageData, {
width: img.width * scale,
height: img.height * scale,
left: (stageData.w - img.width * scale) / 2,
top: (stageData.h - img.height * scale) / 2
});
setGrabCursor(
{w: this.$image.width(), h: this.$image.height()},
{w: this.$stage.width(), h: this.$stage.height()},
this.$stage,
this.isRotated
);
this.$magnify.find(cssSelector.loader).remove();
this.$image.fadeIn();
//console.log(this.$image);
},
loadImg: function (imgSrc, tag) {
var self = this;
var loadHTML = '<div class="magnify-loader"></div>';
this.$magnify.append(loadHTML);
self.$image.attr('src', imgSrc);
//imgSrc = './images/b1.png';
imgSrc = './images/b1.jpg';
preLoadImg(imgSrc, function (img) {
self.imageData = {
originalWidth: img.width,
originalHeight: img.height
};
self.setImageSize(img, tag);
}, function () {
self.$magnify.find(cssSelector.loader).remove();
});
if (this.settings.title) {
this.setImgTitle();
}
},
getImgGroup: function (list, imgSrc) {
var self = this;
self.groupData = [];
$(list).each(function (index, item) {
var src = getImgSrc(item);
self.groupData.push({
src: src,
caption: $(item).data('caption')
});
if (imgSrc === src) {
self.groupIndex = index;
}
})
},
setImgTitle: function () {
var index = this.groupIndex;
var caption = this.groupData[index].caption;
caption = caption ? caption : '';
this.$title.text(caption);
},
triggerHook: function (e, data) {
if (typeof this.settings[e] === 'function') {
typeof this.settings[e].call(this, $.isArray(data) ? data : [data], this.$magnify);
}
},
addEvents: function () {
var self = this;
this.$close.off(EVENTS.CLICK + EVENTS.EVENT_NS).on(EVENTS.CLICK + EVENTS.EVENT_NS, function () {
self.close();
});
this.$prev.off(EVENTS.CLICK + EVENTS.EVENT_NS).on(EVENTS.CLICK + EVENTS.EVENT_NS, function () {
self.jump(-1);
});
this.$next.off(EVENTS.CLICK + EVENTS.EVENT_NS).on(EVENTS.CLICK + EVENTS.EVENT_NS, function () {
self.jump(1);
});
this.$zoomIn.off(EVENTS.CLICK + EVENTS.EVENT_NS).on(EVENTS.CLICK + EVENTS.EVENT_NS, function () {
self.zoom(self.settings.ratioThreshold * 3, {x: self.$stage.width() / 2, y: self.$stage.height() / 2});
});
this.$zoomOut.off(EVENTS.CLICK + EVENTS.EVENT_NS).on(EVENTS.CLICK + EVENTS.EVENT_NS, function () {
self.zoom(-self.settings.ratioThreshold * 3, {x: self.$stage.width() / 2, y: self.$stage.height() / 2});
});
this.$actualSize.off(EVENTS.CLICK + EVENTS.EVENT_NS).on(EVENTS.CLICK + EVENTS.EVENT_NS, function () {
self.actualSize();
});
this.$rotateLeft.off(EVENTS.CLICK + EVENTS.EVENT_NS).on(EVENTS.CLICK + EVENTS.EVENT_NS, function () {
self.rotate(-90);
});
this.$rotateRight.off(EVENTS.CLICK + EVENTS.EVENT_NS).on(EVENTS.CLICK + EVENTS.EVENT_NS, function () {
self.rotate(90);
});
this.$stage.off(EVENTS.WHEEL + EVENTS.EVENT_NS).on(EVENTS.WHEEL + EVENTS.EVENT_NS, function (e) {
self.wheel(e);
});
$D.off(EVENTS.KEYDOWN + EVENTS.EVENT_NS).on(EVENTS.KEYDOWN + EVENTS.EVENT_NS, function (e) {
self.keyDown(e);
});
$W.on(EVENTS.RESIZE + EVENTS.EVENT_NS, function () {
self.resize();
});
},
close: function () {
this.triggerHook('beforeClose', this.$ele);
this.$magnify.remove();
this.isRotated = false;
this.isOpened = false;
this.rotateAngle = 0;
$D.off(EVENTS.KEYDOWN + EVENTS.EVENT_NS);
$W.off(EVENTS.RESIZE + EVENTS.EVENT_NS);
this.triggerHook('closed', this.$ele);
},
wheel: function (e) {
stopPre(e);
var delta = 1;
if (e.originalEvent.deltaY) {
delta = e.originalEvent.deltaY > 0 ? 1 : -1;
} else if (e.originalEvent.wheelDelta) {
delta = -e.originalEvent.wheelDelta / 120;
} else if (e.originalEvent.detail) {
delta = e.originalEvent.detail > 0 ? 1 : -1;
}
var ratio = -delta * this.settings.ratioThreshold;
var pointer = {
x: e.originalEvent.clientX - this.$stage.offset().left + $D.scrollLeft(),
y: e.originalEvent.clientY - this.$stage.offset().top + $D.scrollTop()
};
this.zoom(ratio, pointer, e);
},
zoom: function (ratio, origin) {
ratio = ratio < 0 ? (1 / (1 - ratio)) : (1 + ratio);
if (ratio > 0.95 && ratio < 1.05) {
ratio = 1;
}
//ratio = this.$image.width() / this.imageData.originalWidth * ratio;
//ratio = this.$image.width() / this.imageData.originalWidth * ratio;
ratio = parseInt(this.$image[0].style.width) / this.imageData.originalWidth * ratio;
ratio = Math.max(ratio, this.settings.minRatio);
ratio = Math.min(ratio, this.settings.maxRatio);
var $image = this.$image;
var $stage = this.$stage;
var imgData = {
w: this.imageData.width,
h: this.imageData.height,
x: this.imageData.left,
y: this.imageData.top
};
var stageData = {
w: $stage.width(),
h: $stage.height(),
x: $stage.offset().left,
y: $stage.offset().top
};
var newWidth = this.imageData.originalWidth * ratio;
var newHeight = this.imageData.originalHeight * ratio;
var newLeft = origin.x - (origin.x - imgData.x) / imgData.w * newWidth;
var newTop = origin.y - (origin.y - imgData.y) / imgData.h * newHeight;
var gt = !this.isRotated ? 0 : (newWidth - newHeight) / 2;
var imgNewWidth = !this.isRotated ? newWidth : newHeight;
var imgNewHeight = !this.isRotated ? newHeight : newWidth;
var offsetX = stageData.w - newWidth;
var offsetY = stageData.h - newHeight;
//先调整图片大小
$image.css({
width: Math.round(newWidth),
height: Math.round(newHeight)
});
//再调整图片位置
//获取当前的大小,如果有旋转,会有变化
var imgCurrWidth = $image.width();
var imgCurrHeight = $image.height();
if (imgNewWidth <= stageData.w) {
//缩小了 或者 没变
newLeft = (stageData.w - imgCurrWidth) / 2;
} else {
//放大了
newLeft = -(imgCurrWidth - stageData.w) / 2;
}
if (imgNewHeight <= stageData.h) {
newTop = (stageData.h - imgCurrHeight) / 2;
} else {
newTop = -(imgCurrHeight - stageData.h) / 2;
}
$image.css({
left: Math.round(newLeft),
top: Math.round(newTop)
})
/* if (imgNewHeight <= stageData.h) {
// 缩小了
newTop = (stageData.h - newHeight) / 2;
} else {
newTop = newTop > gt ? gt : (newTop > (offsetY - gt) ? newTop : (offsetY - gt));
}
if (imgNewWidth <= stageData.w) {
newLeft = (stageData.w - newWidth) / 2;
} else {
newLeft = newLeft > -gt ? -gt : (newLeft > (offsetX + gt) ? newLeft : (offsetX + gt));
}
$image.css({
width: Math.round(newWidth),
height: Math.round(newHeight),
left: Math.round(newLeft),
top: Math.round(newTop)
});*/
$.extend(this.imageData, {
width: newWidth,
height: newHeight,
left: newLeft,
top: newTop
});
setGrabCursor(
{w: Math.round(imgNewWidth), h: Math.round(imgNewHeight)},
{w: stageData.w, h: stageData.h},
this.$stage
);
},
jump: function (n) {
var groupLen = this.groupData.length;
if (n > 0) {
if (this.groupIndex + n >= groupLen) {
n = 0
} else {
n = this.groupIndex + 1
}
}
if (n < 0) {
if (this.groupIndex + n < 0) {
n = groupLen + n;
} else {
n = this.groupIndex + n
}
}
this.groupIndex = n;
this.triggerHook('beforeChange', n);
this.loadImg(this.groupData[n].src, 'jump');
this.triggerHook('changed', n);
},
actualSize: function () {
this.isRotated = false;
this.rotateAngle = 0;
this.$image.css({
transform: 'rotate(0deg)'
});
//兼容IE8
var useIeTransforms = function () {
var isIE = false;
if (navigator.appName === 'Microsoft Internet Explorer') {
if (navigator.userAgent.match(/Trident/i) && navigator.userAgent.match(/MSIE 8.0/i)) {
isIE = true
}
}
return isIE;
}();
if (useIeTransforms) {
this.$image.css('filter', 'progid:DXImageTransform.Microsoft.BasicImage(rotation=0)');
}
this.loadImg(this.groupData[this.groupIndex].src);
},
rotate: function (angle) {
var self = this;
this.rotateAngle = this.rotateAngle + angle;
this.isRotated = (this.rotateAngle / 90) % 2 !== 0;
self.transformDeg(this.$image,self.rotateAngle);
},
transformDeg: function (currentImg, currentDeg) {
var unit = this;
var useIeTransforms = function () {
var isIE = false;
if (navigator.appName === 'Microsoft Internet Explorer') {
if (navigator.userAgent.match(/Trident/i) && navigator.userAgent.match(/MSIE 8.0/i)) {
isIE = true
}
}
return isIE;
}();
var cssVal = 'rotate(' + currentDeg + 'deg)';
var _style = ['', '-webkit-', '-moz-', '-o-', '-ms-'];
for (var i = 0; i < _style.length; i++) {
var prefix = _style[i];
currentImg.css(prefix + 'transform', cssVal);
}
if (useIeTransforms) {
var _IeStyle = ['-ms-', ''];
for (var j = 0; j < _IeStyle.length; j++) {
var IEprefix = _IeStyle[j];
// ie8下旋转角度大于270度时就失效了
if(Math.abs(currentDeg)>=360){
currentDeg = currentDeg%360
}
currentImg.css(IEprefix + 'filter', unit.settings.ieTransforms[Math.abs(currentDeg)]);
/* var imgHeightStr = currentImg[0].style.height;
var imgWidthStr = currentImg[0].style.width;
var imgHeightNum = parseInt(imgHeightStr.substr(0, imgHeightStr.indexOf('px')));
var imgWidthNum = parseInt(imgWidthStr.substr(0, imgWidthStr.indexOf('px')));*/
//这样获取的实际的大小, 旋转后相应的宽高会变
var imgHeightNum = currentImg.height();
var imgWidthNum = currentImg.width();
if (defaults.modalSize[0] >= imgHeightNum) {
//缩小了 或者没变
currentImg.css(IEprefix+'left', defaults.modalSize[0]/2 - imgWidthNum/2 + 'px');
currentImg.css(IEprefix+'top', defaults.modalSize[1]/2 - imgHeightNum/2 + 'px');
} else {
//放大了
currentImg.css(IEprefix+'left', -(imgWidthNum - defaults.modalSize[0]) / 2 + 'px')
currentImg.css(IEprefix+'top', -(imgHeightNum - defaults.modalSize[1]) / 2 + 'px')
}
/*if(Math.abs(currentDeg) == 90 || Math.abs(currentDeg) == 270 ){
if(defaults.modalSize[1]>imgWidthNum){
//缩小了
currentImg.css(IEprefix+'left',(defaults.modalSize[1])/2 - imgWidthNum/2+'px');
}else if(defaults.modalSize[1]<=imgWidthNum){
//放大了
currentImg.css(IEprefix+'top',-(imgWidthNum-defaults.modalSize[1])/2+'px');
currentImg.css(IEprefix+'left',(defaults.modalSize[0])/2 - imgHeightNum/2+'px');
}
}else if(Math.abs(currentDeg) == 0 || Math.abs(currentDeg) == 180){
if(imgHeightNum > defaults.modalSize[0]){
currentImg.css(IEprefix+'left',(defaults.modalSize[0])/2 - imgHeightNum/2+'px');
currentImg.css(IEprefix+'top',-(imgHeightNum - defaults.modalSize[1])/2+'px');
}else if(imgHeightNum <= defaults.modalSize[1]){
currentImg.css(IEprefix+'left',(defaults.modalSize[0])/2 - imgWidthNum/2+'px');
currentImg.css(IEprefix+'top',(defaults.modalSize[1])/2 - imgHeightNum/2+'px');
}
}*/
}
}
},
resize: function () {
var self = this;
return throttle(function () {
self.setModalSize()
}, 500);
},
keyDown: function (e) {
var self = this;
if (!this.settings.keyboard) return false;
var keyCode = e.keyCode || e.which || e.charCode;
var ctrlKey = e.ctrlKey || e.metaKey;
var altKey = e.altKey || e.metaKey;
switch (keyCode) {
case 37:
self.jump(-1);
break;
case 39:
self.jump(1);
break;
case 38:
self.zoom(self.settings.ratioThreshold * 3, {
x: self.$stage.width() / 2,
y: self.$stage.height() / 2
});
break;
case 40:
self.zoom(-self.settings.ratioThreshold * 3, {
x: self.$stage.width() / 2,
y: self.$stage.height() / 2
});
break;
case 61:
self.zoom(self.settings.ratioThreshold * 3, {
x: self.$stage.width() / 2,
y: self.$stage.height() / 2
});
break;
case 173:
self.zoom(-self.settings.ratioThreshold * 3, {
x: self.$stage.width() / 2,
y: self.$stage.height() / 2
});
break;
//ctrl+> 逆旋转90度
case 188:
if (ctrlKey) {
self.rotate(-90);
}
break;
//ctrl+< 旋转90度
case 190:
if (ctrlKey) {
self.rotate(90);
}
break;
//ctrl+alt+0 复位
case 48:
if (ctrlKey && altKey) {
self.actualSize();
}
break;
}
},
movable: function (stage, image) {
var self = this,
isDragging = false,
startX = 0,
startY = 0,
left = 0,
top = 0,
widthDiff = 0,
heightDiff = 0,
gt = 0;
var dragStart = function (e) {
stopPre(e);
var imgWidth = $(image).width();
var imgHeight = $(image).height();
var stageWidth = $(stage).width();
var stageHeight = $(stage).height();
startX = e.clientX;
startY = e.clientY;
gt = !self.isRotated ? 0 : (imgWidth - imgHeight) / 2;
widthDiff = !self.isRotated ? imgWidth - stageWidth : imgHeight - stageWidth;
heightDiff = !self.isRotated ? imgHeight - stageHeight : imgWidth - stageHeight;
isDragging = widthDiff > 0 || heightDiff > 0 ? true : false;
isMoving = widthDiff > 0 || heightDiff > 0 ? true : false;
left = $(image).position().left - gt;
top = $(image).position().top + gt;
if (stage.hasClass('is-grab')) {
$('html,body,.magnify-modal,.magnify-stage,.magnify-btn').addClass('is-grabbing');
}
$D.on(EVENTS.MOUSEMOVE + EVENTS.EVENT_NS, dragMove).on(EVENTS.MOUSEEND + EVENTS.EVENT_NS, dragEnd);
};
var dragMove = function (e) {
stopPre(e);
if (isDragging) {
var endX = e.clientX, endY = e.clientY;
var relativeX = endX - startX, relativeY = endY - startY;
var newLeft = relativeX + left, newTop = relativeY + top;
if (heightDiff > 0) {
if (relativeY + top > gt) {
newTop = gt;
} else if (relativeY + top < -heightDiff + gt) {
newTop = -heightDiff + gt;
}
} else {
newTop = top;
}
if (widthDiff > 0) {
if (relativeX + left > -gt) {
newLeft = -gt;
} else if (relativeX + left < -widthDiff - gt) {
newLeft = -widthDiff - gt;
}
} else {
newLeft = left;
}
$(image).css({
left: newLeft,
top: newTop
});
$.extend(self.imageData, {
left: newLeft,
top: newTop
});
}
};
var dragEnd = function () {
$D.off(EVENTS.MOUSEMOVE + EVENTS.EVENT_NS, dragMove).off(EVENTS.MOUSEEND + EVENTS.EVENT_NS, dragEnd);
isDragging = false;
isMoving = false;
$('html,body,.magnify-modal,.magnify-stage,.magnify-btn').removeClass('is-grabbing');
};
$(stage).on(EVENTS.MOUSESTART + EVENTS.EVENT_NS, dragStart);
},
draggable: function (modal, dragHandle, dragCancel) {
var isDragging = false;
var startX = 0, startY = 0, left = 0, top = 0;
var dragStart = function (e) {
e = e || window.event;
var cancelElem = $(e.target).closest(dragCancel);
if (cancelElem.length) {
return true;
}
isDragging = true;
startX = e.clientX;
startY = e.clientY;
left = $(modal).offset().left;
top = $(modal).offset().top;
$D.on(EVENTS.MOUSEMOVE + EVENTS.EVENT_NS, dragMove).on(EVENTS.MOUSEEND + EVENTS.EVENT_NS, dragEnd);
};
var dragMove = function (e) {
stopPre(e);
if (isDragging && !isMoving && !isResizing) {
var endX = e.clientX;
var endY = e.clientY;
var relativeX = endX - startX;
var relativeY = endY - startY;
$(modal).css({
left: relativeX + left,
top: relativeY + top
})
}
};
var dragEnd = function () {
$D.off(EVENTS.MOUSEMOVE + EVENTS.EVENT_NS, dragMove).off(EVENTS.MOUSEEND + EVENTS.EVENT_NS, dragEnd);
isDragging = false;
};
$(dragHandle).on(EVENTS.MOUSESTART + EVENTS.EVENT_NS, dragStart);
}
};
$.fn.Magnify = function (options) {
jqEle = $(this);
var opts = $.extend(true, {}, defaults, options);
jqEle.off(EVENTS.CLICK + EVENTS.EVENT_NS).on(EVENTS.CLICK + EVENTS.EVENT_NS, function (e) {
stopPro(e);
stopPre(e);
$(this).data('magnify', new magnify(this, opts));
});
return jqEle;
};
// 阻止冒泡
function stopPro(event) {
event = event || window.event;
try {
event.stopPropagation();
} catch (e) {
event.cancelBubble = true;
}
}
// 阻止浏览器默认行为
function stopPre(event) {
event = event || window.event;
try {
event.preventDefault();
} catch (e) {
event.returnValue = false;
}
}
// 获取图片地址
function getImgSrc(ele) {
return $(ele).data('src') || $(ele).attr('href');
}
// 获取图片原始属性
function preLoadImg(src, success, error) {
var img = new Image();
img.onload = function () {
success(img);
};
img.onerror = function () {
error(img)
};
img.src = src;
}
function setGrabCursor(imageData, stageData, stage, isRotated) {
var imgWidth = !isRotated ? imageData.w : imageData.h;
var imgHeight = !isRotated ? imageData.h : imageData.w;
if (imgHeight > stageData.h || imgWidth > stageData.w) {
stage.addClass('is-grab');
}
if (imgHeight <= stageData.h && imgWidth <= stageData.w) {
stage.removeClass('is-grab')
}
}
function throttle(fn, delay) {
var timer = null;
var context = this, args = arguments;
clearTimeout(timer);
timer = setTimeout(function () {
fn.apply(context, args);
}, delay);
}
});