Tweening a line with different numbers of points. close #92

This commit is contained in:
lavrton 2015-09-12 12:00:50 +07:00
parent fdf852547e
commit 5f2c70ddc7
9 changed files with 350 additions and 45 deletions

View File

@ -20,10 +20,11 @@
"new-cap": 0
},
"globals": {
"Konva" : false,
"define": false,
"test": false,
"assert": false,
"addStage": false
"Konva" : false,
"define": false,
"test": false,
"assert": false,
"addStage": false,
"suite": false
}
}

View File

@ -14,6 +14,7 @@ This project adheres to [Semantic Versioning](http://semver.org/).
### Changed
- Dragging now works much better. If your pointer is out of stage content dragging will still continue.
- `Konva.Node.create` not works with objects.
- `Konva.Tween` now supports tweening points to state with different length
## [0.9.5][2015-05-28]

143
konva.js
View File

@ -3,7 +3,7 @@
* Konva JavaScript Framework v0.9.9
* http://konvajs.github.io/
* Licensed under the MIT or GPL Version 2 licenses.
* Date: Fri Aug 28 2015
* Date: Sat Sep 12 2015
*
* Original work Copyright (C) 2011 - 2013 by Eric Rowell (KineticJS)
* Modified work Copyright (C) 2014 - 2015 by Anton Lavrenov (Konva)
@ -1169,9 +1169,84 @@ var Konva = {};
return str.substring(0, str.length - 1);
},
each: function(obj, func) {
for (var key in obj) {
func(key, obj[key]);
}
for (var key in obj) {
func(key, obj[key]);
}
},
_getProjectionToSegment: function(x1, y1, x2, y2, x3, y3) {
var x, y, dist;
var pd2 = (x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2);
if(pd2 == 0) {
x = x1;
y = y1;
dist = (x3 - x2) * (x3 - x2) + (y3 - y2) * (y3 - y2);
} else {
var u = ((x3 - x1) * (x2 - x1) + (y3 - y1) * (y2 - y1)) / pd2;
if(u < 0) {
x = x1;
y = y1;
dist = (x1 - x3) * (x1 - x3) + (y1 - y3) * (y1 - y3);
} else if (u > 1.0) {
x = x2;
y = y2;
dist = (x2 - x3) * (x2 - x3) + (y2 - y3) * (y2 - y3);
} else {
x = x1 + u * (x2 - x1);
y = y1 + u * (y2 - y1);
dist = (x - x3) * (x - x3) + (y - y3) * (y - y3);
}
}
return [x, y, dist];
},
// line as array of points.
// line might be closed
_getProjectionToLine: function(pt, line, isClosed) {
var pc = Konva.Util.cloneObject(pt);
var dist = Number.MAX_VALUE;
line.forEach(function(p1, i) {
if (!isClosed && i === line.length - 1) {
return;
}
var p2 = line[(i + 1) % line.length];
var proj = Konva.Util._getProjectionToSegment(p1.x, p1.y, p2.x, p2.y, pt.x, pt.y);
var px = proj[0], py = proj[1], pdist = proj[2];
if (pdist < dist) {
pc.x = px;
pc.y = py;
dist = pdist;
}
});
return pc;
},
_prepareArrayForTween: function(startArray, endArray, isClosed) {
var n, start = [], end = [];
if (startArray.length > endArray.length) {
var temp = endArray;
endArray = startArray;
startArray = temp;
}
for (n = 0; n < startArray.length; n += 2) {
start.push({
x: startArray[n],
y: startArray[n + 1]
});
}
for (n = 0; n < endArray.length; n += 2) {
end.push({
x: endArray[n],
y: endArray[n + 1]
});
}
var newStart = [];
end.forEach(function(point) {
var pr = Konva.Util._getProjectionToLine(point, start, isClosed);
newStart.push(pr.x);
newStart.push(pr.y);
});
return newStart;
}
};
})();
@ -6730,13 +6805,20 @@ var Konva = {};
getClientRect: function(skipTransform) {
var minX, minY, maxX, maxY;
var selfRect = {
x: 0,
y: 0,
width: 0,
height: 0
};
x: 0,
y: 0,
width: 0,
height: 0
};
this.children.each(function(child) {
var rect = child.getClientRect();
// skip invisible children (like empty groups)
// or don't skip... hmmm...
// if (rect.width === 0 && rect.height === 0) {
// return;
// }
if (minX === undefined) { // initial value for first child
minX = rect.x;
minY = rect.y;
@ -10327,7 +10409,7 @@ var Konva = {};
_addAttr: function(key, end) {
var node = this.node,
nodeId = node._id,
start, diff, tweenId, n, len;
start, diff, tweenId, n, len, trueEnd;
// remove conflict from tween map if it exists
tweenId = Konva.Tween.tweens[nodeId][key];
@ -10341,10 +10423,26 @@ var Konva = {};
if (Konva.Util._isArray(end)) {
diff = [];
len = end.length;
for (n = 0; n < len; n++) {
diff.push(end[n] - start[n]);
len = Math.max(end.length, start.length);
if (key === 'points') {
// before tweening points we need to make sure that start.length === end.length
// Konva.Util._prepareArrayForTween thinking that end.length > start.length
if (end.length > start.length) {
// so in this case we will increase number of starting points
start = Konva.Util._prepareArrayForTween(start, end, node.closed());
} else {
// in this case we will increase number of eding points
trueEnd = end;
end = Konva.Util._prepareArrayForTween(end, start, node.closed());
}
}
for (n = 0; n < len; n++) {
diff.push((end[n]) - (start[n]));
}
} else if (colorAttrs.indexOf(key) !== -1) {
start = Konva.Util.colorToRGBA(start);
var endRGBA = Konva.Util.colorToRGBA(end);
@ -10360,25 +10458,28 @@ var Konva = {};
Konva.Tween.attrs[nodeId][this._id][key] = {
start: start,
diff: diff
diff: diff,
end: end,
trueEnd: trueEnd
};
Konva.Tween.tweens[nodeId][key] = this._id;
},
_tweenFunc: function(i) {
var node = this.node,
attrs = Konva.Tween.attrs[node._id][this._id],
key, attr, start, diff, newVal, n, len;
key, attr, start, diff, newVal, n, len, end;
for (key in attrs) {
attr = attrs[key];
start = attr.start;
diff = attr.diff;
end = attr.end;
if (Konva.Util._isArray(start)) {
newVal = [];
len = start.length;
len = Math.max(start.length, end.length);
for (n = 0; n < len; n++) {
newVal.push(start[n] + (diff[n] * i));
newVal.push((start[n] || 0) + (diff[n] * i));
}
} else if (colorAttrs.indexOf(key) !== -1) {
newVal = 'rgba(' +
@ -10409,6 +10510,14 @@ var Konva = {};
that.anim.stop();
};
this.tween.onFinish = function() {
var node = that.node;
// after tweening points of line we need to set original end
var attrs = Konva.Tween.attrs[node._id][that._id];
if (attrs.points) {
node.points(attrs.points.trueEnd);
}
if (that.onFinish) {
that.onFinish.call(that);
}

12
konva.min.js vendored

File diff suppressed because one or more lines are too long

View File

@ -411,13 +411,20 @@
getClientRect: function(skipTransform) {
var minX, minY, maxX, maxY;
var selfRect = {
x: 0,
y: 0,
width: 0,
height: 0
};
x: 0,
y: 0,
width: 0,
height: 0
};
this.children.each(function(child) {
var rect = child.getClientRect();
// skip invisible children (like empty groups)
// or don't skip... hmmm...
// if (rect.width === 0 && rect.height === 0) {
// return;
// }
if (minX === undefined) { // initial value for first child
minX = rect.x;
minY = rect.y;

View File

@ -216,7 +216,7 @@
_addAttr: function(key, end) {
var node = this.node,
nodeId = node._id,
start, diff, tweenId, n, len;
start, diff, tweenId, n, len, trueEnd;
// remove conflict from tween map if it exists
tweenId = Konva.Tween.tweens[nodeId][key];
@ -230,10 +230,26 @@
if (Konva.Util._isArray(end)) {
diff = [];
len = end.length;
for (n = 0; n < len; n++) {
diff.push(end[n] - start[n]);
len = Math.max(end.length, start.length);
if (key === 'points') {
// before tweening points we need to make sure that start.length === end.length
// Konva.Util._prepareArrayForTween thinking that end.length > start.length
if (end.length > start.length) {
// so in this case we will increase number of starting points
start = Konva.Util._prepareArrayForTween(start, end, node.closed());
} else {
// in this case we will increase number of eding points
trueEnd = end;
end = Konva.Util._prepareArrayForTween(end, start, node.closed());
}
}
for (n = 0; n < len; n++) {
diff.push((end[n]) - (start[n]));
}
} else if (colorAttrs.indexOf(key) !== -1) {
start = Konva.Util.colorToRGBA(start);
var endRGBA = Konva.Util.colorToRGBA(end);
@ -249,25 +265,28 @@
Konva.Tween.attrs[nodeId][this._id][key] = {
start: start,
diff: diff
diff: diff,
end: end,
trueEnd: trueEnd
};
Konva.Tween.tweens[nodeId][key] = this._id;
},
_tweenFunc: function(i) {
var node = this.node,
attrs = Konva.Tween.attrs[node._id][this._id],
key, attr, start, diff, newVal, n, len;
key, attr, start, diff, newVal, n, len, end;
for (key in attrs) {
attr = attrs[key];
start = attr.start;
diff = attr.diff;
end = attr.end;
if (Konva.Util._isArray(start)) {
newVal = [];
len = start.length;
len = Math.max(start.length, end.length);
for (n = 0; n < len; n++) {
newVal.push(start[n] + (diff[n] * i));
newVal.push((start[n] || 0) + (diff[n] * i));
}
} else if (colorAttrs.indexOf(key) !== -1) {
newVal = 'rgba(' +
@ -298,6 +317,14 @@
that.anim.stop();
};
this.tween.onFinish = function() {
var node = that.node;
// after tweening points of line we need to set original end
var attrs = Konva.Tween.attrs[node._id][that._id];
if (attrs.points) {
node.points(attrs.points.trueEnd);
}
if (that.onFinish) {
that.onFinish.call(that);
}

View File

@ -905,9 +905,84 @@
return str.substring(0, str.length - 1);
},
each: function(obj, func) {
for (var key in obj) {
func(key, obj[key]);
}
for (var key in obj) {
func(key, obj[key]);
}
},
_getProjectionToSegment: function(x1, y1, x2, y2, x3, y3) {
var x, y, dist;
var pd2 = (x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2);
if(pd2 == 0) {
x = x1;
y = y1;
dist = (x3 - x2) * (x3 - x2) + (y3 - y2) * (y3 - y2);
} else {
var u = ((x3 - x1) * (x2 - x1) + (y3 - y1) * (y2 - y1)) / pd2;
if(u < 0) {
x = x1;
y = y1;
dist = (x1 - x3) * (x1 - x3) + (y1 - y3) * (y1 - y3);
} else if (u > 1.0) {
x = x2;
y = y2;
dist = (x2 - x3) * (x2 - x3) + (y2 - y3) * (y2 - y3);
} else {
x = x1 + u * (x2 - x1);
y = y1 + u * (y2 - y1);
dist = (x - x3) * (x - x3) + (y - y3) * (y - y3);
}
}
return [x, y, dist];
},
// line as array of points.
// line might be closed
_getProjectionToLine: function(pt, line, isClosed) {
var pc = Konva.Util.cloneObject(pt);
var dist = Number.MAX_VALUE;
line.forEach(function(p1, i) {
if (!isClosed && i === line.length - 1) {
return;
}
var p2 = line[(i + 1) % line.length];
var proj = Konva.Util._getProjectionToSegment(p1.x, p1.y, p2.x, p2.y, pt.x, pt.y);
var px = proj[0], py = proj[1], pdist = proj[2];
if (pdist < dist) {
pc.x = px;
pc.y = py;
dist = pdist;
}
});
return pc;
},
_prepareArrayForTween: function(startArray, endArray, isClosed) {
var n, start = [], end = [];
if (startArray.length > endArray.length) {
var temp = endArray;
endArray = startArray;
startArray = temp;
}
for (n = 0; n < startArray.length; n += 2) {
start.push({
x: startArray[n],
y: startArray[n + 1]
});
}
for (n = 0; n < endArray.length; n += 2) {
end.push({
x: endArray[n],
y: endArray[n + 1]
});
}
var newStart = [];
end.forEach(function(point) {
var pr = Konva.Util._getProjectionToLine(point, start, isClosed);
newStart.push(pr.x);
newStart.push(pr.y);
});
return newStart;
}
};
})();

View File

@ -1629,4 +1629,27 @@ suite('Container', function() {
assert.deepEqual(group.getClientRect(), {x:10, y:10, width: 0, height:0});
});
test.skip('getClientRect - test layer', function() {
var stage = addStage();
var layer = new Konva.Layer();
var group1 = new Konva.Group();
var group2 = new Konva.Group();
var rect = new Konva.Rect({
x: 50,
y: 100,
width: 200,
height: 75,
fill: 'red'
});
group1.add(rect);
layer.add(group1);
layer.add(group2);
stage.add(layer);
assert.deepEqual(layer.getClientRect(), {x: 50, y: 100, width: 200, height: 75});
});
});

View File

@ -22,7 +22,7 @@ suite('Tween', function() {
var onFinish = function() {
assert(++finishCount <= 1, 'finishCount should not exceed 1');
done();
}
};
var tweens = 0;
var attrs = 0;
@ -217,4 +217,66 @@ suite('Tween', function() {
}, 50);
});
suite('tween array with different length', function() {
test('prepare array closed', function() {
var start = [0, 0, 10, 0, 10, 10];
var end = [0, 0, 10, 0, 10, 10, 0, 10];
var newStart = Konva.Util._prepareArrayForTween(start, end, true);
assert.deepEqual(newStart, [0, 0, 10, 0, 10, 10, 5, 5]);
});
test('prepare array - opened', function() {
var start = [0, 0, 10, 0, 10, 10, 0, 10];
var end = [0, 0, 10, 0, 7, 9];
end = Konva.Util._prepareArrayForTween(start, end, false);
assert.deepEqual(end, [0, 0, 10, 0, 7, 9, 7, 9]);
});
test('tween array with bigger size', function(done) {
var stage = addStage();
var layer = new Konva.Layer();
stage.add(layer);
var line = new Konva.Line({
stroke: 'black',
points: [100, 100, 200, 100, 200, 200],
closed: true
});
layer.add(line);
line.to({
points: [100, 100, 200, 100, 200, 200, 100, 200],
duration: 0.1,
onFinish: function() {
assert.deepEqual(line.points(), [100, 100, 200, 100, 200, 200, 100, 200]);
done();
}
});
});
test('tween array to lower size', function(done) {
var stage = addStage();
var layer = new Konva.Layer();
stage.add(layer);
var line = new Konva.Line({
stroke: 'black',
points: [100, 100, 200, 100, 200, 200, 100, 200],
closed: true
});
layer.add(line);
line.to({
points: [100, 100, 200, 100, 200, 200],
duration: 0.1,
onFinish: function() {
assert.deepEqual(line.points(), [100, 100, 200, 100, 200, 200]);
done();
}
});
});
});
});