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 @@ +Weight_in_lbs (binned)01020304050Miles_per_Gallon01020304050Miles_per_Gallon197019721974197619781980Year197019721974197619781980Year197019721974197619781980Year1000 – 20002000 – 30003000 – 40004000 – 50005000 – 6000824.8Acceleration100200300400Displacement (binned) \ 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")'}); + }); });