html5图片裁剪控件原型【含缩放,旋转,拖动功能】---2、核心代码

来源:互联网 发布:ei数据库 编辑:程序博客网 时间:2024/05/19 02:05

推荐

这一篇文章是早年为了解决图片裁剪的探索性文章,现在已经开放出了falsh版及html5版本的图片裁剪插件,各位有时间可以看看:
浮士德html5图片裁剪器2016开源版
浮士德头像裁剪flash版2016福利版
上面两个解决方案已经经过多个项目的成功应用,适用于低级浏览器及现代浏览器,ipad,android,iphone4s,iphone5,iphone5s,iphone6等设备等。

前言

将相应html及js脚本放出来,注意,这是原型,并非立刻可以使用的东西。

html界面

<!DOCTYPE HTML><html><head>    <title>个人相片</title>    <meta charset="utf-8" />    <meta content="width=device-width, initial-scale=1,minimum-scale=1.0,maximum-scale=1.0,user-scalable=no" name="viewport"/>    <meta content="yes" name="apple-mobile-web-app-capable">    <meta content="black" name="apple-mobile-web-app-status-bar-style">    <meta content="telephone=yes" name="format-detection">    <meta content="email=no" name="format-detection">    <script type="text/javascript" src="/static/lib/jquery-1.11.0.min.js"></script>    <script type="text/javascript" src="/static/lib/util.min.js"></script>    <script type="text/javascript" src="/static/lib/exif.min.js"></script>    <script type="text/javascript" src="/static/vendor/ImgTools/ImageOrientationFix.js"></script>    <script type="text/javascript" src="/static/vendor/ImgTools/ImageResizer.js"></script>    <script type="text/javascript" src="/static/vendor/layer1.8/layer/layer.min.js"></script>    <link href="/static/vendor/jQuery.showLoading/css/showLoading.css" rel="stylesheet" media="screen" />    <script type="text/javascript" src="/static/vendor/jQuery.showLoading/js/jquery.showLoading.js"></script>    <script type="text/javascript" src="ImageEditor.js"></script></head><body><div>    <h3>请选择图片:</h3>    <div>        <input type="file" style="" id="uploadImage"  accept="image/*">    </div></div><h2>裁剪器区域</h2><div id="div_cropper">        <div ui="image-editor-panel">            <canvas ui="background-layout" style="position: absolute; "></canvas>            <canvas ui="cutter-layout" style="position: absolute; "></canvas>            <canvas ui="operation-layout" style="position: absolute; cursor: pointer; "></canvas>        </div></div><div class="image-editor-tool-bar"><button type="button" id="btn_zoom_in">放大图片</button><button type="button" id="btn_zoom_out">缩小图片</button><button type="button" id="btn_turn_left">向左转</button><button type="button" id="btn_turn_right">向右转</button></div><div><input type="button" id="btn_save" value="保存图片"></div><h2>预览结果:</h2><img src="" id="preview_img"/>    <div id="tips" style="color:green;"></div><script type="text/javascript" src="example2.js"></script><div id="debug" style="color: green;"></div><img src="daojian_1.png" id="img_test" style="display: none;"><div  style="width:1200px;height: 800px; border: 1px solid red;display: none;">    <canvas id="test_canvas" width="1200" height="800"></canvas></div><script type="text/javascript">    var _img=document.getElementById("img_test");    var _canvas=document.getElementById("test_canvas");    var _context=_canvas.getContext("2d");</script></body></html>

核心组件代码

/** * 图片裁剪组件,必须跟jquery exif ImageOrientationFix.js 等一起用。 */function ImageEditor(opts){    var settings={        cutWidth:150 //裁剪框的宽度。        ,cutHeight:200 //裁剪框的高度        ,containerWidth:800 //容器宽度        ,containerHeight:600 //容器高度        ,imageShowWidth:400 //图片默认显示的宽度【会按照要求的宽度及高度等比缩放】        ,imageShowHeight:500 //图片默认显示的高度【会按照要求的宽度及高度等比缩放】        ,containerElement:"" //容器的默认元素,jquery元素或者原生dom元素。        ,showCutterInFirst:true //是否第一时间显示裁剪框---注意,true意味着即使用户没有选择图片,背景层没有显示图片裁剪框也显示。        ,saveMode:"ratio" //裁剪图片的模式有两种,一种是 ratio即,在原图片上面按照比例裁剪图片,尺寸不一定固定,一种是 size,严格按照裁剪框的尺寸来保存图片。    };    $.extend(settings,opts);    function _debug(str){        return;        var _div=$("<div></div>");        _div.text(str);        $("#debug").append(_div);    };    function _clearDebug(){        return;        $("#debug").empty();    }    var __me=this;    //--定义必须用到的dom元素的句柄。    var containerElement=$(settings.containerElement);//整个容器对象,    var panel=containerElement.find('[ui="image-editor-panel"]');//这是包装几个画布的面板。    var canvas_bg=containerElement.find('[ui="background-layout"]')[0];//原生画布对象,这是背景画布,用于绘制图片及缩放,转向等操作。    var canvas_cutter=containerElement.find("[ui='cutter-layout']")[0];//原生画布对象,这是裁剪框对象。用于绘制遮罩层及裁剪框。    var canvas_operation=containerElement.find("[ui='operation-layout']")[0];//原生画布对象,这是操作层对象,用于接受用户的鼠标及手势,然后触发各种事件。    var context_cutter=canvas_cutter.getContext("2d");    var context_bg=canvas_bg.getContext("2d");    var data_origin_image="";//原始图片数据,原始是指经过了ios bug修复剂orientation方向修复以后的base64格式的数据。注意,必要时,假如图片太大,可以先压缩到某个尺寸。    var image_background=new Image();//新建一个背景图的元素用于处理图片旋转等操作。    //--下面预先将背景图片的三个方向都先计算出来。    //window.image_backgroud=image_background;    //--内部运行时数据    var data_cutter={        location:{            x:0            ,y:0        }        ,size:{            w:0            ,h:0        }        ,ratio:1    };//裁剪框数据    var data_bg={        angle:0        ,img_bg_0:""//0度图片。        ,img_bg_90:""//90度图片        ,img_bg_180:""//180度旋转图片        ,img_bg_270:""//270度旋转图片        ,location:{            x:0            ,y:0        }        ,size:{            w:0            ,h:0        }        ,originSize:{            w:0            ,h:0        }        ,zoom:1    };//背景层数据-这个作为原始备份,告诉系统应该如何转换数据。    var data_bg_trans={        angle:0        ,location:{            x:0            ,y:0        }        ,size:{            w:0            ,h:0        }        ,originSize:{            w:0            ,h:0        }        ,zoom:1    };//在非正常情况下的位置的数据等,例如,转换成为90,180,270,0等的数据,    var data_container={        size:{            w:0            ,h:0        }    };//容器数据    var data_op={        panelInfo:{            absoluteTop:0,            absoluteLeft:0,            offsetWidth:0,            offsetHeight:0        }        ,isInDrag:false        ,beginPoint:{            x:0            ,y:0        }        ,point1:{            x:0            ,y:0        }        ,point2:{            x:0            ,y:0        }        //判断是否在裁剪框里面。        ,isInCut:false    };//操控层数据。    var appData={        panelSize:{            w:0            ,h:0        }        ,hasImage:false //是否已经选择了图片,容器里面有没有图片。    };//app内部数据    var innerTools={        browser:{        versions:function(){            var u = navigator.userAgent, app = navigator.appVersion;            return {         //移动终端浏览器版本信息                trident: u.indexOf('Trident') > -1, //IE内核                presto: u.indexOf('Presto') > -1, //opera内核                webKit: u.indexOf('AppleWebKit') > -1, //苹果、谷歌内核                gecko: u.indexOf('Gecko') > -1 && u.indexOf('KHTML') == -1, //火狐内核                mobile: !!u.match(/AppleWebKit.*Mobile.*/), //是否为移动终端                ios: !!u.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/), //ios终端                android: u.indexOf('Android') > -1 || u.indexOf('Linux') > -1, //android终端或uc浏览器                iPhone: u.indexOf('iPhone') > -1 , //是否为iPhone或者QQHD浏览器                iPad: u.indexOf('iPad') > -1, //是否iPad                webApp: u.indexOf('Safari') == -1 //是否web应该程序,没有头部与底部            };        }(),        language:(navigator.browserLanguage || navigator.language).toLowerCase()        }        ,GetAbsoluteLocationEx:function(element){        if(arguments.length!=1||element==null)        {            return null;        }        var elmt=element;        var offsetTop=elmt.offsetTop;        var offsetLeft=elmt.offsetLeft;        var offsetWidth=elmt.offsetWidth;        var offsetHeight=elmt.offsetHeight;        while(elmt=elmt.offsetParent)        {            // add this judge            if(elmt.style.position=='absolute'||elmt.style.position=='relative'                ||(elmt.style.overflow!='visible'&&elmt.style.overflow!=''))            {                break;            }            offsetTop+=elmt.offsetTop;            offsetLeft+=elmt.offsetLeft;        }        var _info={absoluteTop:offsetTop,absoluteLeft:offsetLeft,            offsetWidth:offsetWidth,offsetHeight:offsetHeight};            return _info;    }    };    var app={        init:function(){            var _child=this;            appData.panelSize.w=settings.containerWidth;            appData.panelSize.h=settings.containerHeight;            _child.render_ui();            _child.init_cutter();            _child.initOperationLayout();        }        //--设定容器及其他相关dom的样式。      ,render_ui:function(){      containerElement.css({"width":settings.containerWidth+"px","height":settings.containerHeight+"px"});      canvas_bg.width=settings.containerWidth;      canvas_bg.height=settings.containerHeight;      canvas_cutter.width=settings.containerWidth;      canvas_cutter.height=settings.containerHeight;      canvas_operation.width=settings.containerWidth;      canvas_operation.height=settings.containerHeight;      }        //--计算相关数据--初始化裁剪框。        ,init_cutter:function(){            var _child=this;            data_cutter.size.w=settings.cutWidth;            data_cutter.size.h=settings.cutHeight;            data_cutter.ratio=settings.cutWidth/settings.cutHeight;            //--计算中间点。            var middle_x=appData.panelSize.w/2;            var middle_y=appData.panelSize.h/2;            var _x=middle_x-data_cutter.size.w/2;            var _y=middle_y-data_cutter.size.h/2;            data_cutter.location.x=_x;            data_cutter.location.y=_y;            if(settings.showCutterInFirst){            _child.updateCutter();            }        }        //--根据cutter的数据更新裁剪框层。        ,updateCutter:function(){            var _child=this;            console.log("目前更新裁剪框,数据"+data_cutter.location.x+":x "+data_cutter.location.y);            _child.__clear_cutter_canvas();            _child.__draw_mask();            _child.__draw_cutter();        }        //--清空cutter画布的内容。        ,__clear_cutter_canvas:function(){            context_cutter.clearRect(0,0,canvas_cutter.width,canvas_cutter.height);        }        //--渲染cutter        ,__draw_cutter:function(){           //            context_cutter.strokeStyle = '#ffffff';            context_cutter.lineWidth = 2;            context_cutter.strokeRect(data_cutter.location.x,data_cutter.location.y,data_cutter.size.w,data_cutter.size.h);            context_cutter.clearRect(data_cutter.location.x,data_cutter.location.y,data_cutter.size.w,data_cutter.size.h);            //context_cutter.clearRect(0,0,canvas_cutter.width,canvas_cutter.height);        }       //--渲染遮罩层        ,__draw_mask:function(){            context_cutter.fillStyle = 'rgba(0, 0, 0, 0.3)';            context_cutter.fillRect(0, 0, canvas_cutter.width,canvas_cutter.height);        }        //--对外接口,拖动裁剪框。        ,MoveCutter:function(pos_x,pos_y){            var _child=this;            data_cutter.location.x=pos_x;            data_cutter.location.y=pos_y;            _child.updateCutter();        }        //--移动裁剪框。        ,MoveCutterByDelta:function(delta_x,delta_y){            var _child=this;            var _new_x= data_cutter.location.x+delta_x;            var _new_y=data_cutter.location.y+delta_y;            //--判断边界。            if(_new_x<0){                _new_x=0;            }            if(_new_y<0){                _new_y=0;            }            if(_new_x>(appData.panelSize.w-data_cutter.size.w)){                _new_x=appData.panelSize.w-data_cutter.size.w;            }            if(_new_y>(appData.panelSize.h-data_cutter.size.h)){                _new_y=appData.panelSize.h-data_cutter.size.h;            }            console.log("新的裁剪框位置是:"+_new_x+" X "+_new_y);            _child.MoveCutter(_new_x,_new_y);        }        //--初始化背景层。背景层需要获得图片的base64字符串先。        ,init_background:function(base_64_image){          var _child=this;            _child.init_bg_data(base_64_image,function(finalBase64Image){                _child.updateBackground();            });        }        //--背景图片等图片处理。数据处理等。        ,init_bg_data:function(originBase64,callback){          ImageOrientationFix({            image:originBase64            ,imgType:"base64"            ,onFix:function(base64_str){               data_origin_image=base64_str;               image_background.onload=function(){                   appData.hasImage=true;                   //--获取相关数据及计算。                    data_bg.originSize.w=image_background.naturalWidth;                    data_bg.originSize.h=image_background.naturalHeight;                    data_bg.angle=0;                    data_bg.location.x=0;                    data_bg.location.y=0;                    data_bg.zoom=1;                    data_bg.size.w=data_bg.originSize.w;                    data_bg.size.h=data_bg.originSize.h;                    image_background.onload=function(){};                    console.log("bg层数据");                    console.log(data_bg);                   //--按照当前显示区域,尽量显示全部图片,计算显示尺寸。                   if(data_bg.originSize.w>appData.panelSize.w||data_bg.originSize.h>appData.panelSize.h){                       var _max_scale= Math.max(data_bg.originSize.w/appData.panelSize.w,data_bg.originSize.h/appData.panelSize.h);                       var _current_w=data_bg.originSize.w/_max_scale;                       var _current_h=data_bg.originSize.h/_max_scale;                       data_bg.zoom=1/_max_scale;                       data_bg.size.w=_current_w;                       data_bg.size.h=_current_h;                       console.log("bg层计算得到的可以显示区域是:");                       console.log(data_bg);                   }                   //--计算背景层应该显示的位置,尽量放到中间。                   data_bg.location.x=(appData.panelSize.w-data_bg.size.w)/2;                   data_bg.location.y=(appData.panelSize.h-data_bg.size.h)/2;                   //--计算各个状体的图片。                   data_bg.img_bg_0=image_background;                   data_bg.img_bg_90=new Image();                    data_bg.img_bg_180=new Image();                    data_bg.img_bg_270=new Image();                   var __canvas=document.createElement("canvas");                   var __context=__canvas.getContext("2d");                   //$(document.body).prepend(__canvas);                   //--90度的。                   __canvas.width=data_bg.originSize.h;                   __canvas.height=data_bg.originSize.w;                   __context.save();                   __context.rotate(Math.PI/2);                   __context.drawImage(image_background,0,0-data_bg.originSize.h);                   __context.restore();                   data_bg.img_bg_90.src= __canvas.toDataURL();                   __context.clearRect(0,0,__canvas.width,__canvas.height);                   //--180度的。                   __canvas.width=data_bg.originSize.w;                   __canvas.height=data_bg.originSize.h;                   __context.save();                   __context.rotate(Math.PI);                   __context.drawImage(image_background,0-data_bg.originSize.w,0-data_bg.originSize.h);                   __context.restore();                   data_bg.img_bg_180.src= __canvas.toDataURL();                   __context.clearRect(0,0,__canvas.width,__canvas.height);                   //--270度的。                   __canvas.width=data_bg.originSize.h;                   __canvas.height=data_bg.originSize.w;                   __context.save();                   __context.rotate(Math.PI*1.5);                   __context.drawImage(image_background,0-data_bg.originSize.w,0);                   __context.restore();                   data_bg.img_bg_270.src= __canvas.toDataURL();                   __context.clearRect(0,0,__canvas.width,__canvas.height);                   //--trans 背景数据。                   data_bg_trans.angle=data_bg.angle;                   data_bg_trans.location.x=data_bg.location.x;                   data_bg_trans.location.y=data_bg.location.y;                   data_bg_trans.size.w=data_bg.size.w;                   data_bg_trans.size.h=data_bg.size.h;                   data_bg_trans.originSize.w=data_bg.originSize.w;                   data_bg_trans.originSize.h=data_bg.originSize.h;                   data_bg_trans.zoom=data_bg.zoom;                   if(callback){                       callback(base64_str);                   }               };                  image_background.src=base64_str;            }        });        }        //--清空背景。        ,clear_background:function(){            context_bg.clearRect(0,0,canvas_bg.width,canvas_bg.height);        }        //--根据相关数据更新背景层图像。        ,updateBackground:function(){            var _child=this;            _child.clear_background();            if(data_bg_trans.angle==0||data_bg_trans.angle==360){                 //context.drawImage(img,0,0,img.width,img.height,imgX,imgY,img.width*imgScale,img.height*imgScale);//                context_bg.drawImage(image_background,data_bg.location.x,data_bg.location.y,data_bg.originSize.w,data_bg.originSize.h,0,0,data_bg.size.w,data_bg.size.h);                context_bg.drawImage(image_background,0,0,data_bg_trans.originSize.w,data_bg_trans.originSize.h,data_bg_trans.location.x,data_bg_trans.location.y,data_bg_trans.size.w,data_bg_trans.size.h);            }            else if(data_bg_trans.angle==90){                context_bg.drawImage(data_bg.img_bg_90,0,0,data_bg_trans.originSize.w,data_bg_trans.originSize.h,data_bg_trans.location.x,data_bg_trans.location.y,data_bg_trans.size.w,data_bg_trans.size.h);            }            else if(data_bg_trans.angle==180){                context_bg.drawImage(data_bg.img_bg_180,0,0,data_bg_trans.originSize.w,data_bg_trans.originSize.h,data_bg_trans.location.x,data_bg_trans.location.y,data_bg_trans.size.w,data_bg_trans.size.h);            }            else if(data_bg_trans.angle==270){                context_bg.drawImage(data_bg.img_bg_270,0,0,data_bg_trans.originSize.w,data_bg_trans.originSize.h,data_bg_trans.location.x,data_bg_trans.location.y,data_bg_trans.size.w,data_bg_trans.size.h);            }        }        //--底层api,根据位置移动图片。        ,MoveBackground:function(pos_x,pos_y){            data_bg_trans.location.x=pos_x;            data_bg_trans.location.y=pos_y;            var _child=this;            _child.updateBackground();        }        //--通过偏移量来移动图片。        ,MoveBackgroundByDelta:function(delta_x,delta_y){            var _child=this;            var _new_x=data_bg_trans.location.x+delta_x;            var _new_y=data_bg_trans.location.y+delta_y;            var _min_x=0;            var _max_x=0;            //--宽度边界判断。            //--假如图片宽度竟然比裁剪框要小,那么宽度最小值是0,            if(data_bg_trans.size.w<=data_cutter.size.w){                _min_x=0;                _max_x=appData.panelSize.w-data_bg_trans.size.w;            }            //--假如现在的图片宽度比整个容器宽度要小或者要大,那么就有:            //else if(data_bg_trans.size.w<=appData.panelSize.w){                //计算得出这时候的x最大值最小值。                //var __min_x=            //}            //--假如现在的图片宽度比整个容器宽度要小或者要大,那么就有:            else{                _min_x=data_cutter.size.w-data_bg_trans.size.w;                _max_x=appData.panelSize.w-data_cutter.size.w;            }            //--高度边界判断。            var _min_y=0;            var _max_y=0;            if(data_bg_trans.size.h<=data_cutter.size.h){                _min_y=0;                _max_y=appData.panelSize.h-data_bg_trans.size.h;            }            else{                _min_y=data_cutter.size.h-data_bg_trans.size.h;                _max_y=appData.panelSize.h-data_cutter.size.h;            }            if(_new_x<_min_x){                _new_x=_min_x;            }            else if(_new_x>_max_x){                _new_x=_max_x;            }            if(_new_y<_min_y){                _new_y=_min_y;            }            else if(_new_y>_max_y){                _new_y=_max_y;            }            console.log("新的图片位置是:"+_new_x+" X "+_new_y);            //_child.MoveCutter(_new_x,_new_y);            _child.MoveBackground(_new_x,_new_y);        }        //--底层api,缩放图片。        ,ScaleBackground:function(_scale){            //--在缩放前首先计算得到图片的中心点。            var _middle_x=0;            var _middle_y=0;            //--正常状体下面。            _middle_x=data_bg_trans.location.x+data_bg_trans.size.w/2;            _middle_y=data_bg_trans.location.y+data_bg_trans.size.h/2;            data_bg_trans.zoom=_scale;            data_bg_trans.size.w=data_bg_trans.originSize.w*_scale;            data_bg_trans.size.h=data_bg_trans.originSize.h*_scale;            var __x=_middle_x-(data_bg_trans.size.w)/2;            var __y=_middle_y-(data_bg_trans.size.h)/2;            data_bg_trans.location.x=__x;            data_bg_trans.location.y=__y;            var _child=this;            _child.updateBackground();        }        //--旋转。        ,RotateImage:function(angle){            if(angle!=0&&angle!=90&&angle!=180&&angle!=270&&angle!=360){                console.log("不支持该角度。");                return;            }            var preAngle=data_bg_trans.angle;            //--计算原本的中心点。            var _middle_x=0;            var _middle_y=0;            //--正常状体下面。            _middle_x=data_bg_trans.location.x+data_bg_trans.size.w/2;            _middle_y=data_bg_trans.location.y+data_bg_trans.size.h/2;            //--那么一旦改变了角度,需要将各个坐标系都转换过来。            if(angle==0||angle==360){                data_bg_trans.angle=0;                data_bg_trans.originSize.w=data_bg.originSize.w;                data_bg_trans.originSize.h=data_bg.originSize.h;            }            else if(angle==90){                data_bg_trans.angle=90;                data_bg_trans.originSize.w=data_bg.originSize.h;                data_bg_trans.originSize.h=data_bg.originSize.w;            }            else if(angle==180){                data_bg_trans.angle=180;                data_bg_trans.originSize.w=data_bg.originSize.w;                data_bg_trans.originSize.h=data_bg.originSize.h;            }            else if(angle==270){                data_bg_trans.angle=270;                data_bg_trans.originSize.w=data_bg.originSize.h;                data_bg_trans.originSize.h=data_bg.originSize.w;            }                data_bg_trans.size.w=data_bg_trans.originSize.w*data_bg_trans.zoom;                data_bg_trans.size.h=data_bg_trans.originSize.h*data_bg_trans.zoom;                data_bg_trans.location.x=_middle_x-(data_bg_trans.size.w)/2;                data_bg_trans.location.y=_middle_y-(data_bg_trans.size.h)/2;            data_bg_trans.angle=angle;            var _child=this;            _child.updateBackground();        }        //--初始化操控层。        ,initOperationLayout:function(){            var _child=this;            data_op.panelInfo=innerTools.GetAbsoluteLocationEx(canvas_operation);            console.log("当前panel的位置信息。");            console.log(data_op.panelInfo);            console.log(innerTools.browser);            if(innerTools.browser.versions.mobile==true||innerTools.browser.versions.mobile==true||innerTools.browser.versions.android||innerTools.browser.versions.iPhone){                _child._init_mobile_operations();            }            else{                _child._init_pc_operations();            }        }        //--pc上面的控制事件。        ,_init_pc_operations:function(){    //o是移动对象            var _child=this;            $(canvas_operation).mousedown(function(event){                if(appData.hasImage==false){                    return;                }                data_op.isInDrag=true;                console.log("canvas operation mouse down:");                data_op.panelInfo=innerTools.GetAbsoluteLocationEx(canvas_operation);                if(data_op.panelInfo.absoluteLeft==0&&data_op.panelInfo.absoluteTop==0&&data_op.panelInfo.offsetHeight==0&&data_op.panelInfo.offsetWidth==0){                }                //params.flag = true;                if (!event) {                    event = window.event;                    //防止IE文字选中                    canvas_operation.onselectstart = function () {                        return false;                    }                }                var e = event;                var params_currentX = e.clientX;                var params_currentY = e.clientY;                data_op.beginPoint.x=params_currentX;                data_op.beginPoint.y=params_currentY;                var realX=params_currentX-data_op.panelInfo.absoluteLeft;                var realY=params_currentY-data_op.panelInfo.absoluteTop;             _clearDebug();            _debug("未处理前,realX realY是:"+realX+" x "+realY);                //注意,上面没有考虑到有滚动条的状态,现在添加对滚动条的处理。                            //--notice,假如页面有滚动条,每次都滚到不同位置的话,那么这个定位可能会有问题,于是我们需要进行处理。            var _scrollTop=$(document).scrollTop();            if(_scrollTop>0){                realY=realY+_scrollTop;            }            var _scrollLeft=$(document).scrollLeft();            if(_scrollLeft>0){                realX=realX+_scrollLeft;            }                data_op.point1.x=params_currentX;                data_op.point1.y=params_currentY;                data_op.isInCut=_child.isPointInCutter(realX,realY);            _debug("scroll top left信息:"+_scrollTop+" x "+_scrollLeft);            _debug("当前panel位置信息是:"+JSON.stringify(data_op.panelInfo));            _debug("realX realY是:"+realX+" x "+realY);            _debug("裁剪框位置是:"+JSON.stringify(data_cutter));                console.log("当前坐标");                console.log(params_currentX+"x"+params_currentY);                if(data_op.isInCut){                    console.log("%c 在裁剪框里面。","color:green;");                }            });            $(document).mouseup(function(){                if(appData.hasImage==false){                    return;                }                data_op.isInDrag=false;                console.log("document 鼠标移动上去了。 mouse up");            });            $(document).mousemove(function (event) {                if(appData.hasImage==false){                    return;                }                if(data_op.isInDrag==false){                    return;                }                var e = event ? event : window.event;                var nowX = e.clientX, nowY = e.clientY;                console.log("%c 移动事件 mousemove中,位置:"+nowX+" x "+nowY+" 是否在裁剪框里面:"+data_op.isInCut,"color:red");                // var disX = nowX - params.currentX, disY = nowY - params.currentY;                //target.style.left = parseInt(params.left) + disX + "px";                //target.style.top = parseInt(params.top) + disY + "px";                //--计算位移量。                data_op.point2.x=nowX;                data_op.point2.y=nowY;                var delta_x=data_op.point2.x-data_op.point1.x;                var delta_y=data_op.point2.y-data_op.point1.y;                data_op.point1.x=nowX;                data_op.point1.y=nowY;                if(data_op.isInCut==true){                    //--已经                    console.log("现在在重新渲染裁剪框了。"+delta_x+" x "+delta_y);                    _child.MoveCutterByDelta(delta_x,delta_y);                }                else{                    _child.MoveBackgroundByDelta(delta_x,delta_y);                }            });        }        //--手机端移动端的事件。        ,_init_mobile_operations:function(){            var _child=this;        canvas_operation.addEventListener("touchstart",function(event){            if(appData.hasImage==false){                return;            }        var beginX=event.changedTouches[0].pageX;        var beginY=event.changedTouches[0].pageY;                data_op.isInDrag=true;                console.log("canvas operation touch start");                data_op.panelInfo=innerTools.GetAbsoluteLocationEx(canvas_operation);                if(data_op.panelInfo.absoluteLeft==0&&data_op.panelInfo.absoluteTop==0&&data_op.panelInfo.offsetHeight==0&&data_op.panelInfo.offsetWidth==0){                   // data_op.panelInfo=innerTools.GetAbsoluteLocationEx(canvas_operation);                }                var e = event;                var params_currentX = beginX;                var params_currentY = beginY;                data_op.beginPoint.x=params_currentX;                data_op.beginPoint.y=params_currentY;                var realX=params_currentX-data_op.panelInfo.absoluteLeft;                var realY=params_currentY-data_op.panelInfo.absoluteTop;             _clearDebug();            _debug("未处理前,realX realY是:"+realX+" x "+realY);                //注意,上面没有考虑到有滚动条的状态,现在添加对滚动条的处理。                            //--notice,假如页面有滚动条,每次都滚到不同位置的话,那么这个定位可能会有问题,于是我们需要进行处理。            var _scrollTop=$(document).scrollTop();            if(_scrollTop>0){                //realY=realY+_scrollTop; 移动端不用管,似乎得到的是正确的。            }            var _scrollLeft=$(document).scrollLeft();            if(_scrollLeft>0){               // realX=realX+_scrollLeft; 移动端不用管,似乎得到的是正确的。            }            _debug("scroll top left信息:"+_scrollTop+" x "+_scrollLeft);            _debug("当前panel位置信息是:"+JSON.stringify(data_op.panelInfo));            _debug("realX realY是:"+realX+" x "+realY);            _debug("裁剪框位置是:"+JSON.stringify(data_cutter));                data_op.point1.x=params_currentX;                data_op.point1.y=params_currentY;                data_op.isInCut=_child.isPointInCutter(realX,realY);                console.log("当前坐标");                console.log(params_currentX+"x"+params_currentY);                if(data_op.isInCut){                    console.log("%c 在裁剪框里面。","color:green;");                }            event.preventDefault();            event.stopPropagation();    },false);        canvas_operation.addEventListener("touchmove",function(event){                if(appData.hasImage==false){                    return;                }                if(data_op.isInDrag==false){                    return;                }                event.preventDefault();                event.stopPropagation();                var e = event ? event : window.event;                var beginX=event.changedTouches[0].pageX;                var beginY=event.changedTouches[0].pageY;                var nowX = beginX, nowY = beginY;                console.log("%c 移动事件 mousemove中,位置:"+nowX+" x "+nowY+" 是否在裁剪框里面:"+data_op.isInCut,"color:red");                // var disX = nowX - params.currentX, disY = nowY - params.currentY;                //target.style.left = parseInt(params.left) + disX + "px";                //target.style.top = parseInt(params.top) + disY + "px";                //--计算位移量。                data_op.point2.x=nowX;                data_op.point2.y=nowY;                var delta_x=data_op.point2.x-data_op.point1.x;                var delta_y=data_op.point2.y-data_op.point1.y;                data_op.point1.x=nowX;                data_op.point1.y=nowY;                if(data_op.isInCut==true){                    //--已经                    console.log("现在在重新渲染裁剪框了。"+delta_x+" x "+delta_y);                    _child.MoveCutterByDelta(delta_x,delta_y);                }                else{                    _child.MoveBackgroundByDelta(delta_x,delta_y);                }    },false);        canvas_operation.addEventListener("touchend",function(event){        if(appData.hasImage==false){           return;        }         data_op.isInDrag=false;        event.preventDefault();        event.stopPropagation();        },false);        }        //--判断某个点是否在裁剪框里面。        ,isPointInCutter:function(point_x,point_y){            var min_x=data_cutter.location.x;            var min_y=data_cutter.location.y;            var max_x=min_x+data_cutter.size.w;            var max_y=min_y+data_cutter.size.h;            if(point_x<min_x||point_x>max_x||point_y<min_y||point_y>max_y){                return false;            }            else{                return true;            }        }        ,_cut_by_sizing:function(callback){            var __canvas = document.createElement("canvas");            var __context = __canvas.getContext("2d");            __canvas.width = data_cutter.size.w;            __canvas.height = data_cutter.size.h;            var _image=new Image();            _image.onload=function(){                __context.drawImage(_image,data_cutter.location.x,data_cutter.location.y,data_cutter.size.w,data_cutter.size.h,0,0,data_cutter.size.w,data_cutter.size.h);                if(callback){                    var _base64=__canvas.toDataURL("image/jpeg");                    callback(_base64);                }            };            _image.src=canvas_bg.toDataURL("image/jpeg");        }        ,_cut_by_ratio:function(callback){            //--根据当前操作界面上的数据,换算成为图片上真实尺寸。            var _real_x_in_img=data_cutter.location.x-data_bg_trans.location.x;            var _real_y_in_img=data_cutter.location.y-data_bg_trans.location.y;            _real_x_in_img=_real_x_in_img/data_bg_trans.zoom;            _real_y_in_img=_real_y_in_img/data_bg_trans.zoom;            var _real_w=data_cutter.size.w/data_bg_trans.zoom;            var _real_h=data_cutter.size.h/data_bg_trans.zoom;            var __canvas = document.createElement("canvas");            var __context = __canvas.getContext("2d");            __canvas.width = _real_w;            __canvas.height = _real_h;            var _image;            if(data_bg_trans.angle==0||data_bg_trans.angle==360){                _image=data_bg.img_bg_0;            }            else if(data_bg_trans.angle==90){                _image=data_bg.img_bg_90;            }            else if(data_bg_trans.angle==180){                _image=data_bg.img_bg_180;            }            else if(data_bg_trans.angle==270){                _image=data_bg.img_bg_270;            }            __context.drawImage(_image,_real_x_in_img,_real_y_in_img,_real_w,_real_h,0,0,_real_w,_real_h);            var _base64=__canvas.toDataURL("image/jpeg");            callback(_base64);        }        //--裁剪图像,        ,cut:function(callback){            var _child=this;            if(settings.saveMode=="ratio"){                _child._cut_by_ratio(callback);            }            else{                _child._cut_by_sizing(callback);            }        }    };    app.init();    //初始化控件。    this.init=function(base64_image_str){        console.log("初始化。");        app.init_background(base64_image_str);        app.updateCutter();    };    //--对外接口,移动裁剪框。    this.MoveCutter=function(pos_x,pos_y){        //--这里至少需要进行边界碰撞的判断。        app.MoveCutter(pos_x,pos_y);    };    //--对外接口,移动图片。    this.MoveImage=function(pos_x,pos_y){        //--这里至少需要进行边界碰撞的判断。        app.MoveBackground(pos_x,pos_y);    };    //--对外接口,缩放图片、    this.ScaleImage=function(_scale){        app.ScaleBackground(_scale);    };    this.RotateImage=function(angle){        app.RotateImage(angle);    };    //--是否已经有图片了。    this.hasImage=function(){        return appData.hasImage;    };    this.show_data_cutter=function(){      console.log(data_cutter);    };    //--获取目前的角度。    this.getImageAngle=function(){        return data_bg_trans.angle;    };    //--获取图片的缩放倍率。    this.getImageRotation=function(){        return data_bg_trans.angle;    };    //--获取缩放倍率。    this.getImageZoom=function(){        return data_bg_trans.zoom;    };    this.cutImg=function(callback){      app.cut(callback);    };}

demo脚本

var _e_width=$(window).width()-200;var _e_height=$(window).height()-200;if(_e_width>800){    _e_width=800;}else if(_e_width<450){    _e_width=450;}/*if(_e_height>600){    _e_height=600;}else if(_e_height<400){    _e_height=400;}*/var _image_editor={};try{   _image_editor =new ImageEditor({        cutWidth:150 //裁剪框的宽度。        ,cutHeight:200 //裁剪框的高度        ,containerWidth:_e_width //容器宽度        ,containerHeight:_e_height //容器高度        ,imageShowWidth:400 //图片默认显示的宽度【会按照要求的宽度及高度等比缩放】        ,imageShowHeight:500 //图片默认显示的高度【会按照要求的宽度及高度等比缩放】        ,containerElement:$("#div_cropper") //容器的默认元素,jquery元素或者原生dom元素。});}catch (ed){    alert(ed);}    //--逻辑方法定义$("#uploadImage").change(function(){    if (document.getElementById("uploadImage").files.length === 0) {        layer.alert("请选择图片!",3);        return; }    var oFile = document.getElementById("uploadImage").files[0];    //if (!rFilter.test(oFile.type)) { alert("You must select a valid image file!"); return; }    /*  if(oFile.size>5*1024*1024){     message(myCache.par.lang,{cn:"照片上传:文件不能超过5MB!请使用容量更小的照片。",en:"证书上传:文件不能超过100K!"})     changePanel("result");     return;     }*/    if(!new RegExp("(jpg|jpeg|gif|png)+","gi").test(oFile.type)){        layer.alert("照片上传:文件类型必须是JPG、JPEG、PNG或GIF!",3);        return;    }       var reader = new FileReader();        reader.onload =function(e){                           var _img_str=e.target.result;                // img 元素                _image_editor.init(_img_str);        };    reader.readAsDataURL(oFile);    return;});$("#btn_zoom_out").click(function(){    if(_image_editor.hasImage()==false){        alert("请先选择图片!");        return;    }    var _zoom=_image_editor.getImageZoom();    if(_zoom<0.5){        alert("最小倍率是0.5,无法继续缩小");        return;    }    _image_editor.ScaleImage(_zoom-0.2);});$("#btn_zoom_in").click(function(){    if(_image_editor.hasImage()==false){        alert("请先选择图片!");        return;    }    var _zoom=_image_editor.getImageZoom();    if(_zoom>4){        alert("最大倍率是4,无法继续放大");        return;    }    _image_editor.ScaleImage(_zoom+0.2);});$("#btn_turn_left").click(function(){    if(_image_editor.hasImage()==false){        alert("请先选择图片!");        return;    }    var _angle=_image_editor.getImageAngle();    _angle=(_angle+360)-90;    _angle=(_angle)%360;    _image_editor.RotateImage(_angle);});$("#btn_turn_right").click(function(){    if(_image_editor.hasImage()==false){        alert("请先选择图片!");        return;    }    var _angle=_image_editor.getImageAngle();    _angle=(_angle+0)+90;    _angle=(_angle)%360;    _image_editor.RotateImage(_angle);});$("#btn_save").click(function(){    if(_image_editor.hasImage()==false){        alert("请先选择图片!");        return;    }    _image_editor.cutImg(function(imgStr){        $("#preview_img").attr("src",imgStr);    });});

未完待续,下一篇是实际应用效果

1 0
原创粉丝点击