From e787e8a8088ff4a9e0af361338e25782f5d8d3ca Mon Sep 17 00:00:00 2001 From: stockiNail Date: Wed, 17 May 2023 18:52:01 +0200 Subject: [PATCH 1/5] Enable the text content wrapping within a box label --- src/helpers/helpers.canvas.js | 71 ++++++++++++++++++++++++++++++++++- src/helpers/helpers.chart.js | 10 +++-- src/types/box.js | 2 + src/types/label.js | 3 +- 4 files changed, 79 insertions(+), 7 deletions(-) diff --git a/src/helpers/helpers.canvas.js b/src/helpers/helpers.canvas.js index 436902b8b..081f74dba 100644 --- a/src/helpers/helpers.canvas.js +++ b/src/helpers/helpers.canvas.js @@ -8,6 +8,11 @@ const fontsKey = (fonts) => fonts.reduce(function(prev, item) { prev += item.string; return prev; }, ''); +const getContent = (content, wrappedText) => wrappedText + ? wrappedText + : isArray(content) + ? content + : [content]; /** * @typedef { import('chart.js').Point } Point @@ -94,6 +99,26 @@ export function measureLabelSize(ctx, options) { return widthCache.get(mapKey); } +/** + * @param {CanvasRenderingContext2D} ctx + * @param {{width: number}} properties + * @param {CoreLabelOptions} options + * @returns {{width: number, height: number}} + */ +export function measureWrappedLabelSize(ctx, properties, options) { + const {font, textStrokeWidth} = options; + const content = wrapLabel(ctx, properties, options); + const result = measureLabelSize(ctx, { + content, + font, + textStrokeWidth + }); + if (content !== options.content) { + result.content = content; + } + return result; +} + /** * @param {CanvasRenderingContext2D} ctx * @param {{x: number, y: number, width: number, height: number}} rect @@ -121,7 +146,7 @@ export function drawBox(ctx, rect, options) { /** * @param {CanvasRenderingContext2D} ctx - * @param {{x: number, y: number, width: number, height: number}} rect + * @param {{x: number, y: number, width: number, height: number, _wrappedText: string[]|undefined}} rect * @param {CoreLabelOptions} options */ export function drawLabel(ctx, rect, options) { @@ -133,7 +158,7 @@ export function drawLabel(ctx, rect, options) { ctx.restore(); return; } - const labels = isArray(content) ? content : [content]; + const labels = getContent(content, rect._wrappedText); const optFont = options.font; const fonts = isArray(optFont) ? optFont.map(f => toFont(f)) : [toFont(optFont)]; const optColor = options.color; @@ -329,3 +354,45 @@ function getOpacity(value, elementValue) { const opacity = isNumber(value) ? value : elementValue; return isNumber(opacity) ? clamp(opacity, 0, 1) : 1; } + +function wrapLabel(ctx, properties, options) { + const maxWidth = properties.width; + const {content, textWrapSeparator} = options; + const text = isArray(content) ? content.join(textWrapSeparator) : content; + if (!text.includes(textWrapSeparator)) { + return content; + } + const font = toFont(options.font); + ctx.save(); + ctx.font = font.string; + const width = ctx.measureText(text).width; + if (maxWidth >= width) { + ctx.restore(); + return content; + } + return splitLabel(ctx, text, textWrapSeparator, maxWidth); +} + +function splitLabel(ctx, text, separator, maxWidth) { + const blankWidth = ctx.measureText(separator).width; + const result = []; + const words = text.split(separator); + let temp = ''; + let current = 0; + for (const w of words) { + const wWidth = ctx.measureText(w).width; + if ((current + wWidth + blankWidth) <= maxWidth) { + temp += w + separator; + current += wWidth + blankWidth; + } else { + result.push(temp.trim()); + temp = w + separator; + current = wWidth + blankWidth; + } + } + if (temp.length) { + result.push(temp.trim()); + } + ctx.restore(); + return result; +} diff --git a/src/helpers/helpers.chart.js b/src/helpers/helpers.chart.js index 76ab085c6..29c38514c 100644 --- a/src/helpers/helpers.chart.js +++ b/src/helpers/helpers.chart.js @@ -1,11 +1,12 @@ -import {isFinite, toPadding} from 'chart.js/helpers'; -import {measureLabelSize} from './helpers.canvas'; +import {isArray, isFinite, toPadding} from 'chart.js/helpers'; +import {measureLabelSize, measureWrappedLabelSize, isImageOrCanvas} from './helpers.canvas'; import {isBoundToPoint, getRelativePosition, toPosition, initAnimationProperties} from './helpers.options'; const limitedLineScale = { xScaleID: {min: 'xMin', max: 'xMax', start: 'left', end: 'right', startProp: 'x', endProp: 'x2'}, yScaleID: {min: 'yMin', max: 'yMax', start: 'bottom', end: 'top', startProp: 'y', endProp: 'y2'} }; +const isTextToWrap = (options) => options.type === 'box' && options.label.textWrap && !isArray(options.label.font) && !isImageOrCanvas(options.content); /** * @typedef { import("chart.js").Chart } Chart @@ -270,7 +271,7 @@ function resolveLabelElementProperties(chart, properties, options) { label.callout.display = false; const position = toPosition(label.position); const padding = toPadding(label.padding); - const labelSize = measureLabelSize(chart.ctx, label); + const labelSize = isTextToWrap(options) ? measureWrappedLabelSize(chart.ctx, properties, label) : measureLabelSize(chart.ctx, label); const x = calculateX({properties, options}, labelSize, position, padding); const y = calculateY({properties, options}, labelSize, position, padding); const width = labelSize.width + padding.width; @@ -284,7 +285,8 @@ function resolveLabelElementProperties(chart, properties, options) { height, centerX: x + width / 2, centerY: y + height / 2, - rotation: label.rotation + rotation: label.rotation, + _wrappedText: labelSize.content }; } diff --git a/src/types/box.js b/src/types/box.js index 66d02ae95..9e8a103ff 100644 --- a/src/types/box.js +++ b/src/types/box.js @@ -68,6 +68,8 @@ BoxAnnotation.defaults = { textAlign: 'start', textStrokeColor: undefined, textStrokeWidth: 0, + textWrap: false, + textWrapSeparator: ' ', width: undefined, xAdjust: 0, yAdjust: 0, diff --git a/src/types/label.js b/src/types/label.js index f1c03ce2a..309c8f86f 100644 --- a/src/types/label.js +++ b/src/types/label.js @@ -244,10 +244,11 @@ function resolveCalloutAutoPosition(element, options) { return result.sort((a, b) => a.distance - b.distance)[0].position; } -function getLabelSize({x, y, width, height, options}) { +function getLabelSize({x, y, width, height, _wrappedText, options}) { const hBorderWidth = options.borderWidth / 2; const padding = toPadding(options.padding); return { + _wrappedText, x: x + padding.left + hBorderWidth, y: y + padding.top + hBorderWidth, width: width - padding.left - padding.right - options.borderWidth, From 333fc12922ae3f517b494b2686aff23a9e19b024 Mon Sep 17 00:00:00 2001 From: stockiNail Date: Thu, 18 May 2023 11:51:31 +0200 Subject: [PATCH 2/5] manages multiple fonts and colors --- src/helpers/helpers.canvas.js | 76 +++++++++++++++++++++-------------- src/helpers/helpers.chart.js | 6 +-- src/types/label.js | 4 +- 3 files changed, 51 insertions(+), 35 deletions(-) diff --git a/src/helpers/helpers.canvas.js b/src/helpers/helpers.canvas.js index 081f74dba..2ac271cff 100644 --- a/src/helpers/helpers.canvas.js +++ b/src/helpers/helpers.canvas.js @@ -1,4 +1,4 @@ -import {addRoundedRectPath, isArray, isNumber, toFont, toTRBLCorners, toRadians, PI, TAU, HALF_PI, QUARTER_PI, TWO_THIRDS_PI, RAD_PER_DEG} from 'chart.js/helpers'; +import {clone, addRoundedRectPath, isArray, isNumber, toFont, toPadding, toTRBLCorners, toRadians, PI, TAU, HALF_PI, QUARTER_PI, TWO_THIRDS_PI, RAD_PER_DEG} from 'chart.js/helpers'; import {clampAll, clamp} from './helpers.core'; import {calculateTextAlignment, getSize} from './helpers.options'; @@ -106,16 +106,13 @@ export function measureLabelSize(ctx, options) { * @returns {{width: number, height: number}} */ export function measureWrappedLabelSize(ctx, properties, options) { - const {font, textStrokeWidth} = options; - const content = wrapLabel(ctx, properties, options); + const wrappedOptions = wrapLabel(ctx, properties, options); const result = measureLabelSize(ctx, { - content, - font, - textStrokeWidth + content: wrappedOptions.content, + font: wrappedOptions.font, + textStrokeWidth: options.textStrokeWidth }); - if (content !== options.content) { - result.content = content; - } + result.wrappedOptions = wrappedOptions; return result; } @@ -158,10 +155,11 @@ export function drawLabel(ctx, rect, options) { ctx.restore(); return; } - const labels = getContent(content, rect._wrappedText); - const optFont = options.font; + const wrapOpt = rect._wrappedOptions || {}; + const labels = getContent(content, wrapOpt.content); + const optFont = wrapOpt.font || options.font; const fonts = isArray(optFont) ? optFont.map(f => toFont(f)) : [toFont(optFont)]; - const optColor = options.color; + const optColor = wrapOpt.color || options.color; const colors = isArray(optColor) ? optColor : [optColor]; const x = calculateTextAlignment(rect, options); const y = rect.y + options.textStrokeWidth / 2; @@ -356,43 +354,61 @@ function getOpacity(value, elementValue) { } function wrapLabel(ctx, properties, options) { - const maxWidth = properties.width; + const padding = toPadding(options.padding); + const maxWidth = properties.width - padding.left - padding.right - options.borderWidth; const {content, textWrapSeparator} = options; - const text = isArray(content) ? content.join(textWrapSeparator) : content; - if (!text.includes(textWrapSeparator)) { - return content; - } - const font = toFont(options.font); + const text = isArray(content) ? content : [content]; + const optFont = options.font; + const fonts = isArray(optFont) ? optFont : [optFont]; + const optColor = options.color; + const colors = isArray(optColor) ? optColor : [optColor]; + const result = { + content: [], + font: [], + color: [] + }; ctx.save(); - ctx.font = font.string; - const width = ctx.measureText(text).width; - if (maxWidth >= width) { - ctx.restore(); - return content; - } - return splitLabel(ctx, text, textWrapSeparator, maxWidth); + text.forEach(function(line, index) { + const normLine = line + ''; + const c = colors[Math.min(index, colors.length - 1)]; + const f = fonts[Math.min(index, fonts.length - 1)]; + const font = toFont(f); + ctx.font = font.string; + const width = ctx.measureText(normLine).width; + if (maxWidth >= width || !normLine.includes(textWrapSeparator)) { + result.content.push(normLine); + result.font.push(clone(f)); + result.color.push(c); + } else { + const wrappedLine = splitLabel(ctx, normLine, textWrapSeparator, maxWidth); + result.content.push(...wrappedLine); + result.font.push(...wrappedLine.map(() => clone(f))); + result.color.push(...wrappedLine.map(() => c)); + } + }); + ctx.restore(); + return result; } function splitLabel(ctx, text, separator, maxWidth) { - const blankWidth = ctx.measureText(separator).width; + const sepaWidth = ctx.measureText(separator).width; const result = []; const words = text.split(separator); let temp = ''; let current = 0; for (const w of words) { const wWidth = ctx.measureText(w).width; - if ((current + wWidth + blankWidth) <= maxWidth) { + if ((current + wWidth + sepaWidth) <= maxWidth) { temp += w + separator; - current += wWidth + blankWidth; + current += wWidth + sepaWidth; } else { result.push(temp.trim()); temp = w + separator; - current = wWidth + blankWidth; + current = wWidth + sepaWidth; } } if (temp.length) { result.push(temp.trim()); } - ctx.restore(); return result; } diff --git a/src/helpers/helpers.chart.js b/src/helpers/helpers.chart.js index 29c38514c..3ae792d09 100644 --- a/src/helpers/helpers.chart.js +++ b/src/helpers/helpers.chart.js @@ -1,4 +1,4 @@ -import {isArray, isFinite, toPadding} from 'chart.js/helpers'; +import {isFinite, toPadding} from 'chart.js/helpers'; import {measureLabelSize, measureWrappedLabelSize, isImageOrCanvas} from './helpers.canvas'; import {isBoundToPoint, getRelativePosition, toPosition, initAnimationProperties} from './helpers.options'; @@ -6,7 +6,7 @@ const limitedLineScale = { xScaleID: {min: 'xMin', max: 'xMax', start: 'left', end: 'right', startProp: 'x', endProp: 'x2'}, yScaleID: {min: 'yMin', max: 'yMax', start: 'bottom', end: 'top', startProp: 'y', endProp: 'y2'} }; -const isTextToWrap = (options) => options.type === 'box' && options.label.textWrap && !isArray(options.label.font) && !isImageOrCanvas(options.content); +const isTextToWrap = (options) => options.type === 'box' && options.label.textWrap && !isImageOrCanvas(options.content); /** * @typedef { import("chart.js").Chart } Chart @@ -286,7 +286,7 @@ function resolveLabelElementProperties(chart, properties, options) { centerX: x + width / 2, centerY: y + height / 2, rotation: label.rotation, - _wrappedText: labelSize.content + _wrappedOptions: labelSize.wrappedOptions }; } diff --git a/src/types/label.js b/src/types/label.js index 309c8f86f..3d3d6104b 100644 --- a/src/types/label.js +++ b/src/types/label.js @@ -244,11 +244,11 @@ function resolveCalloutAutoPosition(element, options) { return result.sort((a, b) => a.distance - b.distance)[0].position; } -function getLabelSize({x, y, width, height, _wrappedText, options}) { +function getLabelSize({x, y, width, height, _wrappedOptions, options}) { const hBorderWidth = options.borderWidth / 2; const padding = toPadding(options.padding); return { - _wrappedText, + _wrappedOptions, x: x + padding.left + hBorderWidth, y: y + padding.top + hBorderWidth, width: width - padding.left - padding.right - options.borderWidth, From b5f453fd329b5fcd25ff520886581ada37ad1cb0 Mon Sep 17 00:00:00 2001 From: stockiNail Date: Thu, 18 May 2023 14:14:14 +0200 Subject: [PATCH 3/5] test cases --- src/helpers/helpers.canvas.js | 25 ++++---- src/types/box.js | 1 - test/fixtures/box/labelDecoration.js | 2 +- test/fixtures/box/labelWrap.js | 68 +++++++++++++++++++++ test/fixtures/box/labelWrap.png | Bin 0 -> 23117 bytes test/fixtures/box/labelWrapMultiColors.js | 53 ++++++++++++++++ test/fixtures/box/labelWrapMultiColors.png | Bin 0 -> 13373 bytes test/fixtures/box/labelWrapMultiFonts.js | 53 ++++++++++++++++ test/fixtures/box/labelWrapMultiFonts.png | Bin 0 -> 17113 bytes test/fixtures/ellipse/labelDecoration.js | 2 +- test/fixtures/ellipse/labelWrap.js | 54 ++++++++++++++++ test/fixtures/ellipse/labelWrap.png | Bin 0 -> 22111 bytes 12 files changed, 243 insertions(+), 15 deletions(-) create mode 100644 test/fixtures/box/labelWrap.js create mode 100644 test/fixtures/box/labelWrap.png create mode 100644 test/fixtures/box/labelWrapMultiColors.js create mode 100644 test/fixtures/box/labelWrapMultiColors.png create mode 100644 test/fixtures/box/labelWrapMultiFonts.js create mode 100644 test/fixtures/box/labelWrapMultiFonts.png create mode 100644 test/fixtures/ellipse/labelWrap.js create mode 100644 test/fixtures/ellipse/labelWrap.png diff --git a/src/helpers/helpers.canvas.js b/src/helpers/helpers.canvas.js index 2ac271cff..c4fc2458b 100644 --- a/src/helpers/helpers.canvas.js +++ b/src/helpers/helpers.canvas.js @@ -1,7 +1,8 @@ -import {clone, addRoundedRectPath, isArray, isNumber, toFont, toPadding, toTRBLCorners, toRadians, PI, TAU, HALF_PI, QUARTER_PI, TWO_THIRDS_PI, RAD_PER_DEG} from 'chart.js/helpers'; +import {addRoundedRectPath, isArray, isNumber, toFont, toPadding, toTRBLCorners, toRadians, PI, TAU, HALF_PI, QUARTER_PI, TWO_THIRDS_PI, RAD_PER_DEG} from 'chart.js/helpers'; import {clampAll, clamp} from './helpers.core'; import {calculateTextAlignment, getSize} from './helpers.options'; +const BLANK = ' '; const widthCache = new Map(); const notRadius = (radius) => isNaN(radius) || radius <= 0; const fontsKey = (fonts) => fonts.reduce(function(prev, item) { @@ -143,7 +144,7 @@ export function drawBox(ctx, rect, options) { /** * @param {CanvasRenderingContext2D} ctx - * @param {{x: number, y: number, width: number, height: number, _wrappedText: string[]|undefined}} rect + * @param {{x: number, y: number, width: number, height: number, _wrappedOptions: object|undefined}} rect * @param {CoreLabelOptions} options */ export function drawLabel(ctx, rect, options) { @@ -356,7 +357,7 @@ function getOpacity(value, elementValue) { function wrapLabel(ctx, properties, options) { const padding = toPadding(options.padding); const maxWidth = properties.width - padding.left - padding.right - options.borderWidth; - const {content, textWrapSeparator} = options; + const content = options.content; const text = isArray(content) ? content : [content]; const optFont = options.font; const fonts = isArray(optFont) ? optFont : [optFont]; @@ -375,14 +376,14 @@ function wrapLabel(ctx, properties, options) { const font = toFont(f); ctx.font = font.string; const width = ctx.measureText(normLine).width; - if (maxWidth >= width || !normLine.includes(textWrapSeparator)) { + if (maxWidth >= width || !normLine.includes(BLANK)) { result.content.push(normLine); - result.font.push(clone(f)); + result.font.push(f); result.color.push(c); } else { - const wrappedLine = splitLabel(ctx, normLine, textWrapSeparator, maxWidth); + const wrappedLine = splitLabel(ctx, normLine, maxWidth); result.content.push(...wrappedLine); - result.font.push(...wrappedLine.map(() => clone(f))); + result.font.push(...wrappedLine.map(() => f)); result.color.push(...wrappedLine.map(() => c)); } }); @@ -390,20 +391,20 @@ function wrapLabel(ctx, properties, options) { return result; } -function splitLabel(ctx, text, separator, maxWidth) { - const sepaWidth = ctx.measureText(separator).width; +function splitLabel(ctx, text, maxWidth) { + const sepaWidth = ctx.measureText(BLANK).width; const result = []; - const words = text.split(separator); + const words = text.split(BLANK); let temp = ''; let current = 0; for (const w of words) { const wWidth = ctx.measureText(w).width; if ((current + wWidth + sepaWidth) <= maxWidth) { - temp += w + separator; + temp += w + BLANK; current += wWidth + sepaWidth; } else { result.push(temp.trim()); - temp = w + separator; + temp = w + BLANK; current = wWidth + sepaWidth; } } diff --git a/src/types/box.js b/src/types/box.js index 9e8a103ff..e78299f31 100644 --- a/src/types/box.js +++ b/src/types/box.js @@ -69,7 +69,6 @@ BoxAnnotation.defaults = { textStrokeColor: undefined, textStrokeWidth: 0, textWrap: false, - textWrapSeparator: ' ', width: undefined, xAdjust: 0, yAdjust: 0, diff --git a/test/fixtures/box/labelDecoration.js b/test/fixtures/box/labelDecoration.js index 6603baffa..131886fd4 100644 --- a/test/fixtures/box/labelDecoration.js +++ b/test/fixtures/box/labelDecoration.js @@ -1,5 +1,5 @@ module.exports = { - tolerance: 0.0315, + tolerance: 0.0316, config: { type: 'scatter', options: { diff --git a/test/fixtures/box/labelWrap.js b/test/fixtures/box/labelWrap.js new file mode 100644 index 000000000..625ef1d42 --- /dev/null +++ b/test/fixtures/box/labelWrap.js @@ -0,0 +1,68 @@ +module.exports = { + tolerance: 0.0075, + config: { + type: 'bar', + options: { + scales: { + x: { + display: false, + labels: ['January', 'February', 'March', 'April', 'May', 'June', 'July'], + }, + y: { + display: false, + min: 0, + max: 25 + } + }, + plugins: { + annotation: { + annotations: { + box1: { + type: 'box', + xMin: -0.5, + xMax: 2, + yMin: 0, + yMax: 5, + backgroundColor: 'rgba(255, 99, 132, 0.5)', + label: { + display: true, + content: 'This is a long label - '.repeat(4), + textWrap: true, + } + }, + box2: { + type: 'box', + xMin: 2.5, + xMax: 5, + yMin: 0, + yMax: 5, + backgroundColor: 'rgba(255, 99, 132, 0.5)', + label: { + display: true, + content: ['No wrap!', 'This is a long label - '.repeat(4), 'No wrap!'], + textWrap: true, + } + }, + box3: { + type: 'box', + xMin: 1, + xMax: 5, + yMin: 15, + yMax: 20, + backgroundColor: 'rgba(255, 99, 132, 0.5)', + label: { + display: true, + content: ['No wrap!', 'Overflow ' + 'This is a long label - '.repeat(3), 'No wrap!'], + textWrap: false, + textAlign: 'center' + } + }, + } + } + } + } + }, + options: { + spriteText: true + } +}; diff --git a/test/fixtures/box/labelWrap.png b/test/fixtures/box/labelWrap.png new file mode 100644 index 0000000000000000000000000000000000000000..e5d022cf0b8ba0047726f36a32dc8a7c905b1a06 GIT binary patch literal 23117 zcmeFZWmuJ8_b&RZMVF*>hkzg`dqhEy}X6U|x>=O^;je5Lud##JBM*g{M_9vlnR>}8w zKCVp2_*{?Ydf7mu#hy&-!~dA{x{*8|>yv#o@&~u$PCxg{#NN}oc~k!8%aQu44(F+v zZ&wz6efPY#guaxcd^bB5_Ktm|me(t0Y^6uWz3YefeKooz*qLE?Dl%{~8+!lek+l{M zdT_EBBqlqvzbed>_?Gv?c$DGn( zd#MQ1Y&G{qF?vsL&+H{!{lMN!{8kk_Celq7(}YP{Z8a{P?%J14T({mfmRBS$TlFi{ z;1M)bl5`!q!z*0Q>yO8g3FSL9--KT1xuKVSub z#2%Z2z0e$q@HH z=6nQw;PYo0*M$g4ixL^JVOUK9`B6*n@sR_LjQQ8Gnq-`!etqv7w~J4WwB$;1S2+)l39XyT3Y>72orU0@Cp8(keq7 zO^KW};Yh_G4$CvNp}616&vQ6uahq0>iMz7lrkd=^9t>DbxMtC#Pbi>*!mulWhJFbayky_lHXtQavK!=|$%={s37xuVS_PtY?D z<5U$qKkkseb~WQNs5W<&Sif#LHf~#-R=@v|zt?#8UE;IGlU|3iJ(RR`?cum>IaU3N z;@IJYLq`4l_2SO-)1f@R)NIr70EtP@<+QN^lZ!ug7Y8H6Cnvj!jj3tw)1G5d;+shu zUkBComvEaxZGSoTaznx0?n$~p{;``eMPDFlvQfcmI||6bYcS=u63j;P>hh@3y46}5g+kxUSIqBNYfv5xD+->6Jg0OL&+Y%o` z5!A=bJ=_qstdm4BDOM9p2t66?LB{2N-k9XkB)Jl7o))^yEuDTAt5!zryB#>jDYX-} z{->b$T87|@7-=BE#`UEXhij{=&Cb&=3cgTYDntFVLT{RuoxaV}K?s z^wm7 z535?eFoKt*PY0salV2WB%v@5^UVz)eaZY%*-OQgs& zwcTyk?Rlz3J(y<7xE@~)KJry+`wlNwlW4*N*>v>%{rXP-<#i|m?sK`9fr^qkT@k=1 z!GfIs;6lNZIgn{o+Ey#Q_vY~;zaLFs&Jn7#o3A!#1{dR6F6puFlg|G*2c?&;`IS#rrunQjPzSIzu(~_-??V-<#9uQ9zWLF`|tO7 z@+M>>Q`~rY`r3K#5p;e!(r7H|ca?rr$0@%0A+}8V>I5}cerLqc`3;BHwoeC_jNLlT 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 II;Vst0Lu;}dH?_b literal 0 HcmV?d00001 diff --git a/test/fixtures/box/labelWrapMultiColors.js b/test/fixtures/box/labelWrapMultiColors.js new file mode 100644 index 000000000..751a0769d --- /dev/null +++ b/test/fixtures/box/labelWrapMultiColors.js @@ -0,0 +1,53 @@ +module.exports = { + tolerance: 0.0137, + config: { + type: 'bar', + options: { + scales: { + x: { + display: false, + labels: ['January', 'February', 'March', 'April', 'May', 'June', 'July'], + }, + y: { + display: false, + min: 0, + max: 25 + } + }, + plugins: { + annotation: { + annotations: { + box1: { + type: 'box', + xMin: 2, + xMax: 5, + yMin: 1, + yMax: 6, + backgroundColor: 'rgba(255, 99, 132, 0.5)', + label: { + display: true, + content: 'This is a long label - '.repeat(4), + textWrap: true, + color: ['green', 'white', 'blue'] + } + }, + box2: { + type: 'box', + xMin: 2, + xMax: 5, + yMin: 10, + yMax: 15, + backgroundColor: 'rgba(255, 99, 132, 0.5)', + label: { + display: true, + content: ['No wrap!', 'This is a long label - '.repeat(4), 'No wrap!'], + textWrap: true, + color: ['blank', 'green', 'blue'] + } + } + } + } + } + } + } +}; diff --git a/test/fixtures/box/labelWrapMultiColors.png b/test/fixtures/box/labelWrapMultiColors.png new file mode 100644 index 0000000000000000000000000000000000000000..083de59ddb4a876ac4c280eed84a9e0c6c22b30c GIT binary patch literal 13373 zcmeHuX;f3$y6s9J8VN$^jEaP)rKm_Jg(wIKC}Im#p@ITIRK$)>B!o6WX;cujY)}yr zv=kH&1u;PAq!F+IN)QZ?gho0Ep-&(o$=%>N@4j>E-Eq$uuim@kjVFIrvUm1g-(GvI z`OP`M#T5rT+rckkNqD*$llBOD+XK+Pn%Sp+q(fM0E`!SnhRg8<;b?j2SK z$i!iG=nFT`aMRHad)41=Uaum^We^A@<=r9`h)W3uRG6`&wVCP%hh4!KS3>k!51kY z!J^IV>x<@&Q^8TCxfVpqBjl;_$v(C7zb630h4a@DF2do2i~CJa%-<6S?#j)d$63K( zxHnHUH_i8j1|R;`C!GqeA8lHE59&r9i3EM~Eqa#&0qlA)7_)D#dwF>fFyA77T89Ha zeYvoG?R;2p>el&IUR50pRL>QyRGSYMR=#4s{So$$(T2f)OcDb1$CCVkB-9_cJ(uEs zq?;dE^1p|Zocg`oJ$&+bIxlr|?}THz9h+4PTdp2?70F{6d$xVBVCKwnTZ!SvZT9@S z(+=WFI=4Q4TjR%Clf?1=+Prn|oe`{vGWEOpP<8~Z1uT7Z@a)Cx_L_<2X1jLRv?fddXVSr3DX4!`3Y_Jf5Ji0B|~9` zrk~e^C}rd)h^c;ZaVP*Vx?ze|=EkE4`aAY7E;pek6psfARyZ4P(%d|At(h5 z4yZrLJANB6o&~~0>0EP>HdgXREamT~gtTKgvx1rmas@5Cmqja^(oHWN=`&V#E-ig_ z+_l8B=RsaskVGs@&TDw$!WFz>3bpR%MZn zMGYU~$wajLh;Ggn!FaroBFh{>QnaOfuOXtd-`FKaitKGy_1RpRq(28Q>N==N+;*z{ zxz=`%cFb$v;Qh|03xuX+u1gNBs-Wp5n^U}9!;$^r=Ok^dG4?aUlF7`TO0Ij*yU?=P zF4Gmlux_SECRGGv%iZ=Cnpn~9u&!jQn#Jp zJiKNER&1k;of<-vHR)aSTd7PF;VB*WxYFu7Q>Y#tk>6OUxY|nzyNta#?Bn`=PTqK0 zdqcb~f+ZG=k#>-7uau|0fTMlwXWI=9X{ledaYZ1zerndFxeu5>lvAx;2`w%?8^!=Hh-G6{$_0e+;eOPD1?R(FWzX~n0>fv`BN3f15SC2$39lw_czkXMM!C0msyLmU8I&{#GD1bzkwc z09sld&v_OIYOZ$v9h3>9Mit9Va_!O*G=w|!gC{UB`l@RVJ1K~9 zd8#z^rOfs{2aDwX(kL_DvMTZlG$v}M8;6i^!r}3Ha|amgD7{$8t}|$EP3l~l$DXhi zk!$6_;B{HW_(c=n3Y@&W2Xng4&!<8 zi1Fv3DsCp`^rK1^DqtC=`3m*cFTNbq1eWf?Pet$-B+)>Y@f~77-IKxNs0vV_U_JEAYI>pt)fFA*V>bLG zIFW{x`gA={`U0a+qHh8?9FgZ@%8F67*H`2u}NILx{?&j`y!kvIHEGN zrSCKTh@||1yH;z+2i{D@-AW^UZrIyaJTti3krj|&n#wckA;pmz*y9}^t}To{ej+hR z(wrK&ZuyFeF(v|p4|lW@Whx4wOY{ll3RBNeFztQ z^&7L0^j>Q9^o2cOevJ`UJ(f@&$jbfwnJsY_1Q!L(S^1Uzby8nO>gx^imn%sdiE8kj zL(vl7C7f_U&`y1+aJ1ip>9^9mWU6sF$nC!>uI{Nhiq@|f!CD;KFX$NCVp~=;$#U3B zY9E6WmfEMAU9wkHNjhgCEj)^Ga?Mqey&6ox^S`zY>D}~!5!{6_m83V%TPZPcLe8|w)RDH&_ZIK!vQD+=Q){xl zb5hRni;NkNx^;6_%xrZjcT47gu^JmrE#-$V*a-%Dlv9>t_kawKrdu6ubaxoeQho~& z6j167lA`PG2- z`x||}E5XlYHMm=7E5gipA!{Uu<)_k$+!inp`r{Wh^jyVc;&|m}V;F!eY%B&y| z!(Mi1p*4L_fIcc<#kQFB=>7JhLS7UVpyWtjjN|GJ3Q*p};E5+QL zIY7JdH$a1cYq}DyYo}^h<#uaV{tmOJ-MP?iC}k@GM{1ck0~(xvC$NvB6lobDWG! z{3;k-Wby4l+P{?B{%IC%`9_2K(04{xLAwm0&y#hw-8S9WZn3R}?+ncoHe(>drsg;v zZUrfWk!|ye<2DME>EOV$&Mz_0WQ+-+)UOAVHGllFVeR$)C4?abf*{ki(og>jsaay` zQ_va7iw>+$y?5OH!}7zWeyxpt)9e|RM8Gxi{fTEDB>eEQ#eOCmGmzh8>s4)_tss6d z`Yu-oyR49Rr+_{1N^5&pgZuqb??E2h_-%LVr?+JkpT4)3%sy}BC~U7j^7z4hh$c*V z)91&gI8hgLIdmNh`;t(7w!&sh1gfJqxnWwg#wC%$ZOC)?4Rx)~$+=3JE=K4VSu>r+BbYi^7r_1;XZ zJ6m%|acU8e2JgE=1%`(|N$`oFk>Y5ZMJ43uf^2RiP4Ws`MhUNcRl-%HEk-%{gpCB{ zVfsgdR&IR7L^50+`nmLDh6sA%3X0GJ+%Gi0m4c z9-v$7IdvTxW$sA@NN}aR6Bod*hc9y=i(QxiZBXk!Xz3bt99+hH9phIr%uhPMRmMpC zcnx|5LOC|P+_T-TSbQ}&vAE~-|-fH3P`5bh@~isSRtE%z;fUs6Sb1#8Twd!Pks zN{UgHU+@xcNCcPPPXs#w%lxTZp|X%JHw-CM?Be=vk` z-K<7OC@}A=|7rNysW3?JR7}8GUf@u}7sC~nbqr?hNrOfwpKaoV2@H2S?ZtUCzOd#q zm27~Q3YoTv&OOUOQ^_+3(hiz8mFUCh%o}=V)-^&?iM-f{DITM-i@TrN*^e+dvD}}- z&siCiAx7(>gHkRu71!7+7o&m}dk1@dd!F`U6?&xCi-N+5T^2^5=rL-!Z`Poo@Se|y z7j{t>NZ=o&W*$R(tjp@Vw#Yx*fCC5ejoCx0ph%PTFa{oc2#8Fwrk{(Zj}iq`H*<=})AX1X8&(&cq?x;zW) zOPIjbuL6qJpN;lnYSn^{1}Jn;ptJyDoVQYX+*eXf`D#v|x@Sv`p ztnGAAm<|@NKjbbLHRq~cv@IB*O%%D$u8oS%H)wEKdgk!YKNqc@Wq`)Atv$P{A(?;7 z=iryUAj2Bd+!z!|gqQ0m$?C%0Lqt&;>3rFcj`BUm>EnuEVFPzlTgaP{3voEt+RAik zgLV*?L3!ypRxy3W(zSRbVyy9!?aqEB_kec{{^6NM=HEqXa1?LDb|mmX;5ez%4EN$e zI(lRG1_DwijWa!K%~jF5PEdk;riH)Sn5uvcZA(4(@1rMy>uxc4kFhxW;?eQhHC+wX zh^~hbW8=1zFT*R}OgnH^PMAJtmj?7TS{jq$qh)xq^hqEdyVWn)*`%QRD>LF&$w4%n zP@EC#f^wprZxtGZ52X0U!O~m+GOcTI<&bH#3tX)!*EF&lTA=>ST%kI6$EQvx?|^b5 z8b6FLoH2=gD;}LQJ*=Yaza~ECj^uZdteqDjX|p|faxBkT9+VT7YPIx2BoTni+dnW)~b#VoUF9>q`{E= z6KAQCWP^kQu8`;C<0MFh6Ifb)(nzHGA~04b;%yHZyBR+FlQzYL?)FD^Su$7D4m@Zr zF2J8wFpkFVdSK?+a0|V~GVj|fwF+aPqvtlkOQLNRWSuh{vjB4UHY*(=KzF7dy5S~I zz528DGKmJXYDJ-MrP_L-p|~(xD_KM5W%;%GxPO#$^3=$2vn`R_Ig2bs@$ZZBJ{tUd zm!JhrA+rll!>`RBK0jCX{F8r`1r8LNpE>*69P0agNB!)%itHW?8tn14>VnHtD=v_- za;X~B4MDcv`ymYf*1mt<1}xNos;-3ZuHQOW=mvM|6AmtU0e9%-XJqe&-d;F!{lCT- z|JzJJ2*)fV25b1_9)4QuM%pHED;M77^ET>&pe450C@2df57umS z>&&q{Kj0Qd6NMLc4^~!P%FGC)G3Yila!?f=das`AHlQ_ezaCrIGEy~>+;pMmk zT6y1#AM0=`5XCCJw&ee2wc|&&_zOx#fB7H|yoQeoQGE0602E(BU>do;7|swkV9jS) zdj%zu?fvms>F700eKL;8j%#|Ym{PH==bo zc=)BcfP3GIR@@#INRw@$JC+0|{xL)fuDKb+Y?;8Y?A=3$yQ>(Gz2f8Cq9RYt{hAU) zheI~hw&3EszIQj9Jt#3u^0!Js?pik0S3>A#Ki7tQO`T0~SBG_hdO&6c5l+x3qQ{h? zCUwDzqJTdpGQG}i8GuA%tR2~trIr})O4>W5P~JB9D6if*QKwxpf%L)MHe;Z5cTKxSUee=zd~oPhJ|v(jA!ei7%p+;rGR!oi!B z)xyanWnxkZ!jJ!(CPytvAoG{X)l?53G5EwnwK?XsDAlYHm$5_Io}qC{?JvpukxR2N zg0jP8A&a}LaGG05iyf|rel^vy{Vb?W)#YOnwJ%u}Aj?80FPpFeYI;^kzJ2oAuE+AO zK>?3#Dc=+=jdr-^PEGe;baVBuGn;LC5+p6Sc{Yc!uL!ck*_ul22qsas?9YyPceG)| zp2c{>9-ED~H1(^-;HI4P=@tztxeKL>N;#yMyMkrk%d(&FPd*1uVb)bhjqZl|)3j4& zzhvF$9j@4iH1jyPinuhlhyNOmK6Bd1Ycnny6)d=Gzfb${{l)t{WFz&#eP3QIAIFFz zda@oi?1QWiQIT-jQW!lEf8h*y9gH5c-|>9VoW(tj?j*xHrCZBfRV_cp#?6r5&t&gy zW33UraA)Gs4VwBQMwYnqW53?aw;3by32n;{3#cSz!`BO_WDmA)Yll-Fttd}d%LB36 z7fiQwq$??6Zjk~LFo3@zL{v*oUPUtDSR$=F9iSPBpz`rH_sgO|<1AKZYek(R7_(l1 z4~!9aj0Hz-j7Se{8(Y=Rmqw6iEpdVA;JO#$Xfbd&fxwARmq6Ph4}o#AB&=`mM2|5h zCG`rl2(Rma-`iS=l%oZRf3RYY=EBSMhV+YPir1J*`HsP^i%$uMF0tZ*XRB5u9W{@> z#M2ReHr}jQW6x3xUqE*Rm#1RajJLPCUGQ?&LPkDm-%e$DX&)JiXY8s_uq|$I7a0F% zt}oOTp#aU0E+H^OC$k$sRA?7V+}kzM?smcjKU~i-wg~GlPi^5Y9T2zxmc|vIOa+?= z6t0;jIgpxd{9LJu3qK`kCcgEBK`&{&F#peWh+^oirJt)xJ923U3Gr}>v3$8v=Z*zN zwWW}FNZIjs0U}TBZd%?YKH@gTN?i5cb9l$jx z5I86TRNC@SyIfN%w%IIa!>fE#@_1CJlKiQammyEJoZY^D5E7)jNA1j=BO&jz$wdfx zs=fKc#J4?q(ZgC6>&p4UkZ{1}Al=uHl=9K*(T7AVUK@YuCKJ zpYZ(x3fXGnPDQ$XDXFKhl@WnBpB`)N7_v7F7)EN_X|x>#84kv`KHMcC+_ie<-BIF{>yBG0z< zcdRqGd%#C0d1K@@*wNfG{;5|`isRlSwH*E7)nw$0QVC|Bk|eIifuDUtz6Ni38T{zE z^s+qln=r#M`Y+I;gjC2wHkes&#-Cne=pkF!`n=eK#qWAas(HtB8!ELC>Y8E2D#$rT z)gSpk%s4o8{f?uMsQ}Huf1e@rTF5L&?y&Zsuf=Mbx{eYAH>Vz07}uoUHOUQ|t67d^ z2IPr{%g%CkeF@_8?;X#kjl1B}a#AeKbR&d>Fa1$YcPz$gYdslN!#mT5mnu-CpC-Nc zdX1zSEh)RLFO|&Yk>;oMV~3V5P#Ec~n-l8Zh4WGU$v|H8;XgHy4Rs>Ux;XD9pKGZd z=W+GgO(?&+fGt6Fi$}Je=zqwKxvo+cmd>6@AP1J|rMozEgsdP~R8rY16d1d>B8gvVvjxIxE9{6>F{wuJ{dCtu?F307LKs1J0R`vU zuLQXpjob)|YMnY6tL>xRQObX4ZXT_CGrF7(1#eZSBrSlKcV0_LlaI8@0`VBoJst)X zVeGvvdO2l8a%(i3C{;}wH_rwqPS>EcStI!)f(W5%TkkECC3DWjwt43wSlbEOYavSc z?j67WORQrQ@vpXyBWQ&G$~u15_J7(so^ydB;i@WggLi6v@P6$6`uE*me>s)^f7d;$ zd+hGAEwC>cv+rK%B6S%2lG>M2FJTAQuKlG%<{JL_$|du-)ymccur%t~@jLpXUCI=4 z*N1z?1{+Jz2=p$((f;}rZYjTLDAoRG#2@Kk-`Xo)bxd0~Vj$c3)-@wI-z|BgBVx zk!S!zAkmc)KIbRhRQy@?zv5sptQ;1==}=g#FB}1AgVdt;{|g1q((FI;L<0+k?zT>! zr<4Lvp&xtY0i1~e3AoN&HNLS|GZs`H{_7obFgVs%A+>R@JRK4orrN){B7_D{a;Bah zp|k|R;Nbq=lK@6bO$V3`C5WEfYYH0NJxF;I9cl;%V3psJf1B@>N6>*+`%fac*iqn$ z-qVs-`%Qsi&;8She`eyJ<@C><_$NC36Jr0#6aQrFe_+Rd9Xn}+!JP-}Yg@t@k8PD@ zWX!oJIfben4`uVwNC;B-dNuB((;o;y4x4G6qr~LR%RtWy_pIV&nTSzNjxzngMs;-?SRL|6Q z3Soa@(WK{Hu)27!i>;5SUVMycEA<5j`=39dN8UzbX|9|=gPg(^1aP-fY}AKAATqQVYV9A^!!G{UsOFA$)*tvNC1d|rB?C&}i=#DP$^E4nPRUcsv%g~(yj|*wCbOp7EaC<) zJC?qgZ#KStfke_Zy!`0Lbw7r~h?qmz==a9-K;ra`pC6IH^jU5(H(UUQUioQjZ}H_8 zej!G{HnxU^9_XhDI;g?X=YzTUE#MzvIHjr^N!v*WZv5J4rLO8qGd6_^SN=~5qo2Na zPQM`I=2Sfv?N<26Tf-@+{`4mNer(yJLyCOB>|Nqd33^a}#XcgQo}CrQ>)Ono8|qM` z!K~U;`7z28^&{#(?`-7yRgkBA)hZ0vcc|0X=C3*vEmk8fF5Bk5SC3mewu2`ItkdKZ z^TZf_`wA20-MUJ%`%wkl?F;ed;_tJ`p8gXeGHkn^i&GY_vs~}@#>hV2o-$n`yqA1x zeCNVUudL3_ zt2Rrrs8Fl9q2L()Ph=3M$NE-KXV9of|B_w0x6#^Wx=aJN-g$vQmeYv^2`o9e4JWRW*IWKW_8!j!zu8WfX;Ej!sMMWk|VLI%7 zt&^BsCqI96Ux`saOC+)~G-d0CEKX^Yw3 z&&MX4W6I_iQ!N?@s+fu`qa(mgyTH(WY9seS9Mk-)P(k$Z;l2(|YnQp^Aj#b)OIB?1 zPnIk(lfMnEJ1LM;Mwpp@v8TD%? zX`7M$JbmxT?!Og{FBtaE^X9=(0^d(%%U*U`Tg%5BIQ=r_v3H9_ccbjA?A1kT1ybr3 z=HOw;d4JD}BEjM5eBOA^zGrVQ*D2|6{Tco?nu!0TSn+FQeJ16!toH88c9(l2z!loo z9Z8UNaob4gs&1}0XWOf-JX5gB`fe2O6J73M9W7%R-EN&;ww^{kys^wB!I(DZ=|a3ei_LWu0aS3bb0f*^f)*t$UZdI02}KaM5oOp;?A%^akHZ_ z8Nc~w=YCY4t&ZKwy!xfW9ZZl3_v&DlNK(b=d<*lw)#lgn%chv|9k`fYcA(Lj5O3#U zB3U+%lpx&UxsZY1h@_=8&K>*8CfM-tXPk`XL~XkNOG4uiuE2O}D{O62)YGhGqgdLo zQ2I>BNrBPboi$|wyQhYr>k^q))NMX}x6I>P$B1`2A*_W8yGV-5KIk!@${B3XnV~rv z9+IWsKOWsU8N!jyVoFe&T>I=f5oR?Q+PEd=xixvg)_8G5ymXeia8r{od|~0pS*K!c z-&a4pL@9HQ`g_h9K?Tpnoz)8cD^@FUl9$%l{E2-Zw_~THjs7eXJ3U*pypM0)1)mpfrEcm-Zbs;nuwXjJnmarX&w`IcEt1~ z4y^jCmAW-uVAGi=bQquMl69yb&)S*KlqTE0 zY!fJ`kA}iNW;NjVQ8=1Qq#*xB@fo9dX1IfJ$*tueA_qY@XVF>!HT-u|wwf=w|K@1YF~4$GUG zR9HQq81b2Gt9JEWOUdA*E1Csn&1+E(1zEF;O@eXFn|GTFvJ9ELdrfTE^58g=&!K(I zgCzy?uk*#jYs@*ey=d$R)f-*AgcNbIvvb1Lr{CF@&-;n{zViFGnH1s!@q-(AY|drk z4lUtUvWJD$jtgYrGy7~^R%MB0x`N*vY1b|tyG;J1l)grs5hz%VtIP7dPgpoBPvSE^e*V*4=7Cb)=#utaxMBRQuW>ZBB{}`N;Azwj?Es z25f5;@v*b*R%98u3})+ym5q&Fr)^q(&&U8wJauKqXJP2xc}X42yTPft$^vC5A?ud6 zL*M|)?IP-@KtSBiin;shof*EO@fII}(Mc(3n@0m{CQ4Z#;Qptsx*Cb*hbDID=K%$( zam3AEE%eQS)??yNSx(DHc;tN8xRtm;Q^j^&Kx$n#!EJ%HPkxhOluDS>iTo|OE9=c= z&cxQ0m6C53PYtBMT#tU8zCLgB2g(mSx449bz}7bPNs|rzidJFmbQ}jLZpfWL5A;CT zU{`|eKcELYRpn$-mTcPmCNpoDjOMOE+*SG+=Q%+~X6%&;Qi7M=5!|EE<@Y0{n{TXR?(#FGSbIZcxH${6wmBY@1Jz=Sj)z9C`J=Vo z;1X1|iD;4p&ieq$^idnok_L&(4A?7WdVadLbnSw2ON3G;UeSt$ zU(@%;1s_&C*etg|rG+-z>b1%Zb_*72*%oM3hzfa$*&dGX|FFK6218?NLNRP}{mEZ; zI2$d~dG%JC^fsTM93780Ie-;fVd~5?XLIIRQJ`B}Ob417PLU9y&}!(Fkww0k^5ZSS zARtM>m34@aAiKf5`(!wc!*p84^zzXF+aoF-+dWG}V$TjoZiv^(1h?>njqMlKSGQb$ zq|H94H(yI*%cMK%Eb3t%=CPICi`N-fW#W={P2Q>t9R1ZU$UFl>OWk=`^-Y?4Y<*|^ z+*TsuaKU+&j)3_u94KHmi>d3;hY87tcsdA&-T_E%qg)Hc8b@0xSv9YYW@6+wFCu)= zE!gYM6;FCRM%!Qe>kp4VAHJ&Fy58ZsUapSbD%?RPLEV46-cW1R1m)*V->7!$`BMV! zONrR*q=EaJyJ>ir)k03ZN1(@UrR>_V)qZu+!^H;7U?h%~O>(_=CH#W}P1i#A#^%X4 z@9_sJn=gK5>oXTbgSsYs%LO*Tz+tv)#30WIiXWHpzg}hlQoowRM)X^Y^3JU{ zC89xqs!o_Blt@H`g~3{9aMV|L==5P|Y#Nf{!r6em*2`|jdm(V#QBv~5 z(v0Dz8pvMr%Wqs+*Cew!N|tjAkTrFGTgDO6P>&`_OVvO` zR{5kVgu!$$ux^Juyhs0Bsz7FMMS9#6R!?rxO#m;$^4Yd(R=dY0fzW_0N!YoBrk~&d z)teu)G3RbSevf~wSTH(rp-G=yt*9*aJLFTM`ief+{h1be_5Swvga`R(xoypmQ-zXW zd#1?~^WEJTuIti?q)*0yrK)Dg~xv9x+f5x z7Z3j~nOJ76%9N(b;D9Bocf92d!oFKLDX_*XmT+ODNBQHH|3-1Qno0`k1FbYj3s3D= z=fTiWoug;ABA6Gt*|^5vo0rUHwbm?za!0bP*F3w-dHGjFqjKZ!c}ftZllok>PCjTn zKiQjUK6}#6Pf-uxvM|rDXW!+l)qkuEq4%hyd3vzP;TD2n*sYUTUW9J%O_yJ8pF$zX7zzaAa^%IHNE2W_iqEryH{FP5(9Gp+PI>K z)(?aZ@p2zvRscCU4=+j>QQBeq`2Yh@cCyW6PnxJP6E&FNM6B>zI|iD}O>!W{Tx(Kx zyITSsY%yo==N;sk`Q>j37E63InSs5j_3xDFbE{f~C2hxb&L-1fHzhCSaj?DAmGp&I zruWIroDkEh``pk-dm=4`1EdMVP+QqIr)}kc(DqTuo+?usAi{ym%BAtA9xV_CaGcE65G|a)Lw7oWg4ZN<8`_0Q&N8+*VPsyuLjW-9#8>L zePU5{-qH{I`%E3t{Y9KkY&bWf@1UA1Ggfanv}^M#o)&cm6d83D?H;5Db~VdirC})9 zd>lVL13MJk1NC+fVY|fLws}A<1dhZwE7oJpR@F-*$5okMdgqZY(|pHMixQL2(1U66ldA(9$^I|FUKw1;b<>QIb~M%fTMs_%3O)- z7BlM%!}Fa?zp$yClLVQZ z*1dxer@z8GCH_+sW+CH$#Vq`19K-=5SO6(wGp%p>*SVgM!X6HpjQ1sq1HmOUUC)8W zM$E4nIs`UjOv3gvTvG=ms{zeIWz*!)+5i$N?hXsvl`FQVw$7V=YS*6UfT4W6g^qAP z1EDNZsj9k_d|;#85vp=PV|4XA&*1H;dDe?xAVe)=ZIlfd zvUZY`oVJ}D6?t(%Ac&S`De8NL2bm9sOY?5JEqMfn5;tIq|A6iXDB0oVOQm8aT0adL zT$SIs2tMDqJhyJ9yh)5x2KqZ6gy;GZ*za52lBsYzDq#DSY)Xwryc1%6H7xRCcbsD~ z3Ej<)6$%k*s_GNehXp_f3L9lmXKVdXANJP+jr6Yz+3~Vt_4nA4x_Eu&oVC)FDQ#w7 ztUaYz$_ni79E=T%hniB^H;1PKWgiwbgttusOb4lu1@O@5LWuncBO6AJzo7&AGY$*w zh!GmliX42fUc(OtZ+Dlgy`qIaOj8Mcg7o0i_Vno)A9|oLK4DhF8o&x(b{uNbDniHF zeibfrwBhxM1M``(f3F4fG-HU+Wx*(u>_3E)(7DoTtm_(-67%1W@5!TY4<;8PQq>BGa$+Aig@Vjv9?f1si%D`<(y0V-V z_!aEVEj;5y!ha;cUGv{YA}LkZ!uDEd53h`da^_Ze-8C!-ec^U~k`M5W)@j-cAjes; zcsNd`LHp^XqNjgzkwsFjt72EX3k?md$C zJ@o7CR<1?}A*>w=-OJss&xFBiwwb}yxLaivKbs(d#! zT>2rk*{#FEH$m)fSKc;mj?y-SkaOW7{KX^}E!*!! z(t7FBH&-Qs2!T06;`Ht!t+VM&mOvxqIQ)CK6@hoTapyh;@7%NX=6qV+cCB;PPWaAG zw+i=z_8L5~8rLWz9<)E1Qs1EPX^tM5w>5#G)#~i0O;o<02X*ukQ&-En&efd9$E?)k z+L|nmh}@$Wh`jeNF92-FeUkaD=Wavc4;#s?>9>~aHRHY*=A-Kcn2ozRsL&`Vs)+Qg zgeZfXgqRCvsL&q_XblkB_(xM0>=bkjt>agl8riA_cLbuBw{^gsUfkk4eD?!0vP1Nf zK$NeXesU@wgv|B!mnMA{NNXf{tpgWokelhoTp4wpHa19o*(5yUsvKcGKf7X+Fz9iw zOiv;-sUM2wWl>_g?s{a=(qdZdaH1~6pO^@<4T{3iMJ$GTLX-h5qv@J;+ftP#S+AA4 zV=9;`EO)bP?C{i22+PzR>!RriLN4jTeVKjU8Te}%bahsnGlihtmU~eI9H2F$zx)F&f>9Nhp_wE zD@dVWAPj2k)JD%Buov%0JeYuM!m%D(S)_Q+o+q27x3`ffo-+`Wf zLGv-yy*(_2MyUa${~NK9weIS6FV-8c?x z^{sC{w~U~(uPqd6C@@*D2##XBQ}t?L`m$5+?^&6{LOdFL1s&0(al7`R zD%>?x7PNY@^t=iLDYRxDpPUbr+m}yyjJR*vhpjMxnLjHXAKeD7qr9`#=0;SXjRgA6 zAVdW*t}=F~MhgCrve~nb>0mZaR(+>H8;yjman~{agWHe%u6{ZSrvvm%SNtjHrf_3F z*|8bGkV!alo=wHJPY2QHl%T!41N z`=P>jxSbBDmf!pvFU7>vr1a${|1uE=KYQ~^d|m28b|Pdq=`j}xwkK9ePciy~D>#=m zZ%Qm#;B|4GXUrELUE@yAM%E&0Sz)ND7}5v2Y+SPFynB8)2wlWEtUQ7GbwGW8o}ul% zE??Eh6 zCcbC>nS!jzRkDHW9Diw{jvF=D=0{tuuR?@pZF<5;*bmP}PNNgLY=<@IVjx*VrF}V< z8HVC@#BtCcs5XWnVK~R|2esQaIl^YtXtjPTruGC8+07tzQiylnn1`LT_uUSCVa^U~ zNsLL-x}mlPQLcr^eO4ca0(??aT+&=nLioN%V~D7`Kp7Y-q&#c401H*U8&WoA5FU~J!J^&4Of4c9zhFna1?x5WYiz(Mz3Ak2`Rqg=ZIY$Ynz}h- zL$G9tKjaBy=Jadx-meTb1p826cBH5PEI zs7TaV6@gV&&zBP4xiiiX%{?Uve{`Ts*C}mO>-8EFbc_{A*jj>A?>PHvE+}x@Yan8W zptMyvcz!?iF(Vw@F%3F2nI%AnLZ}?)g*Ghv;5+kU#yLYAumgX`f`Z(Rfc-* zND%4;0!nVZ8NU@84TqtMy)9~FSYf#Ck@##OcnuR^Hhwz(lU7%Z>#S|viN>0r$>|ie3EI*uw53PbID;Dr0Pz`kEo&Gs(=L zBul(JvA!;Xc@n7S*7dp_%}+Yf``(6VG0OS<87Z}w@Y{ASFSX0_Y)iIkvhj>%=t6`J z-9dxzy0zcNEfNalOfG56Z?ARf7K9bW%LAc?q`W(7*TBsek-iT^G=4%PB&NLCzO7BL zSz2+naa{aig=g8;3c#u3?UQoq`-ui$Wn9y(7a4$8t!6W^>xT4-3-yWBEju_`Z@1cR zd#mH_m-VSPKlaesK}VDM`t!i$HH&Lf;ME@~2?X=ZYu6!|He2B|F)0XQ`f@FTsb6w~ zFwGmOH`u)a^>_Z7=z6G;_^CK;rfGOlC5K z(UHb7!=7h?>g_0>9s0`;$I-+ph+35ls6PkMJFQ;Xr7NrWx?LS#-UawWHFI}wpoF51>kY|UP+kT|i89KIloCszGUKG;O zM3{31!DB%Uje@;>gmnal(B8+x4pJg9yJgSfw)7+T*Du1c1oNn(Z<@SX2rOdfuK80s zIQqt7{3T%itTA}rGu$?q5Pw`}a`QS}@UH+uIA9Otzh$z~m)UYpG0 zB@E=)oY*D9j}hDGz)Z|Qr)EDowgh#Jr=DorX@Vp3wuO zs*rXhGH;o^lM{}P(eUzyB!GPu&Xoxy8+tiM(~8v2K<#mEB70gg_6kA=-g_q>e=b z$HCZpro0pPe57c>IafDT(R*Ef<)Sbb)v0?)6Ya`O_O~OtO1IZkM&%hs)=n8o zI!m375AlR>e;QThO+8dS2z~PVO1wX|%RC@YK$jsj1KKe9&89rBfrg58llDdEY|)y= zCZX9v<;zg6Ed7SY9*Kd_Z@I7UK6{0Q5(<8Jm;)ZO^#`N)f1C9C&$ElqHHiI{@|F38 z_m}=7`^$lryD!C9$t#*Lw&k_mn$%3p9~kiT?@}=)?`SNQ;&iu3(tM|E62j&%{SKU8 zq+vK@`QvqdNV071(Sn3jK4z=)ax5UZ>s$3@QtR)&Fc6w(-K!`7CDflw7g!)0fmz$# z@f6ntI+fnYE`aOQ!z*ZdpRozEZgx}o;OYfO$Cga<#DUN(F~#PaxKJ?UOpo>sc8lV8r2EzoD+m@-an5214hk*yg;0u^O}ZL5 zxEUEVDZMi3eB)&_IpEKf*hVYC3P+AbgbG!O-2yIC$-)*gMQ+1bSIC{hS$k)mvUJMd zAD@dXy+>3;PBOaP3)fA1BO6qLVHfi}_HRorg$hfEYkzhP-O@Mq%%uChIzp~?$&DkM z^FwbFu6BV&mEEqFpUnAGR2;Eko$42z0mmLZQ<5Iv0v*=zr+aL9vyV=1|G7XP_p{?k zYNB8u=dMdW)b~Z+>=Qh}Ktukqnzob=^pdU74E4uyNipNRixds5{S|&kd+AW6PIcvET(#U()sWlP5Q-;`c{(8QUX+)N1k0MV25)lEZIH$eqjMk68sy&A(r-!k?g$*}^8HahzpjW$I{Pdt z)LdhlP%!G{T2_>u&lp?1MVh?4nHIiK!CW%4PB7V6<`~JZFsVWtD7=+d_0!Y?E!Pt< z=y0}tJRG?i4hdxF2xT?P-POqVIgwOsk`R+oc}JAIO$U0qu!mAmp-;i0p&v78bit8Z zkCA{;`^h3I2ZtMo+_GI#WWthka&!OW7G;W|XkERq}IWaJd4lcXw0kMs_w$ub`R zq|-i03A(S75&6(S>rF2i`h_gl8_y>ZKBVHv^jlDTNm=y&v3#8soDoC)T0eC2D%cS5 z4@x3$YpxrVge;%B^otU1k>+o&G<=}1P|qc$KCIxt;sQl}imJoV++s84p}5M!owDM0 zHZp0_-l@<83gwH85$S}%iz)L`F&N6wyD2dY9R|DWF*!4D(ztlfJI7b%oT4!-1_D#o z{qCUszWer)`V0?NX!}4ZEgDl!S2D;wVSP0s%mfyb|H#pQ&z^R*NAd0RDp8R%;R9ZB z-)E&vMr+#}tYqQnu-F>uLoi&?V0`9HxDpLE&TXY{t}sQoWOV&ghwUkyIW|EcuW!j& z`^uiVGA4LnwroK(`(HtLJG{g|w1U1NJ%yCooFh5?XG;VO@I6jG)Yn*<)`u{zyqsbXld{qr-T=&Q9Uh**LGFs8yl9`hLZgefOSz)pz2a7Ye{ zAsWvo%-t9ypjeziIPdb2aePb%!t@zJ;T9+NNmE+r>z3U!Q454|?A^-aLlD)U<7~9= zViN?1Ltxp+$}!uY(<{LctZ&?B@Zu@IPD43BF@A#otPK>&V}iN=oT=o;O6mF+M21n$ z3YPn3BnxWnIV^et@=#L3~EXV&?QvDG%dV9gKTe3gM7!gkV?p~ffm^UCW zxh@&KV?>obzwkFECv29#M{kLKk`d^sDEgtFC~0HZ0V&k~-HJLc3=m*9nNLEA1>oo6 zQ><_8W=JtB1EG&jUnWodb#6j~jqGcDtJ8X1=Q5Q}FZ|hXIRBH?`i4P4;H9?Fy9jLF zi{FwmFqE`maQr*80SwhN>Qbtc*W*t7(i`~f+w8aq>Hf3vHM>Mkv0(1CZhdjE@@T+| zOqEV3Zp&6Bjk>H_P^E|~DbW8rsNSAAX;*$NxaA6iB;XIVQ(h{xh3U0b=W~b z(ZZs`?{^>DNG=Q0U1^$qjTH!ge)@wL2U#`v1mBc$)3V45ucSQliuWqX0v$p2^l0N` zCU^d9JbcKJ{zrO(TzF2m%;O^%*^fJ)B-M)k9Ahr&u$3|DH#V}o9g<0?`y71Fk-C~_ z{l?C+jseY;>0u42uDa3>Rj^WyVZ@0->Hv}5+w}$Yp z>^MtE6c`34c|xeNh!*uuR^|}5AGoWT`_S^KPaeeY3Ii`#r5SbQ zY@2*{>L}#MJI-~H1v(gvodRj^6}I_!@{S_+;%B&Ze*6aF;yrto5o$4)T!0d82FBdPjisQmOlTbn4Ne$E;tp!unxM(g3*6LP;?t4 z;oPxHq&jO|9bu50L=aS8)f;Jh)~!?VR+*TrTiKE%h{~RHH$KVa&V=rEZnD;gA)_U} zCx#4(dz6tTIpE(HtTcSz#;g$kC4xN5$|v{ub?{jN7TfMYZp3rf_v!r)99Yvz z8tJn_bB`Qr9`a5KN&DcG*_Lw@$*LBFJ`Kg5Tsr z0KM>psl(}1ig+EBv_JN@qJfI6&sTV5=u=I~TRQ#{E+xPe(TOuvx1unc1}v5CIcRqY zvztUxZadL5js{7Cfa^mU>x+i^L_7j(#wBs92@!@z42f?Bi6(WF)u?Tf`f;h`Psb~X zfsgIuDD*)2;6UO9(^%h1$Y2S1P~dxgTt1Nn>NvCNqAL;Qr*#>rNu|RbT?-8zRI4Av zM=ZREHmO5&V^GsVYd_0dvB6NWY=-&*p(_m7UeE1te0*K`0!%~DnT6+u%g6~%;U z=yD%EOvkPTDXS{;X3YxVW@q^Oae2yd*0D!s>Z&Jng89Zrw$lfH7jp?hP{2BnFGoU@`-C1E>yG3%A7G05wW~9>;g+xij@(D=PQRW{h^o4#5@Jjj&QfQ17OFi&DkZ$Y- zG?H<*t8M6Ds7psAyHOCx_;=f)E3_uC3czOyS}#*Nu9V|b;mejpdC1~;^Z6TJ6cW;~ z>G&JwAFQ5d?f5x_$}fi#Bh51h6&WChDQEWP0Y0ES|@!SoEB23YMyw2|D;Y=t3j8-v$~m>qigujzeFst#ot#kDaFj zfoJWJh-=X1c_&{y0QIM@ttICgWJq~2l`95sh3>azE*J2_P_`WJqywR?!Fq2DMfV)q z&esC%OJOin;fHtkUeI|=cJ?J@o)+fS=)tw(uLW1(=}^csPo~=ICrXdImw*!Co}|G0q?|IvR7#&f(H^-~&el^UCg!KWU}fhz=p=Vtt^2pn9qnxF=Vk zJE8Vx2v=^hpeZ6)9U5vT>}sm~o+5^_g2sU2?%daJ%urCDL4wx42o{wY~M(17aeV*i}n)96C~ ece?4b%iR9rtVGUTku?DQQ&Lcq&$@Q^*?$8c%<{Vc literal 0 HcmV?d00001 diff --git a/test/fixtures/ellipse/labelDecoration.js b/test/fixtures/ellipse/labelDecoration.js index 19330834b..61351711f 100644 --- a/test/fixtures/ellipse/labelDecoration.js +++ b/test/fixtures/ellipse/labelDecoration.js @@ -1,5 +1,5 @@ module.exports = { - tolerance: 0.0320, + tolerance: 0.0321, config: { type: 'scatter', options: { diff --git a/test/fixtures/ellipse/labelWrap.js b/test/fixtures/ellipse/labelWrap.js new file mode 100644 index 000000000..a21ac4e4e --- /dev/null +++ b/test/fixtures/ellipse/labelWrap.js @@ -0,0 +1,54 @@ +module.exports = { + tolerance: 0.0075, + config: { + type: 'bar', + options: { + scales: { + x: { + display: false, + labels: ['January', 'February', 'March', 'April', 'May', 'June', 'July'], + }, + y: { + display: false, + min: 0, + max: 25 + } + }, + plugins: { + annotation: { + annotations: { + box1: { + type: 'ellipse', + xMin: 2, + xMax: 5, + yMin: 0, + yMax: 5, + backgroundColor: 'rgba(255, 99, 132, 0.5)', + label: { + display: true, + content: 'No wrap because ellipse - '.repeat(2), + textWrap: true, + } + }, + box2: { + type: 'ellipse', + xMin: 2, + xMax: 5, + yMin: 10, + yMax: 15, + backgroundColor: 'rgba(255, 99, 132, 0.5)', + label: { + display: true, + content: ['No wrap!', 'No wrap because ellipse - '.repeat(2), 'No wrap!'], + textWrap: true, + } + }, + } + } + } + } + }, + options: { + spriteText: true + } +}; diff --git a/test/fixtures/ellipse/labelWrap.png b/test/fixtures/ellipse/labelWrap.png new file mode 100644 index 0000000000000000000000000000000000000000..e943bc90a7eb0c77323cef4d04edbb72c57b2ee6 GIT binary patch literal 22111 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 IM6N<$f-~zX{{R30 literal 0 HcmV?d00001 From 74aef324e020784d422e22b075da06e6998fdaf1 Mon Sep 17 00:00:00 2001 From: stockiNail Date: Thu, 18 May 2023 16:07:29 +0200 Subject: [PATCH 4/5] change types --- types/label.d.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/types/label.d.ts b/types/label.d.ts index 4c66511f2..0f9d9cba2 100644 --- a/types/label.d.ts +++ b/types/label.d.ts @@ -141,6 +141,7 @@ export interface BoxLabelOptions extends CoreLabelOptions { * @default true */ display?: Scriptable, + textWrap?: Scriptable, rotation?: Scriptable } From 91a359d8af1e6215f132de8f5e809468eee7a928 Mon Sep 17 00:00:00 2001 From: stockiNail Date: Thu, 18 May 2023 18:08:26 +0200 Subject: [PATCH 5/5] add doc and fix CC --- docs/guide/types/_commonInnerLabel.md | 1 + src/helpers/helpers.canvas.js | 9 +++++++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/docs/guide/types/_commonInnerLabel.md b/docs/guide/types/_commonInnerLabel.md index b193ba977..746b448fa 100644 --- a/docs/guide/types/_commonInnerLabel.md +++ b/docs/guide/types/_commonInnerLabel.md @@ -19,6 +19,7 @@ All of these options can be [Scriptable](../options.md#scriptable-options) | `textAlign` | `string` | `'start'` | Text alignment of label content when there's more than one line. Possible options are: `'left'`, `'start'`, `'center'`, `'end'`, `'right'`. | `textStrokeColor` | [`Color`](../options.md#color) | `undefined` | The color of the stroke around the text. | `textStrokeWidth` | `number` | `0` | Stroke width around the text. +| `textWrap` | `boolean` | `false` | If `true` and the content label overflows the size of the box, the label has been splitted in multiple lines to be drawn in the box. This options is applicable only on `'box'` annotation. | `width` | `number`\|`string` | `undefined` | Overrides the width of the image or canvas element. Could be set in pixel by a number, or in percentage of current width of image or canvas element by a string. If undefined, uses the width of the image or canvas element. It is used only when the content is an image or canvas element. | `xAdjust` | `number` | `0` | Adjustment along x-axis (left-right) of label relative to computed position. Negative values move the label left, positive right. | `yAdjust` | `number` | `0` | Adjustment along y-axis (top-bottom) of label relative to computed position. Negative values move the label up, positive down. diff --git a/src/helpers/helpers.canvas.js b/src/helpers/helpers.canvas.js index c4fc2458b..f0a1cfaa8 100644 --- a/src/helpers/helpers.canvas.js +++ b/src/helpers/helpers.canvas.js @@ -363,12 +363,18 @@ function wrapLabel(ctx, properties, options) { const fonts = isArray(optFont) ? optFont : [optFont]; const optColor = options.color; const colors = isArray(optColor) ? optColor : [optColor]; + ctx.save(); + const result = scanLabelLines(ctx, text, maxWidth, {fonts, colors}); + ctx.restore(); + return result; +} + +function scanLabelLines(ctx, text, maxWidth, {fonts, colors}) { const result = { content: [], font: [], color: [] }; - ctx.save(); text.forEach(function(line, index) { const normLine = line + ''; const c = colors[Math.min(index, colors.length - 1)]; @@ -387,7 +393,6 @@ function wrapLabel(ctx, properties, options) { result.color.push(...wrappedLine.map(() => c)); } }); - ctx.restore(); return result; }