2 * Copyright (c) 2006, David Spurr (http://www.defusion.org.uk/)
5 * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
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.
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.
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.
13 * http://www.opensource.org/licenses/bsd-license.php
15 * See scriptaculous.js for full scriptaculous licence
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},_8||{});
43 if(this.options.minWidth>0&&this.options.minHeight>0){
44 this.options.ratioDim.x=this.options.minWidth;
45 this.options.ratioDim.y=this.options.minHeight;
48 this.clickCoords={x:0,y:0};
51 this.isWebKit=/Konqueror|Safari|KHTML/.test(navigator.userAgent);
52 this.isIE=/MSIE/.test(navigator.userAgent);
53 this.isOpera8=/Opera\s[1-8]/.test(navigator.userAgent);
57 $A(document.getElementsByTagName("script")).each(function(s){
58 if(s.src.match(/cropper\.js/)){
59 var _a=s.src.replace(/cropper\.js(.*)?/,"");
60 var _b=document.createElement("link");
63 _b.href=_a+"cropper.css";
65 document.getElementsByTagName("head")[0].appendChild(_b);
68 if(this.options.ratioDim.x>0&&this.options.ratioDim.y>0){
69 var _c=this.getGCD(this.options.ratioDim.x,this.options.ratioDim.y);
70 this.ratioX=this.options.ratioDim.x/_c;
71 this.ratioY=this.options.ratioDim.y/_c;
74 if(this.img.complete||this.isWebKit){
77 Event.observe(this.img,"load",this.onLoad.bindAsEventListener(this));
79 },getGCD:function(a,b){return 1;
83 return this.getGCD(b,a%b);
86 var _10=this.img.parentNode;
91 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];
99 this.overlay=Builder.node("div",{"class":_f+"overlay"});
100 var _12=[this.overlay];
102 this.dragArea=Builder.node("div",{"class":_f+"dragArea"},_12);
103 this.handleN=Builder.node("div",{"class":_f+"handle "+_f+"handleN"});
104 this.handleNE=Builder.node("div",{"class":_f+"handle "+_f+"handleNE"});
105 this.handleE=Builder.node("div",{"class":_f+"handle "+_f+"handleE"});
106 this.handleSE=Builder.node("div",{"class":_f+"handle "+_f+"handleSE"});
107 this.handleS=Builder.node("div",{"class":_f+"handle "+_f+"handleS"});
108 this.handleSW=Builder.node("div",{"class":_f+"handle "+_f+"handleSW"});
109 this.handleW=Builder.node("div",{"class":_f+"handle "+_f+"handleW"});
110 this.handleNW=Builder.node("div",{"class":_f+"handle "+_f+"handleNW"});
111 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"})]);
112 Element.setStyle($(this.selArea),{backgroundColor:"transparent",backgroundRepeat:"no-repeat",backgroundPosition:"0 0"});
113 this.imgWrap.appendChild(this.img);
114 this.imgWrap.appendChild(this.dragArea);
115 this.dragArea.appendChild(this.selArea);
116 this.dragArea.appendChild(Builder.node("div",{"class":_f+"clickArea"}));
117 _10.appendChild(this.imgWrap);
118 Event.observe(this.dragArea,"mousedown",this.startDrag.bindAsEventListener(this));
119 Event.observe(document,"mousemove",this.onDrag.bindAsEventListener(this));
120 Event.observe(document,"mouseup",this.endCrop.bindAsEventListener(this));
121 var _13=[this.handleN,this.handleNE,this.handleE,this.handleSE,this.handleS,this.handleSW,this.handleW,this.handleNW];
122 for(var i=0;i<_13.length;i++){
123 Event.observe(_13[i],"mousedown",this.startResize.bindAsEventListener(this));
125 if(this.options.captureKeys){
126 Event.observe(document,"keydown",this.handleKeys.bindAsEventListener(this));
128 new CropDraggable(this.selArea,{drawMethod:this.moveArea.bindAsEventListener(this)});
130 },setParams:function(){
131 this.imgW=this.img.width;
132 this.imgH=this.img.height;
134 Element.setStyle($(this.overlay),{width:this.imgW+"px",height:this.imgH+"px"});
135 Element.hide($(this.overlay));
136 Element.setStyle($(this.selArea),{backgroundImage:"url("+this.img.src+")"});
138 Element.setStyle($(this.north),{height:0});
139 Element.setStyle($(this.east),{width:0,height:0});
140 Element.setStyle($(this.south),{height:0});
141 Element.setStyle($(this.west),{width:0,height:0});
143 Element.setStyle($(this.imgWrap),{"width":this.imgW+"px","height":this.imgH+"px"});
144 Element.hide($(this.selArea));
145 var _15=Position.positionedOffset(this.imgWrap);
146 this.wrapOffsets={"top":_15[1],"left":_15[0]};
147 var _16={x1:0,y1:0,x2:0,y2:0};
148 this.setAreaCoords(_16);
149 if(this.options.ratioDim.x>0&&this.options.ratioDim.y>0&&this.options.displayOnInit){
150 _16.x1=Math.ceil((this.imgW-this.options.ratioDim.x)/2);
151 _16.y1=Math.ceil((this.imgH-this.options.ratioDim.y)/2);
152 _16.x2=_16.x1+this.options.ratioDim.x;
153 _16.y2=_16.y1+this.options.ratioDim.y;
154 Element.show(this.selArea);
161 this.imgWrap.parentNode.insertBefore(this.img,this.imgWrap);
162 this.imgWrap.parentNode.removeChild(this.imgWrap);
163 Event.stopObserving(this.dragArea,"mousedown",this.startDrag.bindAsEventListener(this));
164 Event.stopObserving(document,"mousemove",this.onDrag.bindAsEventListener(this));
165 Event.stopObserving(document,"mouseup",this.endCrop.bindAsEventListener(this));
166 var _17=[this.handleN,this.handleNE,this.handleE,this.handleSE,this.handleS,this.handleSW,this.handleW,this.handleNW];
167 for(var i=0;i<_17.length;i++){
168 Event.stopObserving(_17[i],"mousedown",this.startResize.bindAsEventListener(this));
170 if(this.options.captureKeys){
171 Event.stopObserving(document,"keydown",this.handleKeys.bindAsEventListener(this));
180 },handleKeys:function(e){
197 if(dir.x!=0||dir.y!=0){
202 this.moveArea([this.areaCoords.x1+dir.x,this.areaCoords.y1+dir.y]);
207 return (this.areaCoords.x2-this.areaCoords.x1);
209 return (this.areaCoords.y2-this.areaCoords.y1);
210 },moveArea:function(_1b){
211 this.setAreaCoords({x1:_1b[0],y1:_1b[1],x2:_1b[0]+this.calcW(),y2:_1b[1]+this.calcH()},true);
213 },cloneCoords:function(_1c){
214 return {x1:_1c.x1,y1:_1c.y1,x2:_1c.x2,y2:_1c.y2};
215 },setAreaCoords:function(_1d,_1e,_1f,_20,_21){
216 var _22=typeof _1e!="undefined"?_1e:false;
217 var _23=typeof _1f!="undefined"?_1f:false;
219 var _24=_1d.x2-_1d.x1;
220 var _25=_1d.y2-_1d.y1;
229 if(_1d.x2>this.imgW){
231 _1d.x1=this.imgW-_24;
233 if(_1d.y2>this.imgH){
235 _1d.y1=this.imgH-_25;
244 if(_1d.x2>this.imgW){
247 if(_1d.y2>this.imgH){
250 if(typeof (_20)!="undefined"){
252 this.applyRatio(_1d,{x:this.ratioX,y:this.ratioY},_20,_21);
255 this.applyRatio(_1d,{x:1,y:1},_20,_21);
258 var _26={a1:_1d.x1,a2:_1d.x2};
259 var _27={a1:_1d.y1,a2:_1d.y2};
260 var _28=this.options.minWidth;
261 var _29=this.options.minHeight;
262 if((_28==0||_29==0)&&_23){
271 this.applyMinDimension(_26,_28,_20.x,{min:0,max:this.imgW});
272 this.applyMinDimension(_27,_29,_20.y,{min:0,max:this.imgH});
273 _1d={x1:_26.a1,y1:_27.a1,x2:_26.a2,y2:_27.a2};
277 },applyMinDimension:function(_2a,_2b,_2c,_2d){
278 if((_2a.a2-_2a.a1)<_2b){
294 },applyRatio:function(_2e,_2f,_30,_31){
296 if(_31=="N"||_31=="S"){
297 _32=this.applyRatioToAxis({a1:_2e.y1,b1:_2e.x1,a2:_2e.y2,b2:_2e.x2},{a:_2f.y,b:_2f.x},{a:_30.y,b:_30.x},{min:0,max:this.imgW});
303 _32=this.applyRatioToAxis({a1:_2e.x1,b1:_2e.y1,a2:_2e.x2,b2:_2e.y2},{a:_2f.x,b:_2f.y},{a:_30.x,b:_30.y},{min:0,max:this.imgH});
309 },applyRatioToAxis:function(_33,_34,_35,_36){
310 var _37=Object.extend(_33,{});
311 var _38=_37.a2-_37.a1;
312 var _3a=Math.floor(_38*_34.b/_34.a);
332 _3c=Math.floor(_3d*_34.a/_34.b);
336 _37.a1=_37.a1=_37.a2-_3c;
340 },drawArea:function(){
342 Element.show($(this.overlay));
344 var _3e=this.calcW();
345 var _3f=this.calcH();
346 var _40=this.areaCoords.x2;
347 var _41=this.areaCoords.y2;
348 var _42=this.selArea.style;
349 _42.left=this.areaCoords.x1+"px";
350 _42.top=this.areaCoords.y1+"px";
353 var _43=Math.ceil((_3e-6)/2)+"px";
354 var _44=Math.ceil((_3f-6)/2)+"px";
355 this.handleN.style.left=_43;
356 this.handleE.style.top=_44;
357 this.handleS.style.left=_43;
358 this.handleW.style.top=_44;
360 this.north.style.height=this.areaCoords.y1+"px";
361 var _45=this.east.style;
362 _45.top=this.areaCoords.y1+"px";
365 _45.width=(this.img.width-_40)+"px";
366 var _46=this.south.style;
368 _46.height=(this.img.height-_41)+"px";
369 var _47=this.west.style;
370 _47.top=this.areaCoords.y1+"px";
372 _47.width=this.areaCoords.x1+"px";
374 _42.backgroundPosition="-"+this.areaCoords.x1+"px "+"-"+this.areaCoords.y1+"px";
377 this.forceReRender();
378 },forceReRender:function(){
379 if(this.isIE||this.isWebKit){
380 var n=document.createTextNode(" ");
386 fixEl=document.getElementsByClassName("imgCrop_marqueeSouth",this.imgWrap)[0];
387 d=Builder.node("div","");
388 d.style.visibility="hidden";
389 var _4a=["SE","S","SW"];
390 for(i=0;i<_4a.length;i++){
391 el=document.getElementsByClassName("imgCrop_handle"+_4a[i],this.selArea)[0];
392 if(el.childNodes.length){
393 el.removeChild(el.childNodes[0]);
399 fixEl.appendChild(n);
400 fixEl.removeChild(n);
402 },startResize:function(e){
403 this.startCoords=this.cloneCoords(this.areaCoords);
405 this.resizeHandle=Element.classNames(Event.element(e)).toString().replace(/([^N|NE|E|SE|S|SW|W|NW])+/,"");
407 },startDrag:function(e){
408 Element.show(this.selArea);
409 this.clickCoords=this.getCurPos(e);
410 this.setAreaCoords({x1:this.clickCoords.x,y1:this.clickCoords.y,x2:this.clickCoords.x,y2:this.clickCoords.y});
414 },getCurPos:function(e){
415 return curPos={x:Event.pointerX(e)-this.wrapOffsets.left,y:Event.pointerY(e)-this.wrapOffsets.top};
416 },onDrag:function(e){
418 if(this.dragging||this.resizing){
419 var _50=this.getCurPos(e);
420 var _51=this.cloneCoords(this.areaCoords);
424 if(_50.x<this.clickCoords.x){
427 if(_50.y<this.clickCoords.y){
430 this.transformCoords(_50.x,this.clickCoords.x,_51,"x");
431 this.transformCoords(_50.y,this.clickCoords.y,_51,"y");
434 _4f=this.resizeHandle;
436 this.transformCoords(_50.x,this.startCoords.x1,_51,"x");
437 if(_50.x<this.startCoords.x1){
442 this.transformCoords(_50.x,this.startCoords.x2,_51,"x");
443 if(_50.x<this.startCoords.x2){
449 this.transformCoords(_50.y,this.startCoords.y2,_51,"y");
450 if(_50.y<this.startCoords.y2){
455 this.transformCoords(_50.y,this.startCoords.y1,_51,"y");
456 if(_50.y<this.startCoords.y1){
463 if(this.dragging||this.resizing){
464 this.setAreaCoords(_51,false,e.shiftKey,_52,_4f);
468 },transformCoords:function(_53,_54,_55,_56){
484 },endCrop:function(){
487 this.options.onEndCrop(this.areaCoords,{width:this.calcW(),height:this.calcH()});
488 },subInitialize:function(){
489 },subDrawArea:function(){
491 Cropper.ImgWithPreview=Class.create();
492 Object.extend(Object.extend(Cropper.ImgWithPreview.prototype,Cropper.Img.prototype),{subInitialize:function(){
493 this.hasPreviewImg=false;
494 if(typeof (this.options.previewWrap)!="undefined"&&this.options.minWidth>0&&this.options.minHeight>0){
495 this.previewWrap=$(this.options.previewWrap);
496 this.previewImg=this.img.cloneNode(false);
497 this.options.displayOnInit=true;
498 this.hasPreviewImg=true;
499 Element.addClassName(this.previewWrap,"imgCrop_previewWrap");
500 Element.setStyle(this.previewWrap,{width:this.options.minWidth+"px",height:this.options.minHeight+"px"});
501 this.previewWrap.appendChild(this.previewImg);
503 },subDrawArea:function(){
504 if(this.hasPreviewImg){
505 var _58=this.calcW();
506 var _59=this.calcH();
507 var _5a={x:this.imgW/_58,y:this.imgH/_59};
508 var _5b={x:_58/this.options.minWidth,y:_59/this.options.minHeight};
509 var _5c={w:Math.ceil(this.options.minWidth*_5a.x)+"px",h:Math.ceil(this.options.minHeight*_5a.y)+"px",x:"-"+Math.ceil(this.areaCoords.x1/_5b.x)+"px",y:"-"+Math.ceil(this.areaCoords.y1/_5b.y)+"px"};
510 var _5d=this.previewImg.style;