diff --git a/docs/features/marks.md b/docs/features/marks.md index 99f805f0a6..da319afdb0 100644 --- a/docs/features/marks.md +++ b/docs/features/marks.md @@ -482,6 +482,7 @@ All marks support the following style options: * **dx** - horizontal offset (in pixels; defaults to 0) * **dy** - vertical offset (in pixels; defaults to 0) * **target** - link target (e.g., “_blank” for a new window); for use with the **href** channel +* **className** - the [class attribute](https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/class), if any (defaults to null) * **ariaDescription** - a textual description of the mark’s contents * **ariaHidden** - if true, hide this content from the accessibility tree * **pointerEvents** - the [pointer events](https://developer.mozilla.org/en-US/docs/Web/CSS/pointer-events) (*e.g.*, *none*) diff --git a/src/mark.d.ts b/src/mark.d.ts index 54f14276ca..d244fdba76 100644 --- a/src/mark.d.ts +++ b/src/mark.d.ts @@ -239,6 +239,13 @@ export interface MarkOptions { */ marginLeft?: number; + /** + * The [class attribute][1]; a constant string. + * + * [1]: https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/class + */ + className?: string; + /** * The [aria-description][1]; a constant textual description. * diff --git a/src/mark.js b/src/mark.js index 768105025e..c8c3bca719 100644 --- a/src/mark.js +++ b/src/mark.js @@ -4,7 +4,7 @@ import {maybeFacetAnchor} from "./facet.js"; import {maybeClip, maybeNamed, maybeValue} from "./options.js"; import {arrayify, isDomainSort, isObject, isOptions, keyword, range, singleton} from "./options.js"; import {project} from "./projection.js"; -import {styles} from "./style.js"; +import {maybeClassName, styles} from "./style.js"; import {basic, initializer} from "./transforms/basic.js"; export class Mark { @@ -22,6 +22,7 @@ export class Mark { marginRight = margin, marginBottom = margin, marginLeft = margin, + className, clip = defaults?.clip, channels: extraChannels, tip, @@ -71,6 +72,7 @@ export class Mark { this.marginLeft = +marginLeft; this.clip = maybeClip(clip); this.tip = maybeTip(tip); + this.className = className ? maybeClassName(className) : null; // Super-faceting currently disallow position channels; in the future, we // could allow position to be specified in fx and fy in addition to (or // instead of) x and y. diff --git a/src/style.js b/src/style.js index a1af100fcd..53601f3f62 100644 --- a/src/style.js +++ b/src/style.js @@ -348,6 +348,7 @@ function applyClip(selection, mark, dimensions, context) { // Note: may mutate selection.node! export function applyIndirectStyles(selection, mark, dimensions, context) { applyClip(selection, mark, dimensions, context); + applyAttr(selection, "class", mark.className); applyAttr(selection, "fill", mark.fill); applyAttr(selection, "fill-opacity", mark.fillOpacity); applyAttr(selection, "stroke", mark.stroke); diff --git a/test/output/classNameOnMarks.svg b/test/output/classNameOnMarks.svg new file mode 100644 index 0000000000..d06c154f19 --- /dev/null +++ b/test/output/classNameOnMarks.svg @@ -0,0 +1,66 @@ + + + + + bananas + oranges + grapes + apples + + + + 0 + 2 + 4 + 6 + 8 + 10 + 12 + 14 + 16 + 18 + 20 + + + units → + + + + + + + + + + + \ No newline at end of file diff --git a/test/plots/class-name.ts b/test/plots/class-name.ts new file mode 100644 index 0000000000..df37884502 --- /dev/null +++ b/test/plots/class-name.ts @@ -0,0 +1,20 @@ +import * as Plot from "@observablehq/plot"; +import * as d3 from "d3"; + +export async function classNameOnMarks() { + const sales = await d3.csv("data/fruit-sales.csv", d3.autoType); + return Plot.plot({ + marginLeft: 50, + y: { + label: null, + reverse: true + }, + marks: [ + Plot.barX( + sales, + Plot.groupY({x: "sum"}, {x: "units", y: "fruit", sort: {y: "x", reverse: true}, className: "fruitbars"}) + ), + Plot.ruleX([0]) + ] + }); +} diff --git a/test/plots/index.ts b/test/plots/index.ts index f1b253323e..7b99e1ada1 100644 --- a/test/plots/index.ts +++ b/test/plots/index.ts @@ -51,6 +51,7 @@ export * from "./cars-mpg.js"; export * from "./cars-parcoords.js"; export * from "./channel-domain.js"; export * from "./clamp.js"; +export * from "./class-name.js"; export * from "./collapsed-histogram.js"; export * from "./color-piecewise.js"; export * from "./country-centroids.js";