Merge branch 'wip-pointer-events' of https://github.com/jquense/konva into jquense-wip-pointer-events

This commit is contained in:
Anton Lavrenov
2019-05-27 14:39:17 -05:00
13 changed files with 544 additions and 13 deletions

View File

@@ -95,6 +95,7 @@ export const Konva = {
return Konva.angleDeg ? angle * PI_OVER_180 : angle;
},
enableTrace: false,
_pointerEventsEnabled: false,
// TODO: move that to stage?
listenClickTap: false,

View File

@@ -10,9 +10,9 @@ import {
getStringValidator,
getBooleanValidator
} from './Validators';
import { Stage } from './Stage';
import { Context } from './Context';
import { Shape } from './Shape';
import { Stage } from './Stage';
export const ids: any = {};
export const names: any = {};
@@ -1565,10 +1565,11 @@ export abstract class Node<Config extends NodeConfig = NodeConfig> {
* @name Konva.Node#getStage
* @returns {Konva.Stage}
*/
getStage() {
getStage(): any {
return this._getCache(STAGE, this._getStage);
}
_getStage() {
_getStage(): Stage | undefined {
var parent = this.getParent();
if (parent) {
return parent.getStage();

59
src/PointerEvents.ts Normal file
View File

@@ -0,0 +1,59 @@
import { KonvaEventObject } from './types';
import { Shape } from './Shape';
import { Stage } from './Stage';
const Captures = new Map<number, Shape | Stage>();
export interface KonvaPointerEvent extends KonvaEventObject<PointerEvent> {
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'))
);
}

View File

@@ -10,6 +10,7 @@ import {
import { Context } from './Context';
import { _registerNode } from './Global';
import * as PointerEvents from './PointerEvents';
import { GetSet, Vector2d } from './types';
@@ -395,8 +396,8 @@ export class Shape<Config extends ShapeConfig = ShapeConfig> extends Node<
// why do we need buffer canvas?
// it give better result when a shape has
// stroke with fill and with some opacity
_useBufferCanvas(caching) {
return (
_useBufferCanvas(caching): boolean {
return !!(
(!caching || this.hasShadow()) &&
this.perfectDrawEnabled() &&
this.getAbsoluteOpacity() !== 1 &&
@@ -711,6 +712,18 @@ export class Shape<Config extends ShapeConfig = ShapeConfig> extends Node<
return this;
}
hasPointerCapture(pointerId: number): boolean {
return PointerEvents.hasPointerCapture(pointerId, this);
}
setPointerCapture(pointerId: number) {
PointerEvents.setPointerCapture(pointerId, this);
}
releaseCapture(pointerId: number) {
PointerEvents.releaseCapture(pointerId, this);
}
draggable: GetSet<boolean, this>;
embossBlend: GetSet<boolean, this>;

View File

@@ -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,12 @@ var STAGE = 'Stage',
MOUSEMOVE = 'mousemove',
MOUSEDOWN = 'mousedown',
MOUSEUP = 'mouseup',
// TODO: add them into "on" method docs and into site docs
POINTERMOVE = 'pointermove',
POINTERDOWN = 'pointerdown',
POINTERUP = 'pointerup',
POINTERCANCEL = 'pointercancel',
LOSTPOINTERCAPTURE = 'lostpointercapture',
CONTEXTMENU = 'contextmenu',
CLICK = 'click',
DBL_CLICK = 'dblclick',
@@ -46,6 +53,9 @@ var STAGE = 'Stage',
CONTENT_DBL_TAP = 'contentDbltap',
CONTENT_TAP = 'contentTap',
CONTENT_TOUCHMOVE = 'contentTouchmove',
CONTENT_POINTERMOVE = 'contentPointermove',
CONTENT_POINTERDOWN = 'contentPointerdown',
CONTENT_POINTERUP = 'contentPointerup',
CONTENT_WHEEL = 'contentWheel',
RELATIVE = 'relative',
KONVA_CONTENT = 'konvajs-content',
@@ -65,7 +75,12 @@ var STAGE = 'Stage',
TOUCHEND,
MOUSEOVER,
WHEEL,
CONTEXTMENU
CONTEXTMENU,
POINTERDOWN,
POINTERMOVE,
POINTERUP,
POINTERCANCEL,
LOSTPOINTERCAPTURE
],
// cached variables
eventsLength = EVENTS.length;
@@ -709,6 +724,73 @@ export class Stage extends Container<BaseLayer> {
}
this._fire(CONTENT_WHEEL, { evt: evt });
}
_pointerdown(evt: PointerEvent) {
if (!Konva._pointerEventsEnabled) {
return;
}
this.setPointersPositions(evt);
const shape =
PointerEvents.getCapturedShape(evt.pointerId) ||
this.getIntersection(this.getPointerPosition());
if (shape) {
shape._fireAndBubble(POINTERDOWN, PointerEvents.createEvent(evt));
}
}
_pointermove(evt: PointerEvent) {
if (!Konva._pointerEventsEnabled) {
return;
}
this.setPointersPositions(evt);
const shape =
PointerEvents.getCapturedShape(evt.pointerId) ||
this.getIntersection(this.getPointerPosition());
if (shape) {
shape._fireAndBubble(POINTERMOVE, PointerEvents.createEvent(evt));
}
}
_pointerup(evt: PointerEvent) {
if (!Konva._pointerEventsEnabled) {
return;
}
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) {
if (!Konva._pointerEventsEnabled) {
return;
}
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

View File

@@ -36,7 +36,7 @@ export interface ImageConfig extends ShapeConfig {
*/
export class Image extends Shape<ImageConfig> {
_useBufferCanvas() {
return (
return !!(
(this.hasShadow() || this.getAbsoluteOpacity() !== 1) &&
this.hasStroke() &&
this.getStage()

View File

@@ -150,11 +150,13 @@ export class Sprite extends Shape<SpriteConfig> {
context.closePath();
context.fillShape(this);
}
_useBufferCanvas() {
return (
(this.hasShadow() || this.getAbsoluteOpacity() !== 1) && this.hasStroke()
);
}
_setInterval() {
var that = this;
this.interval = setInterval(function() {