Skip to content

Commit 819e3f2

Browse files
committed
waffle tips
1 parent 1d01e25 commit 819e3f2

File tree

4 files changed

+593
-16
lines changed

4 files changed

+593
-16
lines changed

src/marks/waffle.js

Lines changed: 64 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import {extent, namespaces} from "d3";
1+
import {extent, namespaces, polygonCentroid} from "d3";
22
import {create} from "../context.js";
33
import {composeRender} from "../mark.js";
44
import {hasXY, identity, indexOf} from "../options.js";
@@ -8,14 +8,36 @@ import {maybeIdentityX, maybeIdentityY} from "../transforms/identity.js";
88
import {maybeIntervalX, maybeIntervalY} from "../transforms/interval.js";
99
import {maybeStackX, maybeStackY} from "../transforms/stack.js";
1010
import {BarX, BarY} from "./bar.js";
11+
import {initializer} from "../transforms/basic.js";
1112

1213
const waffleDefaults = {
1314
ariaLabel: "waffle"
1415
};
1516

1617
export class WaffleX extends BarX {
1718
constructor(data, {unit = 1, gap = 1, round, render, multiple, ...options} = {}) {
18-
super(data, {...options, render: composeRender(render, waffleRender("x"))}, waffleDefaults);
19+
super(
20+
data,
21+
initializer({...options, render: composeRender(render, waffleRender("x"))}, function (data, facets, channels) {
22+
const n = channels.x1.value.length;
23+
const X = new Float64Array(n);
24+
const Y = new Float64Array(n);
25+
return {
26+
data,
27+
facets,
28+
channels: {
29+
...channels,
30+
x1: {value: X, scale: null, source: null},
31+
x2: {value: X, scale: null, source: null},
32+
y1: {value: Y, scale: null, source: null},
33+
y2: {value: Y, scale: null, source: null},
34+
s1: {...channels.x1, source: null},
35+
s2: {...channels.x2, source: null}
36+
}
37+
};
38+
}),
39+
waffleDefaults
40+
);
1941
this.unit = Math.max(0, unit);
2042
this.gap = +gap;
2143
this.round = maybeRound(round);
@@ -25,7 +47,28 @@ export class WaffleX extends BarX {
2547

2648
export class WaffleY extends BarY {
2749
constructor(data, {unit = 1, gap = 1, round, render, multiple, ...options} = {}) {
28-
super(data, {...options, render: composeRender(render, waffleRender("y"))}, waffleDefaults);
50+
super(
51+
data,
52+
initializer({...options, render: composeRender(render, waffleRender("y"))}, function (data, facets, channels) {
53+
const n = channels.y1.value.length;
54+
const X = new Float64Array(n);
55+
const Y = new Float64Array(n);
56+
return {
57+
data,
58+
facets,
59+
channels: {
60+
...channels,
61+
x1: {value: X, scale: null, source: null},
62+
x2: {value: X, scale: null, source: null},
63+
y1: {value: Y, scale: null, source: null},
64+
y2: {value: Y, scale: null, source: null},
65+
s1: {...channels.y1, source: null},
66+
s2: {...channels.y2, source: null}
67+
}
68+
};
69+
}),
70+
waffleDefaults
71+
);
2972
this.unit = Math.max(0, unit);
3073
this.gap = +gap;
3174
this.round = maybeRound(round);
@@ -37,8 +80,8 @@ function waffleRender(y) {
3780
return function (index, scales, values, dimensions, context) {
3881
const {unit, gap, rx, ry, round} = this;
3982
const {document} = context;
40-
const Y1 = values.channels[`${y}1`].value;
41-
const Y2 = values.channels[`${y}2`].value;
83+
const Y1 = values.channels["s1"].value;
84+
const Y2 = values.channels["s2"].value;
4285

4386
// We might not use all the available bandwidth if the cells don’t fit evenly.
4487
const barwidth = this[y === "y" ? "_width" : "_height"](scales, values, dimensions);
@@ -74,6 +117,9 @@ function waffleRender(y) {
74117
if (rx != null) basePatternRect.setAttribute("rx", rx);
75118
if (ry != null) basePatternRect.setAttribute("ry", ry);
76119

120+
const X = values.channels.x1.value;
121+
const Y = values.channels.y1.value;
122+
77123
return create("svg:g", context)
78124
.call(applyIndirectStyles, this, dimensions, context)
79125
.call(this._transform, this, scales)
@@ -95,13 +141,13 @@ function waffleRender(y) {
95141
.enter()
96142
.append("path")
97143
.attr("transform", y === "y" ? template`translate(${x0},${y0})` : template`translate(${y0},${x0})`)
98-
.attr(
99-
"d",
100-
(i) =>
101-
`M${wafflePoints(round(Y1[i] / unit), round(Y2[i] / unit), multiple)
102-
.map(transform)
103-
.join("L")}Z`
104-
)
144+
.attr("d", (i) => {
145+
const pts = wafflePoints(round(Y1[i] / unit), round(Y2[i] / unit), multiple).map(transform);
146+
const [xa, ya] = polygonCentroid(pts);
147+
X[i] = xa + (typeof x0 === "function" ? x0(i) - barwidth / 2 : x0);
148+
Y[i] = ya + (typeof y0 === "function" ? y0(i) : y0);
149+
return `M${pts.join("L")}Z`;
150+
})
105151
.attr("fill", (i) => `url(#${patternId}-${i})`)
106152
.attr("stroke", this.stroke == null ? null : (i) => `url(#${patternId}-${i})`)
107153
)
@@ -198,12 +244,14 @@ function spread(domain) {
198244
return max - min;
199245
}
200246

201-
export function waffleX(data, options = {}) {
247+
export function waffleX(data, {tip, ...options} = {}) {
248+
if (tip === true) tip = "xy";
202249
if (!hasXY(options)) options = {...options, y: indexOf, x2: identity};
203-
return new WaffleX(data, maybeStackX(maybeIntervalX(maybeIdentityX(options))));
250+
return new WaffleX(data, maybeStackX(maybeIntervalX(maybeIdentityX({...options, tip}))));
204251
}
205252

206-
export function waffleY(data, options = {}) {
253+
export function waffleY(data, {tip, ...options} = {}) {
254+
if (tip === true) tip = "xy";
207255
if (!hasXY(options)) options = {...options, x: indexOf, y2: identity};
208-
return new WaffleY(data, maybeStackY(maybeIntervalY(maybeIdentityY(options))));
256+
return new WaffleY(data, maybeStackY(maybeIntervalY(maybeIdentityY({...options, tip}))));
209257
}

test/output/waffleTip.svg

Lines changed: 67 additions & 0 deletions
Loading

0 commit comments

Comments
 (0)