mirror of
https://github.com/konvajs/konva.git
synced 2025-06-28 15:23:44 +08:00
Merge branch 'wip-pointer-events' of https://github.com/jquense/konva into jquense-wip-pointer-events
This commit is contained in:
commit
da11cf8b01
@ -6,6 +6,7 @@ This project adheres to [Semantic Versioning](http://semver.org/).
|
|||||||
## Not released:
|
## Not released:
|
||||||
|
|
||||||
* Typescript fixes
|
* Typescript fixes
|
||||||
|
* Experimental pointer events support. Do `Konva._pointerEventsEnabled = true;` to enable
|
||||||
|
|
||||||
## [3.2.6][2019-05-09]
|
## [3.2.6][2019-05-09]
|
||||||
|
|
||||||
|
104
konva.js
104
konva.js
@ -83,6 +83,7 @@
|
|||||||
return Konva.angleDeg ? angle * PI_OVER_180 : angle;
|
return Konva.angleDeg ? angle * PI_OVER_180 : angle;
|
||||||
},
|
},
|
||||||
enableTrace: false,
|
enableTrace: false,
|
||||||
|
_pointerEventsEnabled: false,
|
||||||
// TODO: move that to stage?
|
// TODO: move that to stage?
|
||||||
listenClickTap: false,
|
listenClickTap: false,
|
||||||
inDblClickWindow: false,
|
inDblClickWindow: false,
|
||||||
@ -5423,8 +5424,40 @@
|
|||||||
*/
|
*/
|
||||||
Collection.mapMethods(Container);
|
Collection.mapMethods(Container);
|
||||||
|
|
||||||
|
var Captures = new Map();
|
||||||
|
function getCapturedShape(pointerId) {
|
||||||
|
return Captures.get(pointerId);
|
||||||
|
}
|
||||||
|
function createEvent(evt) {
|
||||||
|
return {
|
||||||
|
evt: evt,
|
||||||
|
pointerId: evt.pointerId
|
||||||
|
};
|
||||||
|
}
|
||||||
|
function hasPointerCapture(pointerId, shape) {
|
||||||
|
return Captures.get(pointerId) === shape;
|
||||||
|
}
|
||||||
|
function setPointerCapture(pointerId, shape) {
|
||||||
|
releaseCapture(pointerId);
|
||||||
|
var content = shape.getStage().content;
|
||||||
|
content.setPointerCapture(pointerId);
|
||||||
|
Captures.set(pointerId, shape);
|
||||||
|
shape._fire('gotpointercapture', createEvent(new PointerEvent('gotpointercapture')));
|
||||||
|
}
|
||||||
|
function releaseCapture(pointerId, target) {
|
||||||
|
var shape = Captures.get(pointerId);
|
||||||
|
if (!shape)
|
||||||
|
return;
|
||||||
|
var content = shape.getStage().content;
|
||||||
|
content.releasePointerCapture(pointerId);
|
||||||
|
Captures.delete(pointerId);
|
||||||
|
shape._fire('lostpointercapture', createEvent(new PointerEvent('lostpointercapture')));
|
||||||
|
}
|
||||||
|
|
||||||
// CONSTANTS
|
// CONSTANTS
|
||||||
var STAGE$1 = 'Stage', STRING = 'string', PX = 'px', MOUSEOUT = 'mouseout', MOUSELEAVE$1 = 'mouseleave', MOUSEOVER = 'mouseover', MOUSEENTER$1 = 'mouseenter', MOUSEMOVE = 'mousemove', MOUSEDOWN = 'mousedown', MOUSEUP = 'mouseup', CONTEXTMENU = 'contextmenu', CLICK = 'click', DBL_CLICK = 'dblclick', TOUCHSTART = 'touchstart', TOUCHEND = 'touchend', TAP = 'tap', DBL_TAP = 'dbltap', TOUCHMOVE = 'touchmove', WHEEL = 'wheel', CONTENT_MOUSEOUT = 'contentMouseout', CONTENT_MOUSEOVER = 'contentMouseover', CONTENT_MOUSEMOVE = 'contentMousemove', CONTENT_MOUSEDOWN = 'contentMousedown', CONTENT_MOUSEUP = 'contentMouseup', CONTENT_CONTEXTMENU = 'contentContextmenu', CONTENT_CLICK = 'contentClick', CONTENT_DBL_CLICK = 'contentDblclick', CONTENT_TOUCHSTART = 'contentTouchstart', CONTENT_TOUCHEND = 'contentTouchend', CONTENT_DBL_TAP = 'contentDbltap', CONTENT_TAP = 'contentTap', CONTENT_TOUCHMOVE = 'contentTouchmove', CONTENT_WHEEL = 'contentWheel', RELATIVE = 'relative', KONVA_CONTENT = 'konvajs-content', UNDERSCORE = '_', CONTAINER = 'container', MAX_LAYERS_NUMBER = 5, EMPTY_STRING$1 = '', EVENTS = [
|
var STAGE$1 = 'Stage', STRING = 'string', PX = 'px', MOUSEOUT = 'mouseout', MOUSELEAVE$1 = 'mouseleave', MOUSEOVER = 'mouseover', MOUSEENTER$1 = 'mouseenter', 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', TOUCHSTART = 'touchstart', TOUCHEND = 'touchend', TAP = 'tap', DBL_TAP = 'dbltap', TOUCHMOVE = 'touchmove', WHEEL = 'wheel', CONTENT_MOUSEOUT = 'contentMouseout', CONTENT_MOUSEOVER = 'contentMouseover', CONTENT_MOUSEMOVE = 'contentMousemove', CONTENT_MOUSEDOWN = 'contentMousedown', CONTENT_MOUSEUP = 'contentMouseup', CONTENT_CONTEXTMENU = 'contentContextmenu', CONTENT_CLICK = 'contentClick', CONTENT_DBL_CLICK = 'contentDblclick', CONTENT_TOUCHSTART = 'contentTouchstart', CONTENT_TOUCHEND = 'contentTouchend', CONTENT_DBL_TAP = 'contentDbltap', CONTENT_TAP = 'contentTap', CONTENT_TOUCHMOVE = 'contentTouchmove', CONTENT_WHEEL = 'contentWheel', RELATIVE = 'relative', KONVA_CONTENT = 'konvajs-content', UNDERSCORE = '_', CONTAINER = 'container', MAX_LAYERS_NUMBER = 5, EMPTY_STRING$1 = '', EVENTS = [
|
||||||
MOUSEENTER$1,
|
MOUSEENTER$1,
|
||||||
MOUSEDOWN,
|
MOUSEDOWN,
|
||||||
MOUSEMOVE,
|
MOUSEMOVE,
|
||||||
@ -5435,7 +5468,12 @@
|
|||||||
TOUCHEND,
|
TOUCHEND,
|
||||||
MOUSEOVER,
|
MOUSEOVER,
|
||||||
WHEEL,
|
WHEEL,
|
||||||
CONTEXTMENU
|
CONTEXTMENU,
|
||||||
|
POINTERDOWN,
|
||||||
|
POINTERMOVE,
|
||||||
|
POINTERUP,
|
||||||
|
POINTERCANCEL,
|
||||||
|
LOSTPOINTERCAPTURE
|
||||||
],
|
],
|
||||||
// cached variables
|
// cached variables
|
||||||
eventsLength = EVENTS.length;
|
eventsLength = EVENTS.length;
|
||||||
@ -6013,6 +6051,55 @@
|
|||||||
}
|
}
|
||||||
this._fire(CONTENT_WHEEL, { evt: evt });
|
this._fire(CONTENT_WHEEL, { evt: evt });
|
||||||
};
|
};
|
||||||
|
Stage.prototype._pointerdown = function (evt) {
|
||||||
|
if (!Konva._pointerEventsEnabled) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.setPointersPositions(evt);
|
||||||
|
var shape = getCapturedShape(evt.pointerId) ||
|
||||||
|
this.getIntersection(this.getPointerPosition());
|
||||||
|
if (shape) {
|
||||||
|
shape._fireAndBubble(POINTERDOWN, createEvent(evt));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
Stage.prototype._pointermove = function (evt) {
|
||||||
|
if (!Konva._pointerEventsEnabled) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.setPointersPositions(evt);
|
||||||
|
var shape = getCapturedShape(evt.pointerId) ||
|
||||||
|
this.getIntersection(this.getPointerPosition());
|
||||||
|
if (shape) {
|
||||||
|
shape._fireAndBubble(POINTERMOVE, createEvent(evt));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
Stage.prototype._pointerup = function (evt) {
|
||||||
|
if (!Konva._pointerEventsEnabled) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.setPointersPositions(evt);
|
||||||
|
var shape = getCapturedShape(evt.pointerId) ||
|
||||||
|
this.getIntersection(this.getPointerPosition());
|
||||||
|
if (shape) {
|
||||||
|
shape._fireAndBubble(POINTERUP, createEvent(evt));
|
||||||
|
}
|
||||||
|
releaseCapture(evt.pointerId);
|
||||||
|
};
|
||||||
|
Stage.prototype._pointercancel = function (evt) {
|
||||||
|
if (!Konva._pointerEventsEnabled) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.setPointersPositions(evt);
|
||||||
|
var shape = getCapturedShape(evt.pointerId) ||
|
||||||
|
this.getIntersection(this.getPointerPosition());
|
||||||
|
if (shape) {
|
||||||
|
shape._fireAndBubble(POINTERUP, createEvent(evt));
|
||||||
|
}
|
||||||
|
releaseCapture(evt.pointerId);
|
||||||
|
};
|
||||||
|
Stage.prototype._lostpointercapture = function (evt) {
|
||||||
|
releaseCapture(evt.pointerId);
|
||||||
|
};
|
||||||
/**
|
/**
|
||||||
* manually register pointers positions (mouse/touch) in the stage.
|
* manually register pointers positions (mouse/touch) in the stage.
|
||||||
* So you can use stage.getPointerPosition(). Usually you don't need to use that method
|
* So you can use stage.getPointerPosition(). Usually you don't need to use that method
|
||||||
@ -6733,7 +6820,7 @@
|
|||||||
// it give better result when a shape has
|
// it give better result when a shape has
|
||||||
// stroke with fill and with some opacity
|
// stroke with fill and with some opacity
|
||||||
Shape.prototype._useBufferCanvas = function (caching) {
|
Shape.prototype._useBufferCanvas = function (caching) {
|
||||||
return ((!caching || this.hasShadow()) &&
|
return !!((!caching || this.hasShadow()) &&
|
||||||
this.perfectDrawEnabled() &&
|
this.perfectDrawEnabled() &&
|
||||||
this.getAbsoluteOpacity() !== 1 &&
|
this.getAbsoluteOpacity() !== 1 &&
|
||||||
this.hasFill() &&
|
this.hasFill() &&
|
||||||
@ -6993,6 +7080,15 @@
|
|||||||
}
|
}
|
||||||
return this;
|
return this;
|
||||||
};
|
};
|
||||||
|
Shape.prototype.hasPointerCapture = function (pointerId) {
|
||||||
|
return hasPointerCapture(pointerId, this);
|
||||||
|
};
|
||||||
|
Shape.prototype.setPointerCapture = function (pointerId) {
|
||||||
|
setPointerCapture(pointerId, this);
|
||||||
|
};
|
||||||
|
Shape.prototype.releaseCapture = function (pointerId) {
|
||||||
|
releaseCapture(pointerId, this);
|
||||||
|
};
|
||||||
return Shape;
|
return Shape;
|
||||||
}(Node));
|
}(Node));
|
||||||
Shape.prototype._fillFunc = _fillFunc;
|
Shape.prototype._fillFunc = _fillFunc;
|
||||||
@ -10159,7 +10255,7 @@
|
|||||||
return _super !== null && _super.apply(this, arguments) || this;
|
return _super !== null && _super.apply(this, arguments) || this;
|
||||||
}
|
}
|
||||||
Image.prototype._useBufferCanvas = function () {
|
Image.prototype._useBufferCanvas = function () {
|
||||||
return ((this.hasShadow() || this.getAbsoluteOpacity() !== 1) &&
|
return !!((this.hasShadow() || this.getAbsoluteOpacity() !== 1) &&
|
||||||
this.hasStroke() &&
|
this.hasStroke() &&
|
||||||
this.getStage());
|
this.getStage());
|
||||||
};
|
};
|
||||||
|
2
konva.min.js
vendored
2
konva.min.js
vendored
File diff suppressed because one or more lines are too long
@ -95,6 +95,7 @@ export const Konva = {
|
|||||||
return Konva.angleDeg ? angle * PI_OVER_180 : angle;
|
return Konva.angleDeg ? angle * PI_OVER_180 : angle;
|
||||||
},
|
},
|
||||||
enableTrace: false,
|
enableTrace: false,
|
||||||
|
_pointerEventsEnabled: false,
|
||||||
|
|
||||||
// TODO: move that to stage?
|
// TODO: move that to stage?
|
||||||
listenClickTap: false,
|
listenClickTap: false,
|
||||||
|
@ -10,9 +10,9 @@ import {
|
|||||||
getStringValidator,
|
getStringValidator,
|
||||||
getBooleanValidator
|
getBooleanValidator
|
||||||
} from './Validators';
|
} from './Validators';
|
||||||
|
import { Stage } from './Stage';
|
||||||
import { Context } from './Context';
|
import { Context } from './Context';
|
||||||
import { Shape } from './Shape';
|
import { Shape } from './Shape';
|
||||||
import { Stage } from './Stage';
|
|
||||||
|
|
||||||
export const ids: any = {};
|
export const ids: any = {};
|
||||||
export const names: any = {};
|
export const names: any = {};
|
||||||
@ -1565,10 +1565,11 @@ export abstract class Node<Config extends NodeConfig = NodeConfig> {
|
|||||||
* @name Konva.Node#getStage
|
* @name Konva.Node#getStage
|
||||||
* @returns {Konva.Stage}
|
* @returns {Konva.Stage}
|
||||||
*/
|
*/
|
||||||
getStage() {
|
getStage(): any {
|
||||||
return this._getCache(STAGE, this._getStage);
|
return this._getCache(STAGE, this._getStage);
|
||||||
}
|
}
|
||||||
_getStage() {
|
|
||||||
|
_getStage(): Stage | undefined {
|
||||||
var parent = this.getParent();
|
var parent = this.getParent();
|
||||||
if (parent) {
|
if (parent) {
|
||||||
return parent.getStage();
|
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 { Context } from './Context';
|
||||||
import { _registerNode } from './Global';
|
import { _registerNode } from './Global';
|
||||||
|
import * as PointerEvents from './PointerEvents';
|
||||||
|
|
||||||
import { GetSet, Vector2d } from './types';
|
import { GetSet, Vector2d } from './types';
|
||||||
|
|
||||||
@ -395,8 +396,8 @@ export class Shape<Config extends ShapeConfig = ShapeConfig> extends Node<
|
|||||||
// why do we need buffer canvas?
|
// why do we need buffer canvas?
|
||||||
// it give better result when a shape has
|
// it give better result when a shape has
|
||||||
// stroke with fill and with some opacity
|
// stroke with fill and with some opacity
|
||||||
_useBufferCanvas(caching) {
|
_useBufferCanvas(caching): boolean {
|
||||||
return (
|
return !!(
|
||||||
(!caching || this.hasShadow()) &&
|
(!caching || this.hasShadow()) &&
|
||||||
this.perfectDrawEnabled() &&
|
this.perfectDrawEnabled() &&
|
||||||
this.getAbsoluteOpacity() !== 1 &&
|
this.getAbsoluteOpacity() !== 1 &&
|
||||||
@ -711,6 +712,18 @@ export class Shape<Config extends ShapeConfig = ShapeConfig> extends Node<
|
|||||||
return this;
|
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>;
|
draggable: GetSet<boolean, this>;
|
||||||
embossBlend: 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 { BaseLayer } from './BaseLayer';
|
||||||
import { DD } from './DragAndDrop';
|
import { DD } from './DragAndDrop';
|
||||||
import { _registerNode } from './Global';
|
import { _registerNode } from './Global';
|
||||||
|
import * as PointerEvents from './PointerEvents';
|
||||||
|
|
||||||
export interface StageConfig extends ContainerConfig {
|
export interface StageConfig extends ContainerConfig {
|
||||||
container: HTMLDivElement | string;
|
container: HTMLDivElement | string;
|
||||||
@ -24,6 +25,12 @@ var STAGE = 'Stage',
|
|||||||
MOUSEMOVE = 'mousemove',
|
MOUSEMOVE = 'mousemove',
|
||||||
MOUSEDOWN = 'mousedown',
|
MOUSEDOWN = 'mousedown',
|
||||||
MOUSEUP = 'mouseup',
|
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',
|
CONTEXTMENU = 'contextmenu',
|
||||||
CLICK = 'click',
|
CLICK = 'click',
|
||||||
DBL_CLICK = 'dblclick',
|
DBL_CLICK = 'dblclick',
|
||||||
@ -46,6 +53,9 @@ var STAGE = 'Stage',
|
|||||||
CONTENT_DBL_TAP = 'contentDbltap',
|
CONTENT_DBL_TAP = 'contentDbltap',
|
||||||
CONTENT_TAP = 'contentTap',
|
CONTENT_TAP = 'contentTap',
|
||||||
CONTENT_TOUCHMOVE = 'contentTouchmove',
|
CONTENT_TOUCHMOVE = 'contentTouchmove',
|
||||||
|
CONTENT_POINTERMOVE = 'contentPointermove',
|
||||||
|
CONTENT_POINTERDOWN = 'contentPointerdown',
|
||||||
|
CONTENT_POINTERUP = 'contentPointerup',
|
||||||
CONTENT_WHEEL = 'contentWheel',
|
CONTENT_WHEEL = 'contentWheel',
|
||||||
RELATIVE = 'relative',
|
RELATIVE = 'relative',
|
||||||
KONVA_CONTENT = 'konvajs-content',
|
KONVA_CONTENT = 'konvajs-content',
|
||||||
@ -65,7 +75,12 @@ var STAGE = 'Stage',
|
|||||||
TOUCHEND,
|
TOUCHEND,
|
||||||
MOUSEOVER,
|
MOUSEOVER,
|
||||||
WHEEL,
|
WHEEL,
|
||||||
CONTEXTMENU
|
CONTEXTMENU,
|
||||||
|
POINTERDOWN,
|
||||||
|
POINTERMOVE,
|
||||||
|
POINTERUP,
|
||||||
|
POINTERCANCEL,
|
||||||
|
LOSTPOINTERCAPTURE
|
||||||
],
|
],
|
||||||
// cached variables
|
// cached variables
|
||||||
eventsLength = EVENTS.length;
|
eventsLength = EVENTS.length;
|
||||||
@ -709,6 +724,73 @@ export class Stage extends Container<BaseLayer> {
|
|||||||
}
|
}
|
||||||
this._fire(CONTENT_WHEEL, { evt: evt });
|
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.
|
* manually register pointers positions (mouse/touch) in the stage.
|
||||||
* So you can use stage.getPointerPosition(). Usually you don't need to use that method
|
* 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> {
|
export class Image extends Shape<ImageConfig> {
|
||||||
_useBufferCanvas() {
|
_useBufferCanvas() {
|
||||||
return (
|
return !!(
|
||||||
(this.hasShadow() || this.getAbsoluteOpacity() !== 1) &&
|
(this.hasShadow() || this.getAbsoluteOpacity() !== 1) &&
|
||||||
this.hasStroke() &&
|
this.hasStroke() &&
|
||||||
this.getStage()
|
this.getStage()
|
||||||
|
@ -150,11 +150,13 @@ export class Sprite extends Shape<SpriteConfig> {
|
|||||||
context.closePath();
|
context.closePath();
|
||||||
context.fillShape(this);
|
context.fillShape(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
_useBufferCanvas() {
|
_useBufferCanvas() {
|
||||||
return (
|
return (
|
||||||
(this.hasShadow() || this.getAbsoluteOpacity() !== 1) && this.hasStroke()
|
(this.hasShadow() || this.getAbsoluteOpacity() !== 1) && this.hasStroke()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
_setInterval() {
|
_setInterval() {
|
||||||
var that = this;
|
var that = this;
|
||||||
this.interval = setInterval(function() {
|
this.interval = setInterval(function() {
|
||||||
|
235
test/functional/PointerEvents-test.js
Normal file
235
test/functional/PointerEvents-test.js
Normal file
@ -0,0 +1,235 @@
|
|||||||
|
/* eslint-disable max-nested-callbacks */
|
||||||
|
suite('PointerEvents', function() {
|
||||||
|
Konva._pointerEventsEnabled = true;
|
||||||
|
// ======================================================
|
||||||
|
test('pointerdown pointerup pointermove', function(done) {
|
||||||
|
var stage = addStage();
|
||||||
|
var layer = new Konva.Layer();
|
||||||
|
var circle = new Konva.Circle({
|
||||||
|
x: stage.getWidth() / 2,
|
||||||
|
y: stage.getHeight() / 2,
|
||||||
|
radius: 70,
|
||||||
|
fill: 'red',
|
||||||
|
stroke: 'black',
|
||||||
|
strokeWidth: 4
|
||||||
|
});
|
||||||
|
|
||||||
|
// mobile events
|
||||||
|
var pointerdown = false;
|
||||||
|
var pointerup = false;
|
||||||
|
var pointermove = false;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* mobile
|
||||||
|
*/
|
||||||
|
circle.on('pointerdown', function() {
|
||||||
|
pointerdown = true;
|
||||||
|
});
|
||||||
|
|
||||||
|
circle.on('pointerup', function() {
|
||||||
|
pointerup = true;
|
||||||
|
});
|
||||||
|
|
||||||
|
circle.on('pointermove', function() {
|
||||||
|
pointermove = true;
|
||||||
|
});
|
||||||
|
|
||||||
|
layer.add(circle);
|
||||||
|
stage.add(layer);
|
||||||
|
|
||||||
|
var top = stage.content.getBoundingClientRect().top;
|
||||||
|
|
||||||
|
// touchstart circle
|
||||||
|
stage._pointerdown({
|
||||||
|
clientX: 289,
|
||||||
|
clientY: 100 + top,
|
||||||
|
pointerId: 1,
|
||||||
|
preventDefault: function() {}
|
||||||
|
});
|
||||||
|
|
||||||
|
assert(pointerdown, '1) pointerdown should be true');
|
||||||
|
assert(!pointermove, '1) pointermove should be false');
|
||||||
|
assert(!pointerup, '1) pointerup should be false');
|
||||||
|
|
||||||
|
// pointerup circle
|
||||||
|
stage._pointerup({
|
||||||
|
touches: [],
|
||||||
|
preventDefault: function() {}
|
||||||
|
});
|
||||||
|
|
||||||
|
assert(pointerdown, '2) pointerdown should be true');
|
||||||
|
assert(!pointermove, '2) pointermove should be false');
|
||||||
|
assert(pointerup, '2) pointerup should be true');
|
||||||
|
|
||||||
|
// pointerdown circle
|
||||||
|
stage._pointerdown({
|
||||||
|
touches: [
|
||||||
|
{
|
||||||
|
clientX: 289,
|
||||||
|
clientY: 100 + top
|
||||||
|
}
|
||||||
|
],
|
||||||
|
preventDefault: function() {}
|
||||||
|
});
|
||||||
|
|
||||||
|
assert(pointerdown, '3) pointerdown should be true');
|
||||||
|
assert(!pointermove, '3) pointermove should be false');
|
||||||
|
assert(pointerup, '3) pointerup should be true');
|
||||||
|
|
||||||
|
// pointerup circle to triger dbltap
|
||||||
|
stage._pointerup({
|
||||||
|
touches: [],
|
||||||
|
preventDefault: function() {}
|
||||||
|
});
|
||||||
|
// end drag is tied to document mouseup and pointerup event
|
||||||
|
// which can't be simulated. call _endDrag manually
|
||||||
|
//Konva.DD._endDrag();
|
||||||
|
|
||||||
|
assert(pointerdown, '4) pointerdown should be true');
|
||||||
|
assert(!pointermove, '4) pointermove should be false');
|
||||||
|
assert(pointerup, '4) pointerup should be true');
|
||||||
|
|
||||||
|
setTimeout(function() {
|
||||||
|
// pointermove circle
|
||||||
|
stage._pointermove({
|
||||||
|
touches: [
|
||||||
|
{
|
||||||
|
clientX: 290,
|
||||||
|
clientY: 100 + top
|
||||||
|
}
|
||||||
|
],
|
||||||
|
preventDefault: function() {}
|
||||||
|
});
|
||||||
|
|
||||||
|
assert(pointerdown, '5) pointerdown should be true');
|
||||||
|
assert(pointermove, '5) pointermove should be true');
|
||||||
|
assert(pointerup, '5) pointerup should be true');
|
||||||
|
|
||||||
|
done();
|
||||||
|
}, 17);
|
||||||
|
});
|
||||||
|
|
||||||
|
// ======================================================
|
||||||
|
test('pointer capture', function(done) {
|
||||||
|
var stage = addStage();
|
||||||
|
var layer = new Konva.Layer();
|
||||||
|
var circle = new Konva.Circle({
|
||||||
|
x: stage.getWidth() / 2,
|
||||||
|
y: stage.getHeight() / 2,
|
||||||
|
radius: 70,
|
||||||
|
fill: 'red',
|
||||||
|
stroke: 'black',
|
||||||
|
strokeWidth: 4
|
||||||
|
});
|
||||||
|
|
||||||
|
var circle2 = new Konva.Circle({
|
||||||
|
x: stage.getWidth() / 2,
|
||||||
|
y: 20,
|
||||||
|
radius: 20,
|
||||||
|
fill: 'red',
|
||||||
|
stroke: 'black',
|
||||||
|
strokeWidth: 4
|
||||||
|
});
|
||||||
|
|
||||||
|
// mobile events
|
||||||
|
var downCount = 0;
|
||||||
|
var otherDownCount = 0;
|
||||||
|
|
||||||
|
var pointerup = false;
|
||||||
|
var pointermove = false;
|
||||||
|
|
||||||
|
circle2.on('pointerdown', function() {
|
||||||
|
otherDownCount++;
|
||||||
|
});
|
||||||
|
|
||||||
|
circle.on('pointerdown', function(event) {
|
||||||
|
downCount++;
|
||||||
|
this.setPointerCapture(event.pointerId);
|
||||||
|
});
|
||||||
|
|
||||||
|
circle.on('pointerup', function(evt) {
|
||||||
|
assert(this.hasPointerCapture(evt.pointerId), 'circle released capture');
|
||||||
|
pointerup = true;
|
||||||
|
});
|
||||||
|
|
||||||
|
circle.on('pointermove', function(evt) {
|
||||||
|
assert(this.hasPointerCapture(evt.pointerId), 'circle has capture');
|
||||||
|
pointermove = true;
|
||||||
|
});
|
||||||
|
|
||||||
|
layer.add(circle);
|
||||||
|
layer.add(circle2);
|
||||||
|
stage.add(layer);
|
||||||
|
|
||||||
|
var top = stage.content.getBoundingClientRect().top;
|
||||||
|
|
||||||
|
// on circle 2 to confirm it works
|
||||||
|
stage._pointerdown({
|
||||||
|
clientX: 289,
|
||||||
|
clientY: 10 + top,
|
||||||
|
pointerId: 0,
|
||||||
|
preventDefault: function() {}
|
||||||
|
});
|
||||||
|
|
||||||
|
assert(otherDownCount === 1, '6) otherDownCount should be 1');
|
||||||
|
assert(downCount === 0, '6) downCount should be 0');
|
||||||
|
assert(!pointermove, '6) pointermove should be false');
|
||||||
|
assert(!pointerup, '6) pointerup should be false');
|
||||||
|
|
||||||
|
// on circle with capture
|
||||||
|
stage._pointerdown({
|
||||||
|
clientX: 289,
|
||||||
|
clientY: 100 + top,
|
||||||
|
pointerId: 1,
|
||||||
|
preventDefault: function() {}
|
||||||
|
});
|
||||||
|
|
||||||
|
assert(otherDownCount === 1, '7) otherDownCount should be 1');
|
||||||
|
assert(downCount === 1, '7) downCount should be 1');
|
||||||
|
assert(!pointermove, '7) pointermove should be false');
|
||||||
|
assert(!pointerup, '7) pointerup should be true');
|
||||||
|
|
||||||
|
// second pointerdown
|
||||||
|
stage._pointerdown({
|
||||||
|
clientX: 289,
|
||||||
|
clientY: 10 + top,
|
||||||
|
pointerId: 1,
|
||||||
|
preventDefault: function() {}
|
||||||
|
});
|
||||||
|
|
||||||
|
assert(otherDownCount === 1, '8) otherDownCount should be 1');
|
||||||
|
assert(downCount === 2, '8) pointerdown should be 2');
|
||||||
|
assert(!pointermove, '8) pointermove should be false');
|
||||||
|
assert(!pointerup, '8) pointerup should be true');
|
||||||
|
|
||||||
|
setTimeout(function() {
|
||||||
|
// pointermove over circle 2
|
||||||
|
stage._pointermove({
|
||||||
|
clientX: 290,
|
||||||
|
clientY: 10 + top,
|
||||||
|
pointerId: 1,
|
||||||
|
preventDefault: function() {}
|
||||||
|
});
|
||||||
|
|
||||||
|
assert(otherDownCount === 1, '9) otherDownCount should be 1');
|
||||||
|
assert(pointermove, '9) pointermove should be true');
|
||||||
|
|
||||||
|
stage._pointerup({
|
||||||
|
pointerId: 1,
|
||||||
|
preventDefault: function() {}
|
||||||
|
});
|
||||||
|
|
||||||
|
stage._pointerdown({
|
||||||
|
clientX: 289,
|
||||||
|
clientY: 10 + top,
|
||||||
|
pointerId: 1,
|
||||||
|
preventDefault: function() {}
|
||||||
|
});
|
||||||
|
|
||||||
|
assert(otherDownCount === 2, '10) otherDownCount should be 1');
|
||||||
|
assert(pointerup, '10) pointerup should be true');
|
||||||
|
|
||||||
|
done();
|
||||||
|
}, 17);
|
||||||
|
});
|
||||||
|
});
|
@ -177,6 +177,7 @@
|
|||||||
|
|
||||||
<script src="functional/MouseEvents-test.js"></script>
|
<script src="functional/MouseEvents-test.js"></script>
|
||||||
<script src="functional/TouchEvents-test.js"></script>
|
<script src="functional/TouchEvents-test.js"></script>
|
||||||
|
<script src="functional/PointerEvents-test.js"></script>
|
||||||
<script src="functional/DragAndDropEvents-test.js"></script>
|
<script src="functional/DragAndDropEvents-test.js"></script>
|
||||||
|
|
||||||
<!--=============== manual tests ================-->
|
<!--=============== manual tests ================-->
|
||||||
|
@ -329,4 +329,44 @@ Konva.Stage.prototype.simulateTouchEnd = function(pos) {
|
|||||||
Konva.DD._endDragAfter(evt);
|
Konva.DD._endDragAfter(evt);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Konva.Stage.prototype.simulatePointerDown = function(pos) {
|
||||||
|
var top = this.content.getBoundingClientRect().top;
|
||||||
|
|
||||||
|
this._mousedown({
|
||||||
|
clientX: pos.x,
|
||||||
|
clientY: pos.y + top,
|
||||||
|
button: pos.button || 0,
|
||||||
|
pointerId: pos.pointerId || 1
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
Konva.Stage.prototype.simulatePointerMove = function(pos) {
|
||||||
|
var top = this.content.getBoundingClientRect().top;
|
||||||
|
|
||||||
|
var evt = {
|
||||||
|
clientX: pos.x,
|
||||||
|
clientY: pos.y + top,
|
||||||
|
button: pos.button || 0,
|
||||||
|
pointerId: pos.pointerId || 1
|
||||||
|
};
|
||||||
|
|
||||||
|
this._mousemove(evt);
|
||||||
|
Konva.DD._drag(evt);
|
||||||
|
};
|
||||||
|
|
||||||
|
Konva.Stage.prototype.simulatePointerUp = function(pos) {
|
||||||
|
var top = this.content.getBoundingClientRect().top;
|
||||||
|
|
||||||
|
var evt = {
|
||||||
|
clientX: pos.x,
|
||||||
|
clientY: pos.y + top,
|
||||||
|
button: pos.button || 0,
|
||||||
|
pointerId: pos.pointerId || 1
|
||||||
|
};
|
||||||
|
|
||||||
|
Konva.DD._endDragBefore(evt);
|
||||||
|
this._mouseup(evt);
|
||||||
|
Konva.DD._endDragAfter(evt);
|
||||||
|
};
|
||||||
|
|
||||||
init();
|
init();
|
||||||
|
Loading…
Reference in New Issue
Block a user