import FPS from './fps.js'; const ONE_SECOND = 1000; const PRESS_RIPPLE = ONE_SECOND / 3; const DEFAULTS = { board: Tessellate.BOARD_STYLES.HEX, style: Tessellate.DRAW_STYLES.FILL, orientation: Tessellate.ORIENTATION_STYLES.FLAT, tile: Tessellate.TILE_STYLES.HEX, }; const pressRipple = function() { const sinStart = 2 * Math.PI; const halfPi = Math.PI / 2; return pressFactor => Math.sin(sinStart + (pressFactor * halfPi)) + 1; }(); const pressFade = function() { const halfPi = Math.PI / 2; return pressFactor => Math.sin(Math.PI + (pressFactor * halfPi)) + 1; }(); class Demo { constructor() { [ 'setOriginTile', 'setFadeToGray', 'tap', 'pressStart', 'press', 'createTile', 'drawTile', 'draw', ].map(method => this[method] = this[method].bind(this)); const queryStringObj = Tessellate.utils.getQueryStringObj(); this.settings = Object.assign({}, DEFAULTS, queryStringObj); this.map = {}; this.taps = []; this.mines = {}; this.ripples = []; this.fps = new FPS({ element: document.querySelector('#fps'), }); this.setOriginTile(); this.setFadeToGray(); this.tessellate = new Tessellate(Object.assign({ element: '#container', tap: this.tap, pressStart: this.pressStart, press: this.press, draw: this.draw, }, this.settings)); } setOriginTile() { this.map['0,0'] = new Tessellate.Cell({ x: 0, y: 0, scale: 1, drawStyle: Tessellate.DRAW_STYLES.FILL, tileStyle: this.settings.tile, orientation: this.settings.orientation, color: { red: 255, green: 255, blue: 0, alpha: 1, } }); Tessellate.utils.rangeInclusive(0, 5) .map(interval => interval ? interval * 0.2 : 0.01) .forEach(interval => { this.taps.push(new Tessellate.Cell({ x: 0, y: 0, scale: interval, drawStyle: Tessellate.DRAW_STYLES.OUTLINE, tileStyle: this.settings.tile, orientation: this.settings.orientation, color: { red: 0, green: 0, blue: 0, alpha: 1, }, })); }); } setFadeToGray () { window.addEventListener('keydown', event => { if (!event.repeat && event.key === 'Enter') { this.gray = this.gray ? null : Date.now(); } }); } tap(tap) { const {x, y, z} = tap.tile.getPoint(); const key = `${ x },${ z != null ? z : y }`; const pipMax = this.settings.tile === Tessellate.TILE_STYLES.HEX ? 7 : 9; this.map[key].pips = Tessellate.utils.random(1, pipMax); } pressStart(tap) { this.ripples.push({ timestamp: tap.event.timeStampUTC, cell: this.createTile({ x: tap.tile.x, y: tap.tile.y, scale: 1.0, drawStyle: Tessellate.DRAW_STYLES.FILL, tileStyle: Tessellate.TILE_STYLES.CIRCLE, orientation: Tessellate.ORIENTATION_STYLES.FLAT, color: { red: 128, green: 128, blue: 128, alpha: 0.5, }, }) }); if (tap.event.mobile) { this.togglemine(tap.tile) } } press(tap) { if (!tap.event.mobile) { this.togglemine(tap.tile) } } togglemine(tile) { const {x, y, z} = tile.getPoint(); const key = `${ x },${ z != null ? z : y }`; if (this.mines[key]) { delete this.mines[key]; } else { this.mines[key] = tile; } } createTile({x, y, drawStyle, tileStyle, orientation, scale = Tessellate.utils.random(7, 9) / 10, color = { red: Tessellate.utils.random(255), green: Tessellate.utils.random(255), blue: Tessellate.utils.random(255), alpha: Tessellate.utils.random(25, 75) / 100, } }) { return new Tessellate.Cell({ x, y, scale, drawStyle, tileStyle, orientation, color, }); } fadeToGray (tile, fadeFactor) { tile.color.grayscale = tile.color.grayscale || Tessellate.utils.grayscale(tile.color); const grayscale = tile.color.grayscale; const color = { red: parseInt(tile.color.red - ((tile.color.red - grayscale) * fadeFactor)), green: parseInt(tile.color.green - ((tile.color.green - grayscale) * fadeFactor)), blue: parseInt(tile.color.blue - ((tile.color.blue - grayscale) * fadeFactor)), }; tile = Tessellate.utils.extend(tile, {color}); return tile; } drawTile({x, y, z}, context, scale) { const key = `${ x },${ z != null ? z : y }`; this.map[key] = this.map[key] || this.createTile({ x, y, drawStyle: this.settings.style, tileStyle: this.settings.tile, orientation: this.settings.orientation, }); let tile = this.map[key]; const pixelPoint = this.tessellate.tileToPixel(x, y, z); const fadeFactor = this.gray ? Math.min((Date.now() - this.gray) / 5000, 1) : null; tile = this.gray ? this.fadeToGray(tile, fadeFactor) : tile; Tessellate.TILES[tile.tileStyle][tile.drawStyle](context, scale, pixelPoint.getX(), pixelPoint.getY(), tile); Tessellate.Shapes.pips(context, scale, pixelPoint.getX(), pixelPoint.getY(), tile); } draw({context, height, width, scale, tilePoints, now, lastNow}) { this.fps.frame(now, lastNow); Tessellate.Shapes.background(context, height, width, { red: 64, green: 32, blue: 128, }); tilePoints.forEach(tilePoint => this.drawTile(tilePoint, context, scale)); this.ripples.forEach(({timestamp, cell}) => { const pressFactor = Math.min((now - timestamp) / PRESS_RIPPLE, 1); Object.assign(cell, {scale: pressRipple(pressFactor)}); Object.assign(cell.color, {alpha: pressFade(pressFactor)}); const pixelPoint = this.tessellate.tileToPixel(cell.x, cell.y); Tessellate.TILES[cell.tileStyle][cell.drawStyle](context, scale, pixelPoint.getX(), pixelPoint.getY(), cell); }); this.ripples = this.ripples.filter(ripple => (ripple.timestamp + PRESS_RIPPLE) > now); this.taps.forEach(cell => { const pixelPoint = this.tessellate.tileToPixel(cell.x, cell.y); Tessellate.TILES[cell.tileStyle][cell.drawStyle](context, scale, pixelPoint.getX(), pixelPoint.getY(), cell); }); Tessellate.funky.forEach(this.mines, cell => { const pixelPoint = this.tessellate.tileToPixel(cell.x, cell.y); Tessellate.Shapes.mine(context, scale, pixelPoint.getX(), pixelPoint.getY()); }); } } let demo = new Demo();