Navigation Menu

Skip to content

Instantly share code, notes, and snippets.

@rikschennink
Created July 9, 2021 12:20
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save rikschennink/abee3b11fd39e93f0662c2ed88c6ddcd to your computer and use it in GitHub Desktop.
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
{
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