Another hex grid library made in JavaScript, heavily inspired by Red Blob Games' code samples.
All existing JS hex grid libraries I could find are coupled with some form of view. Most often a <canvas>
element or the browser DOM. I want more separation of concerns...and a new hobby project to spend countless hours on.
npm i honeycomb-grid
Hexes and views have an origin
property that define the entity's point:
A hex's origin is its center by default (with a value if Point(0, 0)
). If a hex's origin is set to Point(5, 10)
it means its origin is 5 units right and 10 units down of the hex's center. When a hex is converted to a point, its origin is returned (relative to whatever it's converted from).
A view's origin is its container's top left corner by default (with a value of Point(0, 0)
). This corresponds to how HTML elements are positioned in the DOM. If you want the center of the container as the view's origin, set it to Point(containerWidth / 2, containerHeight / 2)
.
Mapping points to hexes and vice versa can be confusing (I thought it was confusing making this library 😕). This table might clear things up:
Method | Input | Output |
---|---|---|
Hex#toPoint |
N/A | the hex's origin point relative to the start hex (Hex(0, 0, 0) ) |
Grid#hexToPoint |
a hex | same as Hex#toPoint |
Grid#pointToHex |
a point | the hex that contains the point |
View#hexToPixel |
a hex | the hex's top left point relative to its origin, relative to the view's origin |
View#pixelToHex |
a point | the hex that contains the point relative to the view's origin |
Factory function for creating grids. It accepts optional hex settings that apply to all hexes in the grid. Several "shape" methods are exposed that return an array of hexes in a certain shape.
A grid is viewless, i.e.: it's a virtual grid with undefined dimensions. If you want to render a tangible grid, use View.
Parameters
hexSettings
Object? Optional settings that apply to all hexes in the grid.hexSettings.size
number Size of all hexes. (optional, default1
)hexSettings.orientation
(FLAT | POINTY) All hexes are either POINTY ⬢ or FLAT ⬣. (optional, defaultPOINTY
)hexSettings.origin
Point Used to convert a hex to a point. Defaults to the hex's center atPoint(0, 0)
. (optional, defaultPoint(0,0)
)
Examples
import { Grid, HEX_ORIENTATIONS } from 'Honeycomb'
const grid = Grid({
size: 50,
orientation: HEX_ORIENTATIONS.FLAT,
customProperty: `I'm custom 😃`
})
const singleHex = grid.Hex(5, -1, -4)
singleHex.coordinates() // { x: 5, y: -1, z: -4 }
singleHex.size // 50
singleHex.customProperty // I'm custom 😃
grid.triangle(3) // [ { x: 0, y: 0, z: 0 },
// { x: 0, y: 1, z: -1 },
// { x: 0, y: 2, z: -2 },
// { x: 1, y: 0, z: -1 },
// { x: 1, y: 1, z: -2 },
// { x: 2, y: 0, z: -2 } ]
Returns Grid A grid instance containing a Hex factory and several methods. Use the Hex factory for creating individual hexes or using any of the Hex's methods.
- See: redblobgames.com
Returns number The width of a (vertical) column of hexes in the grid.
- See: redblobgames.com
Creates a grid in the shape of a hexagon.
Parameters
options
Object An options object.
Returns Array<Hex> Array of hexes in a hexagon arrangement (very meta 😎).
- See: redblobgames.com
Translates a hex to a point.
Parameters
hex
Hex The hex to translate from.
Examples
import { Grid } from 'Honeycomb'
const grid = Grid({ size: 50 })
const hex = grid.Hex(-1, 4, -3)
grid.hexToPoint(hex) // { x: 86.60254037844386, y: 300 }
// a different origin...
const grid = Grid({ size: 50, origin: [50, 50] })
const hex = grid.Hex(-1, 4, -3)
// ...corresponds to a different point:
grid.hexToPoint(hex) // { x: 36.60254037844386, y: 250 }
Returns Point The point to translate to.
- See: redblobgames.com
Creates a grid in the shape of a parallelogram.
Parameters
options
Object An options object.options.width
number The width (in hexes).options.height
number The height (in hexes).options.start
Hex The start hex. (optional, defaultHex(0,0,0)
)options.direction
(1
|3
|5
) The direction (from the start hex) in which to create the shape. Each direction corresponds to a different arrangement of hexes. (optional, default1
)
Returns Array<Hex> Array of hexes in a parallelogram arrangement.
- See: redblobgames.com
Converts the passed 2-dimensional point to a hex.
Parameters
point
Point The point-like to convert from.
Examples
import { Grid, Point } from 'Honeycomb'
const grid = Grid({ size: 50 })
grid.pointToHex(Point(120, 300)) // { x: -1, y: 4, z: -3 }
// also accepts a point-like:
grid.pointToHex({ x: 120, y: 300 }) // { x: -1, y: 4, z: -3 }
grid.pointToHex([ 120, 300 ]) // { x: -1, y: 4, z: -3 }
Returns Hex The hex (with rounded coordinates) that contains the passed point.
- See: redblobgames.com
Creates a grid in the shape of a rectangle.
Parameters
options
Object An options object.options.width
number The width (in hexes).options.height
number The height (in hexes).options.start
Hex The start hex. (optional, defaultHex(0,0,0)
)options.direction
(0
|1
|2
|3
|4
|5
) The direction (from the start hex) in which to create the shape. Each direction corresponds to a different arrangement of hexes. (optional, default0
)
Returns Array<Hex> Array of hexes in a rectengular arrangement.
- See: redblobgames.com
Returns number The height of a (horizontal) row of hexes in the grid.
- See: redblobgames.com
Creates a grid in the shape of a (equilateral) triangle.
Parameters
options
Object An options object.options.size
number The side length (in hexes).options.start
Hex The start hex. Note: it's not the first hex, but rather a hex relative to the triangle. (optional, defaultHex(0,0,0)
)options.direction
(1
|5
) The direction in which to create the shape. Each direction corresponds to a different arrangement of hexes. In this case a triangle pointing up (direction: 1
) or down (direction: 5
) (with pointy hexes) or right (direction: 1
) or left (direction: 5
) (with flat hexes). (optional, default1
)
Returns Array<Hex> Array of hexes in a triangular arrangement.
Factory function for creating hexes. It can only be accessed by creating a Grid (see the example).
Coordinates not passed to the factory are inferred using the other coordinates:
- When two coordinates are passed, the third coordinate is set to the result of Hex.thirdCoordinate(firstCoordinate, secondCoordinate).
- When one coordinate is passed, the second coordinate is set to the first and the third coordinate is set to the result of Hex.thirdCoordinate(firstCoordinate, secondCoordinate).
- When nothing or a falsy value is passed, all coordinates are set to
0
.
Parameters
coordinates
(number | Object) The x coordinate or an object containing any of the x, y and z coordinates. (optional, default0
)y
number The y coordinate. (optional, default0
)z
number The z coordinate. (optional, default0
)
Examples
import { Grid } from 'Honeycomb'
// `Hex()` is not exposed on `Honeycomb`, but on a grid instance instead:
const Hex = Grid().Hex
Hex() // returns hex( x: 0, y: 0, z: 0 )
Hex(1) // returns hex( x: 1, y: 1, z: -2 )
Hex(1, 2) // returns hex( x: 1, y: 2, z: -3 )
Hex(1, 2, -3) // returns hex( x: 1, y: 2, z: -3 )
Hex(1, 2, 5) // coordinates don't sum up to 0; throws an error
Hex({ x: 3 }) // returns hex( x: 3, y: 3, z: -3 )
Hex({ y: 3 }) // returns hex( x: 3, y: 3, z: -6 )
Hex({ z: 3 }) // returns hex( x: 3, y: -6, z: 3 )
Returns Hex A hex object. It has all three coordinates (x
, y
and z
) as its own properties and various methods in its prototype.
Parameters
Returns Hex The sum of the passed hexes coordinates.
- See: redblobgames.com
Returns the amount of hexes between the current and the given hex.
Parameters
Examples
import { Grid } from 'Honeycomb'
const Hex = Grid().Hex
Hex.distance(Hex(0, 0, 0), Hex(1, 0, -1)) // 1
Hex.distance(Hex(-3, -3, 6), Hex(-1, 4, -3)) // 9
Returns number The amount of hexes between the passed startHex
and endHex
.
- See: redblobgames.com
Parameters
Returns Array<Hex> Array of hexes starting at the passed startHex
and ending with the passed endHex
.
Returns an interpolation between the current hex and the passed hex for a t
between 0 and 1.
More info on wikipedia.
Parameters
Returns Hex A new hex (with possibly fractional coordinates).
- See: redblobgames.com
Returns the neighboring hex in the given direction.
Parameters
hex
Hex The hex to get the neighboring hex from.direction
(0
|1
|2
|3
|4
|5
) Any of the 6 directions.0
is the Eastern direction (East-southeast when the hex is flat),1
corresponds to 60° clockwise,2
to 120° clockwise and so forth. (optional, default0
)diagonal
boolean Whether to look for a neighbor opposite the hex's corner instead of its side. A direction of0
means the top corner of the hex's right side when the hex is pointy and the right corner when the hex is flat. (optional, defaultfalse
)
Examples
import { Grid } from 'Honeycomb'
const Hex = Grid().Hex
const targetHex = Hex()
Hex.neighbor(targetHex) // { x: 1, y: -1, z: 0 }, the hex across the 0th (right) side of targetHex
Hex.neighbor(targetHex, 2) // { x: 0, y: 1, z: -1 }, the hex across the 3rd (South West) side of targetHex
Hex.neighbor(targetHex, 3, true) // { x: -2, y: 1, z: 1 }, the hex opposite the 4th corner of targetHex
Returns Hex The neighboring hex.
- See: redblobgames.com
Returns all neighboring hexes of the given hex.
Parameters
hex
Hex The hex to get all neighbors from.
Returns Array<Hex> An array of the 6 neighboring hexes.
- See: redblobgames.com
Returns a new hex with a tiny offset from the passed hex. Useful for interpolating in a consistent direction.
Parameters
hex
Hex The hex to nudge.
Returns Hex A new hex with a minute offset.
- See: redblobgames.com
Rounds the passed floating point hex coordinates to their nearest integer hex coordinates.
Parameters
hex
Hex The hex to be rounded.
Returns Hex A new hex with rounded coordinates.
Parameters
Returns Hex The difference between the passed hexes coordinates.
Calculates the third coordinate from the other two. The sum of all three coordinates must be 0.
Parameters
firstCoordinate
number The first other coordinate.secondCoordinate
number The second other coordinate.
Returns number The third coordinate.
Returns Object The hex's x, y and z coordinates.
Returns Array<Point> Array of corner points. Starting at the top right corner for pointy hexes and the right corner for flat hexes.
Returns number The (vertical) height of any hex.
Returns boolean Whether hexes have a flat ⬣ orientation.
Returns boolean Whether hexes have a pointy ⬢ orientation.
Returns number The distance between opposite corners of a hex.
Returns number The distance between opposite sides of a hex.
A hex's origin is relative to its center point, but a browser positions a DOM node relative to its top left point. This method can be used to translate the center-originating hex to a top-left-originating hex.
Returns Point The vector relative to the hex's center.
Converts the current hex to its origin point relative to the start hex.
Returns Point The 2D point the hex corresponds to.
Returns number The (horizontal) width of any hex.
The different orientations hexes can have.
Factory function for creating 2-dimensional points. Accepts a point-like and returns a point instance. A point-like can be an object with an x
and y
property (e.g. { x: 0, y: 0 }
) or an array with 2 items (e.g. [0, 0]
) that correspond to x
and y
respectively.
Parameters
coordinatesOrX
(number | Array<number> | Object) The x coordinate or a point-like. (optional, default0
)y
number The y coordinate. (optional, default0
)
Examples
import { Point } from 'Honeycomb'
Point() // { x: 0, y: 0 }
Point(1) // { x: 1, y: 1 }
Point(1, 2) // { x: 1, y: 2 }
Point([1, 2]) // { x: 1, y: 2 }
Point([1]) // { x: 1, y: 1 }
Point({ x: 1, y: 2 }) // { x: 1, y: 2 }
Point({ x: 1 }) // { x: 1, y: 1 }
Point({ y: 2 }) // { x: 2, y: 2 }
Returns Point A point object.
Parameters
point
Point The point to add to the current point.
Returns Point The sum of the passed point's coordinates to the current point's.
Parameters
point
Point The point where the current point is divided by.
Returns Point The division of the current point's coordinates and the passed point's.
Parameters
point
Point The point to multiply with the current point.
Returns Point The multiplication of the passed point's coordinates and the current point's.
Parameters
point
Point The point to subtract from the current point.
Returns Point The difference between the passed point's coordinates and the current point's.
Factory function for creating views. A view instance can be used to render (a grid of) hexes. This function expects raw DOM elements, i.e. it lacks helpers to convert strings to DOM elements. You can use other libraries (e.g. jQuery, svg.js) to help create these DOM elements.
Parameters
options
Object Options to instantiate the view with. (optional, default{}
)options.grid
Grid A grid instance.options.template
Function Template function that should return a DOM element. When hexes are rendered (e.g. by calling View#renderGrid or View#renderHexes), the template function is called with each hex. In the template functionthis
refers to the view instance, so any view method can be called.options.container
Node The container in which hexes are to be rendered. Should be an existing DOM element (e.g. a<div>
or<svg>
) in thedocument
.options.origin
Point Pixel origin where the start hex (Hex(0, 0, 0)
) is placed. Defaults toPoint(0, 0)
, i.e.: the top left corner of the container. The origin is relative to the container (not to the document). (optional, defaultPoint(0,0)
)
Examples
const { Grid, View } from 'Honeycomb'
const container = document.getElementById('my-container')
const rect = container.getBoundingClientRect()
const view = View({
grid: Grid({ size: 20 }),
template: hex => {
// `this` refers to the view instance
const position = this.hexToPixel(hex)
const div = document.createElement('div')
div.classList.add('hex')
div.style.left = position.x + 'px'
div.style.top = position.y + 'px'
return div
},
container,
// set the view's origin to the container's center
origin: {
x: rect.width / 2,
y: rect.height / 2
}
})
// The view instance can now be used to render hexes as divs with dimensions that
// would fit pointy hexes with a radius of 20px. Each div having the class 'hex'
// and a `style` attribute with a `left` and `top` property. The start hex
// (`Hex(0, 0, 0)`) would be placed in the center of the container.
Returns View A view instance to render hexes in.
Returns number The rounded amount of hexes that fit in the container vertically ↕.
Converts the passed hex to a pixel position relative to the container's origin. The hex's top left corner is used (instead of its origin) to render the hex as a DOM node. DOM nodes have their top left corner defined as their origin.
Parameters
hex
Hex The hex to convert to a pixel position.
Returns Point The pixel position.
Converts the passed pixel position (relative to the container) to the corresponding hex.
Parameters
pixel
Point The pixel position to convert to a hex.
Returns Hex The corresponding (rounded) hex.
Renders all hexes that fit in the container, plus the optional padding. This padding defaults to 3 (hexes), so that the container is completely covered in hexes.
Parameters
padding
number Number of hexes to add to all 4 sides of the container. Can be used to guarantee the container is completely covered in hexes. (optional, default3
)
Examples
const { View } from 'Honeycomb'
const view = View() // view creation truncated for brevity
// This renders all hexes that fit in the container, plus an extra layer of 3 hexes:
view.renderGrid()
Returns View The view instance, for chaining.
Renders the passed array of hexes in the container.
Parameters
hexes
Array<Hex> An array of hexes to render. Grid's shape methods (Grid#parallelogram, Grid#triangle, Grid#hexagon and Grid#rectangle) can be used to generate this array.
Examples
const { Grid, View } from 'Honeycomb'
const grid = Grid({ size: 20 })
const view = View() // view creation truncated for brevity
// This renders hexes in the shape of a hexagon with a radius of 3 hexes
// and the start hex (`Hex(0, 0, 0)`) as its center:
view.renderHexes(grid.hexagon(3))
Returns View The view instance, for chaining.
Returns number The rounded amount of hexes that fit in the container horizontally ↔.
- Get
babel-polyfill
(orbabel-runtime
?) to work withbabel-preset-env
, preferably without including a bazillion unused polyfills in the dist... - Docs: find a way to link modules together. Currently, methods of the factory functions doesn't seem to belong to their factory functions (in the context of jsdoc). This bug is nasty, tried lots of things already...
- Expose
Hex
onHoneycomb
, adding the possibility to create (individual) hexes and useHex
's static methods without having to create a grid first? - Add possibility to stretch hexes; they needn't be regularly shaped. This is an actual request as well.
- Make it possible to filter overlapping hexes when multiple shapes are rendered.
- Use JSFiddle for better examples.
- Explain (hex) directions.
- Shiny github.io pages 😎
- View should be hex-orientation-agnostic (always pointy) and just use
transform
to toggle orientations. - Maybe add instance methods for
Grid
andViews.DOM
to get/set options. Then it's optional to pass the options to theGrid
andViews.DOM
factories and makes it possible to get/set those options later. - Add helper to easily fall back to a hex's prototype?
- Don't transpile to ES5. Who needs IE anyway?
- Replace Webpack by Rollup, because it's supposed to be more suitable for libraries.
- Update code (and tests) of
Point
to be more consice with other modules. - Grid shape methods should return Sets instead of arrays?