Skip to content

Instantly share code, notes, and snippets.

@JeffCave
Last active December 24, 2017 00:29
Show Gist options
  • Save JeffCave/688e5ba0f73b3060af67b04083ced787 to your computer and use it in GitHub Desktop.
Save JeffCave/688e5ba0f73b3060af67b04083ced787 to your computer and use it in GitHub Desktop.
Psychedelic Checkerboard

Psychodelic Checkers

Sample of a fun renderer. We made these in my Grade 6 art class and I've always enjoyed them.

What I didn't realize at the time is they make an interesting graph. Assuming you have two domains of equal size, you can start at the top/left and work your way around the entire outer boundary counting off tick marks. Given a set of X/Y coordinates, you can map the intersection of any two domains.

It looks cool, but I'm not sure it communicates anything meaningfully.

<html>
<head>
<script type="text/javascript" src="./PsycheCheckers.js"></script>
<style>
svg{
position:relative;
height:100%;
width:100%;
}
main{
position: relative;
height:480px;
width:100%;
}
</style>
</head>
<body>
<main>
<svg></svg>
</main>
<script>
'use strict';
/* global PsycheCheckers, global RenderPsycheCheckers*/
function redraw(renderer){
let ratio = renderer.rect.height / renderer.rect.width;
if(renderer.psyche.ratio === ratio) return false;
renderer.psyche.ratio = ratio;
renderer.drawLines({'stroke':'black'});
return true;
}
function main(){
let svg = document.querySelector('svg');
let checkers = new PsycheCheckers();
let renderer = new RenderPsycheCheckers(svg,checkers);
window.addEventListener('resize',function(){
redraw(renderer);
});
redraw(renderer);
}
main();
</script>
</body>
</html>
'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(){
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment