Parse
File Parse xybind.js
This tree is parsed live from the source file.
Classes
-
{{ item.name }}
- {{ key }}
Not Classes
{{ getTree() }}
Comments
{{ getTreeComments() }}
Source
// Works.
let defaultRad = (Math.PI2 + degToRad(-90) + Math.PI) % Math.PI2
class XYBindMap {
constructor() {
this.bindMap = new Map()
this.bindMapRev = new Map()
}
step(){
this.bindMap.forEach(this.pairTest.bind(this))
}
updateFunction(target, parent) {
target.xy = parent.xy
}
childToParentUpdate(target, parent, opts, d){
// console.log('primary drag')
let updateRequired = !(d.distance < 2);
let xy = target.xy
if(opts.angle != undefined) {
/* Calculate the angle based on the current location.
This is the inverse of the primary location.*/
let parentRad = (parent.radians + Math.PI * 3) % Math.PI2
let rads = opts.relative? parentRad: defaultRad
let angle = opts.angle + rads
// let angle = (Math.PI2 + (rads + opts.angle)) % Math.PI2
let distance = opts.distance
opts.x = -(d.x + (distance * Math.cos(angle)))
opts.y = -(d.y + (distance * Math.sin(angle)))
// console.log(d)
target.xy = [
xy[0] + opts.x
, xy[1] + opts.y
]
updateRequired = false
}
if(opts.speed) {
target.xy = [
xy[0] + opts.x * opts.speed
, xy[1] + opts.y * opts.speed
]
}
target._updateRequired = updateRequired
}
lockedPosition(target, parent, opts, d){
/* position is locked (reverse) */
// Update for the child, in reverse
let rads = opts.relative? target.radians: defaultRad
// let angle = rads + opts.angle
let angle = rads + opts.angle
let xy = target.xy
if(opts.relative !== true) {
angle += Math.PI * 3
}
opts.x = (d.x + (opts.distance * Math.cos(angle)))
opts.y = (d.y + (opts.distance * Math.sin(angle)))
target.xy = [
xy[0] - (opts.x * opts.speed)
, xy[1] - (opts.y * opts.speed)
]
target._updateRequired = false
}
relockingPosition(target, parent, opts){
/* Dragging a relative control point. */
// Update for the child, in reverse
opts = Object.assign({}, parent._bindingSettings)
// let angle = (Math.PI + (target.radians + opts.angle)) % Math.PI2
// opts.x = (d.x + (opts.distance * Math.cos(angle)))
// opts.y = (d.y + (opts.distance * Math.sin(angle)))
let rot = calculateAngle360(parent, target, parent.rotation)
parent._bindingSettings.angle = degToRad(rot) + Math.PI
parent._bindingSettings.distance = parent.distanceTo(target)
// console.log(d)
// target.xy = [
// xy[0] - opts.x
// , xy[1] - opts.y
// ]
target._updateRequired = false
}
smoothUpdateFunction(target, parent) {
let xy = target.xy
let d = distance2D(xy, parent.xy)
/* If _bindingSettings are defined, the lock step will
pre-lock the control point.*/
if(d.distance < 2 && target._bindingSettings==undefined) {
//lock it
target._updateRequired = false
return this.updateFunction(target, parent)
}
let settings = {
/* the _Settings_ here are _add_ applied to the
current target XY. Therefore
we apply an initial minus value to add. */
x: -d.x,
y: -d.y,
speed: 1,
/* If relative, the parent point radians is taken into
account. */
relative: true,
}
if(target._bindingSettings) {
/* Dragging the primary item activates this _target_
(the control point). */
settings = Object.assign(settings, target._bindingSettings)
return this.childToParentUpdate(target, parent, settings, d)
}
if(parent._bindingSettings) {
/* Actuaing the _primary_ */
// console.log('secondary drag')
settings = Object.assign(settings, parent._bindingSettings)
if(settings.angle != undefined) {
if(settings.movable) {
return this.relockingPosition(target, parent, settings, d)
}
return this.lockedPosition(target, parent, settings, d)
}
}
// console.log(d)
target.xy = [
xy[0] + (settings.x * settings.speed)
, xy[1] + (settings.y * settings.speed)
]
target._updateRequired = !(d.distance < 2)
}
pairTest(vChildren, kOwner) {
vChildren.forEach(vChild => this.pairTestSingle(vChild, kOwner) )
}
pairTestSingle(vChild, kOwner) {
/* Iterate the bindmap, ensuring the XY of a pair match
Propagate the changed value (dirty) to the unchanges value. */
let target = undefined //vChild
let parent = undefined // kOwner
/* Stringy here, as that correctly tests the array == array */
let kOwner_dirty = kOwner._xy && kOwner._xy.toString() != kOwner.xy
let vChild_dirty = vChild._xy && vChild._xy.toString() != vChild.xy
// alt dirty check.
vChild_dirty = vChild._dirty == undefined? vChild_dirty: vChild._dirty// || (~~vChild.xy == ~~kOwner.xy)
kOwner_dirty = kOwner._dirty == undefined? kOwner_dirty: kOwner._dirty// || (~~kOwner.xy == ~~vChild.xy)
if(vChild._updateRequired) {
// console.log('dirty child')
kOwner_dirty = true
}
if(kOwner._updateRequired) {
// console.log('dirty owner')
vChild_dirty = true
}
if(kOwner_dirty === true) {
/*
The parent is dirty, push the changes to the child.
*/
// vChild.xy = kOwner.xy
target = vChild
parent = kOwner
// console.log('dirty owner')
}
if(vChild_dirty === true) {
/* The child vars are dirty, propagate to the parent */
// copy back to parent.
target = kOwner
parent = vChild
}
let updateRequired = target && target._updateRequired == true
let parentUpdateRequired = parent && parent._updateRequired == true
if(parentUpdateRequired || updateRequired || kOwner_dirty || vChild_dirty) {
/*
Only occurs if either are dirty, pushing the _dirty_ (changed)
value to the currently unchanged.
*/
// target && (target._dirty = true)// d < target.radius
// target._updateRequired = !(d.distance < 5)
this.smoothUpdateFunction(target, parent)
// updateFunction()
// console.log(target.radius, target._updateRequired)
}
// Is now clean.
vChild._xy = vChild.xy
kOwner._xy = kOwner.xy
}
connect(parent, child, childPositionSettings={}) {
// child.parentWheel = parent
// parent.childWheel = child
if(childPositionSettings.lock) {
child.xy = parent.xy
}
// parent._dirty = true
child._bindingSettings = childPositionSettings
// child.isPinion = true
this.safeMapAppend(this.bindMap, parent, child)
// this.bindMap.set(parent, child)
// this.bindMapRev.set(child, parent)
this.safeMapAppend(this.bindMapRev, child, parent)
}
safeMapAppend(bindMap,parent, child) {
if(bindMap.has(parent)) {
let items = bindMap.get(parent)
items.push(child)
return
}
bindMap.set(parent, [child])
}
}
let globalXYBind = new XYBindMap(this)
Polypoint.head.lazierProp('Stage', function xyBind(){
// console.log('Returning new lazyProp "xyBind"')
return globalXYBind
});
class PointXYBind {
constructor(point) {
this.point = point
this.settings = {}
}
connectTo(other, opts={}) {
let settings = Object.assign(this.settings, opts)
return globalXYBind.connect(this.point, other, settings)
}
follow(other, opts={}) {
let settings = Object.assign(this.settings, opts)
return globalXYBind.connect(other, this.point, settings)
}
}
Polypoint.head.deferredProp('Point',
function xyBind() {
return new PointXYBind(this)
}
);
Polypoint.head.installFunctions('Point',{
xyBindChild(other, settings={}) {
return this.xyBind.connectTo.apply(this.xyBind, arguments)
}
, xyBindParent(other, settings={}) {
return this.xyBind.follow.apply(this.xyBind, arguments)
}
});
copy