diff --git a/src/scales.d.ts b/src/scales.d.ts index f3bd753c4a..fd3785b074 100644 --- a/src/scales.d.ts +++ b/src/scales.d.ts @@ -435,9 +435,11 @@ export interface ScaleOptions extends ScaleDefaults { * y: {transform: (y) => (y) / 1000} * ``` * - * See also the **percent** and **interval** shorthand options. + * See also the **percent** and **interval** shorthand options. If null, no + * transform is applied, including the default transform implied by the + * **percent** or **interval** option. */ - transform?: (t: any) => any; + transform?: ((t: any) => any) | null; /** * Enforces uniformity for data at regular intervals, such as integer values diff --git a/test/scales/transform-test.ts b/test/scales/transform-test.ts new file mode 100644 index 0000000000..ec9f6c24f3 --- /dev/null +++ b/test/scales/transform-test.ts @@ -0,0 +1,22 @@ +import * as Plot from "@observablehq/plot"; +import {assert, it} from "vitest"; + +function cx(plot: SVGSVGElement | HTMLElement): (string | null)[] { + return Array.from(plot.querySelectorAll("circle"), (circle) => circle.getAttribute("cx")); +} + +it("a null scale transform disables the transform implied by the interval option", () => { + const data = [1.5, 2.5, 3.5]; + const plain = cx(Plot.dotX(data).plot({x: {domain: [0, 4]}})); + const interval = cx(Plot.dotX(data).plot({x: {domain: [0, 4], interval: 1}})); + const intervalNull = cx(Plot.dotX(data).plot({x: {domain: [0, 4], interval: 1, transform: null}})); + assert.notDeepEqual(interval, plain); + assert.deepEqual(intervalNull, plain); +}); + +it("a null scale transform disables the transform implied by the percent option", () => { + const data = [0.25, 0.5, 0.75]; + const plain = cx(Plot.dotX(data).plot({x: {domain: [0, 1]}})); + const percentNull = cx(Plot.dotX(data).plot({x: {domain: [0, 1], percent: true, transform: null}})); + assert.deepEqual(percentNull, plain); +});