events rewrite, fix types

This commit is contained in:
Anton Lavrenov 2021-05-07 07:48:13 -05:00
parent e5d86c9981
commit fcd7cf62b0
13 changed files with 450 additions and 851 deletions

View File

@ -20,6 +20,8 @@ This project adheres to [Semantic Versioning](http://semver.org/).
- `Konva.names` and `Konva.ids` are removed - `Konva.names` and `Konva.ids` are removed
- new `flipEnabled` property for `Konva.Transformer`. - new `flipEnabled` property for `Konva.Transformer`.
- new `node.isClientRectOnScreen()` method - new `node.isClientRectOnScreen()` method
- argument `selector` is removed from `node.getIntersection(pos)` API
- `Konva.captureTouchEventsEnabled` is renamed to `Konva.capturePointerEventsEnabled`
## 7.2.5 ## 7.2.5

View File

@ -459,8 +459,12 @@ export class Context {
* @method * @method
* @name Konva.Context#fillText * @name Konva.Context#fillText
*/ */
fillText(a0, a1, a2) { fillText(text: string, x: number, y: number, maxWidth?: number) {
this._context.fillText(a0, a1, a2); if (maxWidth) {
this._context.fillText(text, x, y, maxWidth);
} else {
this._context.fillText(text, x, y);
}
} }
/** /**
* measureText function. * measureText function.
@ -696,30 +700,6 @@ export class SceneContext extends Context {
shape._fillFunc(this); shape._fillFunc(this);
} }
_fillPattern(shape) { _fillPattern(shape) {
var fillPatternX = shape.getFillPatternX(),
fillPatternY = shape.getFillPatternY(),
fillPatternRotation = Konva.getAngle(shape.getFillPatternRotation()),
fillPatternOffsetX = shape.getFillPatternOffsetX(),
fillPatternOffsetY = shape.getFillPatternOffsetY(),
fillPatternScaleX = shape.getFillPatternScaleX(),
fillPatternScaleY = shape.getFillPatternScaleY();
// if (fillPatternX || fillPatternY) {
// this.translate(fillPatternX || 0, fillPatternY || 0);
// }
// if (fillPatternRotation) {
// this.rotate(fillPatternRotation);
// }
if (fillPatternScaleX || fillPatternScaleY) {
// this.scale(fillPatternScaleX, fillPatternScaleY);
}
// if (fillPatternOffsetX || fillPatternOffsetY) {
// this.translate(-1 * fillPatternOffsetX, -1 * fillPatternOffsetY);
// }
this.setAttr('fillStyle', shape._getFillPattern()); this.setAttr('fillStyle', shape._getFillPattern());
shape._fillFunc(this); shape._fillFunc(this);
} }

View File

@ -95,7 +95,7 @@ export const DD = {
// dragBefore and dragAfter allows us to set correct order of events // dragBefore and dragAfter allows us to set correct order of events
// setup all in dragbefore, and stop dragging only after pointerup triggered. // setup all in dragbefore, and stop dragging only after pointerup triggered.
_endDragBefore(evt?) { _endDragBefore(evt?) {
DD._dragElements.forEach((elem, key) => { DD._dragElements.forEach((elem) => {
const { node } = elem; const { node } = elem;
// we need to find pointer relative to that node // we need to find pointer relative to that node
const stage = node.getStage(); const stage = node.getStage();
@ -113,7 +113,7 @@ export const DD = {
} }
if (elem.dragStatus === 'dragging' || elem.dragStatus === 'stopped') { if (elem.dragStatus === 'dragging' || elem.dragStatus === 'stopped') {
// if a node is stopped manully we still need to reset events: // if a node is stopped manually we still need to reset events:
DD.justDragged = true; DD.justDragged = true;
Konva.listenClickTap = false; Konva.listenClickTap = false;
elem.dragStatus = 'stopped'; elem.dragStatus = 'stopped';

View File

@ -45,7 +45,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, pointerEventsEnabled: false,
/** /**
* Should Konva automatically update canvas on any changes. Default is true. * Should Konva automatically update canvas on any changes. Default is true.
* @property autoDrawEnabled * @property autoDrawEnabled
@ -72,16 +72,15 @@ export const Konva = {
* The case: we touchstart on div1, then touchmove out of that element into another element div2. * The case: we touchstart on div1, then touchmove out of that element into another element div2.
* DOM will continue trigger touchmove events on div1 (not div2). Because events are "captured" into initial target. * DOM will continue trigger touchmove events on div1 (not div2). Because events are "captured" into initial target.
* By default Konva do not do that and will trigger touchmove on another element, while pointer is moving. * By default Konva do not do that and will trigger touchmove on another element, while pointer is moving.
* @property captureTouchEventsEnabled * @property capturePointerEventsEnabled
* @default false * @default false
* @name captureTouchEventsEnabled * @name capturePointerEventsEnabled
* @memberof Konva * @memberof Konva
* @example * @example
* Konva.captureTouchEventsEnabled = true; * Konva.capturePointerEventsEnabled = true;
*/ */
captureTouchEventsEnabled: false, capturePointerEventsEnabled: false,
// TODO: move that to stage?
listenClickTap: false, listenClickTap: false,
inDblClickWindow: false, inDblClickWindow: false,

View File

@ -331,14 +331,11 @@ export class Layer extends Container<Group | Shape> {
* @param {Object} pos * @param {Object} pos
* @param {Number} pos.x * @param {Number} pos.x
* @param {Number} pos.y * @param {Number} pos.y
* @param {String} [selector]
* @returns {Konva.Node} * @returns {Konva.Node}
* @example * @example
* var shape = layer.getIntersection({x: 50, y: 50}); * var shape = layer.getIntersection({x: 50, y: 50});
* // or if you interested in shape parent:
* var group = layer.getIntersection({x: 50, y: 50}, 'Group');
*/ */
getIntersection(pos: Vector2d, selector?: string): Node | null { getIntersection(pos: Vector2d) {
if (!this.isListening() || !this.isVisible()) { if (!this.isListening() || !this.isVisible()) {
return null; return null;
} }
@ -354,9 +351,7 @@ export class Layer extends Container<Group | Shape> {
y: pos.y + intersectionOffset.y * spiralSearchDistance, y: pos.y + intersectionOffset.y * spiralSearchDistance,
}); });
const shape = obj.shape; const shape = obj.shape;
if (shape && selector) { if (shape) {
return shape.findAncestor(selector, true);
} else if (shape) {
return shape; return shape;
} }
// we should continue search if we found antialiased pixel // we should continue search if we found antialiased pixel

View File

@ -39,6 +39,7 @@ var STAGE = 'Stage',
TAP = 'tap', TAP = 'tap',
DBL_TAP = 'dbltap', DBL_TAP = 'dbltap',
TOUCHMOVE = 'touchmove', TOUCHMOVE = 'touchmove',
TOUCHCANCEL = 'touchcancel',
WHEEL = 'wheel', WHEEL = 'wheel',
CONTENT_MOUSEOUT = 'contentMouseout', CONTENT_MOUSEOUT = 'contentMouseout',
CONTENT_MOUSEOVER = 'contentMouseover', CONTENT_MOUSEOVER = 'contentMouseover',
@ -53,52 +54,97 @@ 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',
SPACE = ' ',
UNDERSCORE = '_', UNDERSCORE = '_',
CONTAINER = 'container', CONTAINER = 'container',
MAX_LAYERS_NUMBER = 5, MAX_LAYERS_NUMBER = 5,
EMPTY_STRING = '', EMPTY_STRING = '',
EVENTS = [ EVENTS = [
MOUSEENTER, [MOUSEENTER, '_pointerenter'],
MOUSEDOWN, [MOUSEDOWN, '_pointerdown'],
MOUSEMOVE, [MOUSEMOVE, '_pointermove'],
MOUSEUP, [MOUSEUP, '_pointerup'],
MOUSELEAVE, [MOUSELEAVE, '_pointerleave'],
TOUCHSTART, [TOUCHSTART, '_pointerdown'],
TOUCHMOVE, [TOUCHMOVE, '_pointermove'],
TOUCHEND, [TOUCHEND, '_pointerup'],
MOUSEOVER, [TOUCHCANCEL, '_pointercancel'],
WHEEL, [MOUSEOVER, '_pointerover'],
CONTEXTMENU, [WHEEL, '_wheel'],
POINTERDOWN, [CONTEXTMENU, '_contextmenu'],
POINTERMOVE, [POINTERDOWN, '_pointerdown'],
POINTERUP, [POINTERMOVE, '_pointermove'],
POINTERCANCEL, [POINTERUP, '_pointerup'],
LOSTPOINTERCAPTURE, [POINTERCANCEL, '_pointercancel'],
], [LOSTPOINTERCAPTURE, '_lostpointercapture'],
// cached variables ];
eventsLength = EVENTS.length;
function addEvent(ctx, eventName) {
ctx.content.addEventListener(
eventName,
function (evt) {
ctx[UNDERSCORE + eventName](evt);
},
false
);
}
const NO_POINTERS_MESSAGE = `Pointer position is missing and not registered by the stage. Looks like it is outside of the stage container. You can set it manually from event: stage.setPointersPositions(event);`; const NO_POINTERS_MESSAGE = `Pointer position is missing and not registered by the stage. Looks like it is outside of the stage container. You can set it manually from event: stage.setPointersPositions(event);`;
export const stages: Stage[] = []; export const stages: Stage[] = [];
const EVENTS_MAP = {
mouse: {
pointerout: 'mouseout',
pointerleave: 'mouseleave',
pointerover: 'mouseover',
pointerenter: 'mouseenter',
pointermove: 'mousemove',
pointerdown: 'mousedown',
pointerup: 'mouseup',
pointercancel: 'mousecancel',
pointerclick: 'click',
pointerdblclick: 'dblclick',
},
touch: {
pointerout: 'touchout',
pointerleave: 'touchleave',
pointerover: 'touchover',
pointerenter: 'touchenter',
pointermove: 'touchmove',
pointerdown: 'touchstart',
pointerup: 'touchend',
pointerclick: 'tap',
pointerdblclick: 'dbltap',
},
pointer: {
pointerout: 'pointerout',
pointerleave: 'pointerleave',
pointerover: 'pointerover',
pointerenter: 'pointerenter',
pointermove: 'pointermove',
pointerdown: 'pointerdown',
pointerup: 'pointerup',
pointerclick: 'pointerclick',
pointerdblclick: 'pointerdblclick',
},
};
const getEventType = (type) => {
if (type.indexOf('pointer') >= 0) {
return 'pointer';
}
if (type.indexOf('touch') >= 0) {
return 'touch';
}
return 'mouse';
};
const getEventsMap = (eventType: string) => {
const type = getEventType(eventType);
if (type === 'pointer') {
return Konva.pointerEventsEnabled && EVENTS_MAP.pointer;
}
if (type === 'touch') {
return EVENTS_MAP.touch;
}
if (type === 'mouse') {
return EVENTS_MAP.mouse;
}
};
function checkNoClip(attrs: any = {}) { function checkNoClip(attrs: any = {}) {
if (attrs.clipFunc || attrs.clipWidth || attrs.clipHeight) { if (attrs.clipFunc || attrs.clipWidth || attrs.clipHeight) {
Util.warn( Util.warn(
@ -128,16 +174,23 @@ export class Stage extends Container<Layer> {
content: HTMLDivElement; content: HTMLDivElement;
pointerPos: Vector2d | null; pointerPos: Vector2d | null;
_pointerPositions: (Vector2d & { id?: number })[] = []; _pointerPositions: (Vector2d & { id?: number })[] = [];
_changedPointerPositions: (Vector2d & { id?: number })[] = []; _changedPointerPositions: (Vector2d & { id: number })[] = [];
bufferCanvas: SceneCanvas; bufferCanvas: SceneCanvas;
bufferHitCanvas: HitCanvas; bufferHitCanvas: HitCanvas;
targetShape: Shape; _mouseTargetShape: Shape;
clickStartShape: Shape; _touchTargetShape: Shape;
clickEndShape: Shape; _pointerTargetShape: Shape;
tapStartShape: Shape; _mouseClickStartShape: Shape;
tapEndShape: Shape; _touchClickStartShape: Shape;
dblTimeout: any; _pointerClickStartShape: Shape;
_mouseClickEndShape: Shape;
_touchClickEndShape: Shape;
_pointerClickEndShape: Shape;
_mouseDblTimeout: any;
_touchDblTimeout: any;
_pointerDblTimeout: any;
constructor(config: StageConfig) { constructor(config: StageConfig) {
super(checkNoClip(config)); super(checkNoClip(config));
@ -320,14 +373,11 @@ export class Stage extends Container<Layer> {
* @param {Object} pos * @param {Object} pos
* @param {Number} pos.x * @param {Number} pos.x
* @param {Number} pos.y * @param {Number} pos.y
* @param {String} [selector]
* @returns {Konva.Node} * @returns {Konva.Node}
* @example * @example
* var shape = stage.getIntersection({x: 50, y: 50}); * var shape = stage.getIntersection({x: 50, y: 50});
* // or if you interested in shape parent:
* var group = stage.getIntersection({x: 50, y: 50}, 'Group');
*/ */
getIntersection(pos: Vector2d | null, selector?: string) { getIntersection(pos: Vector2d) {
if (!pos) { if (!pos) {
return null; return null;
} }
@ -337,7 +387,7 @@ export class Stage extends Container<Layer> {
n; n;
for (n = end; n >= 0; n--) { for (n = end; n >= 0; n--) {
const shape = layers[n].getIntersection(pos, selector); const shape = layers[n].getIntersection(pos);
if (shape) { if (shape) {
return shape; return shape;
} }
@ -423,36 +473,64 @@ export class Stage extends Container<Layer> {
if (!Konva.isBrowser) { if (!Konva.isBrowser) {
return; return;
} }
for (var n = 0; n < eventsLength; n++) { EVENTS.forEach(([event, methodName]) => {
addEvent(this, EVENTS[n]); this.content.addEventListener(event, (evt) => {
this[methodName](evt);
});
});
}
_pointerenter(evt) {
this.setPointersPositions(evt);
const events = getEventsMap(evt.type);
this._fire(events.pointerenter, {
evt: evt,
target: this,
currentTarget: this,
});
}
_pointerover(evt) {
this.setPointersPositions(evt);
const events = getEventsMap(evt.type);
this._fire(events.pointerover, {
evt: evt,
target: this,
currentTarget: this,
});
}
_getTargetShape(evenType) {
let shape: Shape | null = this[evenType + 'targetShape'];
if (shape && !shape.getStage()) {
shape = null;
} }
return shape;
} }
_mouseenter(evt) { _pointerleave(evt) {
this.setPointersPositions(evt); const events = getEventsMap(evt.type);
this._fire(MOUSEENTER, { evt: evt, target: this, currentTarget: this }); const eventType = getEventType(evt.type);
}
_mouseover(evt) {
this.setPointersPositions(evt);
this._fire(CONTENT_MOUSEOVER, { evt: evt });
this._fire(MOUSEOVER, { evt: evt, target: this, currentTarget: this });
}
_mouseleave(evt) {
this.setPointersPositions(evt);
var targetShape = this.targetShape?.getStage() ? this.targetShape : null;
if (!events) {
return;
}
this.setPointersPositions(evt);
var targetShape = this._getTargetShape(eventType);
var eventsEnabled = !DD.isDragging || Konva.hitOnDragEnabled; var eventsEnabled = !DD.isDragging || Konva.hitOnDragEnabled;
if (targetShape && eventsEnabled) { if (targetShape && eventsEnabled) {
targetShape._fireAndBubble(MOUSEOUT, { evt: evt }); targetShape._fireAndBubble(events.pointerout, { evt: evt });
targetShape._fireAndBubble(MOUSELEAVE, { evt: evt }); targetShape._fireAndBubble(events.pointerleave, { evt: evt });
this._fire(MOUSELEAVE, { evt: evt, target: this, currentTarget: this }); this._fire(events.pointerleave, {
this.targetShape = null;
} else if (eventsEnabled) {
this._fire(MOUSELEAVE, {
evt: evt, evt: evt,
target: this, target: this,
currentTarget: this, currentTarget: this,
}); });
this._fire(MOUSEOUT, { this[eventType + 'targetShape'] = null;
} else if (eventsEnabled) {
this._fire(events.pointerleave, {
evt: evt,
target: this,
currentTarget: this,
});
this._fire(events.pointerout, {
evt: evt, evt: evt,
target: this, target: this,
currentTarget: this, currentTarget: this,
@ -460,177 +538,220 @@ export class Stage extends Container<Layer> {
} }
this.pointerPos = undefined; this.pointerPos = undefined;
this._pointerPositions = []; this._pointerPositions = [];
this._fire(CONTENT_MOUSEOUT, { evt: evt });
} }
_mousemove(evt) { _pointerdown(evt: TouchEvent | MouseEvent | PointerEvent) {
const events = getEventsMap(evt.type);
const eventType = getEventType(evt.type);
if (!events) {
return;
}
this.setPointersPositions(evt); this.setPointersPositions(evt);
var pointerId = Util._getFirstPointerId(evt);
var targetShape = this.targetShape?.getStage() ? this.targetShape : null; var triggeredOnShape = false;
this._changedPointerPositions.forEach((pos) => {
var shape = this.getIntersection(pos);
DD.justDragged = false;
// probably we are staring a click
Konva.listenClickTap = true;
// no shape detected? do nothing
const hasShape = shape && shape.isListening();
if (!hasShape) {
return;
}
if (Konva.capturePointerEventsEnabled) {
shape.setPointerCapture(pos.id);
}
// save where we started the click
this[eventType + 'ClickStartShape'] = shape;
shape._fireAndBubble(events.pointerdown, {
evt: evt,
pointerId: pos.id,
});
triggeredOnShape = true;
// TODO: test in iframe
// only call preventDefault if the shape is listening for events
const isTouch = evt.type.indexOf('touch') >= 0;
if (shape.preventDefault() && evt.cancelable && isTouch) {
evt.preventDefault();
}
});
// trigger down on stage if not already
if (!triggeredOnShape) {
this._fire(events.pointerdown, {
evt: evt,
target: this,
currentTarget: this,
pointerId: this._pointerPositions[0].id,
});
}
}
_pointermove(evt: TouchEvent | MouseEvent | PointerEvent) {
const events = getEventsMap(evt.type);
const eventType = getEventType(evt.type);
if (!events) {
return;
}
if (DD.isDragging && DD.node.preventDefault() && evt.cancelable) {
evt.preventDefault();
}
this.setPointersPositions(evt);
var eventsEnabled = !DD.isDragging || Konva.hitOnDragEnabled; var eventsEnabled = !DD.isDragging || Konva.hitOnDragEnabled;
if (eventsEnabled) { if (!eventsEnabled) {
const shape = this.getIntersection(this.getPointerPosition()) as Shape; return;
if (shape && shape.isListening()) { }
var differentTarget = targetShape !== shape;
if (eventsEnabled && differentTarget) { var processedShapesIds = {};
if (targetShape) { let triggeredOnShape = false;
targetShape._fireAndBubble( var targetShape = this._getTargetShape(eventType);
MOUSEOUT, this._changedPointerPositions.forEach((pos) => {
{ evt: evt, pointerId }, const shape = (PointerEvents.getCapturedShape(pos.id) ||
shape this.getIntersection(pos)) as Shape;
); const pointerId = pos.id;
targetShape._fireAndBubble( const event = { evt: evt, pointerId };
MOUSELEAVE,
{ evt: evt, pointerId }, var differentTarget = targetShape !== shape;
shape
); if (differentTarget && targetShape) {
} targetShape._fireAndBubble(events.pointerout, event, shape);
shape._fireAndBubble(MOUSEOVER, { evt: evt, pointerId }, targetShape); targetShape._fireAndBubble(events.pointerleave, event, shape);
shape._fireAndBubble( }
MOUSEENTER,
{ evt: evt, pointerId }, if (shape) {
targetShape if (processedShapesIds[shape._id]) {
); return;
shape._fireAndBubble(MOUSEMOVE, { evt: evt, pointerId });
this.targetShape = shape;
} else {
shape._fireAndBubble(MOUSEMOVE, { evt: evt, pointerId });
} }
processedShapesIds[shape._id] = true;
}
if (shape && shape.isListening()) {
triggeredOnShape = true;
if (differentTarget) {
shape._fireAndBubble(events.pointerover, event, targetShape);
shape._fireAndBubble(events.pointerenter, event, targetShape);
this[eventType + 'targetShape'] = shape;
}
shape._fireAndBubble(events.pointermove, event);
} else { } else {
/* if (targetShape) {
* if no shape was detected, clear target shape and try this._fire(events.pointerover, {
* to run mouseout from previous target shape
*/
if (targetShape && eventsEnabled) {
targetShape._fireAndBubble(MOUSEOUT, { evt: evt, pointerId });
targetShape._fireAndBubble(MOUSELEAVE, { evt: evt, pointerId });
this._fire(MOUSEOVER, {
evt: evt, evt: evt,
target: this, target: this,
currentTarget: this, currentTarget: this,
pointerId, pointerId,
}); });
this.targetShape = null; this[eventType + 'targetShape'] = null;
} }
this._fire(MOUSEMOVE, {
evt: evt,
target: this,
currentTarget: this,
pointerId,
});
} }
});
// content event if (!triggeredOnShape) {
this._fire(CONTENT_MOUSEMOVE, { evt: evt }); this._fire(events.pointermove, {
}
// always call preventDefault for desktop events because some browsers
// try to drag and drop the canvas element
if (evt.cancelable) {
evt.preventDefault();
}
}
_mousedown(evt) {
this.setPointersPositions(evt);
var pointerId = Util._getFirstPointerId(evt);
var shape = this.getIntersection(this.getPointerPosition()) as Shape;
DD.justDragged = false;
Konva.listenClickTap = true;
if (shape && shape.isListening()) {
this.clickStartShape = shape;
shape._fireAndBubble(MOUSEDOWN, { evt: evt, pointerId });
} else {
this._fire(MOUSEDOWN, {
evt: evt, evt: evt,
target: this, target: this,
currentTarget: this, currentTarget: this,
pointerId, pointerId: this._changedPointerPositions[0].id,
}); });
} }
// content event // content event
this._fire(CONTENT_MOUSEDOWN, { evt: evt }); this._fire(CONTENT_MOUSEMOVE, { evt: evt });
// Do not prevent default behavior, because it will prevent listening events outside of window iframe
// we used preventDefault for disabling native drag&drop
// but userSelect = none style will do the trick
// if (evt.cancelable) {
// evt.preventDefault();
// }
} }
_mouseup(evt) { _pointerup(evt) {
this.setPointersPositions(evt); const events = getEventsMap(evt.type);
var pointerId = Util._getFirstPointerId(evt); const eventType = getEventType(evt.type);
var shape = this.getIntersection(this.getPointerPosition()) as Shape,
clickStartShape = this.clickStartShape,
clickEndShape = this.clickEndShape,
fireDblClick = false;
if (Konva.inDblClickWindow) { if (!events) {
fireDblClick = true; return;
clearTimeout(this.dblTimeout);
// Konva.inDblClickWindow = false;
} else if (!DD.justDragged) {
// don't set inDblClickWindow after dragging
Konva.inDblClickWindow = true;
clearTimeout(this.dblTimeout);
} }
this.setPointersPositions(evt);
const clickStartShape = this[eventType + 'ClickStartShape'];
const clickEndShape = this[eventType + 'ClickEndShape'];
var processedShapesIds = {};
let triggeredOnShape = false;
this._changedPointerPositions.forEach((pos) => {
const shape = (PointerEvents.getCapturedShape(pos.id) ||
this.getIntersection(pos)) as Shape;
this.dblTimeout = setTimeout(function () { if (shape) {
Konva.inDblClickWindow = false; shape.releaseCapture(pos.id);
}, Konva.dblClickWindow); if (processedShapesIds[shape._id]) {
return;
}
processedShapesIds[shape._id] = true;
}
if (shape && shape.isListening()) { const pointerId = pos.id;
this.clickEndShape = shape; const event = { evt: evt, pointerId };
shape._fireAndBubble(MOUSEUP, { evt: evt, pointerId });
// detect if click or double click occurred let fireDblClick = false;
if ( if (Konva.inDblClickWindow) {
Konva.listenClickTap && fireDblClick = true;
clickStartShape && clearTimeout(this[eventType + 'DblTimeout']);
clickStartShape._id === shape._id } else if (!DD.justDragged) {
) { // don't set inDblClickWindow after dragging
shape._fireAndBubble(CLICK, { evt: evt, pointerId }); Konva.inDblClickWindow = true;
clearTimeout(this[eventType + 'DblTimeout']);
}
if (fireDblClick && clickEndShape && clickEndShape === shape) { this[eventType + 'DblTimeout'] = setTimeout(function () {
shape._fireAndBubble(DBL_CLICK, { evt: evt, pointerId }); Konva.inDblClickWindow = false;
}, Konva.dblClickWindow);
if (shape && shape.isListening()) {
triggeredOnShape = true;
this[eventType + 'ClickEndShape'] = shape;
shape._fireAndBubble(events.pointerup, event);
// detect if click or double click occurred
if (
Konva.listenClickTap &&
clickStartShape &&
clickStartShape === shape
) {
shape._fireAndBubble(events.pointerclick, event);
if (fireDblClick && clickEndShape && clickEndShape === shape) {
shape._fireAndBubble(events.pointerdblclick, event);
}
}
} else {
this[eventType + 'ClickEndShape'] = null;
if (Konva.listenClickTap) {
this._fire(events.pointerclick, {
evt: evt,
target: this,
currentTarget: this,
pointerId,
});
}
if (fireDblClick) {
this._fire(events.pointerdblclick, {
evt: evt,
target: this,
currentTarget: this,
pointerId,
});
} }
} }
} else { });
this.clickEndShape = null;
this._fire(MOUSEUP, { if (!triggeredOnShape) {
this._fire(events.pointerup, {
evt: evt, evt: evt,
target: this, target: this,
currentTarget: this, currentTarget: this,
pointerId, pointerId: this._changedPointerPositions[0].id,
}); });
if (Konva.listenClickTap) {
this._fire(CLICK, {
evt: evt,
target: this,
currentTarget: this,
pointerId,
});
}
if (fireDblClick) {
this._fire(DBL_CLICK, {
evt: evt,
target: this,
currentTarget: this,
pointerId,
});
}
}
// content events
this._fire(CONTENT_MOUSEUP, { evt: evt });
if (Konva.listenClickTap) {
this._fire(CONTENT_CLICK, { evt: evt });
if (fireDblClick) {
this._fire(CONTENT_DBL_CLICK, { evt: evt });
}
} }
Konva.listenClickTap = false; Konva.listenClickTap = false;
@ -654,190 +775,6 @@ export class Stage extends Container<Layer> {
currentTarget: this, currentTarget: this,
}); });
} }
this._fire(CONTENT_CONTEXTMENU, { evt: evt });
}
_touchstart(evt) {
this.setPointersPositions(evt);
var triggeredOnShape = false;
this._changedPointerPositions.forEach((pos) => {
var shape = this.getIntersection(pos) as Shape;
Konva.listenClickTap = true;
DD.justDragged = false;
const hasShape = shape && shape.isListening();
if (!hasShape) {
return;
}
if (Konva.captureTouchEventsEnabled) {
shape.setPointerCapture(pos.id);
}
this.tapStartShape = shape;
shape._fireAndBubble(TOUCHSTART, { evt: evt, pointerId: pos.id }, this);
triggeredOnShape = true;
// only call preventDefault if the shape is listening for events
if (shape.isListening() && shape.preventDefault() && evt.cancelable) {
evt.preventDefault();
}
});
if (!triggeredOnShape) {
this._fire(TOUCHSTART, {
evt: evt,
target: this,
currentTarget: this,
pointerId: this._changedPointerPositions[0].id,
});
}
// content event
this._fire(CONTENT_TOUCHSTART, { evt: evt });
}
_touchmove(evt) {
this.setPointersPositions(evt);
var eventsEnabled = !DD.isDragging || Konva.hitOnDragEnabled;
if (eventsEnabled) {
var triggeredOnShape = false;
var processedShapesIds = {};
this._changedPointerPositions.forEach((pos) => {
const shape =
PointerEvents.getCapturedShape(pos.id) || this.getIntersection(pos);
const hasShape = shape && shape.isListening();
if (!hasShape) {
return;
}
if (processedShapesIds[shape._id]) {
return;
}
processedShapesIds[shape._id] = true;
shape._fireAndBubble(TOUCHMOVE, { evt: evt, pointerId: pos.id });
triggeredOnShape = true;
// only call preventDefault if the shape is listening for events
if (shape.isListening() && shape.preventDefault() && evt.cancelable) {
evt.preventDefault();
}
});
if (!triggeredOnShape) {
this._fire(TOUCHMOVE, {
evt: evt,
target: this,
currentTarget: this,
pointerId: this._changedPointerPositions[0].id,
});
}
this._fire(CONTENT_TOUCHMOVE, { evt: evt });
}
if (DD.isDragging && DD.node.preventDefault() && evt.cancelable) {
evt.preventDefault();
}
}
_touchend(evt) {
this.setPointersPositions(evt);
var tapEndShape = this.tapEndShape,
fireDblClick = false;
if (Konva.inDblClickWindow) {
fireDblClick = true;
clearTimeout(this.dblTimeout);
// Konva.inDblClickWindow = false;
} else if (!DD.justDragged) {
Konva.inDblClickWindow = true;
clearTimeout(this.dblTimeout);
}
this.dblTimeout = setTimeout(function () {
Konva.inDblClickWindow = false;
}, Konva.dblClickWindow);
var triggeredOnShape = false;
var processedShapesIds = {};
var tapTriggered = false;
var dblTapTriggered = false;
this._changedPointerPositions.forEach((pos) => {
var shape =
(PointerEvents.getCapturedShape(pos.id) as Shape) ||
(this.getIntersection(pos) as Shape);
if (shape) {
shape.releaseCapture(pos.id);
}
const hasShape = shape && shape.isListening();
if (!hasShape) {
return;
}
if (processedShapesIds[shape._id]) {
return;
}
processedShapesIds[shape._id] = true;
this.tapEndShape = shape;
shape._fireAndBubble(TOUCHEND, { evt: evt, pointerId: pos.id });
triggeredOnShape = true;
// detect if tap or double tap occurred
if (Konva.listenClickTap && shape === this.tapStartShape) {
tapTriggered = true;
shape._fireAndBubble(TAP, { evt: evt, pointerId: pos.id });
if (fireDblClick && tapEndShape && tapEndShape === shape) {
dblTapTriggered = true;
shape._fireAndBubble(DBL_TAP, { evt: evt, pointerId: pos.id });
}
}
// only call preventDefault if the shape is listening for events
if (shape.isListening() && shape.preventDefault() && evt.cancelable) {
evt.preventDefault();
}
});
if (!triggeredOnShape) {
this._fire(TOUCHEND, {
evt: evt,
target: this,
currentTarget: this,
pointerId: this._changedPointerPositions[0].id,
});
}
if (Konva.listenClickTap && !tapTriggered) {
this.tapEndShape = null;
this._fire(TAP, {
evt: evt,
target: this,
currentTarget: this,
pointerId: this._changedPointerPositions[0].id,
});
}
if (fireDblClick && !dblTapTriggered) {
this._fire(DBL_TAP, {
evt: evt,
target: this,
currentTarget: this,
pointerId: this._changedPointerPositions[0].id,
});
}
// content events
this._fire(CONTENT_TOUCHEND, { evt: evt });
if (Konva.listenClickTap) {
this._fire(CONTENT_TAP, { evt: evt });
if (fireDblClick) {
this._fire(CONTENT_DBL_TAP, { evt: evt });
}
}
if (this.preventDefault() && evt.cancelable) {
evt.preventDefault();
}
Konva.listenClickTap = false;
} }
_wheel(evt) { _wheel(evt) {
@ -853,59 +790,9 @@ export class Stage extends Container<Layer> {
currentTarget: this, currentTarget: this,
}); });
} }
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) { _pointercancel(evt: PointerEvent) {
if (!Konva._pointerEventsEnabled) {
return;
}
this.setPointersPositions(evt); this.setPointersPositions(evt);
const shape = const shape =
PointerEvents.getCapturedShape(evt.pointerId) || PointerEvents.getCapturedShape(evt.pointerId) ||

View File

@ -33,7 +33,7 @@ declare namespace Konva {
export let dragDistance: number; export let dragDistance: number;
export let angleDeg: boolean; export let angleDeg: boolean;
export let showWarnings: boolean; export let showWarnings: boolean;
export let captureTouchEventsEnabled: boolean; export let capturePointerEventsEnabled: boolean;
export let dragButtons: Array<number>; export let dragButtons: Array<number>;
export let hitOnDragEnabled: boolean; export let hitOnDragEnabled: boolean;
export const isDragging: () => boolean; export const isDragging: () => boolean;

View File

@ -243,56 +243,6 @@ describe('Layer', function () {
); );
}); });
// ======================================================
it('layer getIntersection() with selector', function () {
var stage = addStage();
var layer = new Konva.Layer({
name: 'layer',
});
var group = new Konva.Group({
name: 'group',
});
var circle = new Konva.Circle({
x: stage.width() / 2,
y: stage.height() / 2,
radius: 70,
strokeWidth: 4,
fill: 'red',
stroke: 'black',
});
group.add(circle);
layer.add(group);
stage.add(layer);
assert.equal(
layer.getIntersection(
{ x: stage.width() / 2, y: stage.height() / 2 },
'Circle'
),
circle,
'intersection with shape selector'
);
assert.equal(
layer.getIntersection(
{ x: stage.width() / 2, y: stage.height() / 2 },
'.group'
),
group,
'intersection with group selector'
);
assert.equal(
layer.getIntersection(
{ x: stage.width() / 2, y: stage.height() / 2 },
'Stage'
),
stage,
'intersection with stage selector'
);
});
// ====================================================== // ======================================================
it('set layer visibility', function () { it('set layer visibility', function () {
var stage = addStage(); var stage = addStage();

View File

@ -12,139 +12,6 @@ import {
} from './test-utils'; } from './test-utils';
describe('MouseEvents', function () { describe('MouseEvents', function () {
// ======================================================
it('stage content mouse events', function (done) {
var stage = addStage();
var layer = new Konva.Layer();
var circle = new Konva.Circle({
x: 100,
y: 100,
radius: 70,
fill: 'green',
stroke: 'black',
strokeWidth: 4,
name: 'myCircle',
});
layer.add(circle);
stage.add(layer);
var circleMousedown = 0;
var circleMouseup = 0;
var stageContentMousedown = 0;
var stageContentMouseup = 0;
var stageContentMousemove = 0;
var stageContentMouseout = 0;
var stageContentMouseover = 0;
var stageContentClick = 0;
var stageContentDblClick = 0;
circle.on('mousedown', function () {
circleMousedown++;
});
circle.on('mouseup', function () {
circleMouseup++;
});
stage.on('contentMousedown', function () {
stageContentMousedown++;
});
stage.on('contentMouseup', function () {
stageContentMouseup++;
});
stage.on('contentMousemove', function () {
stageContentMousemove++;
});
stage.on('contentMouseout', function () {
stageContentMouseout++;
});
stage.on('contentMouseover', function () {
stageContentMouseover++;
});
stage.on('contentClick', function () {
//console.log('click');
stageContentClick++;
});
stage.on('contentDblclick', function () {
//console.log('dbl click');
stageContentDblClick++;
});
simulateMouseDown(stage, {
x: 100,
y: 100,
});
simulateMouseUp(stage, {
x: 100,
y: 100,
});
assert.equal(circleMousedown, 1);
assert.equal(circleMouseup, 1);
assert.equal(stageContentMousedown, 1);
assert.equal(stageContentMouseup, 1);
assert.equal(stageContentClick, 1);
simulateMouseDown(stage, {
x: 1,
y: 1,
});
simulateMouseUp(stage, {
x: 1,
y: 1,
});
assert.equal(stageContentMousedown, 2);
assert.equal(stageContentMouseup, 2);
// trigger double click
simulateMouseDown(stage, {
x: 1,
y: 1,
});
simulateMouseUp(stage, {
x: 1,
y: 1,
});
assert.equal(stageContentMousedown, 3);
assert.equal(stageContentMouseup, 3);
//assert.equal(stageContentDblClick, 1);
setTimeout(function () {
simulateMouseMove(stage, {
x: 200,
y: 1,
});
assert.equal(stageContentMousemove, 1);
stage._mouseleave({
offsetX: 0,
offsetY: 0,
});
assert.equal(stageContentMouseout, 1);
stage._mouseover({
offsetX: 0,
offsetY: 0,
});
assert.equal(stageContentMouseover, 1);
done();
}, 20);
});
// ====================================================== // ======================================================
it('remove shape with onclick', function () { it('remove shape with onclick', function () {
var stage = addStage(); var stage = addStage();
@ -443,6 +310,54 @@ describe('MouseEvents', function () {
}, 20); }, 20);
}); });
it.skip('mouseleave and mouseenter', function () {
var stage = addStage();
var layer = new Konva.Layer({
throttle: 999,
});
var circle = new Konva.Circle({
x: 100,
y: 100,
radius: 70,
strokeWidth: 4,
fill: 'red',
stroke: 'black',
});
layer.add(circle);
stage.add(layer);
var mouseenter = 0;
circle.on('mouseenter', () => {
mouseenter += 1;
});
var mouseleave = 0;
circle.on('mouseleave', () => {
mouseleave += 1;
});
simulateMouseMove(stage, {
x: 10,
y: 10,
});
simulateMouseMove(stage, {
x: 100,
y: 100,
});
simulateMouseMove(stage, {
x: 100,
y: 100,
});
assert.equal(mouseenter, 1);
assert.equal(mouseleave, 0);
simulateMouseMove(stage, {
x: 10,
y: 10,
});
assert.equal(mouseenter, 1);
assert.equal(mouseleave, 1);
});
// ====================================================== // ======================================================
it('mousedown mouseup mouseover mouseout mousemove click dblclick', function (done) { it('mousedown mouseup mouseover mouseout mousemove click dblclick', function (done) {
var stage = addStage(); var stage = addStage();
@ -2045,7 +1960,7 @@ describe('MouseEvents', function () {
y: 15, y: 15,
}); });
assert.equal(bigClicks, 0, 'single click on big rect'); assert.equal(bigClicks, 0, 'single click on big rect (1)');
assert.equal(smallClicks, 0, 'no click on small rect'); assert.equal(smallClicks, 0, 'no click on small rect');
assert.equal(smallDblClicks, 0, 'no dblclick on small rect'); assert.equal(smallDblClicks, 0, 'no dblclick on small rect');
@ -2059,7 +1974,7 @@ describe('MouseEvents', function () {
y: 100, y: 100,
}); });
assert.equal(bigClicks, 0, 'single click on big rect'); assert.equal(bigClicks, 0, 'single click on big rect (2)');
assert.equal(smallClicks, 1, 'single click on small rect'); assert.equal(smallClicks, 1, 'single click on small rect');
assert.equal(smallDblClicks, 0, 'no dblclick on small rect'); assert.equal(smallDblClicks, 0, 'no dblclick on small rect');
@ -2073,7 +1988,7 @@ describe('MouseEvents', function () {
y: 100, y: 100,
}); });
assert.equal(bigClicks, 0, 'single click on big rect'); assert.equal(bigClicks, 0, 'single click on big rect (3)');
assert.equal(smallClicks, 2, 'second click on small rect'); assert.equal(smallClicks, 2, 'second click on small rect');
assert.equal(smallDblClicks, 1, 'single dblclick on small rect'); assert.equal(smallDblClicks, 1, 'single dblclick on small rect');
@ -2097,9 +2012,10 @@ describe('MouseEvents', function () {
clientX: 10, clientX: 10,
clientY: 10 + top, clientY: 10 + top,
button: 0, button: 0,
type: 'mouseenter',
}; };
stage._mouseenter(evt); stage._pointerenter(evt);
assert.equal(mouseenterCount, 1, 'mouseenterCount should be 1'); assert.equal(mouseenterCount, 1, 'mouseenterCount should be 1');
}); });
@ -2119,9 +2035,10 @@ describe('MouseEvents', function () {
clientX: 0, clientX: 0,
clientY: 0 + top, clientY: 0 + top,
button: 0, button: 0,
type: 'mouseleave',
}; };
stage._mouseleave(evt); stage._pointerleave(evt);
assert.equal(mouseleave, 1, 'mouseleave should be 1'); assert.equal(mouseleave, 1, 'mouseleave should be 1');
}); });
@ -2178,9 +2095,10 @@ describe('MouseEvents', function () {
clientX: 200, clientX: 200,
clientY: -5 + top, clientY: -5 + top,
button: 0, button: 0,
type: 'mouseleave',
}; };
stage._mouseleave(evt); stage._pointerleave(evt);
assert.equal(circleMouseleave, 1, 'circleMouseleave should be 1'); assert.equal(circleMouseleave, 1, 'circleMouseleave should be 1');
assert.equal(circleMouseout, 1, 'circleMouseout should be 1'); assert.equal(circleMouseout, 1, 'circleMouseout should be 1');
@ -2294,16 +2212,20 @@ describe('MouseEvents', function () {
clientX: 10, clientX: 10,
clientY: 10 + top, clientY: 10 + top,
button: 0, button: 0,
type: 'mouseenter',
}; };
stage._mouseenter(evt); stage._pointerenter(evt);
simulateMouseMove(stage, { simulateMouseMove(stage, {
x: 10, x: 10,
y: 10, y: 10,
}); });
stage._mouseleave(evt); stage._pointerleave({
...evt,
type: 'mouseleave',
});
assert.equal(mouseenter, 1, 'mouseenter should be 1'); assert.equal(mouseenter, 1, 'mouseenter should be 1');
}); });

View File

@ -8,9 +8,7 @@ import {
simulatePointerUp, simulatePointerUp,
} from './test-utils'; } from './test-utils';
// TODO: restore it!
describe.skip('PointerEvents', function () { describe.skip('PointerEvents', function () {
Konva._pointerEventsEnabled = true;
// ====================================================== // ======================================================
it('pointerdown pointerup pointermove', function (done) { it('pointerdown pointerup pointermove', function (done) {
var stage = addStage(); var stage = addStage();
@ -51,8 +49,6 @@ describe.skip('PointerEvents', function () {
simulatePointerDown(stage, { simulatePointerDown(stage, {
x: 289, x: 289,
y: 100, y: 100,
pointerId: 1,
preventDefault: function () {},
}); });
assert(pointerdown, '1) pointerdown should be true'); assert(pointerdown, '1) pointerdown should be true');
@ -61,8 +57,8 @@ describe.skip('PointerEvents', function () {
// pointerup circle // pointerup circle
simulatePointerUp(stage, { simulatePointerUp(stage, {
touches: [], x: 289,
preventDefault: function () {}, y: 100,
}); });
assert(pointerdown, '2) pointerdown should be true'); assert(pointerdown, '2) pointerdown should be true');
@ -71,13 +67,8 @@ describe.skip('PointerEvents', function () {
// pointerdown circle // pointerdown circle
simulatePointerDown(stage, { simulatePointerDown(stage, {
touches: [ x: 289,
{ y: 100,
x: 289,
y: 100,
},
],
preventDefault: function () {},
}); });
assert(pointerdown, '3) pointerdown should be true'); assert(pointerdown, '3) pointerdown should be true');
@ -86,8 +77,8 @@ describe.skip('PointerEvents', function () {
// pointerup circle to triger dbltap // pointerup circle to triger dbltap
simulatePointerUp(stage, { simulatePointerUp(stage, {
touches: [], x: 289,
preventDefault: function () {}, y: 100,
}); });
// end drag is tied to document mouseup and pointerup event // end drag is tied to document mouseup and pointerup event
// which can't be simulated. call _endDrag manually // which can't be simulated. call _endDrag manually
@ -100,13 +91,8 @@ describe.skip('PointerEvents', function () {
setTimeout(function () { setTimeout(function () {
// pointermove circle // pointermove circle
simulatePointerMove(stage, { simulatePointerMove(stage, {
touches: [ x: 290,
{ y: 100,
x: 290,
y: 100,
},
],
preventDefault: function () {},
}); });
assert(pointerdown, '5) pointerdown should be true'); assert(pointerdown, '5) pointerdown should be true');
@ -118,7 +104,7 @@ describe.skip('PointerEvents', function () {
}); });
// ====================================================== // ======================================================
it('pointer capture', function (done) { it.skip('pointer capture', function (done) {
var stage = addStage(); var stage = addStage();
var layer = new Konva.Layer(); var layer = new Konva.Layer();
var circle = new Konva.Circle({ var circle = new Konva.Circle({
@ -172,17 +158,15 @@ describe.skip('PointerEvents', function () {
layer.add(circle2); layer.add(circle2);
stage.add(layer); stage.add(layer);
var top = stage.content.getBoundingClientRect().top;
// on circle 2 to confirm it works // on circle 2 to confirm it works
simulatePointerDown(stage, { simulatePointerDown(stage, {
x: 289, x: 289,
y: 10 + top, y: 10,
pointerId: 0, pointerId: 0,
preventDefault: function () {}, preventDefault: function () {},
}); });
assert(otherDownCount === 1, '6) otherDownCount should be 1'); assert.equal(otherDownCount, 1, '6) otherDownCount should be 1');
assert(downCount === 0, '6) downCount should be 0'); assert(downCount === 0, '6) downCount should be 0');
assert(!pointermove, '6) pointermove should be false'); assert(!pointermove, '6) pointermove should be false');
assert(!pointerup, '6) pointerup should be false'); assert(!pointerup, '6) pointerup should be false');
@ -190,12 +174,12 @@ describe.skip('PointerEvents', function () {
// on circle with capture // on circle with capture
simulatePointerDown(stage, { simulatePointerDown(stage, {
x: 289, x: 289,
y: 100 + top, y: 100,
pointerId: 1, pointerId: 1,
preventDefault: function () {}, preventDefault: function () {},
}); });
assert(otherDownCount === 1, '7) otherDownCount should be 1'); assert.equal(otherDownCount, 1, '7) otherDownCount should be 1');
assert(downCount === 1, '7) downCount should be 1'); assert(downCount === 1, '7) downCount should be 1');
assert(!pointermove, '7) pointermove should be false'); assert(!pointermove, '7) pointermove should be false');
assert(!pointerup, '7) pointerup should be true'); assert(!pointerup, '7) pointerup should be true');
@ -203,12 +187,12 @@ describe.skip('PointerEvents', function () {
// second pointerdown // second pointerdown
simulatePointerDown(stage, { simulatePointerDown(stage, {
x: 289, x: 289,
y: 10 + top, y: 10,
pointerId: 1, pointerId: 2,
preventDefault: function () {}, preventDefault: function () {},
}); });
assert(otherDownCount === 1, '8) otherDownCount should be 1'); assert.equal(otherDownCount, 1, '8) otherDownCount should be 1');
assert(downCount === 2, '8) pointerdown should be 2'); assert(downCount === 2, '8) pointerdown should be 2');
assert(!pointermove, '8) pointermove should be false'); assert(!pointermove, '8) pointermove should be false');
assert(!pointerup, '8) pointerup should be true'); assert(!pointerup, '8) pointerup should be true');
@ -217,9 +201,8 @@ describe.skip('PointerEvents', function () {
// pointermove over circle 2 // pointermove over circle 2
simulatePointerMove(stage, { simulatePointerMove(stage, {
x: 290, x: 290,
y: 10 + top, y: 10,
pointerId: 1, pointerId: 1,
preventDefault: function () {},
}); });
assert(otherDownCount === 1, '9) otherDownCount should be 1'); assert(otherDownCount === 1, '9) otherDownCount should be 1');
@ -232,7 +215,7 @@ describe.skip('PointerEvents', function () {
simulatePointerDown(stage, { simulatePointerDown(stage, {
x: 289, x: 289,
y: 10 + top, y: 10,
pointerId: 1, pointerId: 1,
preventDefault: function () {}, preventDefault: function () {},
}); });

View File

@ -309,56 +309,6 @@ describe('Stage', function () {
); );
}); });
// ======================================================
it('layer getIntersection() with selector', function () {
var stage = addStage();
var layer = new Konva.Layer({
name: 'layer',
});
var group = new Konva.Group({
name: 'group',
});
var circle = new Konva.Circle({
x: stage.width() / 2,
y: stage.height() / 2,
radius: 70,
strokeWidth: 4,
fill: 'red',
stroke: 'black',
});
group.add(circle);
layer.add(group);
stage.add(layer);
assert.equal(
stage.getIntersection(
{ x: stage.width() / 2, y: stage.height() / 2 },
'Circle'
),
circle,
'intersection with shape selector'
);
assert.equal(
stage.getIntersection(
{ x: stage.width() / 2, y: stage.height() / 2 },
'.group'
),
group,
'intersection with group selector'
);
assert.equal(
stage.getIntersection(
{ x: stage.width() / 2, y: stage.height() / 2 },
'Stage'
),
stage,
'intersection with stage selector'
);
});
// ====================================================== // ======================================================
it('stage getIntersection() edge detection', function () { it('stage getIntersection() edge detection', function () {
var stage = addStage(); var stage = addStage();
@ -1190,9 +1140,10 @@ describe('Stage', function () {
} }
}); });
stage._mouseover({ stage._pointerover({
clientX: 0, clientX: 0,
clientY: 0, clientY: 0,
type: 'mouseover',
}); });
assert.equal(mouseover, 1, 'initial over'); assert.equal(mouseover, 1, 'initial over');
@ -1267,7 +1218,7 @@ describe('Stage', function () {
stage.on('mouseout', function () { stage.on('mouseout', function () {
count += 1; count += 1;
}); });
stage._mouseleave({}); stage._pointerleave({ type: 'mouseleave' });
assert.equal(count, 2); assert.equal(count, 2);
}); });

View File

@ -9,77 +9,6 @@ import {
} from './test-utils'; } from './test-utils';
describe('TouchEvents', function () { describe('TouchEvents', function () {
// ======================================================
it('stage content touch events', function () {
var stage = addStage();
var layer = new Konva.Layer();
var circle = new Konva.Circle({
x: 100,
y: 100,
radius: 70,
fill: 'green',
stroke: 'black',
strokeWidth: 4,
name: 'myCircle',
});
layer.add(circle);
stage.add(layer);
var circleTouchstart = 0;
var circleTouchend = 0;
var stageContentTouchstart = 0;
var stageContentTouchend = 0;
var stageContentTouchmove = 0;
var stageContentTap = 0;
var stageContentDbltap = 0;
circle.on('touchstart', function () {
circleTouchstart++;
});
circle.on('touchend', function () {
circleTouchend++;
});
stage.on('contentTouchstart', function () {
stageContentTouchstart++;
});
stage.on('contentTouchend', function () {
stageContentTouchend++;
});
stage.on('contentTouchmove', function () {
stageContentTouchmove++;
});
stage.on('contentTap', function () {
stageContentTap++;
});
stage.on('contentDbltap', function () {
stageContentDbltap++;
});
simulateTouchStart(stage, [{ x: 100, y: 100, id: 0 }]);
simulateTouchEnd(stage, [], [{ x: 100, y: 100, id: 0 }]);
assert.equal(circleTouchstart, 1, '1');
assert.equal(circleTouchend, 1, '2');
assert.equal(stageContentTouchstart, 1, '3');
assert.equal(stageContentTouchend, 1, '4');
assert.equal(stageContentDbltap, 0, '5');
simulateTouchStart(stage, [{ x: 1, y: 1, id: 0 }]);
simulateTouchEnd(stage, [], [{ x: 1, y: 1, id: 0 }]);
assert.equal(stageContentTouchstart, 2, '6');
assert.equal(stageContentTouchend, 2, '7');
assert.equal(stageContentDbltap, 1, '8');
});
// ====================================================== // ======================================================
it('touchstart touchend touchmove tap dbltap', function (done) { it('touchstart touchend touchmove tap dbltap', function (done) {
var stage = addStage(); var stage = addStage();
@ -282,26 +211,14 @@ describe('TouchEvents', function () {
stage.add(layer); stage.add(layer);
var circleTouchend = 0; var circleTouchend = 0;
var stageContentTouchstart = 0;
var stageContentTouchend = 0;
circle.on('touchend', function () { circle.on('touchend', function () {
circleTouchend++; circleTouchend++;
}); });
stage.on('contentTouchstart', function () {
stageContentTouchstart++;
});
stage.on('contentTouchend', function () {
stageContentTouchend++;
});
simulateTouchStart(stage, [{ x: 1, y: 1, id: 0 }]); simulateTouchStart(stage, [{ x: 1, y: 1, id: 0 }]);
simulateTouchEnd(stage, [], [{ x: 100, y: 100, id: 0 }]); simulateTouchEnd(stage, [], [{ x: 100, y: 100, id: 0 }]);
assert.equal(stageContentTouchstart, 1);
assert.equal(stageContentTouchend, 1);
assert.equal(circleTouchend, 1); assert.equal(circleTouchend, 1);
}); });
@ -554,7 +471,7 @@ describe('TouchEvents', function () {
}); });
it('can capture touch events', function () { it('can capture touch events', function () {
Konva.captureTouchEventsEnabled = true; Konva.capturePointerEventsEnabled = true;
var stage = addStage(); var stage = addStage();
var layer = new Konva.Layer(); var layer = new Konva.Layer();
stage.add(layer); stage.add(layer);
@ -641,7 +558,7 @@ describe('TouchEvents', function () {
assert.equal(circle1.hasPointerCapture(0), false); assert.equal(circle1.hasPointerCapture(0), false);
assert.equal(circle1.hasPointerCapture(1), false); assert.equal(circle1.hasPointerCapture(1), false);
Konva.captureTouchEventsEnabled = false; Konva.capturePointerEventsEnabled = false;
}); });
it('tap and double tap should trigger just once on stage', function () { it('tap and double tap should trigger just once on stage', function () {

View File

@ -24,7 +24,9 @@ afterEach(function () {
var isManual = this.currentTest.parent.title === 'Manual'; var isManual = this.currentTest.parent.title === 'Manual';
Konva.stages.forEach(function (stage) { Konva.stages.forEach(function (stage) {
clearTimeout(stage.dblTimeout); clearTimeout(stage._mouseDblTimeout);
clearTimeout(stage._touchDblTimeout);
clearTimeout(stage._pointerDblTimeout);
}); });
if (!isFailed && !isManual) { if (!isFailed && !isManual) {
@ -177,37 +179,43 @@ export function showHit(layer) {
} }
export function simulateMouseDown(stage, pos) { export function simulateMouseDown(stage, pos) {
// simulatePointerDown(stage, pos);
var top = isNode ? 0 : stage.content.getBoundingClientRect().top; var top = isNode ? 0 : stage.content.getBoundingClientRect().top;
stage._mousedown({ stage._pointerdown({
clientX: pos.x, clientX: pos.x,
clientY: pos.y + top, clientY: pos.y + top,
button: pos.button || 0, button: pos.button || 0,
type: 'mousedown',
}); });
} }
export function simulateMouseMove(stage, pos) { export function simulateMouseMove(stage, pos) {
// simulatePointerMove(stage, pos);
var top = isNode ? 0 : stage.content.getBoundingClientRect().top; var top = isNode ? 0 : stage.content.getBoundingClientRect().top;
var evt = { var evt = {
clientX: pos.x, clientX: pos.x,
clientY: pos.y + top, clientY: pos.y + top,
button: pos.button || 0, button: pos.button || 0,
type: 'mousemove',
}; };
stage._mousemove(evt); stage._pointermove(evt);
Konva.DD._drag(evt); Konva.DD._drag(evt);
} }
export function simulateMouseUp(stage, pos) { export function simulateMouseUp(stage, pos) {
// simulatePointerUp(stage, pos);
var top = isNode ? 0 : stage.content.getBoundingClientRect().top; var top = isNode ? 0 : stage.content.getBoundingClientRect().top;
var evt = { var evt = {
clientX: pos.x, clientX: pos.x,
clientY: pos.y + top, clientY: pos.y + top,
button: pos.button || 0, button: pos.button || 0,
type: 'mouseup',
}; };
Konva.DD._endDragBefore(evt); Konva.DD._endDragBefore(evt);
stage._mouseup(evt); stage._pointerup(evt);
Konva.DD._endDragAfter(evt); Konva.DD._endDragAfter(evt);
} }
@ -242,9 +250,10 @@ export function simulateTouchStart(stage, pos, changed?) {
var evt = { var evt = {
touches: touches, touches: touches,
changedTouches: changedTouches, changedTouches: changedTouches,
type: 'touchstart',
}; };
stage._touchstart(evt); stage._pointerdown(evt);
} }
export function simulateTouchMove(stage, pos, changed?) { export function simulateTouchMove(stage, pos, changed?) {
@ -278,9 +287,10 @@ export function simulateTouchMove(stage, pos, changed?) {
var evt = { var evt = {
touches: touches, touches: touches,
changedTouches: changedTouches, changedTouches: changedTouches,
type: 'touchmove',
}; };
stage._touchmove(evt); stage._pointermove(evt);
Konva.DD._drag(evt); Konva.DD._drag(evt);
} }
@ -315,10 +325,11 @@ export function simulateTouchEnd(stage, pos, changed?) {
var evt = { var evt = {
touches: touches, touches: touches,
changedTouches: changedTouches, changedTouches: changedTouches,
type: 'touchend',
}; };
Konva.DD._endDragBefore(evt); Konva.DD._endDragBefore(evt);
stage._touchend(evt); stage._pointerup(evt);
Konva.DD._endDragAfter(evt); Konva.DD._endDragAfter(evt);
} }
@ -329,6 +340,7 @@ export function simulatePointerDown(stage: Stage, pos) {
clientY: pos.y + top, clientY: pos.y + top,
button: pos.button || 0, button: pos.button || 0,
pointerId: pos.pointerId || 1, pointerId: pos.pointerId || 1,
type: 'pointerdown',
} as any); } as any);
} }
@ -339,6 +351,7 @@ export function simulatePointerMove(stage: Stage, pos) {
clientY: pos.y + top, clientY: pos.y + top,
button: pos.button || 0, button: pos.button || 0,
pointerId: pos.pointerId || 1, pointerId: pos.pointerId || 1,
type: 'pointermove',
}; };
stage._pointermove(evt as any); stage._pointermove(evt as any);
@ -346,13 +359,13 @@ export function simulatePointerMove(stage: Stage, pos) {
} }
export function simulatePointerUp(stage: Stage, pos) { export function simulatePointerUp(stage: Stage, pos) {
debugger;
var top = isNode ? 0 : stage.content.getBoundingClientRect().top; var top = isNode ? 0 : stage.content.getBoundingClientRect().top;
var evt = { var evt = {
clientX: pos.x, clientX: pos.x,
clientY: pos.y + top, clientY: pos.y + top,
button: pos.button || 0, button: pos.button || 0,
pointerId: pos.pointerId || 1, pointerId: pos.pointerId || 1,
type: 'pointerup',
}; };
Konva.DD._endDragBefore(evt); Konva.DD._endDragBefore(evt);