Skip to content

Commit 7d48d4a

Browse files
authored
tip title format (#2074)
* tip title format * channel, not title
1 parent fb701a0 commit 7d48d4a

File tree

8 files changed

+87
-11
lines changed

8 files changed

+87
-11
lines changed

docs/marks/tip.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,7 @@ Plot.rectY(olympians, Plot.binX({y: "sum"}, {x: "weight", y: (d) => d.sex === "m
131131
```
132132
:::
133133

134-
The order and formatting of channels in the tip can be customized with the **format** option <VersionBadge version="0.6.11" pr="1823" />, which accepts a key-value object mapping channel names to formats. Each [format](../features/formats.md) can be a string (for number or time formats), a function that receives the value as input and returns a string, true to use the default format, and null or false to suppress. The order of channels in the tip follows their order in the format object followed by any additional channels.
134+
The order and formatting of channels in the tip can be customized with the **format** option <VersionBadge version="0.6.11" pr="1823" />, which accepts a key-value object mapping channel names to formats. Each [format](../features/formats.md) can be a string (for number or time formats), a function that receives the value as input and returns a string, true to use the default format, and null or false to suppress. The order of channels in the tip follows their order in the format object followed by any additional channels. When using the **title** channel, the **format** option may be specified as a string or a function; the given format will then apply to the **title** channel. <VersionBadge pr="2074" />
135135

136136
A channel’s label can be specified alongside its value as a {value, label} object; if a channel label is not specified, the associated scale’s label is used, if any; if there is no associated scale, or if the scale has no label, the channel name is used instead.
137137

src/marks/tip.d.ts

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ export interface TipOptions extends MarkOptions, TextStyles {
7474
* is interpreted as a (UTC) time format for temporal channels, and otherwise
7575
* a number format.
7676
*/
77-
format?: {[name in ChannelName]?: boolean | string | ((d: any, i: number) => string)};
77+
format?: {[name in ChannelName]?: null | boolean | TipFormat} | TipFormat;
7878

7979
/** The image filter for the tip’s box; defaults to a drop shadow. */
8080
pathFilter?: string;
@@ -86,6 +86,18 @@ export interface TipOptions extends MarkOptions, TextStyles {
8686
textPadding?: number;
8787
}
8888

89+
/**
90+
* How to format channel values; one of:
91+
*
92+
* - a [d3-format][1] string for numeric scales
93+
* - a [d3-time-format][2] string for temporal scales
94+
* - a function passed a channel *value* and *index*, returning a string
95+
*
96+
* [1]: https://d3js.org/d3-time
97+
* [2]: https://d3js.org/d3-time-format
98+
*/
99+
export type TipFormat = string | ((d: any, i: number) => string);
100+
89101
/**
90102
* Returns a new tip mark for the given *data* and *options*.
91103
*

src/marks/tip.js

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ export class Tip extends Mark {
8484
for (const key in defaults) if (key in this.channels) this[key] = defaults[key]; // apply default even if channel
8585
this.splitLines = splitter(this);
8686
this.clipLine = clipper(this);
87-
this.format = {...format}; // defensive copy before mutate; also promote nullish to empty
87+
this.format = typeof format === "string" || typeof format === "function" ? {title: format} : {...format}; // defensive copy before mutate; also promote nullish to empty
8888
}
8989
render(index, scales, values, dimensions, context) {
9090
const mark = this;
@@ -120,10 +120,10 @@ export class Tip extends Mark {
120120
// channels as name-value pairs.
121121
let sources, format;
122122
if ("title" in values) {
123-
sources = values.channels;
123+
sources = getSourceChannels.call(this, {title: values.channels.title}, scales);
124124
format = formatTitle;
125125
} else {
126-
sources = getSourceChannels.call(this, values, scales);
126+
sources = getSourceChannels.call(this, values.channels, scales);
127127
format = formatChannels;
128128
}
129129

@@ -319,7 +319,7 @@ function getPath(anchor, m, r, width, height) {
319319
}
320320

321321
// Note: mutates this.format!
322-
function getSourceChannels({channels}, scales) {
322+
function getSourceChannels(channels, scales) {
323323
const sources = {};
324324

325325
// Promote x and y shorthand for paired channels (in order).
@@ -384,7 +384,7 @@ function maybeExpandPairedFormat(format, channels, key) {
384384
}
385385

386386
function formatTitle(i, index, {title}) {
387-
return formatDefault(title.value[i], i);
387+
return this.format.title(title.value[i], i);
388388
}
389389

390390
function* formatChannels(i, index, channels, scales, values) {

src/scales.d.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -588,7 +588,7 @@ export interface ScaleOptions extends ScaleDefaults {
588588
* [1]: https://d3js.org/d3-time
589589
* [2]: https://d3js.org/d3-time-format
590590
*/
591-
tickFormat?: string | ((t: any, i: number) => any) | null;
591+
tickFormat?: string | ((d: any, i: number) => any) | null;
592592

593593
/**
594594
* The rotation angle of axis tick labels in degrees clocksize; defaults to 0.

test/output/tipFormatTitleIgnoreFormat.svg renamed to test/output/tipFormatTitleFormat.svg

Lines changed: 1 addition & 1 deletion
Loading
Lines changed: 28 additions & 0 deletions
Loading
Lines changed: 28 additions & 0 deletions
Loading

test/plots/tip-format.ts

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -104,8 +104,16 @@ export async function tipFormatTitleExplicit() {
104104
return tip({length: 1}, {title: [new Date("2010-01-01")]});
105105
}
106106

107-
export async function tipFormatTitleIgnoreFormat() {
108-
return tip({length: 1}, {title: [0], format: {title: ".2f"}});
107+
export async function tipFormatTitleFormat() {
108+
return tip({length: 1}, {title: [0.009], format: {title: ".2f"}});
109+
}
110+
111+
export async function tipFormatTitleFormatFunction() {
112+
return tip({length: 1}, {title: [0.019], format: (d) => d.toFixed(2)});
113+
}
114+
115+
export async function tipFormatTitleFormatShorthand() {
116+
return tip({length: 1}, {title: [0.029], format: ".2f"});
109117
}
110118

111119
export async function tipFormatTitlePrimitive() {

0 commit comments

Comments
 (0)