Skip to content

Commit 84bc745

Browse files
Filmbostock
andauthored
top-level className (#582)
* keep inline stylesheet * inline stylesheets * top-level className * coerce className to string Co-authored-by: Mike Bostock <[email protected]>
1 parent 47173fe commit 84bc745

File tree

3 files changed

+18
-7
lines changed

3 files changed

+18
-7
lines changed

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,8 @@ Plot.plot({
106106
})
107107
```
108108

109+
The generated SVG element has a random class name which applies a default stylesheet. Use the top-level **className** option to specify that class name.
110+
109111
### Scale options
110112

111113
Plot passes data through [scales](https://observablehq.com/@observablehq/plot-scales) as needed before rendering marks. A scale maps abstract values such as time or temperature to visual values such as position or color. Within a given plot, marks share scales. For example, if a plot has two Plot.line marks, both share the same *x* and *y* scales for a consistent representation of data. (Plot does not currently support dual-axis charts, which are [not advised](https://blog.datawrapper.de/dualaxis/).)

src/plot.js

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,14 @@ import {Axes, autoAxisTicks, autoScaleLabels} from "./axes.js";
33
import {facets} from "./facet.js";
44
import {markify} from "./mark.js";
55
import {Scales, autoScaleRange, applyScales, exposeScales, isOrdinalScale} from "./scales.js";
6-
import {filterStyles, offset} from "./style.js";
6+
import {filterStyles, maybeClassName, offset} from "./style.js";
77

88
export function plot(options = {}) {
99
const {facet, style, caption} = options;
1010

11+
// className for inline styles
12+
const className = maybeClassName(options.className);
13+
1114
// When faceting, wrap all marks in a faceting mark.
1215
if (facet !== undefined) {
1316
const {marks} = options;
@@ -68,11 +71,8 @@ export function plot(options = {}) {
6871

6972
const {width, height} = dimensions;
7073

71-
// A unique identifier for this plot, for inline styles.
72-
const uid = `plot-${Math.random().toString(16).slice(2)}`;
73-
7474
const svg = create("svg")
75-
.attr("class", uid)
75+
.attr("class", className)
7676
.attr("fill", "currentColor")
7777
.attr("font-family", "system-ui, sans-serif")
7878
.attr("font-size", 10)
@@ -82,14 +82,14 @@ export function plot(options = {}) {
8282
.attr("height", height)
8383
.attr("viewBox", `0 0 ${width} ${height}`)
8484
.call(svg => svg.append("style").text(`
85-
.${uid} {
85+
.${className} {
8686
display: block;
8787
background: white;
8888
height: auto;
8989
height: intrinsic;
9090
max-width: 100%;
9191
}
92-
.${uid} text {
92+
.${className} text {
9393
white-space: pre;
9494
}
9595
`))

src/style.js

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,3 +153,12 @@ export function filterStyles(index, {fill: F, fillOpacity: FO, stroke: S, stroke
153153
function none(color) {
154154
return color == null || color === "none";
155155
}
156+
157+
const validClassName = /^-?([_a-z]|[\240-\377]|\\[0-9a-f]{1,6}(\r\n|[ \t\r\n\f])?|\\[^\r\n\f0-9a-f])([_a-z0-9-]|[\240-\377]|\\[0-9a-f]{1,6}(\r\n|[ \t\r\n\f])?|\\[^\r\n\f0-9a-f])*$/;
158+
159+
export function maybeClassName(name) {
160+
if (name === undefined) return `plot-${Math.random().toString(16).slice(2)}`;
161+
name = `${name}`;
162+
if (!validClassName.test(name)) throw new Error(`invalid class name: ${name}`);
163+
return name;
164+
}

0 commit comments

Comments
 (0)