├── README.md └── bin ├── pixi.draggable.js └── pixi.draggable.min.js /README.md: -------------------------------------------------------------------------------- 1 | PIXI.draggable 2 | ============== 3 | 4 | The easiest way to get drag & drop done in PIXI.js! 5 | 6 | Demo: http://mokgames.com/draggable/ 7 | 8 | Bag & Skillbar Demo! http://mokgames.com/draggable/demo2.html 9 | 10 | #### How to use #### 11 | Simply load the pixi.draggable.js file after your pixi.js file. 12 | ``` 13 | 14 | 15 | ``` 16 | 17 | #### Creating a draggable sprite #### 18 | 19 | ```javascript 20 | var sprite = new PIXI.Sprite(texture); 21 | stage.addChild(sprite); 22 | 23 | sprite.draggable(); 24 | ``` 25 | 26 | #### Only draggable along the x-axis #### 27 | 28 | ```javascript 29 | var sprite = new PIXI.Sprite(texture); 30 | stage.addChild(sprite); 31 | 32 | sprite.draggable({ axis: 'x' }); 33 | ``` 34 | 35 | #### Full list of drag options #### 36 | 37 | ```javascript 38 | { 39 | distance: 1, 40 | axis: null, 41 | containment: null, 42 | cursor: 'inherit', 43 | cursorAt: null, 44 | grid: false, 45 | handle: null, 46 | cancel: null, 47 | helper: 'original', 48 | alpha: 1, 49 | revert: false, 50 | revertDuration: 500, 51 | label: null, 52 | snap: null, 53 | snapMode: 'both', 54 | snapSort: false, 55 | snapTolerance: 20, 56 | disabled: false, 57 | 58 | // special drag events 59 | drag: null, 60 | start: null, 61 | stop: null, 62 | 63 | // regular mouse // tap events 64 | mousedown: null, 65 | mousemove: null, 66 | mouseup: null, 67 | mouseupoutside: null 68 | } 69 | ``` 70 | 71 | #### Full list of drop options #### 72 | 73 | ```javascript 74 | { 75 | label: null, 76 | drop: null, 77 | accept: true, 78 | greedy: false, 79 | disabled: false, 80 | tolerance: 'intersect' 81 | } 82 | ``` 83 | 84 | A tutorial and the sourcecode to achieve all the effects on the demo page will soon be online! 85 | -------------------------------------------------------------------------------- /bin/pixi.draggable.js: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2014 Sebastian Nette 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 | * 25 | * 26 | */ 27 | 28 | /** 29 | * PIXI Draggables & Droppables v1.0.0 30 | * Copyright (c) 2014, Sebastian Nette 31 | * http://www.mokgames.com/ 32 | */ 33 | 34 | /** 35 | * Attaches draggable method to all displayObjects. 36 | * 37 | * @method draggable 38 | * @param name 39 | * @param val 40 | * @return displayObject 41 | */ 42 | PIXI.DisplayObject.prototype.draggable = function( name, val ) 43 | { 44 | // .draggable(null) destroy 45 | if(val == undefined && name === null) 46 | { 47 | this.__draggable = false; 48 | 49 | // restore events (?) 50 | this.mousedown = this.touchstart = options.mousedown; 51 | this.mousemove = this.touchmove = options.mousemove; 52 | this.mouseup = this.touchend = options.mouseup; 53 | this.mouseupoutside = this.touchendoutside = options.mouseupoutside; 54 | 55 | // check all interactive events 56 | //this.interactive = !!(this.mouseout || this.mouseover || this.click || this.tap || this.mousedown || this.touchstart || this.mousemove || this.touchmove || this.mouseup || this.touchend || this.mouseupoutside || this.touchendoutside); 57 | this.interactive = true; 58 | } 59 | 60 | // if no val set, then name is an object 61 | else if(val === undefined) 62 | { 63 | // make sure this one is correctly removed if it was already draggable 64 | if(this.__draggable) 65 | { 66 | this.draggable(null); 67 | } 68 | 69 | var options = name || {}; 70 | 71 | // fill options with defaults 72 | for(var prop in PIXI.DragAndDropManager.options.drag) 73 | { 74 | if(!options.hasOwnProperty(prop)) 75 | { 76 | options[prop] = PIXI.DragAndDropManager.options.drag[prop]; 77 | } 78 | } 79 | 80 | // carry over old events 81 | if(this.mousedown && !options.mousedown) options.mousedown = this.mousedown; 82 | if(this.mousemove && !options.mousemove) options.mousemove = this.mousemove; 83 | if(this.mouseup && !options.mouseup) options.mouseup = this.mouseup; 84 | if(this.mouseupoutside && !options.mouseupoutside) options.mouseupoutside = this.mouseupoutside; 85 | 86 | this.dragOptions = options; 87 | 88 | this.offset = new PIXI.Point(0,0); 89 | this.original = new PIXI.Point(0,0); 90 | 91 | // only initialize this array if we actually use snap 92 | if(options.snap) 93 | { 94 | this.snapElements = []; 95 | } 96 | 97 | // set interactive 98 | this.interactive = true; 99 | this.__draggable = true; 100 | 101 | // mouse events // maybe avoid bindings? 102 | this.mousedown = this.touchstart = PIXI.DragAndDropManager.onMouseDown.bind(this); 103 | this.mousemove = this.touchmove = PIXI.DragAndDropManager.onMouseMove.bind(this); 104 | this.mouseup = this.touchend = PIXI.DragAndDropManager.onMouseUp.bind(this); 105 | this.mouseupoutside = this.touchendoutside = PIXI.DragAndDropManager.onMouseUpOutside.bind(this); 106 | } 107 | 108 | // both name and val set 109 | else if(this.dragOptions) 110 | { 111 | // make sure draggable was initialized 112 | if(!this.__draggable) 113 | { 114 | this.draggable(); 115 | } 116 | 117 | this.dragOptions[name] = val; 118 | 119 | // only initialize this array if we actually use snap 120 | if(name === 'snap' && val) 121 | { 122 | this.snapElements = []; 123 | } 124 | } 125 | 126 | return this; 127 | }; 128 | 129 | /** 130 | * Attaches droppable method to all displayObjects. 131 | * 132 | * @method droppable 133 | * @param name 134 | * @param val 135 | * @return displayObject 136 | */ 137 | PIXI.DisplayObject.prototype.droppable = function( name, val ) 138 | { 139 | // .droppable(null) destroy 140 | if(val == undefined && name === null) 141 | { 142 | this.__droppable = false; 143 | this.interactive = true; // flag as dirty, cant set to false because there might be other events attached 144 | } 145 | 146 | // if no val set, then name is an object 147 | else if(val === undefined) 148 | { 149 | var options = name || {}; 150 | 151 | // fill options with defaults 152 | for(var prop in PIXI.DragAndDropManager.options.drop) 153 | { 154 | if(!options.hasOwnProperty(prop)) 155 | { 156 | options[prop] = PIXI.DragAndDropManager.options.drop[prop]; 157 | } 158 | } 159 | 160 | this.dropOptions = options; 161 | 162 | // set interactive 163 | this.interactive = true; // TODO: Find a good way to collect droppanles without adding them to the interactive tree. 164 | this.__droppable = true; 165 | } 166 | 167 | // both name and val set 168 | else if(this.dropOptions) 169 | { 170 | // make sure droppable was initialized 171 | if(!this.__droppable) 172 | { 173 | this.droppable(); 174 | } 175 | 176 | this.dropOptions[name] = val; 177 | } 178 | 179 | return this; 180 | }; 181 | 182 | /** 183 | * The DragAndDropManager collects the interactive draggable & droppable items. 184 | * It also provides all drag and drop related functions. 185 | * 186 | * @class DragAndDropManager 187 | * @constructor 188 | */ 189 | PIXI.DragAndDropManager = function() 190 | { 191 | 192 | /** 193 | * An array containing all the draggable items from our interactive tree. 194 | * @property draggableItems 195 | * @type Array 196 | * @private 197 | */ 198 | this.draggableItems = []; 199 | 200 | /** 201 | * An array containing all the droppable items from our interactive tree. 202 | * @property droppableItems 203 | * @type Array 204 | * @private 205 | */ 206 | this.droppableItems = []; 207 | 208 | /** 209 | * An array containing all the currently animated items. 210 | * @property tweeningItems 211 | * @type Array 212 | * @private 213 | */ 214 | this.tweeningItems = []; 215 | 216 | /** 217 | * @property boundTick 218 | * @type Function 219 | */ 220 | this.boundTick = this.tick.bind(this); 221 | 222 | /** 223 | * Is set to true when the ticker is running. 224 | * @property isTicking 225 | * @type Boolean 226 | */ 227 | this.isTicking = false; 228 | }; 229 | 230 | // constructor 231 | PIXI.DragAndDropManager.prototype.constructor = PIXI.DragAndDropManager; 232 | 233 | /** 234 | * @method clear 235 | * @private 236 | */ 237 | PIXI.DragAndDropManager.prototype.clear = function() 238 | { 239 | this.draggableItems.length = 0; 240 | this.droppableItems.length = 0; 241 | }; 242 | 243 | /** 244 | * Collects an draggable or droppable interactive child. 245 | * 246 | * @method collect 247 | * @param displayObject {DisplayObject} the displayObject to collect 248 | * @private 249 | */ 250 | PIXI.DragAndDropManager.prototype.collect = function(child) 251 | { 252 | if(child.__draggable) 253 | { 254 | this.draggableItems.push(child); 255 | } 256 | 257 | if(child.__droppable) 258 | { 259 | this.droppableItems.push(child); 260 | } 261 | }; 262 | 263 | /** 264 | * Is called when the mouse button is pressed on a draggable element. 265 | * 266 | * @method onDrag 267 | * @param item {displayObject} The draggable element. 268 | * @param mouse {Event} The DOM event of a mouse button being released. 269 | * @private 270 | */ 271 | PIXI.DragAndDropManager.prototype.onDrag = function(item, mouse) 272 | { 273 | 274 | var options = item.dragOptions; 275 | 276 | // check if revert animation running 277 | if(item.tweening || options.disabled) 278 | { 279 | item.__isDragging = false; 280 | return; 281 | } 282 | 283 | var i, child; 284 | 285 | // check for valid handle 286 | if (options.handle) 287 | { 288 | // labeled handle 289 | if(typeof options.handle === 'string') 290 | { 291 | var validHandle = false; 292 | 293 | // loop through children to find a valid handle 294 | for(i = item.children.length - 1; i >= 0; i--) 295 | { 296 | child = item.children[i]; 297 | if((child.label === options.handle || (child.__draggable && child.dragOptions.label === options.handle) || (child.__droppable && child.dropOptions.label === options.handle)) && item.stage.interactionManager.hitTest(child, mouse)) 298 | { 299 | validHandle = true; 300 | break; 301 | } 302 | } 303 | 304 | // stop drag if no valid handle found 305 | if(!validHandle) 306 | { 307 | item.__isDragging = false; 308 | return; 309 | } 310 | } 311 | 312 | // handle is sprite 313 | else if(!item.stage.interactionManager.hitTest(options.handle, mouse)) 314 | { 315 | item.__isDragging = false; 316 | return; 317 | } 318 | } 319 | 320 | // check for invalid cancel 321 | if(options.cancel) 322 | { 323 | // labeled cancel 324 | if(typeof options.cancel === 'string') 325 | { 326 | // loop through children to find a cancel 327 | for(i = item.children.length - 1; i >= 0; i--) 328 | { 329 | child = item.children[i]; 330 | if((child.label === options.cancel || (child.__draggable && child.dragOptions.label === options.cancel) || (child.__droppable && child.dropOptions.label === options.cancel)) && item.stage.interactionManager.hitTest(child, mouse)) 331 | { 332 | item.__isDragging = false; 333 | return; 334 | } 335 | } 336 | } 337 | 338 | // label is sprite 339 | else if(item.stage.interactionManager.hitTest(options.cancel, mouse)) 340 | { 341 | item.__isDragging = false; 342 | return; 343 | } 344 | } 345 | 346 | // get relative position 347 | if(options.cursorAt) 348 | { 349 | var local = mouse.getLocalPosition(item); 350 | item.offset.set(options.cursorAt[0] - local.x, options.cursorAt[1] - local.y); 351 | } 352 | else 353 | { 354 | //var local = mouse.getLocalPosition(item); 355 | //item.offset.set(local.x, local.y); 356 | item.offset.set(0, 0); 357 | } 358 | 359 | // get start position 360 | item.original.x = item.x; 361 | item.original.y = item.y; 362 | 363 | // define start x / y 364 | if(!mouse.start) 365 | { 366 | mouse.start = mouse.global.clone(); 367 | } 368 | else 369 | { 370 | mouse.start.x = mouse.global.x; 371 | mouse.start.y = mouse.global.y; 372 | } 373 | 374 | // check for opacity 375 | item.originalAlpha = item.alpha; 376 | }; 377 | 378 | /** 379 | * Is called when the mouse button is pressed on a draggable element and the mouse starts moving. 380 | * This is the first mousemove event for the draggable element. 381 | * 382 | * @method onDragStart 383 | * @param item {displayObject} The draggable element. 384 | * @param mouse {Event} The DOM event of a mouse button being released. 385 | * @private 386 | */ 387 | PIXI.DragAndDropManager.prototype.onDragStart = function(item, mouse) 388 | { 389 | var options = item.dragOptions; 390 | 391 | // verify the minimum drag distance 392 | if(Math.abs(mouse.start.x - mouse.global.x) < options.distance && Math.abs(mouse.start.y - mouse.global.y) < options.distance) 393 | { 394 | item.__dragStart = false; 395 | return; 396 | } 397 | 398 | // destroy prior used helper sprite 399 | this.destroyHelperSprite(item); 400 | 401 | // check for helper 402 | if(options.helper === 'clone') 403 | { 404 | item.dragElement = new PIXI.Sprite(item.generateTexture()); 405 | item.parent.addChild(item.dragElement); 406 | item.dragElement.position.set(item.x, item.y); 407 | item.dragElement.pivot.set(item.pivot.x, item.pivot.y); 408 | if(item.anchor) 409 | { 410 | item.dragElement.anchor.set(item.anchor.x, item.anchor.y); 411 | } 412 | 413 | // set helper interactive to carry over special pointers during move 414 | if(options.cursor !== 'inherit') 415 | { 416 | item.dragElement.interactive = true; 417 | } 418 | } 419 | else 420 | { 421 | item.dragElement = item; 422 | } 423 | 424 | // save default cursor 425 | item.dragElement._defaultCursor = item.dragElement.defaultCursor; 426 | item.dragElement.defaultCursor = options.cursor; 427 | item.dragElement._buttonMode = item.dragElement.buttonMode; 428 | item.dragElement.buttonMode = true; 429 | 430 | // set opacity 431 | item.dragElement.alpha = item.alpha * options.alpha; 432 | 433 | // check for snap feature 434 | if(options.snap) 435 | { 436 | var draggables = this.draggableItems, 437 | draggable, bounds; 438 | 439 | for(var i = draggables.length - 1; i >= 0; i--) 440 | { 441 | draggable = draggables[i]; 442 | if(draggable.worldVisible && (options.snap === true || options.snap === draggable.dragOptions.label) && draggable !== item) 443 | { 444 | bounds = draggable.hitArea ? draggable.hitArea : draggable.getBounds(); 445 | if(!draggable.snapBounds) 446 | { 447 | draggable.snapBounds = { 448 | x: bounds.x, 449 | y: bounds.y, 450 | x2: bounds.x + bounds.width, 451 | y2: bounds.y + bounds.height, 452 | dist: 0 453 | }; 454 | } 455 | else 456 | { 457 | draggable.snapBounds.x = bounds.x; 458 | draggable.snapBounds.y = bounds.y; 459 | draggable.snapBounds.x2 = bounds.x + bounds.width; 460 | draggable.snapBounds.y2 = bounds.y + bounds.height; 461 | } 462 | 463 | item.snapElements.push(draggable); 464 | } 465 | } 466 | } 467 | 468 | // call custom start callback 469 | if(options.start) 470 | { 471 | options.start(item, mouse); 472 | } 473 | }; 474 | 475 | /** 476 | * Is called when the mouse button is pressed on a draggable element and the mouse starts moving. 477 | * 478 | * @method onDragMove 479 | * @param item {displayObject} The draggable element. 480 | * @param mouse {Event} The DOM event of a mouse button being released. 481 | * @private 482 | */ 483 | PIXI.DragAndDropManager.prototype.onDragMove = (function() 484 | { 485 | 486 | function sqr(x) 487 | { 488 | return x * x; 489 | }; 490 | 491 | return function(item, mouse) 492 | { 493 | 494 | var options = item.dragOptions, 495 | mx = mouse.global.x, 496 | my = mouse.global.y, 497 | dx = mx - mouse.start.x, 498 | dy = my - mouse.start.y, 499 | x = item.original.x + dx - item.offset.x, 500 | y = item.original.y + dy - item.offset.y, 501 | x2 = x + item.width, 502 | y2 = y + item.height, 503 | containment, i; 504 | 505 | // check for containment 506 | if(options.containment) 507 | { 508 | if(options.containment === 'parent') 509 | { 510 | containment = /*item.parent.hitArea && item.parent.hitArea.contains ? item.parent.hitArea : */item.parent.getBounds(); 511 | } 512 | else 513 | { 514 | containment = (options.containment instanceof PIXI.Rectangle) ? options.containment : /*(options.containment.hitArea && options.containment.hitArea.contains ? options.containment.hitArea :*/ options.containment.getBounds();//); 515 | } 516 | 517 | // x bounds 518 | if(options.axis !== 'y') 519 | { 520 | if (x < 0) 521 | { 522 | x = 0; 523 | } 524 | else if (x2 > containment.width) 525 | { 526 | x = containment.width - item.width; 527 | } 528 | } 529 | 530 | // y bounds 531 | if(options.axis !== 'x') 532 | { 533 | if (y < 0) 534 | { 535 | y = 0; 536 | } 537 | else if (y2 > containment.height) 538 | { 539 | y = containment.height - item.height; 540 | } 541 | } 542 | } 543 | 544 | // check for grid elements 545 | if(options.grid) 546 | { 547 | var grid; 548 | 549 | // check x grid 550 | if(options.grid[0] && options.axis !== 'y') 551 | { 552 | grid = options.grid[0]; 553 | x = item.original.x + Math.round((x - item.original.x) / grid) * grid; 554 | if(containment && !(x > 0 || x2 < containment.width)) 555 | { 556 | x += (x > 0) ? -grid : grid; 557 | } 558 | } 559 | 560 | // check y grid 561 | if(options.grid[1] && options.axis !== 'x') 562 | { 563 | grid = options.grid[1]; 564 | y = item.original.y + Math.round((y - item.original.y) / grid) * grid; 565 | if(containment && !(y > 0 || y2 < containment.height)) 566 | { 567 | y += (y > 0) ? -grid : grid; 568 | } 569 | } 570 | } 571 | 572 | // check for snap feature 573 | if(options.snap) 574 | { 575 | var snapElement, 576 | snapped = false, 577 | d = options.snapTolerance, 578 | l, r, t, b, i; 579 | 580 | // sort elements closest -> optional, maybe too expensive sometimes 581 | if(options.snapSort) 582 | { 583 | var tx = item.worldTransform.tx + item.width/2; 584 | var ty = item.worldTransform.ty + item.height/2; 585 | 586 | for(i = item.snapElements.length - 1; i >= 0; i--) 587 | { 588 | snapElement = item.snapElements[i]; 589 | snapElement.snapBounds.dist = sqr(tx - snapElement.worldTransform.tx - snapElement.width/2) + sqr(ty - snapElement.worldTransform.ty - snapElement.height/2, 2); 590 | } 591 | 592 | item.snapElements.sort(this.closestSort); 593 | } 594 | 595 | // loop over all snap elements 596 | for(i = item.snapElements.length - 1; !snapped && i >= 0; i--) 597 | { 598 | snapElement = item.snapElements[i]; 599 | 600 | l = snapElement.snapBounds.x; 601 | r = snapElement.snapBounds.x2; 602 | t = snapElement.snapBounds.y; 603 | b = snapElement.snapBounds.y2; 604 | 605 | if(x2 > l - d && x < r + d && y2 > t - d && y < b + d) 606 | { 607 | if (options.snapMode !== 'inner') 608 | { 609 | if (Math.abs(t - y2) <= d) 610 | { 611 | y = t - item.height; 612 | snapped = true; 613 | } 614 | else if (Math.abs(b - y) <= d) 615 | { 616 | y = b; 617 | snapped = true; 618 | } 619 | if (Math.abs(l - x2) <= d) 620 | { 621 | x = l - item.width; 622 | snapped = true; 623 | } 624 | else if (Math.abs(r - x) <= d) 625 | { 626 | x = r; 627 | snapped = true; 628 | } 629 | } 630 | 631 | if (!snapped && options.snapMode !== 'outer') 632 | { 633 | if (Math.abs(t - y) <= d) 634 | { 635 | y = t; 636 | snapped = true; 637 | } 638 | else if (Math.abs(b - y2) <= d) 639 | { 640 | y = b - item.height; 641 | snapped = true; 642 | } 643 | if (Math.abs(l - x) <= d) 644 | { 645 | x = l; 646 | snapped = true; 647 | } 648 | else if (Math.abs(r - x2) <= d) 649 | { 650 | x = r - item.width; 651 | snapped = true; 652 | } 653 | } 654 | } 655 | } 656 | } 657 | 658 | // align along x axis 659 | if(options.axis === 'x') 660 | { 661 | item.dragElement.x = x; 662 | } 663 | 664 | // align along y axis 665 | else if(options.axis === 'y') 666 | { 667 | item.dragElement.y = y; 668 | } 669 | 670 | // both 671 | else 672 | { 673 | item.dragElement.x = x; 674 | item.dragElement.y = y; 675 | } 676 | 677 | // call custom drag callback 678 | if(options.drag) 679 | { 680 | options.drag(item, mouse); 681 | } 682 | 683 | // TODO: visual feedback for droppables 684 | }; 685 | 686 | })(); 687 | 688 | /** 689 | * Is called when the mouse button is released for a draggable element. 690 | * 691 | * @method onDrop 692 | * @param item {displayObject} The draggable element. 693 | * @param mouse {Event} The DOM event of a mouse button being released. 694 | * @private 695 | */ 696 | PIXI.DragAndDropManager.prototype.onDrop = function(item, mouse) 697 | { 698 | 699 | var options = item.dragOptions; 700 | 701 | // restore cursor 702 | item.dragElement.defaultCursor = item.dragElement._defaultCursor; 703 | item.dragElement.buttonMode = item.dragElement._buttonMode; 704 | 705 | // check droppables 706 | var droppables = this.droppableItems; 707 | var dropped = false; 708 | if(droppables.length) 709 | { 710 | // TODO: optimize. sort droppables by greedy, avoids the intersects array. is sort less expensive than an array? 711 | var intersects = [], 712 | droppable, 713 | accept, 714 | currBounds = item.dragElement.getBounds(), 715 | i, j; 716 | 717 | currBounds.x2 = currBounds.x + currBounds.width; 718 | currBounds.y2 = currBounds.y + currBounds.height; 719 | 720 | for(i = droppables.length - 1; i >= 0; i--) 721 | { 722 | droppable = droppables[i]; 723 | 724 | // skip invisible // same item // disabled 725 | if(!droppable.worldVisible || droppable === item || droppable.dropOptions.disabled) 726 | { 727 | continue; 728 | } 729 | accept = droppable.dropOptions.accept; 730 | 731 | // accept multiple kinds 732 | if(accept instanceof Array) 733 | { 734 | for(j = accept.length - 1; j >= 0; j--) 735 | { 736 | if(accept[j] === this || accept[j] === options.label) 737 | { 738 | if(this.intersect(item, mouse, droppable, currBounds)) 739 | { 740 | dropped = true; 741 | if(droppable.dropOptions.greedy) 742 | { 743 | intersects.length = 0; 744 | intersects.push(droppable); 745 | i = -1; // break droppables loop 746 | break; // break accept loop 747 | } 748 | else 749 | { 750 | intersects.push(droppable); 751 | } 752 | } 753 | } 754 | } 755 | } 756 | else if(accept === this || accept === options.label || accept === true) 757 | { 758 | if(this.intersect(item, mouse, droppable, currBounds)) 759 | { 760 | dropped = true; 761 | if(droppable.dropOptions.greedy) 762 | { 763 | intersects.length = 0; 764 | intersects.push(droppable); 765 | break; 766 | } 767 | else 768 | { 769 | intersects.push(droppable); 770 | } 771 | } 772 | } 773 | } 774 | 775 | // call drop on intersects 776 | for(i = intersects.length - 1; i >= 0; i--) 777 | { 778 | if(intersects[i].dropOptions.drop) 779 | { 780 | intersects[i].dropOptions.drop(item, mouse); 781 | } 782 | } 783 | } 784 | else 785 | { 786 | // if no droppables, drop is always true 787 | dropped = true; 788 | } 789 | 790 | // revert 791 | if ((options.revert === 'invalid' && !dropped) || (options.revert === 'valid' && dropped) || options.revert === true) 792 | { 793 | // TODO: better Tweening 794 | if(options.revertDuration) 795 | { 796 | // mark item as tweening 797 | item.tweening = true; 798 | 799 | // add to queue 800 | this.tweeningItems.push({ 801 | time: Date.now(), 802 | duration: options.revertDuration, 803 | item: item, 804 | mouse: mouse, 805 | x: item.dragElement.x, 806 | y: item.dragElement.y, 807 | dx: item.dragElement.x - item.original.x, 808 | dy: item.dragElement.y - item.original.y 809 | }); 810 | 811 | // if ticker is not running -> start it 812 | if(!this.isTicking) 813 | { 814 | this.isTicking = true; 815 | this.tick(); 816 | } 817 | } 818 | else 819 | { 820 | item.dragElement.x = item.original.x; 821 | item.dragElement.y = item.original.y; 822 | this.stop(item, mouse); 823 | } 824 | } 825 | else 826 | { 827 | if(item.dragElement !== item) 828 | { 829 | item.x = item.dragElement.x; 830 | item.y = item.dragElement.y; 831 | } 832 | this.stop(item, mouse); 833 | } 834 | 835 | // TODO: visual feedback for droppables 836 | }; 837 | 838 | /** 839 | * Tick emitter for revert tweening. 840 | * 841 | * @method tick 842 | * @private 843 | */ 844 | PIXI.DragAndDropManager.prototype.tick = function() 845 | { 846 | // stop ticker if no elements tweening 847 | var length = this.tweeningItems.length; 848 | if(!length) 849 | { 850 | this.isTicking = false; 851 | return; 852 | } 853 | 854 | // call next tick 855 | requestAnimationFrame(this.boundTick); 856 | 857 | var now = Date.now(), 858 | tween, elapsed, item; 859 | 860 | for(var i = length - 1; i >= 0; i--) 861 | { 862 | tween = this.tweeningItems[i]; 863 | elapsed = now - tween.time; 864 | item = tween.item; 865 | 866 | // tween is over 867 | if(elapsed >= tween.duration) 868 | { 869 | // stop tweening 870 | item.tweening = false; 871 | 872 | item.dragElement.x = item.original.x; 873 | item.dragElement.y = item.original.y; 874 | 875 | this.stop(item, tween.mouse); 876 | 877 | // remove item from list 878 | this.tweeningItems.splice(i,1); 879 | } 880 | else 881 | { 882 | item.dragElement.x = tween.x - tween.dx * elapsed / tween.duration; 883 | item.dragElement.y = tween.y - tween.dy * elapsed / tween.duration; 884 | } 885 | } 886 | }; 887 | 888 | /** 889 | * Is called when the drop process is over. 890 | * 891 | * @method stop 892 | * @param item {displayObject} A draggable element. 893 | * @param mouse {Event} The DOM event of a mouse. 894 | * @private 895 | */ 896 | PIXI.DragAndDropManager.prototype.stop = function(item, mouse) 897 | { 898 | // revert alpha 899 | item.dragElement.alpha = item.originalAlpha; 900 | 901 | // destroy helper sprite 902 | this.destroyHelperSprite(item); 903 | 904 | // reset snap elements array 905 | if(item.dragOptions.snap) 906 | { 907 | item.snapElements.length = 0; 908 | } 909 | 910 | // call custom stop callback 911 | if(item.dragOptions.stop) 912 | { 913 | item.dragOptions.stop(item, mouse); 914 | } 915 | }; 916 | 917 | /** 918 | * Is called when the draggable elements are sorted from close to far. 919 | * 920 | * @method closestSort 921 | * @param a {displayObject} A draggable element. 922 | * @param b {displayObject} A draggable element. 923 | * @private 924 | */ 925 | PIXI.DragAndDropManager.prototype.closestSort = function(a, b) 926 | { 927 | if(a.snapBounds.snapDist < b.snapBounds.snapDist) 928 | { 929 | return -1; 930 | } 931 | if(a.snapBounds.snapDist > b.snapBounds.snapDist) 932 | { 933 | return 1; 934 | } 935 | return 0; 936 | }; 937 | 938 | /** 939 | * Destroys the helper sprite. 940 | * 941 | * @method destroyHelperSprite 942 | * @private 943 | */ 944 | PIXI.DragAndDropManager.prototype.destroyHelperSprite = function(item) 945 | { 946 | // make sure it's a helper and not the original 947 | if(item.dragElement && item.dragElement !== item) 948 | { 949 | item.dragElement.parent.removeChild(item.dragElement); 950 | item.dragElement.texture.destroy(true); 951 | item.dragElement = null; // TODO: Maybe pooling? 952 | } 953 | }; 954 | 955 | /** 956 | * Is called when the draggable object is dropping. 957 | * 958 | * @method intersect 959 | * @param item {displayObject} The draggable element. 960 | * @param mouse {Event} The DOM event of a mouse. 961 | * @param droppable {displayObject} The droppable element. 962 | * @param currBounds {PIXI.Rectangle} The current bounds of the draggable element. 963 | * @private 964 | */ 965 | PIXI.DragAndDropManager.prototype.intersect = function(item, mouse, droppable, currBounds) 966 | { 967 | var bounds; 968 | switch(droppable.dropOptions.tolerance) 969 | { 970 | 971 | // the draggable object must be at least 50% over the target on both axes 972 | case 'intersect': 973 | bounds = droppable.getBounds(); 974 | return (bounds.x < currBounds.x + (currBounds.width/2) && currBounds.x2 - (currBounds.width/2) < bounds.x+bounds.width && bounds.y < currBounds.y + (currBounds.height/2) && currBounds.y2 - (currBounds.height/2) < bounds.y+bounds.height); 975 | 976 | // the draggable object must fit into the target 977 | case 'fit': 978 | bounds = droppable.getBounds(); 979 | return (bounds.x <= currBounds.x && currBounds.x2 <= bounds.x+bounds.width && bounds.y <= currBounds.y && currBounds.y2 <= bounds.y+bounds.height); 980 | 981 | // the mouse pointer must be inside the target 982 | case 'pointer': 983 | return item.stage.interactionManager.hitTest(droppable, mouse); 984 | 985 | // the draggable object must at least slightly touch the target 986 | case 'touch': 987 | bounds = droppable.getBounds(); 988 | return ( 989 | (currBounds.y >= bounds.y && currBounds.y <= bounds.y+bounds.height) || 990 | (currBounds.y2 >= bounds.y && currBounds.y2 <= bounds.y+bounds.height) || 991 | (currBounds.y < bounds.y && currBounds.y2 > bounds.y+bounds.height) 992 | ) && ( 993 | (currBounds.x >= bounds.x && currBounds.x <= bounds.x+bounds.width) || 994 | (currBounds.x2 >= bounds.x && currBounds.x2 <= bounds.x+bounds.width) || 995 | (currBounds.x < bounds.x && currBounds.x2 > bounds.x+bounds.width) 996 | ); 997 | 998 | // unsupported tolerance 999 | default: 1000 | return false; 1001 | } 1002 | }; 1003 | 1004 | /** 1005 | * Is called when the mouse button is pressed down on the draggable element. 1006 | * "this" refers to the draggable element. 1007 | * 1008 | * @static 1009 | * @method onMouseDown 1010 | * @param mouse {Event} The DOM event of a mouse button being pressed down. 1011 | * @private 1012 | */ 1013 | PIXI.DragAndDropManager.onMouseDown = function(mouse) 1014 | { 1015 | //var item = mouse.target; 1016 | 1017 | // regular event 1018 | if(this.dragOptions.mousedown) 1019 | { 1020 | this.dragOptions.mousedown(mouse); 1021 | } 1022 | 1023 | // item.__isDragging true to notify the other methods that this element is being dragged. 1024 | this.__isDragging = true; 1025 | this.stage.interactionManager.DragAndDropManager.onDrag(this, mouse); 1026 | }; 1027 | 1028 | /** 1029 | * Is called when the mouse moves across the draggable element. 1030 | * "this" refers to the draggable element. 1031 | * 1032 | * @static 1033 | * @method onMouseMove 1034 | * @param mouse {Event} The DOM event of the mouse moving. 1035 | * @private 1036 | */ 1037 | PIXI.DragAndDropManager.onMouseMove = function(mouse) 1038 | { 1039 | //var item = mouse.target; 1040 | 1041 | // regular event 1042 | if(this.dragOptions.mousemove) 1043 | { 1044 | this.dragOptions.mousemove(mouse); 1045 | } 1046 | 1047 | // item.__isDragging must be set true to emit drag move 1048 | if(this.__isDragging) 1049 | { 1050 | 1051 | // the first drag move 1052 | if(!this.__dragStart) 1053 | { 1054 | this.__dragStart = true; 1055 | this.stage.interactionManager.DragAndDropManager.onDragStart(this, mouse); 1056 | } 1057 | else 1058 | { 1059 | this.stage.interactionManager.DragAndDropManager.onDragMove(this, mouse); 1060 | } 1061 | } 1062 | }; 1063 | 1064 | /** 1065 | * Is called when the mouse button is released on the draggable element. 1066 | * "this" refers to the draggable element. 1067 | * 1068 | * @static 1069 | * @method onMouseUp 1070 | * @param mouse {Event} The DOM event of a mouse button being released. 1071 | * @private 1072 | */ 1073 | PIXI.DragAndDropManager.onMouseUp = function(mouse) 1074 | { 1075 | //var item = mouse.target; 1076 | 1077 | // regular event 1078 | if(this.dragOptions.mouseup) 1079 | { 1080 | this.dragOptions.mouseup(mouse); 1081 | } 1082 | 1083 | // item.__isDragging must be set true to emit drop 1084 | if(this.__isDragging) 1085 | { 1086 | this.__isDragging = false; 1087 | if(this.__dragStart) 1088 | { 1089 | this.__dragStart = false; 1090 | this.stage.interactionManager.DragAndDropManager.onDrop(this, mouse); 1091 | } 1092 | } 1093 | }; 1094 | 1095 | /** 1096 | * Is called when the mouse button is released outside the draggable element. 1097 | * "this" refers to the draggable element. 1098 | * 1099 | * @static 1100 | * @method onMouseUpOutside 1101 | * @param mouse {Event} The DOM event of a mouse button being released. 1102 | * @private 1103 | */ 1104 | PIXI.DragAndDropManager.onMouseUpOutside = function(mouse) 1105 | { 1106 | //var item = mouse.target; 1107 | 1108 | // regular event 1109 | if(this.dragOptions.mouseupoutside) 1110 | { 1111 | this.dragOptions.mouseupoutside(mouse); 1112 | } 1113 | 1114 | // check for drop! 1115 | if(this.__isDragging) 1116 | { 1117 | this.__isDragging = false; 1118 | if(this.__dragStart) 1119 | { 1120 | this.__dragStart = false; 1121 | this.stage.interactionManager.DragAndDropManager.onDrop(this, mouse); 1122 | } 1123 | } 1124 | }; 1125 | 1126 | // the default drag abd drop options 1127 | PIXI.DragAndDropManager.options = { 1128 | 1129 | drag: { 1130 | distance: 1, 1131 | axis: null, 1132 | containment: null, 1133 | cursor: 'inherit', 1134 | cursorAt: null, 1135 | grid: false, 1136 | handle: null, 1137 | cancel: null, 1138 | helper: 'original', 1139 | alpha: 1, 1140 | revert: false, 1141 | revertDuration: 500, 1142 | label: null, 1143 | snap: null, 1144 | snapMode: 'both', 1145 | snapSort: false, 1146 | snapTolerance: 20, 1147 | disabled: false, 1148 | 1149 | // special drag events 1150 | drag: null, 1151 | start: null, 1152 | stop: null, 1153 | 1154 | // regular mouse // tap events 1155 | mousedown: null, 1156 | mousemove: null, 1157 | mouseup: null, 1158 | mouseupoutside: null 1159 | }, 1160 | 1161 | drop: { 1162 | label: null, 1163 | drop: null, 1164 | accept: true, 1165 | greedy: false, 1166 | disabled: false, 1167 | tolerance: 'intersect' 1168 | } 1169 | }; 1170 | 1171 | /** 1172 | * We are hooking into the PIXI.InteractionManager to avoid core changes. 1173 | * This is pretty hacky. 1174 | * 1175 | * @method rebuildInteractiveGraph 1176 | * @private 1177 | */ 1178 | PIXI.InteractionManager.prototype.rebuildInteractiveGraph = (function() 1179 | { 1180 | 1181 | // store previously set PIXI.InteractionManager.prototype.rebuildInteractiveGraph 1182 | var rebuildInteractiveGraph = PIXI.InteractionManager.prototype.rebuildInteractiveGraph; 1183 | 1184 | return function() 1185 | { 1186 | 1187 | // make sure the InteractionManager has a DragAndDropManager attached. 1188 | if(!this.DragAndDropManager) 1189 | { 1190 | // create a brand new instance 1191 | this.DragAndDropManager = new PIXI.DragAndDropManager(); 1192 | } 1193 | else 1194 | { 1195 | // clear the old draggable and droppable tree. 1196 | this.DragAndDropManager.clear(); 1197 | } 1198 | 1199 | // call original PIXI.InteractionManager.prototype.rebuildInteractiveGraph 1200 | rebuildInteractiveGraph.call(this); 1201 | 1202 | // collect draggables & droppables from the interactive tree. 1203 | for(var i = this.interactiveItems.length - 1; i >= 0; i--) 1204 | { 1205 | this.DragAndDropManager.collect(this.interactiveItems[i]); 1206 | } 1207 | }; 1208 | })(); 1209 | -------------------------------------------------------------------------------- /bin/pixi.draggable.min.js: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2014 Sebastian Nette 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 | * 25 | * 26 | */ 27 | 28 | /** 29 | * PIXI Draggables & Droppables v1.0.0 30 | * Copyright (c) 2014, Sebastian Nette 31 | * http://www.mokgames.com/ 32 | */ 33 | 34 | PIXI.DisplayObject.prototype.draggable=function(t,e){if(void 0==e&&null===t)this.__draggable=!1,this.mousedown=this.touchstart=n.mousedown,this.mousemove=this.touchmove=n.mousemove,this.mouseup=this.touchend=n.mouseup,this.mouseupoutside=this.touchendoutside=n.mouseupoutside,this.interactive=!0 35 | else if(void 0===e){this.__draggable&&this.draggable(null) 36 | var n=t||{} 37 | for(var a in PIXI.DragAndDropManager.options.drag)n.hasOwnProperty(a)||(n[a]=PIXI.DragAndDropManager.options.drag[a]) 38 | this.mousedown&&!n.mousedown&&(n.mousedown=this.mousedown),this.mousemove&&!n.mousemove&&(n.mousemove=this.mousemove),this.mouseup&&!n.mouseup&&(n.mouseup=this.mouseup),this.mouseupoutside&&!n.mouseupoutside&&(n.mouseupoutside=this.mouseupoutside),this.dragOptions=n,this.offset=new PIXI.Point(0,0),this.original=new PIXI.Point(0,0),n.snap&&(this.snapElements=[]),this.interactive=!0,this.__draggable=!0,this.mousedown=this.touchstart=PIXI.DragAndDropManager.onMouseDown.bind(this),this.mousemove=this.touchmove=PIXI.DragAndDropManager.onMouseMove.bind(this),this.mouseup=this.touchend=PIXI.DragAndDropManager.onMouseUp.bind(this),this.mouseupoutside=this.touchendoutside=PIXI.DragAndDropManager.onMouseUpOutside.bind(this)}else this.dragOptions&&(this.__draggable||this.draggable(),this.dragOptions[t]=e,"snap"===t&&e&&(this.snapElements=[])) 39 | return this},PIXI.DisplayObject.prototype.droppable=function(t,e){if(void 0==e&&null===t)this.__droppable=!1,this.interactive=!0 40 | else if(void 0===e){var n=t||{} 41 | for(var a in PIXI.DragAndDropManager.options.drop)n.hasOwnProperty(a)||(n[a]=PIXI.DragAndDropManager.options.drop[a]) 42 | this.dropOptions=n,this.interactive=!0,this.__droppable=!0}else this.dropOptions&&(this.__droppable||this.droppable(),this.dropOptions[t]=e) 43 | return this},PIXI.DragAndDropManager=function(){this.draggableItems=[],this.droppableItems=[],this.tweeningItems=[],this.boundTick=this.tick.bind(this),this.isTicking=!1},PIXI.DragAndDropManager.prototype.constructor=PIXI.DragAndDropManager,PIXI.DragAndDropManager.prototype.clear=function(){this.draggableItems.length=0,this.droppableItems.length=0},PIXI.DragAndDropManager.prototype.collect=function(t){t.__draggable&&this.draggableItems.push(t),t.__droppable&&this.droppableItems.push(t)},PIXI.DragAndDropManager.prototype.onDrag=function(t,e){var n=t.dragOptions 44 | if(t.tweening||n.disabled)return void(t.__isDragging=!1) 45 | var a,r 46 | if(n.handle)if("string"==typeof n.handle){var i=!1 47 | for(a=t.children.length-1;a>=0;a--)if(r=t.children[a],(r.label===n.handle||r.__draggable&&r.dragOptions.label===n.handle||r.__droppable&&r.dropOptions.label===n.handle)&&t.stage.interactionManager.hitTest(r,e)){i=!0 48 | break}if(!i)return void(t.__isDragging=!1)}else if(!t.stage.interactionManager.hitTest(n.handle,e))return void(t.__isDragging=!1) 49 | if(n.cancel)if("string"==typeof n.cancel){for(a=t.children.length-1;a>=0;a--)if(r=t.children[a],(r.label===n.cancel||r.__draggable&&r.dragOptions.label===n.cancel||r.__droppable&&r.dropOptions.label===n.cancel)&&t.stage.interactionManager.hitTest(r,e))return void(t.__isDragging=!1)}else if(t.stage.interactionManager.hitTest(n.cancel,e))return void(t.__isDragging=!1) 50 | if(n.cursorAt){var o=e.getLocalPosition(t) 51 | t.offset.set(n.cursorAt[0]-o.x,n.cursorAt[1]-o.y)}else t.offset.set(0,0) 52 | t.original.x=t.x,t.original.y=t.y,e.start?(e.start.x=e.global.x,e.start.y=e.global.y):e.start=e.global.clone(),t.originalAlpha=t.alpha},PIXI.DragAndDropManager.prototype.onDragStart=function(t,e){var n=t.dragOptions 53 | if(Math.abs(e.start.x-e.global.x)=0;o--)a=i[o],!a.worldVisible||n.snap!==!0&&n.snap!==a.dragOptions.label||a===t||(r=a.hitArea?a.hitArea:a.getBounds(),a.snapBounds?(a.snapBounds.x=r.x,a.snapBounds.y=r.y,a.snapBounds.x2=r.x+r.width,a.snapBounds.y2=r.y+r.height):a.snapBounds={x:r.x,y:r.y,x2:r.x+r.width,y2:r.y+r.height,dist:0},t.snapElements.push(a)) 55 | n.start&&n.start(t,e)},PIXI.DragAndDropManager.prototype.onDragMove=function(){function t(t){return t*t}return function(e,n){var a,r,i=e.dragOptions,o=n.global.x,s=n.global.y,g=o-n.start.x,d=s-n.start.y,l=e.original.x+g-e.offset.x,p=e.original.y+d-e.offset.y,h=l+e.width,u=p+e.height 56 | if(i.containment&&(a="parent"===i.containment?e.parent.getBounds():i.containment instanceof PIXI.Rectangle?i.containment:i.containment.getBounds(),"y"!==i.axis&&(0>l?l=0:h>a.width&&(l=a.width-e.width)),"x"!==i.axis&&(0>p?p=0:u>a.height&&(p=a.height-e.height))),i.grid){var m 57 | i.grid[0]&&"y"!==i.axis&&(m=i.grid[0],l=e.original.x+Math.round((l-e.original.x)/m)*m,a&&!(l>0||h0?-m:m)),i.grid[1]&&"x"!==i.axis&&(m=i.grid[1],p=e.original.y+Math.round((p-e.original.y)/m)*m,a&&!(p>0||u0?-m:m))}if(i.snap){var c,D,y,I,f,r,M=!1,b=i.snapTolerance 58 | if(i.snapSort){var x=e.worldTransform.tx+e.width/2,v=e.worldTransform.ty+e.height/2 59 | for(r=e.snapElements.length-1;r>=0;r--)c=e.snapElements[r],c.snapBounds.dist=t(x-c.worldTransform.tx-c.width/2)+t(v-c.worldTransform.ty-c.height/2,2) 60 | e.snapElements.sort(this.closestSort)}for(r=e.snapElements.length-1;!M&&r>=0;r--)c=e.snapElements[r],D=c.snapBounds.x,y=c.snapBounds.x2,I=c.snapBounds.y,f=c.snapBounds.y2,h>D-b&&y+b>l&&u>I-b&&f+b>p&&("inner"!==i.snapMode&&(Math.abs(I-u)<=b?(p=I-e.height,M=!0):Math.abs(f-p)<=b&&(p=f,M=!0),Math.abs(D-h)<=b?(l=D-e.width,M=!0):Math.abs(y-l)<=b&&(l=y,M=!0)),M||"outer"===i.snapMode||(Math.abs(I-p)<=b?(p=I,M=!0):Math.abs(f-u)<=b&&(p=f-e.height,M=!0),Math.abs(D-l)<=b?(l=D,M=!0):Math.abs(y-h)<=b&&(l=y-e.width,M=!0)))}"x"===i.axis?e.dragElement.x=l:"y"===i.axis?e.dragElement.y=p:(e.dragElement.x=l,e.dragElement.y=p),i.drag&&i.drag(e,n)}}(),PIXI.DragAndDropManager.prototype.onDrop=function(t,e){var n=t.dragOptions 61 | t.dragElement.defaultCursor=t.dragElement._defaultCursor,t.dragElement.buttonMode=t.dragElement._buttonMode 62 | var a=this.droppableItems,r=!1 63 | if(a.length){var i,o,s,g,d=[],l=t.dragElement.getBounds() 64 | for(l.x2=l.x+l.width,l.y2=l.y+l.height,s=a.length-1;s>=0;s--)if(i=a[s],i.worldVisible&&i!==t&&!i.dropOptions.disabled)if(o=i.dropOptions.accept,o instanceof Array){for(g=o.length-1;g>=0;g--)if((o[g]===this||o[g]===n.label)&&this.intersect(t,e,i,l)){if(r=!0,i.dropOptions.greedy){d.length=0,d.push(i),s=-1 65 | break}d.push(i)}}else if((o===this||o===n.label||o===!0)&&this.intersect(t,e,i,l)){if(r=!0,i.dropOptions.greedy){d.length=0,d.push(i) 66 | break}d.push(i)}for(s=d.length-1;s>=0;s--)d[s].dropOptions.drop&&d[s].dropOptions.drop(t,e)}else r=!0 67 | "invalid"===n.revert&&!r||"valid"===n.revert&&r||n.revert===!0?n.revertDuration?(t.tweening=!0,this.tweeningItems.push({time:Date.now(),duration:n.revertDuration,item:t,mouse:e,x:t.dragElement.x,y:t.dragElement.y,dx:t.dragElement.x-t.original.x,dy:t.dragElement.y-t.original.y}),this.isTicking||(this.isTicking=!0,this.tick())):(t.dragElement.x=t.original.x,t.dragElement.y=t.original.y,this.stop(t,e)):(t.dragElement!==t&&(t.x=t.dragElement.x,t.y=t.dragElement.y),this.stop(t,e))},PIXI.DragAndDropManager.prototype.tick=function(){var t=this.tweeningItems.length 68 | if(!t)return void(this.isTicking=!1) 69 | requestAnimationFrame(this.boundTick) 70 | for(var e,n,a,r=Date.now(),i=t-1;i>=0;i--)e=this.tweeningItems[i],n=r-e.time,a=e.item,n>=e.duration?(a.tweening=!1,a.dragElement.x=a.original.x,a.dragElement.y=a.original.y,this.stop(a,e.mouse),this.tweeningItems.splice(i,1)):(a.dragElement.x=e.x-e.dx*n/e.duration,a.dragElement.y=e.y-e.dy*n/e.duration)},PIXI.DragAndDropManager.prototype.stop=function(t,e){t.dragElement.alpha=t.originalAlpha,this.destroyHelperSprite(t),t.dragOptions.snap&&(t.snapElements.length=0),t.dragOptions.stop&&t.dragOptions.stop(t,e)},PIXI.DragAndDropManager.prototype.closestSort=function(t,e){return t.snapBounds.snapDiste.snapBounds.snapDist?1:0},PIXI.DragAndDropManager.prototype.destroyHelperSprite=function(t){t.dragElement&&t.dragElement!==t&&(t.dragElement.parent.removeChild(t.dragElement),t.dragElement.texture.destroy(!0),t.dragElement=null)},PIXI.DragAndDropManager.prototype.intersect=function(t,e,n,a){var r 71 | switch(n.dropOptions.tolerance){case"intersect":return r=n.getBounds(),r.x=r.y&&a.y<=r.y+r.height||a.y2>=r.y&&a.y2<=r.y+r.height||a.yr.y+r.height)&&(a.x>=r.x&&a.x<=r.x+r.width||a.x2>=r.x&&a.x2<=r.x+r.width||a.xr.x+r.width) 75 | default:return!1}},PIXI.DragAndDropManager.onMouseDown=function(t){this.dragOptions.mousedown&&this.dragOptions.mousedown(t),this.__isDragging=!0,this.stage.interactionManager.DragAndDropManager.onDrag(this,t)},PIXI.DragAndDropManager.onMouseMove=function(t){this.dragOptions.mousemove&&this.dragOptions.mousemove(t),this.__isDragging&&(this.__dragStart?this.stage.interactionManager.DragAndDropManager.onDragMove(this,t):(this.__dragStart=!0,this.stage.interactionManager.DragAndDropManager.onDragStart(this,t)))},PIXI.DragAndDropManager.onMouseUp=function(t){this.dragOptions.mouseup&&this.dragOptions.mouseup(t),this.__isDragging&&(this.__isDragging=!1,this.__dragStart&&(this.__dragStart=!1,this.stage.interactionManager.DragAndDropManager.onDrop(this,t)))},PIXI.DragAndDropManager.onMouseUpOutside=function(t){this.dragOptions.mouseupoutside&&this.dragOptions.mouseupoutside(t),this.__isDragging&&(this.__isDragging=!1,this.__dragStart&&(this.__dragStart=!1,this.stage.interactionManager.DragAndDropManager.onDrop(this,t)))},PIXI.DragAndDropManager.options={drag:{distance:1,axis:null,containment:null,cursor:"inherit",cursorAt:null,grid:!1,handle:null,cancel:null,helper:"original",alpha:1,revert:!1,revertDuration:500,label:null,snap:null,snapMode:"both",snapSort:!1,snapTolerance:20,disabled:!1,drag:null,start:null,stop:null,mousedown:null,mousemove:null,mouseup:null,mouseupoutside:null},drop:{label:null,drop:null,accept:!0,greedy:!1,disabled:!1,tolerance:"intersect"}},PIXI.InteractionManager.prototype.rebuildInteractiveGraph=function(){var t=PIXI.InteractionManager.prototype.rebuildInteractiveGraph 76 | return function(){this.DragAndDropManager?this.DragAndDropManager.clear():this.DragAndDropManager=new PIXI.DragAndDropManager,t.call(this) 77 | for(var e=this.interactiveItems.length-1;e>=0;e--)this.DragAndDropManager.collect(this.interactiveItems[e])}}(); 78 | --------------------------------------------------------------------------------