2 * Copyright (c) 2006, David Spurr (http://www.defusion.org.uk/)
\r
3 * All rights reserved.
\r
5 * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
\r
7 * * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
\r
8 * * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
\r
9 * * Neither the name of the David Spurr nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
\r
11 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
\r
13 * http://www.opensource.org/licenses/bsd-license.php
\r
15 * See scriptaculous.js for full scriptaculous licence
\r
18 var CropDraggable=Class.create();
19 Object.extend(Object.extend(CropDraggable.prototype,Draggable.prototype),{initialize:function(_1){
20 this.options=Object.extend({drawMethod:function(){
23 this.handle=this.element;
24 this.delta=this.currentDelta();
26 this.eventMouseDown=this.initDrag.bindAsEventListener(this);
27 Event.observe(this.handle,"mousedown",this.eventMouseDown);
28 Draggables.register(this);
30 var _3=Position.cumulativeOffset(this.element);
31 var d=this.currentDelta();
34 var p=[0,1].map(function(i){
35 return (_2[i]-_3[i]-this.offset[i]);
37 this.options.drawMethod(p);
40 Cropper.Img=Class.create();
41 Cropper.Img.prototype={initialize:function(_7,_8){
42 this.options=Object.extend({ratioDim:{x:0,y:0},minWidth:0,minHeight:0,displayOnInit:false,onEndCrop:Prototype.emptyFunction,captureKeys:true,onloadCoords:null,maxWidth:0,maxHeight:0},_8||{});
44 this.clickCoords={x:0,y:0};
47 this.isWebKit=/Konqueror|Safari|KHTML/.test(navigator.userAgent);
48 this.isIE=/MSIE/.test(navigator.userAgent);
49 this.isOpera8=/Opera\s[1-8]/.test(navigator.userAgent);
53 this.fixedWidth=(this.options.maxWidth>0&&(this.options.minWidth>=this.options.maxWidth));
54 this.fixedHeight=(this.options.maxHeight>0&&(this.options.minHeight>=this.options.maxHeight));
55 if(typeof this.img=="undefined"){
58 $A(document.getElementsByTagName("script")).each(function(s){
59 if(s.src.match(/cropper\.js/)){
60 var _a=s.src.replace(/cropper\.js(.*)?/,"");
61 var _b=document.createElement("link");
64 _b.href=_a+"cropper.css";
66 document.getElementsByTagName("head")[0].appendChild(_b);
69 if(this.options.ratioDim.x>0&&this.options.ratioDim.y>0){
70 var _c=this.getGCD(this.options.ratioDim.x,this.options.ratioDim.y);
71 this.ratioX=this.options.ratioDim.x/_c;
72 this.ratioY=this.options.ratioDim.y/_c;
75 if(this.img.complete||this.isWebKit){
78 Event.observe(this.img,"load",this.onLoad.bindAsEventListener(this));
80 },getGCD:function(a,b){
84 return this.getGCD(b,a%b);
87 var _10=this.img.parentNode;
92 this.imgWrap=Builder.node("div",{"class":_f+"wrap"+_11});
93 this.north=Builder.node("div",{"class":_f+"overlay "+_f+"north"},[Builder.node("span")]);
94 this.east=Builder.node("div",{"class":_f+"overlay "+_f+"east"},[Builder.node("span")]);
95 this.south=Builder.node("div",{"class":_f+"overlay "+_f+"south"},[Builder.node("span")]);
96 this.west=Builder.node("div",{"class":_f+"overlay "+_f+"west"},[Builder.node("span")]);
97 var _12=[this.north,this.east,this.south,this.west];
98 this.dragArea=Builder.node("div",{"class":_f+"dragArea"},_12);
99 this.handleN=Builder.node("div",{"class":_f+"handle "+_f+"handleN"});
100 this.handleNE=Builder.node("div",{"class":_f+"handle "+_f+"handleNE"});
101 this.handleE=Builder.node("div",{"class":_f+"handle "+_f+"handleE"});
102 this.handleSE=Builder.node("div",{"class":_f+"handle "+_f+"handleSE"});
103 this.handleS=Builder.node("div",{"class":_f+"handle "+_f+"handleS"});
104 this.handleSW=Builder.node("div",{"class":_f+"handle "+_f+"handleSW"});
105 this.handleW=Builder.node("div",{"class":_f+"handle "+_f+"handleW"});
106 this.handleNW=Builder.node("div",{"class":_f+"handle "+_f+"handleNW"});
107 this.selArea=Builder.node("div",{"class":_f+"selArea"},[Builder.node("div",{"class":_f+"marqueeHoriz "+_f+"marqueeNorth"},[Builder.node("span")]),Builder.node("div",{"class":_f+"marqueeVert "+_f+"marqueeEast"},[Builder.node("span")]),Builder.node("div",{"class":_f+"marqueeHoriz "+_f+"marqueeSouth"},[Builder.node("span")]),Builder.node("div",{"class":_f+"marqueeVert "+_f+"marqueeWest"},[Builder.node("span")]),this.handleN,this.handleNE,this.handleE,this.handleSE,this.handleS,this.handleSW,this.handleW,this.handleNW,Builder.node("div",{"class":_f+"clickArea"})]);
108 this.imgWrap.appendChild(this.img);
109 this.imgWrap.appendChild(this.dragArea);
110 this.dragArea.appendChild(this.selArea);
111 this.dragArea.appendChild(Builder.node("div",{"class":_f+"clickArea"}));
112 _10.appendChild(this.imgWrap);
113 this.startDragBind=this.startDrag.bindAsEventListener(this);
114 Event.observe(this.dragArea,"mousedown",this.startDragBind);
115 this.onDragBind=this.onDrag.bindAsEventListener(this);
116 Event.observe(document,"mousemove",this.onDragBind);
117 this.endCropBind=this.endCrop.bindAsEventListener(this);
118 Event.observe(document,"mouseup",this.endCropBind);
119 this.resizeBind=this.startResize.bindAsEventListener(this);
120 this.handles=[this.handleN,this.handleNE,this.handleE,this.handleSE,this.handleS,this.handleSW,this.handleW,this.handleNW];
121 this.registerHandles(true);
122 if(this.options.captureKeys){
123 this.keysBind=this.handleKeys.bindAsEventListener(this);
124 Event.observe(document,"keypress",this.keysBind);
126 new CropDraggable(this.selArea,{drawMethod:this.moveArea.bindAsEventListener(this)});
128 },registerHandles:function(_13){
129 for(var i=0;i<this.handles.length;i++){
130 var _15=$(this.handles[i]);
133 if(this.fixedWidth&&this.fixedHeight){
136 if(this.fixedWidth||this.fixedHeight){
137 var _17=_15.className.match(/([S|N][E|W])$/);
138 var _18=_15.className.match(/(E|W)$/);
139 var _19=_15.className.match(/(N|S)$/);
143 if(this.fixedWidth&&_18){
146 if(this.fixedHeight&&_19){
156 Event.observe(_15,"mousedown",this.resizeBind);
160 Event.stopObserving(_15,"mousedown",this.resizeBind);
163 },setParams:function(){
164 this.imgW=this.img.width;
165 this.imgH=this.img.height;
166 $(this.north).setStyle({height:0});
167 $(this.east).setStyle({width:0,height:0});
168 $(this.south).setStyle({height:0});
169 $(this.west).setStyle({width:0,height:0});
170 $(this.imgWrap).setStyle({"width":this.imgW+"px","height":this.imgH+"px"});
171 $(this.selArea).hide();
172 var _1a={x1:0,y1:0,x2:0,y2:0};
174 if(this.options.onloadCoords!=null){
175 _1a=this.cloneCoords(this.options.onloadCoords);
178 if(this.options.ratioDim.x>0&&this.options.ratioDim.y>0){
179 _1a.x1=Math.ceil((this.imgW-this.options.ratioDim.x)/2);
180 _1a.y1=Math.ceil((this.imgH-this.options.ratioDim.y)/2);
181 _1a.x2=_1a.x1+this.options.ratioDim.x;
182 _1a.y2=_1a.y1+this.options.ratioDim.y;
186 this.setAreaCoords(_1a,false,false,1);
187 if(this.options.displayOnInit&&_1b){
196 this.imgWrap.parentNode.insertBefore(this.img,this.imgWrap);
197 this.imgWrap.parentNode.removeChild(this.imgWrap);
198 Event.stopObserving(this.dragArea,"mousedown",this.startDragBind);
199 Event.stopObserving(document,"mousemove",this.onDragBind);
200 Event.stopObserving(document,"mouseup",this.endCropBind);
201 this.registerHandles(false);
202 if(this.options.captureKeys){
203 Event.stopObserving(document,"keypress",this.keysBind);
213 },handleKeys:function(e){
230 if(dir.x!=0||dir.y!=0){
235 this.moveArea([this.areaCoords.x1+dir.x,this.areaCoords.y1+dir.y]);
240 return (this.areaCoords.x2-this.areaCoords.x1);
242 return (this.areaCoords.y2-this.areaCoords.y1);
243 },moveArea:function(_1e){
244 this.setAreaCoords({x1:_1e[0],y1:_1e[1],x2:_1e[0]+this.calcW(),y2:_1e[1]+this.calcH()},true,false);
246 },cloneCoords:function(_1f){
247 return {x1:_1f.x1,y1:_1f.y1,x2:_1f.x2,y2:_1f.y2};
248 },setAreaCoords:function(_20,_21,_22,_23,_24){
250 var _25=_20.x2-_20.x1;
251 var _26=_20.y2-_20.y1;
260 if(_20.x2>this.imgW){
262 _20.x1=this.imgW-_25;
264 if(_20.y2>this.imgH){
266 _20.y1=this.imgH-_26;
275 if(_20.x2>this.imgW){
278 if(_20.y2>this.imgH){
283 this.applyRatio(_20,{x:this.ratioX,y:this.ratioY},_23,_24);
286 this.applyRatio(_20,{x:1,y:1},_23,_24);
289 var _27=[this.options.minWidth,this.options.minHeight];
290 var _28=[this.options.maxWidth,this.options.maxHeight];
291 if(_27[0]>0||_27[1]>0||_28[0]>0||_28[1]>0){
292 var _29={a1:_20.x1,a2:_20.x2};
293 var _2a={a1:_20.y1,a2:_20.y2};
294 var _2b={min:0,max:this.imgW};
295 var _2c={min:0,max:this.imgH};
296 if((_27[0]!=0||_27[1]!=0)&&_22){
305 if((_28[0]!=0||_28[0]!=0)&&_22){
306 if(_28[0]>0&&_28[0]<=_28[1]){
309 if(_28[1]>0&&_28[1]<=_28[0]){
315 this.applyDimRestriction(_29,_27[0],_23.x,_2b,"min");
318 this.applyDimRestriction(_2a,_27[1],_23.y,_2c,"min");
321 this.applyDimRestriction(_29,_28[0],_23.x,_2b,"max");
324 this.applyDimRestriction(_2a,_28[1],_23.y,_2c,"max");
326 _20={x1:_29.a1,y1:_2a.a1,x2:_29.a2,y2:_2a.a2};
331 },applyDimRestriction:function(_2d,val,_2f,_30,_31){
334 _32=((_2d.a2-_2d.a1)<val);
336 _32=((_2d.a2-_2d.a1)>val);
354 },applyRatio:function(_33,_34,_35,_36){
356 if(_36=="N"||_36=="S"){
357 _37=this.applyRatioToAxis({a1:_33.y1,b1:_33.x1,a2:_33.y2,b2:_33.x2},{a:_34.y,b:_34.x},{a:_35.y,b:_35.x},{min:0,max:this.imgW});
363 _37=this.applyRatioToAxis({a1:_33.x1,b1:_33.y1,a2:_33.x2,b2:_33.y2},{a:_34.x,b:_34.y},{a:_35.x,b:_35.y},{min:0,max:this.imgH});
369 },applyRatioToAxis:function(_38,_39,_3a,_3b){
370 var _3c=Object.extend(_38,{});
371 var _3d=_3c.a2-_3c.a1;
372 var _3e=Math.floor(_3d*_39.b/_39.a);
392 _40=Math.floor(_41*_39.a/_39.b);
396 _3c.a1=_3c.a1=_3c.a2-_40;
400 },drawArea:function(){
401 var _42=this.calcW();
402 var _43=this.calcH();
404 var _45=[this.areaCoords.x1+px,this.areaCoords.y1+px,_42+px,_43+px,this.areaCoords.x2+px,this.areaCoords.y2+px,(this.img.width-this.areaCoords.x2)+px,(this.img.height-this.areaCoords.y2)+px];
405 var _46=this.selArea.style;
410 var _47=Math.ceil((_42-6)/2)+px;
411 var _48=Math.ceil((_43-6)/2)+px;
412 this.handleN.style.left=_47;
413 this.handleE.style.top=_48;
414 this.handleS.style.left=_47;
415 this.handleW.style.top=_48;
416 this.north.style.height=_45[1];
417 var _49=this.east.style;
422 var _4a=this.south.style;
425 var _4b=this.west.style;
430 this.forceReRender();
431 },forceReRender:function(){
432 if(this.isIE||this.isWebKit){
433 var n=document.createTextNode(" ");
439 fixEl=document.getElementsByClassName("imgCrop_marqueeSouth",this.imgWrap)[0];
440 d=Builder.node("div","");
441 d.style.visibility="hidden";
442 var _4e=["SE","S","SW"];
443 for(i=0;i<_4e.length;i++){
444 el=document.getElementsByClassName("imgCrop_handle"+_4e[i],this.selArea)[0];
445 if(el.childNodes.length){
446 el.removeChild(el.childNodes[0]);
452 fixEl.appendChild(n);
453 fixEl.removeChild(n);
455 },startResize:function(e){
456 this.startCoords=this.cloneCoords(this.areaCoords);
458 this.resizeHandle=Event.element(e).classNames().toString().replace(/([^N|NE|E|SE|S|SW|W|NW])+/,"");
460 },startDrag:function(e){
462 this.clickCoords=this.getCurPos(e);
463 this.setAreaCoords({x1:this.clickCoords.x,y1:this.clickCoords.y,x2:this.clickCoords.x,y2:this.clickCoords.y},false,false,null);
467 },getCurPos:function(e){
468 var el=this.imgWrap,wrapOffsets=Position.cumulativeOffset(el);
469 while(el.nodeName!="BODY"){
470 wrapOffsets[1]-=el.scrollTop||0;
471 wrapOffsets[0]-=el.scrollLeft||0;
474 return curPos={x:Event.pointerX(e)-wrapOffsets[0],y:Event.pointerY(e)-wrapOffsets[1]};
475 },onDrag:function(e){
476 if(this.dragging||this.resizing){
478 var _55=this.getCurPos(e);
479 var _56=this.cloneCoords(this.areaCoords);
482 if(_55.x<this.clickCoords.x){
485 if(_55.y<this.clickCoords.y){
488 this.transformCoords(_55.x,this.clickCoords.x,_56,"x");
489 this.transformCoords(_55.y,this.clickCoords.y,_56,"y");
492 _54=this.resizeHandle;
494 this.transformCoords(_55.x,this.startCoords.x1,_56,"x");
495 if(_55.x<this.startCoords.x1){
500 this.transformCoords(_55.x,this.startCoords.x2,_56,"x");
501 if(_55.x<this.startCoords.x2){
507 this.transformCoords(_55.y,this.startCoords.y2,_56,"y");
508 if(_55.y<this.startCoords.y2){
513 this.transformCoords(_55.y,this.startCoords.y1,_56,"y");
514 if(_55.y<this.startCoords.y1){
521 this.setAreaCoords(_56,false,e.shiftKey,_57,_54);
525 },transformCoords:function(_58,_59,_5a,_5b){
532 },endCrop:function(){
535 this.options.onEndCrop(this.areaCoords,{width:this.calcW(),height:this.calcH()});
536 },subInitialize:function(){
537 },subDrawArea:function(){
539 Cropper.ImgWithPreview=Class.create();
540 Object.extend(Object.extend(Cropper.ImgWithPreview.prototype,Cropper.Img.prototype),{subInitialize:function(){
541 this.hasPreviewImg=false;
542 if(typeof (this.options.previewWrap)!="undefined"&&this.options.minWidth>0&&this.options.minHeight>0){
543 this.previewWrap=$(this.options.previewWrap);
544 this.previewImg=this.img.cloneNode(false);
545 this.previewImg.id="imgCrop_"+this.previewImg.id;
546 this.options.displayOnInit=true;
547 this.hasPreviewImg=true;
548 this.previewWrap.addClassName("imgCrop_previewWrap");
549 this.previewWrap.setStyle({width:this.options.minWidth+"px",height:this.options.minHeight+"px"});
550 this.previewWrap.appendChild(this.previewImg);
552 },subDrawArea:function(){
553 if(this.hasPreviewImg){
554 var _5d=this.calcW();
555 var _5e=this.calcH();
556 var _5f={x:this.imgW/_5d,y:this.imgH/_5e};
557 var _60={x:_5d/this.options.minWidth,y:_5e/this.options.minHeight};
558 var _61={w:Math.ceil(this.options.minWidth*_5f.x)+"px",h:Math.ceil(this.options.minHeight*_5f.y)+"px",x:"-"+Math.ceil(this.areaCoords.x1/_60.x)+"px",y:"-"+Math.ceil(this.areaCoords.y1/_60.y)+"px"};
559 var _62=this.previewImg.style;