├── 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 |
--------------------------------------------------------------------------------