首先引用一段关于拖动,缩放,剪切的基础代码
1 /* 2 * 作者:http://cloudgamer.cnblogs.com/ 3 * 4 * 改进与增强 5 * 作者:http://yoker.sc0826.com/ 6 * 时间:2008年11月09日 7 * 功能:远程web图片在线裁剪,图片预加载比例缩放,裁剪参数个性设置,裁剪比例缩放等。 8 */ 9 10 /* -------------这里定义一些环境变量--------------- */ 11 12 //获取dom对象的方法 13 var $ = function(id) { 14 return "string" == typeof id ? document.getElementById(id) : id; 15 }; 16 //判断是否ie 17 var isIE = (document.all) ? true : false; 18 //添加事件 19 function addEventHandler(oTarget, sEventType, fnHandler) { 20 if (oTarget.addEventListener) { 21 oTarget.addEventListener(sEventType, fnHandler, false); 22 } else if (oTarget.attachEvent) { 23 oTarget.attachEvent("on" + sEventType, fnHandler); 24 } else { 25 oTarget["on" + sEventType] = fnHandler; 26 } 27 }; 28 //移除事件 29 function removeEventHandler(oTarget, sEventType, fnHandler) { 30 if (oTarget.removeEventListener) { 31 oTarget.removeEventListener(sEventType, fnHandler, false); 32 } else if (oTarget.detachEvent) { 33 oTarget.detachEvent("on" + sEventType, fnHandler); 34 } else { 35 oTarget["on" + sEventType] = null; 36 } 37 }; 38 //这相当于一个类工厂。 39 //js中函数即是类,new function()就是用该函数作为构造函数生成一个对象 40 //当然,默认的该对象需自定义一个initialize方法 41 var Class = { 42 create: function() { 43 return function() { 44 this.initialize.apply(this, arguments); 45 } 46 } 47 } 48 49 //这是对象拷贝函数 50 Object.extend = function(destination, source) { 51 for (var property in source) { 52 destination[property] = source[property]; 53 } 54 return destination; 55 }
这里定义了几个环境变量,包括挂载/卸载事件方法,根据id获取dom对象方法。比较有意思的是
var Class = {
create: function() {
return function() {
this.initialize.apply(this, arguments);
}
}
}
的写法。网上说prototype.js是这么写的。
看起来这样写实现了某种标准化,比如能产生一批受约束的类,这些类看起来是从某个抽象类中继承而来,然后更方便的用propertype定义方法。
整个编程看起来更加面向对象而不是面向函数。
除此之外没什么好处。
js的prototype相当于c#的直接初始化字段,function相当于在构造函数中初始化字段,无形中都生成对象。js中的this应是某个对象,
1 //拖放程序 2 var Drag = Class.create(); 3 Drag.prototype = { 4 //拖放对象,触发对象 5 initialize: function(obj, drag, options) { 6 var oThis = this; 7 8 this._obj = $(obj); //拖放对象 9 this.Drag = $(drag); //触发对象 10 this._x = this._y = 0; //记录鼠标相对拖放对象的位置 11 //事件对象(用于移除事件) 12 this._fM = function(e) { oThis.Move(window.event || e); } 13 this._fS = function() { oThis.Stop(); } 14 15 this.SetOptions(options); 16 17 this.Limit = !!this.options.Limit; 18 this.mxLeft = parseInt(this.options.mxLeft); 19 this.mxRight = parseInt(this.options.mxRight); 20 this.mxTop = parseInt(this.options.mxTop); 21 this.mxBottom = parseInt(this.options.mxBottom); 22 23 this.onMove = this.options.onMove; 24 25 this._obj.style.position = "absolute"; 26 addEventHandler(this.Drag, "mousedown", function(e) { oThis.Start(window.event || e); }); 27 }, 28 //设置默认属性 29 SetOptions: function(options) { 30 this.options = {//默认值 31 Limit: false, //是否设置限制(为true时下面参数有用,可以是负数) 32 mxLeft: 0, //左边限制 33 mxRight: 0, //右边限制 34 mxTop: 0, //上边限制 35 mxBottom: 0, //下边限制 36 onMove: function() { } //移动时执行 37 }; 38 Object.extend(this.options, options || {}); 39 }, 40 //准备拖动 41 Start: function(oEvent) { 42 //记录鼠标相对拖放对象的位置 43 this._x = oEvent.clientX - this._obj.offsetLeft; 44 this._y = oEvent.clientY - this._obj.offsetTop; 45 //mousemove时移动 mouseup时停止 46 addEventHandler(document, "mousemove", this._fM); 47 addEventHandler(document, "mouseup", this._fS); 48 //使鼠标移到窗口外也能释放 49 if (isIE) { 50 addEventHandler(this.Drag, "losecapture", this._fS); 51 this.Drag.setCapture(); 52 } else { 53 addEventHandler(window, "blur", this._fS); 54 } 55 }, 56 //拖动 57 Move: function(oEvent) { 58 //清除选择(ie设置捕获后默认带这个) 59 window.getSelection && window.getSelection().removeAllRanges(); 60 //当前鼠标位置减去相对拖放对象的位置得到offset位置 61 var iLeft = oEvent.clientX - this._x, iTop = oEvent.clientY - this._y; 62 //设置范围限制 63 if (this.Limit) { 64 //获取超出长度 65 var iRight = iLeft + this._obj.offsetWidth - this.mxRight, iBottom = iTop + this._obj.offsetHeight - this.mxBottom; 66 //这里是先设置右边下边再设置左边上边,可能会不准确 67 if (iRight > 0) iLeft -= iRight; 68 if (iBottom > 0) iTop -= iBottom; 69 if (this.mxLeft > iLeft) iLeft = this.mxLeft; 70 if (this.mxTop > iTop) iTop = this.mxTop; 71 } 72 //设置位置 73 this._obj.style.left = iLeft + "px"; 74 this._obj.style.top = iTop + "px"; 75 //附加程序 76 this.onMove(); 77 }, 78 //停止拖动 79 Stop: function() { 80 //移除事件 81 removeEventHandler(document, "mousemove", this._fM); 82 removeEventHandler(document, "mouseup", this._fS); 83 if (isIE) { 84 removeEventHandler(this.Drag, "losecapture", this._fS); 85 this.Drag.releaseCapture(); 86 } else { 87 removeEventHandler(window, "blur", this._fS); 88 } 89 } 90 };
拖放类的基本思路是给一个参照的dom对象,一个移动的dom对象,捕捉鼠标相对参照对象的变化,赋值给移动对象。
另外两个功能,其一允许用户自定义onmove,把移动中x,y值传出去,其二给移动对象定义mouseclik确保鼠标按下时记录相关参数,做好拖放准备。
总之是拖放功能的总管秘书。
缩放类
与拖放类思路基本相同。
document.defaultView.getComputedStyle用于获取所有dom元素的style对象。
1 //图片切割 2 var ImgCropper = Class.create(); 3 ImgCropper.prototype = { 4 //容器对象,拖放缩放对象,图片地址,宽度,高度 5 initialize: function(container, drag, url, width, height, options) { 6 var oThis = this; 7 8 //容器对象 9 this.Container = $(container); 10 this.Container.style.position = "relative"; 11 this.Container.style.overflow = "hidden"; 12 13 14 //拖放对象 15 this.Drag = $(drag); 16 this.Drag.style.cursor = "move"; 17 this.Drag.style.zIndex = 200; 18 if (isIE) { 19 //设置overflow解决ie6的渲染问题(缩放时填充对象高度的问题) 20 this.Drag.style.overflow = "hidden"; 21 //ie下用一个透明的层填充拖放对象 不填充的话onmousedown会失效(未知原因) 22 (function(style) { 23 style.width = style.height = "100%"; 24 style.backgroundColor = "#fff"; 25 style.opacity = 0; 26 style.filter = 'alpha(opacity = 0)'; 27 })(this.Drag.appendChild(document.createElement("div")).style) 28 } 29 30 this._cropper = this.Container.appendChild(document.createElement("img")); //切割对象 31 this._pic = this.Container.appendChild(document.createElement("img")); //图片对象 32 this._pic.style.position = "absolute"; 33 this._cropper.style.position = "absolute"; 34 this._pic.style.top = this._pic.style.left = this._cropper.style.top = this._cropper.style.left = "0"; //对齐 35 this._pic.style.zIndex = 100; 36 this._cropper.style.zIndex = 150; 37 this._cropper.onload = function() { oThis.SetPos(); } 38 39 40 41 this.Url = url; //图片地址 42 this.Width = parseInt(width); //宽度 43 this.Height = parseInt(height); //高度 44 45 this.SetOptions(options); 46 47 this.Opacity = parseInt(this.options.Opacity); 48 this.dragTop = parseInt(this.options.dragTop); 49 this.dragLeft = parseInt(this.options.dragLeft); 50 this.dragWidth = parseInt(this.options.dragWidth); 51 this.dragHeight = parseInt(this.options.dragHeight); 52 53 //设置预览对象 54 this.View = $(this.options.View) || null; //预览对象 55 this.viewWidth = parseInt(this.options.viewWidth); 56 this.viewHeight = parseInt(this.options.viewHeight); 57 this._view = null; //预览图片对象 58 if (this.View) { 59 this.View.style.position = "relative"; 60 this.View.style.overflow = "hidden"; 61 this._view = this.View.appendChild(document.createElement("img")); 62 this._view.style.position = "absolute"; 63 } 64 65 this.Scale = parseInt(this.options.Scale); 66 67 //设置拖放 68 this._drag = new Drag(this.Drag, this.Drag, { Limit: true, onMove: function() { oThis.SetPos(); } }); 69 //设置缩放 70 this._resize = this.GetResize(); 71 this.Init(); 72 }, 73 //设置默认属性 74 SetOptions: function(options) { 75 this.options = {//默认值 76 Opacity: 50, //透明度(0到100) 77 //拖放位置和宽高 78 dragTop: 0, 79 dragLeft: 0, 80 dragWidth: 100, 81 dragHeight: 100, 82 //缩放触发对象 83 Right: "", 84 Left: "", 85 Up: "", 86 Down: "", 87 RightDown: "", 88 LeftDown: "", 89 RightUp: "", 90 LeftUp: "", 91 Scale: false, //是否按比例缩放 92 //预览对象设置 93 View: "", //预览对象 94 viewWidth: 100, //预览宽度 95 viewHeight: 100//预览高度 96 }; 97 Object.extend(this.options, options || {}); 98 }, 99 //初始化对象 100 Init: function() { 101 var oThis = this; 102 103 //设置拖放对象 104 this.Drag.style.top = this.dragTop + "px"; 105 this.Drag.style.left = this.dragLeft + "px"; 106 this.Drag.style.width = this.dragWidth + "px"; 107 this.Drag.style.height = this.dragHeight + "px"; 108 109 //Yoker.Wu前台缩放效果改善,图片加载完成后,得到缩放大小再初始化显示 110 var trueImg = new Image(); 111 trueImg.src = this.Url; 112 //图片已经加载并缓存 113 if (trueImg.complete) { 114 if (trueImg.width > oThis.Width || trueImg.height > oThis.Height) { 115 if (this.Width / this.Height > trueImg.width / trueImg.height) { 116 this.Width = parseInt(trueImg.width * this.Height / trueImg.height); 117 } else { 118 this.Height = parseInt(trueImg.height * this.Width / trueImg.width); 119 } 120 } else { 121 this.Width = trueImg.width; 122 this.Height = trueImg.height; 123 } 124 125 //设置容器 126 this.Container.style.width = this.Width + "px"; 127 this.Container.style.height = this.Height + "px"; 128 129 //设置切割对象 130 this._cropper.src = this.Url; 131 this._pic.src = this.Url; 132 this._pic.style.width = this._cropper.style.width = this.Width + "px"; 133 this._pic.style.height = this._cropper.style.height = this.Height + "px"; 134 if (isIE) { 135 if (navigator.appVersion.indexOf("MSIE 6.0") != -1 136 || navigator.appVersion.indexOf("MSIE 7.0") != -1 137 || navigator.appVersion.indexOf("MSIE 8.0") != -1) { 138 this._pic.style.filter = "alpha(opacity:" + this.Opacity + ")"; 139 } 140 else if (navigator.appVersion.indexOf("MSIE 9.0") != -1) { 141 this._pic.style.filter = "alpha(opacity:" + this.Opacity + ")"; 142 this._pic.style.opacity = this.Opacity / 100; 143 } 144 else { 145 this._pic.style.opacity = this.Opacity / 100; 146 } 147 } else { 148 this._pic.style.opacity = this.Opacity / 100; 149 } 150 this._cropper.style.filter = "alpha(opacity:100)"; 151 this._cropper.style.opacity = 1; 152 //设置预览对象 153 if (this.View) { this._view.src = this.Url; } 154 155 //设置拖放 156 this._drag.mxRight = this.Width; this._drag.mxBottom = this.Height; 157 //设置缩放 158 if (this._resize) { this._resize.mxRight = this.Width; this._resize.mxBottom = this.Height; this._resize.Scale = this.Scale; } 159 } 160 //新加载的情况 161 trueImg.onload = function() { 162 if (this.width > oThis.Width || this.height > oThis.Height) { 163 if (oThis.Width / oThis.Height > this.width / this.height) { 164 oThis.Width = parseInt(this.width * oThis.Height / this.height); 165 } else { 166 oThis.Height = parseInt(this.height * oThis.Width / this.width); 167 } 168 } else { 169 oThis.Width = this.width; 170 oThis.Height = this.height; 171 } 172 //设置容器 173 oThis.Container.style.width = oThis.Width + "px"; 174 oThis.Container.style.height = oThis.Height + "px"; 175 176 //设置切割对象 177 oThis._cropper.src = oThis.Url; 178 oThis._pic.src = oThis.Url; 179 oThis._pic.style.width = oThis._cropper.style.width = oThis.Width + "px"; 180 oThis._pic.style.height = oThis._cropper.style.height = oThis.Height + "px"; 181 if (isIE) { 182 if (navigator.appVersion.indexOf("MSIE 6.0") != -1 183 || navigator.appVersion.indexOf("MSIE 7.0") != -1 184 || navigator.appVersion.indexOf("MSIE 8.0") != -1) { 185 oThis._pic.style.filter = "alpha(opacity:" + oThis.Opacity + ")"; 186 } 187 else if (navigator.appVersion.indexOf("MSIE 9.0") != -1) { 188 oThis._pic.style.filter = "alpha(opacity:" + oThis.Opacity + ")"; 189 oThis._pic.style.opacity = oThis.Opacity / 100; 190 } 191 else { 192 oThis._pic.style.opacity = oThis.Opacity / 100; 193 } 194 } else { 195 oThis._pic.style.opacity = oThis.Opacity / 100; 196 } 197 oThis._cropper.style.filter = "alpha(opacity:100)"; 198 oThis._cropper.style.opacity = 1; 199 200 //设置预览对象 201 if (oThis.View) { oThis._view.src = oThis.Url; } 202 203 //设置拖放 204 oThis._drag.mxRight = oThis.Width; oThis._drag.mxBottom = oThis.Height; 205 //设置缩放 206 if (oThis._resize) { oThis._resize.mxRight = oThis.Width; oThis._resize.mxBottom = oThis.Height; oThis._resize.Scale = oThis.Scale; } 207 } 208 }, 209 //设置获取缩放对象 210 GetResize: function() { 211 var op = this.options; 212 //有触发对象时才设置 213 if (op.RightDown || op.LeftDown || op.RightUp || op.LeftUp || op.Right || op.Left || op.Up || op.Down) { 214 var oThis = this, _resize = new Resize(this.Drag, { Limit: true, onResize: function() { oThis.SetPos(); } }); 215 216 //设置缩放触发对象 217 if (op.RightDown) { _resize.Set(op.RightDown, "right-down"); } 218 if (op.LeftDown) { _resize.Set(op.LeftDown, "left-down"); } 219 220 if (op.RightUp) { _resize.Set(op.RightUp, "right-up"); } 221 if (op.LeftUp) { _resize.Set(op.LeftUp, "left-up"); } 222 223 if (op.Right) { _resize.Set(op.Right, "right"); } 224 if (op.Left) { _resize.Set(op.Left, "left"); } 225 226 if (op.Up) { _resize.Set(op.Up, "up"); } 227 if (op.Down) { _resize.Set(op.Down, "down"); } 228 229 return _resize; 230 } else { return null; } 231 }, 232 //设置切割 233 SetPos: function() { 234 var o = this.Drag; 235 //按拖放对象的参数进行切割 236 this._cropper.style.clip = "rect(" + o.offsetTop + "px " + (o.offsetLeft + o.offsetWidth) + "px " + (o.offsetTop + o.offsetHeight) + "px " + o.offsetLeft + "px)"; 237 238 //切割预览 239 if (this.View) this.PreView(); 240 }, 241 //切割预览 242 PreView: function() { 243 //按比例设置宽度和高度 244 var o = this.Drag, h = this.viewWidth, w = h * o.offsetWidth / o.offsetHeight; 245 if (w > this.viewHeight) { w = this.viewHeight; h = w * o.offsetHeight / o.offsetWidth; } 246 //获取对应比例尺寸 247 var scale = h / o.offsetHeight, ph = this.Height * scale, pw = this.Width * scale, pt = o.offsetTop * scale, pl = o.offsetLeft * scale, styleView = this._view.style; 248 //设置样式 249 styleView.width = pw + "px"; styleView.height = ph + "px"; 250 styleView.top = -pt + "px "; styleView.left = -pl + "px"; 251 //切割预览图 252 styleView.clip = "rect(" + pt + "px " + (pl + w) + "px " + (pt + h) + "px " + pl + "px)"; 253 } 254 }
拖放中 window.getSelection && window.getSelection().removeAllRanges();用途不明,待查。
缩放中防止冒泡用户不明。