From 10b21689ba1a47452843016ba94afdf23b1568c2 Mon Sep 17 00:00:00 2001 From: Jason Quense Date: Tue, 26 Mar 2019 16:30:00 -0400 Subject: [PATCH] WIP --- src/Node.ts | 6 ++-- src/PointerEvents.ts | 59 ++++++++++++++++++++++++++++++++++++ src/Shape.ts | 13 ++++++++ src/Stage.ts | 72 +++++++++++++++++++++++++++++++++++++++++++- 4 files changed, 147 insertions(+), 3 deletions(-) create mode 100644 src/PointerEvents.ts diff --git a/src/Node.ts b/src/Node.ts index b7ae5e06..91ba0186 100644 --- a/src/Node.ts +++ b/src/Node.ts @@ -10,6 +10,7 @@ import { getStringValidator, getBooleanValidator } from './Validators'; +import { Stage } from './Stage'; export const ids: any = {}; export const names: any = {}; @@ -1521,10 +1522,11 @@ export abstract class Node { * @name Konva.Node#getStage * @returns {Konva.Stage} */ - getStage() { + getStage(): Stage | undefined { return this._getCache(STAGE, this._getStage); } - _getStage() { + + _getStage(): Stage | undefined { var parent = this.getParent(); if (parent) { return parent.getStage(); diff --git a/src/PointerEvents.ts b/src/PointerEvents.ts new file mode 100644 index 00000000..f1fa50d6 --- /dev/null +++ b/src/PointerEvents.ts @@ -0,0 +1,59 @@ +import { KonvaEventObject } from './types'; + +import { Shape } from './Shape'; +import { Stage } from './Stage'; + +const Captures = new Map(); + +export interface KonvaPointerEvent extends KonvaEventObject { + pointerId: number; +} + +let implicitRelease = null; + +export function getCapturedShape(pointerId: number) { + return Captures.get(pointerId); +} + +export function createEvent(evt: PointerEvent): KonvaPointerEvent { + return { + evt, + pointerId: evt.pointerId + } as any; +} + +export function hasPointerCapture(pointerId: number, shape: Shape | Stage) { + return Captures.get(pointerId) === shape; +} + +export function setPointerCapture(pointerId: number, shape: Shape | Stage) { + releaseCapture(pointerId); + + const { content } = shape.getStage(); + + content.setPointerCapture(pointerId); + + Captures.set(pointerId, shape); + + shape._fire( + 'gotpointercapture', + createEvent(new PointerEvent('gotpointercapture')) + ); +} + +export function releaseCapture(pointerId: number, target?: Shape | Stage) { + const shape = Captures.get(pointerId); + + if (!shape) return; + + const { content } = shape.getStage(); + + content.releasePointerCapture(pointerId); + + Captures.delete(pointerId); + + shape._fire( + 'lostpointercapture', + createEvent(new PointerEvent('lostpointercapture')) + ); +} diff --git a/src/Shape.ts b/src/Shape.ts index 81fac66c..529d2868 100644 --- a/src/Shape.ts +++ b/src/Shape.ts @@ -10,6 +10,7 @@ import { import { Context } from './Context'; import { _registerNode } from './Global'; +import * as PointerEvents from './PointerEvents'; import { GetSet, Vector2d } from './types'; @@ -707,6 +708,18 @@ export class Shape extends Node< return this; } + hasPointerCapture(pointerId: number) { + PointerEvents.releaseCapture(pointerId, this); + } + + setPointerCapture(pointerId: number) { + PointerEvents.setPointerCapture(pointerId, this); + } + + releaseCapture(pointerId: number) { + PointerEvents.releaseCapture(pointerId, this); + } + draggable: GetSet; embossBlend: GetSet; diff --git a/src/Stage.ts b/src/Stage.ts index 67a28378..ccac1b19 100644 --- a/src/Stage.ts +++ b/src/Stage.ts @@ -8,6 +8,7 @@ import { Shape } from './Shape'; import { BaseLayer } from './BaseLayer'; import { DD } from './DragAndDrop'; import { _registerNode } from './Global'; +import * as PointerEvents from './PointerEvents'; export interface StageConfig extends ContainerConfig { container: HTMLDivElement | string; @@ -24,6 +25,11 @@ var STAGE = 'Stage', MOUSEMOVE = 'mousemove', MOUSEDOWN = 'mousedown', MOUSEUP = 'mouseup', + POINTERMOVE = 'pointermove', + POINTERDOWN = 'pointerdown', + POINTERUP = 'pointerup', + POINTERCANCEL = 'pointercancel', + LOSTPOINTERCAPTURE = 'lostpointercapture', CONTEXTMENU = 'contextmenu', CLICK = 'click', DBL_CLICK = 'dblclick', @@ -65,7 +71,12 @@ var STAGE = 'Stage', TOUCHEND, MOUSEOVER, WHEEL, - CONTEXTMENU + CONTEXTMENU, + POINTERDOWN, + POINTERMOVE, + POINTERUP, + POINTERCANCEL, + LOSTPOINTERCAPTURE ], // cached variables eventsLength = EVENTS.length; @@ -379,10 +390,14 @@ export class Stage extends Container { addEvent(this, EVENTS[n]); } } +<<<<<<< HEAD _mouseenter(evt) { this.setPointersPositions(evt); this._fire(MOUSEENTER, { evt: evt, target: this, currentTarget: this }); } +======= + +>>>>>>> WIP _mouseover(evt) { this.setPointersPositions(evt); this._fire(CONTENT_MOUSEOVER, { evt: evt }); @@ -711,6 +726,61 @@ export class Stage extends Container { } this._fire(CONTENT_WHEEL, { evt: evt }); } + + _pointerdown(evt: PointerEvent) { + this.setPointersPositions(evt); + + const shape = + PointerEvents.getCapturedShape(evt.pointerId) || + this.getIntersection(this.getPointerPosition()); + + if (shape) { + shape._fireAndBubble(POINTERDOWN, PointerEvents.createEvent(evt)); + } + } + + _pointermove(evt: PointerEvent) { + this.setPointersPositions(evt); + + const shape = + PointerEvents.getCapturedShape(evt.pointerId) || + this.getIntersection(this.getPointerPosition()); + + if (shape) { + shape._fireAndBubble(POINTERMOVE, PointerEvents.createEvent(evt)); + } + } + + _pointerup(evt: PointerEvent) { + this.setPointersPositions(evt); + const shape = + PointerEvents.getCapturedShape(evt.pointerId) || + this.getIntersection(this.getPointerPosition()); + + if (shape) { + shape._fireAndBubble(POINTERUP, PointerEvents.createEvent(evt)); + } + + PointerEvents.releaseCapture(evt.pointerId); + } + + _pointercancel(evt: PointerEvent) { + this.setPointersPositions(evt); + const shape = + PointerEvents.getCapturedShape(evt.pointerId) || + this.getIntersection(this.getPointerPosition()); + + if (shape) { + shape._fireAndBubble(POINTERUP, PointerEvents.createEvent(evt)); + } + + PointerEvents.releaseCapture(evt.pointerId); + } + + _lostpointercapture(evt: PointerEvent) { + PointerEvents.releaseCapture(evt.pointerId); + } + /** * manually register pointers positions (mouse/touch) in the stage. * So you can use stage.getPointerPosition(). Usually you don't need to use that method