Add ObservedPoint class that records changes and passes them on to the owner, and use it for all Point objects returned from Rectangle.

This commit is contained in:
Jürg Lehni 2011-03-16 07:12:34 +01:00
parent 4e65d2c1d3
commit b1c0a48552
2 changed files with 76 additions and 13 deletions

View file

@ -159,8 +159,12 @@ var Point = this.Point = Base.extend({
if (this.isZero()) {
if (this._angle != null) {
var a = this._angle;
this.x = Math.cos(a) * length;
this.y = Math.sin(a) * length;
// Use #set() instead of direct assignment, so ObservedPoint
// can optimise
this.set(
Math.cos(a) * length,
Math.sin(a) * length
);
} else {
// Assume angle = 0
this.x = length;
@ -173,8 +177,12 @@ var Point = this.Point = Base.extend({
// x and y are 0
this.getAngle();
}
this.x *= scale;
this.y *= scale;
// Use #set() instead of direct assignment, so ObservedPoint
// can optimise
this.set(
this.x * scale,
this.y * scale
);
}
return this;
},
@ -229,8 +237,12 @@ var Point = this.Point = Base.extend({
angle = this._angle = angle * Math.PI / 180;
if (!this.isZero()) {
var length = this.getLength();
this.x = Math.cos(angle) * length;
this.y = Math.sin(angle) * length;
// Use #set() instead of direct assignment, so ObservedPoint
// can optimise
this.set(
Math.cos(angle) * length,
Math.sin(angle) * length
);
}
return this;
},
@ -560,3 +572,52 @@ var Point = this.Point = Base.extend({
}
}
});
var ObservedPoint = Point.extend({
beans: true,
set: function(x, y) {
this._x = x;
this._y = y;
this._observer[this._set](this);
return this;
},
getX: function() {
return this._x;
},
setX: function(x) {
this._x = x;
this._observer[this._set](this);
},
getY: function() {
return this._y;
},
setY: function(y) {
this._y = y;
this._observer[this._set](this);
},
statics: {
/**
* Provide a faster creator for Points out of two coordinates that
* does not rely on Point#initialize at all. This speeds up all math
* operations a lot.
*/
create: function(observer, set, x, y) {
// Don't use the shorter form as we want absolute maximum
// performance here:
// return new Point(Point.dont).set(x, y);
// TODO: Benchmark and decide
var point = new ObservedPoint(ObservedPoint.dont);
point._x = x;
point._y = y;
point._observer = observer;
point._set = set;
return point;
}
}
});

View file

@ -71,7 +71,7 @@ var Rectangle = this.Rectangle = Base.extend({
},
getPoint: function() {
return Point.create(this.x, this.y);
return ObservedPoint.create(this, 'setPoint', this.x, this.y);
},
setPoint: function(point) {
@ -150,7 +150,8 @@ var Rectangle = this.Rectangle = Base.extend({
},
getCenter: function() {
return Point.create(this.getCenterX(), this.getCenterY());
return ObservedPoint.create(this, 'setCenter',
this.getCenterX(), this.getCenterY());
},
setCenter: function(point) {
@ -242,10 +243,10 @@ var Rectangle = this.Rectangle = Base.extend({
['Right', 'Center'], ['Bottom', 'Center']
],
function(parts, index) {
var key = parts.join('');
var part = parts.join('');
// find out if the first of the pair is an x or y property,
// by checking the first character for [R]ight or [L]eft;
var xFirst = /^[RL]/.test(key);
var xFirst = /^[RL]/.test(part);
// Rename Center to CenterX or CenterY:
if (index >= 4)
parts[1] += xFirst ? 'Y' : 'X';
@ -255,10 +256,11 @@ var Rectangle = this.Rectangle = Base.extend({
getY = 'get' + y,
setX = 'set' + x,
setY = 'set' + y;
this['get' + key] = function() {
return Point.create(this[getX](), this[getY]());
this['get' + part] = function() {
return ObservedPoint.create(this, 'set' + part,
this[getX](), this[getY]());
};
this['set' + key] = function(point) {
this['set' + part] = function(point) {
point = Point.read(arguments);
return this[setX](point.x)[setY](point.y); // Note: call chaining!
};