drawing shapes on a canvas when the user clicks
This commit is contained in:
9
.gitignore
vendored
Normal file
9
.gitignore
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
*~
|
||||
*.swp
|
||||
*.pyc
|
||||
*.pyo
|
||||
.DS_Store
|
||||
|
||||
node_modules/*
|
||||
hexmine
|
||||
|
||||
17
package.json
Normal file
17
package.json
Normal file
@@ -0,0 +1,17 @@
|
||||
{
|
||||
"name": "tessellate",
|
||||
"version": "0.0.0",
|
||||
"description": "",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"author": "",
|
||||
"license": "BSD-2-Clause",
|
||||
"devDependencies": {
|
||||
"webpack": "~1.12.13",
|
||||
"babel-loader": "~6.2.2",
|
||||
"babel-core": "~6.5.2",
|
||||
"babel-preset-es2015": "~6.5.0"
|
||||
}
|
||||
}
|
||||
278
public/css/main.css
Normal file
278
public/css/main.css
Normal file
@@ -0,0 +1,278 @@
|
||||
/*! HTML5 Boilerplate v5.2.0 | MIT License | https://html5boilerplate.com/ */
|
||||
|
||||
/*
|
||||
* What follows is the result of much research on cross-browser styling.
|
||||
* Credit left inline and big thanks to Nicolas Gallagher, Jonathan Neal,
|
||||
* Kroc Camen, and the H5BP dev community and team.
|
||||
*/
|
||||
|
||||
/* ==========================================================================
|
||||
Base styles: opinionated defaults
|
||||
========================================================================== */
|
||||
|
||||
html {
|
||||
color: #222;
|
||||
font-size: 1em;
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
/*
|
||||
* Remove text-shadow in selection highlight:
|
||||
* https://twitter.com/miketaylr/status/12228805301
|
||||
*
|
||||
* These selection rule sets have to be separate.
|
||||
* Customize the background color to match your design.
|
||||
*/
|
||||
|
||||
::-moz-selection {
|
||||
background: #b3d4fc;
|
||||
text-shadow: none;
|
||||
}
|
||||
|
||||
::selection {
|
||||
background: #b3d4fc;
|
||||
text-shadow: none;
|
||||
}
|
||||
|
||||
/*
|
||||
* A better looking default horizontal rule
|
||||
*/
|
||||
|
||||
hr {
|
||||
display: block;
|
||||
height: 1px;
|
||||
border: 0;
|
||||
border-top: 1px solid #ccc;
|
||||
margin: 1em 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Remove the gap between audio, canvas, iframes,
|
||||
* images, videos and the bottom of their containers:
|
||||
* https://github.com/h5bp/html5-boilerplate/issues/440
|
||||
*/
|
||||
|
||||
audio,
|
||||
canvas,
|
||||
iframe,
|
||||
img,
|
||||
svg,
|
||||
video {
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
/*
|
||||
* Remove default fieldset styles.
|
||||
*/
|
||||
|
||||
fieldset {
|
||||
border: 0;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Allow only vertical resizing of textareas.
|
||||
*/
|
||||
|
||||
textarea {
|
||||
resize: vertical;
|
||||
}
|
||||
|
||||
/* ==========================================================================
|
||||
Browser Upgrade Prompt
|
||||
========================================================================== */
|
||||
|
||||
.browserupgrade {
|
||||
margin: 0.2em 0;
|
||||
background: #ccc;
|
||||
color: #000;
|
||||
padding: 0.2em 0;
|
||||
}
|
||||
|
||||
/* ==========================================================================
|
||||
Author's custom styles
|
||||
========================================================================== */
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
#container {
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
/* ==========================================================================
|
||||
Helper classes
|
||||
========================================================================== */
|
||||
|
||||
/*
|
||||
* Hide visually and from screen readers:
|
||||
*/
|
||||
|
||||
.hidden {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
/*
|
||||
* Hide only visually, but have it available for screen readers:
|
||||
* http://snook.ca/archives/html_and_css/hiding-content-for-accessibility
|
||||
*/
|
||||
|
||||
.visuallyhidden {
|
||||
border: 0;
|
||||
clip: rect(0 0 0 0);
|
||||
height: 1px;
|
||||
margin: -1px;
|
||||
overflow: hidden;
|
||||
padding: 0;
|
||||
position: absolute;
|
||||
width: 1px;
|
||||
}
|
||||
|
||||
/*
|
||||
* Extends the .visuallyhidden class to allow the element
|
||||
* to be focusable when navigated to via the keyboard:
|
||||
* https://www.drupal.org/node/897638
|
||||
*/
|
||||
|
||||
.visuallyhidden.focusable:active,
|
||||
.visuallyhidden.focusable:focus {
|
||||
clip: auto;
|
||||
height: auto;
|
||||
margin: 0;
|
||||
overflow: visible;
|
||||
position: static;
|
||||
width: auto;
|
||||
}
|
||||
|
||||
/*
|
||||
* Hide visually and from screen readers, but maintain layout
|
||||
*/
|
||||
|
||||
.invisible {
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
/*
|
||||
* Clearfix: contain floats
|
||||
*
|
||||
* For modern browsers
|
||||
* 1. The space content is one way to avoid an Opera bug when the
|
||||
* `contenteditable` attribute is included anywhere else in the document.
|
||||
* Otherwise it causes space to appear at the top and bottom of elements
|
||||
* that receive the `clearfix` class.
|
||||
* 2. The use of `table` rather than `block` is only necessary if using
|
||||
* `:before` to contain the top-margins of child elements.
|
||||
*/
|
||||
|
||||
.clearfix:before,
|
||||
.clearfix:after {
|
||||
content: " "; /* 1 */
|
||||
display: table; /* 2 */
|
||||
}
|
||||
|
||||
.clearfix:after {
|
||||
clear: both;
|
||||
}
|
||||
|
||||
/* ==========================================================================
|
||||
EXAMPLE Media Queries for Responsive Design.
|
||||
These examples override the primary ('mobile first') styles.
|
||||
Modify as content requires.
|
||||
========================================================================== */
|
||||
|
||||
@media only screen and (min-width: 35em) {
|
||||
/* Style adjustments for viewports that meet the condition */
|
||||
}
|
||||
|
||||
@media print,
|
||||
(-webkit-min-device-pixel-ratio: 1.25),
|
||||
(min-resolution: 1.25dppx),
|
||||
(min-resolution: 120dpi) {
|
||||
/* Style adjustments for high resolution devices */
|
||||
}
|
||||
|
||||
/* ==========================================================================
|
||||
Print styles.
|
||||
Inlined to avoid the additional HTTP request:
|
||||
http://www.phpied.com/delay-loading-your-print-css/
|
||||
========================================================================== */
|
||||
|
||||
@media print {
|
||||
*,
|
||||
*:before,
|
||||
*:after {
|
||||
background: transparent !important;
|
||||
color: #000 !important; /* Black prints faster:
|
||||
http://www.sanbeiji.com/archives/953 */
|
||||
box-shadow: none !important;
|
||||
text-shadow: none !important;
|
||||
}
|
||||
|
||||
a,
|
||||
a:visited {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
a[href]:after {
|
||||
content: " (" attr(href) ")";
|
||||
}
|
||||
|
||||
abbr[title]:after {
|
||||
content: " (" attr(title) ")";
|
||||
}
|
||||
|
||||
/*
|
||||
* Don't show links that are fragment identifiers,
|
||||
* or use the `javascript:` pseudo protocol
|
||||
*/
|
||||
|
||||
a[href^="#"]:after,
|
||||
a[href^="javascript:"]:after {
|
||||
content: "";
|
||||
}
|
||||
|
||||
pre,
|
||||
blockquote {
|
||||
border: 1px solid #999;
|
||||
page-break-inside: avoid;
|
||||
}
|
||||
|
||||
/*
|
||||
* Printing Tables:
|
||||
* http://css-discuss.incutio.com/wiki/Printing_Tables
|
||||
*/
|
||||
|
||||
thead {
|
||||
display: table-header-group;
|
||||
}
|
||||
|
||||
tr,
|
||||
img {
|
||||
page-break-inside: avoid;
|
||||
}
|
||||
|
||||
img {
|
||||
max-width: 100% !important;
|
||||
}
|
||||
|
||||
p,
|
||||
h2,
|
||||
h3 {
|
||||
orphans: 3;
|
||||
widows: 3;
|
||||
}
|
||||
|
||||
h2,
|
||||
h3 {
|
||||
page-break-after: avoid;
|
||||
}
|
||||
}
|
||||
14
public/index.html
Normal file
14
public/index.html
Normal file
@@ -0,0 +1,14 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="content-type" content="text/html; charset=utf-8">
|
||||
|
||||
<title>Tessellate</title>
|
||||
<link rel="stylesheet" href="css/main.css">
|
||||
</head>
|
||||
<body>
|
||||
<div id="container" style="width: 100vw; height: 100vh;"></div>
|
||||
|
||||
<script src="js/main.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
788
public/js/main.js
Normal file
788
public/js/main.js
Normal file
File diff suppressed because one or more lines are too long
123
src/hex.js
Normal file
123
src/hex.js
Normal file
@@ -0,0 +1,123 @@
|
||||
|
||||
import Point from './point.js';
|
||||
|
||||
function computeY(x, z) {
|
||||
return -x - z;
|
||||
}
|
||||
|
||||
// convert real numbers to integers:
|
||||
// round off coords
|
||||
// throw out whichever one changed the most
|
||||
// re-establish "x + y + z = 0"
|
||||
function roundOff(x, y, z) {
|
||||
let rX = Math.round(x);
|
||||
let rY = Math.round(y);
|
||||
let rZ = Math.round(z);
|
||||
|
||||
let xDiff = Math.abs(rX - x);
|
||||
let yDiff = Math.abs(rY - y);
|
||||
let zDiff = Math.abs(rZ - z);
|
||||
|
||||
if ((xDiff > yDiff) && (xDiff > zDiff)) {
|
||||
rX = -rY-rZ;
|
||||
}
|
||||
else if (yDiff > zDiff) {
|
||||
rY = -rX-rZ;
|
||||
}
|
||||
else {
|
||||
rZ = -rX-rY;
|
||||
}
|
||||
|
||||
x = rX === -0 ? 0 : rX;
|
||||
y = rY === -0 ? 0 : rY;
|
||||
z = rZ === -0 ? 0 : rZ;
|
||||
|
||||
return {x, y, z};
|
||||
}
|
||||
|
||||
export default class Hex extends Point {
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
if (arguments.length === 2) { // hex = Hex(q, r);
|
||||
this.x = arguments[0];
|
||||
this.z = arguments[1];
|
||||
this.y = computeY(this.x, this.z);
|
||||
}
|
||||
else if (arguments.length === 3) { // hex = Hex(x, y, z);
|
||||
this.x = arguments[0];
|
||||
this.y = arguments[1];
|
||||
this.z = arguments[2];
|
||||
}
|
||||
|
||||
roundOff(this.x, this.y, this.z);
|
||||
}
|
||||
|
||||
return {
|
||||
getX: function() {return this.x;},
|
||||
getY: function() {return this.y;},
|
||||
getZ: function() {return this.z;},
|
||||
|
||||
setX: function(newX) {this.x = newX; return this;},
|
||||
setY: function(newY) {this.y = newY; return this;},
|
||||
setZ: function(newZ) {this.z = newZ; return this;},
|
||||
|
||||
moveX: function(byX) {this.x += byX; return this;},
|
||||
moveY: function(byY) {this.y += byY; return this;},
|
||||
moveZ: function(byZ) {this.z += byZ; return this;},
|
||||
|
||||
getQ: function() {return this.x;},
|
||||
getR: function() {return this.z;},
|
||||
|
||||
setQ: function(newQ) {
|
||||
this.x = newQ;
|
||||
this.y = computeY(this.x, this.z);
|
||||
return this;
|
||||
},
|
||||
setR: function(newR) {
|
||||
this.z = newR;
|
||||
this.y = computeY(this.x, this.z);
|
||||
return this;
|
||||
},
|
||||
|
||||
moveQ: function(byQ) {
|
||||
this.x += byQ;
|
||||
this.y = computeY(this.x, this.z);
|
||||
return this;
|
||||
},
|
||||
moveR: function(byR) {
|
||||
this.z += byR;
|
||||
this.y = computeY(this.x, this.z);
|
||||
return this;
|
||||
},
|
||||
|
||||
getHex: function() { return {x: this.x, y: this.y, z: this.z}; },
|
||||
setHex: function(newHex) {
|
||||
this.x = newHex.x;
|
||||
this.y = newHex.y;
|
||||
this.z = newHex.z;
|
||||
return this;
|
||||
},
|
||||
moveHex: function(byHex) {
|
||||
this.x += byHex.x;
|
||||
this.y += byHex.y;
|
||||
this.z += byHex.z;
|
||||
return this;
|
||||
},
|
||||
|
||||
getAxial: function() {return {x: this.x, z: this.z};},
|
||||
setAxial: function(newAxial) {
|
||||
this.x = newAxial.q;
|
||||
this.z = newAxial.r;
|
||||
this.y = computeY(this.x, this.y);
|
||||
return this;
|
||||
},
|
||||
moveAxial: function(byAxial) {
|
||||
this.x += byAxial.q;
|
||||
this.z += byAxial.r;
|
||||
this.y = computeY(this.x, this.z);
|
||||
return this;
|
||||
}
|
||||
};
|
||||
};
|
||||
7
src/main.js
Normal file
7
src/main.js
Normal file
@@ -0,0 +1,7 @@
|
||||
|
||||
import Tessellate from './tessellate.js';
|
||||
|
||||
var tessellate = new Tessellate({
|
||||
element: '#container'
|
||||
});
|
||||
|
||||
24
src/onTap.js
Normal file
24
src/onTap.js
Normal file
@@ -0,0 +1,24 @@
|
||||
|
||||
export default class OnTap {
|
||||
constructor(settings) {
|
||||
this.element = settings.element || document.body;
|
||||
|
||||
this.callbacks = {};
|
||||
|
||||
this.events = ['click'];
|
||||
|
||||
this.events.map(method => {
|
||||
this[method] = this[method].bind(this);
|
||||
|
||||
if (typeof settings[method] === 'function') {
|
||||
this.element.addEventListener(method, this[method]);
|
||||
this.callbacks[method] = settings[method];
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
click(event) {
|
||||
this.callbacks.click(event);
|
||||
}
|
||||
}
|
||||
|
||||
15
src/point.js
Normal file
15
src/point.js
Normal file
@@ -0,0 +1,15 @@
|
||||
|
||||
export default class Point {
|
||||
constructor(newX, newY) {
|
||||
this.x = newX;
|
||||
this.y = newY;
|
||||
}
|
||||
|
||||
getX() { return this.x; }
|
||||
getY() { return this.y; }
|
||||
|
||||
setX(newX) { this.x = newX; }
|
||||
setY(newY) { this.y = newY; }
|
||||
|
||||
getPoint() { return {x: this.x, y: this.y}; }
|
||||
};
|
||||
37
src/sketch.js
Normal file
37
src/sketch.js
Normal file
@@ -0,0 +1,37 @@
|
||||
|
||||
export default class Sketch {
|
||||
constructor(settings) {
|
||||
this.lastTime = null;
|
||||
|
||||
['getContext', 'onResize', 'render'].map(method => this[method] = this[method].bind(this));
|
||||
|
||||
this.draw = settings.draw || function() {}; // () => {};
|
||||
this.container = settings.element || document.body;
|
||||
|
||||
window.addEventListener('optimizedResize', this.onResize);
|
||||
|
||||
this.canvas = document.createElement('canvas');
|
||||
this.canvas.width = this.container.offsetWidth;
|
||||
this.canvas.height = this.container.offsetHeight;
|
||||
|
||||
this.context = this.canvas.getContext('2d');
|
||||
|
||||
this.container.appendChild(this.canvas);
|
||||
|
||||
requestAnimationFrame(this.render);
|
||||
}
|
||||
|
||||
getContext() { return this.context; }
|
||||
|
||||
onResize(event) {
|
||||
console.log('sketch - onResize', arguments);
|
||||
}
|
||||
|
||||
render(now) {
|
||||
this.draw(this.context, now, this.lastTime);
|
||||
|
||||
this.lastTime = now;
|
||||
requestAnimationFrame(this.render);
|
||||
}
|
||||
}
|
||||
|
||||
62
src/tessellate.js
Normal file
62
src/tessellate.js
Normal file
@@ -0,0 +1,62 @@
|
||||
|
||||
import {random} from './utils.js';
|
||||
|
||||
import OnTap from './onTap.js';
|
||||
import Point from './point.js';
|
||||
import Sketch from './sketch.js';
|
||||
|
||||
import TileCircle from './tileCircle.js';
|
||||
import TileDiamond from './tileDiamond.js';
|
||||
import TileHex from './tileHex.js';
|
||||
import TileSquare from './tileSquare.js';
|
||||
|
||||
export default class Tessellate {
|
||||
constructor(settings) {
|
||||
['draw'].map(method => {this[method] = this[method].bind(this)});
|
||||
|
||||
this.element = document.querySelector(settings.element);
|
||||
|
||||
this.sketch = new Sketch({
|
||||
element: this.element,
|
||||
draw: this.draw
|
||||
});
|
||||
|
||||
this.map = [];
|
||||
|
||||
this.onTap = new OnTap({
|
||||
element: this.element,
|
||||
click: (event) => {
|
||||
let x = event.pageX;
|
||||
let y = event.pageY;
|
||||
let tiles = ['circle', 'diamond', 'hex', 'square'];
|
||||
let styles = ['filled', 'outline'];
|
||||
let scale = random(10, 50);
|
||||
|
||||
this.map.push({
|
||||
tile: tiles[random(tiles.length-1)],
|
||||
style: styles[random(styles.length-1)],
|
||||
x,
|
||||
y,
|
||||
scale,
|
||||
pointy: random(1) ? true : false,
|
||||
color: `rgba(${ random(255) }, ${ random(255) }, ${ random(255) }, 0.5)`
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
this.circle = new TileCircle({context: this.sketch.getContext()});
|
||||
this.diamond = new TileDiamond({context: this.sketch.getContext()});
|
||||
this.hex = new TileHex({context: this.sketch.getContext()});
|
||||
this.square = new TileSquare({context: this.sketch.getContext()});
|
||||
}
|
||||
|
||||
draw(context, now, lastTime) {
|
||||
let canvas = context.canvas;
|
||||
let width = canvas.width;
|
||||
let height = canvas.height;
|
||||
|
||||
context.clearRect(0, 0, width, height);
|
||||
|
||||
this.map.forEach(cell => this[cell.tile][cell.style](cell));
|
||||
}
|
||||
}
|
||||
11
src/tile.js
Normal file
11
src/tile.js
Normal file
@@ -0,0 +1,11 @@
|
||||
|
||||
export default class Tile {
|
||||
constructor(settings) {
|
||||
this.context = settings.context || null;
|
||||
}
|
||||
|
||||
setContext(newContext) {
|
||||
this.context = newContext || this.context;
|
||||
}
|
||||
}
|
||||
|
||||
26
src/tileCircle.js
Normal file
26
src/tileCircle.js
Normal file
@@ -0,0 +1,26 @@
|
||||
|
||||
import Tile from './tile.js';
|
||||
|
||||
let RGBA_DEFAULT = 'rgba(0, 0, 0, 0.5)';
|
||||
|
||||
export default class TileCircle extends Tile {
|
||||
constructor(settings) {
|
||||
super(settings);
|
||||
}
|
||||
|
||||
filled(settings) {
|
||||
this.context.beginPath();
|
||||
this.context.arc(settings.x, settings.y, settings.scale, 0, 2*Math.PI, false);
|
||||
this.context.fillStyle = settings.color || RGBA_DEFAULT;
|
||||
this.context.fill();
|
||||
}
|
||||
|
||||
outline(settings) {
|
||||
this.context.beginPath();
|
||||
this.context.arc(settings.x, settings.y, settings.scale, 0, 2*Math.PI, false);
|
||||
this.context.lineWidth = settings.width ? settings.width : 1;
|
||||
this.context.strokeStyle = settings.color || RGBA_DEFAULT;
|
||||
this.context.stroke();
|
||||
}
|
||||
}
|
||||
|
||||
45
src/tileDiamond.js
Normal file
45
src/tileDiamond.js
Normal file
@@ -0,0 +1,45 @@
|
||||
|
||||
import Tile from './tile.js';
|
||||
|
||||
import {hypotenuse} from './utils.js';
|
||||
|
||||
let RGBA_DEFAULT = 'rgba(0, 0, 0, 0.5)';
|
||||
|
||||
export default class TileDiamond extends Tile {
|
||||
constructor(settings) {
|
||||
super(settings);
|
||||
}
|
||||
|
||||
filled(settings) {
|
||||
let x = settings.x;
|
||||
let y = settings.y;
|
||||
let scale = settings.scale;
|
||||
|
||||
this.context.beginPath();
|
||||
this.context.moveTo(x+hypotenuse(scale), y);
|
||||
this.context.lineTo(x, y-hypotenuse(scale));
|
||||
this.context.lineTo(x-hypotenuse(scale), y);
|
||||
this.context.lineTo(x, y+hypotenuse(scale));
|
||||
|
||||
this.context.fillStyle = settings.color || RGBA_DEFAULT;
|
||||
this.context.fill();
|
||||
}
|
||||
|
||||
outline(settings) {
|
||||
let x = settings.x;
|
||||
let y = settings.y;
|
||||
let scale = settings.scale;
|
||||
|
||||
this.context.beginPath();
|
||||
this.context.moveTo(x+hypotenuse(scale), y);
|
||||
this.context.lineTo(x, y-hypotenuse(scale));
|
||||
this.context.lineTo(x-hypotenuse(scale), y);
|
||||
this.context.lineTo(x, y+hypotenuse(scale));
|
||||
this.context.closePath();
|
||||
|
||||
this.context.lineWidth = settings.width ? settings.width : 1;
|
||||
this.context.strokeStyle = settings.color || RGBA_DEFAULT;
|
||||
this.context.stroke();
|
||||
}
|
||||
}
|
||||
|
||||
97
src/tileHex.js
Normal file
97
src/tileHex.js
Normal file
@@ -0,0 +1,97 @@
|
||||
|
||||
import Tile from './tile.js';
|
||||
|
||||
let RGBA_DEFAULT = 'rgba(0, 0, 0, 0.5)';
|
||||
|
||||
export default class TileHex extends Tile {
|
||||
constructor(settings) {
|
||||
super(settings);
|
||||
|
||||
this.sqrt3 = Math.sqrt(3);
|
||||
|
||||
this.hexSides = 6;
|
||||
this.pointyTopCornerX = [];
|
||||
this.pointyTopCornerY = [];
|
||||
this.flatTopCornerX = [];
|
||||
this.flatTopCornerY = [];
|
||||
|
||||
// dice dots, 0,0 is center
|
||||
// TODO: if pointy: [0].concat(flatTop), if flat: [0].concat(pointy)
|
||||
// this.hexDotX = [0];
|
||||
// this.hexDotY = [0];
|
||||
|
||||
this.hexSlices = 24;
|
||||
this.hexSliceX = [0];
|
||||
this.hexSliceY = [0];
|
||||
|
||||
for (let hexSlice = 0; hexSlice < this.hexSlices; hexSlice++) {
|
||||
this.hexSliceX[hexSlice] = parseInt(Math.cos(((hexSlice/this.hexSlices)*this.hexSides) * (2 * Math.PI) / this.hexSides) * 1000) / 1000;
|
||||
this.hexSliceY[hexSlice] = parseInt(Math.sin(((hexSlice/this.hexSlices)*this.hexSides) * (2 * Math.PI) / this.hexSides) * 1000) / 1000;
|
||||
|
||||
if (((hexSlice-2) % 4) === 0) {
|
||||
let cur = (hexSlice-2) / 4;
|
||||
this.pointyTopCornerX[cur] = this.hexSliceX[hexSlice];
|
||||
this.pointyTopCornerY[cur] = this.hexSliceY[hexSlice];
|
||||
}
|
||||
|
||||
if ((hexSlice % 4) === 0) {
|
||||
let cur = hexSlice / 4;
|
||||
this.flatTopCornerX[cur] = this.hexSliceX[hexSlice];
|
||||
this.flatTopCornerY[cur] = this.hexSliceY[hexSlice];
|
||||
}
|
||||
|
||||
// if (((hexSlice-2) % 4) === 0) {
|
||||
// let cur = (hexSlice-2) / 4;
|
||||
// this.hexCornerX[cur] = this.hexSliceX[hexSlice];
|
||||
// this.hexCornerY[cur] = this.hexSliceY[hexSlice];
|
||||
// }
|
||||
//
|
||||
// if ((hexSlice % 4) === 0) {
|
||||
// let cur = hexSlice / 4;
|
||||
// this.hexDotX[cur+1] = this.hexSliceX[hexSlice];
|
||||
// this.hexDotY[cur+1] = this.hexSliceY[hexSlice];
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
outline(settings) {
|
||||
let x = settings.x;
|
||||
let y = settings.y;
|
||||
let scale = settings.scale;
|
||||
let hexCornerX = settings.pointy ? this.pointyTopCornerX : this.flatTopCornerX;
|
||||
let hexCornerY = settings.pointy ? this.pointyTopCornerY : this.flatTopCornerY;
|
||||
|
||||
this.context.beginPath();
|
||||
this.context.moveTo(x + scale * hexCornerX[0], y + scale * hexCornerY[0]);
|
||||
this.context.lineTo(x + scale * hexCornerX[1], y + scale * hexCornerY[1]);
|
||||
this.context.lineTo(x + scale * hexCornerX[2], y + scale * hexCornerY[2]);
|
||||
this.context.lineTo(x + scale * hexCornerX[3], y + scale * hexCornerY[3]);
|
||||
this.context.lineTo(x + scale * hexCornerX[4], y + scale * hexCornerY[4]);
|
||||
this.context.lineTo(x + scale * hexCornerX[5], y + scale * hexCornerY[5]);
|
||||
this.context.closePath();
|
||||
|
||||
this.context.lineWidth = settings.width ? settings.width : 1;
|
||||
this.context.strokeStyle = settings.color || RGBA_DEFAULT;
|
||||
this.context.stroke();
|
||||
}
|
||||
|
||||
filled(settings) {
|
||||
let x = settings.x;
|
||||
let y = settings.y;
|
||||
let scale = settings.scale;
|
||||
let hexCornerX = settings.pointy ? this.pointyTopCornerX : this.flatTopCornerX;
|
||||
let hexCornerY = settings.pointy ? this.pointyTopCornerY : this.flatTopCornerY;
|
||||
|
||||
this.context.beginPath();
|
||||
this.context.moveTo(x + scale * hexCornerX[0], y + scale * hexCornerY[0]);
|
||||
this.context.lineTo(x + scale * hexCornerX[1], y + scale * hexCornerY[1]);
|
||||
this.context.lineTo(x + scale * hexCornerX[2], y + scale * hexCornerY[2]);
|
||||
this.context.lineTo(x + scale * hexCornerX[3], y + scale * hexCornerY[3]);
|
||||
this.context.lineTo(x + scale * hexCornerX[4], y + scale * hexCornerY[4]);
|
||||
this.context.lineTo(x + scale * hexCornerX[5], y + scale * hexCornerY[5]);
|
||||
|
||||
this.context.fillStyle = settings.color || RGBA_DEFAULT;
|
||||
this.context.fill();
|
||||
}
|
||||
}
|
||||
|
||||
43
src/tileSquare.js
Normal file
43
src/tileSquare.js
Normal file
@@ -0,0 +1,43 @@
|
||||
|
||||
import Tile from './tile.js';
|
||||
|
||||
let RGBA_DEFAULT = 'rgba(0, 0, 0, 0.5)';
|
||||
|
||||
export default class TileSquare extends Tile {
|
||||
constructor(settings) {
|
||||
super(settings);
|
||||
}
|
||||
|
||||
filled(settings) {
|
||||
let x = settings.x;
|
||||
let y = settings.y;
|
||||
let scale = settings.scale;
|
||||
|
||||
this.context.beginPath();
|
||||
this.context.moveTo(x+scale, y+scale);
|
||||
this.context.lineTo(x+scale, y-scale);
|
||||
this.context.lineTo(x-scale, y-scale);
|
||||
this.context.lineTo(x-scale, y+scale);
|
||||
|
||||
this.context.fillStyle = settings.color || RGBA_DEFAULT;
|
||||
this.context.fill();
|
||||
}
|
||||
|
||||
outline(settings) {
|
||||
let x = settings.x;
|
||||
let y = settings.y;
|
||||
let scale = settings.scale;
|
||||
|
||||
this.context.beginPath();
|
||||
this.context.moveTo(x+scale, y+scale);
|
||||
this.context.lineTo(x+scale, y-scale);
|
||||
this.context.lineTo(x-scale, y-scale);
|
||||
this.context.lineTo(x-scale, y+scale);
|
||||
this.context.closePath();
|
||||
|
||||
this.context.lineWidth = settings.width ? settings.width : 1;
|
||||
this.context.strokeStyle = settings.color || RGBA_DEFAULT;
|
||||
this.context.stroke();
|
||||
}
|
||||
}
|
||||
|
||||
48
src/utils.js
Normal file
48
src/utils.js
Normal file
@@ -0,0 +1,48 @@
|
||||
|
||||
export function throttleEvent(type, name, obj) {
|
||||
obj = obj || window;
|
||||
let running = false;
|
||||
|
||||
let throttle = () => {
|
||||
if (!running) {
|
||||
running = true;
|
||||
|
||||
requestAnimationFrame(() => {
|
||||
obj.dispatchEvent(new CustomEvent(name));
|
||||
running = false;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
obj.addEventListener(type, throttle);
|
||||
}
|
||||
|
||||
throttleEvent('resize', 'optimizedResize');
|
||||
|
||||
export function clone(obj) {
|
||||
return JSON.parse(JSON.stringify(obj));
|
||||
}
|
||||
|
||||
export function extend(obj, src) {
|
||||
for (let key in src) {
|
||||
if (src.hasOwnProperty(key)) obj[key] = src[key];
|
||||
}
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
export function hypotenuse(a, b) {
|
||||
if (b == null) b = a;
|
||||
|
||||
return Math.sqrt(a*a + b*b);
|
||||
}
|
||||
|
||||
export function random(min, max) {
|
||||
if (max == null) {
|
||||
max = min;
|
||||
min = 0;
|
||||
}
|
||||
|
||||
return min + Math.floor(Math.random() * (max - min + 1));
|
||||
}
|
||||
|
||||
21
webpack.config.js
Normal file
21
webpack.config.js
Normal file
@@ -0,0 +1,21 @@
|
||||
var path = require('path');
|
||||
|
||||
module.exports = {
|
||||
entry: path.join(__dirname, 'src', 'main.js'),
|
||||
output: {
|
||||
libraryTarget: 'this',
|
||||
path: path.join(__dirname, 'public', 'js'),
|
||||
filename: 'main.js'
|
||||
},
|
||||
devtool: 'inline-source-map',
|
||||
module: {
|
||||
loaders: [{
|
||||
test: path.join(__dirname, 'src'),
|
||||
loader: 'babel-loader',
|
||||
query: {
|
||||
presets: ['es2015']
|
||||
}
|
||||
}]
|
||||
}
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user