UNPKG

interactjs

Version:

Drag and drop, resizing and multi-touch gestures with inertia and snapping for modern browsers (and also IE8+)

226 lines (181 loc) 6.29 kB
const hypot = require('./hypot'); const browser = require('./browser'); const dom = require('./domObjects'); const domUtils = require('./domUtils'); const is = require('./is'); const pointerExtend = require('./pointerExtend'); const pointerUtils = { copyCoords: function (dest, src) { dest.page = dest.page || {}; dest.page.x = src.page.x; dest.page.y = src.page.y; dest.client = dest.client || {}; dest.client.x = src.client.x; dest.client.y = src.client.y; dest.timeStamp = src.timeStamp; }, setCoordDeltas: function (targetObj, prev, cur) { targetObj.page.x = cur.page.x - prev.page.x; targetObj.page.y = cur.page.y - prev.page.y; targetObj.client.x = cur.client.x - prev.client.x; targetObj.client.y = cur.client.y - prev.client.y; targetObj.timeStamp = cur.timeStamp - prev.timeStamp; // set pointer velocity const dt = Math.max(targetObj.timeStamp / 1000, 0.001); targetObj.page.speed = hypot(targetObj.page.x, targetObj.page.y) / dt; targetObj.page.vx = targetObj.page.x / dt; targetObj.page.vy = targetObj.page.y / dt; targetObj.client.speed = hypot(targetObj.client.x, targetObj.page.y) / dt; targetObj.client.vx = targetObj.client.x / dt; targetObj.client.vy = targetObj.client.y / dt; }, isNativePointer: function (pointer) { return (pointer instanceof dom.Event || pointer instanceof dom.Touch); }, // Get specified X/Y coords for mouse or event.touches[0] getXY: function (type, pointer, xy) { xy = xy || {}; type = type || 'page'; xy.x = pointer[type + 'X']; xy.y = pointer[type + 'Y']; return xy; }, getPageXY: function (pointer, page) { page = page || {}; // Opera Mobile handles the viewport and scrolling oddly if (browser.isOperaMobile && pointerUtils.isNativePointer(pointer)) { pointerUtils.getXY('screen', pointer, page); page.x += window.scrollX; page.y += window.scrollY; } else { pointerUtils.getXY('page', pointer, page); } return page; }, getClientXY: function (pointer, client) { client = client || {}; if (browser.isOperaMobile && pointerUtils.isNativePointer(pointer)) { // Opera Mobile handles the viewport and scrolling oddly pointerUtils.getXY('screen', pointer, client); } else { pointerUtils.getXY('client', pointer, client); } return client; }, getPointerId: function (pointer) { return is.number(pointer.pointerId)? pointer.pointerId : pointer.identifier; }, setCoords: function (targetObj, pointers, timeStamp) { const pointer = (pointers.length > 1 ? pointerUtils.pointerAverage(pointers) : pointers[0]); const tmpXY = {}; pointerUtils.getPageXY(pointer, tmpXY); targetObj.page.x = tmpXY.x; targetObj.page.y = tmpXY.y; pointerUtils.getClientXY(pointer, tmpXY); targetObj.client.x = tmpXY.x; targetObj.client.y = tmpXY.y; targetObj.timeStamp = is.number(timeStamp) ? timeStamp :new Date().getTime(); }, pointerExtend: pointerExtend, getTouchPair: function (event) { const touches = []; // array of touches is supplied if (is.array(event)) { touches[0] = event[0]; touches[1] = event[1]; } // an event else { if (event.type === 'touchend') { if (event.touches.length === 1) { touches[0] = event.touches[0]; touches[1] = event.changedTouches[0]; } else if (event.touches.length === 0) { touches[0] = event.changedTouches[0]; touches[1] = event.changedTouches[1]; } } else { touches[0] = event.touches[0]; touches[1] = event.touches[1]; } } return touches; }, pointerAverage: function (pointers) { const average = { pageX : 0, pageY : 0, clientX: 0, clientY: 0, screenX: 0, screenY: 0, }; for (const pointer of pointers) { for (const prop in average) { average[prop] += pointer[prop]; } } for (const prop in average) { average[prop] /= pointers.length; } return average; }, touchBBox: function (event) { if (!event.length && !(event.touches && event.touches.length > 1)) { return; } const touches = pointerUtils.getTouchPair(event); const minX = Math.min(touches[0].pageX, touches[1].pageX); const minY = Math.min(touches[0].pageY, touches[1].pageY); const maxX = Math.max(touches[0].pageX, touches[1].pageX); const maxY = Math.max(touches[0].pageY, touches[1].pageY); return { x: minX, y: minY, left: minX, top: minY, width: maxX - minX, height: maxY - minY, }; }, touchDistance: function (event, deltaSource) { const sourceX = deltaSource + 'X'; const sourceY = deltaSource + 'Y'; const touches = pointerUtils.getTouchPair(event); const dx = touches[0][sourceX] - touches[1][sourceX]; const dy = touches[0][sourceY] - touches[1][sourceY]; return hypot(dx, dy); }, touchAngle: function (event, prevAngle, deltaSource) { const sourceX = deltaSource + 'X'; const sourceY = deltaSource + 'Y'; const touches = pointerUtils.getTouchPair(event); const dx = touches[1][sourceX] - touches[0][sourceX]; const dy = touches[1][sourceY] - touches[0][sourceY]; const angle = 180 * Math.atan2(dy , dx) / Math.PI; return angle; }, getPointerType: function (pointer, interaction) { // if the PointerEvent API isn't available, then the pointer must be ither // a MouseEvent or TouchEvent if (interaction.mouse) { return 'mouse'; } if (!browser.supportsPointerEvent) { return 'touch'; } return is.string(pointer.pointerType) ? pointer.pointerType : [undefined, undefined,'touch', 'pen', 'mouse'][pointer.pointerType]; }, // [ event.target, event.currentTarget ] getEventTargets: function (event) { return [ domUtils.getActualElement(event.path ? event.path[0] : event.target), domUtils.getActualElement(event.currentTarget), ]; }, }; module.exports = pointerUtils;