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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