diff --git a/src/context.d.ts b/src/context.d.ts index 84b8d136467..ce2c3568d8a 100644 --- a/src/context.d.ts +++ b/src/context.d.ts @@ -1,4 +1,5 @@ import type {GeoStreamWrapper} from "d3"; +import type {MarkOptions} from "./mark.js"; /** Additional rendering context provided to marks and initializers. */ export interface Context { @@ -16,4 +17,7 @@ export interface Context { /** The current projection, if any. */ projection?: GeoStreamWrapper; + + /** The default clip for all marks. */ + clip?: MarkOptions["clip"]; } diff --git a/src/context.js b/src/context.js index c1911f91181..32faa96f3ac 100644 --- a/src/context.js +++ b/src/context.js @@ -1,8 +1,9 @@ import {creator, select} from "d3"; +import {maybeClip} from "./style.js"; export function createContext(options = {}) { - const {document = typeof window !== "undefined" ? window.document : undefined} = options; - return {document}; + const {document = typeof window !== "undefined" ? window.document : undefined, clip} = options; + return {document, clip: maybeClip(clip)}; } export function create(name, {document}) { diff --git a/src/mark.js b/src/mark.js index 831048fa4ae..4cd3d854ab3 100644 --- a/src/mark.js +++ b/src/mark.js @@ -22,7 +22,7 @@ export class Mark { marginRight = margin, marginBottom = margin, marginLeft = margin, - clip, + clip = defaults?.clip, channels: extraChannels, tip, render diff --git a/src/marks/axis.js b/src/marks/axis.js index 11984ca9359..c7c7312d3f9 100644 --- a/src/marks/axis.js +++ b/src/marks/axis.js @@ -564,6 +564,7 @@ function axisMark(mark, k, ariaLabel, data, options, initialize) { channels = {}; } m.ariaLabel = ariaLabel; + if (m.clip === undefined) m.clip = false; // don’t clip axes by default return m; } diff --git a/src/marks/frame.js b/src/marks/frame.js index 43abe051590..372678cf335 100644 --- a/src/marks/frame.js +++ b/src/marks/frame.js @@ -6,14 +6,16 @@ import {applyChannelStyles, applyDirectStyles, applyIndirectStyles, applyTransfo const defaults = { ariaLabel: "frame", fill: "none", - stroke: "currentColor" + stroke: "currentColor", + clip: false }; const lineDefaults = { ariaLabel: "frame", fill: null, stroke: "currentColor", - strokeLinecap: "square" + strokeLinecap: "square", + clip: false }; export class Frame extends Mark { diff --git a/src/plot.d.ts b/src/plot.d.ts index fbf407d8067..e2223693879 100644 --- a/src/plot.d.ts +++ b/src/plot.d.ts @@ -1,6 +1,6 @@ import type {ChannelValue} from "./channel.js"; import type {LegendOptions} from "./legends.js"; -import type {Data, Markish} from "./mark.js"; +import type {Data, MarkOptions, Markish} from "./mark.js"; import type {ProjectionFactory, ProjectionImplementation, ProjectionName, ProjectionOptions} from "./projection.js"; import type {Scale, ScaleDefaults, ScaleName, ScaleOptions} from "./scales.js"; @@ -146,6 +146,9 @@ export interface PlotOptions extends ScaleDefaults { */ document?: Document; + /** The default clip for all marks. */ + clip?: MarkOptions["clip"]; + // scale, axis, and legend definitions /** diff --git a/src/style.js b/src/style.js index b3e046cc919..decebe5ed94 100644 --- a/src/style.js +++ b/src/style.js @@ -2,17 +2,8 @@ import {geoPath, group, namespaces} from "d3"; import {create} from "./context.js"; import {defined, nonempty} from "./defined.js"; import {formatDefault} from "./format.js"; -import { - string, - number, - maybeColorChannel, - maybeNumberChannel, - maybeKeyword, - isNoneish, - isNone, - isRound, - keyof -} from "./options.js"; +import {isNone, isNoneish, isRound, maybeColorChannel, maybeNumberChannel} from "./options.js"; +import {keyof, keyword, number, string} from "./options.js"; import {warn} from "./warnings.js"; export const offset = (typeof window !== "undefined" ? window.devicePixelRatio > 1 : typeof it === "undefined") ? 0 : 0.5; // prettier-ignore @@ -311,13 +302,15 @@ export function* groupIndex(I, position, mark, channels) { export function maybeClip(clip) { if (clip === true) clip = "frame"; else if (clip === false) clip = null; - return maybeKeyword(clip, "clip", ["frame", "sphere"]); + else if (clip != null) clip = keyword(clip, "clip", ["frame", "sphere"]); + return clip; } // Note: may mutate selection.node! function applyClip(selection, mark, dimensions, context) { let clipUrl; - switch (mark.clip) { + const {clip = context.clip} = mark; + switch (clip) { case "frame": { const {width, height, marginLeft, marginRight, marginTop, marginBottom} = dimensions; const id = getClipId(); diff --git a/test/plots/band-clip.ts b/test/plots/band-clip.ts index 34380664ce3..ec83f38ab48 100644 --- a/test/plots/band-clip.ts +++ b/test/plots/band-clip.ts @@ -4,15 +4,8 @@ import * as d3 from "d3"; export async function bandClip() { return Plot.plot({ y: {type: "band"}, - marks: [ - Plot.frame(), - Plot.text(["A", "B", "C"], { - x: (d) => d, - y: (d) => d, - clip: true, - fontSize: 50 - }) - ] + clip: true, + marks: [Plot.frame(), Plot.text(["A", "B", "C"], {x: (d) => d, y: (d) => d, fontSize: 50})] }); }