Giter Club home page Giter Club logo

honeycomb's Introduction

⬡ Honeycomb NPM version Minified size Gitter

A hexagon grid library made in JavaScriptTypeScript, heavily inspired by Red Blob Games' blog posts and code samples.

Honeycomb works in modern browsers and Node (>=16). It's recommended to use Honeycomb with TypeScript, but not required.

ko-fi

Installation

NPM:

npm i honeycomb-grid

Yarn:

yarn add honeycomb-grid

Or download the distribution from jsdelivr or unpkg.com.

Basic example

Create a rectangular grid of 10 by 10 hexes and log each hex:

import { defineHex, Grid, rectangle } from 'honeycomb-grid'

// 1. Create a hex class:
const Tile = defineHex({ dimensions: 30 })

// 2. Create a grid by passing the class and a "traverser" for a rectangular-shaped grid:
const grid = new Grid(Tile, rectangle({ width: 10, height: 10 }))

// 3. Iterate over the grid to log each hex:
grid.forEach(console.log)

Documentation

Documentation is available at abbekeultjes.nl/honeycomb. API docs can be found at abbekeultjes.nl/honeycomb/api/.

Backlog

These are ideas that may require further investigation 🕵️. Don't hesitate to open an issue or start a discussion.

  • Directions should also be given in degrees (in steps of 30°)?
  • Add functionality related to edges and/or corners. Use https://www.redblobgames.com/grids/parts/#hexagons.
  • Add path finding (e.g. A*) functionality. Currently available as an example, see /examples/a-star-path-finding/.
  • Clarify the "Line of sight" example (and rename to "Field of view"). Maybe add animations and some enemies as well?
  • Add examples for (procedural) map generation (from a seed).

honeycomb's People

Contributors

flauwekeul avatar glitchassassin avatar hankolsen avatar ildifa avatar mbrinkl avatar perlkonig avatar semantic-release-bot avatar sigstackfault avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

honeycomb's Issues

[Feature Request] Add `proto` to `Hex` instead of using `Hex().__proto__`

Hex created via Honeycomb.extendHex() is not a class.
As a result, when we need to access properties of the hex prototype (like calculating the size of the SVG element of the grid), we have to write Hex().__proto__.

It is OK, but not good enough.

Since it is feasible and not uncommon in practice to make a function have its properties (when they are logically most closely related with the function), why not provide us with something like Hex.proto?


I know it is not a big deal, but bad code smells even when it is small. 👃

Alternative Spiral Grid

Hey,
First thing I want to thank you, this module is just great and helped me a lot.
I'm building some tool for the game "the settlers of catan",

in this game, when you arrange the tiles on the board, you need to arrange them in a spiral order, but in the following way:
image

the "spiral" grid in the library is almost exactly what I need, but just almost (left image)
when it move up to the next ring, It "jumps" up, instead of continue in the "spiral" naturally... (right image)

so after visiting "7" I wish to visit "19".
for now, I first create the grid, assigning some id's to the board, and then travsere them again in the "correct" way.
for the record, this is the excat way to visit catan board (according to the id's in the images of-course)
[8, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 2, 7, 6, 5, 4, 3, 1];

can you share your thoughts ?
many thanks

Hex edge utilities

Utilities for getting the edges of hexes would be appreciated. Maybe looping over them too.

License

Hello, I'd love to use this as a basis for a game - would you consider attaching a license to the project?

Add image, hover and click on hex ?

Hello, I don't know if this place is the good one to ask that if not, please forgive me. :)
I didn't see any possibilities to add an image on a hex of the grid nor add it hover and click fonctionnalities. Is it possible ?

Grid.get doesn't work inside class

Hi! In my project i use svg.js along with this lib. I define class, inside which i use grid. When i call grid.get from class functions, a "TypeError: Grid.get is not a function" comes out. Grid.get works only inside class constructor. Any other class function gives error. Other Grid functions like hexesBetween also doesn't work.
Here is the fiddle. Here I set click handler to polygons. Click and see an error.

pointToHex returns hex below the point when point is above the grid

When I click the blank space above the hex grid, I would expect Grid.pointToHex to return a hex not in the grid, but instead it returns the hex below it.

Below is an adaptation of one of the documentation's JSFiddle examples that demonstrates what I mean.

const app = new PIXI.Application({ transparent: true, antialias: true })
const graphics = new PIXI.Graphics()

const Hex = Honeycomb.extendHex({ size: 5 })
const Grid = Honeycomb.defineGrid(Hex)

document.body.appendChild(app.view)
// set a line style of 1px wide and color #999
graphics.lineStyle(1, 0x999999)

// render 10,000 hexes
const grid = Grid.rectangle({ width: 100, height: 100 });
grid.forEach(hex => {
    const point = hex.toPoint()
    // add the hex's position to each of its corner points
    const corners = hex.corners().map(corner => corner.add(point))
    // separate the first from the other corners
    const [firstCorner, ...otherCorners] = corners

    // move the "pencil" to the first corner
    graphics.moveTo(firstCorner.x, firstCorner.y)
    // draw lines to the other corners
    otherCorners.forEach(({ x, y }) => graphics.lineTo(x, y))
    // finish at the first corner
    graphics.lineTo(firstCorner.x, firstCorner.y)

    app.stage.addChild(graphics)
})

document.addEventListener('click', ({offsetX, offsetY}) =>
       // should output undefined when I click the blank space above the grid
	console.log(grid.get(Grid.pointToHex(offsetX, offsetY)))
)

I appreciate your library, by the way.

"export 'FlatCompassDirection' was not found in 'honeycomb-grid'

Hi,

I'm using this (very useful) library with typescript and webpack and run into this warning

"export 'FlatCompassDirection' was not found in 'honeycomb-grid'

for this code

import { Hex, Point, FlatCompassDirection } from 'honeycomb-grid';
...
const neighbors = grid.neighborsOf(hex, [
        FlatCompassDirection.SE, FlatCompassDirection.S, FlatCompassDirection.SW,
        FlatCompassDirection.NW, FlatCompassDirection.N, FlatCompassDirection.NE,
]);

It results in this error at runtime:

TypeError: honeycomb_grid__WEBPACK_IMPORTED_MODULE_14__.FlatCompassDirection is undefined

It looks a lot like this webpack issue, that seem to indicate you can fix the issue by changing the way it is declared.

Many answers on stackoverflow seem to imply it could also work by declaring the enum as 'const' in the types declaration file.

TypeError: grid.neighborsOf is not a function in when used with vm.$set in Vue

I'm using hc with vue as follows

    mounted() {
        let self = this;

        const Hex = extendHex({
            size: 20,
            orientation: "flat"
        });

        let Grid = defineGrid(Hex);
        let grid = Grid.rectangle({
            width: 25, // value:		number (excluding center hex)
            height: 20,
            start: [0, 0], // value: 	any point
        });

        console.log(1, grid.neighborsOf(Hex(), [1, 10])); // this outputs 1 array[...]
        self.$set(self, "hex", Hex);
        console.log(2, grid.neighborsOf(Hex(), [1, 10])); // this outputs 2 array[...]
        self.$set(self, "grid", grid);
        console.log(3, grid.neighborsOf(Hex(), [1, 10])); // this fails with grid.neighborsOf is not a function 
}

Am i doing something wrong here?

Usage questions

Hello!

First, great thanks for this library. I'm making a hex-based game and really hope it will save me a lot of time on implementation.

I'm just starting to play with it and got a couple of questions, because I'm not sure I'm getting the right idea how to use it.

  1. When I use Grid factory to create a rectange grid, like this:
var Grid = HC.Grid({
    size: 24,
    orientation: HC.HEX_ORIENTATIONS.POINTY
});

var grid = Grid.rectangle(10, 10);

Now the grid variable is an array, but i'd expect to use it as object, i mean a container of all hexes, to be able to do smth like this:

grid.getHex(1,2,3).getNeighborsInRadius(3);
// or
grid.getHex(1,2,3).getDistanceTo(grid.getHex(5,6,7));

What is the right way to do this?

  1. I'm testing finding hex by coordinates, using the very first hex of the grid, getting its center point and then trying to find hex by this point, like this:
var Grid = HC.Grid({
    size: 24,
    orientation: HC.HEX_ORIENTATIONS.POINTY
});

var grid = Grid.rectangle(10, 10);
console.log(grid[0]);

var hex = Grid.pointToHex(grid[0].center());
console.log(hex);

The output of this is:

{ x: 0, y: 0, z: 0 }
{ x: 0, y: 1, z: -1 }

But i expected to see the same hex, because i'm looking by its center.
What am I doing wrong?

  1. When i'm trying to get coordinates for all hexes in the grid:
for (var i = 0; i < grid.length; i++) {
    console.log(grid[i].center());
}

I'm getting all the same results for each hex, why is this happening?

{ x: 20.784609690826528, y: 24 }
{ x: 20.784609690826528, y: 24 }
{ x: 20.784609690826528, y: 24 }
{ x: 20.784609690826528, y: 24 }
...

Again, thank you for your work, hope you can help me =)

[Feature Request] Support Hex weights

It would be sick if this library supported an additional weight property on Hex objects. This would enable functions like Hex.distance and some of the Grid functions to support more use cases.

I noticed Red Blob's article mentions 'movement cost', it would be nice if that could be a parameter of the individual Hex objects.

[2.0] `isPointy` prop instead of `isPointy()`, `isFlat()` and `orientation`

Since you are rewriting the library, I guess it is a good time to rethink over the concepts, principles and architect of the lib, and move on to version 2.0.

This post is the first of my incoming ones.

Let's start with a minor but API-breaking one as an appetizer.

The lib now has three interfaces for the effectively same thing: orientation.
This situation is confusing.


This makes me recall my confusion about how to express gender/sex of a person object years ago.

If in a simple world, like in a game, not on Facebook (which provides quite many gender options), there are only two genders: "male" and "female", and null is not allowed.

Naturally, I could give Person a prop gender and let it be "male" | "female".
Or, I could let it be 0 | 1, but I need to remember which value means what and risk mistakes.
Even when I fall back to "male" | "female", errors like misspelling, capitalizing ("Male") can still happen.
Let alone if I need to coopoarate with other team members.

The best practice I've come to is prop isMale, which is boolean, which is easy-to-use and error-proof.

A Person class doesn't have to be exactly like a passport.

(Well, I am talking about JavaScript only. In C++ or database, 0|1 may be preferred.)


Back to your lib.

It is sure that there are only two orientations and null is not allowed. So similar to gender.

I imagine your story might be like the following:

  1. At the beginning, you created orientation.
  2. But later you found yourself in many needs of if ... else ... and as a result you created isPointy().
  3. Then, you felt it asymmetric, so you continued to add isFlat() .

Now, we have more "freedom" than we need.
On the contrary, three options here are as bad as as three watches (to tell the time).

I foresee no need other than if ... else ... with orientation in practical uses of this lib.

In fact, in your own source code, orientation is read only by Grid::rectangle and Grid::neighborsOf (when they call compassToNumberDirection) besides, of course, isPointy() and isFlat() .

So, we can safely decide to use one boolean prop, namely isPointy, in place of the three.

Nudged/Rounding Issue

This comes up in calculating hex lines. Sample code to demonstrate the issue:

let original = Honeycomb.extendHex()(-3, -1)
let nudged = original.nudge()
let rounded = nudged.round()

document.write(`
Original: ${original.q}, ${original.r}, ${original.s} <br/>
Nudged: ${nudged.q}, ${nudged.r}, ${nudged.s} <br/>
Rounded: ${rounded.q}, ${rounded.r}, ${rounded.s}
`);

Expected behavior: Original and Nudged should round to the same value
Actual behavior:

Original: -2, -1, 3
Nudged: -2.999999, -0.999999, 3.9999979999999997
Rounded: -3, -1, 4

How to generate a grid from a rectangle with fixed size for the hexagon?

I need to generate a hexagonal grid in my JS frontend that perfectly matches the one I generate from my Python backend because I use the centroid of the hexagon as an ID.

This is the Python code / library I use now:

https://github.com/stephanh42/hexutil#converting-between-hexagonal-grid-coordinates-and-screen-coordinates

hex_width = 100
hex_height = 58
grid = HexGrid(width=hex_width, height=hex_height)
hexes = grid.hexes_in_rectangle([x_min, y_min, width, height])

Is there a way to fix the height and width of a hexagon with "honeycomb"?

TypeScript issue with "this" & types checking

Hey, i'm having issue with this code:

import * as honeycomb from "honeycomb-grid";
import SVG from "svg.js";

type DataKeys<T> = {
  [K in keyof T]: T[K] extends () => void ? never : K
}[keyof T];

type Data<T> = Pick<T, DataKeys<T>>;

export default class Grid<T extends Grid<T>> {
  private static draw = SVG(document.body);
  private static fontSize = 12;
  private hex = honeycomb.extendHex({
    size: 20,
    render(draw) {
      this.render(draw);
    }
  }); // what type should i set here ?
  private position = this.toPoint(); // Uncaught TypeError: this.toPoint is not a function. How to tackle this ?
  private centerPosition = this.center().add(this.position); // Same shit here...
  private Grid = honeycomb.defineGrid(this.hex); // what type should i set here ? GridFactory ?

  constructor(data?: Partial<Data<T>>) {
    if (data) {
      Object.assign(this, data);
    }
    this.Grid.hexagon({
      center: [5, 5],
      onCreate: this.renderHex,
      radius: 4
    });
  }
  private render(draw) {
    // draw the hex
    // Uncaught TypeError: this.corners is not a function. How to tackle this ?
    draw
      .polygon(this.corners().map(({ x, y }) => `${x},${y}`))
      .fill("none")
      .stroke({ width: 1, color: "#999" })
      .translate(this.position.x, this.position.y);

    // draw x and y coordinates
    draw
      .text(`${this.x},${this.y}`)
      .font({
        anchor: "middle",
        fill: "#69c",
        leading: 1.4,
        size: this.fontSize
      })
      .translate(this.centerPosition.x, this.centerPosition.y - this.fontSize);
  }
  // what type should i set for "hex" ?
  private renderHex(hex) {
    hex.render(draw);
  }
}

That's confusing...

Position hexes correctly when border width is not 0

After successfuly following the examples, I got a pointy grid of hexes with stroke width = 1.
But soon I noticed that the left strokes of the first column is thinner than others.

I changed stroke width into much larger values and realized that half of those strokes are out of the left side of the viewport of the svg root/container element.
The same story happens to the top corner strokes which stand partly beyond the top side of the viewport.

So, when calculating positions of hexes, stroke/border width ought to be used.


I've fixed this issue.

The screenshot shows the dashed outline (set via css) of the container svg element.
The borders & corners of hexes are right in the box of the element.

grid-of-hexes-with-border

Here's the code:

  Point = Honeycomb.Point;
  sqrt3 = Math.sqrt(3);

  Hex = Honeycomb.extendHex({
    border: 12,
    .
    .
    .
    toPoint: function() {
      var border, q, r, size, x, y;
      {q, r, size, border} = this;
      border = border || 0;
      if (this.isPointy()) {
        x = size * sqrt3 * (q + r / 2) + border / 2;
        y = size * 3 / 2 * r + border / sqrt3;
      } else {
        x = size * 3 / 2 * q + border / sqrt3;
        y = size * sqrt3 * (r + q / 2) + border / 2;
      }
      return Point(x, y);
    }

I have also worked a lot to make the width and height of the viewport be exactly of the visual size of the grid, so that the right and bottom borders/corners can sit next to the sides of the viewport too.

Here's the essential parts of my work. Hope you can understand them without much pain...

  l = {
    grid: {
      w: 4,
      h: 3
    }
  };
  .
  .
  .
  el = document.querySelector '#main-grid'
  draw = SVG el


  grid = Grid.rectangle({
    width: l.grid.w,
    height: l.grid.h,
    onCreate: function(hex) {
      return hex.render(draw);
    }
  });


  hex_proto = Hex().__proto__;

  if (hex_proto.isPointy()) {
    grid.view = {
      w: hex_proto.size * sqrt3 * (l.grid.w + 0.5) + hex_proto.border,
      h: hex_proto.size * (l.grid.h / 2 * 3 + 0.5) + hex_proto.border * 2 / sqrt3
    };
  } else {
    grid.view = {
      h: hex_proto.size * sqrt3 * (l.grid.h + 0.5) + hex_proto.border,
      w: hex_proto.size * (l.grid.w / 2 * 3 + 0.5) + hex_proto.border * 2 / sqrt3
    };
  }
  el.style.width = `${grid.view.w}px`;
  el.style.height = `${grid.view.h}px`;

Second grid overriding original Hex factory

Hey man, I've been using Honeycomb for the last month, and I absolutely love it, you've done a really good job. Sadly though I've run into a problem that's taken up my whole day with no solution, so I figured I'd pop in and ask.

I've been implementing a system to store hexes in a grid inside hexes of another grid, which will be at a different 'zoom' level (so for instance 7 hexagons might be inside 1 hexagon in the grid 1 zoom level up). Basically it's just an implementation of this Sander Evans page,. which you've probably seen since I found it from the Red Blob Gaming page. https://observablehq.com/@sanderevers/hexagon-tiling-of-an-hexagonal-grid

One thing to note here is that if the first grid is "pointy," then the second one should be "flat" if you don't want things to rotate around when zooming.

The problem I've arrived at though is that when I create the second grid, its Hex factory overrides the initial hex factory, so that my first pointy grid is now using flat hex assumptions in its operations, even though originally it was created with a pointy Hex factory.

It's worth noting that since defineGrid doesn't take properties in the same way that extendHex does, I ended up writing my own mixin so that I can put some more methods onto the prototype. So it's possible that the issue is entirely in my code and nothing to do with Honeycomb, but I honestly can't tell at this point so I figured I'd ask if what I'm describing sounds like normal behaviour for Honeycomb to you, and if you might be able to shed some light on what's happening.

Thanks for taking the time, and again, awesome job :D

Examples show Grid#hexagon misuse

Grid#hexagon takes an options object, but in the examples it is shown accepting an integer argument grid.hexagon(3). When called with an integer, Grid#hexagon returns an empty array.

Hex#corners not working

Thanks for making this lib - I'm hoping to make heavy use of it in a hobby project.

Having difficulty with the following bit of code, not sure if bug or user error:

const grid = Grid({
  size: 20,
  orientation: HEX_ORIENTATIONS.FLAT,
});

const hexArray = grid.rectangle({
  width: 2,
  height: 2,
  direction: 1,
});

hexArray.forEach(hex => console.log( grid.Hex(hex).corners()) );

Expected behavior: console should log 4 arrays of corners, each with a unique set of coords

Actual behavior: console logs 4 arrays of corners, each with the same set of coords

Contributing

Hi!

I just wanted to say thank you for publishing this lib! I am using it for a tiny game prototype I am playing around with now. Do you have any roadmap or known bugs or some features in mind? Mind be useful to drop them into some easy to start on issues so that someone (maybe me) can pick up and make this lib's bus factor higher.

cheers!

Set an all grid and add properties to an hex

Hello again ;) ,
My goal is to use your tool as a map generator. I have to save that map in a database in order to allow the user to find it back. I thought about saving the coordinates of each hex.
My question is : when I have my array of coordinate after an API call, what is the best way to display back those hex ?

I got a second question, in my map the hex has more properties. So once again, what is the best way to do that ?

Thanks for your answer.

Error in TS

ERROR in node_modules/honeycomb-grid/dist/honeycomb.d.ts(47,32): error TS2304: Cannot find name 'ConcatArray'.

What is the (de)serialization story?

Since the library is awesome in the way that it is viewless and works in both node and browser, the next logical feature would be the ability to serialize/deserialize to something like JSON, so we can send/receive grid data in a client-server architecture.

How to move a grid with updating coordinates in pointToHex?

After moving the hexagonal grid using the SVG viewBox, translate, etc. pointToHex remained unchanged and continues give me the coordinates before the changes. I need to move it, because when creating the hexagonal grid, only a quarter of it is visible.

Is there a way to add spaces/margin between hexagons?

Hey,

First of all thanks for the great library.

So, for one of my project, I am trying to plot hexagons, but for each hexagon, I want to have some spacing(more like a margin, padding) between each hexagon, I tried to do this using svg library, but couldn't make it work. Is there a way in Honeycomb library to do it mathematically? I tried to play with the hex generator, but couldn't get proper margin/spacing between each hexagon.

One of the approaches, which I think might work is to change the corner coordinates(which is the same for every hex) before I render the points.

But, I couldn't find figure out the math as of now to reduce the corner coordinates evenly(without distorting the hexagonal shape), more like shrinking the size of the hexagonal.

Any clue will be deeply appreciated.

A few questions ...

Hi !

I'm playing with your example to see if it could work for a video game. I work with React but other implementations lack of customisation or just does not work.

I'm trying to implement a React view for a video game, so I have a few questions :

First, I make a rectangle map. I may change later but it fits best to a PC screen. I would like to use the “even-q” vertical layout from Red Blob, i.e. the top left angle is round and not sharp ; it feels less sharp to the eye. Is it possible to configure the grid in such a way ?

Then, I would like to draw an isometric map, so is it possible to configure a different radius for the height and the width of the hexagons ?

Thanks !

Why is Grid.get so slow?

Calling Grid.get in a loop seems to be extremely slow. It appears that its looping over the entire grid. Why? Seems unnecessary.

t.distance is not a function

Hi everybody
I dont' know if it's an error or if i do something wrong but whith this code i got the error: t.distance is not a function.

const Hex = Honeycomb.extendHex({ size: 30 });
const Grid = Honeycomb.defineGrid(Hex);
const grid = Grid.rectangle({ width: 50, height: 50 });
const hexBetween = grid.hexesBetween({ x: 0, y: 0 }, { x: 5, y: 5 });
console.log(hexBetween);

Someone can say me if it's a problem or where i do a mistake ?

Problem with downloading

Hi!

You forget to add a download option for those who want to use it in browser.
I mean a .min version, I don't want to have all the source in my dir you know :)

Can you help me with that?

Thanks !

Type definitions are broken with latest TypeScript version (starting from 3.0.0)

Upgrading TypeScript from 3.2.4 to 3.3.3 is causing the following problems:

node_modules/honeycomb-grid/dist/honeycomb.d.ts:1:44 - error TS2744: Type parameter defaults can only reference previously declared type parameters.

declare function defineGrid<T = HexFactory<T>>(Hex?: HexFactory<T>): GridFactory<Hex<T>>

node_modules/honeycomb-grid/dist/honeycomb.d.ts:36:27 - error TS2744: Type parameter defaults can only reference previously declared type parameters.

export class Grid<T = Hex<T>> extends Array<T> {

For more information please check this issue in the TypeScript repository.

Thanks

No type definitions for ring and spiral

If these aren't generated automatically, you should be able to just copy from hexagon:

ring(options: { radius: number; center?: HexCoordinates; onCreate?: onCreateCallback<T> }): Grid<T>
spiral(options: { radius: number; center?: HexCoordinates; onCreate?: onCreateCallback<T> }): Grid<T>

Nudge Float Rounding Issue

I'm back!

I'm not sure how this was avoided before, but with the fix in the latest version of honeycomb-grid I'm now getting float rounding errors:

Error: Cube coordinates must have a sum of 0. q: 4.000001, r: -3.999999, s: -0.000002, sum: 2.7955602446123017e-16.

You can duplicate with the following:

hex = Honeycomb.extendHex()({q: 4, r: -4, s: 0})
hex.nudge()

The fix is probably to make this zero check more flexible to allow for float rounding issues:

https://github.com/flauwekeul/honeycomb/blob/master/src/hex/index.js#L253

check my grid code once sir

	<style type="text/css">

svg {}
.hexfield {
fill: transparent;
stroke: yellowgreen;
stroke-width: 1;
}
.hexfield:focus {
outline:none;
}
.hexfield:hover {
fill: green;
}
.hexfield:active {
fill: red;
outline: none;
}
.hexfield.clicked{
fill: black;
}
</style>

Rows
Columns
Radius
Rebuild
<script> var rebuild = function () { var radius = parseInt($('#radius').val()), columns = parseInt($('#columns').val()), rows = parseInt($('#rows').val()), cssClass = 'hexfield'; $('#container').empty().hexGridWidget(radius, columns, rows, cssClass).on('hexclick', function (e) { $('#logger').text('clicked [' + e.column + ',' + e.row + '] hex with center at [' + e.center.x + ',' + e.center.y + '] px'); }); $('#container .hexfield').click(function () { this.classList.toggle('clicked'); }); }; $('#rebuild').click(rebuild); rebuild(); </script> <script> $.fn.hexGridWidget = function (radius, columns, rows, cssClass) { 'use strict'; var createSVG = function (tag) { return $(document.createElementNS('http://www.w3.org/2000/svg', tag || 'svg')); }; return $(this).each(function () { var element = $(this), hexClick = function () { var hex = $(this); element.trigger($.Event('hexclick', hex.data())); }, height = Math.sqrt(3) / 2 * radius, svgParent = createSVG('svg').attr('tabindex', 1).appendTo(element).css({ width: (1.5 * columns + 0.5) * radius, height: (2 * rows + 1) * height }), column, row, center, toPoint = function (dx, dy) { return Math.round(dx + center.x) + ',' + Math.round(dy + center.y); }; for (row = 0; row < rows; row++) { for (column = 0; column < columns; column++) { center = {x:Math.round((1 + 1.5 * column) * radius), y: Math.round(height * (1 + row * 2 + (column % 2)))}; createSVG('polygon').attr({ points: [ toPoint(-1 * radius / 2, -1 * height), toPoint(radius / 2, -1 * height), toPoint(radius, 0), toPoint(radius / 2, height), toPoint(-1 * radius / 2, height), toPoint(-1 * radius, 0) ].join(' '), 'class':cssClass, tabindex:1 }) .appendTo(svgParent).data({center:center, row:row, column:column}).on('click', hexClick).attr({'hex-row': row, 'hex-column': column}); } } }); }; </script>

i faced issue , plz solve my issue sir

[2.0] Model-View Separation

This one is fundamental.

After dicussion about relations between hexes and grids, I recalled your "viewless" idea.

That sounded strange for me when I saw it since it is very clear that methods like toPoint and Grid.pointToHex() are all about view. And directions of ''NW' is also about view.

Now I think I can guess what the urge behind your idea is.

You are against more props like border in Hex because Hex was originally a model object.

In fact, the redblobgames.com blog post is all about model.

You might had already felt uneasy when you added size and toPoint to Hex but the seemingly obvious necessity dispelled the feeling.
Then border looked to you not so seemingly necessary, so the feeling came back.


Now, let's go further, and take a leap of faith.

Why should ANY view-related job be in Hex?

My answer is no.

I suggest you remove size and toPoint from Hex.

And also deport view-related things from Gird.

Then, add a class GridView to handle those things, dedicatedly.


A not uncommon requirement in games is to have a minimap along with the main map. ( eg The Battle for Wesnoth which I plan to study from)

The models are identical. Just two very different views.

Another case is that now I use SVG.js but maybe someday later I decide to migrate to PixiJS. I won't like to modify code within Hex and Grid in the duration.

And what if a user need to use tilted hexes for pseudo 3D?


So, what will be the relations like?

Hexes and grids never care about view.
Whenever a grid changes, it emits to related GridViews.
For example, if you move a hex in a grid, just change their models and tell GridViews about the change.

So, the side of a hex is set in GridView?

Yes, and can be in more than one GridViews.

It may seem counterintuitive, but how hexes look like and where their views (shapes) are in the screen are not the concerns of the hexes, or the grids.

And how mouse events affect the model?

Let GridView listens those event and calculate which hex the mouse is interacting with.

Then, GridView calls control logics about what to do next with the hex or its grid.

GridView should provide its own events, converting mouse positions into hex (just as Grid.pointToHex() did), so that control logics can easily deal the target hex out-of-boxedly.

[Discussion] How to couple instances of the grid and its hexes nicely?

I was making a map of hexes.
Sometimes, I need to start with a given hex and interact with its grid, or, other peer hexes.

For example, to get neighbors of the hex.
My workaround now is as follows:

var main_grid = null;

Hex = Honeycomb.extendHex({
  .
  .
  neighbors: function() {
    return main_grid.neighborsOf(this);
  },
  .
  .
}
.
.
grid = Grid.rectangle({ ... });

main_grid = grid

I know it is "neat" to decouple grid and hexes, as not all hexes must belong / be bound to a grid.

But when hexes ARE bound to a grid and they seldom or never jump around, they are fixed logically.

In this case, it is natural to couple the grid with them as to have a more "object-oriented" way of coding.

That's why I made a Hex()::neighbors() instead of using grid.neighborsOf(hex).

And a thought experiment: If I had two grids, it would be wrong to calculate grid2.neighborsOf(hex) but the "freedom" of decoupling would "allow" me to make such mistakes, since there was no relation fixed in code and the correct relation exists only in my mind.

That's why, when dealing with frontend programming, I am not a big fan of "functional programming"...


Back to the topic.

My workaround (with a semi-global variale main_grid) works for me, but not in a nice way, I'm afraid.

I'm not sure how to improve it.

What do you think?

And moreover, perhaps, someday you may offer an out-of-box solution in your lib?

Select and change hex properties

I successfully created the hex map. Now my task is to select a random hex in a field, change its color, as well as to select all the neighboring hexs and they also change the color (fields where you can move in the game).

Here is my code:

let n = 1;
const draw = SVG(document.body)
const Hex = Honeycomb.extendHex({
    size: 50,
    //orientation: 'flat',	// default: 'pointy'
    //offset: 1,						// default: -1
    render(draw) {
        const position = this.toPoint()
        const centerPosition = this.center().add(position)

        this.draw = draw

        // draw the hex
        this.draw
            .polygon(this.corners().map(({ x, y }) => `${x},${y}`))
            .fill('none')
            .stroke({ width: 1, color: '#999' })
            .translate(position.x, position.y)

        const fontSize = 12

        // draw x and y coordinates
        this.draw
            .text(`${n} (${this.x},${this.y})`)
            .font({
                size: fontSize,
                anchor: 'middle',
                leading: 1.4,
                fill: '#69c'
            })
            .translate(centerPosition.x, centerPosition.y - fontSize)
        n++;
    }
})
const Grid = Honeycomb.defineGrid(Hex)
const grid = Grid.hexagon({
    radius: 5,
    center: [5, 5],
    onCreate: renderHex
})

function renderHex(hex) {
    hex.render(draw)
}

I'd be grateful for your help.

center method is not working

I want to know the center point of each hexagon, but only one hexagon center point is output.

Let's look at the code below.

const Hex = Honeycomb.extendHex({size: 11})
const Grid = Honeycomb.defineGrid(Hex)
Grid.hexagon({radius: 15}).forEach(hex => {
  console.log(hex.toPoint()); // each hexagon points..
  console.log(hex.center()); // just one hexagon points..
});

Am I misunderstanding?

get grid overall size

Is there any easy way to get the overall size of a grid? Or do I have to calculate it my self?

I'm drawing a (rectangular) grid (using SVG.js) inside absolute positioned container which has a relative positioned parent.
So in order to get the scrolls working properly, I need to define the width and height sizes of the absolute positioned container.

So far I couldn't find anything in the docs. Or have I missed anything?

Grid class issue

Hi!
This code example from readme

const Grid = Honeycomb.defineGrid()
const Hex = Grid.Hex
const grid = Grid.rectangle({ width: 2, height: 2 })

What type is grid?

I see at honeycomb.d.ts
export class Grid<T = Hex<T>> extends Array<T> {

and I try to use it:

import { Grid } from 'honeycomb-grid'

but got an error:

'honeycomb-grid' does not contain an export named 'Grid'

Maybe I doing something wrong?

Examples?

In several closed issues you reference an examples folder, they seem to have vanished though?

I was hoping to find an example of rendering text inside a hex, as I want to print coordinates out to compare the various rendering options. In addition to that, the ability to stroke the edges custom colors/weights?

This is by far the simplest looking hex generator I've seen in awhile, rot.js was my previous experience but it was pretty difficult to gain an understanding of...

Keep up the awesome work, and hopefully I'll have some contributions as well once I get things nailed down :D

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.