1/** 2 * Available for use under the MIT License (http://en.wikipedia.org/wiki/MIT_License) 3 * 4 * Copyright (c) 2014 - 2015 by Adam Banaszkiewicz 5 * 6 * Permission is hereby granted, free of charge, to any person obtaining a copy 7 * of this software and associated documentation files (the "Software"), to deal 8 * in the Software without restriction, including without limitation the rights 9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 * copies of the Software, and to permit persons to whom the Software is 11 * furnished to do so, subject to the following conditions: 12 * 13 * The above copyright notice and this permission notice shall be included in 14 * all copies or substantial portions of the Software. 15 * 16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 * THE SOFTWARE. 23 * 24 * @version 0.3.1 25 * @date 2015.12.14 26 * @author Adam Banaszkiewicz 27 */ 28(function($){ 29 /** 30 * Zwraca obiekt z szerokoÅciÄ strony. 31 * 32 * @result object 33 */ 34 document.getWindowWidth = function() { 35 if( typeof( window.innerWidth ) == 'number' ) 36 { 37 return window.innerWidth; 38 } 39 else if(document.documentElement && (document.documentElement.clientWidth || document.documentElement.clientHeight)) 40 { 41 return document.documentElement.clientWidth; 42 } 43 else if(document.body && (document.body.clientWidth || document.body.clientHeight)) 44 { 45 return document.body.clientWidth; 46 } 47 48 return 1280; 49 }; 50 51 $.fn.cropimg = function(options) { 52 options = $.extend({ 53 /** 54 * Maksymalna szerokoÅÄ kontenera z narzÄdziami. Null oznacza 100%. 55 * 56 * @var integer 57 * @var null 58 */ 59 maxContainerWidth: null, 60 61 /** 62 * SzerokoÅÄ obrazka po kadrowaniu. 63 * 64 * @var integer 65 */ 66 resultWidth: 100, 67 68 /** 69 * WysokoÅÄ obrazka po kadrowaniu. 70 * 71 * @var integer 72 */ 73 resultHeight: 100, 74 75 /** 76 * Przedrostek ID elementów INPUT do których wrzucane bÄdÄ dane na temat 77 * pozycji obrazka oraz zaznaczonej jego czÄÅci. 78 * 79 * @var string 80 */ 81 inputPrefix: '', 82 83 /** 84 * Opóźnienie w czasie, pomiÄdzy jednorazowym zoomem, a zoomem 85 * wielokrotnym. WartoÅc podawana w milisekundach. 86 * 87 * @var integer 88 */ 89 zoomDelay: 400, 90 91 /** 92 * krotnoÅÄ przybliżenia dla kóÅka myszki. 93 * 94 * @var integer 95 */ 96 mouseWheelZoomTimes: 10, 97 98 /** 99 * O jakÄ czÄÅÄ caÅoÅci ma odbywaÄ siÄ zoomowanie. 100 * 101 * @type integer 102 */ 103 zoomStep: 25, 104 105 /** 106 * Czy pokazywaÄ tooltipy na buttonach? 107 * 108 * @var boolean 109 */ 110 showBtnTips: true, 111 112 /** 113 * Display zooming buttons? 114 * 115 * @var boolean 116 */ 117 displayZoomingButtons: true, 118 119 /** 120 * Display fixing positions buttons? 121 * 122 * @var boolean 123 */ 124 displayFixingPositionsButtons: true, 125 126 /** 127 * Display fixing size buttons? 128 * 129 * @var boolean 130 */ 131 displayFixingSizeButtons: true, 132 133 /** 134 * Czas animacji pokazywania i ukrywania tooltipów. 135 * 136 * @var integer 137 */ 138 btnTipsFadeTime: 100, 139 140 /** 141 * TreÅÄ tooltipa przycisku: przybliż. 142 * 143 * @var string 144 */ 145 textBtnTipZoomIn: 'Zoom in', 146 147 /** 148 * TreÅÄ tooltipa przycisku: oddal. 149 * 150 * @var string 151 */ 152 textBtnTipZoomOut: 'Zoom out', 153 154 /** 155 * TreÅÄ tooltipa przycisku: dopasuj do szerokoÅci. 156 * 157 * @var string 158 */ 159 textBtnTipRTW: 'Resize to container width', 160 161 /** 162 * TreÅÄ tooltipa przycisku: dopasuj do wydokoÅci. 163 * 164 * @var string 165 */ 166 textBtnTipRTH: 'Resize to container height', 167 168 /** 169 * TreÅÄ tooltipa przycisku: przenieÅ w lewy górny róg. 170 * 171 * @var string 172 */ 173 textBtnTipFPTL: 'Move image to Top Left Corner', 174 175 /** 176 * TreÅÄ tooltipa przycisku: przenieÅ w górÄ na Årodek. 177 * 178 * @var string 179 */ 180 textBtnTipFPTC: 'Move image to Top Center', 181 182 /** 183 * TreÅÄ tooltipa przycisku: przenieÅ w prawy górny róg. 184 * 185 * @var string 186 */ 187 textBtnTipFPTR: 'Move image to Top Right Corner', 188 189 /** 190 * TreÅÄ tooltipa przycisku: przenieÅ w lewo na Årodek. 191 * 192 * @var string 193 */ 194 textBtnTipFPCL: 'Move image to Center Left', 195 196 /** 197 * TreÅÄ tooltipa przycisku: przenieÅ na sam Årodek kontenera. 198 * 199 * @var string 200 */ 201 textBtnTipFPCC: 'Move image to Center of container', 202 203 /** 204 * TreÅÄ tooltipa przycisku: przenieÅ w prawo na Årodek. 205 * 206 * @var string 207 */ 208 textBtnTipFPCR: 'Move image to Center Right', 209 210 /** 211 * TreÅÄ tooltipa przycisku: przenieÅ w dolny lewy róg. 212 * 213 * @var string 214 */ 215 textBtnTipFPBL: 'Move image to Bottom Left Corner', 216 217 /** 218 * TreÅÄ tooltipa przycisku: przenieÅ w dolny róg na Årodek. 219 * 220 * @var string 221 */ 222 textBtnTipFPBC: 'Move image to Bottom Center', 223 224 /** 225 * TreÅÄ tooltipa przycisku: przenieÅ w dolny prawy róg. 226 * 227 * @var string 228 */ 229 textBtnTipFPBR: 'Move image to Bottom Right Corner', 230 231 /** 232 * WywoÅywana podczas inicjacji pluginu. 233 * 234 * @var function 235 */ 236 onInit: function() {}, 237 238 /** 239 * WywoÅywana podczas zmiany zoomu, lub pozycji obrazka. 240 * 241 * @var function 242 */ 243 onChange: function(w, h, x, y, img) {} 244 }, options); 245 246 var CI_Main = function(image, options) { 247 this.options = options; 248 249 /**
250 * Przechowuje informacje, czy obrazek zostaÅ już zmieniony, czy jeszcze 251 * nic user nie robiÅ. 252 * 253 * @var boolean 254 */ 255 this.changed = false; 256 257 /** 258 * Obiekt jQuery z obrazkiem. 259 * 260 * @var jQuery 261 */ 262 this.image = image; 263 264 /** 265 * Obiekt z danymi na temat obrazka. 266 * 267 * @var jQuery 268 */ 269 this.imageData = {}; 270 271 /** 272 * Obiekt jQuery z gÅównym kontenerem w którym znajduje siÄ caÅy plugin. 273 * 274 * @var jQuery 275 */ 276 this.container = null; 277 278 /** 279 * Obiekt jQuery z kontenerem obrazka. 280 * 281 * @var jQuery 282 */ 283 this.imageContainer = null; 284 285 /** 286 * Obiekt z danymi na temat kontenera obrazka. 287 * 288 * @var jQuery 289 */ 290 this.imgCntData = {width: -1}; 291 292 /** 293 * Przechowuje czas w mikrosekundach wywoÅania pluginu. Potrzebne do 294 * nadawania ID elementom. 295 * 296 * @var integer 297 */ 298 this.mt = (new Date()).getTime() + Math.floor((Math.random() * 1000) + 1); 299 300 this.vars = { 301 x: 0, 302 y: 0, 303 w: 0, 304 h: 0 305 }; 306 307 this.ToolDrawer = null; 308 this.BtnTips = null; 309 this.Movable = null; 310 this.Zooming = null; 311 this.CroppingResult = null; 312 this.Reset = null; 313 }; 314 315 /** 316 * Obiekt z metodami do rysowania narzÄdzi pluginu. 317 */ 318 var CI_TOOLDRAWER = function(main) { 319 this.main = main; 320 321 /** 322 * DomyÅlna metoda obiektu. 323 */ 324 this.draw = function() { 325 this.drawContainers(); 326 327 if (this.main.options.displayZoomingButtons) { 328 this.drawZoomingButtons(); 329 } 330 331 if (this.main.options.displayFixingPositionsButtons) { 332 this.drawFixingPositionButtons(); 333 } 334 335 if (this.main.options.displayFixingSizeButtons) { 336 this.drawFixingSizeButtons(); 337 } 338 339 var self = this; 340 341 $(window).resize(function(e) { 342 self.onResize(self, e); 343 }); 344 }; 345 346 /** 347 * Rysuje kontenery (DIV) i te ważniejsze przypisuje do zmiennych. 348 * 349 * @return void 350 */ 351 this.drawContainers = function() { 352 // Tworzymy gÅówny kontener na aplikacjÄ 353 this.main.image.wrap($('<div />', {'class':'ci-main','id':'ci-main-'+this.main.mt,'style':'max-width:'+this.main.options.resultWidth+'px'})); 354 this.main.container = $('.ci-main#ci-main-'+this.main.mt); 355 356 // Tworzymy kontener bezpoÅrednio na zdjÄcie 357 this.main.image.wrap($('<div />', {'class':'ci-image-wrapper','id':'ci-image-wrapper-'+this.main.mt,'style':'max-width:'+this.main.options.resultWidth+'px;height:'+this.main.options.resultHeight+'px'})); 358 this.main.imageContainer = $('.ci-image-wrapper#ci-image-wrapper-'+this.main.mt); 359 360 // Kontener na "przybliż - oddal" 361 this.main.container.append($('<div />', {'class':'ci-tool ci-zooming'})); 362 }; 363 364 /** 365 * Tworzy buttony "przybliż - oddal". 366 * 367 * @return void 368 */ 369 this.drawZoomingButtons = function() { 370 this.main.container.find('.ci-tool.ci-zooming') 371 .append($('<span />', {'title':this.main.options.textBtnTipZoomIn,'href':'#','class':'ci-button ci-tool-zoomin'}).click(function(){return false;})) 372 .append($('<span />', {'title':this.main.options.textBtnTipZoomOut,'href':'#','class':'ci-button ci-tool-zoomout'}).click(function(){return false;})); 373 }, 374 375 /** 376 * Rysuje buttony przesuwania zdjÄcia do krawÄdzi i rogów kontenera. 377 * 378 * @return void 379 */ 380 this.drawFixingPositionButtons = function() { 381 this.main.imageContainer 382 .append($('<span />', {'title':this.main.options.textBtnTipFPTL,'href':'#','class':'ci-fixing-position ci-fptl'}).click(function(){return false;})) 383 .append($('<span />', {'title':this.main.options.textBtnTipFPTC,'href':'#','class':'ci-fixing-position ci-fptc'}).click(function(){return false;})) 384 .append($('<span />', {'title':this.main.options.textBtnTipFPTR,'href':'#','class':'ci-fixing-position ci-fptr'}).click(function(){return false;})) 385 .append($('<span />', {'title':this.main.options.textBtnTipFPCL,'href':'#','class':'ci-fixing-position ci-fpcl'}).click(function(){return false;})) 386 .append($('<span />', {'title':this.main.options.textBtnTipFPCC,'href':'#','class':'ci-fixing-position ci-fpcc'}).click(function(){return false;})) 387 .append($('<span />', {'title':this.main.options.textBtnTipFPCR,'href':'#','class':'ci-fixing-position ci-fpcr'}).click(function(){return false;})) 388 .append($('<span />', {'title':this.main.options.textBtnTipFPBL,'href':'#','class':'ci-fixing-position ci-fpbl'}).click(function(){return false;})) 389 .append($('<span />', {'title':this.main.options.textBtnTipFPBC,'href':'#','class':'ci-fixing-position ci-fpbc'}).click(function(){return false;})) 390 .append($('<span />', {'title':this.main.options.textBtnTipFPBR,'href':'#','class':'ci-fixing-position ci-fpbr'}).click(function(){return false;})); 391 }, 392 393 /** 394 * Rysuje buttony zmiany rozmiarów zdjÄcia wzglÄdem kontenera. 395 * 396 * @return void 397 */ 398 this.drawFixingSizeButtons = function() { 399 this.main.container.find('.ci-tool.ci-zooming') 400 .append($('<span />', {'title':this.main.options.textBtnTipRTW,'href':'#','class':'ci-fixing-size ci-fsw'}).click(function(){return false;})) 401 .append($('<span />', {'title':this.main.options.textBtnTipRTH,'href':'#','class':'ci-fixing-size ci-fsh'}).click(function(){return false;})); 402 }, 403 404 /** 405 * Rysuje buttony zmiany rozmiarów zdjÄcia wzglÄdem kontenera. 406 * 407 * @return void 408 */ 409 this.drawFixingSizeButtons = function() { 410 this.main.container.find('.ci-tool.ci-zooming') 411 .append($('<span />', {'title':this.main.options.textBtnTipRTW,'href':'#','class':'ci-fixing-size ci-fsw'}).click(function(){return false;})) 412 .append($('<span />', {'title':this.main.options.textBtnTipRTH,'href':'#','class':'ci-fixing-size ci-fsh'}).click(function(){return false;})); 413 }, 414 415 this.onResize = function(self, e) { 416 /** 417 * JeÅli szerokoÅÄ kontenera zdjÄcia jest mniejsza niż szerokoÅÄ 418 * domyÅlna zaznaczenia to zmniejszamy wysokoÅÄ proporcjonalnie 419 * do zmniejszonej szerokoÅci by zachowaÄ proporcje. 420 */ 421 if(self.main.imageContainer.width() < self.main.options.resultWidth) 422 { 423 self.main.imgCntData.proportionsToOriginal = self.main.imageContainer.width() / self.main.options.resultWidth; 424 self.main.imageContainer.css('height', (self.main.options.resultHeight * self.main.imgCntData.proportionsToOriginal)+'px'); 425 426 // Uaktualniamy dane na temat kontenera obrazka 427 self.main.imgCntData.width = self.main.imageContainer.width(); 428 self.main.imgCntData.height = self.main.imageContainer.height(); 429 430 // Uaktualniamy dane na temat zaznaczonego obszaru zdjÄcia 431 self.main.CroppingResult.cropPercent = self.main.imgCntData.proportionsToOriginal; 432 } 433 /** 434 * W każdym innym wypadku ustawiamy wysokoÅÄ kontenera na domyÅlnÄ 435 * wysokoÅÄ kadrowanego obrazu oraz ustawiamy proporcje kontenera 436 * na 1 - czyli nieprzeskalowane (oryginaÅ). 437 */ 438 else 439 { 440 self.main.imageContainer.css('height', self.main.options.resultHeight); 441 442 // Uaktualniamy dane na temat kontenera obrazka 443 self.main.imgCntData.width = self.main.imageContainer.width(); 444 self.main.imgCntData.height = self.main.options.resultHeight; 445 self.main.imgCntData.proportionsToOriginal = 1; 446 } 447 448 // OdÅwieżamy wartoÅci 449 if(self.main.changed) 450 { 451 self.main.Zooming.eventMouseUp(); 452 } 453 } 454 }; 455 456 457 /** 458 * Obiekt z metodami do zarzÄ dzania tooltipami przycisków. 459 */ 460 var CI_BTNSTIPS = function(main) { 461 this.main = main; 462 463 /** 464 * Przechowuje ID tooltipu, który aktualnie jest dodawany do BODY. 465 * 466 * @var string 467 */ 468 this.currentTipId = ''; 469 470 /** 471 * Przechowuje ID tooltipu, który aktualnie jest już BODY, który można usunÄ Ä. 472 * 473 * @var string 474 */ 475 this.lastTipId = ''; 476 477 /** 478 * Inicjacja tooltipów 479 * 480 * @return void 481 */ 482 this.init = function() { 483 var self = this; 484 485 // Tylko, jeÅli tak wybrano. 486 if(this.main.options.showBtnTips == false) 487 { 488 return false;
489 } 490 491 /** 492 * Szukamy wszystkie elementy, które posiadajÄ atrybut title. TreÅÄ 493 * z TITLE wrzucamy do DATA-TXT i usuwamy TITLE a nastÄpnie 494 * podpinamy zdarzenia na hover. 495 */ 496 $('[title]', this.main.container).add($('[title]', this.main.imageContainer)).each(function() { 497 $(this).attr('data-txt', $(this).attr('title')) 498 .removeAttr('title') 499 .hover(function() { 500 self.main.BtnTips.show(self, this); 501 }, function() { 502 self.main.BtnTips.hide(self, this); 503 }); 504 }); 505 }, 506 507 /** 508 * Pokazuje tooltip. Podpinane na zdarzenie elementu mouseenter. 509 * 510 * @return void 511 */ 512 this.show = function(self, elm) { 513 // Tworzymy nowe ID tooltipu 514 self.currentTipId = 'ci-tip-'+(new Date()).getTime(); 515 516 // Dodajemy Tooltip do body 517 $('body').append($('<span class="ci-tip" id="'+self.currentTipId+'">'+$(elm).attr('data-txt')+'</span>').fadeTo(0, 0).fadeTo(self.main.options.btnTipsFadeTime, 1)); 518 519 // Pobieramy offset elementu, do którego należy tooltip 520 var elmOffset = $(elm).offset(), 521 // Pobieramy przed chwilÄ dodany do BODY tooltip 522 tip = $('body').find('.ci-tip#'+self.currentTipId); 523 524 // Obliczamy pozycjÄ nowego toltipa 525 tip.css({ 526 'left': elmOffset.left - (tip.outerWidth() / 2) + ($(elm).outerWidth() / 2), 527 'top' : elmOffset.top - (tip.outerHeight()) - (($(elm).outerHeight() - 5) / 2) 528 }); 529 530 // Przepisujemy ID tooltipa z Aktualy na Ostatni 531 self.lastTipId = self.currentTipId; 532 }, 533 534 /** 535 * Ukrywa a nastÄpnie usuwa tooltip. Dodatkowe zdarzenie pozwala 536 * ukryÄ element od razu, po najechaniu na niego, a nie czekaÄ aż ukryje 537 * siÄ on animacjÄ fade. Podpinane na zdarzenie elementu mouseout. 538 * 539 * @return void 540 */ 541 this.hide = function() { 542 $('body').find('.ci-tip#'+this.lastTipId).hover(function() {$(this).remove();}, $.noop).fadeTo(this.main.options.btnTipsFadeTime, 0, function() { 543 $(this).remove(); 544 }); 545 } 546 }; 547 548 549 var CI_MOVABLE = function(main) { 550 this.main = main; 551 552 /** 553 * Przechowuje obiekt z wartoÅciami pozycji myszki na której byÅ kursor, 554 * podczas rozpoczÄcia przesuwania obrazka. 555 * 556 * @var object 557 */ 558 this.mousePositionStart = { 559 x:0, 560 y:0 561 }; 562 563 this.imagePosition = { 564 'left':0, 565 'top':0 566 }; 567 568 /** 569 * Przechowuje informacje dla metod Eventów o tym, 570 * czy przycisk myszki jest wciÅniÄty - mousedown. 571 */ 572 this.mouseDowned = false; 573 574 /** 575 * Metoda inicjujÄ ca. 576 */ 577 this.init = function() { 578 var self = this; 579 580 /** 581 * Po klikniÄciu na kontener obrazka rozpoczynamy przesuwanie zdjÄcia. 582 */ 583 this.main.imageContainer.bind('mousedown', function(e) { 584 self.eventMouseDown(self, e); 585 }); 586 587 this.main.imageContainer.bind('touchstart', function(e) { 588 self.eventMouseDown(self, e); 589 }); 590 591 $('body') 592 /** 593 * Podczas jeżdżenia po BODY przesuwamy obrazek wzglÄdem pozycji myszki. 594 */ 595 .bind('mousemove', function(e) { 596 self.eventMouseMove(self, e); 597 }) 598 .bind('touchmove', function(e) { 599 self.eventMouseMove(self, e); 600 }) 601 /** 602 * Po puszczeniu przycisku myszki koÅczymy przesuwanie. 603 */ 604 .bind('mouseup', function(e) { 605 self.eventMouseUp(self, e); 606 }) 607 .bind('touchend', function(e) { 608 self.eventMouseUp(self, e); 609 }); 610 611 /** 612 * DziÄki temu, po klikniÄciu na obrazek i próbie "przeniesienia go" 613 * nie wykona siÄ domyÅlna reakcja przeglÄ darki. 614 */ 615 var _sp = function(e) { 616 e.preventDefault(); 617 }; 618 619 this.main.imageContainer.find('img') 620 .bind('mousemove', _sp) 621 .bind('mouseup', _sp) 622 .bind('mousedown', _sp); 623 624 this.bindFixingButtons(); 625 }, 626 627 /** 628 * Metoda eventu onmousedown. Zapisuje pozycjÄ myszki oraz obrazka 629 * by można byÅo obliczyÄ nowÄ pozycjÄ podczas przenosin. Podpina 630 * zdarzenia przenoszenia dla BODY. 631 * 632 * @event onmousedown 633 * @param object e 634 * @return void 635 */ 636 this.eventMouseDown = function(self, e) { 637 if(self.mouseDowned === false || e.type == 'touchstart') 638 { 639 // Zapisujemy pozycjÄ myszki 640 641 if (e.type == 'touchstart') 642 { 643 self.mousePositionStart.x = e.originalEvent.touches[0].pageX; 644 self.mousePositionStart.y = e.originalEvent.touches[0].pageY; 645 } 646 else 647 { 648 self.mousePositionStart.x = e.pageX; 649 self.mousePositionStart.y = e.pageY; 650 } 651 652 // Potrzebujemy te dane o obrazku by móc dobrze go przesunÄ Ä z tych wartoÅci poczÄ tkowych 653 self.imagePosition.left = parseInt(self.main.image.css('left').replace('px', '')); 654 self.imagePosition.top = parseInt(self.main.image.css('top').replace('px', '')); 655 656 // Ustawiamy, że już byÅo zmieniane 657 self.main.changed = true; 658 659 self.mouseDowned = true; 660 } 661 }, 662 663 /** 664 * Metoda eventu onmouseup. Zdejmuje zdarzenia przenosin z BODY. 665 * 666 * @event onmouseup 667 * @return void 668 */ 669 this.eventMouseUp = function(self, e) { 670 if(self.mouseDowned === true || e.type == 'touchend') 671 { 672 self.mouseDowned = false;
673 674 /** 675 * Uaktualniamy pozycjÄ obrazka. Robimy to tutaj a nie w funkcji 676 * przesuwania ponieważ tam zabieraÅaby niepotrzebnie moc obliczeniowÄ 677 * przeglÄ darki wrzucajÄ c co jeden piksel dane do inputów a tak 678 * oblicza pozycjÄ tylko raz i tylko raz wrzuca jÄ do inputów. 679 */ 680 self.main.CroppingResult.update(parseInt(self.main.image.css('left').replace('px', '')), parseInt(self.main.image.css('top').replace('px', ''))); 681 682 /** 683 * Może zdarzyÄ siÄ tak, że użytkownik tylko kliknie w przeniesienie 684 * obrazka do którejÅ z krawÄdzi. W ten sposób (jeÅli nie ma) dodadzÄ 685 * siÄ pozycje X i Y obrazka lub uaktualniÄ , ale nic nie stanie siÄ 686 * z wartoÅciami W i H obrazka - wiÄc jeÅli ich tam nie byÅo, to po 687 * uaktualnieniu ich nadal nie bÄdzie (lub bÄdzie 0 i 0), dla tego 688 * musimy tutaj sztucznie wymusiÄ ustawienie wartoÅci W i H obrazka. 689 */ 690 self.main.Zooming.eventMouseUp(); 691 } 692 }, 693 694 /** 695 * Metoda eventu onmousemove. Za pomocÄ metody pomocniczej oblicza 696 * pozycjÄ obrazka i przesuwa go. 697 * 698 * @event onmousemove 699 * @param object e 700 * @return void 701 */ 702 this.eventMouseMove = function(self, e) { 703 if(self.mouseDowned === true || e.type == 'touchmove') 704 { 705 // Ustawiamy, że już byÅo zmieniane 706 self.main.changed = true; 707 708 // Obliczamy nowe pozycje i przesuwamy obrazek. 709 if (e.type == 'touchmove') 710 { 711 self.main.image.css(self.calculatePosition(e.originalEvent.touches[0].pageX, e.originalEvent.touches[0].pageY)); 712 } 713 else 714 { 715 self.main.image.css(self.calculatePosition(e.pageX, e.pageY)); 716 } 717 } 718 }, 719 720 /** 721 * Podpina funkcje pod przyciski w kontenerze zdjÄcia odpowiedzialne 722 * za przesuniÄcie zdjÄcia do danej krawÄdzi lub rogu kontenera. 723 * 724 * @return void 725 */ 726 this.bindFixingButtons = function() { 727 var self = this; 728 729 // Top left 730 this.main.imageContainer.find('.ci-fixing-position.ci-fptl').mou
730seup(function() { 731 self.main.image.css({'top':'0px','left':'0px'}); 732 self.main.vars.x = 0; 733 self.main.vars.y = 0; 734 self.main.CroppingResult.update(0, 0); 735 736 }); 737 738 // Top center 739 this.main.imageContainer.find('.ci-fixing-position.ci-fptc').mouseup(function() { 740 var left = -((self.main.imageData.width / 2) - (self.main.imgCntData.width / 2)); 741 self.main.image.css({'top':'0px','left':left+'px'}); 742 self.main.vars.x = 0; 743 self.main.vars.y = left; 744 self.main.CroppingResult.update(left, 0); 745 746 }); 747 748 // Top right 749 this.main.imageContainer.find('.ci-fixing-position.ci-fptr').mouseup(function() { 750 var left = -(self.main.imageData.width - self.main.imgCntData.width); 751 self.main.image.css({'top':'0px','left':left+'px'}); 752 self.main.vars.x = 0; 753 self.main.vars.y = left; 754 self.main.CroppingResult.update(left, 0); 755 756 }); 757 758 // Center left 759 this.main.imageContainer.find('.ci-fixing-position.ci-fpcl').mouseup(function() { 760 var top = -((self.main.imageData.height / 2) - (self.main.imgCntData.height / 2)); 761 self.main.image.css({'top':top+'px','left':'0px'}); 762 self.main.vars.x = 0; 763 self.main.vars.y = top; 764 self.main.CroppingResult.update(0, top); 765 766 }); 767 768 // Center center 769 this.main.imageContainer.find('.ci-fixing-position.ci-fpcc').mouseup(function() { 770 var top = -((self.main.imageData.height / 2) - (self.main.imgCntData.height / 2)); 771 var left = -((self.main.imageData.width / 2) - (self.main.imgCntData.width / 2)); 772 self.main.image.css({'top':top+'px','left':left+'px'}); 773 self.main.vars.x = left; 774 self.main.vars.y = top; 775 self.main.CroppingResult.update(left, top); 776 777 }); 778 779 // Center right 780 this.main.imageContainer.find('.ci-fixing-position.ci-fpcr').mouseup(function() { 781 var top = -((self.main.imageData.height / 2) - (self.main.imgCntData.height / 2)); 782 var left = -(self.main.imageData.width - self.main.imgCntData.width); 783 self.main.image.css({'top':top+'px','left':left+'px'}); 784 self.main.vars.x = left; 785 self.main.vars.y = top; 786 self.main.CroppingResult.update(left, top); 787 788 }); 789 790 // Bottom left 791 this.main.imageContainer.find('.ci-fixing-position.ci-fpbl').mouseup(function() { 792 var top = -(self.main.imageData.height - self.main.imgCntData.height); 793 self.main.image.css({'top':top+'px','left':'0px'}); 794 self.main.vars.x = 0; 795 self.main.vars.y = top; 796 self.main.CroppingResult.update(0, top); 797 798 }); 799 800 // Bottom center 801 this.main.imageContainer.find('.ci-fixing-position.ci-fpbc').mouseup(function() { 802 var top = -(self.main.imageData.height - self.main.imgCntData.height); 803 var left = -((self.main.imageData.width / 2) - (self.main.imgCntData.width / 2)); 804 self.main.image.css({'top':top+'px','left':left+'px'}); 805 self.main.vars.x = left; 806 self.main.vars.y = top; 807 self.main.CroppingResult.update(left, top); 808 809 }); 810 811 // Bottom right 812 this.main.imageContainer.find('.ci-fixing-position.ci-fpbr').mouseup(function() { 813 var top = -(self.main.imageData.height - self.main.imgCntData.height); 814 var left = -(self.main.imageData.width - self.main.imgCntData.width); 815 self.main.image.css({'top':top+'px','left':left+'px'}); 816 self.main.vars.x = left; 817 self.main.vars.y = top; 818 self.main.CroppingResult.update(left, top); 819 820 }); 821 }, 822 823 /** 824 * Metoda oblicza pozycjÄ obrazka wzglÄdem pozycji kursora oraz 825 * domyÅlnej pozycji obrazka tuż przed przenoszeniem i zwraca obiekt 826 * z obliczonymi nowymi wspóÅrzÄdnymi obrazka. 827 * 828 * @param integer pageX WartoÅÄ obiektu event.pageX 829 * @param integer pageY WartoÅÄ obiektu event.pageY 830 * 831 * @return object 832 */ 833 this.calculatePosition = function(pageX, pageY) { 834 return {'top':pageY - this.mousePositionStart.y + this.imagePosition.top,'left':pageX - this.mousePositionStart.x + this.imagePosition.left}; 835 } 836 }; 837 838 839 /** 840 * Obiekt odpowiedzialny za "przybliż - oddal". 841 */ 842 var CI_ZOOMING = function(main) { 843 this.main = main; 844 845 /** 846 * Przechowuje obiekt interwaÅu zoomowania. 847 * 848 * @var object 849 */ 850 this.interval = null; 851 852 /** 853 * Czas, który pozostaÅ, do rozpoczÄcia zoomu w petli. 854 * 855 * @var integer 856 */ 857 this.timesLeftToZoom = 10; 858 859 /** 860 * Przechowuje informacje na temat tego, czy można zastopowaÄ 861 * zoomowanie podczas zdarzenia mouseup na body. 862 * 863 * @var boolean 864 */ 865 this.canStopZoom = false;
866 867 /** 868 * Przechowuje funkcjÄ callable z wywoÅaniem funkcji zoom z parametrem 869 * okreÅlajÄ cym czy ma przybliżaÄ czy oddalaÄ. 870 * 871 * @var function 872 */ 873 this.zoomFunction = function() {}; 874 875 /** 876 * Inicjator. 877 */ 878 this.init = function() { 879 var self = this; 880 881 this.timesLeftToZoom = this.main.options.zoomDelay; 882 883 // Podpinamy zoom dla przycisków 884 this.main.container 885 .find('.ci-tool.ci-zooming .ci-button') 886 .mousedown(function() { 887 self.canStopZoom = true; 888 self.eventMouseDown($(this).hasClass('ci-tool-zoomin') ? 'in' : 'out'); 889 }) 890 .mouseup(function(e) { 891 self.eventMouseUp(); 892 self.canStopZoom = false; 893 e.stopPropagation(); 894 }) 895 .click(function() { 896 self.canStopZoom = false; 897 self.eventMouseClick($(this).hasClass('ci-tool-zoomin') ? 'in' : 'out'); 898 }); 899 900 // Reset zoom 901 $('body').mouseup(function() { 902 if(self.canStopZoom) 903 self.stopZoom(); 904 }); 905 906 /** 907 * Musimy pobraÄ wymiary obrazka, ale nie uda nam siÄ to przed jego 908 * zaÅadowaniem, dlatego tworzymy jeszcze jeden obrazek w kontenerze, 909 * podpinamy pod niego zdarzenie, by po wywoÅaniu pobraÅo wymiary, 910 * i Åadujemy go do kontenera. Po zaÅadowaniu usuwamy z kontenera, 911 * by nie pozostawiÄ Åladów. 912 */ 913 var loader = document.createElement('IMG'); 914 loader.className = 'ci-image-loader'; 915 loader.onload = function() { 916 // Dane obrazka 917 self.main.imageData = { 918 // Oryginalne wymiary obrazka 919 originalWidth: self.main.image.width(), 920 originalHeight: self.main.image.height(), 921 // Aktualne wymiary obrazka 922 width: self.main.image.width(), 923 height: self.main.image.height(), 924 // Poporcje wymiarów obrazka wzglÄdem oryginalnych 925 proportions: 1 926 }; 927 928 $('.ci-image-loader', self.main.imageContainer).remove(); 929 self.main.options.onInit(); 930 }; 931 loader.src = this.main.image.attr('src'); 932 933 this.bindFixingButtons(); 934 935 /** 936 * JeÅli jest skrypt mousewheel to podpinamy zoomowanie za pomocÄ 937 * kóÅka myszki. 938 */ 939 if(typeof this.main.container.mousewheel == 'function') 940 { 941 this.main.container.mousewheel(function(e) { 942 var type = e.deltaY == 1 ? 'in' : 'out'; 943 944 self.zoom(type); 945 946 self.eventMouseUp(); 947 948 e.stopPropagation(); 949 e.preventDefault(); 950 return false; 951 }); 952 } 953 }, 954 955 /** 956 * Metoda przygotowuje metodÄ zoomowania w zależnoÅci od podanej wartoÅci 957 * w parametrze type. 958 * 959 * @param string type 960 * @return void 961 */ 962 this.prepareToZoom = function(type) { 963 // Ustawiamy, że już byÅo zmieniane 964 this.main.changed = true; 965 966 // Ustawiamy, że w interwale może byÄ wykonywana funkcja zoomowania 967 this.allowedZoomingFromInterval = true; 968 969 // Ustawiamy funkcjÄ wywoÅujÄ cÄ funkcjÄ zoomowania w zależnoÅci od typu 970 this.zoomFunction = function() {this.zoom(type);}; 971 }, 972 973 /** 974 * Metoda rozpoczyna zmianÄ rozmiaru w zależnoÅci od podanego typu. 975 * Typ 'in' oznacza przybliżenie; Typ 'out' oznacza oddalenie. Najpierw 976 * wykonuje raz funkcjÄ zoomowania, a nastepnie ustawia interval tak, by 977 * po wciÅniÄciu i przytrzymaniu klawisza myszki można byÅo zoomowaÄ 978 * caÅy czas bez kolejnych wciÅniÄÄ. 979 * 980 * @param string type 981 * @return false 982 */ 983 this.eventMouseDown = function(type) { 984 var self = this; 985 986 // Przygotowujemy metodÄ do zoomowania 987 this.prepareToZoom(type); 988 989 // Ustawiamy odliczanie na zoomowanie ciÄ gÅe 990 this.interval = setInterval(function() { 991 self.timesLeftToZoom = self.timesLeftToZoom - 10; 992 993 if(self.timesLeftToZoom <= 0) 994 self.zoomFunction(); 995 }, 10); 996 997 return false;
998 }, 999 1000 /** 1001 * Zatrzymanie zmiany rozmiaru. 1002 * 1003 * @return void 1004 */ 1005 this.eventMouseUp = function() { 1006 this.main.CroppingResult.update( 1007 undefined, 1008 undefined, 1009 this.main.options.resultWidth * parseFloat(this.main.CroppingResult.cropPercent), 1010 this.main.options.resultHeight * parseFloat(this.main.CroppingResult.cropPercent), 1011 true 1012 ); 1013 1014 this.stopZoom(); 1015 }, 1016 1017 /** 1018 * Zdarzenie pojedyÅczego klikniÄcia w przycisk. JeÅli tylko kliknie 1019 * zoomujemy o jeden stopieÅ. 1020 * 1021 * @param string type 1022 * @return void 1023 */ 1024 this.eventMouseClick = function(type) { 1025 // Zatrzymujemy to co byÅo do tej pory 1026 this.stopZoom(); 1027 // Przygotowujemy metodÄ do zoomowania 1028 this.prepareToZoom(type); 1029 // Wykonujemy jeden raz funkcjÄ zoomowania 1030 this.zoomFunction(); 1031 }, 1032 1033 /** 1034 * Metoda resetuje i stopuje ZOOM. 1035 * 1036 * @return void 1037 */ 1038 this.stopZoom = function() { 1039 this.timesLeftToZoom = this.main.options.zoomDelay; 1040 1041 clearInterval(this.interval); 1042 }, 1043 1044 /** 1045 * GÅówna metoda odpowiedzialna za zoomowanie obrazka. Parametr type='in' oznacza 1046 * przybliżenie, parametr type='out' oznacza oddalenie. 1047 * 1048 * @param string type 'in' lub 'out' 1049 * @return void 1050 */ 1051 this.zoom = function(type) { 1052 // Zmieniamy wielkoÅÄ procent w zależnoÅci od tego, czy przybliżamy czy oddalamy 1053 if(type == 'in') 1054 this.main.imageData.proportions = (parseFloat(this.main.imageData.proportions) + (this.main.options.zoomStep / 1000)).toFixed(4); 1055 else 1056 this.main.imageData.proportions = (parseFloat(this.main.imageData.proportions) - (this.main.options.zoomStep / 1000)).toFixed(4); 1057 1058 // Maksymalne przybliżenie to 200% 1059 if(this.main.imageData.proportions >= 2) { 1060 this.main.imageData.proportions = 2; 1061 $('.ci-button.ci-tool-zoomin').addClass('disabled'); 1062 } else { 1063 $('.ci-button.ci-tool-zoomin').removeClass('disabled'); 1064 } 1065 1066 // Maksymalne oddalenie to 1% 1067 if(this.main.imageData.proportions <= 1){ 1068 this.main.imageData.proportions = 1; 1069 $('.ci-button.ci-tool-zoomout').addClass('disabled'); 1070 } else { 1071 $('.ci-button.ci-tool-zoomout').removeClass('disabled'); 1072 } 1073 1074 $('#image-slider-size').slider('value', (this.main.imageData.proportions - 1) * 40); 1075 1076 1077 this.main.imageData.width = (this.main.imageData.originalWidth * this.main.imageData.proportions); 1078 this.main.imageData.height = (this.main.imageData.originalHeight * this.main.imageData.proportions) 1079 1080 // Obliczamy nowe wymiary obrazka wzglÄdem obliczonych procentów 1081 var newSizes = this.fixSizes( 1082 this.main.imageData.originalWidth * this.main.imageData.proportions, 1083 this.main.imageData.originalHeight * this.main.imageData.proportions 1084 ); 1085 1086 // Zmieniamy rozmiar zdjÄcia 1087 this.main.image.css({ 1088 'width':newSizes.width, 1089 'height':newSizes.height, 1090 'max-width':newSizes.width, 1091 'max-height':newSizes.height, 1092 'min-width':newSizes.width, 1093 'min-height':newSizes.height 1094 }); 1095 }, 1096 1097 /** 1098 * Podpina funkcje pod przyciski w kontenerze zdjÄcia odpowiedzialne 1099 * za zmianÄ rozmiaru zdjÄcia wzglÄdem rozmiaru kontenera. 1100 * 1101 * @return void 1102 */ 1103 this.bindFixingButtons = function() { 1104 var self = this; 1105 1106 var update = function() { 1107 self.main.imageData.width = (self.main.imageData.originalWidth * self.main.imageData.proportions); 1108 self.main.imageData.height = (self.main.imageData.originalHeight * self.main.imageData.proportions) 1109 1110 // Obliczamy nowe wymiary obrazka wzglÄdem obliczonych procentów 1111 var newSizes = self.fixSizes( 1112 self.main.imageData.originalWidth * self.main.imageData.proportions, 1113 self.main.imageData.originalHeight * self.main.imageData.proportions 1114 ); 1115 1116 // Zmieniamy rozmiar zdjÄcia 1117 self.main.image.css({ 1118 'width':newSizes.width, 1119 'height':newSizes.height, 1120 'max-width':newSizes.width, 1121 'max-height':newSizes.height, 1122 'min-width':newSizes.width, 1123 'min-height':newSizes.height 1124 }); 1125 1126 self.main.CroppingResult.update(undefined, undefined, self.main.options.resultWidth * parseFloat(self.main.CroppingResult.cropPercent), self.main.options.resultHeight * parseFloat(self.main.CroppingResult.cropPercent), true); 1127 }; 1128 1129 // SzerokoÅÄ kontenera 1130 this.main.container.find('.ci-fixing-size.ci-fsw').click(function() { 1131 self.main.imageData.proportions = self.main.imageContainer.width() / self.main.imageData.originalWidth; 1132 update(); 1133 }); 1134 1135 // WysokoÅÄ kontenera 1136 this.main.container.find('.ci-fixing-size.ci-fsh').click(function() { 1137 self.main.imageData.proportions = self.main.imageContainer.height() / self.main.imageData.originalHeight; 1138 update(); 1139 }); 1140 }, 1141 1142 this.fixSizes = function(width, height) { 1143 /** 1144 * JeÅli z jakiegoÅ powodu któraÅ z wartoÅci jest równa zero, to 1145 * ustawiamy domyÅlne wymiary zdjÄcia. 1146 */ 1147 if(width == 0 || height == 0) 1148 { 1149 width = this.main.imageData.width; 1150 height = this.main.imageData.height; 1151 } 1152 1153 var containerSizes = { 1154 'width':this.main.options.resultWidth, 1155 'height':this.main.options.resultHeight 1156 }; 1157 1158 if(this.main.options.restrictedBounds) 1159 { 1160 if(containerSizes.width > width || containerSizes.height > height) 1161 { 1162 var propsWidth = containerSizes.width / width; 1163 var propsHeight = containerSizes.height / height; 1164 1165 var smaller = 0; 1166 1167 if(propsWidth > propsHeight) 1168 smaller = propsWidth; 1169 else 1170 smaller = propsHeight; 1171 1172 width = width * smaller; 1173 height = height * smaller; 1174 1175 this.main.Zooming.eventMouseUp(); 1176 } 1177 } 1178 1179 return {'width':width+'px','height':height+'px'}; 1180 } 1181 }; 1182 1183 1184 /** 1185 * Obiekt odpowiedzialny jest za wrzucanie danych na temat pozycji zdjÄcia
1186 * w kontenerze oraz jego wymiarów do inputów przechowujÄ cych te dane. 1187 */ 1188 var CI_CROPPING_RESULT = function(main) { 1189 this.main = main; 1190 1191 /** 1192 * WspóÅrzÄdne punktu zaczepienia zaznaczenia obrazka. 1193 */ 1194 this.coordinates = { 'x' : 0, 'y' : 0 }; 1195 1196 /** 1197 * WartoÅÄ w procentach zaznaczenia obrazka. DomyÅlnie: 1 == 100% 1198 */ 1199 this.cropPercent = 1; 1200 1201 /** 1202 * Zapisuje podane dane do inputów o ID typu z doklejonym prefiksem. JeÅli 1203 * podana wartoÅÄ jest undefined lub niepodana to pobieramy wartoÅÄ 1204 * aktualnÄ danego inputa i jÄ wrzucamy. W innym wypadku wrzucamy wartoÅÄ 1205 * zero. 1206 * 1207 * @param integer x WspóÅrzÄdna X 1208 * @param integer y WspóÅrzÄdna Y 1209 * @param integer w SzerokoÅÄ zaznaczenia obrazka 1210 * @param integer h WysokoÅÄ zaznaczenia obrazka 1211 * 1212 * @return void 1213 */ 1214 this.update = function(x, y, w, h, triggerEvent) { 1215 var prop = this.main.imageData.originalWidth / this.main.imageData.width; 1216 1217 var valueX = this.main.vars.x; 1218 1219 if(x != undefined) valueX = Math.ceil(prop * x); 1220 else if(valueX == '') valueX = 0; 1221 1222 x = valueX; 1223 $('#'+this.main.options.inputPrefix+'x').val(valueX); 1224 this.main.vars.x = valueX; 1225 1226 1227 var valueY = this.main.vars.y; 1228 1229 if(y != undefined) valueY = Math.ceil(prop * y); 1230 else if(valueY == '') valueY = 0; 1231 1232 y = valueY; 1233 $('#'+this.main.options.inputPrefix+'y').val(valueY); 1234 this.main.vars.y = valueY; 1235 1236 1237 var valueW = this.main.vars.w; 1238 1239 if(w != undefined) valueW = Math.ceil(prop * w) 1240 else if(valueW == '') valueW = 0; 1241 1242 w = valueW; 1243 $('#'+this.main.options.inputPrefix+'w').val(valueW); 1244 this.main.vars.w = valueW; 1245 1246 1247 var valueH = this.main.vars.h; 1248 1249 if(h != undefined) valueH = Math.ceil(prop * h) 1250 else if(valueH == '') valueH = 0; 1251 1252 h = valueH; 1253 $('#'+this.main.options.inputPrefix+'h').val(valueH); 1254 this.main.vars.h = valueH; 1255 1256 if(triggerEvent === true) 1257 { 1258 this.main.options.onChange(this.main.vars.x, this.main.vars.y, this.main.vars.w, this.main.vars.h, this.main.image); 1259 } 1260 } 1261 }; 1262 1263 /** 1264 * Resetuje obiekt pluginu i zostawia sam obrazek usuwajÄ c kod HTML. 1265 */ 1266 var CI_RESET = function(main) { 1267 this.main = main; 1268 1269 this.reset = function() { 1270 var img = this.main.image.clone().removeAttr('style'); 1271 1272 this.main.container.replaceWith(img); 1273 1274 img.data('cropimg', null); 1275 }; 1276 } 1277 1278 1279 return this.each(function() { 1280 var Main = new CI_Main($(this), options); 1281 Main.ToolDrawer = new CI_TOOLDRAWER(Main); 1282 Main.BtnTips = new CI_BTNSTIPS(Main); 1283 Main.Movable = new CI_MOVABLE(Main); 1284 Main.Zooming = new CI_ZOOMING(Main); 1285 Main.CroppingResult = new CI_CROPPING_RESULT(Main); 1286 Main.Reset = new CI_RESET(Main); 1287 1288 Main.ToolDrawer.draw(); 1289 Main.BtnTips.init(); 1290 Main.Movable.init(); 1291 Main.Zooming.init(); 1292 1293 $(this).data('cropimg', Main.Reset); 1294 1295 $(window).trigger('resize'); 1296 }); 1297 } 1298})(jQuery);
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.