2,191
edits
(Created page with "→General-purpose JavaScript used for The 'Shroom: ") |
m (Upcoming 'Shroom release) |
||
Line 1: | Line 1: | ||
/* General-purpose JavaScript used for The 'Shroom */ | /* General-purpose JavaScript used for The 'Shroom */ | ||
/* | |||
* Special Issue 195: dynamic curtain | |||
*/ | |||
function ShroomCurtain(container) { | |||
this.container = container; | |||
this.canvas = document.createElement('canvas'); | |||
this.button = document.createElement('button'); | |||
this.ctx = this.canvas.getContext('2d'); | |||
this.raf = this.renderCurtains.bind(this); | |||
this.oc = this.openCurtain.bind(this); | |||
this.canvas.className = 'shroom195curtain-canvas'; | |||
this.button.className = 'shroom195curtain-button'; | |||
this.button.textContent = 'Open the curtains'; | |||
var ct = localStorage.getItem('shroom_195curtain'); | |||
var execute = ct ? parseInt(ct) + 30 * 60 * 1000 < Date.now() : true; | |||
if (execute) { | |||
this.container.insertBefore(this.button, this.container.firstChild); | |||
this.container.insertBefore(this.canvas, this.container.firstChild); | |||
requestAnimationFrame(this.raf); | |||
this.button.addEventListener('click', this.oc); | |||
window.addEventListener('resize', this.setCanvasSize.bind(this)); | |||
this.setCanvasSize(); | |||
} | |||
var placeholder = document.querySelector('.shroom195curtain-placeholder'); | |||
placeholder.classList.add('exit'); | |||
setTimeout(function () { | |||
return placeholder.parentNode.removeChild(placeholder); | |||
}, 1000); | |||
} | |||
ShroomCurtain.prototype.openCurtain = function openCurtain() { | |||
var _this = this; | |||
this.opening = Date.now(); | |||
this.button.removeEventListener('click', this.oc); | |||
this.button.classList.add('exit'); | |||
setTimeout(function () { | |||
return _this.button.parentNode.removeChild(_this.button); | |||
}, 1000); | |||
localStorage.setItem('shroom_195curtain', Date.now().toString()); | |||
}; | |||
ShroomCurtain.prototype.setCanvasSize = function setCanvasSize() { | |||
var containerSize = this.container.getBoundingClientRect(); | |||
this.canvas.width = Math.round(containerSize.width * window.devicePixelRatio); | |||
this.canvas.height = Math.round(containerSize.height * window.devicePixelRatio); | |||
this.canvas.style.width = ''.concat(containerSize.width, 'px'); | |||
this.canvas.style.height = ''.concat(containerSize.height, 'px'); | |||
}; | |||
ShroomCurtain.prototype.renderCurtains = function renderCurtains(timestamp) { | |||
this.ctx.resetTransform(); | |||
this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height); | |||
var openingDuration = this.opening ? Date.now() - this.opening : 0; | |||
var openingProgress = openingDuration / (this.canvas.width / window.devicePixelRatio * 4 + 1000); | |||
this.ctx.fillStyle = 'rgba(0,0,0,'.concat(1 - this.inAndOut(Math.min(openingProgress, 1)), ')'); | |||
this.ctx.fillRect(0, 0, this.canvas.width, this.canvas.height); | |||
this.renderCurtain(timestamp, true, openingDuration); | |||
this.renderCurtain(timestamp, false, openingDuration); | |||
if (openingProgress <= 1) requestAnimationFrame(this.raf); else this.container.removeChild(this.canvas); | |||
}; | |||
ShroomCurtain.prototype.renderCurtain = function renderCurtain(timestamp, left, openingDuration) { | |||
var m = left ? -1 : 1; | |||
var neededFolds = Math.max(Math.round(this.canvas.width / window.devicePixelRatio / 90), 2); | |||
var foldWidth = this.canvas.width / neededFolds / 2; | |||
var curtainOffset = Math.pow(Math.min(openingDuration / (this.canvas.width / window.devicePixelRatio * 4 + 1000), 1), 2) * this.canvas.width / 2; | |||
var curtainSkewOffset = (this.inAndOut(Math.min(openingDuration / 3000, 1)) * m * -150 + Math.sin(timestamp / 1000) * (foldWidth / 6)) * window.devicePixelRatio; | |||
var gr = this.ctx.createLinearGradient(left ? this.canvas.width : 0, 0, this.canvas.width / 2, 0); | |||
gr.addColorStop(0, '#900'); | |||
gr.addColorStop(.95, '#c00'); | |||
gr.addColorStop(1, '#a00'); | |||
this.ctx.fillStyle = gr; | |||
this.ctx.save(); | |||
this.ctx.beginPath(); | |||
this.ctx.moveTo(left ? this.canvas.width : 0, 0); | |||
this.ctx.lineTo(this.canvas.width / 2 + m * (1 - curtainOffset), 0); | |||
this.ctx.lineTo(this.canvas.width / 2 + curtainSkewOffset + m * (1 - curtainOffset), this.canvas.height); | |||
this.ctx.lineTo(left ? this.canvas.width : 0, this.canvas.height); | |||
this.ctx.closePath(); | |||
this.ctx.fill(); | |||
this.ctx.clip(); | |||
for (var i = 0; i < neededFolds; i++) { | |||
var foldX = left ? this.canvas.width - foldWidth * (i + 1) : foldWidth * i; | |||
var slideOffset = curtainOffset / ((neededFolds - i - 1) / (neededFolds - 1) + 1) * m; | |||
var subtractSway = -Math.tan(curtainSkewOffset / this.canvas.height) * (i / neededFolds); | |||
var foldGr = this.ctx.createLinearGradient(foldX - slideOffset, 0, foldX + foldWidth - slideOffset, 0); | |||
for (var grI = 0; grI <= 1; grI += .1) | |||
// cos((x - .5) * PI * 2) + 1 | |||
foldGr.addColorStop(grI, 'rgba(0,0,0,'.concat((Math.cos((grI - .5) * Math.PI * 2) + 1) * .1, ')')); | |||
this.ctx.setTransform(1, 0, Math.tan(foldWidth / 3 / this.canvas.height) * Math.cos(timestamp / (1000 + Math.cos(foldX) * 100) + Math.cos(foldX * 1.2)) - subtractSway, 1, 0, 0); | |||
this.ctx.fillStyle = foldGr; | |||
this.ctx.fillRect(foldX - slideOffset, 0, foldWidth, this.canvas.height); | |||
} | |||
this.ctx.restore(); | |||
}; | |||
ShroomCurtain.prototype.inAndOut = function inAndOut(t) { | |||
return 3 * t * t - 2 * t * t * t; | |||
}; | |||
var curtainContainer = document.querySelector('.shroom195curtain'); | |||
if (curtainContainer) { | |||
new ShroomCurtain(curtainContainer); | |||
} |