From e081d3c0b707f64043f9ff72a95974cebf82907a Mon Sep 17 00:00:00 2001 From: user Date: Tue, 7 Oct 2025 16:39:28 -0400 Subject: [PATCH 01/12] Enable text stroke on scale titles --- src/core/core.scale.js | 4 ++++ src/types/index.d.ts | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/src/core/core.scale.js b/src/core/core.scale.js index dcf4bd00b2b..b40c63bb926 100644 --- a/src/core/core.scale.js +++ b/src/core/core.scale.js @@ -1596,6 +1596,8 @@ export default class Scale extends Element { const padding = toPadding(title.padding); const align = title.align; let offset = font.lineHeight / 2; + let strokeWidth = title.strokeWidth; + let strokeColor = title.strokeColor; if (position === 'bottom' || position === 'center' || isObject(position)) { offset += padding.bottom; @@ -1615,6 +1617,8 @@ export default class Scale extends Element { textAlign: titleAlign(align, position, reverse), textBaseline: 'middle', translation: [titleX, titleY], + strokeColor: strokeColor, + strokeWidth: strokeWidth }); } diff --git a/src/types/index.d.ts b/src/types/index.d.ts index 3b373620c0f..858599201c8 100644 --- a/src/types/index.d.ts +++ b/src/types/index.d.ts @@ -3270,6 +3270,10 @@ export interface CartesianScaleOptions extends CoreScaleOptions { text: string | string[]; /** Color of the axis label. */ color: Color; + /** Color of the axis label's stroke. */ + strokeColor: Color; + /** Stroke width of the axis label. */ + strokeWidth: number; /** Information about the axis title font. */ font: ScriptableAndScriptableOptions, ScriptableCartesianScaleContext>; /** Padding to apply around scale labels. */ From 8d34a08c6280c0ca033bccad7ec6ba475d056937 Mon Sep 17 00:00:00 2001 From: user Date: Thu, 9 Oct 2025 19:34:42 -0400 Subject: [PATCH 02/12] update documentation --- docs/axes/labelling.md | 2 ++ src/types/index.d.ts | 8 ++++---- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/docs/axes/labelling.md b/docs/axes/labelling.md index 98583e964fd..a50c4a92145 100644 --- a/docs/axes/labelling.md +++ b/docs/axes/labelling.md @@ -12,6 +12,8 @@ Namespace: `options.scales[scaleId].title`, it defines options for the scale tit | `align` | `string` | `'center'` | Alignment of the axis title. Possible options are `'start'`, `'center'` and `'end'` | `text` | `string`\|`string[]` | `''` | The text for the title. (i.e. "# of People" or "Response Choices"). | `color` | [`Color`](../general/colors.md) | `Chart.defaults.color` | Color of label. +| `strokeColor` | [`Color`](../general/colors.md) | | Color of text stroke. +| `strokeWidth` | `number` | | Size of stroke width. | `font` | `Font` | `Chart.defaults.font` | See [Fonts](../general/fonts.md) | `padding` | [`Padding`](../general/padding.md) | `4` | Padding to apply around scale labels. Only `top`, `bottom` and `y` are implemented. diff --git a/src/types/index.d.ts b/src/types/index.d.ts index 858599201c8..911b4cb2bc8 100644 --- a/src/types/index.d.ts +++ b/src/types/index.d.ts @@ -3270,10 +3270,10 @@ export interface CartesianScaleOptions extends CoreScaleOptions { text: string | string[]; /** Color of the axis label. */ color: Color; - /** Color of the axis label's stroke. */ - strokeColor: Color; - /** Stroke width of the axis label. */ - strokeWidth: number; + /** The color of the text stroke for the axis label.*/ + strokeColor?: Color; + /** The text stroke width for the axis label.*/ + strokeWidth?: number; /** Information about the axis title font. */ font: ScriptableAndScriptableOptions, ScriptableCartesianScaleContext>; /** Padding to apply around scale labels. */ From 34097c59b5d8bc69c4f6fb96040520200fb5bcff Mon Sep 17 00:00:00 2001 From: user Date: Thu, 9 Oct 2025 19:36:33 -0400 Subject: [PATCH 03/12] specify stroke width units --- docs/axes/labelling.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/axes/labelling.md b/docs/axes/labelling.md index a50c4a92145..2c4a7f4b206 100644 --- a/docs/axes/labelling.md +++ b/docs/axes/labelling.md @@ -13,7 +13,7 @@ Namespace: `options.scales[scaleId].title`, it defines options for the scale tit | `text` | `string`\|`string[]` | `''` | The text for the title. (i.e. "# of People" or "Response Choices"). | `color` | [`Color`](../general/colors.md) | `Chart.defaults.color` | Color of label. | `strokeColor` | [`Color`](../general/colors.md) | | Color of text stroke. -| `strokeWidth` | `number` | | Size of stroke width. +| `strokeWidth` | `number` | | Size of stroke width, in pixels. | `font` | `Font` | `Chart.defaults.font` | See [Fonts](../general/fonts.md) | `padding` | [`Padding`](../general/padding.md) | `4` | Padding to apply around scale labels. Only `top`, `bottom` and `y` are implemented. From 33ccfee29cc891063c0f587da943fa8d3037fe18 Mon Sep 17 00:00:00 2001 From: user Date: Mon, 13 Oct 2025 18:23:57 -0400 Subject: [PATCH 04/12] Simplify usage of strokeColor and strokeWidth --- .gitignore | 1 + src/core/core.scale.js | 6 ++---- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/.gitignore b/.gitignore index c731872efa5..828d3f91bd0 100644 --- a/.gitignore +++ b/.gitignore @@ -26,6 +26,7 @@ docs/.vuepress/dist .project .settings .vscode +.zed *.log *.swp *.stackdump diff --git a/src/core/core.scale.js b/src/core/core.scale.js index b40c63bb926..e81b6b933bf 100644 --- a/src/core/core.scale.js +++ b/src/core/core.scale.js @@ -1596,8 +1596,6 @@ export default class Scale extends Element { const padding = toPadding(title.padding); const align = title.align; let offset = font.lineHeight / 2; - let strokeWidth = title.strokeWidth; - let strokeColor = title.strokeColor; if (position === 'bottom' || position === 'center' || isObject(position)) { offset += padding.bottom; @@ -1617,8 +1615,8 @@ export default class Scale extends Element { textAlign: titleAlign(align, position, reverse), textBaseline: 'middle', translation: [titleX, titleY], - strokeColor: strokeColor, - strokeWidth: strokeWidth + strokeColor: title.strokeColor, + strokeWidth: title.strokeWidth }); } From ad3cbdadc6fa9b76b542db783b17cac2ba7edd51 Mon Sep 17 00:00:00 2001 From: user Date: Mon, 13 Oct 2025 18:24:18 -0400 Subject: [PATCH 05/12] Add scale title stroke test --- test/fixtures/core.scale/title/stroke-text.js | 85 ++++++++++++++++++ .../fixtures/core.scale/title/stroke-text.png | Bin 0 -> 5047 bytes 2 files changed, 85 insertions(+) create mode 100644 test/fixtures/core.scale/title/stroke-text.js create mode 100644 test/fixtures/core.scale/title/stroke-text.png diff --git a/test/fixtures/core.scale/title/stroke-text.js b/test/fixtures/core.scale/title/stroke-text.js new file mode 100644 index 00000000000..13e8f64093e --- /dev/null +++ b/test/fixtures/core.scale/title/stroke-text.js @@ -0,0 +1,85 @@ +module.exports = { + config: { + type: 'line', + options: { + events: [], + scales: { + top: { + type: 'linear', + position: 'top', + ticks: { + display: false + }, + grid: { + display: false + }, + title: { + display: true, + align: 'start', + text: 'top', + strokeWidth: 1, + strokeColor: '#333' + } + }, + left: { + type: 'linear', + position: 'left', + ticks: { + display: false + }, + grid: { + display: false + }, + title: { + display: true, + align: 'start', + text: 'left', + strokeWidth: 1, + strokeColor: '#333', + } + }, + bottom: { + type: 'linear', + position: 'bottom', + ticks: { + display: false + }, + grid: { + display: false + }, + title: { + display: true, + align: 'start', + text: 'bottom', + strokeWidth: 1, + strokeColor: '#333', + } + }, + right: { + type: 'linear', + position: 'right', + ticks: { + display: false + }, + grid: { + display: false + }, + title: { + display: true, + align: 'start', + text: 'right', + strokeWidth: 1, + strokeColor: '#333', + } + }, + } + } + }, + options: { + spriteText: true, + canvas: { + height: 256, + width: 256 + }, + } +}; diff --git a/test/fixtures/core.scale/title/stroke-text.png b/test/fixtures/core.scale/title/stroke-text.png new file mode 100644 index 0000000000000000000000000000000000000000..c5a5338e3a4e17aa9a27c65d51a4ebea0296688c GIT binary patch literal 5047 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 NYIMY~NZ&Q)e*iv}R>c4S literal 0 HcmV?d00001 From 4be53da5d012294a3a31fd284820224bd580b7a0 Mon Sep 17 00:00:00 2001 From: user Date: Tue, 7 Oct 2025 16:39:28 -0400 Subject: [PATCH 06/12] Enable text stroke on scale titles --- src/core/core.scale.js | 4 ++++ src/types/index.d.ts | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/src/core/core.scale.js b/src/core/core.scale.js index dcf4bd00b2b..b40c63bb926 100644 --- a/src/core/core.scale.js +++ b/src/core/core.scale.js @@ -1596,6 +1596,8 @@ export default class Scale extends Element { const padding = toPadding(title.padding); const align = title.align; let offset = font.lineHeight / 2; + let strokeWidth = title.strokeWidth; + let strokeColor = title.strokeColor; if (position === 'bottom' || position === 'center' || isObject(position)) { offset += padding.bottom; @@ -1615,6 +1617,8 @@ export default class Scale extends Element { textAlign: titleAlign(align, position, reverse), textBaseline: 'middle', translation: [titleX, titleY], + strokeColor: strokeColor, + strokeWidth: strokeWidth }); } diff --git a/src/types/index.d.ts b/src/types/index.d.ts index 3b373620c0f..858599201c8 100644 --- a/src/types/index.d.ts +++ b/src/types/index.d.ts @@ -3270,6 +3270,10 @@ export interface CartesianScaleOptions extends CoreScaleOptions { text: string | string[]; /** Color of the axis label. */ color: Color; + /** Color of the axis label's stroke. */ + strokeColor: Color; + /** Stroke width of the axis label. */ + strokeWidth: number; /** Information about the axis title font. */ font: ScriptableAndScriptableOptions, ScriptableCartesianScaleContext>; /** Padding to apply around scale labels. */ From aeef7a8ded9fed53e47f44d76cdefe836530d41f Mon Sep 17 00:00:00 2001 From: user Date: Thu, 9 Oct 2025 19:34:42 -0400 Subject: [PATCH 07/12] update documentation --- docs/axes/labelling.md | 2 ++ src/types/index.d.ts | 8 ++++---- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/docs/axes/labelling.md b/docs/axes/labelling.md index 98583e964fd..a50c4a92145 100644 --- a/docs/axes/labelling.md +++ b/docs/axes/labelling.md @@ -12,6 +12,8 @@ Namespace: `options.scales[scaleId].title`, it defines options for the scale tit | `align` | `string` | `'center'` | Alignment of the axis title. Possible options are `'start'`, `'center'` and `'end'` | `text` | `string`\|`string[]` | `''` | The text for the title. (i.e. "# of People" or "Response Choices"). | `color` | [`Color`](../general/colors.md) | `Chart.defaults.color` | Color of label. +| `strokeColor` | [`Color`](../general/colors.md) | | Color of text stroke. +| `strokeWidth` | `number` | | Size of stroke width. | `font` | `Font` | `Chart.defaults.font` | See [Fonts](../general/fonts.md) | `padding` | [`Padding`](../general/padding.md) | `4` | Padding to apply around scale labels. Only `top`, `bottom` and `y` are implemented. diff --git a/src/types/index.d.ts b/src/types/index.d.ts index 858599201c8..911b4cb2bc8 100644 --- a/src/types/index.d.ts +++ b/src/types/index.d.ts @@ -3270,10 +3270,10 @@ export interface CartesianScaleOptions extends CoreScaleOptions { text: string | string[]; /** Color of the axis label. */ color: Color; - /** Color of the axis label's stroke. */ - strokeColor: Color; - /** Stroke width of the axis label. */ - strokeWidth: number; + /** The color of the text stroke for the axis label.*/ + strokeColor?: Color; + /** The text stroke width for the axis label.*/ + strokeWidth?: number; /** Information about the axis title font. */ font: ScriptableAndScriptableOptions, ScriptableCartesianScaleContext>; /** Padding to apply around scale labels. */ From cf6dc2b23ffa155d3bd85f14fa4302efe2cdd5e9 Mon Sep 17 00:00:00 2001 From: user Date: Thu, 9 Oct 2025 19:36:33 -0400 Subject: [PATCH 08/12] specify stroke width units --- docs/axes/labelling.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/axes/labelling.md b/docs/axes/labelling.md index a50c4a92145..2c4a7f4b206 100644 --- a/docs/axes/labelling.md +++ b/docs/axes/labelling.md @@ -13,7 +13,7 @@ Namespace: `options.scales[scaleId].title`, it defines options for the scale tit | `text` | `string`\|`string[]` | `''` | The text for the title. (i.e. "# of People" or "Response Choices"). | `color` | [`Color`](../general/colors.md) | `Chart.defaults.color` | Color of label. | `strokeColor` | [`Color`](../general/colors.md) | | Color of text stroke. -| `strokeWidth` | `number` | | Size of stroke width. +| `strokeWidth` | `number` | | Size of stroke width, in pixels. | `font` | `Font` | `Chart.defaults.font` | See [Fonts](../general/fonts.md) | `padding` | [`Padding`](../general/padding.md) | `4` | Padding to apply around scale labels. Only `top`, `bottom` and `y` are implemented. From e4a30679e5f99f5d5715c490f487880c3037b99c Mon Sep 17 00:00:00 2001 From: user Date: Mon, 13 Oct 2025 18:23:57 -0400 Subject: [PATCH 09/12] Simplify usage of strokeColor and strokeWidth --- .gitignore | 1 + src/core/core.scale.js | 6 ++---- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/.gitignore b/.gitignore index c731872efa5..828d3f91bd0 100644 --- a/.gitignore +++ b/.gitignore @@ -26,6 +26,7 @@ docs/.vuepress/dist .project .settings .vscode +.zed *.log *.swp *.stackdump diff --git a/src/core/core.scale.js b/src/core/core.scale.js index b40c63bb926..e81b6b933bf 100644 --- a/src/core/core.scale.js +++ b/src/core/core.scale.js @@ -1596,8 +1596,6 @@ export default class Scale extends Element { const padding = toPadding(title.padding); const align = title.align; let offset = font.lineHeight / 2; - let strokeWidth = title.strokeWidth; - let strokeColor = title.strokeColor; if (position === 'bottom' || position === 'center' || isObject(position)) { offset += padding.bottom; @@ -1617,8 +1615,8 @@ export default class Scale extends Element { textAlign: titleAlign(align, position, reverse), textBaseline: 'middle', translation: [titleX, titleY], - strokeColor: strokeColor, - strokeWidth: strokeWidth + strokeColor: title.strokeColor, + strokeWidth: title.strokeWidth }); } From d5a3c4b877326421903d5a637029a64fcc4794e1 Mon Sep 17 00:00:00 2001 From: user Date: Mon, 13 Oct 2025 18:24:18 -0400 Subject: [PATCH 10/12] Add scale title stroke test --- test/fixtures/core.scale/title/stroke-text.js | 85 ++++++++++++++++++ .../fixtures/core.scale/title/stroke-text.png | Bin 0 -> 5047 bytes 2 files changed, 85 insertions(+) create mode 100644 test/fixtures/core.scale/title/stroke-text.js create mode 100644 test/fixtures/core.scale/title/stroke-text.png diff --git a/test/fixtures/core.scale/title/stroke-text.js b/test/fixtures/core.scale/title/stroke-text.js new file mode 100644 index 00000000000..13e8f64093e --- /dev/null +++ b/test/fixtures/core.scale/title/stroke-text.js @@ -0,0 +1,85 @@ +module.exports = { + config: { + type: 'line', + options: { + events: [], + scales: { + top: { + type: 'linear', + position: 'top', + ticks: { + display: false + }, + grid: { + display: false + }, + title: { + display: true, + align: 'start', + text: 'top', + strokeWidth: 1, + strokeColor: '#333' + } + }, + left: { + type: 'linear', + position: 'left', + ticks: { + display: false + }, + grid: { + display: false + }, + title: { + display: true, + align: 'start', + text: 'left', + strokeWidth: 1, + strokeColor: '#333', + } + }, + bottom: { + type: 'linear', + position: 'bottom', + ticks: { + display: false + }, + grid: { + display: false + }, + title: { + display: true, + align: 'start', + text: 'bottom', + strokeWidth: 1, + strokeColor: '#333', + } + }, + right: { + type: 'linear', + position: 'right', + ticks: { + display: false + }, + grid: { + display: false + }, + title: { + display: true, + align: 'start', + text: 'right', + strokeWidth: 1, + strokeColor: '#333', + } + }, + } + } + }, + options: { + spriteText: true, + canvas: { + height: 256, + width: 256 + }, + } +}; diff --git a/test/fixtures/core.scale/title/stroke-text.png b/test/fixtures/core.scale/title/stroke-text.png new file mode 100644 index 0000000000000000000000000000000000000000..c5a5338e3a4e17aa9a27c65d51a4ebea0296688c GIT binary patch literal 5047 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 NYIMY~NZ&Q)e*iv}R>c4S literal 0 HcmV?d00001 From 11589eda2a1bec8f59b6023ba3695527fb6c304f Mon Sep 17 00:00:00 2001 From: user Date: Sat, 18 Oct 2025 18:52:29 -0400 Subject: [PATCH 11/12] Implement non image based tests --- test/specs/core.scale.tests.js | 80 ++++++++++++++++++++++++++++++++++ 1 file changed, 80 insertions(+) diff --git a/test/specs/core.scale.tests.js b/test/specs/core.scale.tests.js index caa3c8f32ea..a388e7c9ca5 100644 --- a/test/specs/core.scale.tests.js +++ b/test/specs/core.scale.tests.js @@ -817,4 +817,84 @@ describe('Core.scale', function() { } }); }); + describe('Scale Title stroke', ()=>{ + function getChartWithScaleTitleStroke() { + return window.acquireChart({ + type: 'line', + options: { + scales: { + x: { + type: 'linear', + title: { + display: true, + text: 'title-x', + color: '#ddd', + strokeWidth: 1, + strokeColor: '#333' + } + }, + y: { + type: 'linear', + title: { + display: true, + text: 'title-y', + color: '#ddd', + strokeWidth: 2, + strokeColor: '#222' + } + } + } + } + }); + } + + function getChartWithoutScaleTitleStroke() { + return window.acquireChart({ + type: 'line', + options: { + scales: { + x: { + type: 'linear', + title: { + display: true, + text: 'title-x', + color: '#ddd' + } + }, + y: { + type: 'linear', + title: { + display: true, + text: 'title-y', + color: '#ddd' + } + } + } + } + }); + } + + it('should draw a scale title stroke when provided x-axis', function() { + var chart = getChartWithScaleTitleStroke(); + var scale = chart.scales.x; + expect(scale.options.title.strokeColor).toEqual('#333'); + expect(scale.options.title.strokeWidth).toEqual(1); + }); + + it('should draw a scale title stroke when provided y-axis', function() { + var chart = getChartWithScaleTitleStroke(); + var scale = chart.scales.y; + expect(scale.options.title.strokeColor).toEqual('#222'); + expect(scale.options.title.strokeWidth).toEqual(2); + }); + + it('should not draw a scale title stroke when not provided', function() { + var chart = getChartWithoutScaleTitleStroke(); + var scales = chart.scales; + expect(scales.y.options.title.strokeColor).toBeUndefined(); + expect(scales.y.options.title.strokeWidth).toBeUndefined(); + expect(scales.x.options.title.strokeColor).toBeUndefined(); + expect(scales.x.options.title.strokeWidth).toBeUndefined(); + }); + }); }); From ac379178f4430d9aa19d19387fd40e8374733c72 Mon Sep 17 00:00:00 2001 From: user Date: Sat, 18 Oct 2025 19:24:19 -0400 Subject: [PATCH 12/12] Remove image based test --- test/fixtures/core.scale/title/stroke-text.js | 85 ------------------ .../fixtures/core.scale/title/stroke-text.png | Bin 5047 -> 0 bytes 2 files changed, 85 deletions(-) delete mode 100644 test/fixtures/core.scale/title/stroke-text.js delete mode 100644 test/fixtures/core.scale/title/stroke-text.png diff --git a/test/fixtures/core.scale/title/stroke-text.js b/test/fixtures/core.scale/title/stroke-text.js deleted file mode 100644 index 13e8f64093e..00000000000 --- a/test/fixtures/core.scale/title/stroke-text.js +++ /dev/null @@ -1,85 +0,0 @@ -module.exports = { - config: { - type: 'line', - options: { - events: [], - scales: { - top: { - type: 'linear', - position: 'top', - ticks: { - display: false - }, - grid: { - display: false - }, - title: { - display: true, - align: 'start', - text: 'top', - strokeWidth: 1, - strokeColor: '#333' - } - }, - left: { - type: 'linear', - position: 'left', - ticks: { - display: false - }, - grid: { - display: false - }, - title: { - display: true, - align: 'start', - text: 'left', - strokeWidth: 1, - strokeColor: '#333', - } - }, - bottom: { - type: 'linear', - position: 'bottom', - ticks: { - display: false - }, - grid: { - display: false - }, - title: { - display: true, - align: 'start', - text: 'bottom', - strokeWidth: 1, - strokeColor: '#333', - } - }, - right: { - type: 'linear', - position: 'right', - ticks: { - display: false - }, - grid: { - display: false - }, - title: { - display: true, - align: 'start', - text: 'right', - strokeWidth: 1, - strokeColor: '#333', - } - }, - } - } - }, - options: { - spriteText: true, - canvas: { - height: 256, - width: 256 - }, - } -}; diff --git a/test/fixtures/core.scale/title/stroke-text.png b/test/fixtures/core.scale/title/stroke-text.png deleted file mode 100644 index c5a5338e3a4e17aa9a27c65d51a4ebea0296688c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5047 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 NYIMY~NZ&Q)e*iv}R>c4S