mirror of
https://github.com/konvajs/konva.git
synced 2026-01-23 13:26:07 +08:00
Merge branch 'wip-pointer-events' of https://github.com/jquense/konva into jquense-wip-pointer-events
This commit is contained in:
@@ -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,
|
||||
|
||||
@@ -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
59
src/PointerEvents.ts
Normal 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'))
|
||||
);
|
||||
}
|
||||
17
src/Shape.ts
17
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';
|
||||
|
||||
@@ -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>;
|
||||
|
||||
|
||||
84
src/Stage.ts
84
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,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
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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() {
|
||||
|
||||
Reference in New Issue
Block a user