diff --git a/examples/compiled/bar_axis_title_quoted.png b/examples/compiled/bar_axis_title_quoted.png new file mode 100644 index 00000000000..92f051fbf6d Binary files /dev/null and b/examples/compiled/bar_axis_title_quoted.png differ diff --git a/examples/compiled/bar_axis_title_quoted.svg b/examples/compiled/bar_axis_title_quoted.svg new file mode 100644 index 00000000000..f591eba2c6b --- /dev/null +++ b/examples/compiled/bar_axis_title_quoted.svg @@ -0,0 +1 @@ +ABCDEFGHI"Quoted" Title020406080100bA Simple Bar Chart \ No newline at end of file diff --git a/examples/compiled/bar_axis_title_quoted.vg.json b/examples/compiled/bar_axis_title_quoted.vg.json new file mode 100644 index 00000000000..bda80bd0318 --- /dev/null +++ b/examples/compiled/bar_axis_title_quoted.vg.json @@ -0,0 +1,123 @@ +{ + "$schema": "https://vega.github.io/schema/vega/v5.json", + "background": "white", + "padding": 5, + "height": 200, + "title": {"text": "A Simple Bar Chart", "frame": "group"}, + "style": "cell", + "data": [ + { + "name": "source_0", + "values": [ + {"a": "A", "b": 28}, + {"a": "B", "b": 55}, + {"a": "C", "b": 43}, + {"a": "D", "b": 91}, + {"a": "E", "b": 81}, + {"a": "F", "b": 53}, + {"a": "G", "b": 19}, + {"a": "H", "b": 87}, + {"a": "I", "b": 52} + ] + }, + { + "name": "data_0", + "source": "source_0", + "transform": [ + { + "type": "stack", + "groupby": ["a"], + "field": "b", + "sort": {"field": [], "order": []}, + "as": ["b_start", "b_end"], + "offset": "zero" + }, + { + "type": "filter", + "expr": "isValid(datum[\"b\"]) && isFinite(+datum[\"b\"])" + } + ] + } + ], + "signals": [ + {"name": "x_step", "value": 20}, + { + "name": "width", + "update": "bandspace(domain('x').length, 0.1, 0.05) * x_step" + } + ], + "marks": [ + { + "name": "marks", + "type": "rect", + "style": ["bar"], + "from": {"data": "data_0"}, + "encode": { + "update": { + "fill": {"value": "#4c78a8"}, + "ariaRoleDescription": {"value": "bar"}, + "description": { + "signal": "\"\\\"Quoted\\\" Title: \" + (isValid(datum[\"a\"]) ? datum[\"a\"] : \"\"+datum[\"a\"]) + \"; b: \" + (format(datum[\"b\"], \"\"))" + }, + "x": {"scale": "x", "field": "a"}, + "width": {"signal": "max(0.25, bandwidth('x'))"}, + "y": {"scale": "y", "field": "b_end"}, + "y2": {"scale": "y", "field": "b_start"} + } + } + } + ], + "scales": [ + { + "name": "x", + "type": "band", + "domain": {"data": "data_0", "field": "a", "sort": true}, + "range": {"step": {"signal": "x_step"}}, + "paddingInner": 0.1, + "paddingOuter": 0.05 + }, + { + "name": "y", + "type": "linear", + "domain": {"data": "data_0", "fields": ["b_start", "b_end"]}, + "range": [{"signal": "height"}, 0], + "nice": true, + "zero": true + } + ], + "axes": [ + { + "scale": "y", + "orient": "left", + "gridScale": "x", + "grid": true, + "tickCount": {"signal": "ceil(height/40)"}, + "domain": false, + "labels": false, + "aria": false, + "maxExtent": 0, + "minExtent": 0, + "ticks": false, + "zindex": 0 + }, + { + "scale": "x", + "orient": "bottom", + "grid": false, + "title": "\"Quoted\" Title", + "labelAlign": "right", + "labelAngle": 270, + "labelBaseline": "middle", + "zindex": 0 + }, + { + "scale": "y", + "orient": "left", + "grid": false, + "title": "b", + "labelOverlap": true, + "tickCount": {"signal": "ceil(height/40)"}, + "zindex": 0 + } + ] +} diff --git a/examples/specs/bar_axis_title_quoted.vl.json b/examples/specs/bar_axis_title_quoted.vl.json new file mode 100644 index 00000000000..49bd174b188 --- /dev/null +++ b/examples/specs/bar_axis_title_quoted.vl.json @@ -0,0 +1,16 @@ +{ + "$schema": "https://vega.github.io/schema/vega-lite/v5.json", + "title": "A Simple Bar Chart", + "data": { + "values": [ + {"a": "A", "b": 28}, {"a": "B", "b": 55}, {"a": "C", "b": 43}, + {"a": "D", "b": 91}, {"a": "E", "b": 81}, {"a": "F", "b": 53}, + {"a": "G", "b": 19}, {"a": "H", "b": 87}, {"a": "I", "b": 52} + ] + }, + "mark": "bar", + "encoding": { + "x": {"field": "a", "type": "nominal", "title": "\"Quoted\" Title"}, + "y": {"field": "b", "type": "quantitative"} + } +} diff --git a/src/compile/mark/encode/tooltip.ts b/src/compile/mark/encode/tooltip.ts index bf31cdd695a..53b5ae8f422 100644 --- a/src/compile/mark/encode/tooltip.ts +++ b/src/compile/mark/encode/tooltip.ts @@ -88,7 +88,7 @@ export function tooltipData( }; const title = fieldDef.title || defaultTitle(fieldDef, formatConfig); - const key = array(title).join(', '); + const key = array(title).join(', ').replaceAll(/"/g, '\\"'); let value: string; diff --git a/test/compile/mark/encode/tooltip.test.ts b/test/compile/mark/encode/tooltip.test.ts index 238e7bf007d..58d4e633774 100644 --- a/test/compile/mark/encode/tooltip.test.ts +++ b/test/compile/mark/encode/tooltip.test.ts @@ -152,6 +152,19 @@ describe('compile/mark/encode/tooltip', () => { signal: '{"baz": isValid(datum["Foobar"]) ? datum["Foobar"] : ""+datum["Foobar"]}' }); }); + + it('generates correct keys and values for channels with title with quotes', () => { + const model = parseUnitModelWithScaleAndLayoutSize({ + mark: {type: 'point', tooltip: true}, + encoding: { + color: {field: 'Foobar', type: 'nominal', title: '"baz"'} + } + }); + const props = tooltip(model); + expect(props.tooltip).toEqual({ + signal: '{"\\"baz\\"": isValid(datum["Foobar"]) ? datum["Foobar"] : ""+datum["Foobar"]}' + }); + }); }); describe('tooltipForEncoding', () => { diff --git a/tsconfig.json b/tsconfig.json index c1450bfefcb..60bbcda2c73 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -15,7 +15,7 @@ "resolveJsonModule": true, "suppressImplicitAnyIndexErrors": true, "isolatedModules": true, - "lib": ["ESNext.Array", "DOM", "DOM.Iterable"], + "lib": ["ESNext.Array", "DOM", "DOM.Iterable", "ES2021.String"], "noEmit": true }, "files": ["src/index.ts"],