260 lines
6.0 KiB
JavaScript
260 lines
6.0 KiB
JavaScript
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();
|
|
|