From 4b7e0f2981969a9c7a83a7ef190cc7e39c31408c Mon Sep 17 00:00:00 2001 From: Jose Raul Perez Date: Sun, 24 Nov 2019 19:52:03 +0100 Subject: [PATCH 1/7] add stroke lines option around ticks to improve readability --- docs/axes/styling.md | 2 ++ src/core/core.defaults.js | 4 +++- src/core/core.scale.js | 10 +++++++++- src/helpers/helpers.options.js | 4 +++- test/context.js | 1 + test/specs/helpers.options.tests.js | 16 ++++++++++++---- test/specs/scale.category.tests.js | 2 ++ test/specs/scale.linear.tests.js | 2 ++ test/specs/scale.logarithmic.tests.js | 2 ++ test/specs/scale.radialLinear.tests.js | 2 ++ test/specs/scale.time.tests.js | 2 ++ 11 files changed, 40 insertions(+), 7 deletions(-) diff --git a/docs/axes/styling.md b/docs/axes/styling.md index e26789eaf82..3a8e7fc2cdb 100644 --- a/docs/axes/styling.md +++ b/docs/axes/styling.md @@ -43,9 +43,11 @@ The tick configuration is nested under the scale configuration in the `ticks` ke | `fontStyle` | `string` | `'normal'` | Font style for the tick labels, follows CSS font-style options (i.e. normal, italic, oblique, initial, inherit). | `lineHeight` | number|string | `1.2` | Height of an individual line of text (see [MDN](https://developer.mozilla.org/en-US/docs/Web/CSS/line-height)). | `reverse` | `boolean` | `false` | Reverses order of tick labels. +| `lineWidth` | `number` | `0` | Stroke width around the text. | `minor` | `object` | `{}` | Minor ticks configuration. Omitted options are inherited from options above. | `major` | `object` | `{}` | Major ticks configuration. Omitted options are inherited from options above. | `padding` | `number` | `0` | Sets the offset of the tick labels from the axis +| `strokeStyle` | `string` | `` | The color of the stroke around the text. | `z` | `number` | `0` | z-index of tick layer. Useful when ticks are drawn on chart area. Values <= 0 are drawn under datasets, > 0 on top. ## Minor Tick Configuration diff --git a/src/core/core.defaults.js b/src/core/core.defaults.js index 6c8e996a1a8..ecd8a9681fe 100644 --- a/src/core/core.defaults.js +++ b/src/core/core.defaults.js @@ -20,7 +20,9 @@ defaults._set('global', { defaultFontSize: 12, defaultFontStyle: 'normal', defaultLineHeight: 1.2, - showLines: true + showLines: true, + defaultStrokeStyle: '', + defaultLineWidth: 0 }); module.exports = defaults; diff --git a/src/core/core.scale.js b/src/core/core.scale.js index 2157db83cb7..d673c6fdcce 100644 --- a/src/core/core.scale.js +++ b/src/core/core.scale.js @@ -53,6 +53,8 @@ defaults._set('scale', { minRotation: 0, maxRotation: 50, mirror: false, + lineWidth: 0, + strokeStyle: '', padding: 0, display: true, autoSkip: true, @@ -199,7 +201,9 @@ function parseFontOptions(options, nestedOpts) { fontFamily: valueOrDefault(nestedOpts.fontFamily, options.fontFamily), fontSize: valueOrDefault(nestedOpts.fontSize, options.fontSize), fontStyle: valueOrDefault(nestedOpts.fontStyle, options.fontStyle), - lineHeight: valueOrDefault(nestedOpts.lineHeight, options.lineHeight) + lineHeight: valueOrDefault(nestedOpts.lineHeight, options.lineHeight), + lineWidth: valueOrDefault(nestedOpts.lineWidth, options.lineWidth), + strokeStyle: valueOrDefault(nestedOpts.strokeStyle, options.strokeStyle), }), { color: resolve([nestedOpts.fontColor, options.fontColor, defaults.global.defaultFontColor]) }); @@ -1255,16 +1259,20 @@ class Scale extends Element { ctx.fillStyle = tickFont.color; ctx.textBaseline = 'middle'; ctx.textAlign = item.textAlign; + ctx.strokeStyle = tickFont.strokeStyle; + ctx.lineWidth = tickFont.lineWidth; label = item.label; y = item.textOffset; if (isArray(label)) { for (j = 0, jlen = label.length; j < jlen; ++j) { // We just make sure the multiline element is a string here.. + ctx.strokeText('' + label[j], 0, y); ctx.fillText('' + label[j], 0, y); y += tickFont.lineHeight; } } else { + ctx.strokeText(label, 0, y); ctx.fillText(label, 0, y); } ctx.restore(); diff --git a/src/helpers/helpers.options.js b/src/helpers/helpers.options.js index 0bca84dba51..a75abacb816 100644 --- a/src/helpers/helpers.options.js +++ b/src/helpers/helpers.options.js @@ -101,7 +101,9 @@ module.exports = { size: size, style: valueOrDefault(options.fontStyle, globalDefaults.defaultFontStyle), weight: null, - string: '' + string: '', + strokeStyle: valueOrDefault(options.strokeStyle, globalDefaults.defaultStrokeStyle), + lineWidth: valueOrDefault(options.lineWidth, globalDefaults.defaultLineWidth) }; font.string = toFontString(font); diff --git a/test/context.js b/test/context.js index 88966f230fe..42b399d9f36 100644 --- a/test/context.js +++ b/test/context.js @@ -94,6 +94,7 @@ Context.prototype._initMethods = function() { fill: function() {}, fillRect: function() {}, fillText: function() {}, + strokeText: function() {}, lineTo: function() {}, measureText: function(text) { // return the number of characters * fixed size diff --git a/test/specs/helpers.options.tests.js b/test/specs/helpers.options.tests.js index 1afbd59bd45..605aed5862d 100644 --- a/test/specs/helpers.options.tests.js +++ b/test/specs/helpers.options.tests.js @@ -76,7 +76,9 @@ describe('Chart.helpers.options', function() { defaultFontFamily: 'foobar', defaultFontSize: 42, defaultFontStyle: 'xxxyyy', - defaultLineHeight: 1.5 + defaultLineHeight: 1.5, + defaultLineWidth: 14, + defaultStrokeStyle: 'default' }; expect(parseFont({})).toEqual({ @@ -85,7 +87,9 @@ describe('Chart.helpers.options', function() { size: 42, string: 'xxxyyy 42px foobar', style: 'xxxyyy', - weight: null + weight: null, + lineWidth: 14, + strokeStyle: 'default' }); Chart.defaults.global = global; @@ -95,14 +99,18 @@ describe('Chart.helpers.options', function() { fontFamily: 'bla', lineHeight: 8, fontSize: 21, - fontStyle: 'zzz' + fontStyle: 'zzz', + lineWidth: 20, + strokeStyle: 'blue' })).toEqual({ family: 'bla', lineHeight: 8 * 21, size: 21, string: 'zzz 21px bla', style: 'zzz', - weight: null + weight: null, + lineWidth: 20, + strokeStyle: 'blue' }); }); it('should return null as a font string if fontSize or fontFamily are missing', function() { diff --git a/test/specs/scale.category.tests.js b/test/specs/scale.category.tests.js index 5485f137e01..ba90f9dd93c 100644 --- a/test/specs/scale.category.tests.js +++ b/test/specs/scale.category.tests.js @@ -49,6 +49,8 @@ describe('Category scale tests', function() { labelOffset: 0, minor: {}, major: {}, + lineWidth: 0, + strokeStyle: '', } }); diff --git a/test/specs/scale.linear.tests.js b/test/specs/scale.linear.tests.js index 459db671c57..dff791ac183 100644 --- a/test/specs/scale.linear.tests.js +++ b/test/specs/scale.linear.tests.js @@ -42,6 +42,8 @@ describe('Linear Scale', function() { labelOffset: 0, minor: {}, major: {}, + lineWidth: 0, + strokeStyle: '', } }); diff --git a/test/specs/scale.logarithmic.tests.js b/test/specs/scale.logarithmic.tests.js index 599dfd38e5e..837306b7475 100644 --- a/test/specs/scale.logarithmic.tests.js +++ b/test/specs/scale.logarithmic.tests.js @@ -42,6 +42,8 @@ describe('Logarithmic Scale tests', function() { labelOffset: 0, minor: {}, major: {}, + lineWidth: 0, + strokeStyle: '', }, }); diff --git a/test/specs/scale.radialLinear.tests.js b/test/specs/scale.radialLinear.tests.js index a64157a7e69..6c046568fdd 100644 --- a/test/specs/scale.radialLinear.tests.js +++ b/test/specs/scale.radialLinear.tests.js @@ -63,6 +63,8 @@ describe('Test the radial linear scale', function() { labelOffset: 0, minor: {}, major: {}, + lineWidth: 0, + strokeStyle: '', }, }); diff --git a/test/specs/scale.time.tests.js b/test/specs/scale.time.tests.js index 09fc2ff0204..df69d86c8ed 100755 --- a/test/specs/scale.time.tests.js +++ b/test/specs/scale.time.tests.js @@ -95,6 +95,8 @@ describe('Time scale tests', function() { major: { enabled: false }, + lineWidth: 0, + strokeStyle: '', }, time: { parser: false, From 72a6e70bd98174050c44d95a4ff51e28b58bf7ea Mon Sep 17 00:00:00 2001 From: Jose Raul Perez Date: Wed, 27 Nov 2019 17:29:56 +0100 Subject: [PATCH 2/7] move the tick stroke to the correct place --- src/core/core.defaults.js | 4 +--- src/core/core.scale.js | 11 ++++++++--- src/helpers/helpers.options.js | 4 +--- test/specs/helpers.options.tests.js | 16 ++++------------ 4 files changed, 14 insertions(+), 21 deletions(-) diff --git a/src/core/core.defaults.js b/src/core/core.defaults.js index ecd8a9681fe..6c8e996a1a8 100644 --- a/src/core/core.defaults.js +++ b/src/core/core.defaults.js @@ -20,9 +20,7 @@ defaults._set('global', { defaultFontSize: 12, defaultFontStyle: 'normal', defaultLineHeight: 1.2, - showLines: true, - defaultStrokeStyle: '', - defaultLineWidth: 0 + showLines: true }); module.exports = defaults; diff --git a/src/core/core.scale.js b/src/core/core.scale.js index d673c6fdcce..573dfc2ac00 100644 --- a/src/core/core.scale.js +++ b/src/core/core.scale.js @@ -213,7 +213,12 @@ function parseTickFontOptions(options) { var minor = parseFontOptions(options, options.minor); var major = options.major.enabled ? parseFontOptions(options, options.major) : minor; - return {minor: minor, major: major}; + return { + minor: minor, + major: major, + strokeStyle: valueOrDefault(options.strokeStyle, defaults.scale.ticks.strokeStyle), + lineWidth: valueOrDefault(options.lineWidth, defaults.scale.ticks.lineWidth) + }; } function nonSkipped(ticksToFilter) { @@ -1259,8 +1264,8 @@ class Scale extends Element { ctx.fillStyle = tickFont.color; ctx.textBaseline = 'middle'; ctx.textAlign = item.textAlign; - ctx.strokeStyle = tickFont.strokeStyle; - ctx.lineWidth = tickFont.lineWidth; + ctx.strokeStyle = optionTicks.strokeStyle; + ctx.lineWidth = optionTicks.lineWidth; label = item.label; y = item.textOffset; diff --git a/src/helpers/helpers.options.js b/src/helpers/helpers.options.js index a75abacb816..0bca84dba51 100644 --- a/src/helpers/helpers.options.js +++ b/src/helpers/helpers.options.js @@ -101,9 +101,7 @@ module.exports = { size: size, style: valueOrDefault(options.fontStyle, globalDefaults.defaultFontStyle), weight: null, - string: '', - strokeStyle: valueOrDefault(options.strokeStyle, globalDefaults.defaultStrokeStyle), - lineWidth: valueOrDefault(options.lineWidth, globalDefaults.defaultLineWidth) + string: '' }; font.string = toFontString(font); diff --git a/test/specs/helpers.options.tests.js b/test/specs/helpers.options.tests.js index 605aed5862d..1afbd59bd45 100644 --- a/test/specs/helpers.options.tests.js +++ b/test/specs/helpers.options.tests.js @@ -76,9 +76,7 @@ describe('Chart.helpers.options', function() { defaultFontFamily: 'foobar', defaultFontSize: 42, defaultFontStyle: 'xxxyyy', - defaultLineHeight: 1.5, - defaultLineWidth: 14, - defaultStrokeStyle: 'default' + defaultLineHeight: 1.5 }; expect(parseFont({})).toEqual({ @@ -87,9 +85,7 @@ describe('Chart.helpers.options', function() { size: 42, string: 'xxxyyy 42px foobar', style: 'xxxyyy', - weight: null, - lineWidth: 14, - strokeStyle: 'default' + weight: null }); Chart.defaults.global = global; @@ -99,18 +95,14 @@ describe('Chart.helpers.options', function() { fontFamily: 'bla', lineHeight: 8, fontSize: 21, - fontStyle: 'zzz', - lineWidth: 20, - strokeStyle: 'blue' + fontStyle: 'zzz' })).toEqual({ family: 'bla', lineHeight: 8 * 21, size: 21, string: 'zzz 21px bla', style: 'zzz', - weight: null, - lineWidth: 20, - strokeStyle: 'blue' + weight: null }); }); it('should return null as a font string if fontSize or fontFamily are missing', function() { From da952b3d99537cf472918144584d59a38fc14ed2 Mon Sep 17 00:00:00 2001 From: Jose Raul Perez Date: Sun, 1 Dec 2019 18:15:21 +0100 Subject: [PATCH 3/7] let the stroke only in parseFontOptions --- src/core/core.scale.js | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/core/core.scale.js b/src/core/core.scale.js index 573dfc2ac00..af9461e1f65 100644 --- a/src/core/core.scale.js +++ b/src/core/core.scale.js @@ -213,12 +213,7 @@ function parseTickFontOptions(options) { var minor = parseFontOptions(options, options.minor); var major = options.major.enabled ? parseFontOptions(options, options.major) : minor; - return { - minor: minor, - major: major, - strokeStyle: valueOrDefault(options.strokeStyle, defaults.scale.ticks.strokeStyle), - lineWidth: valueOrDefault(options.lineWidth, defaults.scale.ticks.lineWidth) - }; + return {minor: minor, major: major}; } function nonSkipped(ticksToFilter) { From 9a0d7666130c4cde94f27dd755a6b6be51b0397c Mon Sep 17 00:00:00 2001 From: Jose Raul Perez Date: Fri, 10 Jan 2020 18:20:12 +0100 Subject: [PATCH 4/7] apply strokeStyle only when is actually set --- src/core/core.scale.js | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/src/core/core.scale.js b/src/core/core.scale.js index 7918f2dda97..a25ef221415 100644 --- a/src/core/core.scale.js +++ b/src/core/core.scale.js @@ -1271,6 +1271,7 @@ class Scale extends Element { const ctx = me.ctx; const items = me._labelItems || (me._labelItems = me._computeLabelItems(chartArea)); + const useTextWithStroke = optionTicks.lineWidth > 0 && optionTicks.strokeStyle !== ''; let i, j, ilen, jlen; for (i = 0, ilen = items.length; i < ilen; ++i) { @@ -1285,20 +1286,27 @@ class Scale extends Element { ctx.fillStyle = tickFont.color; ctx.textBaseline = 'middle'; ctx.textAlign = item.textAlign; - ctx.strokeStyle = optionTicks.strokeStyle; - ctx.lineWidth = optionTicks.lineWidth; + + if (useTextWithStroke) { + ctx.strokeStyle = optionTicks.strokeStyle; + ctx.lineWidth = optionTicks.lineWidth; + } const label = item.label; let y = item.textOffset; if (isArray(label)) { for (j = 0, jlen = label.length; j < jlen; ++j) { // We just make sure the multiline element is a string here.. - ctx.strokeText('' + label[j], 0, y); + if (useTextWithStroke) { + ctx.strokeText('' + label[j], 0, y); + } ctx.fillText('' + label[j], 0, y); y += tickFont.lineHeight; } } else { - ctx.strokeText(label, 0, y); + if (useTextWithStroke) { + ctx.strokeText(label, 0, y); + } ctx.fillText(label, 0, y); } ctx.restore(); From 3fda1616a8e7fafd54e6936a63f19386bcb849eb Mon Sep 17 00:00:00 2001 From: Jose Raul Perez Date: Fri, 10 Jan 2020 20:14:01 +0100 Subject: [PATCH 5/7] move the font options to the correct place --- src/core/core.scale.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/core/core.scale.js b/src/core/core.scale.js index a25ef221415..2e92eebb2ca 100644 --- a/src/core/core.scale.js +++ b/src/core/core.scale.js @@ -141,10 +141,10 @@ function parseFontOptions(options, nestedOpts) { fontSize: valueOrDefault(nestedOpts.fontSize, options.fontSize), fontStyle: valueOrDefault(nestedOpts.fontStyle, options.fontStyle), lineHeight: valueOrDefault(nestedOpts.lineHeight, options.lineHeight), + }), { + color: resolve([nestedOpts.fontColor, options.fontColor, defaults.fontColor]), lineWidth: valueOrDefault(nestedOpts.lineWidth, options.lineWidth), strokeStyle: valueOrDefault(nestedOpts.strokeStyle, options.strokeStyle), - }), { - color: resolve([nestedOpts.fontColor, options.fontColor, defaults.fontColor]) }); } @@ -1271,12 +1271,12 @@ class Scale extends Element { const ctx = me.ctx; const items = me._labelItems || (me._labelItems = me._computeLabelItems(chartArea)); - const useTextWithStroke = optionTicks.lineWidth > 0 && optionTicks.strokeStyle !== ''; let i, j, ilen, jlen; for (i = 0, ilen = items.length; i < ilen; ++i) { const item = items[i]; const tickFont = item.font; + const useTextWithStroke = tickFont.lineWidth > 0 && tickFont.strokeStyle !== ''; // Make sure we draw text in the correct color and font ctx.save(); @@ -1288,8 +1288,8 @@ class Scale extends Element { ctx.textAlign = item.textAlign; if (useTextWithStroke) { - ctx.strokeStyle = optionTicks.strokeStyle; - ctx.lineWidth = optionTicks.lineWidth; + ctx.strokeStyle = tickFont.strokeStyle; + ctx.lineWidth = tickFont.lineWidth; } const label = item.label; From de76d657bc111c765146478cc3b4ac464e1610c6 Mon Sep 17 00:00:00 2001 From: Jose Raul Perez Date: Sun, 12 Jan 2020 09:38:25 +0100 Subject: [PATCH 6/7] remove unnecessary comma --- src/core/core.scale.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/core/core.scale.js b/src/core/core.scale.js index 2e92eebb2ca..06f21ec70d2 100644 --- a/src/core/core.scale.js +++ b/src/core/core.scale.js @@ -140,11 +140,11 @@ function parseFontOptions(options, nestedOpts) { fontFamily: valueOrDefault(nestedOpts.fontFamily, options.fontFamily), fontSize: valueOrDefault(nestedOpts.fontSize, options.fontSize), fontStyle: valueOrDefault(nestedOpts.fontStyle, options.fontStyle), - lineHeight: valueOrDefault(nestedOpts.lineHeight, options.lineHeight), + lineHeight: valueOrDefault(nestedOpts.lineHeight, options.lineHeight) }), { color: resolve([nestedOpts.fontColor, options.fontColor, defaults.fontColor]), lineWidth: valueOrDefault(nestedOpts.lineWidth, options.lineWidth), - strokeStyle: valueOrDefault(nestedOpts.strokeStyle, options.strokeStyle), + strokeStyle: valueOrDefault(nestedOpts.strokeStyle, options.strokeStyle) }); } From 028102bd992bb18c0fed354cfbe1e1805ce8c0fe Mon Sep 17 00:00:00 2001 From: Jose Raul Perez Date: Sun, 12 Jan 2020 09:40:38 +0100 Subject: [PATCH 7/7] chage variable name --- src/core/core.scale.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/core/core.scale.js b/src/core/core.scale.js index 06f21ec70d2..01aa7178464 100644 --- a/src/core/core.scale.js +++ b/src/core/core.scale.js @@ -1276,7 +1276,7 @@ class Scale extends Element { for (i = 0, ilen = items.length; i < ilen; ++i) { const item = items[i]; const tickFont = item.font; - const useTextWithStroke = tickFont.lineWidth > 0 && tickFont.strokeStyle !== ''; + const useStroke = tickFont.lineWidth > 0 && tickFont.strokeStyle !== ''; // Make sure we draw text in the correct color and font ctx.save(); @@ -1287,7 +1287,7 @@ class Scale extends Element { ctx.textBaseline = 'middle'; ctx.textAlign = item.textAlign; - if (useTextWithStroke) { + if (useStroke) { ctx.strokeStyle = tickFont.strokeStyle; ctx.lineWidth = tickFont.lineWidth; } @@ -1297,14 +1297,14 @@ class Scale extends Element { if (isArray(label)) { for (j = 0, jlen = label.length; j < jlen; ++j) { // We just make sure the multiline element is a string here.. - if (useTextWithStroke) { + if (useStroke) { ctx.strokeText('' + label[j], 0, y); } ctx.fillText('' + label[j], 0, y); y += tickFont.lineHeight; } } else { - if (useTextWithStroke) { + if (useStroke) { ctx.strokeText(label, 0, y); } ctx.fillText(label, 0, y);