`
cloudgamer
  • 浏览: 61038 次
  • 性别: Icon_minigender_1
  • 来自: 顺德
社区版块
存档分类
最新评论

JavaScript 图片切割效果

阅读更多

序一(08/07/21)

很久之前就在一个网站的截取相片的功能中看到这个效果,也叫图片裁剪、图片剪切(设置一下也可以做出放大镜等类似的效果)。
当时觉得很神奇,碍于水平有限,没做出来。
前些日子突然想做一个透镜效果,就突然想到了这个效果,于是找出当年“珍藏”的代码决定一尝所愿。

序二(08/12/06)

自上一个版本的图片切割效果出来后,虽然也经常看到“框架开发这个如何如何容易”之类的评论,但也受到很多人的肯定,小弟在此感谢大家的支持。
上一个版本由于是初次接触这类效果,而且是三个大功能一起开发,能力所限,所以仅仅是实现了效果就完成了。
后来我知道这个效果叫ImageCropper,找了些这类效果参考,完善了切割的部分。
近来我把其中的拖放效果缩放效果单独出来研究,经过整理和完善,再套进切割效果,个人感觉效果已经不错了。
要说明的是这个只是一个效果,并不是真正的切割图片,要获取真正的切割图片请参考图片切割系统

先看看效果:

<script type="text/javascript"><!-- var isIE = (document.all) ? true : false; var $$ = function (id) { return "string" == typeof id ? document.getElementById(id) : id; }; var Class = { create: function() { return function() { this.initialize.apply(this, arguments); } } } var Extend = function(destination, source) { for (var property in source) { destination[property] = source[property]; } } var Bind = function(object, fun) { return function() { return fun.apply(object, arguments); } } var BindAsEventListener = function(object, fun) { var args = Array.prototype.slice.call(arguments).slice(2); return function(event) { return fun.apply(object, [event || window.event].concat(args)); } } var CurrentStyle = function(element){ return element.currentStyle || document.defaultView.getComputedStyle(element, null); } function addEventHandler(oTarget, sEventType, fnHandler) { if (oTarget.addEventListener) { oTarget.addEventListener(sEventType, fnHandler, false); } else if (oTarget.attachEvent) { oTarget.attachEvent("on" + sEventType, fnHandler); } else { oTarget["on" + sEventType] = fnHandler; } }; function removeEventHandler(oTarget, sEventType, fnHandler) { if (oTarget.removeEventListener) { oTarget.removeEventListener(sEventType, fnHandler, false); } else if (oTarget.detachEvent) { oTarget.detachEvent("on" + sEventType, fnHandler); } else { oTarget["on" + sEventType] = null; } }; //图片切割 var ImgCropper = Class.create(); ImgCropper.prototype = { //容器对象,控制层,图片地址 initialize: function(container, handle, url, options) { this._Container = $$(container);//容器对象 this._layHandle = $$(handle);//控制层 this.Url = url;//图片地址 this._layBase = this._Container.appendChild(document.createElement("img"));//底层 this._layCropper = this._Container.appendChild(document.createElement("img"));//切割层 this._layCropper.onload = Bind(this, this.SetPos); //用来设置大小 this._tempImg = document.createElement("img"); this._tempImg.onload = Bind(this, this.SetSize); this.SetOptions(options); this.Opacity = Math.round(this.options.Opacity); this.Color = this.options.Color; this.Scale = !!this.options.Scale; this.Ratio = Math.max(this.options.Ratio, 0); this.Width = Math.round(this.options.Width); this.Height = Math.round(this.options.Height); //设置预览对象 var oPreview = $$(this.options.Preview);//预览对象 if(oPreview){ oPreview.style.position = "relative"; oPreview.style.overflow = "hidden"; this.viewWidth = Math.round(this.options.viewWidth); this.viewHeight = Math.round(this.options.viewHeight); //预览图片对象 this._view = oPreview.appendChild(document.createElement("img")); this._view.style.position = "absolute"; this._view.onload = Bind(this, this.SetPreview); } //设置拖放 this._drag = new Drag(this._layHandle, { Limit: true, onMove: Bind(this, this.SetPos), Transparent: true }); //设置缩放 this.Resize = !!this.options.Resize; if(this.Resize){ var op = this.options, _resize = new Resize(this._layHandle, { Max: true, onResize: Bind(this, this.SetPos) }); //设置缩放触发对象 op.RightDown && (_resize.Set(op.RightDown, "right-down")); op.LeftDown && (_resize.Set(op.LeftDown, "left-down")); op.RightUp && (_resize.Set(op.RightUp, "right-up")); op.LeftUp && (_resize.Set(op.LeftUp, "left-up")); op.Right && (_resize.Set(op.Right, "right")); op.Left && (_resize.Set(op.Left, "left")); op.Down && (_resize.Set(op.Down, "down")); op.Up && (_resize.Set(op.Up, "up")); //最小范围限制 this.Min = !!this.options.Min; this.minWidth = Math.round(this.options.minWidth); this.minHeight = Math.round(this.options.minHeight); //设置缩放对象 this._resize = _resize; } //设置样式 this._Container.style.position = "relative"; this._Container.style.overflow = "hidden"; this._layHandle.style.zIndex = 200; this._layCropper.style.zIndex = 100; this._layBase.style.position = this._layCropper.style.position = "absolute"; this._layBase.style.top = this._layBase.style.left = this._layCropper.style.top = this._layCropper.style.left = 0;//对齐 //初始化设置 this.Init(); }, //设置默认属性 SetOptions: function(options) { this.options = {//默认值 Opacity: 50,//透明度(0到100) Color: "",//背景色 Width: 0,//图片高度 Height: 0,//图片高度 //缩放触发对象 Resize: false,//是否设置缩放 Right: "",//右边缩放对象 Left: "",//左边缩放对象 Up: "",//上边缩放对象 Down: "",//下边缩放对象 RightDown: "",//右下缩放对象 LeftDown: "",//左下缩放对象 RightUp: "",//右上缩放对象 LeftUp: "",//左上缩放对象 Min: false,//是否最小宽高限制(为true时下面min参数有用) minWidth: 50,//最小宽度 minHeight: 50,//最小高度 Scale: false,//是否按比例缩放 Ratio: 0,//缩放比例(宽/高) //预览对象设置 Preview: "",//预览对象 viewWidth: 0,//预览宽度 viewHeight: 0//预览高度 }; Extend(this.options, options || {}); }, //初始化对象 Init: function() { //设置背景色 this.Color && (this._Container.style.backgroundColor = this.Color); //设置图片 this._tempImg.src = this._layBase.src = this._layCropper.src = this.Url; //设置透明 if(isIE){ this._layBase.style.filter = "alpha(opacity:" + this.Opacity + ")"; } else { this._layBase.style.opacity = this.Opacity / 100; } //设置预览对象 this._view && (this._view.src = this.Url); //设置缩放 if(this.Resize){ with(this._resize){ Scale = this.Scale; Ratio = this.Ratio; Min = this.Min; minWidth = this.minWidth; minHeight = this.minHeight; } } }, //设置切割样式 SetPos: function() { //ie6渲染bug with(this._layHandle.style){ zoom = .9; zoom = 1; } //获取位置参数 var p = this.GetPos(); //按拖放对象的参数进行切割 this._layCropper.style.clip = "rect(" + p.Top + "px " + (p.Left + p.Width) + "px " + (p.Top + p.Height) + "px " + p.Left + "px)"; //设置预览 this.SetPreview(); }, //设置预览效果 SetPreview: function() { if(this._view){ //预览显示的宽和高 var p = this.GetPos(), s = this.GetSize(p.Width, p.Height, this.viewWidth, this.viewHeight), scale = s.Height / p.Height; //按比例设置参数 var pHeight = this._layBase.height * scale, pWidth = this._layBase.width * scale, pTop = p.Top * scale, pLeft = p.Left * scale; //设置预览对象 with(this._view.style){ //设置样式 width = pWidth + "px"; height = pHeight + "px"; top = - pTop + "px "; left = - pLeft + "px"; //切割预览图 clip = "rect(" + pTop + "px " + (pLeft + s.Width) + "px " + (pTop + s.Height) + "px " + pLeft + "px)"; } } }, //设置图片大小 SetSize: function() { var s = this.GetSize(this._tempImg.width, this._tempImg.height, this.Width, this.Height); //设置底图和切割图 this._layBase.style.width = this._layCropper.style.width = s.Width + "px"; this._layBase.style.height = this._layCropper.style.height = s.Height + "px"; //设置拖放范围 this._drag.mxRight = s.Width; this._drag.mxBottom = s.Height; //设置缩放范围 if(this.Resize){ this._resize.mxRight = s.Width; this._resize.mxBottom = s.Height; } }, //获取当前样式 GetPos: function() { with(this._layHandle){ return { Top: offsetTop, Left: offsetLeft, Width: offsetWidth, Height: offsetHeight } } }, //获取尺寸 GetSize: function(nowWidth, nowHeight, fixWidth, fixHeight) { var iWidth = nowWidth, iHeight = nowHeight, scale = iWidth / iHeight; //按比例设置 if(fixHeight){ iWidth = (iHeight = fixHeight) * scale; } if(fixWidth && (!fixHeight || iWidth > fixWidth)){ iHeight = (iWidth = fixWidth) / scale; } //返回尺寸对象 return { Width: iWidth, Height: iHeight } } } // --></script><script type="text/javascript"><!-- //拖放程序 var Drag = Class.create(); Drag.prototype = { //拖放对象 initialize: function(drag, options) { this.Drag = $$(drag);//拖放对象 this._x = this._y = 0;//记录鼠标相对拖放对象的位置 this._marginLeft = this._marginTop = 0;//记录margin //事件对象(用于绑定移除事件) this._fM = BindAsEventListener(this, this.Move); this._fS = Bind(this, this.Stop); this.SetOptions(options); this.Limit = !!this.options.Limit; this.mxLeft = parseInt(this.options.mxLeft); this.mxRight = parseInt(this.options.mxRight); this.mxTop = parseInt(this.options.mxTop); this.mxBottom = parseInt(this.options.mxBottom); this.LockX = !!this.options.LockX; this.LockY = !!this.options.LockY; this.Lock = !!this.options.Lock; this.onStart = this.options.onStart; this.onMove = this.options.onMove; this.onStop = this.options.onStop; this._Handle = $$(this.options.Handle) || this.Drag; this._mxContainer = $$(this.options.mxContainer) || null; this.Drag.style.position = "absolute"; //透明 if(isIE && !!this.options.Transparent){ //填充拖放对象 with(this._Handle.appendChild(document.createElement("div")).style){ width = height = "100%"; backgroundColor = "#fff"; filter = "alpha(opacity:0)"; fontSize = 0; } } //修正范围 this.Repair(); addEventHandler(this._Handle, "mousedown", BindAsEventListener(this, this.Start)); }, //设置默认属性 SetOptions: function(options) { this.options = {//默认值 Handle: "",//设置触发对象(不设置则使用拖放对象) Limit: false,//是否设置范围限制(为true时下面参数有用,可以是负数) mxLeft: 0,//左边限制 mxRight: 9999,//右边限制 mxTop: 0,//上边限制 mxBottom: 9999,//下边限制 mxContainer: "",//指定限制在容器内 LockX: false,//是否锁定水平方向拖放 LockY: false,//是否锁定垂直方向拖放 Lock: false,//是否锁定 Transparent: false,//是否透明 onStart: function(){},//开始移动时执行 onMove: function(){},//移动时执行 onStop: function(){}//结束移动时执行 }; Extend(this.options, options || {}); }, //准备拖动 Start: function(oEvent) { if(this.Lock){ return; } this.Repair(); //记录鼠标相对拖放对象的位置 this._x = oEvent.clientX - this.Drag.offsetLeft; this._y = oEvent.clientY - this.Drag.offsetTop; //记录margin this._marginLeft = parseInt(CurrentStyle(this.Drag).marginLeft) || 0; this._marginTop = parseInt(CurrentStyle(this.Drag).marginTop) || 0; //mousemove时移动 mouseup时停止 addEventHandler(document, "mousemove", this._fM); addEventHandler(document, "mouseup", this._fS); if(isIE){ //焦点丢失 addEventHandler(this._Handle, "losecapture", this._fS); //设置鼠标捕获 this._Handle.setCapture(); }else{ //焦点丢失 addEventHandler(window, "blur", this._fS); //阻止默认动作 oEvent.preventDefault(); }; //附加程序 this.onStart(); }, //修正范围 Repair: function() { if(this.Limit){ //修正错误范围参数 this.mxRight = Math.max(this.mxRight, this.mxLeft + this.Drag.offsetWidth); this.mxBottom = Math.max(this.mxBottom, this.mxTop + this.Drag.offsetHeight); //如果有容器必须设置position为relative来相对定位,并在获取offset之前设置 !this._mxContainer || CurrentStyle(this._mxContainer).position == "relative" || (this._mxContainer.style.position = "relative"); } }, //拖动 Move: function(oEvent) { //判断是否锁定 if(this.Lock){ this.Stop(); return; }; //清除选择 window.getSelection ? window.getSelection().removeAllRanges() : document.selection.empty(); //设置移动参数 var iLeft = oEvent.clientX - this._x, iTop = oEvent.clientY - this._y; //设置范围限制 if(this.Limit){ //设置范围参数 var mxLeft = this.mxLeft, mxRight = this.mxRight, mxTop = this.mxTop, mxBottom = this.mxBottom; //如果设置了容器,再修正范围参数 if(!!this._mxContainer){ mxLeft = Math.max(mxLeft, 0); mxTop = Math.max(mxTop, 0); mxRight = Math.min(mxRight, this._mxContainer.clientWidth); mxBottom = Math.min(mxBottom, this._mxContainer.clientHeight); }; //修正移动参数 iLeft = Math.max(Math.min(iLeft, mxRight - this.Drag.offsetWidth), mxLeft); iTop = Math.max(Math.min(iTop, mxBottom - this.Drag.offsetHeight), mxTop); } //设置位置,并修正margin if(!this.LockX){ this.Drag.style.left = iLeft - this._marginLeft + "px"; } if(!this.LockY){ this.Drag.style.top = iTop - this._marginTop + "px"; } //附加程序 this.onMove(); }, //停止拖动 Stop: function() { //移除事件 removeEventHandler(document, "mousemove", this._fM); removeEventHandler(document, "mouseup", this._fS); if(isIE){ removeEventHandler(this._Handle, "losecapture", this._fS); this._Handle.releaseCapture(); }else{ removeEventHandler(window, "blur", this._fS); }; //附加程序 this.onStop(); } }; // --></script><script type="text/javascript"><!-- //缩放程序 var Resize = Class.create(); Resize.prototype = { //缩放对象 initialize: function(obj, options) { this._obj = $$(obj);//缩放对象 this._styleWidth = this._styleHeight = this._styleLeft = this._styleTop = 0;//样式参数 this._sideRight = this._sideDown = this._sideLeft = this._sideUp = 0;//坐标参数 this._fixLeft = this._fixTop = 0;//定位参数 this._scaleLeft = this._scaleTop = 0;//定位坐标 this._mxSet = function(){};//范围设置程序 this._mxRightWidth = this._mxDownHeight = this._mxUpHeight = this._mxLeftWidth = 0;//范围参数 this._mxScaleWidth = this._mxScaleHeight = 0;//比例范围参数 this._fun = function(){};//缩放执行程序 //获取边框宽度 var _style = CurrentStyle(this._obj); this._borderX = (parseInt(_style.borderLeftWidth) || 0) + (parseInt(_style.borderRightWidth) || 0); this._borderY = (parseInt(_style.borderTopWidth) || 0) + (parseInt(_style.borderBottomWidth) || 0); //事件对象(用于绑定移除事件) this._fR = BindAsEventListener(this, this.Resize); this._fS = Bind(this, this.Stop); this.SetOptions(options); //范围限制 this.Max = !!this.options.Max; this._mxContainer = $$(this.options.mxContainer) || null; this.mxLeft = Math.round(this.options.mxLeft); this.mxRight = Math.round(this.options.mxRight); this.mxTop = Math.round(this.options.mxTop); this.mxBottom = Math.round(this.options.mxBottom); //宽高限制 this.Min = !!this.options.Min; this.minWidth = Math.round(this.options.minWidth); this.minHeight = Math.round(this.options.minHeight); //按比例缩放 this.Scale = !!this.options.Scale; this.Ratio = Math.max(this.options.Ratio, 0); this.onResize = this.options.onResize; this._obj.style.position = "absolute"; !this._mxContainer || CurrentStyle(this._mxContainer).position == "relative" || (this._mxContainer.style.position = "relative"); }, //设置默认属性 SetOptions: function(options) { this.options = {//默认值 Max: false,//是否设置范围限制(为true时下面mx参数有用) mxContainer:"",//指定限制在容器内 mxLeft: 0,//左边限制 mxRight: 9999,//右边限制 mxTop: 0,//上边限制 mxBottom: 9999,//下边限制 Min: false,//是否最小宽高限制(为true时下面min参数有用) minWidth: 50,//最小宽度 minHeight: 50,//最小高度 Scale: false,//是否按比例缩放 Ratio: 0,//缩放比例(宽/高) onResize: function(){}//缩放时执行 }; Extend(this.options, options || {}); }, //设置触发对象 Set: function(resize, side) { var resize = $$(resize), fun; if(!resize) return; //根据方向设置 switch (side.toLowerCase()) { case "up" : fun = this.Up; break; case "down" : fun = this.Down; break; case "left" : fun = this.Left; break; case "right" : fun = this.Right; break; case "left-up" : fun = this.LeftUp; break; case "right-up" : fun = this.RightUp; break; case "left-down" : fun = this.LeftDown; break; case "right-down" : default : fun = this.RightDown; }; //设置触发对象 addEventHandler(resize, "mousedown", BindAsEventListener(this, this.Start, fun)); }, //准备缩放 Start: function(e, fun, touch) { //防止冒泡(跟拖放配合时设置) e.stopPropagation ? e.stopPropagation() : (e.cancelBubble = true); //设置执行程序 this._fun = fun; //样式参数值 this._styleWidth = this._obj.clientWidth; this._styleHeight = this._obj.clientHeight; this._styleLeft = this._obj.offsetLeft; this._styleTop = this._obj.offsetTop; //四条边定位坐标 this._sideLeft = e.clientX - this._styleWidth; this._sideRight = e.clientX + this._styleWidth; this._sideUp = e.clientY - this._styleHeight; this._sideDown = e.clientY + this._styleHeight; //top和left定位参数 this._fixLeft = this._styleLeft + this._styleWidth; this._fixTop = this._styleTop + this._styleHeight; //缩放比例 if(this.Scale){ //设置比例 this.Ratio = Math.max(this.Ratio, 0) || this._styleWidth / this._styleHeight; //left和top的定位坐标 this._scaleLeft = this._styleLeft + this._styleWidth / 2; this._scaleTop = this._styleTop + this._styleHeight / 2; }; //范围限制 if(this.Max){ //设置范围参数 var mxLeft = this.mxLeft, mxRight = this.mxRight, mxTop = this.mxTop, mxBottom = this.mxBottom; //如果设置了容器,再修正范围参数 if(!!this._mxContainer){ mxLeft = Math.max(mxLeft, 0); mxTop = Math.max(mxTop, 0); mxRight = Math.min(mxRight, this._mxContainer.clientWidth); mxBottom = Math.min(mxBottom, this._mxContainer.clientHeight); }; //根据最小值再修正 mxRight = Math.max(mxRight, mxLeft + (this.Min ? this.minWidth : 0) + this._borderX); mxBottom = Math.max(mxBottom, mxTop + (this.Min ? this.minHeight : 0) + this._borderY); //由于转向时要重新设置所以写成function形式 this._mxSet = function(){ this._mxRightWidth = mxRight - this._styleLeft - this._borderX; this._mxDownHeight = mxBottom - this._styleTop - this._borderY; this._mxUpHeight = Math.max(this._fixTop - mxTop, this.Min ? this.minHeight : 0); this._mxLeftWidth = Math.max(this._fixLeft - mxLeft, this.Min ? this.minWidth : 0); }; this._mxSet(); //有缩放比例下的范围限制 if(this.Scale){ this._mxScaleWidth = Math.min(this._scaleLeft - mxLeft, mxRight - this._scaleLeft - this._borderX) * 2; this._mxScaleHeight = Math.min(this._scaleTop - mxTop, mxBottom - this._scaleTop - this._borderY) * 2; }; }; //mousemove时缩放 mouseup时停止 addEventHandler(document, "mousemove", this._fR); addEventHandler(document, "mouseup", this._fS); if(isIE){ addEventHandler(this._obj, "losecapture", this._fS); this._obj.setCapture(); }else{ addEventHandler(window, "blur", this._fS); e.preventDefault(); }; }, //缩放 Resize: function(e) { //清除选择 window.getSelection ? window.getSelection().removeAllRanges() : document.selection.empty(); //执行缩放程序 this._fun(e); //设置样式,变量必须大于等于0否则ie出错 with(this._obj.style){ width = this._styleWidth + "px"; height = this._styleHeight + "px"; top = this._styleTop + "px"; left = this._styleLeft + "px"; } //附加程序 this.onResize(); }, //缩放程序 //上 Up: function(e) { this.RepairY(this._sideDown - e.clientY, this._mxUpHeight); this.RepairTop(); this.TurnDown(this.Down); }, //下 Down: function(e) { this.RepairY(e.clientY - this._sideUp, this._mxDownHeight); this.TurnUp(this.Up); }, //右 Right: function(e) { this.RepairX(e.clientX - this._sideLeft, this._mxRightWidth); this.TurnLeft(this.Left); }, //左 Left: function(e) { this.RepairX(this._sideRight - e.clientX, this._mxLeftWidth); this.RepairLeft(); this.TurnRight(this.Right); }, //右下 RightDown: function(e) { this.RepairAngle( e.clientX - this._sideLeft, this._mxRightWidth, e.clientY - this._sideUp, this._mxDownHeight ); this.TurnLeft(this.LeftDown) || this.TurnUp(this.RightUp); }, //右上 RightUp: function(e) { this.RepairAngle( e.clientX - this._sideLeft, this._mxRightWidth, this._sideDown - e.clientY, this._mxUpHeight ); this.RepairTop(); this.TurnLeft(this.LeftUp) || this.TurnDown(this.RightDown); }, //左下 LeftDown: function(e) { this.RepairAngle( this._sideRight - e.clientX, this._mxLeftWidth, e.clientY - this._sideUp, this._mxDownHeight ); this.RepairLeft(); this.TurnRight(this.RightDown) || this.TurnUp(this.LeftUp); }, //左上 LeftUp: function(e) { this.RepairAngle( this._sideRight - e.clientX, this._mxLeftWidth, this._sideDown - e.clientY, this._mxUpHeight ); this.RepairTop(); this.RepairLeft(); this.TurnRight(this.RightUp) || this.TurnDown(this.LeftDown); }, //修正程序 //水平方向 RepairX: function(iWidth, mxWidth) { iWidth = this.RepairWidth(iWidth, mxWidth); if(this.Scale){ var iHeight = Math.round(iWidth / this.Ratio); if(this.Max && iHeight > this._mxScaleHeight){ iWidth = Math.round((iHeight = this._mxScaleHeight) * this.Ratio); }else if(this.Min && iHeight < this.minHeight){ var tWidth = Math.round(this.minHeight * this.Ratio); if(tWidth < mxWidth){ iHeight = this.minHeight; iWidth = tWidth; } } this._styleHeight = iHeight; this._styleTop = this._scaleTop - iHeight / 2; } this._styleWidth = iWidth; }, //垂直方向 RepairY: function(iHeight, mxHeight) { iHeight = this.RepairHeight(iHeight, mxHeight); if(this.Scale){ var iWidth = Math.round(iHeight * this.Ratio); if(this.Max && iWidth > this._mxScaleWidth){ iHeight = Math.round((iWidth = this._mxScaleWidth) / this.Ratio); }else if(this.Min && iWidth < this.minWidth){ var tHeight = Math.round(this.minWidth / this.Ratio); if(tHeight < mxHeight){ iWidth = this.minWidth; iHeight = tHeight; } } this._styleWidth = iWidth; this._styleLeft = this._scaleLeft - iWidth / 2; } this._styleHeight = iHeight; }, //对角方向 RepairAngle: function(iWidth, mxWidth, iHeight, mxHeight) { iWidth = this.RepairWidth(iWidth, mxWidth); if(this.Scale){ iHeight = Math.round(iWidth / this.Ratio); if(this.Max && iHeight > mxHeight){ iWidth = Math.round((iHeight = mxHeight) * this.Ratio); }else if(this.Min && iHeight < this.minHeight){ var tWidth = Math.round(this.minHeight * this.Ratio); if(tWidth < mxWidth){ iHeight = this.minHeight; iWidth = tWidth; } } }else{ iHeight = this.RepairHeight(iHeight, mxHeight); } this._styleWidth = iWidth; this._styleHeight = iHeight; }, //top RepairTop: function() { this._styleTop = this._fixTop - this._styleHeight; }, //left RepairLeft: function() { this._styleLeft = this._fixLeft - this._styleWidth; }, //height RepairHeight: function(iHeight, mxHeight) { iHeight = Math.min(this.Max ? mxHeight : iHeight, iHeight); iHeight = Math.max(this.Min ? this.minHeight : iHeight, iHeight, 0); return iHeight; }, //width RepairWidth: function(iWidth, mxWidth) { iWidth = Math.min(this.Max ? mxWidth : iWidth, iWidth); iWidth = Math.max(this.Min ? this.minWidth : iWidth, iWidth, 0); return iWidth; }, //转向程序 //转右 TurnRight: function(fun) { if(!(this.Min || this._styleWidth)){ this._fun = fun; this._sideLeft = this._sideRight; this.Max && this._mxSet(); return true; } }, //转左 TurnLeft: function(fun) { if(!(this.Min || this._styleWidth)){ this._fun = fun; this._sideRight = this._sideLeft; this._fixLeft = this._styleLeft; this.Max && this._mxSet(); return true; } }, //转上 TurnUp: function(fun) { if(!(this.Min || this._styleHeight)){ this._fun = fun; this._sideDown = this._sideUp; this._fixTop = this._styleTop; this.Max && this._mxSet(); return true; } }, //转下 TurnDown: function(fun) { if(!(this.Min || this._styleHeight)){ this._fun = fun; this._sideUp = this._sideDown; this.Max && this._mxSet(); return true; } }, //停止缩放 Stop: function() { removeEventHandler(document, "mousemove", this._fR); removeEventHandler(document, "mouseup", this._fS); if(isIE){ removeEventHandler(this._obj, "losecapture", this._fS); this._obj.releaseCapture(); }else{ removeEventHandler(window, "blur", this._fS); } } }; // --></script><style type="text/css"><!-- #rRightDown,#rLeftDown,#rLeftUp,#rRightUp,#rRight,#rLeft,#rUp,#rDown{ position:absolute; background:#FFF; border: 1px solid #333; width: 6px; height: 6px; z-index:500; font-size:0; opacity: 0.5; filter:alpha(opacity=50); } #rLeftDown,#rRightUp{cursor:ne-resize;} #rRightDown,#rLeftUp{cursor:nw-resize;} #rRight,#rLeft{cursor:e-resize;} #rUp,#rDown{cursor:n-resize;} #rLeftDown{left:-4px;bottom:-4px;} #rRightUp{right:-4px;top:-4px;} #rRightDown{right:-4px;bottom:-4px;background-color:#00F;} #rLeftUp{left:-4px;top:-4px;} #rRight{right:-4px;top:50%;margin-top:-4px;} #rLeft{left:-4px;top:50%;margin-top:-4px;} #rUp{top:-4px;left:50%;margin-left:-4px;} #rDown{bottom:-4px;left:50%;margin-left:-4px;} #bgDiv{width:300px; height:400px; border:1px solid #666666; position:relative;} #dragDiv{border:1px dashed #fff; width:100px; height:60px; top:50px; left:50px; cursor:move; } --></style>




图片地址:<script type="text/javascript"><!-- var ic = new ImgCropper("bgDiv", "dragDiv", "http://images.cnblogs.com/cnblogs_com/cloudgamer/143727/r_xx2.jpg", { Width: 300, Height: 400, Color: "#000", Resize: true, Right: "rRight", Left: "rLeft", Up: "rUp", Down: "rDown", RightDown: "rRightDown", LeftDown: "rLeftDown", RightUp: "rRightUp", LeftUp: "rLeftUp", Preview: "viewDiv", viewWidth: 300, viewHeight: 300 }) $$("idSize").onclick = function(){ if(ic.Height == 200){ ic.Height = 400; this.value = "缩小显示"; }else{ ic.Height = 200; this.value = "还原显示"; } ic.Init(); } $$("idOpacity").onclick = function(){ if(ic.Opacity == 0){ ic.Opacity = 50; this.value = "全透明"; }else{ ic.Opacity = 0; this.value = "半透明"; } ic.Init(); } $$("idColor").onclick = function(){ if(ic.Color == "#000"){ ic.Color = "#fff"; this.value = "黑色背景"; }else{ ic.Color = "#000"; this.value = "白色背景"; } ic.Init(); } $$("idScale").onclick = function(){ if(ic.Scale){ ic.Scale = false; this.value = "使用比例"; }else{ ic.Scale = true; this.value = "取消比例"; } ic.Init(); } $$("idMin").onclick = function(){ if(ic.Min){ ic.Min = false; this.value = "设置最小尺寸"; }else{ ic.Min = true; this.value = "取消最小尺寸"; } ic.Init(); } $$("idView").onclick = function(){ if(ic.viewWidth == 200){ ic.viewWidth = 300; this.value = "缩小预览"; }else{ ic.viewWidth = 200; this.value = "扩大预览"; } ic.Init(); } $$("idImg").onclick = function(){ if(ic.Url == "http://images.cnblogs.com/cnblogs_com/cloudgamer/143727/r_xx2.jpg"){ ic.Url = "http://images.cnblogs.com/cnblogs_com/cloudgamer/143727/r_min.jpg"; }else{ ic.Url = "http://images.cnblogs.com/cnblogs_com/cloudgamer/143727/r_xx2.jpg"; } ic.Init(); } $$("idPic").onclick = function(){ if($$("idPicUrl").value){ ic.Url = $$("idPicUrl").value; } ic.Init(); } // --></script>


程序说明

这个效果主要分三个部分:层的拖放、层的缩放、图片切割(包括预览)。
其中层的拖放层的缩放我已经在其他两篇文章中有详细说明,这里就说说图片切割这部分吧。

【图片切割】

关于图片切割的设计,有三个方法:
1.定位四个半透明层,遮住要盖住的部分,没试过,感觉比较麻烦;
2.把图片设为背景图,通过设置背景图的位置来实现,但这样的缺点是只能按图片的正常比例实现,不够灵活;
3.把图片放到切割对象里面,通过设置图片的top和left实现,这个方法是可行,但下面有更简单的方法实现;
4.通过设置图片的clip来实现。

这里介绍方法4的实现方法,这个方法是从当年“珍藏”的代码中看到的,先说说clip:
clip的作用是“检索或设置对象的可视区域。可视区域外的部分是透明的。”
依据上-右-下-左的顺序提供自对象左上角为(0,0)坐标计算的四个偏移数值来剪切。
例如:

div { position:absolute; width:60px; height:60px; clip:rect(0 20 50 10); }


注意position:absolute的设置是必须的(详细看手册)。

下面说说具体实现原理:
首先需要一个容器(_Container),容器里面会插入三个层:
底图层(_layBase):那个半透明的图片;
切割层(_layCropper):正常显示的那个部分;
控制层(_layHandle):就是控制显示的那个部分。

其中为了底图层和切割层是程序自动创建的图片,控制层是自己定义的层(程序中是一个div)。
底图层和切割层必须完全重合,程序中把这两个层都绝对定位到了左上角:

this._layBase.style.top = this._layBase.style.left = this._layCropper.style.top = this._layCropper.style.left = 0;


层叠顺序也要设置一下保证各层顺序。

下面说说各部分的作用:
容器:除了容器本身的作用,通过设置其背景色来设置透明的渐变色,由于图片本身没有背景色所以要通过容器来设置;
底图层:在容器最底部,作用是显示非选择区域的图片,透明效果就是在这层设置;
切割层:最关键的一个层,在底图层和控制层之间,在这个层通过clip设置其可视区域来实现切割图片的效果;
控制层:位于顶部,拖放(_drag)和缩放(_resize)效果就是在这个层实现,根据其拖放和缩放的结果控制切割层的切割效果。

这里要注意的是控制层的_drag拖放效果的Transparent要设为true(详细看拖放效果的透明背景bug部分)。
要使用缩放需要把Resize设为true,并设置各个拖拉对象,程序通过_resize设置缩放的比例和最少范围(详细看拖拉缩放效果)。

下面说说控制层如何控制切割效果:
控制层的拖放和缩放过程中加入了SetPos设置切割样式程序,在SetPos程序中根据控制层的样式设置切割层的可视区域范围:

var p = this.GetPos();
this._layCropper.style.clip = "rect(" + p.Top + "px " + (p.Left + p.Width) + "px " + (p.Top + p.Height) + "px " + p.Left + "px)";


其中GetPos程序,它可以把当前控制层的样式参数作为一个对象返回:

with(this._layHandle){
    
return { Top: offsetTop, Left: offsetLeft, Width: offsetWidth, Height: offsetHeight }
}


如果理解了的话就会觉得其实原理挺简单的,不过要想出来还是要一定创意才行,为想出这个方法的人致敬!

【切割预览】

预览效果需要设置Preview属性为预览容器对象,程序会自动给容器插入一个预览对象(图片)。
预览效果的关键在于如何根据控制层的数据来给预览对象定位,这个主要在SetPreview预览效果程序中处理。
首先根据控制层的高宽比置预览对象显示的宽和高(不是图片本身的宽高哦),这里可以用GetSize程序获取:

var p = this.GetPos(), s = this.GetSize(p.Width, p.Height, this.viewWidth, this.viewHeight), scale = s.Height / p.Height;


其中GetSize获取尺寸程序可以根据图片实际大小按比例缩放到要设置的大小:

Code
<!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />-->var iWidth = nowWidth, iHeight = nowHeight, scale = iWidth / iHeight;
//按比例设置
if(fixHeight){ iWidth = (iHeight = fixHeight) * scale; }
if(fixWidth && (!fixHeight || iWidth > fixWidth)){ iHeight = (iWidth = fixWidth) / scale; }
//返回尺寸对象
return { Width: iWidth, Height: iHeight }


可以看出如果后两个参数(viewWidth和this.viewHeight)都不设置就会按原来大小显示了,

然后再按预览图跟控制层的比例设置预览图的样式参数:

var pHeight = this._layBase.height * scale, pWidth = this._layBase.width * scale, pTop = o.Top * scale, pLeft = o.Left * scale;


最后根据参数对预览对象进行样式设置和切割:

Code
<!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />-->with(this._view.style){
    
//设置样式
    width = pWidth + "px"; height = pHeight + "px"; top = - pTop + "px "; left = - pLeft + "px";
    
//切割预览图
    clip = "rect(" + pTop + "px " + (pLeft + s.Width) + "px " + (pTop + s.Height) + "px " + pLeft + "px)";
}


这里有点烦乱,但应该不难理解就不详细说明了。

【图片大小】

容器的大小一般是固定的,但图片的大小就不是固定的,这里又可以使用SetSize程序用来设置图片大小:

Code
<!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />-->var s = this.GetSize(this._tempImg.width, this._tempImg.height, this.Width, this.Height);
//设置底图和切割图
this._layBase.style.width = this._layCropper.style.width = s.Width + "px";
this._layBase.style.height = this._layCropper.style.height = s.Height + "px";


有了图片大小就可以用来设置拖放和缩放的范围限制了:

Code
<!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />-->this._drag.mxRight = s.Width; this._drag.mxBottom = s.Height;
if(this.Resize){ this._resize.mxRight = s.Width; this._resize.mxBottom = s.Height; }


ps:程序中的Init程序是用来把个性设置呈现出来,所以一般设置过属性之后(例如图片地址、透明度等)就执行一次Init程序就可以显示效果了。

【ie6渲染bug】

拖放效果中说到插入一个div解决ie的透明背景bug,这里就需要修复这个bug。
缩放效果配合使用时,不得不说ie6的一个渲染bug,用下面的代码测试(ie6):

Code
<!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<body>
<div id="aa" style="width:300px;height:100px;border:1px solid;"><div style="background:#00f;height:100%;"></div></div>
<script>setTimeout("aa.style.height=200",0)</script>
</body>
</html>


可以对比ie7的效果,可以看出里面的div虽然高度设置了100%,但在外面的div修改高度之后,却不知什么原因没有填充了(外面的div渲染后,没有触发里面的div再渲染)。

解决这个bug的关键是使里面的div能再渲染,这里有几个方法可以解决:
1,设置控制层的overflow为hidden,好处是只需要设置一次,但这个样式会影响其他效果,当然在不影响效果的情况下这个是最好的方法;
2,在缩放的时候,通过修改控制层的某些样式,使里面的div再渲染,这样的样式包括zoom,display(应该还有其他吧);
3,在缩放的时候,通过修改插入div的某些样式,使其再渲染,这样的样式包括display(zoom也不行);
程序中是通过修改_layHandle的zoom解决的:

if(isIE6){ with(this._layHandle.style){ zoom = .9; zoom = 1; }; };


ps:这个bug的原因貌似跟ie的layout有关,但我查了一下还是没弄清楚,谁有详细的介绍或解析务必跟我分享一下啊。


使用说明

实例化时有三个必要参数:容器对象、控制层、图片地址:

var ic = new ImgCropper("bgDiv""dragDiv""1.jpg");


有以下这些可选参数和属性:
属性:默认值//说明
Opacity: 50,//透明度(0到100)
Color:  "",//背景色
Width:  0,//图片高度
Height:  0,//图片高度
//缩放触发对象
Resize:  false,//是否设置缩放
Right:  "",//右边缩放对象
Left:  "",//左边缩放对象
Up:   "",//上边缩放对象
Down:  "",//下边缩放对象
RightDown: "",//右下缩放对象
LeftDown: "",//左下缩放对象
RightUp: "",//右上缩放对象
LeftUp:  "",//左上缩放对象
Min:  false,//是否最小宽高限制(为true时下面min参数有用)
minWidth: 50,//最小宽度
minHeight: 50,//最小高度
Scale:  false,//是否按比例缩放
Ratio:  0,//缩放比例(宽/高)
//预览对象设置
Preview: "",//预览对象
viewWidth: 0,//预览宽度
viewHeight: 0//预览高度

 

程序代码

Code
<!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />-->//图片切割
var ImgCropper = Class.create();
ImgCropper.prototype 
= {
  
//容器对象,控制层,图片地址
  initialize: function(container, handle, url, options) {
    
this._Container = $(container);//容器对象
    this._layHandle = $(handle);//控制层
    this.Url = url;//图片地址
    
    
this._layBase = this._Container.appendChild(document.createElement("img"));//底层
    this._layCropper = this._Container.appendChild(document.createElement("img"));//切割层
    this._layCropper.onload = Bind(thisthis.SetPos);
    
//用来设置大小
    this._tempImg = document.createElement("img");
    
this._tempImg.onload = Bind(thisthis.SetSize);
    
    
this.SetOptions(options);
    
    
this.Opacity = Math.round(this.options.Opacity);
    
this.Color = this.options.Color;
    
this.Scale = !!this.options.Scale;
    
this.Ratio =<spa
分享到:
评论

相关推荐

    JavaScript 图片切割效果 v2.0

    以上就是JavaScript图片切割效果v2.0的相关知识点,它结合了前端与后端技术,提供了一种便捷的用户交互方式来处理网页中的图片。在实际开发中,掌握这些技术可以帮助你创建出更加灵活和用户友好的图片编辑功能。

    JavaScript 图片切割效果(带拖放、缩放效果)

    JavaScript图片切割效果是一种常见的前端交互技术,用于在网页上实现用户自定义裁剪图片的功能。这一功能结合了拖放和缩放操作,为用户提供了一种直观且灵活的方式来选择他们感兴趣的图片区域。以下是对这一技术的...

    JavaScript 图片切割效果(带拖放、缩放效果)

    作者:cloudgamer 自己的网站需要这个功能,看到了cloudgamer的程序,非常值得收藏和使用,所以自己请教了cloudgamer,并进行了小小的修改,感谢cloudgamer的支持,本程序可以获取到选取框的尺寸! 本程序版权归原作者...

    JavaScript图片切割代码

    JavaScript图片切割技术是一种在网页上实现动态图像裁剪的功能,常用于用户自定义头像、产品图片编辑等场景。这项技术结合了HTML、CSS和JavaScript,使得用户可以在浏览器端通过交互方式选择并调整图片的裁剪区域。...

    JavaScript 图片切割效果(放大镜)第1/4页

    实现JavaScript图片切割的关键步骤包括: 1. 创建一个容器元素(_Container),它将包含底图层 (_layBase)、切割层 (_layCropper) 和控制层 (_layHandle)。底图层显示半透明的全图,切割层显示用户可以看到的正常...

    用JavaScript实现图片切割效果实例

    在本文中,我们将深入探讨如何使用JavaScript来实现一个图片切割效果的实例。这个实例允许用户进行全透明设置、更换图片以及调整图片大小,为网页应用提供了丰富的交互性。JavaScript作为客户端脚本语言,在Web开发...

    JavaScript切割图片

    在提供的压缩包中,"JavaScript 图片切割效果 - cloudgamer - 博客园.mht"可能是一个包含有关JavaScript图片切割实例的网页文件,而"ImgCropper_sys.rar"很可能是`ImgCropper`库的源码或示例。通过研究这些资源,你...

    整合图片分割、切割、.net效果

    **图片切割效果**不仅限于基本的几何切割,还可以实现复杂的形状切割、自定义切割路径等。例如,使用SVG(可缩放矢量图形)路径数据,可以精确地指定切割轮廓,创造出各种艺术效果。同时,结合CSS3的clip-path属性,...

    非常炫的javascript图片效果

    9. **图片拼图效果**:将图片切割成小块,然后随机或有序地重组,形成一个互动的游戏或展示。 10. **动态图片滤镜**:用户可以实时调整图片的滤镜效果,如黑白、模糊、对比度等,增加互动性。 在压缩包文件"04_...

    图片切割,ASP.NET,jQuery,多种效果,多种方式

    在给定的标题“图片切割,ASP.NET,jQuery,多种效果,多种方式”以及描述中,我们可以看到几个关键的技术点:图片切割、ASP.NET、jQuery,以及提及的三个工具或库——ImgCropper、jquery.imgareaselect和BitmapCutter。...

    图片切割效果(带拖放、缩放效果)

    总之,"图片切割效果(带拖放、缩放效果)"是一个综合运用了JavaScript、HTML5 Canvas、CSS3技术的项目,它在网页设计和开发中具有广泛的应用价值,能够提升用户体验,使图片浏览更加灵活和个性化。通过学习和实践...

    JS图片切割

    JavaScript图片切割技术是一种在网页端实现的图像处理方法,它允许用户通过JavaScript代码对图片进行裁剪、调整大小或创建自定义的视图区域。这种技术广泛应用于网页设计、在线编辑器、图像预览和社交媒体分享等多个...

    图片切割器.zip

    【标题】:“图片切割器.zip”是一个包含有关图像切割技术的资源包,它可能是通过JavaScript和jQuery实现的一个实例。这个压缩文件很可能包含了源代码、示例图像以及相关的教程材料,帮助用户了解如何利用这两个流行...

    javascript实现的图片切割多块效果实例

    本文将详细阐述如何使用...通过上述知识点的学习和实例分析,读者将能够理解和掌握利用JavaScript和CSS实现图片切割多块效果的方法。这些技巧在网页设计和用户体验优化方面非常有用,可以为用户提供动态的交互体验。

    jQuery切割过渡效果图像滑块.zip

    【jQuery切割过渡效果图像滑块】是一个基于JavaScript库jQuery实现的动态图像展示工具,它具有独特的切割过渡效果,为网站的图像展示增添了丰富的视觉体验。这个图像滑块不仅包含左右箭头供用户导航,还提供了缩略图...

    js图片切割,很有用!

    本文将深入探讨JavaScript(简称js)实现的图片切割技术,结合提供的文件名,我们能够推断这是一个简单的图片裁剪应用。 标题"js图片切割,很有用!"表明我们将讨论的是使用JavaScript进行图像裁剪的功能。在网页...

Global site tag (gtag.js) - Google Analytics