Skip to content

Instantly share code, notes, and snippets.

@m93a
Created September 5, 2015 12:58
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save m93a/1dc1f46114c92664a7bc to your computer and use it in GitHub Desktop.
Save m93a/1dc1f46114c92664a7bc to your computer and use it in GitHub Desktop.
Advanced anchor-pivot switching support for every DisplayObject
//create some dummy containers & sprites
var container = new PIXI.Container;
var sprite1 = new PIXI.Sprite(texture);
sprite1.position = new PIXI.Point(0,0);
sprite1.width = 20;
sprite1.height = 20;
var sprite2 = new PIXI.Sprite(texture);
sprite2.position = new PIXI.Point(100,0);
sprite2.width = 20;
sprite2.height = 20;
//first the basic behavior
//by default pivot is the default property
//and anchor is automatically computed
container.addChild(sprite1);
container.pivot = new PIXI.Point(10,10); //center
container.addChild(sprite2);
//now, the pivot is not in the center
//of the container but remains on 10,10
container.removeChildren();
//now swapping the default property to anchor
//you can swap def. prop. by assigning to it
container.addChild(sprite1);
container.anchor = new PIXI.Point(.5,.5); //center
container.addChild(sprite2);
//now, the pivot is still in the center
//let's try another thing
container.pivot = container.pivot; //set pivot as default
container.removeChild(sprite2);
//pivot stays in the former center
//on the point 60,10
//TODO
//setting computed point's properties doesn't work yet
//so this will take no effect on computed properties
container.anchor.x = 42;
//TODO
//also this doesn't work on sprites because they've
//got their anchor property defined in the constructor
//then, during rendering, pivot and anchor are summed
(function main(){
if(typeof PIXI !== "object") return requestAnimationFrame(main);
//helper function to define getters and setters
function getSet(obj,prop,get,set){
Object.defineProperty(obj,prop,{
enumerable: true,
configurable: true,
get: get, set: set
});
};
//helper function to remove getters and setters
function realValue(obj,prop,value){
Object.defineProperty(obj,prop,{
enumerable: true,
configurable: true,
writable: true,
value: value
});
};
//apply automatic .anchor property calculation on obj
function autoAnchor(obj,anchorCache,pivotCache){
var firstRun = true;
/*
* if WeakMap is not supported by browser,
* the computed property getter will always
* return a new object
*/
if(!anchorCache && typeof WeakMap === "function"){
anchorCache = new WeakMap;
}
if(!pivotCache && typeof WeakMap === "function"){
pivotCache = new WeakMap;
}
getSet(obj,"anchor",function getter(){
//if the object exist in cache, return it
if(!firstRun && anchorCache && anchorCache.has(this)) return anchorCache.get(this);
//else create a new auto-computing point
var self = this;
var point;
if(firstRun && anchorCache && anchorCache.has(this)){
point = anchorCache.get(this);
}else{
point = new PIXI.Point();
}
getSet(point,"x",function(){ return self.pivot.x/self.width },function(){});
getSet(point,"y",function(){ return self.pivot.y/self.height },function(){});
if(anchorCache) anchorCache.set(this,point); //save to cache
/*
* if the user tries to force change the computed property
* to pivot, he would logically do `obj.anchor=obj.anchor`
* this would however result in infinite recursion, therefore
* we mark the point as possibly recursive so we know we
* should remove the getters and setters
*/
point._maybeRecursive = true;
return point;
},function setter(newValue){
//remove getsetters from a recursive value
if(newValue._maybeRecursive){
realValue(newValue,"x",newValue.x);
realValue(newValue,"y",newValue.y);
}
//remove getsetters from anchor
realValue(this,"anchor",newValue);
//this feature is not compatibile with Sprite
if(this instanceof PIXI.Sprite) return;
if(pivotCache && this.pivot instanceof PIXI.Point){
pivotCache.set(this.pivot);
}
//enable pivot auto-computation
autoPivot(this,anchorCache,pivotCache);
});
};
//apply automatic .pivot property calculation on obj
//this is essentially the same, so I won't comment it
function autoPivot(obj,anchorCache,pivotCache){
var firstRun = true;
if(!anchorCache && typeof WeakMap === "function"){
anchorCache = new WeakMap;
}
if(!pivotCache && typeof WeakMap === "function"){
pivotCache = new WeakMap;
}
getSet(obj,"pivot",function getter(){
if(!firstRun && pivotCache && pivotCache.has(this)) return pivotCache.get(this);
//else create a new auto-computing point
var self = this;
var point;
if(firstRun && pivotCache && pivotCache.has(this)){
point = pivotCache.get(this);
}else{
point = new PIXI.Point();
}
getSet(point,"x",function(){ return self.anchor.x*self.width },function(){});
getSet(point,"y",function(){ return self.anchor.y*self.height },function(){});
if(pivotCache) pivotCache.set(this,point);
point._maybeRecursive = true;
return point;
},function setter(newValue){
if(newValue._maybeRecursive){
realValue(newValue,"x",newValue.x);
realValue(newValue,"y",newValue.y);
}
realValue(this,"pivot",newValue);
if(this instanceof PIXI.Sprite) return;
if(anchorCache && this.anchor instanceof PIXI.Point){
anchorCache.set(this.anchor);
}
autoAnchor(this,anchorCache,pivotCache);
});
};
//apply automatic anchor computation on DisplayObjects
autoAnchor(PIXI.DisplayObject.prototype);
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment