|
/** |
|
* @see https://w3c.github.io/pointerevents/#pointer-event-types |
|
*/ |
|
const POINTER_EVENT_NAME_LIST = [ |
|
'pointerover', |
|
'pointerenter', |
|
'pointerdown', |
|
'pointermove', |
|
'pointerup', |
|
'pointercancel', |
|
'pointerout', |
|
'pointerleave', |
|
'gotpointercapture', |
|
'lostpointercapture', |
|
]; |
|
|
|
const POINTER_EVENT_PROP_LIST = [ |
|
/** |
|
* PointerEvent property list |
|
* @see https://w3c.github.io/pointerevents/#pointerevent-interface |
|
*/ |
|
'pointerId', |
|
'width', |
|
'height', |
|
'pressure', |
|
'tangentialPressure', |
|
'tiltX', |
|
'tiltY', |
|
'twist', |
|
'pointerType', |
|
'isPrimary', |
|
/** |
|
* MouseEvent property list |
|
* @see https://www.w3.org/TR/uievents/#interface-mouseevent |
|
* @see https://drafts.csswg.org/cssom-view/#extensions-to-the-mouseevent-interface |
|
*/ |
|
'screenX', |
|
'screenY', |
|
'clientX', |
|
'clientY', |
|
'ctrlKey', |
|
'shiftKey', |
|
'altKey', |
|
'metaKey', |
|
'button', |
|
'buttons', |
|
'relatedTarget', |
|
'pageX', |
|
'pageY', |
|
'x', |
|
'y', |
|
'offsetX', |
|
'offsetY', |
|
/** |
|
* UIEvent property list |
|
* @see https://www.w3.org/TR/uievents/#uievent-uievent |
|
*/ |
|
'view', |
|
'detail', |
|
/** |
|
* Event property list |
|
* @see https://dom.spec.whatwg.org/#event |
|
*/ |
|
'type', |
|
'target', |
|
'srcElement', |
|
'currentTarget', |
|
'eventPhase', |
|
'cancelBubble', |
|
'bubbles', |
|
'cancelable', |
|
'returnValue', |
|
'defaultPrevented', |
|
'composed', |
|
'isTrusted', |
|
'timeStamp', |
|
]; |
|
|
|
const outputElem = document.getElementById('output'); |
|
const squareElem = document.createElement('div'); |
|
|
|
squareElem.classList.add('square'); |
|
|
|
/* |
|
* ドラッグ操作用のイベントを定義 |
|
*/ |
|
const dragStateMap = new WeakMap; |
|
const dragListener = event => { |
|
const { type: eventType, pointerId, pageX: pointerPosX, pageY: pointerPosY } = event; |
|
const squareElemStyle = squareElem.style; |
|
/** |
|
* @see https://w3c.github.io/pointerevents/#dfn-active-buttons-state |
|
* @see https://w3c.github.io/pointerevents/#dom-element-haspointercapture |
|
*/ |
|
const isActiveButtonsState = event.buttons !== 0 || squareElem.hasPointerCapture(pointerId); |
|
|
|
event.preventDefault(); |
|
|
|
if (eventType === 'pointerdown' && !dragStateMap.has(squareElem)) { |
|
squareElem.setPointerCapture(pointerId); |
|
|
|
/* |
|
* styleが未設定の場合は、設定する |
|
*/ |
|
if (String(squareElemStyle.left).length === 0 || String(squareElemStyle.top).length === 0) { |
|
const clientRect = squareElem.getBoundingClientRect(); |
|
squareElemStyle.left = `${window.pageXOffset + clientRect.left}px`; |
|
squareElemStyle.top = `${window.pageYOffset + clientRect.top}px`; |
|
} |
|
|
|
dragStateMap.set(squareElem, { |
|
initialPointerPosX: pointerPosX, |
|
initialPointerPosY: pointerPosY, |
|
initialSquarePosX: Number.parseFloat(squareElemStyle.left), |
|
initialSquarePosY: Number.parseFloat(squareElemStyle.top), |
|
pending: false, |
|
}); |
|
} else if ( |
|
( |
|
eventType === 'pointermove' || |
|
eventType === 'pointerup' |
|
) && |
|
dragStateMap.has(squareElem) && |
|
isActiveButtonsState |
|
) { |
|
const dragState = dragStateMap.get(squareElem); |
|
|
|
if (!dragState.pending) { |
|
dragState.pending = true; |
|
|
|
window.requestAnimationFrame(() => { |
|
squareElemStyle.left = `${dragState.initialSquarePosX + (pointerPosX - dragState.initialPointerPosX)}px`; |
|
squareElemStyle.top = `${dragState.initialSquarePosY + (pointerPosY - dragState.initialPointerPosY)}px`; |
|
|
|
dragState.pending = false; |
|
}); |
|
} |
|
} |
|
|
|
if (eventType === 'pointerup' || eventType === 'pointercancel' || (eventType === 'pointermove' && !isActiveButtonsState)) { |
|
squareElem.releasePointerCapture(pointerId); |
|
dragStateMap.delete(squareElem); |
|
} |
|
}; |
|
squareElem.addEventListener('pointerdown', dragListener); |
|
squareElem.addEventListener('pointermove', dragListener); |
|
squareElem.addEventListener('pointerup', dragListener); |
|
squareElem.addEventListener('pointercancel', dragListener); |
|
|
|
/* |
|
* デバッグ用のイベントを定義 |
|
*/ |
|
const pointerListener = event => { |
|
console.groupCollapsed(event.type); |
|
console.dir(event); |
|
const cloneObj = {}; |
|
for (const prop of POINTER_EVENT_PROP_LIST) { |
|
cloneObj[prop] = event[prop]; |
|
} |
|
console.dir(cloneObj); |
|
console.groupEnd(); |
|
}; |
|
for (const eventName of POINTER_EVENT_NAME_LIST) { |
|
squareElem.addEventListener(eventName, pointerListener); |
|
} |
|
|
|
/* |
|
* 四角形をDOMツリーに追加 |
|
*/ |
|
outputElem.appendChild(squareElem); |