Finite boards (#1)

This commit is contained in:
gavin
2018-07-15 02:54:26 +00:00
committed by Gitea
parent 68f83bfc4b
commit 0545c0a5d9
14 changed files with 497 additions and 356 deletions

View File

@@ -1,4 +1,11 @@
import {extend} from './utils.js';
import {has, toFixed} from './utils.js';
const SETTINGS_DEFAULTS = {
// in pixels
scale: 50,
scaleMin: 10,
scaleMax: 250,
};
export default class Cartographer {
constructor(settings) {
@@ -9,31 +16,22 @@ export default class Cartographer {
'getScale',
'move',
'zoom'
'_checkMove',
'zoom',
].map(method => this[method] = this[method].bind(this));
this.pointyTop = settings.pointyTop;
Object.assign(this, SETTINGS_DEFAULTS, settings);
// in pixels
this.originX = 0;
this.originY = 0;
this.originX = has(this, 'originX') ? this.originX :
this.canvasWidth ? parseInt(this.canvasWidth / 2) :
0;
// in pixels
this.scale = 25;
this.scaleMin = 10;
this.scaleMax = 250;
this.originY = has(this, 'originY') ? this.originY :
this.canvasHeight ? parseInt(this.canvasHeight / 2) :
0;
// in cells
this.width = 0;
this.height = 0;
extend(this, settings);
this.originX = parseInt(this.originX);
this.originY = parseInt(this.originY);
this.width = parseInt(this.width);
this.height = parseInt(this.height);
this._checkScale(this.canvasHeight, this.canvasWidth);
}
getOriginX() {return this.originX;}
@@ -44,13 +42,45 @@ export default class Cartographer {
move(event) {
if (event.deltaX) {
this.originX = Math.floor((this.originX*1000) + (event.deltaX*1000)) / 1000;
this.originX = toFixed(this.originX + event.deltaX);
}
if (event.deltaY) {
this.originY = Math.floor((this.originY*1000) + (event.deltaY*1000)) / 1000;
this.originY = toFixed(this.originY + event.deltaY);
}
this._checkMove(event);
}
_checkMove(event) {
const colWidth = this.horizontalDistance();
const rowHeight = this.verticalDistance();
if (this.width) {
const canvasWidth = event.target.offsetWidth;
const halfBoardWidth = (this.width * colWidth + colWidth) / 2;
this.originX = this.originX > halfBoardWidth ? halfBoardWidth :
(canvasWidth - this.originX) > halfBoardWidth ? canvasWidth - halfBoardWidth :
this.originX;
}
if (this.height) {
const canvasHeight = event.target.offsetHeight;
const halfBoardHeight = (this.height * rowHeight + rowHeight) / 2;
this.originY = this.originY > halfBoardHeight ? halfBoardHeight :
(canvasHeight - this.originY) > halfBoardHeight ? canvasHeight - halfBoardHeight :
this.originY;
}
}
_checkScale(canvasHeight, canvasWidth) {
const heightMin = this.height ? this.calculateVerticalScale(canvasHeight, this.height + 1) : 0;
const widthMin = this.width ? this.calculateHorizontalScale(canvasWidth, this.width + 1) : 0;
this.scaleMin = Math.max(this.scaleMin, heightMin, widthMin);
this.scale = this.scaleMin > this.scale ? this.scaleMin : this.scale;
}
zoom(event) {
@@ -71,7 +101,11 @@ export default class Cartographer {
// zoom to the current mouse location
this.move({
deltaX: (((event.offsetX - this.originX) / scaleOrig) * (scaleOrig - scaleTemp)),
deltaY: (((event.offsetY - this.originY) / scaleOrig) * (scaleOrig - scaleTemp))
deltaY: (((event.offsetY - this.originY) / scaleOrig) * (scaleOrig - scaleTemp)),
target: {
offsetWidth: event.target.offsetWidth,
offsetHeight: event.target.offsetHeight,
},
});
}
}

79
src/cartographerFlatXY.js Normal file
View File

@@ -0,0 +1,79 @@
import Cartographer from './cartographer.js';
import {rangeInclusive, sqrt2} from './utils.js';
import Square from './square.js';
import Point from './point.js';
export default class CartographerFlatXY extends Cartographer {
constructor(settings) {
super(settings);
[
'maxWidth',
'minWidth',
'horizontalDistance',
'verticalDistance',
'calculateHorizontalScale',
'calculateVerticalScale',
'tileToPixel',
'pixelToTile',
'boundingBox',
].map(method => this[method] = this[method].bind(this));
}
maxWidth() {
return this.minWidth() * sqrt2;
}
minWidth() {
return this.scale * 2;
}
horizontalDistance() {
return this.minWidth();
}
verticalDistance() {
return this.minWidth();
}
calculateHorizontalScale(pixels, tiles) {
return pixels / tiles / 2;
}
calculateVerticalScale(pixels, tiles) {
return pixels / tiles / 2;
}
tileToPixel(square) {
const x = square.getX() * this.minWidth();
const y = square.getY() * this.minWidth();
return new Point(x + this.originX, this.originY - y);
}
pixelToTile(point) {
const pixelX = point.getX() - this.originX;
const pixelY = this.originY - point.getY();
const x = pixelX / this.minWidth();
const y = pixelY / this.minWidth();
return new Square(x, y);
}
boundingBox(upperLeftPoint, upperRightPoint, lowerLeftPoint, lowerRightPoint) {
const upperLeftTile = this.pixelToTile(upperLeftPoint);
const lowerRightTile = this.pixelToTile(lowerRightPoint);
const upperRightTile = this.pixelToTile(upperRightPoint);
const columns = rangeInclusive(upperLeftTile.getX(), upperRightTile.getX());
const rows = rangeInclusive(lowerRightTile.getY(), upperLeftTile.getY());
return columns.map(x => rows.map(y => new Square(x, y)));
}
}

View File

@@ -0,0 +1,86 @@
import Cartographer from './cartographer.js';
import {rangeInclusive, sqrt3} from './utils.js';
import Hex from './hex.js';
import Point from './point.js';
export default class CartographerFlatXYZ extends Cartographer {
constructor(settings) {
super(settings);
[
'maxWidth',
'minWidth',
'horizontalDistance',
'verticalDistance',
'calculateHorizontalScale',
'calculateVerticalScale',
'tileToPixel',
'pixelToTile',
'boundingBox',
].map(method => this[method] = this[method].bind(this));
}
maxWidth() {
return this.scale * 2;
}
minWidth() {
return this.scale * sqrt3;
}
horizontalDistance() {
return this.maxWidth() * (3/4);
}
verticalDistance() {
return this.minWidth();
}
calculateHorizontalScale(pixels, tiles) {
return pixels / (tiles * (3/4)) / 2;
}
calculateVerticalScale(pixels, tiles) {
return pixels / tiles / sqrt3;
}
tileToPixel(hex) {
const pixelX = this.scale * 3/2 * hex.getQ();
const pixelY = this.scale * sqrt3 * (hex.getR() + (hex.getQ() / 2));
return new Point(pixelX + this.originX, pixelY + this.originY);
}
pixelToTile(point) {
const pixelX = point.getX() - this.originX;
const pixelY = point.getY() - this.originY;
const q = (pixelX * (2 / 3)) / this.scale;
const r = ((pixelY * (sqrt3 / 3)) - (pixelX / 3)) / this.scale;
return new Hex(q, r);
}
boundingBox(upperLeftPoint, upperRightPoint, lowerLeftPoint, lowerRightPoint) {
const upperLeftTile = this.pixelToTile(upperLeftPoint);
const lowerLeftTile = this.pixelToTile(lowerLeftPoint);
const lowerRightTile = this.pixelToTile(lowerRightPoint);
const upperRightTile = this.pixelToTile(upperRightPoint);
const columns = rangeInclusive(upperLeftTile.getQ() - 1, upperRightTile.getQ() + 1);
const height = lowerRightTile.getR() - upperRightTile.getR();
return columns.map((q, index) => {
const top = upperLeftTile.getR() - Math.floor(index / 2);
const bottom = top + height;
const rows = rangeInclusive(top, bottom + 1);
return rows.map(r => new Hex(q, r));
});
}
}

105
src/cartographerPointyXY.js Normal file
View File

@@ -0,0 +1,105 @@
import Cartographer from './cartographer.js';
import {rangeInclusive, sqrt2} from './utils.js';
import Square from './square.js';
import Point from './point.js';
export default class CartographerPointyXY extends Cartographer {
constructor(settings) {
super(settings);
[
'maxWidth',
'minWidth',
'horizontalDistance',
'verticalDistance',
'calculateHorizontalScale',
'calculateVerticalScale',
'tileToPixel',
'pixelToTile',
'boundingBox',
].map(method => this[method] = this[method].bind(this));
}
maxWidth() {
return this.minWidth() * sqrt2;
}
minWidth() {
return this.scale * 2;
}
horizontalDistance() {
return this.maxWidth() / 2;
}
verticalDistance() {
return this.maxWidth() / 2;
}
calculateHorizontalScale(pixels, tiles) {
return pixels / sqrt2 / tiles;
}
calculateVerticalScale(pixels, tiles) {
return pixels / sqrt2 / tiles;
}
tileToPixel(square) {
const x = square.getX();
const y = square.getY();
// (above/below axis) * (distance from axis) / (size)
let pixelX = (x < y ? -1 : 1) * (Math.abs(y - x) / sqrt2) * this.minWidth();
let pixelY = (-x < y ? 1 : -1) * (Math.abs(x + y) / sqrt2) * this.minWidth();
return new Point(pixelX + this.originX, this.originY - pixelY);
}
pixelToTile(point) {
const pixelX = point.getX() - this.originX;
const pixelY = this.originY - point.getY();
// (above/below axis) * (distance from axis) / (size)
const x = (-pixelX < pixelY ? 1 : -1) * (Math.abs(pixelX + pixelY) / sqrt2) / this.minWidth();
const y = (pixelX < pixelY ? 1 : -1) * (Math.abs(pixelY - pixelX) / sqrt2) / this.minWidth();
return new Square(x, y);
}
boundingBox(upperLeftPoint, upperRightPoint, lowerLeftPoint, lowerRightPoint) {
const upperLeftTile = this.pixelToTile(upperLeftPoint);
const lowerRightTile = this.pixelToTile(lowerRightPoint);
const upperRightTile = this.pixelToTile(upperRightPoint);
const lowerLeftTile = this.pixelToTile(lowerLeftPoint);
const columns = rangeInclusive(lowerLeftTile.getX(), upperRightTile.getX());
const upperLeftIntercept = upperLeftTile.getY() - upperLeftTile.getX();
const upperRightIntercept = upperLeftTile.getY() + upperLeftTile.getX();
const lowerLeftIntercept = lowerRightTile.getY() - lowerRightTile.getX();
const lowerRightIntercept = lowerRightTile.getY() + lowerRightTile.getX();
const aboutHalf = Math.floor(columns.length / 2);
const midway = columns.length % 2 ? columns[aboutHalf] :
(columns[aboutHalf - 1] + columns[aboutHalf]) / 2;
return columns.map(x => {
let top = x < midway ? upperLeftIntercept + x : upperRightIntercept - x;
let bottom = x < midway ? lowerRightIntercept - x : lowerLeftIntercept + x;
bottom = Math.min(bottom, top);
top = Math.max(bottom, top);
// push out by 1 on either end to account for interlocking tiles
const rows = rangeInclusive(bottom - 1, top + 1);
return rows.map(y => new Square(x, y));
});
}
}

View File

@@ -0,0 +1,86 @@
import Cartographer from './cartographer.js';
import {rangeInclusive, sqrt3} from './utils.js';
import Hex from './hex.js';
import Point from './point.js';
export default class CartographerPointyXYZ extends Cartographer {
constructor(settings) {
super(settings);
[
'maxWidth',
'minWidth',
'horizontalDistance',
'verticalDistance',
'calculateHorizontalScale',
'calculateVerticalScale',
'tileToPixel',
'pixelToTile',
'boundingBox',
].map(method => this[method] = this[method].bind(this));
}
maxWidth() {
return this.scale * 2;
}
minWidth() {
return this.scale * sqrt3;
}
horizontalDistance() {
return this.minWidth();
}
verticalDistance() {
return this.maxWidth() * (3/4);
}
calculateHorizontalScale(pixels, tiles) {
return pixels / tiles / sqrt3;
}
calculateVerticalScale(pixels, tiles) {
return pixels / (tiles * (3/4)) / 2;
}
tileToPixel(hex) {
const pixelX = this.scale * sqrt3 * (hex.getQ() + (hex.getR() / 2));
const pixelY = this.scale * 3/2 * hex.getR();
return new Point(pixelX + this.originX, pixelY + this.originY);
}
pixelToTile(point) {
const pixelX = point.getX() - this.originX;
const pixelY = point.getY() - this.originY;
const q = ((pixelX * (sqrt3 / 3)) - (pixelY / 3)) / this.scale;
const r = (pixelY * (2 / 3)) / this.scale;
return new Hex(q, r);
}
boundingBox(upperLeftPoint, upperRightPoint, lowerLeftPoint, lowerRightPoint) {
const upperLeftTile = this.pixelToTile(upperLeftPoint);
const lowerLeftTile = this.pixelToTile(lowerLeftPoint);
const lowerRightTile = this.pixelToTile(lowerRightPoint);
const upperRightTile = this.pixelToTile(upperRightPoint);
const rows = rangeInclusive(upperLeftTile.getR() -1 , lowerLeftTile.getR() + 1);
const width = upperRightTile.getQ() - upperLeftTile.getQ();
return rows.map((r, index) => {
const left = upperLeftTile.getQ() - Math.floor(index / 2);
const right = left + width;
const columns = rangeInclusive(left, right + 1);
return columns.map(q => new Hex(q, r));
});
}
}

View File

@@ -1,132 +0,0 @@
import Cartographer from './cartographer.js';
import {rangeInclusive, sqrt2} from './utils.js';
import Square from './square.js';
import Point from './point.js';
export default class CartographerXY extends Cartographer {
constructor(settings) {
super(settings);
[
'maxWidth',
'minWidth',
'maxDistance',
'minDistance',
'getCellWidth',
'getCellHeight',
'getHorzDistance',
'getVertDistance',
'tileToPixel',
'pixelToTile',
'boundingBox',
].map(method => this[method] = this[method].bind(this));
}
maxWidth() {
return this.minWidth() * sqrt2;
}
minWidth() {
return this.scale * 2;
}
maxDistance() {
return this.maxWidth();
}
minDistance() {
return this.minWidth();
}
getCellWidth() {return this.pointyTop ? this.maxWidth() : this.minWidth();}
getCellHeight() {return this.pointyTop ? this.maxWidth() : this.minWidth();}
getHorzDistance() {return this.pointyTop ? this.maxDistance() : this.minDistance();}
getVertDistance() {return this.pointyTop ? this.maxDistance() : this.minDistance();}
tileToPixel(square) {
const scale = this.scale;
// (above/below axis) * (distance from axis) / (size)
const pointyDistanceX = (x, y) => (x < y ? -1 : 1) * (Math.abs(y - x) / sqrt2) * this.minWidth();
const pointyDistanceY = (x, y) => (-x < y ? 1 : -1) * (Math.abs(x + y) / sqrt2) * this.minWidth();
const flatDistance = a => this.minWidth() * a;
const x = square.getX();
const y = square.getY();
let pixelX = this.pointyTop ? pointyDistanceX(x, y) : flatDistance(x);
let pixelY = this.pointyTop ? pointyDistanceY(x, y) : flatDistance(y);
pixelX += this.originX;
pixelY = this.originY - pixelY;;
return new Point(pixelX, pixelY);
}
pixelToTile(point) {
let scale = this.scale;
// (above/below axis) * (distance from axis) / (size)
const pointyDistanceX = (x, y) => (-x < y ? 1 : -1) * (Math.abs(x + y) / sqrt2) / this.minWidth();
const pointyDistanceY = (x, y) => (x < y ? 1 : -1) * (Math.abs(y - x) / sqrt2) / this.minWidth();
const flatDistance = a => a / this.minWidth();
let pixelX = point.getX() - this.originX;
let pixelY = this.originY - point.getY();
let x = this.pointyTop ? pointyDistanceX(pixelX, pixelY) : flatDistance(pixelX);
let y = this.pointyTop ? pointyDistanceY(pixelX, pixelY) : flatDistance(pixelY);
return new Square(x, y);
}
boundingBox(upperLeftPoint, upperRightPoint, lowerLeftPoint, lowerRightPoint) {
const upperLeftTile = this.pixelToTile(upperLeftPoint);
const lowerRightTile = this.pixelToTile(lowerRightPoint);
const upperRightTile = this.pixelToTile(upperRightPoint);
if (this.pointyTop) {
const lowerLeftTile = this.pixelToTile(lowerLeftPoint);
const columns = rangeInclusive(lowerLeftTile.getX(), upperRightTile.getX());
const upperLeftIntercept = upperLeftTile.getY() - upperLeftTile.getX();
const upperRightIntercept = upperLeftTile.getY() + upperLeftTile.getX();
const lowerLeftIntercept = lowerRightTile.getY() - lowerRightTile.getX();
const lowerRightIntercept = lowerRightTile.getY() + lowerRightTile.getX();
const aboutHalf = Math.floor(columns.length / 2);
const midway = columns.length % 2 ? columns[aboutHalf] :
(columns[aboutHalf - 1] + columns[aboutHalf]) / 2;
return columns.map(x => {
let top = x < midway ? upperLeftIntercept + x : upperRightIntercept - x;
let bottom = x < midway ? lowerRightIntercept - x : lowerLeftIntercept + x;
bottom = Math.min(bottom, top);
top = Math.max(bottom, top);
// push out by 1 on either end to account for interlocking tiles
const rows = rangeInclusive(bottom - 1, top + 1);
return rows.map(y => new Square(x, y));
});
}
else {
const columns = rangeInclusive(upperLeftTile.getX(), upperRightTile.getX());
const rows = rangeInclusive(lowerRightTile.getY(), upperLeftTile.getY());
return columns.map(x => rows.map(y => new Square(x, y)));
}
}
}

View File

@@ -1,124 +0,0 @@
import Cartographer from './cartographer.js';
import {extend, rangeInclusive, sqrt3} from './utils.js';
import Hex from './hex.js';
import Point from './point.js';
export default class CartographerXYZ extends Cartographer {
constructor(settings) {
super(settings);
[
'maxWidth',
'minWidth',
'maxDistance',
'minDistance',
'getCellWidth',
'getCellHeight',
'getHorzDistance',
'getVertDistance',
'tileToPixel',
'pixelToTile',
'boundingBox',
].map(method => this[method] = this[method].bind(this));
}
maxWidth() {
return this.scale * 2;
}
minWidth() {
return this.maxWidth() * sqrt3;
}
maxDistance() {
return this.maxWidth() * (3/4);
}
minDistance() {
return this.minWidth();
}
getCellWidth() {return this.pointyTop ? this.minWidth() : this.maxWidth();}
getCellHeight() {return this.pointyTop ? this.maxWidth() : this.minWidth();}
getHorzDistance() {return this.pointyTop ? this.minDistance() : this.maxDistance();}
getVertDistance() {return this.pointyTop ? this.maxDistance() : this.minDistance();}
tileToPixel(hex) {
let scale = this.scale;
function minWidth(a, b) {
return scale * sqrt3 * (a + (b / 2))
};
function maxWidth(a) {
return scale * 3/2 * a
};
let pixelX = this.pointyTop ? minWidth(hex.getQ(), hex.getR()) : maxWidth(hex.getQ());
let pixelY = this.pointyTop ? maxWidth(hex.getR()) : minWidth(hex.getR(), hex.getQ());
pixelX += this.originX;
pixelY += this.originY;
return new Point(pixelX, pixelY);
}
pixelToTile(point) {
let scale = this.scale;
function radiusLong(a, b) {
return ((a * (sqrt3 / 3)) - (b / 3)) / scale;
};
function radiusShort(a) {
return (a * (2 / 3)) / scale;
};
let pixelX = point.getX() - this.originX;
let pixelY = point.getY() - this.originY;
let q = this.pointyTop ? radiusLong(pixelX, pixelY) : radiusShort(pixelX);
let r = this.pointyTop ? radiusShort(pixelY) : radiusLong(pixelY, pixelX);
return new Hex(q, r);
}
boundingBox(upperLeftPoint, upperRightPoint, lowerLeftPoint, lowerRightPoint) {
const upperLeftTile = this.pixelToTile(upperLeftPoint);
const lowerLeftTile = this.pixelToTile(lowerLeftPoint);
const lowerRightTile = this.pixelToTile(lowerRightPoint);
const upperRightTile = this.pixelToTile(upperRightPoint);
if (this.pointyTop) {
const rows = rangeInclusive(upperLeftTile.getR() -1 , lowerLeftTile.getR() + 1);
const width = upperRightTile.getQ() - upperLeftTile.getQ();
return rows.map((r, index) => {
const left = upperLeftTile.getQ() - Math.floor(index / 2);
const right = left + width;
const columns = rangeInclusive(left, right + 1);
return columns.map(q => new Hex(q, r));
});
}
else {
const columns = rangeInclusive(upperLeftTile.getQ() - 1, upperRightTile.getQ() + 1);
const height = lowerRightTile.getR() - upperRightTile.getR();
return columns.map((q, index) => {
const top = upperLeftTile.getR() - Math.floor(index / 2);
const bottom = top + height;
const rows = rangeInclusive(top, bottom + 1);
return rows.map(r => new Hex(q, r));
});
}
}
}

View File

@@ -1,5 +1,3 @@
import {extend} from './utils.js';
import {random} from './utils.js';
export default class Cell {
@@ -19,7 +17,7 @@ export default class Cell {
this.alpha = 0.5;
this.created = Date.now();
extend(this, settings);
Object.assign(this, settings);
}
getColor() {

19
src/consts.js Normal file
View File

@@ -0,0 +1,19 @@
export const HEX = 'hex';
export const CIRCLE = 'circle';
export const SQUARE = 'square';
export const TILE_STYLES = {HEX, CIRCLE, SQUARE};
export const BOARD_STYLES = {
HEX,
SQUARE,
};
export const FLAT = 'flat';
export const POINTY = 'pointy';
export const TILE_ORIENTATIONS = {
FLAT,
POINTY,
};

View File

@@ -1,3 +1,4 @@
import {POINTY} from './consts.js';
export default class DrawHexagon {
constructor(settings) {
@@ -33,8 +34,8 @@ export default class DrawHexagon {
outline(context, scale, x, y, cell) {
scale = scale * cell.scale;
let hexCornerX = cell.pointyTop ? this.pointyTopCornerX : this.flatTopCornerX;
let hexCornerY = cell.pointyTop ? this.pointyTopCornerY : this.flatTopCornerY;
let hexCornerX = cell.orientation === POINTY ? this.pointyTopCornerX : this.flatTopCornerX;
let hexCornerY = cell.orientation === POINTY ? this.pointyTopCornerY : this.flatTopCornerY;
context.beginPath();
context.moveTo(x + scale * hexCornerX[0], y + scale * hexCornerY[0]);
@@ -52,8 +53,8 @@ export default class DrawHexagon {
filled(context, scale, x, y, cell) {
scale = scale * cell.scale;
let hexCornerX = cell.pointyTop ? this.pointyTopCornerX : this.flatTopCornerX;
let hexCornerY = cell.pointyTop ? this.pointyTopCornerY : this.flatTopCornerY;
let hexCornerX = cell.orientation === POINTY ? this.pointyTopCornerX : this.flatTopCornerX;
let hexCornerY = cell.orientation === POINTY ? this.pointyTopCornerY : this.flatTopCornerY;
context.beginPath();
context.moveTo(x + scale * hexCornerX[0], y + scale * hexCornerY[0]);

View File

@@ -1,5 +1,5 @@
import {sqrt2} from './utils.js';
import {POINTY} from './consts.js';
export default class DrawSquare {
constructor(settings) {
@@ -11,8 +11,8 @@ export default class DrawSquare {
filled(context, scale, x, y, cell) {
scale = scale * cell.scale;
let squareCornerX = cell.pointyTop ? this.diamondX : this.squareX;
let squareCornerY = cell.pointyTop ? this.diamondY : this.squareY;
let squareCornerX = cell.orientation === POINTY ? this.diamondX : this.squareX;
let squareCornerY = cell.orientation === POINTY ? this.diamondY : this.squareY;
context.beginPath();
context.moveTo(x + scale * squareCornerX[0], y + scale * squareCornerY[0]);
@@ -26,8 +26,8 @@ export default class DrawSquare {
outline(context, scale, x, y, cell) {
scale = scale * cell.scale;
let squareCornerX = cell.pointyTop ? this.diamondX : this.squareX;
let squareCornerY = cell.pointyTop ? this.diamondY : this.squareY;
let squareCornerX = cell.orientation === POINTY ? this.diamondX : this.squareX;
let squareCornerY = cell.orientation === POINTY ? this.diamondY : this.squareY;
context.beginPath();
context.moveTo(x + scale * squareCornerX[0], y + scale * squareCornerY[0]);

View File

@@ -18,7 +18,7 @@ class Demo {
tile: Tessellate.TILE_STYLES.HEX,
tap: this.onTap,
draw: this.draw,
pointyTop: false, //utils.random(1) ? true : false,
orientation: Tessellate.TILE_ORIENTATIONS.FLAT,
}, queryStringObj));
this.circle = new DrawCircle();
@@ -40,7 +40,7 @@ class Demo {
x: tap.point.x,
y: tap.point.y,
scale,
pointyTop: utils.random(1) ? true : false,
orientation: utils.random(1) ? Tessellate.TILE_ORIENTATIONS.FLAT : Tessellate.TILE_ORIENTATIONS.POINTY,
red: utils.random(255),
green: utils.random(255),
blue: utils.random(255),

View File

@@ -14,14 +14,18 @@ export {DrawCircle, DrawHexagon, DrawSquare};
import Cell from './cell.js';
export {Cell};
import CartographerXY from './cartographerXY.js';
import CartographerXYZ from './cartographerXYZ.js';
import CartographerFlatXY from './cartographerFlatXY.js';
import CartographerPointyXY from './cartographerPointyXY.js';
import CartographerFlatXYZ from './cartographerFlatXYZ.js';
import CartographerPointyXYZ from './cartographerPointyXYZ.js';
const HEX = 'hex';
const CIRCLE = 'circle';
const SQUARE = 'square';
const TILE_STYLES = {HEX, CIRCLE, SQUARE};
import {
HEX, CIRCLE, SQUARE,
TILE_STYLES,
BOARD_STYLES,
FLAT, POINTY,
TILE_ORIENTATIONS,
} from './consts.js';
const TILES = {
[HEX]: new DrawHexagon(),
@@ -34,18 +38,34 @@ const DEFAULTS = {
board: HEX,
tap: utils.noop,
draw: utils.noop,
pointyTop: false,
orientation: FLAT,
};
function selectCartographer(board, orientation) {
switch (board) {
case HEX:
switch (orientation) {
case FLAT: return CartographerFlatXYZ;
case POINTY: return CartographerPointyXYZ;
}
case SQUARE:
switch (orientation) {
case FLAT: return CartographerFlatXY;
case POINTY: return CartographerPointyXY;
}
}
}
export default class Tessellate {
static get TILES () {return TILES}
static get TILE_STYLES () {return TILE_STYLES}
static get BOARD_STYLES () {return {HEX, SQUARE}}
static get TILES() {return TILES}
static get TILE_STYLES() {return TILE_STYLES}
static get BOARD_STYLES() {return BOARD_STYLES}
static get TILE_ORIENTATIONS() {return TILE_ORIENTATIONS}
constructor(settings) {
['seedTiles', 'tap', 'draw', 'drawMap', 'move', 'zoom'].map(method => {this[method] = this[method].bind(this)});
this.settings = utils.extend(DEFAULTS, settings);
this.settings = Object.assign(DEFAULTS, settings);
this.settings.element = this.settings.element instanceof HTMLElement ? this.settings.element :
document.querySelector(this.settings.element);
@@ -64,61 +84,33 @@ export default class Tessellate {
this.map = [];
this.seedTiles();
const boardSettings = {
pointyTop: this.settings.pointyTop,
originX: this.sketch.getContext().canvas.width / 2,
originY: this.sketch.getContext().canvas.height / 2
};
const cartographer = selectCartographer(this.settings.board, this.settings.orientation);
this.cartographer = new cartographer({
height: this.settings.height,
width: this.settings.width,
scale: this.settings.scale,
this.cartographer = this.settings.board === HEX ? new CartographerXYZ(boardSettings) : new CartographerXY(boardSettings);
canvasWidth: this.sketch.getContext().canvas.width,
canvasHeight: this.sketch.getContext().canvas.height,
originX: this.settings.originX || this.sketch.getContext().canvas.width / 2,
originY: this.settings.originY || this.sketch.getContext().canvas.height / 2,
});
}
seedTiles() {
this.map[0] = [];
// this.map[1] = [];
// this.map[-1] = [];
// this.map[-5] = [];
this.map[0][0] = new Cell({
x: 0,
y: 0,
pointyTop: this.settings.pointyTop,
orientation: this.settings.orientation,
red: 0,
green: 0,
blue: 0,
alpha: 75/100,
scale: 9/10,
});
// this.map[1][1] = new Cell({
// x: 1,
// y: 1,
// pointyTop: this.settings.pointyTop,
// red: 0,
// green: 0,
// blue: 255,
// alpha: 90/100,
// scale: 9/10,
// });
// this.map[-1][-1] = new Cell({
// x: -1,
// y: -1,
// pointyTop: this.settings.pointyTop,
// red: 255,
// green: 0,
// blue: 0,
// alpha: 90/100,
// scale: 9/10,
// });
// this.map[-5][5] = new Cell({
// x: -5,
// y: 5,
// pointyTop: this.settings.pointyTop,
// red: 0,
// green: 255,
// blue: 0,
// alpha: 90/100,
// scale: 9/10,
// });
}
tap(event) {
@@ -161,7 +153,7 @@ export default class Tessellate {
this.map[tile.getX()][tile.getY()] = new Cell({
x: tile.getX(),
y: tile.getY(),
pointyTop: this.settings.pointyTop,
orientation: this.settings.orientation,
red: utils.random(64, 192),
green: utils.random(64, 192),
blue: utils.random(64, 192),

View File

@@ -33,14 +33,8 @@ export function clone(obj) {
return JSON.parse(JSON.stringify(obj));
}
export function extend(obj, ...sources) {
sources.forEach(src => {
for (let key in src) {
if (src.hasOwnProperty(key)) obj[key] = src[key];
}
});
return obj;
export function has(obj, prop) {
return obj && obj.hasOwnProperty(prop);
}
export function hypotenuse(a, b) {
@@ -115,4 +109,7 @@ export function parseString (str) {
str;
}
export function toFixed(number, precision = 3, fallback = NaN) {
return typeof number === 'number' && !isNaN(number) ? Number(number.toFixed(precision)) : fallback;
}