Created
July 9, 2021 12:20
-
-
Save rikschennink/abee3b11fd39e93f0662c2ed88c6ddcd to your computer and use it in GitHub Desktop.
A script to simulate pointer events, very specific to Pintura project so might need some customisation to work with yours
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
const DEBUG = false; | |
const style = document.createElement('style'); | |
style.textContent = ` | |
.sim-pointer { | |
margin-top: -1px; | |
position: absolute; | |
z-index: 9999999999999; | |
left: -24px; | |
top: -24px; | |
width: 48px; | |
height: 48px; | |
border-radius: 24px; | |
line-height: 48px; | |
text-align: center; | |
user-select: none; | |
font-weight: bold; | |
font-family: monospace; | |
color: rgba(0, 0, 0, 0.75); | |
transition: background-color .15s, color .15s, box-shadow .15s; | |
background-color: rgba(255, 255, 255, 0.5); | |
backdrop-filter: saturate(180%) blur(10px); | |
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.75); | |
} | |
.sim-pointer::after { | |
content:''; | |
position: absolute; | |
left: -16px; | |
top: -16px; | |
bottom:-16px; | |
right: -16px; | |
background: transparent; | |
border-radius: inherit; | |
} | |
.sim-pointer[data-active='true'] { | |
margin-top: 0; | |
color: #514a0c; | |
background-color: rgba(255, 235, 50, 0.7); | |
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.25), 0 0 8px rgba(255, 235, 50, 0.5); | |
} | |
`; | |
document.body.appendChild(style); | |
let activeCounter = 0; | |
let offset = 10000000000; | |
let id = 1; | |
let target; | |
const dispatch = function (target, position, id, type) { | |
const event = new UIEvent(type, { | |
view: window, | |
bubbles: true, | |
cancelable: true, | |
}); | |
const props = { | |
pointerId: offset + id, | |
clientX: position.x, | |
clientY: position.y, | |
pageX: position.x, | |
pageY: position.y, | |
isPrimary: id === 1, | |
button: 0, | |
simulated: true, | |
}; | |
Object.keys(props).forEach(function (key) { | |
Object.defineProperty(event, key, { | |
value: props[key], | |
writable: false, | |
}); | |
}); | |
DEBUG && console.log('sim: pointer dispatch', type, event); | |
target.dispatchEvent(event); | |
}; | |
const pointerblock = function (e) { | |
if (e.simulated) return; | |
e.stopPropagation(); | |
e.preventDefault(); | |
}; | |
const pointerselect = function (e) { | |
const node = e.target; | |
if (node.pointerActive) { | |
DEBUG && console.log('sim: pointer deselect'); | |
activeCounter--; | |
node.pointerActive = false; | |
// set inactive style | |
node.dataset.active = false; | |
// now pointer up | |
dispatch(node.pointerTarget, node.pointerPosition, node.pointerId, 'pointerup'); | |
// unblock events, need to do this when no pointers | |
if (activeCounter === 0) { | |
document.documentElement.removeEventListener('pointermove', pointerblock, true); | |
document.documentElement.removeEventListener('pointercancel', pointerblock, true); | |
document.documentElement.removeEventListener('pointerup', pointerblock, true); | |
} | |
} else { | |
DEBUG && console.log('sim: pointer select'); | |
activeCounter++; | |
node.pointerActive = true; | |
node.dataset.active = true; | |
document.documentElement.addEventListener('pointermove', pointerblock, true); | |
document.documentElement.addEventListener('pointercancel', pointerblock, true); | |
document.documentElement.addEventListener('pointerup', pointerblock, true); | |
// get target below pointer | |
node.style.display = 'none'; | |
node.pointerTarget = document.elementFromPoint(e.pageX, e.pageY); | |
node.style.display = ''; | |
node.pointerTarget.setPointerCapture = function (id) {}; | |
node.pointerTarget.releasePointerCapture = function (id) {}; | |
// now pointerdown | |
dispatch(node.pointerTarget, node.pointerPosition, node.pointerId, 'pointerdown'); | |
} | |
}; | |
window.pointercreate = function (x, y) { | |
const node = document.createElement('div'); | |
node.className = 'sim-pointer'; | |
node.pointerId = id++; | |
node.pointerPosition = { x, y }; | |
node.textContent = node.pointerId; | |
node.style.transform = `translate3d(${x}px, ${y}px, 0)`; | |
document.body.appendChild(node); | |
// start handling interactions | |
node.addEventListener('pointerdown', pointerdown); | |
}; | |
const downCenterOffset = {}; | |
const pointerdown = function (e) { | |
if (e.simulated) return; | |
e.stopPropagation(); | |
e.preventDefault(); | |
target = e.target; | |
downCenterOffset.x = e.offsetX - 24; | |
downCenterOffset.y = e.offsetY - 24; | |
document.addEventListener('pointermove', pointermove, true); | |
document.addEventListener('pointercancel', pointerup, true); | |
document.addEventListener('pointerup', pointerup, true); | |
}; | |
const pointermove = function (e) { | |
if (e.simulated) return; | |
e.preventDefault(); | |
e.stopPropagation(); | |
target.pointerPosition = { | |
x: e.pageX - downCenterOffset.x, | |
y: e.pageY - downCenterOffset.y, | |
}; | |
target.style.transform = `translate3d(${target.pointerPosition.x}px, ${target.pointerPosition.y}px, 0)`; | |
if (target.pointerActive) { | |
dispatch(target.pointerTarget, target.pointerPosition, target.pointerId, 'pointermove'); | |
} | |
}; | |
const pointerup = function (e) { | |
if (e.simulated) return; | |
e.preventDefault(); | |
e.stopPropagation(); | |
document.removeEventListener('pointermove', pointermove, true); | |
document.removeEventListener('pointercancel', pointerup, true); | |
document.removeEventListener('pointerup', pointerup, true); | |
}; | |
document.addEventListener( | |
'pointerdown', | |
function (e) { | |
if (!e.metaKey) return; | |
e.stopPropagation(); | |
if (e.target.pointerPosition) { | |
pointerselect(e); | |
} else { | |
pointercreate(e.pageX, e.pageY); | |
} | |
}, | |
true | |
); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment