mirror of
https://github.com/konvajs/konva.git
synced 2025-05-02 20:05:08 +08:00
implemented clone method (inspired by matteo78) and added thorough unit tests
This commit is contained in:
parent
7f7cd24838
commit
a8ab9a2533
50
dist/kinetic-core.js
vendored
50
dist/kinetic-core.js
vendored
@ -454,7 +454,6 @@ Kinetic.Node = Kinetic.Class.extend({
|
||||
|
||||
this.setDefaultAttrs(this.defaultNodeAttrs);
|
||||
this.eventListeners = {};
|
||||
|
||||
this.setAttrs(config);
|
||||
|
||||
// bind events
|
||||
@ -1105,6 +1104,41 @@ Kinetic.Node = Kinetic.Class.extend({
|
||||
|
||||
return m;
|
||||
},
|
||||
/**
|
||||
* clone node
|
||||
* @param {Object} config used to override cloned
|
||||
* attrs
|
||||
*/
|
||||
clone: function(obj) {
|
||||
// instantiate new node
|
||||
var classType = this.shapeType || this.nodeType;
|
||||
var node = new Kinetic[classType](this.attrs);
|
||||
|
||||
/*
|
||||
* copy over user listeners
|
||||
*/
|
||||
for(var key in this.eventListeners) {
|
||||
var allListeners = this.eventListeners[key];
|
||||
for(var n = 0; n < allListeners.length; n++) {
|
||||
var listener = allListeners[n];
|
||||
/*
|
||||
* don't include kinetic namespaced listeners because
|
||||
* these are generated by the constructors
|
||||
*/
|
||||
if(listener.name.indexOf('kinetic') < 0) {
|
||||
// if listeners array doesn't exist, then create it
|
||||
if(!node.eventListeners[key]) {
|
||||
node.eventListeners[key] = [];
|
||||
}
|
||||
node.eventListeners[key].push(listener);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// apply attr overrides
|
||||
node.setAttrs(obj);
|
||||
return node;
|
||||
},
|
||||
_fireChangeEvent: function(attr) {
|
||||
this._handleEvent(attr + 'Change', {});
|
||||
},
|
||||
@ -1120,7 +1154,7 @@ Kinetic.Node = Kinetic.Class.extend({
|
||||
this._dragCleanup();
|
||||
var go = Kinetic.Global;
|
||||
var that = this;
|
||||
this.on('mousedown.kinetic_initdrag touchstart.kinetic_initdrag', function(evt) {
|
||||
this.on('mousedown.kinetic touchstart.kinetic', function(evt) {
|
||||
that._initDrag();
|
||||
});
|
||||
},
|
||||
@ -1141,8 +1175,8 @@ Kinetic.Node = Kinetic.Class.extend({
|
||||
* remove drag and drop event listener
|
||||
*/
|
||||
_dragCleanup: function() {
|
||||
this.off('mousedown.kinetic_initdrag');
|
||||
this.off('touchstart.kinetic_initdrag');
|
||||
this.off('mousedown.kinetic');
|
||||
this.off('touchstart.kinetic');
|
||||
},
|
||||
/**
|
||||
* handle node event
|
||||
@ -3439,7 +3473,7 @@ Kinetic.Ellipse = Kinetic.Shape.extend({
|
||||
this._convertRadius();
|
||||
|
||||
var that = this;
|
||||
this.on('radiusChange', function() {
|
||||
this.on('radiusChange.kinetic', function() {
|
||||
that._convertRadius();
|
||||
});
|
||||
},
|
||||
@ -3632,7 +3666,7 @@ Kinetic.Sprite = Kinetic.Shape.extend({
|
||||
this._super(config);
|
||||
|
||||
var that = this;
|
||||
this.on('animationChange', function() {
|
||||
this.on('animationChange.kinetic', function() {
|
||||
// reset index when animation changes
|
||||
that.setIndex(0);
|
||||
});
|
||||
@ -4011,7 +4045,7 @@ Kinetic.Text = Kinetic.Shape.extend({
|
||||
var that = this;
|
||||
for(var n = 0; n < attrs.length; n++) {
|
||||
var attr = attrs[n];
|
||||
this.on(attr + 'Change', that._setTextData);
|
||||
this.on(attr + 'Change.kinetic', that._setTextData);
|
||||
}
|
||||
|
||||
that._setTextData();
|
||||
@ -4470,9 +4504,7 @@ Kinetic.Path = Kinetic.Shape.extend({
|
||||
}
|
||||
}
|
||||
this.fill();
|
||||
//console.profile();
|
||||
this.stroke();
|
||||
//console.profileEnd();
|
||||
};
|
||||
// call super constructor
|
||||
this._super(config);
|
||||
|
42
src/Node.js
42
src/Node.js
@ -33,7 +33,6 @@ Kinetic.Node = Kinetic.Class.extend({
|
||||
|
||||
this.setDefaultAttrs(this.defaultNodeAttrs);
|
||||
this.eventListeners = {};
|
||||
|
||||
this.setAttrs(config);
|
||||
|
||||
// bind events
|
||||
@ -684,6 +683,41 @@ Kinetic.Node = Kinetic.Class.extend({
|
||||
|
||||
return m;
|
||||
},
|
||||
/**
|
||||
* clone node
|
||||
* @param {Object} config used to override cloned
|
||||
* attrs
|
||||
*/
|
||||
clone: function(obj) {
|
||||
// instantiate new node
|
||||
var classType = this.shapeType || this.nodeType;
|
||||
var node = new Kinetic[classType](this.attrs);
|
||||
|
||||
/*
|
||||
* copy over user listeners
|
||||
*/
|
||||
for(var key in this.eventListeners) {
|
||||
var allListeners = this.eventListeners[key];
|
||||
for(var n = 0; n < allListeners.length; n++) {
|
||||
var listener = allListeners[n];
|
||||
/*
|
||||
* don't include kinetic namespaced listeners because
|
||||
* these are generated by the constructors
|
||||
*/
|
||||
if(listener.name.indexOf('kinetic') < 0) {
|
||||
// if listeners array doesn't exist, then create it
|
||||
if(!node.eventListeners[key]) {
|
||||
node.eventListeners[key] = [];
|
||||
}
|
||||
node.eventListeners[key].push(listener);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// apply attr overrides
|
||||
node.setAttrs(obj);
|
||||
return node;
|
||||
},
|
||||
_fireChangeEvent: function(attr) {
|
||||
this._handleEvent(attr + 'Change', {});
|
||||
},
|
||||
@ -699,7 +733,7 @@ Kinetic.Node = Kinetic.Class.extend({
|
||||
this._dragCleanup();
|
||||
var go = Kinetic.Global;
|
||||
var that = this;
|
||||
this.on('mousedown.kinetic_initdrag touchstart.kinetic_initdrag', function(evt) {
|
||||
this.on('mousedown.kinetic touchstart.kinetic', function(evt) {
|
||||
that._initDrag();
|
||||
});
|
||||
},
|
||||
@ -720,8 +754,8 @@ Kinetic.Node = Kinetic.Class.extend({
|
||||
* remove drag and drop event listener
|
||||
*/
|
||||
_dragCleanup: function() {
|
||||
this.off('mousedown.kinetic_initdrag');
|
||||
this.off('touchstart.kinetic_initdrag');
|
||||
this.off('mousedown.kinetic');
|
||||
this.off('touchstart.kinetic');
|
||||
},
|
||||
/**
|
||||
* handle node event
|
||||
|
@ -39,7 +39,7 @@ Kinetic.Ellipse = Kinetic.Shape.extend({
|
||||
this._convertRadius();
|
||||
|
||||
var that = this;
|
||||
this.on('radiusChange', function() {
|
||||
this.on('radiusChange.kinetic', function() {
|
||||
that._convertRadius();
|
||||
});
|
||||
},
|
||||
|
@ -57,9 +57,7 @@ Kinetic.Path = Kinetic.Shape.extend({
|
||||
}
|
||||
}
|
||||
this.fill();
|
||||
//console.profile();
|
||||
this.stroke();
|
||||
//console.profileEnd();
|
||||
};
|
||||
// call super constructor
|
||||
this._super(config);
|
||||
|
@ -32,7 +32,7 @@ Kinetic.Sprite = Kinetic.Shape.extend({
|
||||
this._super(config);
|
||||
|
||||
var that = this;
|
||||
this.on('animationChange', function() {
|
||||
this.on('animationChange.kinetic', function() {
|
||||
// reset index when animation changes
|
||||
that.setIndex(0);
|
||||
});
|
||||
|
@ -99,7 +99,7 @@ Kinetic.Text = Kinetic.Shape.extend({
|
||||
var that = this;
|
||||
for(var n = 0; n < attrs.length; n++) {
|
||||
var attr = attrs[n];
|
||||
this.on(attr + 'Change', that._setTextData);
|
||||
this.on(attr + 'Change.kinetic', that._setTextData);
|
||||
}
|
||||
|
||||
that._setTextData();
|
||||
|
@ -3142,6 +3142,74 @@ Test.prototype.tests = {
|
||||
test(offsetChange, 'offsetChange should have been triggered with setOffset()');
|
||||
test(!shadowOffsetChange, 'offsetChange should not have been triggered with setShadow()');
|
||||
},
|
||||
'NODE - clone a shape': function(containerId) {
|
||||
var stage = new Kinetic.Stage({
|
||||
container: containerId,
|
||||
width: 578,
|
||||
height: 200
|
||||
});
|
||||
var layer = new Kinetic.Layer();
|
||||
var rect = new Kinetic.Rect({
|
||||
x: 50,
|
||||
y: 50,
|
||||
width: 200,
|
||||
height: 50,
|
||||
fill: 'blue',
|
||||
offset: [10, 10],
|
||||
shadow: {
|
||||
color: 'black',
|
||||
offset: [20, 20]
|
||||
},
|
||||
draggable: true,
|
||||
name: 'myRect'
|
||||
});
|
||||
|
||||
var clicks = [];
|
||||
|
||||
rect.on('click', function() {
|
||||
clicks.push(this.getName());
|
||||
});
|
||||
var clone = rect.clone({
|
||||
x: 300,
|
||||
fill: 'red',
|
||||
name: 'rectClone'
|
||||
});
|
||||
|
||||
test(clone.getX() === 300, 'clone x should be 300');
|
||||
test(clone.getY() === 50, 'clone y should be 50');
|
||||
test(clone.getWidth() === 200, 'clone width should be 200');
|
||||
test(clone.getHeight() === 50, 'clone height should be 50');
|
||||
test(clone.getFill() === 'red', 'clone fill should be red');
|
||||
|
||||
test(rect.getShadow().color === 'black', 'rect shadow color should be black');
|
||||
test(clone.getShadow().color === 'black', 'clone shadow color should be black');
|
||||
|
||||
clone.setShadow({
|
||||
color: 'green'
|
||||
});
|
||||
|
||||
/*
|
||||
* Make sure that when we change a clone object attr that the rect object
|
||||
* attr isn't updated by reference
|
||||
*/
|
||||
|
||||
test(rect.getShadow().color === 'black', 'rect shadow color should be black');
|
||||
test(clone.getShadow().color === 'green', 'clone shadow color should be green');
|
||||
|
||||
layer.add(rect);
|
||||
layer.add(clone);
|
||||
stage.add(layer);
|
||||
|
||||
// make sure private ids are different
|
||||
test(rect._id !== clone._id, 'rect and clone ids should be different');
|
||||
|
||||
// test user event binding cloning
|
||||
test(clicks.length === 0, 'no clicks should have been triggered yet');
|
||||
rect.simulate('click');
|
||||
test(clicks.toString() === 'myRect', 'only myRect should have been clicked on');
|
||||
clone.simulate('click');
|
||||
test(clicks.toString() === 'myRect,rectClone', 'click order should be myRect followed by rectClone');
|
||||
},
|
||||
'NODE - test on attr change': function(containerId) {
|
||||
var stage = new Kinetic.Stage({
|
||||
container: containerId,
|
||||
|
Loading…
Reference in New Issue
Block a user