diff --git a/src/cell.js b/src/cell.js index fcf4fde..0da4c8d 100644 --- a/src/cell.js +++ b/src/cell.js @@ -1,4 +1,4 @@ -import {random} from './utils.js'; +import {getColor, random} from './utils.js'; import { HEX, CIRCLE, SQUARE, FLAT, POINTY, @@ -15,10 +15,12 @@ const DEFAULTS = { drawStyle: FILL, width: 1, - red: 0, - green: 0, - blue: 0, - alpha: 0.5, + color: { + red: 0, + green: 0, + blue: 0, + alpha: 0.5, + }, }; export default class Cell { @@ -29,7 +31,7 @@ export default class Cell { } getColor() { - return `rgba(${this.red},${this.green},${this.blue},${this.alpha})`; + return getColor(this.color); } } diff --git a/src/drawShapes.js b/src/drawShapes.js index 775d7cc..fd2d1f3 100644 --- a/src/drawShapes.js +++ b/src/drawShapes.js @@ -1,16 +1,53 @@ -import {range, sqrt2, toFixed} from './utils.js'; +import {getColor, range, sqrt2, toFixed} from './utils.js'; import {HEX, SQUARE, FLAT, POINTY} from './consts.js'; const DEFAULTS = { - flagScale: 0.5, - pipScale: 0.15, - pipDistance: 0.4, + mine: { + border: { + scale: 0.38, + + color: { + red: 255, + blue: 255, + green: 255, + }, + + horns: { + scale: 0.07, + distance: 0.36, + }, + }, + body: { + scale: 0.36, + + color: { + red: 192, + blue: 32, + green: 32, + }, + + horns: { + scale: 0.05, + distance: 0.36, + }, + } + }, + + pip: { + scale: 0.15, + distance: 0.4, + color: { + red: 0, + blue: 0, + green: 0, + }, + }, sides: 6, slices: 24, }; -function generateFlatSquarePips() { +function generateFlatSquarePips () { const pips = []; const pipX = [0, 1, 1, -1, -1, 1, -1, 0, 0]; const pipY = [0, 1, -1, -1, 1, 0, 0, -1, 1]; @@ -30,7 +67,7 @@ function generateFlatSquarePips() { return pips; } -function generatePointySquarePips() { +function generatePointySquarePips () { const pips = []; const pipX = [0, sqrt2, 0, -sqrt2, 0, sqrt2 / 2, -sqrt2 / 2, sqrt2 / 2, -sqrt2 / 2]; const pipY = [0, 0, -sqrt2, 0, sqrt2, -sqrt2 / 2, sqrt2 / 2, sqrt2 / 2, -sqrt2 / 2]; @@ -50,7 +87,7 @@ function generatePointySquarePips() { return pips; } -function generateFlatHexPips(slicesX, slicesY) { +function generateFlatHexPips (slicesX, slicesY) { const pips = [] slicesX = [0].concat(slicesX); slicesY = [0].concat(slicesY); @@ -68,7 +105,7 @@ function generateFlatHexPips(slicesX, slicesY) { return pips; } -function generatePointyHexPips(slicesX, slicesY) { +function generatePointyHexPips (slicesX, slicesY) { const pips = [] slicesX = [0].concat(slicesX); slicesY = [0].concat(slicesY); @@ -87,7 +124,7 @@ function generatePointyHexPips(slicesX, slicesY) { } export default class DrawShapes { - constructor(settings) { + constructor (settings) { this.settings = Object.assign({}, DEFAULTS, settings); const sides = this.settings.sides; @@ -105,9 +142,11 @@ export default class DrawShapes { [POINTY]: generatePointySquarePips(), } }; + + this.horns = this.pipVertices[HEX][FLAT][6].concat(this.pipVertices[HEX][POINTY][6]); } - pip(context, scale, cellX, cellY, vertexX, vertexY, pipRadius, pipDistance) { + pip (context, scale, cellX, cellY, vertexX, vertexY, pipRadius, pipDistance) { const x = cellX + (pipDistance * vertexX); const y = cellY + (pipDistance * vertexY); @@ -115,14 +154,14 @@ export default class DrawShapes { context.arc(x, y, pipRadius, 0, Math.PI*2, true); } - pips(context, scale, x, y, cell) { + pips (context, scale, x, y, cell, pip = this.settings.pip) { const {tileStyle, orientation, pips} = cell; if (this.pipVertices[tileStyle] && this.pipVertices[tileStyle][orientation] && this.pipVertices[tileStyle][orientation][pips]) { - const pipRadius = scale * this.settings.pipScale; - const pipDistance = scale * this.settings.pipDistance; + const pipRadius = scale * pip.scale; + const pipDistance = scale * pip.distance; context.beginPath(); @@ -130,23 +169,44 @@ export default class DrawShapes { .forEach(([pipX, pipY]) => this.pip(context, scale, x,y, pipX, pipY, pipRadius, pipDistance)); context.closePath(); - context.fillStyle = 'rgb(0,0,0)'; + context.fillStyle = getColor(pip.color); context.fill(); } } - flag (context, scale, x, y) { - context.beginPath(); + mine (context, scale, x, y, mine = this.settings.mine) { + this._mine(context, scale, x, y, mine.border); + this._horns(context, scale, x, y, mine.border.horns, mine.border.color); + this._mine(context, scale, x, y, mine.body); + this._horns(context, scale, x, y, mine.body.horns, mine.body.color); + } + _mine (context, scale, x, y, mine) { + context.beginPath(); context.moveTo(x, y); - context.arc(x, y, scale * this.settings.flagScale, 0, Math.PI*2, true); + + context.arc(x, y, scale * mine.scale, 0, Math.PI*2, true); context.closePath(); - context.fillStyle = 'rgb(255,0,0)'; + context.fillStyle = getColor(mine.color); context.fill(); } - mine(context, scale, x, y) { + _horns (context, scale, x, y, horn, color) { + const hornRadius = scale * horn.scale; + const hornDistance = scale * horn.distance; + + context.beginPath(); + + this.horns + .forEach(([hornX, hornY]) => this.pip(context, scale, x,y, hornX, hornY, hornRadius, hornDistance)); + + context.closePath(); + context.fillStyle = getColor(color); + context.fill(); + } + + explosion (context, scale, x, y) { var peak = scale * 0.667; var valley = scale * 0.333; diff --git a/src/main.js b/src/main.js index cd11136..39dcd99 100644 --- a/src/main.js +++ b/src/main.js @@ -39,7 +39,7 @@ class Demo { this.map = {}; this.taps = []; - this.flags = {}; + this.mines = {}; this.ripples = []; this.setOriginTile(); @@ -60,10 +60,13 @@ class Demo { drawStyle: Tessellate.DRAW_STYLES.FILL, tileStyle: this.settings.tile, orientation: this.settings.orientation, - red: 255, - green: 255, - blue: 0, - alpha: 1, + + color: { + red: 255, + green: 255, + blue: 0, + alpha: 1, + } }); Tessellate.utils.rangeInclusive(0, 5) @@ -76,28 +79,29 @@ class Demo { drawStyle: Tessellate.DRAW_STYLES.OUTLINE, tileStyle: this.settings.tile, orientation: this.settings.orientation, - red: 0, - green: 0, - blue: 0, - alpha: 1, + + color: { + red: 0, + green: 0, + blue: 0, + alpha: 1, + }, })); }); } tap(tap) { const {x, y, z} = tap.tile.getPoint(); - console.log(x, y, z); 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); - console.log(this.map[key].pips); } pressStart(tap) { this.ripples.push({ - timestamp: tap.event.timeStamp, + timestamp: tap.event.timeStampUTC, cell: this.createTile({ x: tap.tile.x, @@ -109,43 +113,47 @@ class Demo { tileStyle: Tessellate.TILE_STYLES.CIRCLE, orientation: Tessellate.ORIENTATION_STYLES.FLAT, - red: 255, - green: 127, - blue: 127, - alpha: 0.5, + color: { + red: 128, + green: 128, + blue: 128, + alpha: 0.5, + }, }) }); if (tap.event.mobile) { - this.toggleFlag(tap.tile) + this.togglemine(tap.tile) } } press(tap) { if (!tap.event.mobile) { - this.toggleFlag(tap.tile) + this.togglemine(tap.tile) } } - toggleFlag(tile) { + togglemine(tile) { const {x, y, z} = tile.getPoint(); const key = `${ x },${ z != null ? z : y }`; - if (this.flags[key]) { - delete this.flags[key]; + if (this.mines[key]) { + delete this.mines[key]; } else { - this.flags[key] = tile; + this.mines[key] = tile; } } createTile({x, y, drawStyle, tileStyle, orientation, scale = Tessellate.utils.random(7, 9) / 10, - red = Tessellate.utils.random(255), - green = Tessellate.utils.random(255), - blue = Tessellate.utils.random(255), - alpha = Tessellate.utils.random(25, 75) / 100, + 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({ @@ -157,10 +165,7 @@ class Demo { tileStyle, orientation, - red, - green, - blue, - alpha, + color, }); } @@ -186,13 +191,10 @@ class Demo { const now = Date.now(); this.ripples.forEach(({timestamp, cell}) => { - let pressFactor = (now - timestamp) / PRESS_RIPPLE; - pressFactor = pressFactor > 1 ? 1 : pressFactor; + const pressFactor = Math.min((now - timestamp) / PRESS_RIPPLE, 1); - Object.assign(cell, { - scale: pressRipple(pressFactor), - alpha: pressFade(pressFactor), - }); + 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); @@ -204,15 +206,15 @@ class Demo { Tessellate.TILES[cell.tileStyle][cell.drawStyle](context, scale, pixelPoint.getX(), pixelPoint.getY(), cell); }); - Tessellate.funky.forEach(this.flags, cell => { + Tessellate.funky.forEach(this.mines, cell => { const pixelPoint = this.tessellate.tileToPixel(cell.x, cell.y); - Tessellate.Shapes.flag(context, scale, pixelPoint.getX(), pixelPoint.getY()); + Tessellate.Shapes.mine(context, scale, pixelPoint.getX(), pixelPoint.getY()); }); - if (!this.notFirstTime) { - this.notFirstTime = true; - console.log(tilePoints); - } +// if (!this.notFirstTime) { +// this.notFirstTime = true; +// console.log(tilePoints); +// } } } diff --git a/src/onTap.js b/src/onTap.js index 06ed573..d2b3fc8 100644 --- a/src/onTap.js +++ b/src/onTap.js @@ -1,6 +1,7 @@ - import {noop} from './utils.js'; +const MODULE = 'onTap'; + const DEFAULTS = { debug: false, @@ -23,6 +24,28 @@ const DEFAULTS = { wheelFactor: -100, }; +const events = [ + 'contextmenu', + + 'mousedown', + 'mouseup', + 'mousemove', + + 'touchstart', + 'touchend', + 'touchmove', + 'touchcancel', + + 'wheel', +]; + +const methods = [ + 'eventHandler', + + 'tapStart', + 'pressStart', +].concat(events); + export default class OnTap { constructor(settings) { this.settings = Object.assign({}, DEFAULTS, settings); @@ -31,27 +54,16 @@ export default class OnTap { tapStartTime: null, }; - [ - // TODO: don't set up listeners for these two - 'tapStart', - 'pressStart', + methods.forEach(method => this[method] = this[method].bind(this)); + events.forEach(eventName => this.settings.element.addEventListener(eventName, event => this.eventHandler(event, eventName))); + } - 'contextmenu', + eventHandler (event, eventName) { + event.timeStampUTC = Date.now(); - 'mousedown', - 'mouseup', - 'mousemove', + if (this.settings.debug) console.debug(`[${ MODULE }][${ eventName }]`, event); - 'touchstart', - 'touchend', - 'touchmove', - 'touchcancel', - - 'wheel', - ].forEach(method => { - this[method] = this[method].bind(this); - this.settings.element.addEventListener(method, this[method]); - }); + this[eventName](event); } contextmenu(event) { @@ -59,11 +71,9 @@ export default class OnTap { } tapStart(event) { - if (this.settings.debug) console.debug('onTap.tapStart', event); - if (!this.state.tapStartTime) { const {mobile} = event; - this.state.tapStartTime = event.timeStamp; + this.state.tapStartTime = event.timeStampUTC; if (mobile || this.settings.desktopPress) { clearTimeout(this.state.pressTO); @@ -71,7 +81,7 @@ export default class OnTap { this.state.pressTO = setTimeout(() => { this.pressStart({ mobile, - timeStamp: Date.now(), + timeStampUTC: Date.now(), offsetX: this.state.lastX, offsetY: this.state.lastY, }); @@ -83,8 +93,6 @@ export default class OnTap { } mousedown(event) { - if (this.settings.debug) console.debug('onTap.mousedown', event); - Object.assign(event, { mobile: false, }); @@ -103,8 +111,6 @@ export default class OnTap { touchstart(event) { event.preventDefault(); - if (this.settings.debug) console.debug('onTap.touchstart', event); - Object.assign(event, { mobile: true, }); @@ -125,17 +131,13 @@ export default class OnTap { } pressStart(event) { - if (this.settings.debug) console.debug('onTap.pressStart', event); - this.settings.pressStart(event); } mouseup(event) { - if (this.settings.debug) console.debug('onTap.mouseup', event); - Object.assign(event, { mobile: false, - duration: event.timeStamp - this.state.tapStartTime, + duration: event.timeStampUTC - this.state.tapStartTime, }); if (!this.state.moving) { @@ -161,11 +163,9 @@ export default class OnTap { touchend(event) { event.preventDefault(); - if (this.settings.debug) console.debug('onTap.touchend', event); - Object.assign(event, { mobile: true, - duration: event.timeStamp - this.state.tapStartTime, + duration: event.timeStampUTC - this.state.tapStartTime, }); const touches = [...event.touches]; @@ -206,8 +206,6 @@ export default class OnTap { } mousemove(event) { - if (this.settings.debug) console.debug('onTap.mousemove', event); - if (this.state.tapStartTime) { if (!this.state.moving) { if ((Math.abs(event.offsetX - this.state.lastX) > this.settings.moveThreshold) @@ -235,8 +233,6 @@ export default class OnTap { touchmove(event) { event.preventDefault(); - if (this.settings.debug) console.debug('onTap.touchmove', event); - if (this.state.tapStartTime) { const touches = [...event.touches]; @@ -281,8 +277,6 @@ export default class OnTap { } wheel(event) { - if (this.settings.debug) console.debug('onTap.wheel', event); - Object.assign(event, { scaleStep: 1 + (event.deltaY / this.settings.wheelFactor), mobile: false, diff --git a/src/utils.js b/src/utils.js index 506a38a..0694256 100644 --- a/src/utils.js +++ b/src/utils.js @@ -121,3 +121,8 @@ export function toFixed(number, precision = 3, fallback = NaN) { return typeof number === 'number' && !isNaN(number) ? Number(number.toFixed(precision)) : fallback; } +export function getColor ({red, green, blue, alpha}) { + return alpha != null ? `rgba(${ red }, ${ green }, ${ blue }, ${ alpha })` : + `rgb(${ red }, ${ green }, ${ blue })`; +} +