HexGrid.tsx
· 1.8 KiB · TypeScript
Raw
import { css } from "@linaria/core"
import type { CSSProperties, ReactNode } from "react"
import React from "react"
/** width / heigt */
const hexAspectRatio = 4 / 3 * Math.sqrt(3) / 2
export function HexGrid({
gap,
rows,
cols,
children
}: {
gap: number,
rows: number,
cols: number,
children: ReactNode
}) {
return (
<div className={css`position: relative;`}>
<div
style={{
"--hex-y-gap": `${gap}px`,
"--hex-x-gap": `${gap * Math.sqrt(3) / 2}px`,
/* Add .5 to account for staggered columns */
"--hex-rows": rows + .5,
"--hex-cols": cols
} as CSSProperties}
className={css`
/* available width divided by columns adjusted for overlap */
--hex-width: calc(
(100% - ((var(--hex-cols) - 1) * var(--hex-x-gap)))
/ (var(--hex-cols) * 3 / 4 + 1 / 4)
);
/* total y gaps plus total hex heights */
padding-bottom: calc(
(var(--hex-rows) - 1) * var(--hex-y-gap)
+ var(--hex-rows) * var(--hex-width) / ${hexAspectRatio}
);
`}
>
{children}
</div>
</div>
)
}
export function Hex({
children,
row,
col
}: {
children: ReactNode,
row: number,
col: number
}) {
const colStyle = css`
/* available height minus total y gaps divided by rows */
--hex-height: calc(
(100% - (var(--hex-rows) - 1) * var(--hex-y-gap))
/ var(--hex-rows)
);
position: absolute;
width: var(--hex-width);
height: var(--hex-height);
top: calc((var(--hex-height) + var(--hex-y-gap)) * var(--hex-row));
left: calc((var(--hex-width) * 3 / 4 + var(--hex-x-gap)) * var(--hex-col));
`
return <div
className={colStyle}
style={{
"--hex-row": row + (col % 2 === 0 ? .5 : 0),
"--hex-col": col
} as CSSProperties}
>
<div
className={css`
position: absolute;
inset: 0;
display: grid;
grid-template: 100% / 100%;
`}
>
{children}
</div>
</div>
}
1 | import { css } from "@linaria/core" |
2 | import type { CSSProperties, ReactNode } from "react" |
3 | import React from "react" |
4 | |
5 | /** width / heigt */ |
6 | const hexAspectRatio = 4 / 3 * Math.sqrt(3) / 2 |
7 | |
8 | export function HexGrid({ |
9 | gap, |
10 | rows, |
11 | cols, |
12 | children |
13 | }: { |
14 | gap: number, |
15 | rows: number, |
16 | cols: number, |
17 | children: ReactNode |
18 | }) { |
19 | return ( |
20 | <div className={css`position: relative;`}> |
21 | <div |
22 | style={{ |
23 | "--hex-y-gap": `${gap}px`, |
24 | "--hex-x-gap": `${gap * Math.sqrt(3) / 2}px`, |
25 | /* Add .5 to account for staggered columns */ |
26 | "--hex-rows": rows + .5, |
27 | "--hex-cols": cols |
28 | } as CSSProperties} |
29 | className={css` |
30 | /* available width divided by columns adjusted for overlap */ |
31 | --hex-width: calc( |
32 | (100% - ((var(--hex-cols) - 1) * var(--hex-x-gap))) |
33 | / (var(--hex-cols) * 3 / 4 + 1 / 4) |
34 | ); |
35 | |
36 | /* total y gaps plus total hex heights */ |
37 | padding-bottom: calc( |
38 | (var(--hex-rows) - 1) * var(--hex-y-gap) |
39 | + var(--hex-rows) * var(--hex-width) / ${hexAspectRatio} |
40 | ); |
41 | `} |
42 | > |
43 | {children} |
44 | </div> |
45 | </div> |
46 | ) |
47 | } |
48 | |
49 | export function Hex({ |
50 | children, |
51 | row, |
52 | col |
53 | }: { |
54 | children: ReactNode, |
55 | row: number, |
56 | col: number |
57 | }) { |
58 | const colStyle = css` |
59 | /* available height minus total y gaps divided by rows */ |
60 | --hex-height: calc( |
61 | (100% - (var(--hex-rows) - 1) * var(--hex-y-gap)) |
62 | / var(--hex-rows) |
63 | ); |
64 | |
65 | position: absolute; |
66 | width: var(--hex-width); |
67 | height: var(--hex-height); |
68 | top: calc((var(--hex-height) + var(--hex-y-gap)) * var(--hex-row)); |
69 | left: calc((var(--hex-width) * 3 / 4 + var(--hex-x-gap)) * var(--hex-col)); |
70 | ` |
71 | |
72 | return <div |
73 | className={colStyle} |
74 | style={{ |
75 | "--hex-row": row + (col % 2 === 0 ? .5 : 0), |
76 | "--hex-col": col |
77 | } as CSSProperties} |
78 | > |
79 | <div |
80 | className={css` |
81 | position: absolute; |
82 | inset: 0; |
83 | display: grid; |
84 | grid-template: 100% / 100%; |
85 | `} |
86 | > |
87 | {children} |
88 | </div> |
89 | </div> |
90 | } |
91 |