Skip to content

Commit 1533c86

Browse files
committed
unit = auto
closes #2214
1 parent 415db54 commit 1533c86

File tree

4 files changed

+4277
-11
lines changed

4 files changed

+4277
-11
lines changed

src/marks/waffle.d.ts

+6-2
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,12 @@ import type {BarXOptions, BarYOptions} from "./bar.js";
55
interface WaffleOptions {
66
/** The number of cells per row or column; defaults to undefined for automatic. */
77
multiple?: number;
8-
/** The quantity each cell represents; defaults to 1. */
9-
unit?: number;
8+
/**
9+
* The quantity each cell represents; defaults to "auto", which defaults to 1
10+
* unless this makes the cell size unreasonable — in which case it adopts a
11+
* suitable power of 1,000.
12+
*/
13+
unit?: number | "auto";
1014
/** The gap in pixels between cells; defaults to 1. */
1115
gap?: number;
1216
/** If true, round to integers to avoid partial cells. */

src/marks/waffle.js

+21-8
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import {extent, namespaces} from "d3";
22
import {valueObject} from "../channel.js";
33
import {create} from "../context.js";
44
import {composeRender} from "../mark.js";
5-
import {hasXY, identity, indexOf} from "../options.js";
5+
import {hasXY, identity, indexOf, keyword} from "../options.js";
66
import {applyChannelStyles, applyDirectStyles, applyIndirectStyles, getPatternId} from "../style.js";
77
import {template} from "../template.js";
88
import {initializer} from "../transforms/basic.js";
@@ -16,21 +16,21 @@ const waffleDefaults = {
1616
};
1717

1818
export class WaffleX extends BarX {
19-
constructor(data, {unit = 1, gap = 1, round, render, multiple, ...options} = {}) {
19+
constructor(data, {unit, gap = 1, round, render, multiple, ...options} = {}) {
2020
options = initializer({...options, render: composeRender(render, waffleRender("x"))}, waffleInitializer("x"));
2121
super(data, options, waffleDefaults);
22-
this.unit = Math.max(0, unit);
22+
this.unit = maybeUnit(unit);
2323
this.gap = +gap;
2424
this.round = maybeRound(round);
2525
this.multiple = maybeMultiple(multiple);
2626
}
2727
}
2828

2929
export class WaffleY extends BarY {
30-
constructor(data, {unit = 1, gap = 1, round, render, multiple, ...options} = {}) {
30+
constructor(data, {unit, gap = 1, round, render, multiple, ...options} = {}) {
3131
options = initializer({...options, render: composeRender(render, waffleRender("y"))}, waffleInitializer("y"));
3232
super(data, options, waffleDefaults);
33-
this.unit = Math.max(0, unit);
33+
this.unit = maybeUnit(unit);
3434
this.gap = +gap;
3535
this.round = maybeRound(round);
3636
this.multiple = maybeMultiple(multiple);
@@ -39,8 +39,7 @@ export class WaffleY extends BarY {
3939

4040
function waffleInitializer(y) {
4141
return function (data, facets, channels, scales, dimensions) {
42-
const {round, unit} = this;
43-
42+
const {round} = this;
4443
const values = valueObject(channels, scales);
4544
const Y1 = values.channels[`${y}1`].value;
4645
const Y2 = values.channels[`${y}2`].value;
@@ -49,8 +48,18 @@ function waffleInitializer(y) {
4948
const barwidth = this[y === "y" ? "_width" : "_height"](scales, values, dimensions);
5049
const barx = this[y === "y" ? "_x" : "_y"](scales, values, dimensions);
5150

51+
// Auto unit: if the scale of a unit makes it so small that it is invisible,
52+
// or conversely insanely large, adopt a different power of 10**3.
53+
const p = scaleof(scales.scales[y]); // pixel length per unit of 1
54+
let {unit} = this;
55+
if (unit === "auto") {
56+
const area = barwidth * p; // pixel area per unit of 1
57+
if (area < 5 || area > 5e4) unit = 1000 ** Math.ceil((1 - Math.log10(area)) / 3);
58+
else unit = 1;
59+
}
60+
5261
// The length of a unit along y in pixels.
53-
const scale = unit * scaleof(scales.scales[y]);
62+
const scale = unit * p;
5463

5564
// The number of cells on each row (or column) of the waffle.
5665
const {multiple = Math.max(1, Math.floor(Math.sqrt(barwidth / scale)))} = this;
@@ -281,3 +290,7 @@ export function waffleY(data, {tip, ...options} = {}) {
281290
if (!hasXY(options)) options = {...options, x: indexOf, y2: identity};
282291
return new WaffleY(data, {tip, ...maybeStackY(maybeIntervalY(maybeIdentityY(options)))});
283292
}
293+
294+
function maybeUnit(unit = "auto") {
295+
return typeof unit === "number" ? Math.max(0, unit) : keyword(unit, "unit", ["auto"]);
296+
}

0 commit comments

Comments
 (0)