|
'use strict'; |
|
|
|
JSON.clone = JSON.clone || function(o){ |
|
let obj = JSON.stringify(o); |
|
if(typeof obj === 'undefined'){ |
|
return undefined; |
|
} |
|
obj = JSON.parse(obj); |
|
return obj; |
|
}; |
|
|
|
class PsycheCheckers{ |
|
|
|
constructor(opts){ |
|
if(!opts) opts = {}; |
|
opts = JSON.clone(opts); |
|
|
|
if(!Array.isArray(opts.seedPoints)){ |
|
/* |
|
seedPoints = [ |
|
[Math.random(), Math.random()], |
|
[Math.random(), Math.random()], |
|
]; |
|
*/ |
|
opts.seedPoints = [ |
|
[0.25, 1/3], |
|
[0.75, 2/3], |
|
]; |
|
} |
|
|
|
if(isNaN(opts.ticks)){ |
|
opts.ticks = 50; |
|
} |
|
opts.ticks = Math.round(opts.ticks); |
|
|
|
if(isNaN(opts.ratio)){ |
|
opts.ratio = 480/640; |
|
} |
|
opts.ticks = parseInt(opts.ticks,10); |
|
|
|
|
|
|
|
this.dirtyEvent(); |
|
|
|
this.opts = opts; |
|
this.innerPoints = JSON.clone(opts.seedPoints); |
|
this.ratio = opts.ratio; |
|
} |
|
|
|
get ratio(){ |
|
return this._ratio; |
|
} |
|
|
|
set ratio(newRatio){ |
|
if(isNaN(newRatio)) return; |
|
if(isNaN(this._ratio)) this._ratio = 0; |
|
newRatio = +newRatio; |
|
|
|
if(this._ratio === newRatio) return; |
|
|
|
this.dirtyEvent(); |
|
this._ratio = newRatio; |
|
} |
|
|
|
get outerPoints(){ |
|
if(this._outerPoints) return this._outerPoints; |
|
|
|
let p = []; |
|
|
|
let half = Math.ceil(this.opts.ticks / 2); |
|
let horizontal = Math.round(half * this.ratio/(this.ratio + 1)); |
|
let vertical = half - horizontal; |
|
let dist = 0; |
|
|
|
dist = 1/horizontal; |
|
for(let x=0; x <= 1; x += dist){ |
|
p.push([x,0]); |
|
p.push([1-x,1]); |
|
} |
|
dist = 1/vertical; |
|
for(let y=0; y <= 1 ; y += dist){ |
|
p.push([0,1-y]); |
|
p.push([1,y]); |
|
} |
|
// we end up duplicating the very first and last points on the |
|
// rectangle |
|
p.shift(); |
|
p.pop(); |
|
|
|
this._outerPoints = p; |
|
return this._outerPoints; |
|
} |
|
|
|
get lines(){ |
|
if(this._lines) return this._lines; |
|
|
|
let lin = []; |
|
|
|
for(let i=0; i< this.innerPoints.length; i++){ |
|
for(let o = 0; o < this.outerPoints.length; o++){ |
|
lin.push([ |
|
this.innerPoints[i], |
|
this.outerPoints[o], |
|
]); |
|
} |
|
} |
|
|
|
this._lines = lin; |
|
return this._lines; |
|
} |
|
|
|
|
|
/** |
|
* List of all quadrilaterals formed on draw area |
|
* |
|
* |
|
*/ |
|
get quadrilaterals(){ |
|
if(this._quadrilaterals) return this._quadrilaterals; |
|
|
|
let q = []; |
|
|
|
//TODO: This is the biggest challenge |
|
throw new Error('Not Implemented'); |
|
|
|
this._quadrilaterals = q; |
|
return this._quadrilaterals; |
|
} |
|
|
|
|
|
dirtyEvent(){ |
|
this._ratio = 1; |
|
this._outerPoints = null; |
|
this._lines = null; |
|
} |
|
|
|
} |
|
|
|
|
|
class RenderPsycheCheckers{ |
|
constructor(svg, checkers){ |
|
this.svg = svg; |
|
this.psyche = checkers; |
|
} |
|
|
|
get rect(){ |
|
return this.svg.getClientRects()[0]; |
|
} |
|
|
|
get dataCoordinates(){ |
|
let width = this.rect.width; |
|
let height = this.rect.height; |
|
let data = this.psyche.lines |
|
.map(function(d,l){ |
|
d = JSON.clone(d); |
|
d[0][0] *= width; |
|
d[0][1] *= height; |
|
d[1][0] *= width; |
|
d[1][1] *= height; |
|
return d; |
|
}); |
|
return data; |
|
} |
|
|
|
drawLines(attributes){ |
|
let data = this.dataCoordinates; |
|
let lines = Array.from(this.svg.querySelectorAll('line')); |
|
while(lines.length < data.length){ |
|
lines.unshift(document.createElementNS("http://www.w3.org/2000/svg","line")); |
|
this.svg.appendChild(lines[0]); |
|
} |
|
while(lines.length > data.length){ |
|
let line = lines.pop(); |
|
line.parentNode.removeChild(line); |
|
} |
|
lines.forEach(function(line,l){ |
|
let d = data[l]; |
|
line.setAttribute('x1',d[0][0]); |
|
line.setAttribute('y1',d[0][1]); |
|
line.setAttribute('x2',d[1][0]); |
|
line.setAttribute('y2',d[1][1]); |
|
|
|
Object.entries(attributes).forEach(function(attr){ |
|
line.setAttribute(attr[0],attr[1]); |
|
}); |
|
}); |
|
} |
|
|
|
drawQuads(){ |
|
|
|
} |
|
} |