prepare new version. Update docs.

This commit is contained in:
Anton Lavrenov
2019-08-05 13:54:08 +07:00
parent f1846ba996
commit 519bd94a7c
13 changed files with 845 additions and 1717 deletions

View File

@@ -5,8 +5,13 @@ This project adheres to [Semantic Versioning](http://semver.org/).
## Not released: ## Not released:
* Better multitouch support ## [4.0.0][2019-08-05]
* New drag&drop implementation
Basically the release doesn't have any breaking changes. You may only have issues if you are using something from `Konva.DD` object (which is private and never documented). Otherwise you should be fine. `Konva` has major upgrade about touch events system and drag&drop flow. The API is exactly the same. But the internal refactoring is huge so I decided to make a major version. Please upgrade carefully. Report about any issues you have.
* Better multi-touch support. Now we can trigger several `touch` events on one or many nodes.
* New drag&drop implementation. You can drag several shapes at once with several pointers.
* HSL colors support
## [3.4.1][2019-07-18] ## [3.4.1][2019-07-18]

2142
konva.js

File diff suppressed because it is too large Load Diff

4
konva.min.js vendored

File diff suppressed because one or more lines are too long

View File

@@ -1,6 +1,6 @@
{ {
"name": "konva", "name": "konva",
"version": "3.4.1", "version": "4.0.0-0",
"author": "Anton Lavrenov", "author": "Anton Lavrenov",
"files": [ "files": [
"README.md", "README.md",

View File

@@ -79,15 +79,9 @@ cp ./konva.js ../konva-site/
# echo "replace CDN links" # echo "replace CDN links"
# find source themes -exec perl -i -pe "s|${old_cdn}|${new_cdn}|g" {} + >/dev/null find source themes react-demos vue-demos main-demo -name "*.json|*.html" -exec perl -i -pe "s|${old_version}|${new_version}|g" {} + >/dev/null
# find source themes -exec perl -i -pe "s|${old_cdn_min}|${new_cdn_min}|g" {} + >/dev/null
# echo "regenerate site" # echo "regenerate site"
# ./deploy.sh >/dev/null # ./deploy.sh >/dev/null
echo "DONE!" echo "DONE!"
echo "-------"
echo "Now you need:"
echo "1. Update CDN link to ${new_cdn} at http://codepen.io/lavrton/pen/myBPGo"
echo "2. Update cdn links on konva website from ${old_version} to ${new_version}"

View File

@@ -175,6 +175,9 @@ export abstract class BaseLayer extends Container<Group | Shape> {
getLayer() { getLayer() {
return this; return this;
} }
hitGraphEnabled() {
return true;
}
remove() { remove() {
var _canvas = this.getCanvas()._canvas; var _canvas = this.getCanvas()._canvas;

View File

@@ -135,12 +135,6 @@ export abstract class Container<ChildType extends Node> extends Node<
this._fire('add', { this._fire('add', {
child: child child: child
}); });
// if node under drag we need to update drag animation
if (child.isDragging()) {
DD.anim.setLayers(child.getLayer());
}
// chainable // chainable
return this; return this;
} }
@@ -443,9 +437,10 @@ export abstract class Container<ChildType extends Node> extends Node<
} }
} }
shouldDrawHit(canvas?) { shouldDrawHit(canvas?) {
// TODO: set correct type if (canvas && canvas.isCache) {
var layer = this.getLayer() as any; return true;
}
var layer = this.getLayer();
var layerUnderDrag = false; var layerUnderDrag = false;
DD._dragElements.forEach(elem => { DD._dragElements.forEach(elem => {
if (elem.isDragging && elem.node.getLayer() === layer) { if (elem.isDragging && elem.node.getLayer() === layer) {
@@ -454,10 +449,7 @@ export abstract class Container<ChildType extends Node> extends Node<
}); });
var dragSkip = !Konva.hitOnDragEnabled && layerUnderDrag; var dragSkip = !Konva.hitOnDragEnabled && layerUnderDrag;
return ( return layer && layer.hitGraphEnabled() && this.isVisible() && !dragSkip;
(canvas && canvas.isCache) ||
(layer && layer.hitGraphEnabled() && this.isVisible() && !dragSkip)
);
} }
getClientRect(attrs): IRect { getClientRect(attrs): IRect {
attrs = attrs || {}; attrs = attrs || {};

View File

@@ -66,13 +66,12 @@ var CONTEXT_PROPERTIES = [
'imageSmoothingEnabled' 'imageSmoothingEnabled'
]; ];
// TODO: document all context methods
const traceArrMax = 100; const traceArrMax = 100;
/** /**
* Konva wrapper around native 2d canvas context. It has almost the same API of 2d context with some additional functions. * Konva wrapper around native 2d canvas context. It has almost the same API of 2d context with some additional functions.
* With core Konva shapes you don't need to use this object. But you have to use it if you want to create * With core Konva shapes you don't need to use this object. But you will use it if you want to create
* a custom shape or a custom hit regions. * a [custom shape](/docs/react/Custom_Shape.html) or a [custom hit regions](/docs/events/Custom_Hit_Region.html).
* For full information about each 2d context API use [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D)
* @constructor * @constructor
* @memberof Konva * @memberof Konva
* @example * @example
@@ -275,28 +274,67 @@ export class Context {
this._context[attr] = val; this._context[attr] = val;
} }
// context pass through methods /**
* arc function.
* @method
* @name Konva.Context#arc
*/
arc(a0, a1, a2, a3, a4, a5) { arc(a0, a1, a2, a3, a4, a5) {
this._context.arc(a0, a1, a2, a3, a4, a5); this._context.arc(a0, a1, a2, a3, a4, a5);
} }
/**
* arcTo function.
* @method
* @name Konva.Context#arcTo
*/
arcTo(a0, a1, a2, a3, a4, a5) { arcTo(a0, a1, a2, a3, a4, a5) {
this._context.arc(a0, a1, a2, a3, a4, a5); this._context.arc(a0, a1, a2, a3, a4, a5);
} }
/**
* beginPath function.
* @method
* @name Konva.Context#beginPath
*/
beginPath() { beginPath() {
this._context.beginPath(); this._context.beginPath();
} }
/**
* bezierCurveTo function.
* @method
* @name Konva.Context#bezierCurveTo
*/
bezierCurveTo(a0, a1, a2, a3, a4, a5) { bezierCurveTo(a0, a1, a2, a3, a4, a5) {
this._context.bezierCurveTo(a0, a1, a2, a3, a4, a5); this._context.bezierCurveTo(a0, a1, a2, a3, a4, a5);
} }
/**
* clearRect function.
* @method
* @name Konva.Context#clearRect
*/
clearRect(a0, a1, a2, a3) { clearRect(a0, a1, a2, a3) {
this._context.clearRect(a0, a1, a2, a3); this._context.clearRect(a0, a1, a2, a3);
} }
/**
* clip function.
* @method
* @name Konva.Context#clip
*/
clip() { clip() {
this._context.clip(); this._context.clip();
} }
/**
* closePath function.
* @method
* @name Konva.Context#closePath
*/
closePath() { closePath() {
this._context.closePath(); this._context.closePath();
} }
/**
* createImageData function.
* @method
* @name Konva.Context#createImageData
*/
createImageData(a0, a1) { createImageData(a0, a1) {
var a = arguments; var a = arguments;
if (a.length === 2) { if (a.length === 2) {
@@ -305,15 +343,35 @@ export class Context {
return this._context.createImageData(a0); return this._context.createImageData(a0);
} }
} }
/**
* createLinearGradient function.
* @method
* @name Konva.Context#createLinearGradient
*/
createLinearGradient(a0, a1, a2, a3) { createLinearGradient(a0, a1, a2, a3) {
return this._context.createLinearGradient(a0, a1, a2, a3); return this._context.createLinearGradient(a0, a1, a2, a3);
} }
/**
* createPattern function.
* @method
* @name Konva.Context#createPattern
*/
createPattern(a0, a1) { createPattern(a0, a1) {
return this._context.createPattern(a0, a1); return this._context.createPattern(a0, a1);
} }
/**
* createRadialGradient function.
* @method
* @name Konva.Context#createRadialGradient
*/
createRadialGradient(a0, a1, a2, a3, a4, a5) { createRadialGradient(a0, a1, a2, a3, a4, a5) {
return this._context.createRadialGradient(a0, a1, a2, a3, a4, a5); return this._context.createRadialGradient(a0, a1, a2, a3, a4, a5);
} }
/**
* drawImage function.
* @method
* @name Konva.Context#drawImage
*/
drawImage(a0, a1, a2, a3?, a4?, a5?, a6?, a7?, a8?) { drawImage(a0, a1, a2, a3?, a4?, a5?, a6?, a7?, a8?) {
var a = arguments, var a = arguments,
_context = this._context; _context = this._context;
@@ -326,57 +384,147 @@ export class Context {
_context.drawImage(a0, a1, a2, a3, a4, a5, a6, a7, a8); _context.drawImage(a0, a1, a2, a3, a4, a5, a6, a7, a8);
} }
} }
/**
* ellipse function.
* @method
* @name Konva.Context#ellipse
*/
ellipse(a0, a1, a2, a3, a4, a5, a6, a7) { ellipse(a0, a1, a2, a3, a4, a5, a6, a7) {
this._context.ellipse(a0, a1, a2, a3, a4, a5, a6, a7); this._context.ellipse(a0, a1, a2, a3, a4, a5, a6, a7);
} }
/**
* isPointInPath function.
* @method
* @name Konva.Context#isPointInPath
*/
isPointInPath(x, y) { isPointInPath(x, y) {
return this._context.isPointInPath(x, y); return this._context.isPointInPath(x, y);
} }
/**
* fill function.
* @method
* @name Konva.Context#fill
*/
fill() { fill() {
this._context.fill(); this._context.fill();
} }
/**
* fillRect function.
* @method
* @name Konva.Context#fillRect
*/
fillRect(x, y, width, height) { fillRect(x, y, width, height) {
this._context.fillRect(x, y, width, height); this._context.fillRect(x, y, width, height);
} }
/**
* strokeRect function.
* @method
* @name Konva.Context#strokeRect
*/
strokeRect(x, y, width, height) { strokeRect(x, y, width, height) {
this._context.strokeRect(x, y, width, height); this._context.strokeRect(x, y, width, height);
} }
/**
* fillText function.
* @method
* @name Konva.Context#fillText
*/
fillText(a0, a1, a2) { fillText(a0, a1, a2) {
this._context.fillText(a0, a1, a2); this._context.fillText(a0, a1, a2);
} }
/**
* measureText function.
* @method
* @name Konva.Context#measureText
*/
measureText(text) { measureText(text) {
return this._context.measureText(text); return this._context.measureText(text);
} }
/**
* getImageData function.
* @method
* @name Konva.Context#getImageData
*/
getImageData(a0, a1, a2, a3) { getImageData(a0, a1, a2, a3) {
return this._context.getImageData(a0, a1, a2, a3); return this._context.getImageData(a0, a1, a2, a3);
} }
/**
* lineTo function.
* @method
* @name Konva.Context#lineTo
*/
lineTo(a0, a1) { lineTo(a0, a1) {
this._context.lineTo(a0, a1); this._context.lineTo(a0, a1);
} }
/**
* moveTo function.
* @method
* @name Konva.Context#moveTo
*/
moveTo(a0, a1) { moveTo(a0, a1) {
this._context.moveTo(a0, a1); this._context.moveTo(a0, a1);
} }
/**
* rect function.
* @method
* @name Konva.Context#rect
*/
rect(a0, a1, a2, a3) { rect(a0, a1, a2, a3) {
this._context.rect(a0, a1, a2, a3); this._context.rect(a0, a1, a2, a3);
} }
/**
* putImageData function.
* @method
* @name Konva.Context#putImageData
*/
putImageData(a0, a1, a2) { putImageData(a0, a1, a2) {
this._context.putImageData(a0, a1, a2); this._context.putImageData(a0, a1, a2);
} }
/**
* quadraticCurveTo function.
* @method
* @name Konva.Context#quadraticCurveTo
*/
quadraticCurveTo(a0, a1, a2, a3) { quadraticCurveTo(a0, a1, a2, a3) {
this._context.quadraticCurveTo(a0, a1, a2, a3); this._context.quadraticCurveTo(a0, a1, a2, a3);
} }
/**
* restore function.
* @method
* @name Konva.Context#restore
*/
restore() { restore() {
this._context.restore(); this._context.restore();
} }
/**
* rotate function.
* @method
* @name Konva.Context#rotate
*/
rotate(a0) { rotate(a0) {
this._context.rotate(a0); this._context.rotate(a0);
} }
/**
* save function.
* @method
* @name Konva.Context#save
*/
save() { save() {
this._context.save(); this._context.save();
} }
/**
* scale function.
* @method
* @name Konva.Context#scale
*/
scale(a0, a1) { scale(a0, a1) {
this._context.scale(a0, a1); this._context.scale(a0, a1);
} }
/**
* setLineDash function.
* @method
* @name Konva.Context#setLineDash
*/
setLineDash(a0) { setLineDash(a0) {
// works for Chrome and IE11 // works for Chrome and IE11
if (this._context.setLineDash) { if (this._context.setLineDash) {
@@ -391,21 +539,51 @@ export class Context {
// no support for IE9 and IE10 // no support for IE9 and IE10
} }
/**
* getLineDash function.
* @method
* @name Konva.Context#getLineDash
*/
getLineDash() { getLineDash() {
return this._context.getLineDash(); return this._context.getLineDash();
} }
/**
* setTransform function.
* @method
* @name Konva.Context#setTransform
*/
setTransform(a0, a1, a2, a3, a4, a5) { setTransform(a0, a1, a2, a3, a4, a5) {
this._context.setTransform(a0, a1, a2, a3, a4, a5); this._context.setTransform(a0, a1, a2, a3, a4, a5);
} }
/**
* stroke function.
* @method
* @name Konva.Context#stroke
*/
stroke() { stroke() {
this._context.stroke(); this._context.stroke();
} }
/**
* strokeText function.
* @method
* @name Konva.Context#strokeText
*/
strokeText(a0, a1, a2, a3) { strokeText(a0, a1, a2, a3) {
this._context.strokeText(a0, a1, a2, a3); this._context.strokeText(a0, a1, a2, a3);
} }
/**
* transform function.
* @method
* @name Konva.Context#transform
*/
transform(a0, a1, a2, a3, a4, a5) { transform(a0, a1, a2, a3, a4, a5) {
this._context.transform(a0, a1, a2, a3, a4, a5); this._context.transform(a0, a1, a2, a3, a4, a5);
} }
/**
* translate function.
* @method
* @name Konva.Context#translate
*/
translate(a0, a1) { translate(a0, a1) {
this._context.translate(a0, a1); this._context.translate(a0, a1);
} }

View File

@@ -1,22 +1,9 @@
import { Animation } from './Animation';
import { Konva } from './Global'; import { Konva } from './Global';
import { Node } from './Node'; import { Node } from './Node';
import { Vector2d } from './types'; import { Vector2d } from './types';
import { Util } from './Util'; import { Util } from './Util';
// TODO: make better module,
// make sure other modules import it without global
export const DD = { export const DD = {
startPointerPos: {
x: 0,
y: 0
},
// properties
anim: new Animation(function() {
var b = this.dirty;
this.dirty = false;
return b;
}),
get isDragging() { get isDragging() {
var flag = false; var flag = false;
DD._dragElements.forEach(elem => { DD._dragElements.forEach(elem => {
@@ -27,10 +14,6 @@ export const DD = {
return flag; return flag;
}, },
justDragged: false, justDragged: false,
offset: {
x: 0,
y: 0
},
get node() { get node() {
// return first dragging node // return first dragging node
var node: Node | undefined; var node: Node | undefined;
@@ -67,8 +50,9 @@ export const DD = {
const pos = stage._changedPointerPositions.find( const pos = stage._changedPointerPositions.find(
pos => pos.id === elem.pointerId pos => pos.id === elem.pointerId
); );
// not related pointer
if (!pos) { if (!pos) {
console.error('Can not find pointer');
return; return;
} }
if (!elem.isDragging) { if (!elem.isDragging) {
@@ -109,6 +93,9 @@ export const DD = {
); );
}); });
}, },
// dragBefore and dragAfter allows us to set correct order of events
// setup all in dragbefore, and stop dragging only after pointerup triggered.
_endDragBefore(evt) { _endDragBefore(evt) {
DD._dragElements.forEach((elem, key) => { DD._dragElements.forEach((elem, key) => {
const { node } = elem; const { node } = elem;
@@ -140,31 +127,6 @@ export const DD = {
drawNode.draw(); drawNode.draw();
} }
}); });
// var node = DD.node;
// if (node) {
// DD.anim.stop();
// // only fire dragend event if the drag and drop
// // operation actually started.
// if (DD.isDragging) {
// DD.isDragging = false;
// DD.justDragged = true;
// Konva.listenClickTap = false;
// if (evt) {
// evt.dragEndNode = node;
// }
// }
// DD.node = null;
// const drawNode =
// node.getLayer() || (node instanceof Konva['Stage'] && node);
// if (drawNode) {
// drawNode.draw();
// }
// }
}, },
_endDragAfter(evt) { _endDragAfter(evt) {
DD._dragElements.forEach((elem, key) => { DD._dragElements.forEach((elem, key) => {
@@ -181,19 +143,6 @@ export const DD = {
DD._dragElements.delete(key); DD._dragElements.delete(key);
} }
}); });
// evt = evt || {};
// var dragEndNode = evt.dragEndNode;
// if (evt && dragEndNode) {
// dragEndNode.fire(
// 'dragend',
// {
// type: 'dragend',
// target: dragEndNode,
// evt: evt
// },
// true
// );
// }
} }
}; };

View File

@@ -1036,7 +1036,7 @@ export abstract class Node<Config extends NodeConfig = NodeConfig> {
* @returns {Boolean} * @returns {Boolean}
*/ */
shouldDrawHit() { shouldDrawHit() {
var layer = this.getLayer() as any; var layer = this.getLayer();
return ( return (
(!layer && this.isListening() && this.isVisible()) || (!layer && this.isListening() && this.isVisible()) ||
@@ -2242,10 +2242,6 @@ export abstract class Node<Config extends NodeConfig = NodeConfig> {
pointerId, pointerId,
dragStopped: false dragStopped: false
}); });
DD.startPointerPos = pos;
DD.offset.x = pos.x - ap.x;
DD.offset.y = pos.y - ap.y;
// this._setDragPosition();
} }
} }

View File

@@ -624,6 +624,7 @@ export class Shape<Config extends ShapeConfig = ShapeConfig> extends Node<
cachedHitCanvas = cachedCanvas && cachedCanvas.hit; cachedHitCanvas = cachedCanvas && cachedCanvas.hit;
if (!this.colorKey) { if (!this.colorKey) {
console.log(this);
Util.warn( Util.warn(
'Looks like your canvas has a destroyed shape in it. Do not reuse shape after you destroyed it. See the shape in logs above. If you want to reuse shape you should call remove() instead of destroy()' 'Looks like your canvas has a destroyed shape in it. Do not reuse shape after you destroyed it. See the shape in logs above. If you want to reuse shape you should call remove() instead of destroy()'
); );

View File

@@ -701,7 +701,7 @@ export class Stage extends Container<BaseLayer> {
} }
_touchmove(evt) { _touchmove(evt) {
this.setPointersPositions(evt); this.setPointersPositions(evt);
if (!DD.isDragging) { if (!DD.isDragging || Konva.hitOnDragEnabled) {
var triggeredOnShape = false; var triggeredOnShape = false;
var processedShapesIds = {}; var processedShapesIds = {};
this._changedPointerPositions.forEach(pos => { this._changedPointerPositions.forEach(pos => {

View File

@@ -277,12 +277,6 @@ suite('DragAndDrop', function() {
rect.moveTo(startDragLayer); rect.moveTo(startDragLayer);
startDragLayer.draw(); startDragLayer.draw();
assert.equal(
Konva.DD.anim.getLayers()[0],
endDragLayer,
'drag layer should be switched'
);
var shape = startDragLayer.getIntersection({ var shape = startDragLayer.getIntersection({
x: 2, x: 2,
y: 2 y: 2
@@ -738,7 +732,117 @@ suite('DragAndDrop', function() {
assert.equal(circle2.isDragging(), false); assert.equal(circle2.isDragging(), false);
assert.equal(Konva.DD.isDragging, false); assert.equal(Konva.DD.isDragging, false);
}); });
// TODO: try move the same node with the second finger
test('drag with multi-touch (same shape)', function() {
var stage = addStage();
var layer = new Konva.Layer();
stage.add(layer);
var circle1 = new Konva.Circle({
x: 70,
y: 70,
radius: 70,
fill: 'green',
stroke: 'black',
strokeWidth: 4,
name: 'myCircle',
draggable: true
});
layer.add(circle1);
layer.draw();
var dragstart1 = 0;
var dragmove1 = 0;
circle1.on('dragstart', function() {
dragstart1 += 1;
});
circle1.on('dragmove', function() {
dragmove1 += 1;
});
stage.simulateTouchStart([
{
x: 70,
y: 70,
id: 0
}
]);
// move one finger
stage.simulateTouchMove([
{
x: 75,
y: 75,
id: 0
}
]);
stage.simulateTouchStart(
[
{
x: 75,
y: 75,
id: 0
},
{
x: 80,
y: 80,
id: 1
}
],
[
{
x: 80,
y: 80,
id: 1
}
]
);
stage.simulateTouchMove(
[
{
x: 75,
y: 75,
id: 0
},
{
x: 85,
y: 85,
id: 1
}
],
[
{
x: 85,
y: 85,
id: 1
}
]
);
assert.equal(dragstart1, 1);
assert.equal(circle1.isDragging(), true);
assert.equal(dragmove1, 1);
assert.equal(circle1.x(), 75);
assert.equal(circle1.y(), 75);
// remove first finger
stage.simulateTouchEnd(
[],
[
{
x: 75,
y: 75,
id: 0
},
{
x: 85,
y: 85,
id: 1
}
]
);
});
// TODO: try to move two shapes on different stages // TODO: try to move two shapes on different stages
test('can stop drag on dragstart without changing position later', function() { test('can stop drag on dragstart without changing position later', function() {