[ Index ] |
WordPress Cross Reference |
[Summary view] [Print] [Text view]
1 /* 2 * imgAreaSelect jQuery plugin 3 * version 0.9.10 4 * 5 * Copyright (c) 2008-2013 Michal Wojciechowski (odyniec.net) 6 * 7 * Dual licensed under the MIT (MIT-LICENSE.txt) 8 * and GPL (GPL-LICENSE.txt) licenses. 9 * 10 * http://odyniec.net/projects/imgareaselect/ 11 * 12 */ 13 14 (function($) { 15 16 /* 17 * Math functions will be used extensively, so it's convenient to make a few 18 * shortcuts 19 */ 20 var abs = Math.abs, 21 max = Math.max, 22 min = Math.min, 23 round = Math.round; 24 25 /** 26 * Create a new HTML div element 27 * 28 * @return A jQuery object representing the new element 29 */ 30 function div() { 31 return $('<div/>'); 32 } 33 34 /** 35 * imgAreaSelect initialization 36 * 37 * @param img 38 * A HTML image element to attach the plugin to 39 * @param options 40 * An options object 41 */ 42 $.imgAreaSelect = function (img, options) { 43 var 44 /* jQuery object representing the image */ 45 $img = $(img), 46 47 /* Has the image finished loading? */ 48 imgLoaded, 49 50 /* Plugin elements */ 51 52 /* Container box */ 53 $box = div(), 54 /* Selection area */ 55 $area = div(), 56 /* Border (four divs) */ 57 $border = div().add(div()).add(div()).add(div()), 58 /* Outer area (four divs) */ 59 $outer = div().add(div()).add(div()).add(div()), 60 /* Handles (empty by default, initialized in setOptions()) */ 61 $handles = $([]), 62 63 /* 64 * Additional element to work around a cursor problem in Opera 65 * (explained later) 66 */ 67 $areaOpera, 68 69 /* Image position (relative to viewport) */ 70 left, top, 71 72 /* Image offset (as returned by .offset()) */ 73 imgOfs = { left: 0, top: 0 }, 74 75 /* Image dimensions (as returned by .width() and .height()) */ 76 imgWidth, imgHeight, 77 78 /* 79 * jQuery object representing the parent element that the plugin 80 * elements are appended to 81 */ 82 $parent, 83 84 /* Parent element offset (as returned by .offset()) */ 85 parOfs = { left: 0, top: 0 }, 86 87 /* Base z-index for plugin elements */ 88 zIndex = 0, 89 90 /* Plugin elements position */ 91 position = 'absolute', 92 93 /* X/Y coordinates of the starting point for move/resize operations */ 94 startX, startY, 95 96 /* Horizontal and vertical scaling factors */ 97 scaleX, scaleY, 98 99 /* Current resize mode ("nw", "se", etc.) */ 100 resize, 101 102 /* Selection area constraints */ 103 minWidth, minHeight, maxWidth, maxHeight, 104 105 /* Aspect ratio to maintain (floating point number) */ 106 aspectRatio, 107 108 /* Are the plugin elements currently displayed? */ 109 shown, 110 111 /* Current selection (relative to parent element) */ 112 x1, y1, x2, y2, 113 114 /* Current selection (relative to scaled image) */ 115 selection = { x1: 0, y1: 0, x2: 0, y2: 0, width: 0, height: 0 }, 116 117 /* Document element */ 118 docElem = document.documentElement, 119 120 /* User agent */ 121 ua = navigator.userAgent, 122 123 /* Various helper variables used throughout the code */ 124 $p, d, i, o, w, h, adjusted; 125 126 /* 127 * Translate selection coordinates (relative to scaled image) to viewport 128 * coordinates (relative to parent element) 129 */ 130 131 /** 132 * Translate selection X to viewport X 133 * 134 * @param x 135 * Selection X 136 * @return Viewport X 137 */ 138 function viewX(x) { 139 return x + imgOfs.left - parOfs.left; 140 } 141 142 /** 143 * Translate selection Y to viewport Y 144 * 145 * @param y 146 * Selection Y 147 * @return Viewport Y 148 */ 149 function viewY(y) { 150 return y + imgOfs.top - parOfs.top; 151 } 152 153 /* 154 * Translate viewport coordinates to selection coordinates 155 */ 156 157 /** 158 * Translate viewport X to selection X 159 * 160 * @param x 161 * Viewport X 162 * @return Selection X 163 */ 164 function selX(x) { 165 return x - imgOfs.left + parOfs.left; 166 } 167 168 /** 169 * Translate viewport Y to selection Y 170 * 171 * @param y 172 * Viewport Y 173 * @return Selection Y 174 */ 175 function selY(y) { 176 return y - imgOfs.top + parOfs.top; 177 } 178 179 /* 180 * Translate event coordinates (relative to document) to viewport 181 * coordinates 182 */ 183 184 /** 185 * Get event X and translate it to viewport X 186 * 187 * @param event 188 * The event object 189 * @return Viewport X 190 */ 191 function evX(event) { 192 return event.pageX - parOfs.left; 193 } 194 195 /** 196 * Get event Y and translate it to viewport Y 197 * 198 * @param event 199 * The event object 200 * @return Viewport Y 201 */ 202 function evY(event) { 203 return event.pageY - parOfs.top; 204 } 205 206 /** 207 * Get the current selection 208 * 209 * @param noScale 210 * If set to <code>true</code>, scaling is not applied to the 211 * returned selection 212 * @return Selection object 213 */ 214 function getSelection(noScale) { 215 var sx = noScale || scaleX, sy = noScale || scaleY; 216 217 return { x1: round(selection.x1 * sx), 218 y1: round(selection.y1 * sy), 219 x2: round(selection.x2 * sx), 220 y2: round(selection.y2 * sy), 221 width: round(selection.x2 * sx) - round(selection.x1 * sx), 222 height: round(selection.y2 * sy) - round(selection.y1 * sy) }; 223 } 224 225 /** 226 * Set the current selection 227 * 228 * @param x1 229 * X coordinate of the upper left corner of the selection area 230 * @param y1 231 * Y coordinate of the upper left corner of the selection area 232 * @param x2 233 * X coordinate of the lower right corner of the selection area 234 * @param y2 235 * Y coordinate of the lower right corner of the selection area 236 * @param noScale 237 * If set to <code>true</code>, scaling is not applied to the 238 * new selection 239 */ 240 function setSelection(x1, y1, x2, y2, noScale) { 241 var sx = noScale || scaleX, sy = noScale || scaleY; 242 243 selection = { 244 x1: round(x1 / sx || 0), 245 y1: round(y1 / sy || 0), 246 x2: round(x2 / sx || 0), 247 y2: round(y2 / sy || 0) 248 }; 249 250 selection.width = selection.x2 - selection.x1; 251 selection.height = selection.y2 - selection.y1; 252 } 253 254 /** 255 * Recalculate image and parent offsets 256 */ 257 function adjust() { 258 /* 259 * Do not adjust if image has not yet loaded or if width is not a 260 * positive number. The latter might happen when imgAreaSelect is put 261 * on a parent element which is then hidden. 262 */ 263 if (!imgLoaded || !$img.width()) 264 return; 265 266 /* 267 * Get image offset. The .offset() method returns float values, so they 268 * need to be rounded. 269 */ 270 imgOfs = { left: round($img.offset().left), top: round($img.offset().top) }; 271 272 /* Get image dimensions */ 273 imgWidth = $img.innerWidth(); 274 imgHeight = $img.innerHeight(); 275 276 imgOfs.top += ($img.outerHeight() - imgHeight) >> 1; 277 imgOfs.left += ($img.outerWidth() - imgWidth) >> 1; 278 279 /* Set minimum and maximum selection area dimensions */ 280 minWidth = round(options.minWidth / scaleX) || 0; 281 minHeight = round(options.minHeight / scaleY) || 0; 282 maxWidth = round(min(options.maxWidth / scaleX || 1<<24, imgWidth)); 283 maxHeight = round(min(options.maxHeight / scaleY || 1<<24, imgHeight)); 284 285 /* 286 * Workaround for jQuery 1.3.2 incorrect offset calculation, originally 287 * observed in Safari 3. Firefox 2 is also affected. 288 */ 289 if ($().jquery == '1.3.2' && position == 'fixed' && 290 !docElem['getBoundingClientRect']) 291 { 292 imgOfs.top += max(document.body.scrollTop, docElem.scrollTop); 293 imgOfs.left += max(document.body.scrollLeft, docElem.scrollLeft); 294 } 295 296 /* Determine parent element offset */ 297 parOfs = /absolute|relative/.test($parent.css('position')) ? 298 { left: round($parent.offset().left) - $parent.scrollLeft(), 299 top: round($parent.offset().top) - $parent.scrollTop() } : 300 position == 'fixed' ? 301 { left: $(document).scrollLeft(), top: $(document).scrollTop() } : 302 { left: 0, top: 0 }; 303 304 left = viewX(0); 305 top = viewY(0); 306 307 /* 308 * Check if selection area is within image boundaries, adjust if 309 * necessary 310 */ 311 if (selection.x2 > imgWidth || selection.y2 > imgHeight) 312 doResize(); 313 } 314 315 /** 316 * Update plugin elements 317 * 318 * @param resetKeyPress 319 * If set to <code>false</code>, this instance's keypress 320 * event handler is not activated 321 */ 322 function update(resetKeyPress) { 323 /* If plugin elements are hidden, do nothing */ 324 if (!shown) return; 325 326 /* 327 * Set the position and size of the container box and the selection area 328 * inside it 329 */ 330 $box.css({ left: viewX(selection.x1), top: viewY(selection.y1) }) 331 .add($area).width(w = selection.width).height(h = selection.height); 332 333 /* 334 * Reset the position of selection area, borders, and handles (IE6/IE7 335 * position them incorrectly if we don't do this) 336 */ 337 $area.add($border).add($handles).css({ left: 0, top: 0 }); 338 339 /* Set border dimensions */ 340 $border 341 .width(max(w - $border.outerWidth() + $border.innerWidth(), 0)) 342 .height(max(h - $border.outerHeight() + $border.innerHeight(), 0)); 343 344 /* Arrange the outer area elements */ 345 $($outer[0]).css({ left: left, top: top, 346 width: selection.x1, height: imgHeight }); 347 $($outer[1]).css({ left: left + selection.x1, top: top, 348 width: w, height: selection.y1 }); 349 $($outer[2]).css({ left: left + selection.x2, top: top, 350 width: imgWidth - selection.x2, height: imgHeight }); 351 $($outer[3]).css({ left: left + selection.x1, top: top + selection.y2, 352 width: w, height: imgHeight - selection.y2 }); 353 354 w -= $handles.outerWidth(); 355 h -= $handles.outerHeight(); 356 357 /* Arrange handles */ 358 switch ($handles.length) { 359 case 8: 360 $($handles[4]).css({ left: w >> 1 }); 361 $($handles[5]).css({ left: w, top: h >> 1 }); 362 $($handles[6]).css({ left: w >> 1, top: h }); 363 $($handles[7]).css({ top: h >> 1 }); 364 case 4: 365 $handles.slice(1,3).css({ left: w }); 366 $handles.slice(2,4).css({ top: h }); 367 } 368 369 if (resetKeyPress !== false) { 370 /* 371 * Need to reset the document keypress event handler -- unbind the 372 * current handler 373 */ 374 if ($.imgAreaSelect.onKeyPress != docKeyPress) 375 $(document).unbind($.imgAreaSelect.keyPress, 376 $.imgAreaSelect.onKeyPress); 377 378 if (options.keys) 379 /* 380 * Set the document keypress event handler to this instance's 381 * docKeyPress() function 382 */ 383 $(document)[$.imgAreaSelect.keyPress]( 384 $.imgAreaSelect.onKeyPress = docKeyPress); 385 } 386 387 /* 388 * Internet Explorer displays 1px-wide dashed borders incorrectly by 389 * filling the spaces between dashes with white. Toggling the margin 390 * property between 0 and "auto" fixes this in IE6 and IE7 (IE8 is still 391 * broken). This workaround is not perfect, as it requires setTimeout() 392 * and thus causes the border to flicker a bit, but I haven't found a 393 * better solution. 394 * 395 * Note: This only happens with CSS borders, set with the borderWidth, 396 * borderOpacity, borderColor1, and borderColor2 options (which are now 397 * deprecated). Borders created with GIF background images are fine. 398 */ 399 if (msie && $border.outerWidth() - $border.innerWidth() == 2) { 400 $border.css('margin', 0); 401 setTimeout(function () { $border.css('margin', 'auto'); }, 0); 402 } 403 } 404 405 /** 406 * Do the complete update sequence: recalculate offsets, update the 407 * elements, and set the correct values of x1, y1, x2, and y2. 408 * 409 * @param resetKeyPress 410 * If set to <code>false</code>, this instance's keypress 411 * event handler is not activated 412 */ 413 function doUpdate(resetKeyPress) { 414 adjust(); 415 update(resetKeyPress); 416 x1 = viewX(selection.x1); y1 = viewY(selection.y1); 417 x2 = viewX(selection.x2); y2 = viewY(selection.y2); 418 } 419 420 /** 421 * Hide or fade out an element (or multiple elements) 422 * 423 * @param $elem 424 * A jQuery object containing the element(s) to hide/fade out 425 * @param fn 426 * Callback function to be called when fadeOut() completes 427 */ 428 function hide($elem, fn) { 429 options.fadeSpeed ? $elem.fadeOut(options.fadeSpeed, fn) : $elem.hide(); 430 } 431 432 /** 433 * Selection area mousemove event handler 434 * 435 * @param event 436 * The event object 437 */ 438 function areaMouseMove(event) { 439 var x = selX(evX(event)) - selection.x1, 440 y = selY(evY(event)) - selection.y1; 441 442 if (!adjusted) { 443 adjust(); 444 adjusted = true; 445 446 $box.one('mouseout', function () { adjusted = false; }); 447 } 448 449 /* Clear the resize mode */ 450 resize = ''; 451 452 if (options.resizable) { 453 /* 454 * Check if the mouse pointer is over the resize margin area and set 455 * the resize mode accordingly 456 */ 457 if (y <= options.resizeMargin) 458 resize = 'n'; 459 else if (y >= selection.height - options.resizeMargin) 460 resize = 's'; 461 if (x <= options.resizeMargin) 462 resize += 'w'; 463 else if (x >= selection.width - options.resizeMargin) 464 resize += 'e'; 465 } 466 467 $box.css('cursor', resize ? resize + '-resize' : 468 options.movable ? 'move' : ''); 469 if ($areaOpera) 470 $areaOpera.toggle(); 471 } 472 473 /** 474 * Document mouseup event handler 475 * 476 * @param event 477 * The event object 478 */ 479 function docMouseUp(event) { 480 /* Set back the default cursor */ 481 $('body').css('cursor', ''); 482 /* 483 * If autoHide is enabled, or if the selection has zero width/height, 484 * hide the selection and the outer area 485 */ 486 if (options.autoHide || selection.width * selection.height == 0) 487 hide($box.add($outer), function () { $(this).hide(); }); 488 489 $(document).unbind('mousemove', selectingMouseMove); 490 $box.mousemove(areaMouseMove); 491 492 options.onSelectEnd(img, getSelection()); 493 } 494 495 /** 496 * Selection area mousedown event handler 497 * 498 * @param event 499 * The event object 500 * @return false 501 */ 502 function areaMouseDown(event) { 503 if (event.which != 1) return false; 504 505 adjust(); 506 507 if (resize) { 508 /* Resize mode is in effect */ 509 $('body').css('cursor', resize + '-resize'); 510 511 x1 = viewX(selection[/w/.test(resize) ? 'x2' : 'x1']); 512 y1 = viewY(selection[/n/.test(resize) ? 'y2' : 'y1']); 513 514 $(document).mousemove(selectingMouseMove) 515 .one('mouseup', docMouseUp); 516 $box.unbind('mousemove', areaMouseMove); 517 } 518 else if (options.movable) { 519 startX = left + selection.x1 - evX(event); 520 startY = top + selection.y1 - evY(event); 521 522 $box.unbind('mousemove', areaMouseMove); 523 524 $(document).mousemove(movingMouseMove) 525 .one('mouseup', function () { 526 options.onSelectEnd(img, getSelection()); 527 528 $(document).unbind('mousemove', movingMouseMove); 529 $box.mousemove(areaMouseMove); 530 }); 531 } 532 else 533 $img.mousedown(event); 534 535 return false; 536 } 537 538 /** 539 * Adjust the x2/y2 coordinates to maintain aspect ratio (if defined) 540 * 541 * @param xFirst 542 * If set to <code>true</code>, calculate x2 first. Otherwise, 543 * calculate y2 first. 544 */ 545 function fixAspectRatio(xFirst) { 546 if (aspectRatio) 547 if (xFirst) { 548 x2 = max(left, min(left + imgWidth, 549 x1 + abs(y2 - y1) * aspectRatio * (x2 > x1 || -1))); 550 y2 = round(max(top, min(top + imgHeight, 551 y1 + abs(x2 - x1) / aspectRatio * (y2 > y1 || -1)))); 552 x2 = round(x2); 553 } 554 else { 555 y2 = max(top, min(top + imgHeight, 556 y1 + abs(x2 - x1) / aspectRatio * (y2 > y1 || -1))); 557 x2 = round(max(left, min(left + imgWidth, 558 x1 + abs(y2 - y1) * aspectRatio * (x2 > x1 || -1)))); 559 y2 = round(y2); 560 } 561 } 562 563 /** 564 * Resize the selection area respecting the minimum/maximum dimensions and 565 * aspect ratio 566 */ 567 function doResize() { 568 /* 569 * Make sure the top left corner of the selection area stays within 570 * image boundaries (it might not if the image source was dynamically 571 * changed). 572 */ 573 x1 = min(x1, left + imgWidth); 574 y1 = min(y1, top + imgHeight); 575 576 if (abs(x2 - x1) < minWidth) { 577 /* Selection width is smaller than minWidth */ 578 x2 = x1 - minWidth * (x2 < x1 || -1); 579 580 if (x2 < left) 581 x1 = left + minWidth; 582 else if (x2 > left + imgWidth) 583 x1 = left + imgWidth - minWidth; 584 } 585 586 if (abs(y2 - y1) < minHeight) { 587 /* Selection height is smaller than minHeight */ 588 y2 = y1 - minHeight * (y2 < y1 || -1); 589 590 if (y2 < top) 591 y1 = top + minHeight; 592 else if (y2 > top + imgHeight) 593 y1 = top + imgHeight - minHeight; 594 } 595 596 x2 = max(left, min(x2, left + imgWidth)); 597 y2 = max(top, min(y2, top + imgHeight)); 598 599 fixAspectRatio(abs(x2 - x1) < abs(y2 - y1) * aspectRatio); 600 601 if (abs(x2 - x1) > maxWidth) { 602 /* Selection width is greater than maxWidth */ 603 x2 = x1 - maxWidth * (x2 < x1 || -1); 604 fixAspectRatio(); 605 } 606 607 if (abs(y2 - y1) > maxHeight) { 608 /* Selection height is greater than maxHeight */ 609 y2 = y1 - maxHeight * (y2 < y1 || -1); 610 fixAspectRatio(true); 611 } 612 613 selection = { x1: selX(min(x1, x2)), x2: selX(max(x1, x2)), 614 y1: selY(min(y1, y2)), y2: selY(max(y1, y2)), 615 width: abs(x2 - x1), height: abs(y2 - y1) }; 616 617 update(); 618 619 options.onSelectChange(img, getSelection()); 620 } 621 622 /** 623 * Mousemove event handler triggered when the user is selecting an area 624 * 625 * @param event 626 * The event object 627 * @return false 628 */ 629 function selectingMouseMove(event) { 630 x2 = /w|e|^$/.test(resize) || aspectRatio ? evX(event) : viewX(selection.x2); 631 y2 = /n|s|^$/.test(resize) || aspectRatio ? evY(event) : viewY(selection.y2); 632 633 doResize(); 634 635 return false; 636 } 637 638 /** 639 * Move the selection area 640 * 641 * @param newX1 642 * New viewport X1 643 * @param newY1 644 * New viewport Y1 645 */ 646 function doMove(newX1, newY1) { 647 x2 = (x1 = newX1) + selection.width; 648 y2 = (y1 = newY1) + selection.height; 649 650 $.extend(selection, { x1: selX(x1), y1: selY(y1), x2: selX(x2), 651 y2: selY(y2) }); 652 653 update(); 654 655 options.onSelectChange(img, getSelection()); 656 } 657 658 /** 659 * Mousemove event handler triggered when the selection area is being moved 660 * 661 * @param event 662 * The event object 663 * @return false 664 */ 665 function movingMouseMove(event) { 666 x1 = max(left, min(startX + evX(event), left + imgWidth - selection.width)); 667 y1 = max(top, min(startY + evY(event), top + imgHeight - selection.height)); 668 669 doMove(x1, y1); 670 671 event.preventDefault(); 672 return false; 673 } 674 675 /** 676 * Start selection 677 */ 678 function startSelection() { 679 $(document).unbind('mousemove', startSelection); 680 adjust(); 681 682 x2 = x1; 683 y2 = y1; 684 doResize(); 685 686 resize = ''; 687 688 if (!$outer.is(':visible')) 689 /* Show the plugin elements */ 690 $box.add($outer).hide().fadeIn(options.fadeSpeed||0); 691 692 shown = true; 693 694 $(document).unbind('mouseup', cancelSelection) 695 .mousemove(selectingMouseMove).one('mouseup', docMouseUp); 696 $box.unbind('mousemove', areaMouseMove); 697 698 options.onSelectStart(img, getSelection()); 699 } 700 701 /** 702 * Cancel selection 703 */ 704 function cancelSelection() { 705 $(document).unbind('mousemove', startSelection) 706 .unbind('mouseup', cancelSelection); 707 hide($box.add($outer)); 708 709 setSelection(selX(x1), selY(y1), selX(x1), selY(y1)); 710 711 /* If this is an API call, callback functions should not be triggered */ 712 if (!(this instanceof $.imgAreaSelect)) { 713 options.onSelectChange(img, getSelection()); 714 options.onSelectEnd(img, getSelection()); 715 } 716 } 717 718 /** 719 * Image mousedown event handler 720 * 721 * @param event 722 * The event object 723 * @return false 724 */ 725 function imgMouseDown(event) { 726 /* Ignore the event if animation is in progress */ 727 if (event.which != 1 || $outer.is(':animated')) return false; 728 729 adjust(); 730 startX = x1 = evX(event); 731 startY = y1 = evY(event); 732 733 /* Selection will start when the mouse is moved */ 734 $(document).mousemove(startSelection).mouseup(cancelSelection); 735 736 return false; 737 } 738 739 /** 740 * Window resize event handler 741 */ 742 function windowResize() { 743 doUpdate(false); 744 } 745 746 /** 747 * Image load event handler. This is the final part of the initialization 748 * process. 749 */ 750 function imgLoad() { 751 imgLoaded = true; 752 753 /* Set options */ 754 setOptions(options = $.extend({ 755 classPrefix: 'imgareaselect', 756 movable: true, 757 parent: 'body', 758 resizable: true, 759 resizeMargin: 10, 760 onInit: function () {}, 761 onSelectStart: function () {}, 762 onSelectChange: function () {}, 763 onSelectEnd: function () {} 764 }, options)); 765 766 $box.add($outer).css({ visibility: '' }); 767 768 if (options.show) { 769 shown = true; 770 adjust(); 771 update(); 772 $box.add($outer).hide().fadeIn(options.fadeSpeed||0); 773 } 774 775 /* 776 * Call the onInit callback. The setTimeout() call is used to ensure 777 * that the plugin has been fully initialized and the object instance is 778 * available (so that it can be obtained in the callback). 779 */ 780 setTimeout(function () { options.onInit(img, getSelection()); }, 0); 781 } 782 783 /** 784 * Document keypress event handler 785 * 786 * @param event 787 * The event object 788 * @return false 789 */ 790 var docKeyPress = function(event) { 791 var k = options.keys, d, t, key = event.keyCode; 792 793 d = !isNaN(k.alt) && (event.altKey || event.originalEvent.altKey) ? k.alt : 794 !isNaN(k.ctrl) && event.ctrlKey ? k.ctrl : 795 !isNaN(k.shift) && event.shiftKey ? k.shift : 796 !isNaN(k.arrows) ? k.arrows : 10; 797 798 if (k.arrows == 'resize' || (k.shift == 'resize' && event.shiftKey) || 799 (k.ctrl == 'resize' && event.ctrlKey) || 800 (k.alt == 'resize' && (event.altKey || event.originalEvent.altKey))) 801 { 802 /* Resize selection */ 803 804 switch (key) { 805 case 37: 806 /* Left */ 807 d = -d; 808 case 39: 809 /* Right */ 810 t = max(x1, x2); 811 x1 = min(x1, x2); 812 x2 = max(t + d, x1); 813 fixAspectRatio(); 814 break; 815 case 38: 816 /* Up */ 817 d = -d; 818 case 40: 819 /* Down */ 820 t = max(y1, y2); 821 y1 = min(y1, y2); 822 y2 = max(t + d, y1); 823 fixAspectRatio(true); 824 break; 825 default: 826 return; 827 } 828 829 doResize(); 830 } 831 else { 832 /* Move selection */ 833 834 x1 = min(x1, x2); 835 y1 = min(y1, y2); 836 837 switch (key) { 838 case 37: 839 /* Left */ 840 doMove(max(x1 - d, left), y1); 841 break; 842 case 38: 843 /* Up */ 844 doMove(x1, max(y1 - d, top)); 845 break; 846 case 39: 847 /* Right */ 848 doMove(x1 + min(d, imgWidth - selX(x2)), y1); 849 break; 850 case 40: 851 /* Down */ 852 doMove(x1, y1 + min(d, imgHeight - selY(y2))); 853 break; 854 default: 855 return; 856 } 857 } 858 859 return false; 860 }; 861 862 /** 863 * Apply style options to plugin element (or multiple elements) 864 * 865 * @param $elem 866 * A jQuery object representing the element(s) to style 867 * @param props 868 * An object that maps option names to corresponding CSS 869 * properties 870 */ 871 function styleOptions($elem, props) { 872 for (var option in props) 873 if (options[option] !== undefined) 874 $elem.css(props[option], options[option]); 875 } 876 877 /** 878 * Set plugin options 879 * 880 * @param newOptions 881 * The new options object 882 */ 883 function setOptions(newOptions) { 884 if (newOptions.parent) 885 ($parent = $(newOptions.parent)).append($box.add($outer)); 886 887 /* Merge the new options with the existing ones */ 888 $.extend(options, newOptions); 889 890 adjust(); 891 892 if (newOptions.handles != null) { 893 /* Recreate selection area handles */ 894 $handles.remove(); 895 $handles = $([]); 896 897 i = newOptions.handles ? newOptions.handles == 'corners' ? 4 : 8 : 0; 898 899 while (i--) 900 $handles = $handles.add(div()); 901 902 /* Add a class to handles and set the CSS properties */ 903 $handles.addClass(options.classPrefix + '-handle').css({ 904 position: 'absolute', 905 /* 906 * The font-size property needs to be set to zero, otherwise 907 * Internet Explorer makes the handles too large 908 */ 909 fontSize: 0, 910 zIndex: zIndex + 1 || 1 911 }); 912 913 /* 914 * If handle width/height has not been set with CSS rules, set the 915 * default 5px 916 */ 917 if (!parseInt($handles.css('width')) >= 0) 918 $handles.width(5).height(5); 919 920 /* 921 * If the borderWidth option is in use, add a solid border to 922 * handles 923 */ 924 if (o = options.borderWidth) 925 $handles.css({ borderWidth: o, borderStyle: 'solid' }); 926 927 /* Apply other style options */ 928 styleOptions($handles, { borderColor1: 'border-color', 929 borderColor2: 'background-color', 930 borderOpacity: 'opacity' }); 931 } 932 933 /* Calculate scale factors */ 934 scaleX = options.imageWidth / imgWidth || 1; 935 scaleY = options.imageHeight / imgHeight || 1; 936 937 /* Set selection */ 938 if (newOptions.x1 != null) { 939 setSelection(newOptions.x1, newOptions.y1, newOptions.x2, 940 newOptions.y2); 941 newOptions.show = !newOptions.hide; 942 } 943 944 if (newOptions.keys) 945 /* Enable keyboard support */ 946 options.keys = $.extend({ shift: 1, ctrl: 'resize' }, 947 newOptions.keys); 948 949 /* Add classes to plugin elements */ 950 $outer.addClass(options.classPrefix + '-outer'); 951 $area.addClass(options.classPrefix + '-selection'); 952 for (i = 0; i++ < 4;) 953 $($border[i-1]).addClass(options.classPrefix + '-border' + i); 954 955 /* Apply style options */ 956 styleOptions($area, { selectionColor: 'background-color', 957 selectionOpacity: 'opacity' }); 958 styleOptions($border, { borderOpacity: 'opacity', 959 borderWidth: 'border-width' }); 960 styleOptions($outer, { outerColor: 'background-color', 961 outerOpacity: 'opacity' }); 962 if (o = options.borderColor1) 963 $($border[0]).css({ borderStyle: 'solid', borderColor: o }); 964 if (o = options.borderColor2) 965 $($border[1]).css({ borderStyle: 'dashed', borderColor: o }); 966 967 /* Append all the selection area elements to the container box */ 968 $box.append($area.add($border).add($areaOpera)).append($handles); 969 970 if (msie) { 971 if (o = ($outer.css('filter')||'').match(/opacity=(\d+)/)) 972 $outer.css('opacity', o[1]/100); 973 if (o = ($border.css('filter')||'').match(/opacity=(\d+)/)) 974 $border.css('opacity', o[1]/100); 975 } 976 977 if (newOptions.hide) 978 hide($box.add($outer)); 979 else if (newOptions.show && imgLoaded) { 980 shown = true; 981 $box.add($outer).fadeIn(options.fadeSpeed||0); 982 doUpdate(); 983 } 984 985 /* Calculate the aspect ratio factor */ 986 aspectRatio = (d = (options.aspectRatio || '').split(/:/))[0] / d[1]; 987 988 $img.add($outer).unbind('mousedown', imgMouseDown); 989 990 if (options.disable || options.enable === false) { 991 /* Disable the plugin */ 992 $box.unbind('mousemove', areaMouseMove).unbind('mousedown', areaMouseDown); 993 $(window).unbind('resize', windowResize); 994 } 995 else { 996 if (options.enable || options.disable === false) { 997 /* Enable the plugin */ 998 if (options.resizable || options.movable) 999 $box.mousemove(areaMouseMove).mousedown(areaMouseDown); 1000 1001 $(window).resize(windowResize); 1002 } 1003 1004 if (!options.persistent) 1005 $img.add($outer).mousedown(imgMouseDown); 1006 } 1007 1008 options.enable = options.disable = undefined; 1009 } 1010 1011 /** 1012 * Remove plugin completely 1013 */ 1014 this.remove = function () { 1015 /* 1016 * Call setOptions with { disable: true } to unbind the event handlers 1017 */ 1018 setOptions({ disable: true }); 1019 $box.add($outer).remove(); 1020 }; 1021 1022 /* 1023 * Public API 1024 */ 1025 1026 /** 1027 * Get current options 1028 * 1029 * @return An object containing the set of options currently in use 1030 */ 1031 this.getOptions = function () { return options; }; 1032 1033 /** 1034 * Set plugin options 1035 * 1036 * @param newOptions 1037 * The new options object 1038 */ 1039 this.setOptions = setOptions; 1040 1041 /** 1042 * Get the current selection 1043 * 1044 * @param noScale 1045 * If set to <code>true</code>, scaling is not applied to the 1046 * returned selection 1047 * @return Selection object 1048 */ 1049 this.getSelection = getSelection; 1050 1051 /** 1052 * Set the current selection 1053 * 1054 * @param x1 1055 * X coordinate of the upper left corner of the selection area 1056 * @param y1 1057 * Y coordinate of the upper left corner of the selection area 1058 * @param x2 1059 * X coordinate of the lower right corner of the selection area 1060 * @param y2 1061 * Y coordinate of the lower right corner of the selection area 1062 * @param noScale 1063 * If set to <code>true</code>, scaling is not applied to the 1064 * new selection 1065 */ 1066 this.setSelection = setSelection; 1067 1068 /** 1069 * Cancel selection 1070 */ 1071 this.cancelSelection = cancelSelection; 1072 1073 /** 1074 * Update plugin elements 1075 * 1076 * @param resetKeyPress 1077 * If set to <code>false</code>, this instance's keypress 1078 * event handler is not activated 1079 */ 1080 this.update = doUpdate; 1081 1082 /* Do the dreaded browser detection */ 1083 var msie = (/msie ([\w.]+)/i.exec(ua)||[])[1], 1084 opera = /opera/i.test(ua), 1085 safari = /webkit/i.test(ua) && !/chrome/i.test(ua); 1086 1087 /* 1088 * Traverse the image's parent elements (up to <body>) and find the 1089 * highest z-index 1090 */ 1091 $p = $img; 1092 1093 while ($p.length) { 1094 zIndex = max(zIndex, 1095 !isNaN($p.css('z-index')) ? $p.css('z-index') : zIndex); 1096 /* Also check if any of the ancestor elements has fixed position */ 1097 if ($p.css('position') == 'fixed') 1098 position = 'fixed'; 1099 1100 $p = $p.parent(':not(body)'); 1101 } 1102 1103 /* 1104 * If z-index is given as an option, it overrides the one found by the 1105 * above loop 1106 */ 1107 zIndex = options.zIndex || zIndex; 1108 1109 if (msie) 1110 $img.attr('unselectable', 'on'); 1111 1112 /* 1113 * In MSIE and WebKit, we need to use the keydown event instead of keypress 1114 */ 1115 $.imgAreaSelect.keyPress = msie || safari ? 'keydown' : 'keypress'; 1116 1117 /* 1118 * There is a bug affecting the CSS cursor property in Opera (observed in 1119 * versions up to 10.00) that prevents the cursor from being updated unless 1120 * the mouse leaves and enters the element again. To trigger the mouseover 1121 * event, we're adding an additional div to $box and we're going to toggle 1122 * it when mouse moves inside the selection area. 1123 */ 1124 if (opera) 1125 $areaOpera = div().css({ width: '100%', height: '100%', 1126 position: 'absolute', zIndex: zIndex + 2 || 2 }); 1127 1128 /* 1129 * We initially set visibility to "hidden" as a workaround for a weird 1130 * behaviour observed in Google Chrome 1.0.154.53 (on Windows XP). Normally 1131 * we would just set display to "none", but, for some reason, if we do so 1132 * then Chrome refuses to later display the element with .show() or 1133 * .fadeIn(). 1134 */ 1135 $box.add($outer).css({ visibility: 'hidden', position: position, 1136 overflow: 'hidden', zIndex: zIndex || '0' }); 1137 $box.css({ zIndex: zIndex + 2 || 2 }); 1138 $area.add($border).css({ position: 'absolute', fontSize: 0 }); 1139 1140 /* 1141 * If the image has been fully loaded, or if it is not really an image (eg. 1142 * a div), call imgLoad() immediately; otherwise, bind it to be called once 1143 * on image load event. 1144 */ 1145 img.complete || img.readyState == 'complete' || !$img.is('img') ? 1146 imgLoad() : $img.one('load', imgLoad); 1147 1148 /* 1149 * MSIE 9.0 doesn't always fire the image load event -- resetting the src 1150 * attribute seems to trigger it. The check is for version 7 and above to 1151 * accommodate for MSIE 9 running in compatibility mode. 1152 */ 1153 if (!imgLoaded && msie && msie >= 7) 1154 img.src = img.src; 1155 }; 1156 1157 /** 1158 * Invoke imgAreaSelect on a jQuery object containing the image(s) 1159 * 1160 * @param options 1161 * Options object 1162 * @return The jQuery object or a reference to imgAreaSelect instance (if the 1163 * <code>instance</code> option was specified) 1164 */ 1165 $.fn.imgAreaSelect = function (options) { 1166 options = options || {}; 1167 1168 this.each(function () { 1169 /* Is there already an imgAreaSelect instance bound to this element? */ 1170 if ($(this).data('imgAreaSelect')) { 1171 /* Yes there is -- is it supposed to be removed? */ 1172 if (options.remove) { 1173 /* Remove the plugin */ 1174 $(this).data('imgAreaSelect').remove(); 1175 $(this).removeData('imgAreaSelect'); 1176 } 1177 else 1178 /* Reset options */ 1179 $(this).data('imgAreaSelect').setOptions(options); 1180 } 1181 else if (!options.remove) { 1182 /* No exising instance -- create a new one */ 1183 1184 /* 1185 * If neither the "enable" nor the "disable" option is present, add 1186 * "enable" as the default 1187 */ 1188 if (options.enable === undefined && options.disable === undefined) 1189 options.enable = true; 1190 1191 $(this).data('imgAreaSelect', new $.imgAreaSelect(this, options)); 1192 } 1193 }); 1194 1195 if (options.instance) 1196 /* 1197 * Return the imgAreaSelect instance bound to the first element in the 1198 * set 1199 */ 1200 return $(this).data('imgAreaSelect'); 1201 1202 return this; 1203 }; 1204 1205 })(jQuery);
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Tue Mar 25 01:41:18 2014 | WordPress honlapkészítés: online1.hu |