From fbf3427ca2f7a1817abf93b10c6b8c30404a509a Mon Sep 17 00:00:00 2001 From: cmcnulty Date: Wed, 12 Oct 2022 06:08:22 -0500 Subject: [PATCH] Fix #10749 - backdrops with rotated labels (#10759) * Fix #10749 - backdrops with rotated labels * remove translation adjustment Because backdrop now occurs after translation, we don't want to double-adjust the position. * increase tolerance slightly due to anti-aliasing Co-authored-by: Charles McNulty --- src/core/core.scale.js | 9 +- src/helpers/helpers.canvas.js | 12 +++ .../core.scale/tick-backdrop-rotation.js | 85 ++++++++++++++++++ .../core.scale/tick-backdrop-rotation.png | Bin 0 -> 17806 bytes 4 files changed, 99 insertions(+), 7 deletions(-) create mode 100644 test/fixtures/core.scale/tick-backdrop-rotation.js create mode 100644 test/fixtures/core.scale/tick-backdrop-rotation.png diff --git a/src/core/core.scale.js b/src/core/core.scale.js index dc479d5fb..f741e2e60 100644 --- a/src/core/core.scale.js +++ b/src/core/core.scale.js @@ -1253,8 +1253,8 @@ export default class Scale extends Element { const height = labelSizes.heights[i]; const width = labelSizes.widths[i]; - let top = y + textOffset - labelPadding.top; - let left = x - labelPadding.left; + let top = textOffset - labelPadding.top; + let left = 0 - labelPadding.left; switch (textBaseline) { case 'middle': @@ -1554,11 +1554,6 @@ export default class Scale extends Element { const tickFont = item.font; const label = item.label; - if (item.backdrop) { - ctx.fillStyle = item.backdrop.color; - ctx.fillRect(item.backdrop.left, item.backdrop.top, item.backdrop.width, item.backdrop.height); - } - let y = item.textOffset; renderText(ctx, label, 0, y, tickFont, item); } diff --git a/src/helpers/helpers.canvas.js b/src/helpers/helpers.canvas.js index 365386549..773398c18 100644 --- a/src/helpers/helpers.canvas.js +++ b/src/helpers/helpers.canvas.js @@ -340,6 +340,10 @@ export function renderText(ctx, text, x, y, font, opts = {}) { for (i = 0; i < lines.length; ++i) { line = lines[i]; + if (opts.backdrop) { + drawBackdrop(ctx, opts.backdrop); + } + if (stroke) { if (opts.strokeColor) { ctx.strokeStyle = opts.strokeColor; @@ -408,6 +412,14 @@ function decorateText(ctx, x, y, line, opts) { } } +function drawBackdrop(ctx, opts) { + const oldColor = ctx.fillStyle; + + ctx.fillStyle = opts.color; + ctx.fillRect(opts.left, opts.top, opts.width, opts.height); + ctx.fillStyle = oldColor; +} + /** * Add a path of a rectangle with rounded corners to the current sub-path * @param {CanvasRenderingContext2D} ctx Context diff --git a/test/fixtures/core.scale/tick-backdrop-rotation.js b/test/fixtures/core.scale/tick-backdrop-rotation.js new file mode 100644 index 000000000..8e2bad7a5 --- /dev/null +++ b/test/fixtures/core.scale/tick-backdrop-rotation.js @@ -0,0 +1,85 @@ +const grid = { + display: false +}; +const title = { + display: false, +}; +module.exports = { + tolerance: 0.0016, + config: { + type: 'line', + options: { + events: [], + scales: { + top: { + type: 'linear', + position: 'top', + ticks: { + display: true, + showLabelBackdrop: true, + minRotation: 45, + backdropColor: 'blue', + backdropPadding: 5, + align: 'start', + crossAlign: 'near', + }, + grid, + title + }, + left: { + type: 'linear', + position: 'left', + ticks: { + display: true, + showLabelBackdrop: true, + minRotation: 90, + backdropColor: 'green', + backdropPadding: { + x: 2, + y: 5 + }, + crossAlign: 'center', + }, + grid, + title + }, + bottom: { + type: 'linear', + position: 'bottom', + ticks: { + display: true, + showLabelBackdrop: true, + backdropColor: 'blue', + backdropPadding: { + x: 5, + y: 5 + }, + align: 'end', + crossAlign: 'far', + minRotation: 60, + }, + grid, + title + }, + right: { + type: 'linear', + position: 'right', + ticks: { + display: true, + showLabelBackdrop: true, + backdropColor: 'gray', + }, + grid, + title + }, + } + } + }, + options: { + canvas: { + height: 256, + width: 256 + }, + spriteText: true, + } +}; diff --git a/test/fixtures/core.scale/tick-backdrop-rotation.png b/test/fixtures/core.scale/tick-backdrop-rotation.png new file mode 100644 index 0000000000000000000000000000000000000000..4c5d47efab9785fd8fd50b21d0b49de7e430c68f GIT binary patch literal 17806 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