diff --git a/build/vega-lite-schema.json b/build/vega-lite-schema.json
index d8d55fea45e..f793af899a2 100644
--- a/build/vega-lite-schema.json
+++ b/build/vega-lite-schema.json
@@ -7644,7 +7644,11 @@
"description": "Mark Config"
},
"numberFormat": {
- "description": "D3 Number format for guide labels and text marks. For example `\"s\"` for SI units. Use [D3's number format pattern](https://github.com/d3/d3-format#locale_format).",
+ "description": "If numberFormatType is not specified, D3 Number format for guide labels and text marks. For example `\"s\"` for SI units. Use [D3's number format pattern](https://github.com/d3/d3-format#locale_format).\n\nIf `config.numberFormatType` is specified and `config.customFormatTypes` is `true`, this value will be passed as `format` alongside `datum.value` to the `config.numberFormatType` function.",
+ "type": "string"
+ },
+ "numberFormatType": {
+ "description": "[Custom format type](https://vega.github.io/vega-lite/docs/config.html#custom-format-type) for `config.numberFormat`.\n\n__Default value:__ `undefined` -- This is equilvalent to call D3-format, which is exposed as [`format` in Vega-Expression](https://vega.github.io/vega/docs/expressions/#format). __Note:__ You must also set `customFormatTypes` to `true` to use this feature.",
"type": "string"
},
"padding": {
diff --git a/examples/compiled/config_numberFormatType_test.png b/examples/compiled/config_numberFormatType_test.png
new file mode 100644
index 00000000000..60036d911a9
Binary files /dev/null and b/examples/compiled/config_numberFormatType_test.png differ
diff --git a/examples/compiled/config_numberFormatType_test.svg b/examples/compiled/config_numberFormatType_test.svg
new file mode 100644
index 00000000000..5835ebfce4f
--- /dev/null
+++ b/examples/compiled/config_numberFormatType_test.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/examples/compiled/config_numberFormatType_test.vg.json b/examples/compiled/config_numberFormatType_test.vg.json
new file mode 100644
index 00000000000..0d33c1e9b38
--- /dev/null
+++ b/examples/compiled/config_numberFormatType_test.vg.json
@@ -0,0 +1,293 @@
+{
+ "$schema": "https://vega.github.io/schema/vega/v5.json",
+ "description": "Testing global number formatting config",
+ "background": "white",
+ "padding": 5,
+ "data": [
+ {
+ "name": "source_0",
+ "url": "data/cars.json",
+ "format": {"type": "json", "parse": {"Year": "date"}},
+ "transform": [
+ {
+ "type": "extent",
+ "field": "Weight_in_lbs",
+ "signal": "bin_maxbins_4_Weight_in_lbs_extent"
+ },
+ {
+ "type": "bin",
+ "field": "Weight_in_lbs",
+ "as": [
+ "bin_maxbins_4_Weight_in_lbs",
+ "bin_maxbins_4_Weight_in_lbs_end"
+ ],
+ "signal": "bin_maxbins_4_Weight_in_lbs_bins",
+ "extent": {"signal": "bin_maxbins_4_Weight_in_lbs_extent"},
+ "maxbins": 4
+ },
+ {
+ "type": "extent",
+ "field": "Displacement",
+ "signal": "child_bin_maxbins_6_Displacement_extent"
+ },
+ {
+ "type": "bin",
+ "field": "Displacement",
+ "as": [
+ "bin_maxbins_6_Displacement",
+ "bin_maxbins_6_Displacement_end"
+ ],
+ "signal": "child_bin_maxbins_6_Displacement_bins",
+ "extent": {"signal": "child_bin_maxbins_6_Displacement_extent"},
+ "maxbins": 6
+ },
+ {
+ "type": "filter",
+ "expr": "(isDate(datum[\"Year\"]) || (isValid(datum[\"Year\"]) && isFinite(+datum[\"Year\"]))) && isValid(datum[\"Miles_per_Gallon\"]) && isFinite(+datum[\"Miles_per_Gallon\"]) && isValid(datum[\"Acceleration\"]) && isFinite(+datum[\"Acceleration\"]) && isValid(datum[\"bin_maxbins_6_Displacement\"]) && isFinite(+datum[\"bin_maxbins_6_Displacement\"])"
+ }
+ ]
+ },
+ {
+ "name": "facet_domain",
+ "source": "source_0",
+ "transform": [
+ {
+ "type": "aggregate",
+ "groupby": [
+ "bin_maxbins_4_Weight_in_lbs",
+ "bin_maxbins_4_Weight_in_lbs_end"
+ ]
+ }
+ ]
+ },
+ {
+ "name": "facet_domain_row",
+ "transform": [
+ {
+ "type": "sequence",
+ "start": 0,
+ "stop": {"signal": "ceil(length(data(\"facet_domain\")) / 3)"}
+ }
+ ]
+ },
+ {
+ "name": "facet_domain_column",
+ "transform": [
+ {
+ "type": "sequence",
+ "start": 0,
+ "stop": {"signal": "min(length(data(\"facet_domain\")), 3)"}
+ }
+ ]
+ }
+ ],
+ "signals": [
+ {"name": "child_width", "value": 150},
+ {"name": "child_height", "value": 150}
+ ],
+ "layout": {"padding": 20, "bounds": "full", "align": "all", "columns": 3},
+ "marks": [
+ {
+ "name": "facet-title",
+ "type": "group",
+ "role": "column-title",
+ "title": {
+ "text": "Weight_in_lbs (binned)",
+ "style": "guide-title",
+ "offset": 10
+ }
+ },
+ {
+ "name": "row_header",
+ "type": "group",
+ "role": "row-header",
+ "from": {"data": "facet_domain_row"},
+ "encode": {"update": {"height": {"signal": "child_height"}}},
+ "axes": [
+ {
+ "scale": "y",
+ "orient": "left",
+ "grid": false,
+ "title": "Miles_per_Gallon",
+ "labelOverlap": true,
+ "tickCount": {"signal": "ceil(child_height/40)"},
+ "encode": {
+ "labels": {
+ "update": {"text": {"signal": "pow(datum.value, \"1.0\")"}}
+ }
+ },
+ "zindex": 0
+ }
+ ]
+ },
+ {
+ "name": "column_footer",
+ "type": "group",
+ "role": "column-footer",
+ "from": {"data": "facet_domain_column"},
+ "encode": {"update": {"width": {"signal": "child_width"}}},
+ "axes": [
+ {
+ "scale": "x",
+ "orient": "bottom",
+ "grid": false,
+ "title": "Year",
+ "labelFlush": true,
+ "labelOverlap": true,
+ "tickCount": {"signal": "ceil(child_width/40)"},
+ "zindex": 0
+ }
+ ]
+ },
+ {
+ "name": "cell",
+ "type": "group",
+ "title": {
+ "text": {
+ "signal": "!isValid(parent[\"bin_maxbins_4_Weight_in_lbs\"]) || !isFinite(+parent[\"bin_maxbins_4_Weight_in_lbs\"]) ? \"null\" : pow(parent[\"bin_maxbins_4_Weight_in_lbs\"], \"1.0\") + \" – \" + pow(parent[\"bin_maxbins_4_Weight_in_lbs_end\"], \"1.0\")"
+ },
+ "style": "guide-label",
+ "frame": "group",
+ "offset": 10
+ },
+ "style": "cell",
+ "from": {
+ "facet": {
+ "name": "facet",
+ "data": "source_0",
+ "groupby": [
+ "bin_maxbins_4_Weight_in_lbs",
+ "bin_maxbins_4_Weight_in_lbs_end"
+ ]
+ }
+ },
+ "sort": {
+ "field": ["datum[\"bin_maxbins_4_Weight_in_lbs\"]"],
+ "order": ["ascending"]
+ },
+ "encode": {
+ "update": {
+ "width": {"signal": "child_width"},
+ "height": {"signal": "child_height"}
+ }
+ },
+ "marks": [
+ {
+ "name": "child_marks",
+ "type": "symbol",
+ "style": ["point"],
+ "from": {"data": "facet"},
+ "encode": {
+ "update": {
+ "opacity": {"value": 0.7},
+ "tooltip": {
+ "signal": "{\"Year\": timeFormat(datum[\"Year\"], '%b %d, %Y'), \"Miles_per_Gallon\": pow(datum[\"Miles_per_Gallon\"], \"1.0\"), \"Acceleration\": pow(datum[\"Acceleration\"], \"1.0\"), \"Displacement (binned)\": !isValid(datum[\"bin_maxbins_6_Displacement\"]) || !isFinite(+datum[\"bin_maxbins_6_Displacement\"]) ? \"null\" : pow(datum[\"bin_maxbins_6_Displacement\"], \"1.0\") + \" – \" + pow(datum[\"bin_maxbins_6_Displacement_end\"], \"1.0\")}"
+ },
+ "fill": {"value": "transparent"},
+ "stroke": {"scale": "color", "field": "Acceleration"},
+ "ariaRoleDescription": {"value": "point"},
+ "description": {
+ "signal": "\"Year: \" + (timeFormat(datum[\"Year\"], '%b %d, %Y')) + \"; Miles_per_Gallon: \" + (pow(datum[\"Miles_per_Gallon\"], \"1.0\")) + \"; Acceleration: \" + (pow(datum[\"Acceleration\"], \"1.0\")) + \"; Displacement (binned): \" + (!isValid(datum[\"bin_maxbins_6_Displacement\"]) || !isFinite(+datum[\"bin_maxbins_6_Displacement\"]) ? \"null\" : pow(datum[\"bin_maxbins_6_Displacement\"], \"1.0\") + \" – \" + pow(datum[\"bin_maxbins_6_Displacement_end\"], \"1.0\"))"
+ },
+ "x": {"scale": "x", "field": "Year"},
+ "y": {"scale": "y", "field": "Miles_per_Gallon"},
+ "size": {
+ "signal": "scale(\"size\", 0.5 * datum[\"bin_maxbins_6_Displacement\"] + 0.5 * datum[\"bin_maxbins_6_Displacement_end\"])"
+ }
+ }
+ }
+ }
+ ],
+ "axes": [
+ {
+ "scale": "x",
+ "orient": "bottom",
+ "gridScale": "y",
+ "grid": true,
+ "tickCount": {"signal": "ceil(child_width/40)"},
+ "domain": false,
+ "labels": false,
+ "aria": false,
+ "maxExtent": 0,
+ "minExtent": 0,
+ "ticks": false,
+ "zindex": 0
+ },
+ {
+ "scale": "y",
+ "orient": "left",
+ "gridScale": "x",
+ "grid": true,
+ "tickCount": {"signal": "ceil(child_height/40)"},
+ "domain": false,
+ "labels": false,
+ "aria": false,
+ "maxExtent": 0,
+ "minExtent": 0,
+ "ticks": false,
+ "zindex": 0
+ }
+ ]
+ }
+ ],
+ "scales": [
+ {
+ "name": "x",
+ "type": "time",
+ "domain": {"data": "source_0", "field": "Year"},
+ "range": [0, {"signal": "child_width"}]
+ },
+ {
+ "name": "y",
+ "type": "linear",
+ "domain": {"data": "source_0", "field": "Miles_per_Gallon"},
+ "range": [{"signal": "child_height"}, 0],
+ "nice": true,
+ "zero": true
+ },
+ {
+ "name": "color",
+ "type": "linear",
+ "domain": {"data": "source_0", "field": "Acceleration"},
+ "range": "ramp",
+ "interpolate": "hcl",
+ "zero": false
+ },
+ {
+ "name": "size",
+ "type": "linear",
+ "domain": {
+ "signal": "[child_bin_maxbins_6_Displacement_bins.start, child_bin_maxbins_6_Displacement_bins.stop]"
+ },
+ "range": [0, 361],
+ "bins": {"signal": "child_bin_maxbins_6_Displacement_bins"},
+ "zero": true
+ }
+ ],
+ "legends": [
+ {
+ "stroke": "color",
+ "gradientLength": {"signal": "clamp(child_height, 64, 200)"},
+ "title": "Acceleration",
+ "encode": {
+ "labels": {"update": {"text": {"signal": "pow(datum.value, \"1.0\")"}}},
+ "gradient": {"update": {"opacity": {"value": 0.7}}}
+ }
+ },
+ {
+ "size": "size",
+ "symbolType": "circle",
+ "title": "Displacement (binned)",
+ "encode": {
+ "labels": {"update": {"text": {"signal": "pow(datum.value, \"1.0\")"}}},
+ "symbols": {
+ "update": {
+ "fill": {"value": "transparent"},
+ "opacity": {"value": 0.7}
+ }
+ }
+ }
+ }
+ ],
+ "config": {"customFormatTypes": true}
+}
diff --git a/examples/specs/config_numberFormatType_test.vl.json b/examples/specs/config_numberFormatType_test.vl.json
new file mode 100644
index 00000000000..420f64f9035
--- /dev/null
+++ b/examples/specs/config_numberFormatType_test.vl.json
@@ -0,0 +1,20 @@
+{
+ "$schema": "https://vega.github.io/schema/vega-lite/v5.json",
+ "description": "Testing global number formatting config",
+ "width": 150,
+ "height": 150,
+ "data": {"url": "data/cars.json"},
+ "mark": {"type": "point", "tooltip": true},
+ "encoding": {
+ "x": {"field": "Year", "type": "temporal"},
+ "y": {"field": "Miles_per_Gallon", "type": "quantitative"},
+ "color": {"field": "Acceleration", "type": "quantitative"},
+ "size": {"bin": true, "field": "Displacement", "type": "quantitative"},
+ "facet": {"bin": {"maxbins": 4}, "field": "Weight_in_lbs", "columns": 3}
+ },
+ "config": {
+ "numberFormat": "1.0",
+ "numberFormatType": "pow",
+ "customFormatTypes": true
+ }
+}
diff --git a/examples/specs/normalized/config_numberFormatType_test_normalized.vl.json b/examples/specs/normalized/config_numberFormatType_test_normalized.vl.json
new file mode 100644
index 00000000000..ce96547025f
--- /dev/null
+++ b/examples/specs/normalized/config_numberFormatType_test_normalized.vl.json
@@ -0,0 +1,23 @@
+{
+ "$schema": "https://vega.github.io/schema/vega-lite/v5.json",
+ "description": "Testing global number formatting config",
+ "data": {"url": "data/cars.json"},
+ "config": {
+ "numberFormat": "1.0",
+ "numberFormatType": "pow",
+ "customFormatTypes": true
+ },
+ "columns": 3,
+ "facet": {"bin": {"maxbins": 4}, "field": "Weight_in_lbs"},
+ "spec": {
+ "width": 150,
+ "height": 150,
+ "mark": {"type": "point", "tooltip": true},
+ "encoding": {
+ "x": {"field": "Year", "type": "temporal"},
+ "y": {"field": "Miles_per_Gallon", "type": "quantitative"},
+ "color": {"field": "Acceleration", "type": "quantitative"},
+ "size": {"bin": true, "field": "Displacement", "type": "quantitative"}
+ }
+ }
+}
\ No newline at end of file
diff --git a/site/_includes/docs_toc.md b/site/_includes/docs_toc.md
index 8902f79e9cf..a71657fc066 100644
--- a/site/_includes/docs_toc.md
+++ b/site/_includes/docs_toc.md
@@ -287,7 +287,6 @@
- [Nominal]({{site.baseurl}}/docs/type.html#nominal)
- [GeoJSON]({{site.baseurl}}/docs/type.html#geojson)
- [Value]({{site.baseurl}}/docs/value.html)
- - [Examples]({{site.baseurl}}/docs/value.html#examples)
- [Projection]({{site.baseurl}}/docs/projection.html)
- [Documentation Overview]({{site.baseurl}}/docs/projection.html#documentation-overview)
- [Projection Properties]({{site.baseurl}}/docs/projection.html#projection-properties)
@@ -330,7 +329,6 @@
- [Using Parameters]({{site.baseurl}}/docs/parameter.html#using-parameters)
- [Selection Configuration]({{site.baseurl}}/docs/parameter.html#config)
- [Value]({{site.baseurl}}/docs/value.html)
- - [Examples]({{site.baseurl}}/docs/value.html#examples)
- [Expr]({{site.baseurl}}/docs/parameter.html)
- [Documentation Overview]({{site.baseurl}}/docs/parameter.html#documentation-overview)
- [Defining a Parameter]({{site.baseurl}}/docs/parameter.html#defining-a-parameter)
diff --git a/site/docs/config.md b/site/docs/config.md
index 2dfca0b6724..da5ef00302d 100644
--- a/site/docs/config.md
+++ b/site/docs/config.md
@@ -52,7 +52,7 @@ A Vega-Lite `config` object can have the following top-level properties:
These two config properties define the default number and time formats for text marks as well as axes, headers, and legends:
-{% include table.html props="numberFormat,timeFormat,customFormatTypes" source="Config" %}
+{% include table.html props="numberFormat,numberFormatType,timeFormat,customFormatTypes" source="Config" %}
{:#custom-format-type}
diff --git a/src/compile/axis/encode.ts b/src/compile/axis/encode.ts
index f3387522505..02be3f3e970 100644
--- a/src/compile/axis/encode.ts
+++ b/src/compile/axis/encode.ts
@@ -1,5 +1,5 @@
import {getSecondaryRangeChannel, PositionScaleChannel} from '../../channel';
-import {getFieldOrDatumDef} from '../../channeldef';
+import {channelDefType, getFieldOrDatumDef} from '../../channeldef';
import {formatCustomType, isCustomFormatType} from '../format';
import {UnitModel} from '../unit';
@@ -22,6 +22,23 @@ export function labels(model: UnitModel, channel: PositionScaleChannel, specifie
}),
...specifiedLabelsSpec
};
+ } else if (
+ format === undefined &&
+ formatType === undefined &&
+ config.customFormatTypes &&
+ config.numberFormatType &&
+ channelDefType(fieldOrDatumDef) === 'quantitative'
+ ) {
+ return {
+ text: formatCustomType({
+ fieldOrDatumDef,
+ field: 'datum.value',
+ format: config.numberFormat,
+ formatType: config.numberFormatType,
+ config
+ }),
+ ...specifiedLabelsSpec
+ };
}
return specifiedLabelsSpec;
diff --git a/src/compile/format.ts b/src/compile/format.ts
index bbc645a37b9..3e00554b1d8 100644
--- a/src/compile/format.ts
+++ b/src/compile/format.ts
@@ -56,6 +56,23 @@ export function formatSignalRef({
}
const field = fieldToFormat(fieldOrDatumDef, expr, normalizeStack);
+ const type = channelDefType(fieldOrDatumDef);
+
+ if (
+ type === 'quantitative' &&
+ format === undefined &&
+ formatType === undefined &&
+ config.customFormatTypes &&
+ config.numberFormatType
+ ) {
+ return formatCustomType({
+ fieldOrDatumDef,
+ format: config.numberFormat,
+ formatType: config.numberFormatType,
+ expr,
+ config
+ });
+ }
if (isFieldOrDatumDefForTimeFormat(fieldOrDatumDef)) {
const signal = timeFormatExpression(
@@ -68,7 +85,7 @@ export function formatSignalRef({
return signal ? {signal} : undefined;
}
- format = numberFormat(channelDefType(fieldOrDatumDef), format, config);
+ format = numberFormat(type, format, config);
if (isFieldDef(fieldOrDatumDef) && isBinning(fieldOrDatumDef.bin)) {
const endField = vgField(fieldOrDatumDef, {expr, binSuffix: 'end'});
return {
@@ -121,7 +138,11 @@ export function formatCustomType({
}) {
field ??= fieldToFormat(fieldOrDatumDef, expr, normalizeStack);
- if (isFieldDef(fieldOrDatumDef) && isBinning(fieldOrDatumDef.bin)) {
+ if (
+ field !== 'datum.value' && // For axis/legend, we can't correctly know the end of the bin from `datum`
+ isFieldDef(fieldOrDatumDef) &&
+ isBinning(fieldOrDatumDef.bin)
+ ) {
const endField = vgField(fieldOrDatumDef, {expr, binSuffix: 'end'});
return {
signal: binFormatExpression(field, endField, format, formatType, config)
@@ -140,6 +161,8 @@ export function guideFormat(
) {
if (isCustomFormatType(formatType)) {
return undefined; // handled in encode block
+ } else if (format === undefined && formatType === undefined && config.numberFormatType && config.customFormatTypes) {
+ return undefined; // handled in encode block
}
if (isFieldOrDatumDefForTimeFormat(fieldOrDatumDef)) {
@@ -216,7 +239,11 @@ export function binFormatExpression(
format: string | Dict,
formatType: string,
config: Config
-) {
+): string {
+ if (format === undefined && formatType === undefined && config.customFormatTypes && config.numberFormatType) {
+ return binFormatExpression(startField, endField, config.numberFormat, config.numberFormatType, config);
+ }
+
const start = binNumberFormatExpr(startField, format, formatType, config);
const end = binNumberFormatExpr(endField, format, formatType, config);
return `${fieldValidPredicate(startField, false)} ? "null" : ${start} + "${BIN_RANGE_DELIMITER}" + ${end}`;
diff --git a/src/compile/legend/encode.ts b/src/compile/legend/encode.ts
index 180d8758e58..7529e71f322 100644
--- a/src/compile/legend/encode.ts
+++ b/src/compile/legend/encode.ts
@@ -150,15 +150,25 @@ export function labels(specifiedlabelsSpec: any, {fieldOrDatumDef, model, channe
const {format, formatType} = legend;
- const text = isCustomFormatType(formatType)
- ? formatCustomType({
- fieldOrDatumDef,
- field: 'datum.value',
- format,
- formatType,
- config
- })
- : undefined;
+ let text = undefined;
+
+ if (isCustomFormatType(formatType)) {
+ text = formatCustomType({
+ fieldOrDatumDef,
+ field: 'datum.value',
+ format,
+ formatType,
+ config
+ });
+ } else if (format === undefined && formatType === undefined && config.customFormatTypes && config.numberFormatType) {
+ text = formatCustomType({
+ fieldOrDatumDef,
+ field: 'datum.value',
+ format: config.numberFormat,
+ formatType: config.numberFormatType,
+ config
+ });
+ }
const labelsSpec = {
...(opacity ? {opacity} : {}),
diff --git a/src/config.ts b/src/config.ts
index 66ab07b2a14..b8d4a2ec183 100644
--- a/src/config.ts
+++ b/src/config.ts
@@ -145,10 +145,23 @@ export interface VLOnlyConfig {
fieldTitle?: 'verbal' | 'functional' | 'plain';
/**
- * D3 Number format for guide labels and text marks. For example `"s"` for SI units. Use [D3's number format pattern](https://github.com/d3/d3-format#locale_format).
+ * If numberFormatType is not specified,
+ * D3 Number format for guide labels and text marks. For example `"s"` for SI units.
+ * Use [D3's number format pattern](https://github.com/d3/d3-format#locale_format).
+ *
+ * If `config.numberFormatType` is specified and `config.customFormatTypes` is `true`, this value will be passed as `format` alongside `datum.value` to the `config.numberFormatType` function.
*/
numberFormat?: string;
+ /**
+ * [Custom format type](https://vega.github.io/vega-lite/docs/config.html#custom-format-type)
+ * for `config.numberFormat`.
+ *
+ * __Default value:__ `undefined` -- This is equilvalent to call D3-format, which is exposed as [`format` in Vega-Expression](https://vega.github.io/vega/docs/expressions/#format).
+ * __Note:__ You must also set `customFormatTypes` to `true` to use this feature.
+ */
+ numberFormatType?: string;
+
/**
* Default time format for raw time values (without time units) in text marks, legend labels and header labels.
*
@@ -579,6 +592,7 @@ const VL_ONLY_CONFIG_PROPERTIES: (keyof Config)[] = [
'facet',
'concat',
'numberFormat',
+ 'numberFormatType',
'timeFormat',
'countTitle',
'header',
diff --git a/test/compile/axis/encode.test.ts b/test/compile/axis/encode.test.ts
index e9aeb52e33e..dd4786135db 100644
--- a/test/compile/axis/encode.test.ts
+++ b/test/compile/axis/encode.test.ts
@@ -49,5 +49,17 @@ describe('compile/axis/encode', () => {
const labels = encode.labels(model, 'x', {});
expect(labels.text.signal).toBe('customNumberFormat(datum.value)');
});
+
+ it('applies custom format type from config', () => {
+ const model = parseUnitModelWithScale({
+ mark: 'point',
+ encoding: {
+ x: {field: 'a', type: 'quantitative'}
+ },
+ config: {customFormatTypes: true, numberFormat: 'abc', numberFormatType: 'customNumberFormat'}
+ });
+ const labels = encode.labels(model, 'x', {});
+ expect(labels.text.signal).toBe('customNumberFormat(datum.value, "abc")');
+ });
});
});
diff --git a/test/compile/format.test.ts b/test/compile/format.test.ts
index 8c935585a29..d6810a703b5 100644
--- a/test/compile/format.test.ts
+++ b/test/compile/format.test.ts
@@ -1,5 +1,11 @@
import {vgField} from '../../src/channeldef';
-import {formatSignalRef, guideFormatType, numberFormat, timeFormatExpression} from '../../src/compile/format';
+import {
+ formatSignalRef,
+ guideFormat,
+ guideFormatType,
+ numberFormat,
+ timeFormatExpression
+} from '../../src/compile/format';
import {defaultConfig} from '../../src/config';
import {NOMINAL, ORDINAL, QUANTITATIVE, TEMPORAL} from '../../src/type';
@@ -116,7 +122,22 @@ describe('Format', () => {
});
});
- it('should formats datumDef if format is present', () => {
+ it('correctly formats binned field defs if custom format config is present', () => {
+ expect(
+ formatSignalRef({
+ fieldOrDatumDef: {bin: true, field: 'foo', type: 'quantitative'},
+ format: undefined,
+ formatType: undefined,
+ expr: 'parent',
+ config: {numberFormat: 'abc', numberFormatType: 'customFormatter'}
+ })
+ ).toEqual({
+ signal:
+ '!isValid(parent["bin_maxbins_10_foo"]) || !isFinite(+parent["bin_maxbins_10_foo"]) ? "null" : format(parent["bin_maxbins_10_foo"], "abc") + " – " + format(parent["bin_maxbins_10_foo_end"], "abc")'
+ });
+ });
+
+ it('should format datumDef if format is present', () => {
expect(
formatSignalRef({
fieldOrDatumDef: {datum: 200, type: 'quantitative'},
@@ -129,6 +150,52 @@ describe('Format', () => {
signal: 'format(200, ".2f")'
});
});
+
+ it('should use a custom formatter datumDef if formatType is present', () => {
+ expect(
+ formatSignalRef({
+ fieldOrDatumDef: {datum: 200, type: 'quantitative'},
+ format: 'abc',
+ formatType: 'customFormatter',
+ expr: 'parent',
+ config: {}
+ })
+ ).toEqual({
+ signal: 'customFormatter(200, "abc")'
+ });
+ });
+
+ it('should use a custom formatter datumDef if config.numberFormatType is present', () => {
+ expect(
+ formatSignalRef({
+ fieldOrDatumDef: {datum: 200, type: 'quantitative'},
+ format: undefined,
+ formatType: undefined,
+ expr: 'parent',
+ config: {numberFormat: 'abc', numberFormatType: 'customFormatter', customFormatTypes: true}
+ })
+ ).toEqual({
+ signal: 'customFormatter(200, "abc")'
+ });
+ });
+ });
+
+ describe('guideFormat', () => {
+ it('returns undefined for custom formatType', () => {
+ const format = guideFormat({datum: 200, type: 'quantitative'}, 'quantitative', 'abc', 'custom', {}, false);
+ expect(format).toBeUndefined();
+ });
+ it('returns undefined for custom formatType in the config', () => {
+ const format = guideFormat(
+ {datum: 200, type: 'quantitative'},
+ 'quantitative',
+ undefined,
+ undefined,
+ {numberFormat: 'abc', numberFormatType: 'customFormatter', customFormatTypes: true},
+ false
+ );
+ expect(format).toBeUndefined();
+ });
});
describe('guideFormatType()', () => {
diff --git a/test/compile/legend/encode.test.ts b/test/compile/legend/encode.test.ts
index 32856a6bd11..319baee5321 100644
--- a/test/compile/legend/encode.test.ts
+++ b/test/compile/legend/encode.test.ts
@@ -166,4 +166,23 @@ describe('compile/legend', () => {
expect(label.text).toEqual({signal: 'customDateFormat(datum.value, "abc")'});
});
});
+
+ it('returns correct expression for custom format Type from config.numberFormatType', () => {
+ const fieldDef: Encoding['color'] = {
+ field: 'a',
+ type: 'temporal'
+ };
+
+ const model = parseUnitModelWithScale({
+ mark: 'point',
+ encoding: {color: fieldDef},
+ config: {customFormatTypes: true, numberFormat: 'abc', numberFormatType: 'customDateFormat'}
+ });
+
+ const label = encode.labels(
+ {},
+ {fieldOrDatumDef: fieldDef, model, channel: COLOR, legendCmpt: symbolLegend, legendType: 'symbol'}
+ );
+ expect(label.text).toEqual({signal: 'customDateFormat(datum.value, "abc")'});
+ });
});