From: Evert Timberg Date: Thu, 4 Jun 2020 23:53:40 +0000 (-0400) Subject: Enable custom legend box heights (#7459) X-Git-Tag: v3.0.0-beta.2~108 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=0703d78286840ba4b8990cd91e6315e7431702ba;p=thirdparty%2FChart.js.git Enable custom legend box heights (#7459) Enable custom legend box heights --- diff --git a/docs/docs/configuration/legend.md b/docs/docs/configuration/legend.md index a0b9523c5..07c1d2329 100644 --- a/docs/docs/configuration/legend.md +++ b/docs/docs/configuration/legend.md @@ -49,6 +49,7 @@ The legend label configuration is nested below the legend configuration using th | Name | Type | Default | Description | ---- | ---- | ------- | ----------- | `boxWidth` | `number` | `40` | Width of coloured box. +| `boxHeight` | `number` | fontSize | Height of the coloured box. | `font` | `Font` | `defaults.font` | See [Fonts](fonts.md) | `padding` | `number` | `10` | Padding between rows of colored boxes. | `generateLabels` | `function` | | Generates legend items for each thing in the legend. Default implementation returns the text + styling for the color box. See [Legend Item](#legend-item-interface) for details. diff --git a/src/plugins/plugin.legend.js b/src/plugins/plugin.legend.js index 0faddddd9..9a6b93ffb 100644 --- a/src/plugins/plugin.legend.js +++ b/src/plugins/plugin.legend.js @@ -2,7 +2,7 @@ import defaults from '../core/core.defaults'; import Element from '../core/core.element'; import layouts from '../core/core.layouts'; import {drawPoint} from '../helpers/helpers.canvas'; -import {callback as call, mergeIf, valueOrDefault} from '../helpers/helpers.core'; +import {callback as call, mergeIf, valueOrDefault, isNullOrUndef} from '../helpers/helpers.core'; import {toFont, toPadding} from '../helpers/helpers.options'; import {getRtlAdapter, overrideTextDirection, restoreTextDirection} from '../helpers/helpers.rtl'; @@ -90,9 +90,23 @@ defaults.set('legend', { * @return {number} width of the color box area */ function getBoxWidth(labelOpts, fontSize) { - return labelOpts.usePointStyle && labelOpts.boxWidth > fontSize ? + const {boxWidth} = labelOpts; + return (labelOpts.usePointStyle && boxWidth > fontSize) || isNullOrUndef(boxWidth) ? fontSize : - labelOpts.boxWidth; + boxWidth; +} + +/** + * Helper function to get the box height + * @param {object} labelOpts - the label options on the legend + * @param {*} fontSize - the label font size + * @return {number} height of the color box area + */ +function getBoxHeight(labelOpts, fontSize) { + const {boxHeight} = labelOpts; + return (labelOpts.usePointStyle && boxHeight > fontSize) || isNullOrUndef(boxHeight) ? + fontSize : + boxHeight; } export class Legend extends Element { @@ -239,6 +253,9 @@ export class Legend extends Element { const ctx = me.ctx; const labelFont = toFont(labelOpts.font); const fontSize = labelFont.size; + const boxWidth = getBoxWidth(labelOpts, fontSize); + const boxHeight = getBoxHeight(labelOpts, fontSize); + const itemHeight = Math.max(boxHeight, fontSize); // Reset hit boxes const hitboxes = me.legendHitBoxes = []; @@ -271,11 +288,10 @@ export class Legend extends Element { ctx.textBaseline = 'middle'; me.legendItems.forEach((legendItem, i) => { - const boxWidth = getBoxWidth(labelOpts, fontSize); const width = boxWidth + (fontSize / 2) + ctx.measureText(legendItem.text).width; if (i === 0 || lineWidths[lineWidths.length - 1] + width + 2 * labelOpts.padding > minSize.width) { - totalHeight += fontSize + labelOpts.padding; + totalHeight += itemHeight + labelOpts.padding; lineWidths[lineWidths.length - (i > 0 ? 0 : 1)] = 0; } @@ -284,7 +300,7 @@ export class Legend extends Element { left: 0, top: 0, width, - height: fontSize + height: itemHeight }; lineWidths[lineWidths.length - 1] += width + labelOpts.padding; @@ -302,7 +318,6 @@ export class Legend extends Element { const heightLimit = minSize.height - titleHeight; me.legendItems.forEach((legendItem, i) => { - const boxWidth = getBoxWidth(labelOpts, fontSize); const itemWidth = boxWidth + (fontSize / 2) + ctx.measureText(legendItem.text).width; // If too tall, go to new column @@ -323,7 +338,7 @@ export class Legend extends Element { left: 0, top: 0, width: itemWidth, - height: fontSize + height: itemHeight, }; }); @@ -377,11 +392,13 @@ export class Legend extends Element { ctx.font = labelFont.string; const boxWidth = getBoxWidth(labelOpts, fontSize); + const boxHeight = getBoxHeight(labelOpts, fontSize); + const height = Math.max(fontSize, boxHeight); const hitboxes = me.legendHitBoxes; // current position const drawLegendBox = function(x, y, legendItem) { - if (isNaN(boxWidth) || boxWidth <= 0) { + if (isNaN(boxWidth) || boxWidth <= 0 || isNaN(boxHeight) || boxHeight < 0) { return; } @@ -417,9 +434,12 @@ export class Legend extends Element { drawPoint(ctx, drawOptions, centerX, centerY); } else { // Draw box as legend symbol - ctx.fillRect(rtlHelper.leftForLtr(x, boxWidth), y, boxWidth, fontSize); + // Adjust position when boxHeight < fontSize (want it centered) + const yBoxTop = y + Math.max((fontSize - boxHeight) / 2, 0); + + ctx.fillRect(rtlHelper.leftForLtr(x, boxWidth), yBoxTop, boxWidth, boxHeight); if (lineWidth !== 0) { - ctx.strokeRect(rtlHelper.leftForLtr(x, boxWidth), y, boxWidth, fontSize); + ctx.strokeRect(rtlHelper.leftForLtr(x, boxWidth), yBoxTop, boxWidth, boxHeight); } } @@ -429,8 +449,7 @@ export class Legend extends Element { const fillText = function(x, y, legendItem, textWidth) { const halfFontSize = fontSize / 2; const xLeft = rtlHelper.xPlus(x, boxWidth + halfFontSize); - const yMiddle = y + halfFontSize; - + const yMiddle = y + (height / 2); ctx.fillText(legendItem.text, xLeft, yMiddle); if (legendItem.hidden) { @@ -473,7 +492,7 @@ export class Legend extends Element { overrideTextDirection(me.ctx, opts.textDirection); - const itemHeight = fontSize + labelOpts.padding; + const itemHeight = height + labelOpts.padding; me.legendItems.forEach((legendItem, i) => { const textWidth = ctx.measureText(legendItem.text).width; const width = boxWidth + (fontSize / 2) + textWidth; diff --git a/test/specs/plugin.legend.tests.js b/test/specs/plugin.legend.tests.js index 991c81f92..dcb9b1fef 100644 --- a/test/specs/plugin.legend.tests.js +++ b/test/specs/plugin.legend.tests.js @@ -373,6 +373,37 @@ describe('Legend block tests', function() { }); }); + it('should draw items with a custom boxHeight', function() { + var chart = window.acquireChart( + { + type: 'line', + data: { + datasets: [{ + label: 'dataset1', + data: [] + }], + labels: [] + }, + options: { + legend: { + position: 'right', + labels: { + boxHeight: 40 + } + } + } + }, + { + canvas: { + width: 512, + height: 105 + } + } + ); + const hitBox = chart.legend.legendHitBoxes[0]; + expect(hitBox.height).toBe(40); + }); + it('should pick up the first item when the property is an array', function() { var chart = window.acquireChart({ type: 'bar',