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

推荐

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

前言

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

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.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_xmax_x||point_ymax_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);
    });
});

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

你可能感兴趣的:(前端)