From 102d596674a8ab8480bcd9cca95e69b8cbc78695 Mon Sep 17 00:00:00 2001 From: Lukas Hermann Date: Wed, 19 Jul 2023 16:04:41 -0700 Subject: [PATCH 1/3] fix: escape quotes in tooltip titles --- src/compile/mark/encode/tooltip.ts | 2 +- test/compile/mark/encode/tooltip.test.ts | 13 +++++++++++++ tsconfig.json | 2 +- 3 files changed, 15 insertions(+), 2 deletions(-) diff --git a/src/compile/mark/encode/tooltip.ts b/src/compile/mark/encode/tooltip.ts index bf31cdd695..53b5ae8f42 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 238e7bf007..58d4e63377 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 c1450bfefc..60bbcda2c7 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"], From 3522355a16cfc83c52aaff14a573263cbb14d897 Mon Sep 17 00:00:00 2001 From: Lukas Hermann Date: Wed, 19 Jul 2023 16:37:13 -0700 Subject: [PATCH 2/3] chore: add example --- examples/specs/bar_axis_title_quoted.vl.json | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 examples/specs/bar_axis_title_quoted.vl.json 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 0000000000..49bd174b18 --- /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"} + } +} From 02a2380ddc54fda11a6e41142883845e75822426 Mon Sep 17 00:00:00 2001 From: GitHub Actions Bot Date: Wed, 19 Jul 2023 23:40:53 +0000 Subject: [PATCH 3/3] chore: update examples [CI] --- examples/compiled/bar_axis_title_quoted.png | Bin 0 -> 8587 bytes examples/compiled/bar_axis_title_quoted.svg | 1 + .../compiled/bar_axis_title_quoted.vg.json | 123 ++++++++++++++++++ 3 files changed, 124 insertions(+) create mode 100644 examples/compiled/bar_axis_title_quoted.png create mode 100644 examples/compiled/bar_axis_title_quoted.svg create mode 100644 examples/compiled/bar_axis_title_quoted.vg.json diff --git a/examples/compiled/bar_axis_title_quoted.png b/examples/compiled/bar_axis_title_quoted.png new file mode 100644 index 0000000000000000000000000000000000000000..92f051fbf6dcb03fa9c0596cc8bdb7f18ee502a6 GIT binary patch literal 8587 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 literal 0 HcmV?d00001 diff --git a/examples/compiled/bar_axis_title_quoted.svg b/examples/compiled/bar_axis_title_quoted.svg new file mode 100644 index 0000000000..f591eba2c6 --- /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 0000000000..bda80bd031 --- /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 + } + ] +}