| 
									
										
										
										
											2019-08-04 13:31:51 -07:00
										 |  |  | <div class="draggable-area {draggableClassAfterRaf}" | 
					
						
							|  |  |  |      on:pointerMove="onPointerMove(event)" | 
					
						
							|  |  |  |      on:pointerLeave="onPointerLeave(event)" | 
					
						
							|  |  |  |      on:pointerUp="onPointerUp(event)" | 
					
						
							| 
									
										
										
										
											2019-07-07 00:14:19 -07:00
										 |  |  |      on:click="onClick(event)" | 
					
						
							|  |  |  |      ref:area | 
					
						
							|  |  |  | > | 
					
						
							| 
									
										
										
										
											2019-08-04 13:31:51 -07:00
										 |  |  |   <div class="draggable-indicator {indicatorClassAfterRaf}" | 
					
						
							|  |  |  |        style={indicatorStyleAfterRaf} | 
					
						
							|  |  |  |        on:pointerDown="onPointerDown(event)" | 
					
						
							| 
									
										
										
										
											2019-07-07 00:14:19 -07:00
										 |  |  |        ref:indicator | 
					
						
							|  |  |  |   > | 
					
						
							|  |  |  |     <div class="draggable-indicator-inner"> | 
					
						
							|  |  |  |       <slot></slot> | 
					
						
							|  |  |  |     </div> | 
					
						
							|  |  |  |   </div> | 
					
						
							|  |  |  | </div> | 
					
						
							|  |  |  | <style> | 
					
						
							|  |  |  |   .draggable-area { | 
					
						
							|  |  |  |     position: relative; | 
					
						
							|  |  |  |     touch-action: none; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   .draggable-indicator { | 
					
						
							|  |  |  |     position: absolute; | 
					
						
							|  |  |  |     cursor: pointer; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   .draggable-indicator-inner { | 
					
						
							|  |  |  |     pointer-events: none; | 
					
						
							|  |  |  |     display: flex; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | </style> | 
					
						
							|  |  |  | <script> | 
					
						
							| 
									
										
										
										
											2019-08-04 13:31:51 -07:00
										 |  |  |   import { observe } from 'svelte-extras' | 
					
						
							| 
									
										
										
										
											2019-08-07 20:38:01 -07:00
										 |  |  |   import { throttleTimer } from '../_utils/throttleTimer' | 
					
						
							| 
									
										
										
										
											2019-08-04 13:31:51 -07:00
										 |  |  |   import { pointerUp, pointerDown, pointerLeave, pointerMove } from '../_utils/pointerEvents' | 
					
						
							| 
									
										
										
										
											2019-08-07 20:38:01 -07:00
										 |  |  |   import { requestPostAnimationFrame } from '../_utils/requestPostAnimationFrame' | 
					
						
							| 
									
										
										
										
											2019-08-04 13:31:51 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |   // ensure DOM writes only happen once after a rAF | 
					
						
							| 
									
										
										
										
											2019-08-07 20:38:01 -07:00
										 |  |  |   const updateIndicatorStyle = throttleTimer(requestAnimationFrame) | 
					
						
							|  |  |  |   const updateIndicatorClass = throttleTimer(requestAnimationFrame) | 
					
						
							|  |  |  |   const updateDraggableClass = throttleTimer(requestAnimationFrame) | 
					
						
							| 
									
										
										
										
											2019-08-04 13:31:51 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |   // ensure DOM reads only happen once after a rPAF | 
					
						
							| 
									
										
										
										
											2019-08-07 20:38:01 -07:00
										 |  |  |   const calculateGBCR = throttleTimer(requestPostAnimationFrame) | 
					
						
							| 
									
										
										
										
											2019-07-07 00:14:19 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |   const clamp = x => Math.max(0, Math.min(1, x)) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   export default { | 
					
						
							| 
									
										
										
										
											2019-08-04 13:31:51 -07:00
										 |  |  |     oncreate () { | 
					
						
							|  |  |  |       this.observe('dragging', dragging => { | 
					
						
							|  |  |  |         if (dragging) { | 
					
						
							|  |  |  |           this.fire('dragStart') | 
					
						
							|  |  |  |         } else { | 
					
						
							| 
									
										
										
										
											2019-08-07 20:38:01 -07:00
										 |  |  |           const { x, y } = this.get() | 
					
						
							| 
									
										
										
										
											2019-08-04 13:31:51 -07:00
										 |  |  |           this.fire('dragEnd') | 
					
						
							| 
									
										
										
										
											2019-08-07 20:38:01 -07:00
										 |  |  |           this.fire('change', { x, y }) | 
					
						
							| 
									
										
										
										
											2019-08-04 13:31:51 -07:00
										 |  |  |         } | 
					
						
							|  |  |  |       }, { init: false }) | 
					
						
							|  |  |  |       this.observe('indicatorStyle', indicatorStyle => { | 
					
						
							|  |  |  |         console.log('Draggable indicatorStyle', indicatorStyle) | 
					
						
							|  |  |  |         updateIndicatorStyle(() => { | 
					
						
							|  |  |  |           this.set({ indicatorStyleAfterRaf: indicatorStyle }) | 
					
						
							|  |  |  |         }) | 
					
						
							|  |  |  |       }) | 
					
						
							|  |  |  |       this.observe('indicatorClass', indicatorClass => { | 
					
						
							|  |  |  |         updateIndicatorClass(() => { | 
					
						
							|  |  |  |           this.set(({ indicatorClassAfterRaf: indicatorClass })) | 
					
						
							|  |  |  |         }) | 
					
						
							|  |  |  |       }) | 
					
						
							|  |  |  |       this.observe('draggableClass', draggableClass => { | 
					
						
							|  |  |  |         updateDraggableClass(() => { | 
					
						
							|  |  |  |           this.set({ draggableClassAfterRaf: draggableClass }) | 
					
						
							|  |  |  |         }) | 
					
						
							|  |  |  |       }) | 
					
						
							|  |  |  |     }, | 
					
						
							| 
									
										
										
										
											2019-07-07 00:14:19 -07:00
										 |  |  |     data: () => ({ | 
					
						
							| 
									
										
										
										
											2019-08-04 13:31:51 -07:00
										 |  |  |       dragging: false, | 
					
						
							| 
									
										
										
										
											2019-07-07 00:14:19 -07:00
										 |  |  |       draggableClass: '', | 
					
						
							| 
									
										
										
										
											2019-08-04 13:31:51 -07:00
										 |  |  |       draggableClassAfterRaf: '', | 
					
						
							| 
									
										
										
										
											2019-07-07 00:14:19 -07:00
										 |  |  |       indicatorClass: '', | 
					
						
							| 
									
										
										
										
											2019-08-04 13:31:51 -07:00
										 |  |  |       indicatorClassAfterRaf: '', | 
					
						
							| 
									
										
										
										
											2019-07-07 00:14:19 -07:00
										 |  |  |       x: 0, | 
					
						
							|  |  |  |       y: 0, | 
					
						
							|  |  |  |       indicatorWidth: 0, | 
					
						
							| 
									
										
										
										
											2019-08-04 13:31:51 -07:00
										 |  |  |       indicatorHeight: 0, | 
					
						
							|  |  |  |       indicatorStyleAfterRaf: '' | 
					
						
							| 
									
										
										
										
											2019-07-07 00:14:19 -07:00
										 |  |  |     }), | 
					
						
							|  |  |  |     computed: { | 
					
						
							|  |  |  |       indicatorStyle: ({ x, y, indicatorWidth, indicatorHeight }) => ( | 
					
						
							|  |  |  |         `left: calc(${x * 100}% - ${indicatorWidth / 2}px); top: calc(${y * 100}% - ${indicatorHeight / 2}px);` | 
					
						
							|  |  |  |       ) | 
					
						
							|  |  |  |     }, | 
					
						
							|  |  |  |     methods: { | 
					
						
							| 
									
										
										
										
											2019-08-04 13:31:51 -07:00
										 |  |  |       observe, | 
					
						
							| 
									
										
										
										
											2019-07-07 00:14:19 -07:00
										 |  |  |       onPointerDown (e) { | 
					
						
							| 
									
										
										
										
											2019-08-04 13:31:51 -07:00
										 |  |  |         console.log('Draggable: onPointerDown') | 
					
						
							| 
									
										
										
										
											2019-08-03 13:49:37 -07:00
										 |  |  |         const rect = this.refs.indicator.getBoundingClientRect() | 
					
						
							| 
									
										
										
										
											2019-08-04 13:31:51 -07:00
										 |  |  |         console.log('Draggable: e.clientX', e.clientX) | 
					
						
							|  |  |  |         console.log('Draggable: e.clientY', e.clientY) | 
					
						
							| 
									
										
										
										
											2019-07-07 00:14:19 -07:00
										 |  |  |         this.set({ | 
					
						
							|  |  |  |           dragging: true, | 
					
						
							|  |  |  |           dragOffsetX: e.clientX - rect.left, | 
					
						
							|  |  |  |           dragOffsetY: e.clientY - rect.top | 
					
						
							|  |  |  |         }) | 
					
						
							|  |  |  |       }, | 
					
						
							|  |  |  |       onPointerMove (e) { | 
					
						
							| 
									
										
										
										
											2019-08-04 13:31:51 -07:00
										 |  |  |         console.log('Draggable: onPointerMove') | 
					
						
							|  |  |  |         const { dragging, indicatorWidth, indicatorHeight, dragOffsetX, dragOffsetY } = this.get() | 
					
						
							|  |  |  |         if (dragging) { | 
					
						
							|  |  |  |           console.log('Draggable: dragging') | 
					
						
							|  |  |  |           calculateGBCR(() => { | 
					
						
							| 
									
										
										
										
											2019-08-03 13:49:37 -07:00
										 |  |  |             const rect = this.refs.area.getBoundingClientRect() | 
					
						
							|  |  |  |             const offsetX = dragOffsetX - (indicatorWidth / 2) | 
					
						
							|  |  |  |             const offsetY = dragOffsetY - (indicatorHeight / 2) | 
					
						
							|  |  |  |             const x = clamp((e.clientX - rect.left - offsetX) / rect.width) | 
					
						
							|  |  |  |             const y = clamp((e.clientY - rect.top - offsetY) / rect.height) | 
					
						
							| 
									
										
										
										
											2019-07-07 00:14:19 -07:00
										 |  |  |             this.set({ x, y }) | 
					
						
							|  |  |  |           }) | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       }, | 
					
						
							|  |  |  |       onPointerUp (e) { | 
					
						
							| 
									
										
										
										
											2019-08-04 13:31:51 -07:00
										 |  |  |         console.log('Draggable: onPointerUp') | 
					
						
							| 
									
										
										
										
											2019-07-07 00:14:19 -07:00
										 |  |  |         this.set({ dragging: false }) | 
					
						
							|  |  |  |       }, | 
					
						
							|  |  |  |       onPointerLeave (e) { | 
					
						
							| 
									
										
										
										
											2019-08-04 13:31:51 -07:00
										 |  |  |         console.log('Draggable: onPointerLeave') | 
					
						
							| 
									
										
										
										
											2019-07-07 00:14:19 -07:00
										 |  |  |         this.set({ dragging: false }) | 
					
						
							|  |  |  |       }, | 
					
						
							|  |  |  |       onClick (e) { | 
					
						
							| 
									
										
										
										
											2019-08-04 13:31:51 -07:00
										 |  |  |         console.log('Draggable: onClick') | 
					
						
							|  |  |  |         console.log('Draggable: target classList', e.target.classList) | 
					
						
							|  |  |  |         console.log('Draggable: currentTarget classList', e.currentTarget.classList) | 
					
						
							| 
									
										
										
										
											2019-07-07 00:14:19 -07:00
										 |  |  |         if (!e.target.classList.contains('draggable-indicator')) { | 
					
						
							| 
									
										
										
										
											2019-08-04 13:31:51 -07:00
										 |  |  |           console.log('Draggable: onClick handled') | 
					
						
							| 
									
										
										
										
											2019-08-03 13:49:37 -07:00
										 |  |  |           const rect = this.refs.area.getBoundingClientRect() | 
					
						
							|  |  |  |           const x = clamp((e.clientX - rect.left) / rect.width) | 
					
						
							|  |  |  |           const y = clamp((e.clientY - rect.top) / rect.height) | 
					
						
							| 
									
										
										
										
											2019-07-07 00:14:19 -07:00
										 |  |  |           this.set({ x, y }) | 
					
						
							|  |  |  |           this.fire('change', { x, y }) | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       } | 
					
						
							| 
									
										
										
										
											2019-08-04 13:31:51 -07:00
										 |  |  |     }, | 
					
						
							|  |  |  |     events: { | 
					
						
							|  |  |  |       pointerUp, | 
					
						
							|  |  |  |       pointerDown, | 
					
						
							|  |  |  |       pointerLeave, | 
					
						
							|  |  |  |       pointerMove | 
					
						
							| 
									
										
										
										
											2019-07-07 00:14:19 -07:00
										 |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | </script> |