442 lines
8.7 KiB
JavaScript
442 lines
8.7 KiB
JavaScript
// ----- setup ----- //
|
|
|
|
var illoElem = document.querySelector('.illo');
|
|
var sceneSize = 96;
|
|
var TAU = Zdog.TAU;
|
|
var ROOT3 = Math.sqrt(3);
|
|
var ROOT5 = Math.sqrt(5);
|
|
var PHI = ( 1 + ROOT5 ) / 2;
|
|
var isSpinning = true;
|
|
var viewRotation = new Zdog.Vector();
|
|
var displaySize;
|
|
|
|
// colors
|
|
var eggplant = '#636';
|
|
var garnet = '#C25';
|
|
var orange = '#E62';
|
|
var gold = '#EA0';
|
|
var yellow = '#ED0';
|
|
|
|
var illo = new Zdog.Illustration({
|
|
element: illoElem,
|
|
scale: 8,
|
|
resize: 'fullscreen',
|
|
onResize: function( width, height ) {
|
|
displaySize = Math.min( width, height );
|
|
this.zoom = Math.floor( displaySize / sceneSize );
|
|
},
|
|
});
|
|
|
|
var solids = [];
|
|
|
|
// ----- hourglass ----- //
|
|
|
|
( function() {
|
|
|
|
var hourglass = new Zdog.Anchor({
|
|
addTo: illo,
|
|
translate: { x: 0, y: -4 },
|
|
});
|
|
|
|
solids.push( hourglass );
|
|
|
|
var hemi = new Zdog.Hemisphere({
|
|
diameter: 2,
|
|
translate: { z: -1 },
|
|
addTo: hourglass,
|
|
color: garnet,
|
|
backface: orange,
|
|
stroke: false,
|
|
});
|
|
|
|
hemi.copy({
|
|
translate: { z: 1 },
|
|
rotate: { y: TAU/2 },
|
|
color: eggplant,
|
|
backface: gold,
|
|
});
|
|
|
|
})();
|
|
|
|
// ----- sphere ----- //
|
|
|
|
( function() {
|
|
|
|
var sphere = new Zdog.Anchor({
|
|
addTo: illo,
|
|
translate: { x: -4, y: -4 },
|
|
});
|
|
|
|
solids.push( sphere );
|
|
|
|
var hemi = new Zdog.Hemisphere({
|
|
diameter: 2,
|
|
addTo: sphere,
|
|
color: orange,
|
|
backface: eggplant,
|
|
stroke: false,
|
|
});
|
|
|
|
hemi.copy({
|
|
rotate: { y: TAU/2 },
|
|
color: eggplant,
|
|
backface: orange,
|
|
});
|
|
|
|
})();
|
|
|
|
// ----- cylinder ----- //
|
|
|
|
var cylinder = new Zdog.Cylinder({
|
|
diameter: 2,
|
|
length: 2,
|
|
addTo: illo,
|
|
translate: { x: 4, y: -4 },
|
|
// rotate: { x: TAU/4 },
|
|
color: gold,
|
|
backface: garnet,
|
|
stroke: false,
|
|
});
|
|
|
|
solids.push( cylinder );
|
|
|
|
// ----- cone ----- //
|
|
|
|
var cone = new Zdog.Anchor({
|
|
addTo: illo,
|
|
translate: { x: -4, y: 0 },
|
|
});
|
|
|
|
solids.push( cone );
|
|
|
|
new Zdog.Cone({
|
|
diameter: 2,
|
|
length: 2,
|
|
addTo: cone,
|
|
translate: { z: 1 },
|
|
rotate: { y: TAU/2 },
|
|
color: garnet,
|
|
backface: gold,
|
|
stroke: false,
|
|
});
|
|
|
|
// ----- tetrahedron ----- //
|
|
|
|
( function() {
|
|
|
|
var tetrahedron = new Zdog.Anchor({
|
|
addTo: illo,
|
|
translate: { x: 0, y: 0 },
|
|
scale: 2.5,
|
|
});
|
|
|
|
var radius = 0.5;
|
|
var inradius = Math.cos( TAU/6 ) * radius;
|
|
var height = radius + inradius;
|
|
|
|
solids.push( tetrahedron );
|
|
|
|
var triangle = new Zdog.Polygon({
|
|
sides: 3,
|
|
radius: radius,
|
|
addTo: tetrahedron,
|
|
translate: { y: height/2 },
|
|
fill: true,
|
|
stroke: false,
|
|
color: eggplant,
|
|
// backface: false,
|
|
});
|
|
|
|
|
|
for ( var i=0; i < 3; i++ ) {
|
|
var rotor1 = new Zdog.Anchor({
|
|
addTo: tetrahedron,
|
|
rotate: { y: TAU/3 * -i },
|
|
});
|
|
var rotor2 = new Zdog.Anchor({
|
|
addTo: rotor1,
|
|
translate: { z: inradius, y: height/2 },
|
|
rotate: { x: Math.acos(1/3) * -1 + TAU/4 },
|
|
});
|
|
triangle.copy({
|
|
addTo: rotor2,
|
|
translate: { y: -inradius },
|
|
color: [ gold, garnet, orange ][i],
|
|
});
|
|
}
|
|
|
|
triangle.rotate.set({ x: -TAU/4, z: -TAU/2 });
|
|
|
|
})();
|
|
|
|
// ----- octahedron ----- //
|
|
|
|
( function() {
|
|
|
|
var octahedron = new Zdog.Anchor({
|
|
addTo: newcanvas,
|
|
translate: { x: -4, y: 4 },
|
|
scale: 1.75,
|
|
});
|
|
|
|
var colorWheel = [ eggplant, garnet, orange, gold, yellow ];
|
|
|
|
// radius of triangle with side length = 1
|
|
var radius = ROOT3/2 * 2/3;
|
|
var height = radius * 3/2;
|
|
var tilt = Math.asin( 0.5 / height );
|
|
|
|
[ -1, 1 ].forEach( function( ySide ) {
|
|
for ( var i=0; i < 4; i++ ) {
|
|
var rotor = new Zdog.Anchor({
|
|
addTo: octahedron,
|
|
rotate: { y: TAU/4 * (i + 1.5) * -1 },
|
|
});
|
|
|
|
var anchor = new Zdog.Anchor({
|
|
addTo: rotor,
|
|
translate: { z: 0.5 },
|
|
rotate: { x: tilt * ySide },
|
|
// scale: { y: -ySide },
|
|
});
|
|
|
|
new Zdog.Polygon({
|
|
sides: 3,
|
|
radius: radius,
|
|
addTo: anchor,
|
|
translate: { y: -radius/2 * ySide },
|
|
scale: { y: ySide },
|
|
stroke: false,
|
|
fill: true,
|
|
color: colorWheel[ i + 0.5 + 0.5*ySide ],
|
|
backface: false,
|
|
});
|
|
}
|
|
});
|
|
|
|
|
|
})();
|
|
|
|
// ----- cube ----- //
|
|
|
|
var cube = new Zdog.Box({
|
|
addTo: illo,
|
|
width: 2,
|
|
height: 2,
|
|
depth: 2,
|
|
translate: { x: 4, y: 0 },
|
|
topFace: yellow,
|
|
frontFace: gold,
|
|
leftFace: orange,
|
|
rightFace: orange,
|
|
rearFace: garnet,
|
|
bottomFace: eggplant,
|
|
stroke: false,
|
|
});
|
|
|
|
solids.push( cube );
|
|
|
|
// ----- dodecahedron ----- //
|
|
|
|
( function() {
|
|
|
|
var dodecahedron = new Zdog.Anchor({
|
|
addTo: illo,
|
|
translate: { x: 0, y: 4 },
|
|
scale: 0.75,
|
|
});
|
|
|
|
solids.push( dodecahedron );
|
|
|
|
// https://en.wikipedia.org/wiki/Regular_dodecahedron#Dimensions
|
|
var midradius = ( PHI * PHI ) / 2;
|
|
|
|
// top & bottom faces
|
|
var face = new Zdog.Polygon({
|
|
sides: 5,
|
|
radius: 1,
|
|
addTo: dodecahedron,
|
|
translate: { y: -midradius },
|
|
rotate: { x: TAU/4 },
|
|
fill: true,
|
|
stroke: false,
|
|
color: yellow,
|
|
// backface: false,
|
|
});
|
|
|
|
face.copy({
|
|
translate: { y: midradius },
|
|
rotate: { x: -TAU/4 },
|
|
color: eggplant,
|
|
});
|
|
|
|
|
|
[ -1, 1 ].forEach( function( ySide ) {
|
|
|
|
|
|
var colorWheel = {
|
|
'-1': [ eggplant, garnet, gold, orange, garnet ],
|
|
1: [ yellow, gold, garnet, orange, gold ],
|
|
}[ ySide ];
|
|
|
|
for ( var i=0; i < 5; i++ ) {
|
|
var rotor1 = new Zdog.Anchor({
|
|
addTo: dodecahedron,
|
|
rotate: { y: TAU/5 * (i) },
|
|
});
|
|
var rotor2 = new Zdog.Anchor({
|
|
addTo: rotor1,
|
|
rotate: { x: TAU/4*ySide - Math.atan(2) },
|
|
});
|
|
|
|
face.copy({
|
|
addTo: rotor2,
|
|
translate: { z: midradius },
|
|
rotate: { z: TAU/2 },
|
|
color: colorWheel[i],
|
|
});
|
|
}
|
|
});
|
|
|
|
})();
|
|
|
|
// ----- isocahedron ----- //
|
|
|
|
( function() {
|
|
|
|
var isocahedron = new Zdog.Anchor({
|
|
addTo: illo,
|
|
translate: { x: 4, y: 4 },
|
|
scale: 1.2,
|
|
});
|
|
|
|
solids.push( isocahedron );
|
|
|
|
// geometry
|
|
// radius of triangle with side length = 1
|
|
var faceRadius = ROOT3/2 * 2/3;
|
|
var faceHeight = faceRadius * 3/2;
|
|
var capApothem = 0.5 / Math.tan( TAU/10 );
|
|
var capRadius = 0.5 / Math.sin( TAU/10 );
|
|
var capTilt = Math.asin( capApothem / faceHeight );
|
|
var capSagitta = capRadius - capApothem;
|
|
var sideTilt = Math.asin( capSagitta / faceHeight );
|
|
var sideHeight = Math.sqrt( faceHeight*faceHeight - capSagitta*capSagitta );
|
|
|
|
// var colorWheel = [ eggplant, garnet, orange, gold, yellow ];
|
|
|
|
[ -1, 1 ].forEach( function( ySide ) {
|
|
var capColors = {
|
|
'-1': [ garnet, gold, yellow, gold, orange ],
|
|
1: [ gold, garnet, eggplant, garnet, orange ],
|
|
}[ ySide ];
|
|
|
|
var sideColors = {
|
|
'-1': [ garnet, gold, yellow, orange, garnet ],
|
|
1: [ gold, garnet, eggplant, orange, orange ],
|
|
}[ ySide ];
|
|
|
|
for ( var i=0; i < 5; i++ ) {
|
|
var rotor = new Zdog.Anchor({
|
|
addTo: isocahedron,
|
|
rotate: { y: TAU/5 * -i },
|
|
translate: { y: sideHeight/2 * ySide },
|
|
});
|
|
|
|
var capRotateX = -capTilt;
|
|
var isYPos = ySide > 0;
|
|
capRotateX += isYPos ? TAU/2 : 0;
|
|
|
|
var capAnchor = new Zdog.Anchor({
|
|
addTo: rotor,
|
|
translate: { z: capApothem * ySide },
|
|
rotate: { x: capRotateX },
|
|
});
|
|
|
|
// cap face
|
|
var face = new Zdog.Polygon({
|
|
sides: 3,
|
|
radius: faceRadius,
|
|
addTo: capAnchor,
|
|
translate: { y: -faceRadius/2 },
|
|
stroke: false,
|
|
fill: true,
|
|
color: capColors[i],
|
|
// backface: false,
|
|
});
|
|
|
|
var sideRotateX = -sideTilt;
|
|
sideRotateX += isYPos ? 0 : TAU/2;
|
|
var sideAnchor = capAnchor.copy({
|
|
rotate: { x: sideRotateX },
|
|
});
|
|
|
|
face.copy({
|
|
addTo: sideAnchor,
|
|
translate: { y: -faceRadius/2 },
|
|
rotate: { y: TAU/2 },
|
|
color: sideColors[i]
|
|
});
|
|
|
|
}
|
|
});
|
|
|
|
})();
|
|
|
|
// -- animate --- //
|
|
|
|
var keyframes = [
|
|
{ x: 0, y: 0 },
|
|
{ x: 0, y: TAU },
|
|
{ x: TAU, y: TAU },
|
|
];
|
|
|
|
var ticker = 0;
|
|
var cycleCount = 180;
|
|
var turnLimit = keyframes.length - 1;
|
|
|
|
function animate() {
|
|
update();
|
|
illo.renderGraph();
|
|
requestAnimationFrame( animate );
|
|
}
|
|
|
|
animate();
|
|
|
|
function update() {
|
|
|
|
if ( isSpinning ) {
|
|
var progress = ticker / cycleCount;
|
|
var tween = Zdog.easeInOut( progress % 1, 4 );
|
|
var turn = Math.floor( progress % turnLimit );
|
|
var keyA = keyframes[ turn ];
|
|
var keyB = keyframes[ turn + 1 ];
|
|
viewRotation.x = Zdog.lerp( keyA.x, keyB.x, tween );
|
|
viewRotation.y = Zdog.lerp( keyA.y, keyB.y, tween );
|
|
ticker++;
|
|
}
|
|
|
|
solids.forEach( function( solid ) {
|
|
solid.rotate.set( viewRotation );
|
|
});
|
|
|
|
illo.updateGraph();
|
|
}
|
|
|
|
// ----- inputs ----- //
|
|
|
|
var dragStartRX, dragStartRY;
|
|
|
|
new Zdog.Dragger({
|
|
startElement: illoElem,
|
|
onDragStart: function() {
|
|
isSpinning = false;
|
|
dragStartRX = viewRotation.x;
|
|
dragStartRY = viewRotation.y;
|
|
},
|
|
onDragMove: function( pointer, moveX, moveY ) {
|
|
viewRotation.x = dragStartRX - ( moveY / displaySize * TAU );
|
|
viewRotation.y = dragStartRY - ( moveX / displaySize * TAU );
|
|
},
|
|
});
|