installing-addons.md
Installing Addons
Polypoint and all its assets are pluggable through a process of install and mixin prototype loading. This allows us to import for it to hoist methods on existing assets.
Like this:
// Pretend Polypoint.Stage
class Stage {}
// tell Polypoint this is a mixin thing.
Polypoint.install(Stage)
const stage = new Stage();
/* could also become */
// const stage = new Polypoint.Stage();
// No dragging tools yet
console.log(stage.dragging)
undefined
Install something:
// We can install a new function
Polypoint.lazierProp('Stage', function dragging(){
console.log('new dragging instance')
let dr = new Dragging(this)
dr.initDragging();
return dr
});
console.log(stage.dragging)
// "new dragging instance"
// <Dragging>
Usage
A Polypoint asset should be loaded into the primary object.
Install
Use Polypoint.install to ensure the entity is available for overloading:
// Pretend Polypoint.Stage
class Thing {}
// tell Polypoint this is a mixin thing.
Polypoint.install(Thing)
Polypoint.Thing == Thing
mixin
Install properties onto an incoming unit. The target may be any installed asset:
Polypoint.mixin('Point', {
_draggable: {
value: true,
writable: true
}
, draggable: {
get() {
return this._draggable
}
}
})
this.center.draggable == true
this.center._draggable = false
this.center.draggable == false
The mixin exposes the standard Object.defineProperties
installFunctions
Assume many functions to install:
Polypoint.head.installFunctions('Point', {
track(other, settings) {
return constraints.distance(other, this, settings)
}
, leash(other, settings) {
return constraints.within(other, this, settings)
}
});
Synonymous to:
Polypoint.head.mixin('Point', {
track: {
value(any=false) {
// ...
}
, writable: true
}
, leash: {
// ...
}
})
lazyProp
Assume many correctly named functions to access values on first call.
Polypoint.head.lazyProp('Point', {
pen() {
let r = this._pen
if(r == undefined) {
r = new PointPen(this)
this._pen = r
}
return r
}
})
stage.center._pen == undefined
stage.center.pen == Pen
stage.center._pen == Pen
Synonymous to:
Polypoint.head.mixin('Point', {
pen: {
get() {
let r = this._pen
if(r == undefined) {
r = new PointPen(this)
this._pen = r
}
return r
}
}
})
lazierProp
Using the lazyProp for a first call create is very common. Therefore we have a lazier function:
[TIP] Arrow functions may not maintain the correct scope for
thiswithin the call. Read the "Method Note" for more info
Polypoint.head.lazierProp('Stage',
function screenshot() {
return new Screenshot(this)
}
);
This applies the screenshot() method to a stage, but will only call once.
Any subsequesnt calls to stage.screenshot() will yield the generated object:
const stage = new Stage;
stage._screenshot == undefined
console.log(stage.screenshot)
stage._screenshot == stage.screenshot
Synonymous to:
Polypoint.head.lazyProp('Stage', {
screenshot() {
let s = this._screenshot;
if(s) { return s };
this._screenshot = new Screenshot(this)
return this._screenshot
}
})
Arrow Functions ()=>{}
The lazy prop is called once, and the result is cached under the _{name} of the method.
The scope of the callback (this), is the target instance (new Point). The this reference for arrow functions is the outer scope.
If the sub entity requires a reference to the owning entity (Such as the Point.as... methods need a reference to its point), ensure to use the classic function:
In this example the PointCast class requires a reference to this of type Point:
// Without lazy prop:
const point = new Point(100, 200)
point.as = PointerCast(point);
point.as.array()
// [100, 200]
With the lazierProp example, we ensure a closed scope for this one-time call using function(){ ... }:
Polypoint.lazierProp('Point', function(){
return new PointCast(this)
}, 'as')
When using arrow functions ()=>{} the this reference is not the Point, but is more likely the window
// will not work
// `this` is undefined
Polypoint.lazierProp('Point', ()=>new PointCast, 'as')
// `this` is Window
Polypoint.lazierProp('Point', ()=>{ new PointCast(this)}, 'as')
In both cases the this reference did not correctly apply the scope as the Point instance.