Skip to content

Commit 4a1e110

Browse files
committed
hexgrid
1 parent 5c073b1 commit 4a1e110

File tree

5 files changed

+85
-52
lines changed

5 files changed

+85
-52
lines changed

src/index.js

+1
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ export {boxX, boxY} from "./marks/box.js";
66
export {Cell, cell, cellX, cellY} from "./marks/cell.js";
77
export {Dot, dot, dotX, dotY} from "./marks/dot.js";
88
export {Frame, frame} from "./marks/frame.js";
9+
export {Hexgrid, hexgrid} from "./marks/hexgrid.js";
910
export {Image, image} from "./marks/image.js";
1011
export {Line, line, lineX, lineY} from "./marks/line.js";
1112
export {Link, link} from "./marks/link.js";

src/marks/hexgrid.js

+45
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
import {create} from "d3";
2+
import {Mark} from "../plot.js";
3+
import {number} from "../options.js";
4+
import {applyDirectStyles, applyIndirectStyles, applyTransform, offset} from "../style.js";
5+
import {sqrt4_3} from "../symbols.js";
6+
7+
const defaults = {
8+
ariaLabel: "hexgrid",
9+
fill: "none",
10+
stroke: "currentColor",
11+
strokeOpacity: 0.1
12+
};
13+
14+
export function hexgrid(options) {
15+
return new Hexgrid(options);
16+
}
17+
18+
export class Hexgrid extends Mark {
19+
constructor({radius = 10, clip = true, ...options} = {}) {
20+
super(undefined, undefined, {clip, ...options}, defaults);
21+
this.radius = number(radius);
22+
}
23+
render(index, scales, channels, dimensions) {
24+
const {dx, dy, radius: rx} = this;
25+
const {marginTop, marginRight, marginBottom, marginLeft, width, height} = dimensions;
26+
const x0 = marginLeft, x1 = width - marginRight, y0 = marginTop, y1 = height - marginBottom;
27+
const ry = rx * sqrt4_3, hy = ry / 2, wx = rx * 2, wy = ry * 1.5;
28+
const path = `m0,${-ry}l${rx},${hy}v${ry}l${-rx},${hy}`;
29+
const i0 = Math.floor(x0 / wx), i1 = Math.ceil(x1 / wx);
30+
const j0 = Math.floor((y0 + hy) / wy), j1 = Math.ceil((y1 - hy) / wy) + 1;
31+
const m = [];
32+
for (let j = j0; j < j1; ++j) {
33+
for (let i = i0; i < i1; ++i) {
34+
m.push(`M${i * wx + (j & 1) * rx},${j * wy}${path}`);
35+
}
36+
}
37+
return create("svg:g")
38+
.call(applyIndirectStyles, this, dimensions)
39+
.call(g => g.append("path")
40+
.call(applyDirectStyles, this)
41+
.call(applyTransform, null, null, offset + dx, offset + dy)
42+
.attr("d", m.join("")))
43+
.node();
44+
}
45+
}

src/symbols.js

+8-8
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,17 @@
11
import {symbolAsterisk, symbolDiamond2, symbolPlus, symbolSquare2, symbolTriangle2, symbolX as symbolTimes} from "d3";
22
import {symbolCircle, symbolCross, symbolDiamond, symbolSquare, symbolStar, symbolTriangle, symbolWye} from "d3";
33

4-
const w = 2 / Math.sqrt(3);
4+
export const sqrt4_3 = 2 / Math.sqrt(3);
55

66
const symbolHexagon = {
77
draw(context, size) {
8-
const s = Math.sqrt(size / Math.PI), t = s * w, h = t / 2;
9-
context.moveTo(0, t);
10-
context.lineTo(s, h);
11-
context.lineTo(s, -h);
12-
context.lineTo(0, -t);
13-
context.lineTo(-s, -h);
14-
context.lineTo(-s, h);
8+
const rx = Math.sqrt(size / Math.PI), ry = rx * sqrt4_3, hy = ry / 2;
9+
context.moveTo(0, ry);
10+
context.lineTo(rx, hy);
11+
context.lineTo(rx, -hy);
12+
context.lineTo(0, -ry);
13+
context.lineTo(-rx, -hy);
14+
context.lineTo(-rx, hy);
1515
context.closePath();
1616
}
1717
};

test/output/hexbin.svg

+28-42
Loading

test/plots/hexbin.js

+3-2
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,16 @@ import {hexbin as Hexbin} from "d3-hexbin";
44

55
export default async function() {
66
const penguins = await d3.csv("data/penguins.csv", d3.autoType);
7+
const radius = 12;
78
return Plot.plot({
8-
grid: true,
99
marks: [
10+
Plot.frame(),
11+
Plot.hexgrid({radius}),
1012
Plot.dot(penguins, {
1113
x: "culmen_depth_mm",
1214
y: "culmen_length_mm",
1315
symbol: "hexagon",
1416
initialize([index], {x: {value: X}, y: {value: Y}}, {x, y}) {
15-
const radius = 12;
1617
const bins = Hexbin().x(i => x(X[i])).y(i => y(Y[i])).radius(radius * 2 / Math.sqrt(3))(index);
1718
return {
1819
facets: [d3.range(bins.length)],

0 commit comments

Comments
 (0)