Skip to content

Commit 6429dbe

Browse files
committed
support for CSS basic shapes in the mark’s **clip** option
the **r** option of the image mark sets a default width = 2*r, and a default clip=circle() closes #1413
1 parent 678df1d commit 6429dbe

File tree

7 files changed

+134
-7
lines changed

7 files changed

+134
-7
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -778,7 +778,7 @@ All marks support the following style options:
778778
* **pointerEvents** - the [pointer events](https://developer.mozilla.org/en-US/docs/Web/CSS/pointer-events) (*e.g.*, *none*)
779779
* **clip** - whether and how to clip the mark
780780

781-
If the **clip** option is *frame* (or equivalently true), the mark is clipped to the frame’s dimensions; if the **clip** option is null (or equivalently false), the mark is not clipped. If the **clip** option is *sphere*, then a [geographic projection](#projection-options) is required and the mark will be clipped to the projected sphere (_e.g._, the front hemisphere when using the orthographic projection).
781+
If the **clip** option is *frame* (or equivalently true), the mark is clipped to the frame’s dimensions; if the **clip** option is null (or equivalently false), the mark is not clipped. If the **clip** option is *sphere*, then a [geographic projection](#projection-options) is required and the mark will be clipped to the projected sphere (_e.g._, the front hemisphere when using the orthographic projection). The **clip** option can also be specified as a CSS [basic-shape](https://developer.mozilla.org/en-US/docs/Web/CSS/basic-shape).
782782

783783
For all marks except [text](#plottextdata-options), the **dx** and **dy** options are rendered as a transform property, possibly including a 0.5px offset on low-density screens.
784784

src/mark.d.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -273,11 +273,14 @@ export interface MarkOptions {
273273
*
274274
* - *frame* or true - clip to the plot’s frame (inner area)
275275
* - *sphere* - clip to the projected sphere (*e.g.*, front hemisphere)
276+
* - a CSS [basic shape][1], such as *circle()*
276277
* - null or false - do not clip
277278
*
278279
* The *sphere* clip option requires a geographic projection.
280+
*
281+
* [1]: https://developer.mozilla.org/en-US/docs/Web/CSS/basic-shape
279282
*/
280-
clip?: "frame" | "sphere" | boolean | null;
283+
clip?: "frame" | "sphere" | "circle()" | (string & Record<never, never>) | boolean | null;
281284

282285
/**
283286
* The horizontal offset in pixels; a constant option. On low-density screens,

src/mark.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ export class Mark {
6262
this.marginRight = +marginRight;
6363
this.marginBottom = +marginBottom;
6464
this.marginLeft = +marginLeft;
65-
this.clip = maybeClip(clip);
65+
[this.clip, this.clipShape] = maybeClip(clip);
6666
// Super-faceting currently disallow position channels; in the future, we
6767
// could allow position to be specified in fx and fy in addition to (or
6868
// instead of) x and y.

src/marks/image.js

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,15 @@ export class Image extends Mark {
113113
}
114114

115115
export function image(data, options = {}) {
116-
let {x, y, ...remainingOptions} = options;
116+
let {
117+
x,
118+
y,
119+
r,
120+
width = typeof r === "number" ? 2 * r : undefined,
121+
clip = typeof r === "number" ? "circle()" : undefined,
122+
...remainingOptions
123+
} = options;
117124
if (options.frameAnchor === undefined) [x, y] = maybeTuple(x, y);
118-
return new Image(data, {...remainingOptions, x, y});
125+
126+
return new Image(data, {...remainingOptions, width, clip, x, y});
119127
}

src/style.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -304,7 +304,9 @@ export function* groupIndex(I, position, {z}, channels) {
304304
export function maybeClip(clip) {
305305
if (clip === true) clip = "frame";
306306
else if (clip === false) clip = null;
307-
return maybeKeyword(clip, "clip", ["frame", "sphere"]);
307+
return typeof clip === "string" && /^(circle|ellipse|inset|polygon|rectangle)\([^)]*\)$/.test(clip)
308+
? [, clip]
309+
: [maybeKeyword(clip, "clip", ["frame", "sphere"])];
308310
}
309311

310312
// Note: may mutate selection.node!
@@ -374,6 +376,7 @@ export function applyIndirectStyles(selection, mark, dimensions, context) {
374376

375377
export function applyDirectStyles(selection, mark) {
376378
applyStyle(selection, "mix-blend-mode", mark.mixBlendMode);
379+
applyStyle(selection, "clip-path", mark.clipShape);
377380
applyAttr(selection, "opacity", mark.opacity);
378381
}
379382

Lines changed: 87 additions & 0 deletions
Loading

0 commit comments

Comments
 (0)