From 0edb2ac604a4a93bcddfdaefc112bf4bd73b21fa Mon Sep 17 00:00:00 2001 From: Dominic Jean Date: Thu, 1 Sep 2022 06:37:12 -0400 Subject: [PATCH] enable pointStyleWidth for all legend style (#10639) --- docs/configuration/legend.md | 2 +- src/helpers/helpers.canvas.js | 61 ++++++---- .../legend-pointStyle-width-default.json | 111 +++++++++++++++++ .../legend-pointStyle-width-default.png | Bin 0 -> 15327 bytes .../legend-pointStyle-width.json | 112 ++++++++++++++++++ .../legend-pointStyle-width.png | Bin 0 -> 17675 bytes 6 files changed, 260 insertions(+), 26 deletions(-) create mode 100644 test/fixtures/plugin.legend/pointStyle-width/legend-pointStyle-width-default.json create mode 100644 test/fixtures/plugin.legend/pointStyle-width/legend-pointStyle-width-default.png create mode 100644 test/fixtures/plugin.legend/pointStyle-width/legend-pointStyle-width.json create mode 100644 test/fixtures/plugin.legend/pointStyle-width/legend-pointStyle-width.png diff --git a/docs/configuration/legend.md b/docs/configuration/legend.md index 04045b3fd..3438c16c0 100644 --- a/docs/configuration/legend.md +++ b/docs/configuration/legend.md @@ -66,7 +66,7 @@ Namespace: `options.plugins.legend.labels` | [`pointStyle`](elements.md#point-styles) | [`pointStyle`](elements.md#types) | `'circle'` | If specified, this style of point is used for the legend. Only used if `usePointStyle` is true. | `textAlign` | `string` | `'center'` | Horizontal alignment of the label text. Options are: `'left'`, `'right'` or `'center'`. | `usePointStyle` | `boolean` | `false` | Label style will match corresponding point style (size is based on pointStyleWidth or the minimum value between boxWidth and font.size). -| `pointStyleWidth` | `number` | `null` | If `usePointStyle` is true, the width of the point style used for the legend (only for `circle`, `rect` and `line` point stlye). +| `pointStyleWidth` | `number` | `null` | If `usePointStyle` is true, the width of the point style used for the legend. | `useBorderRadius` | `boolean` | `false` | Label borderRadius will match coresponding borderRadius. | `borderRadius` | `number` | `undefined` | Override the borderRadius to use. diff --git a/src/helpers/helpers.canvas.js b/src/helpers/helpers.canvas.js index d79f6fb11..365386549 100644 --- a/src/helpers/helpers.canvas.js +++ b/src/helpers/helpers.canvas.js @@ -131,7 +131,7 @@ export function drawPoint(ctx, options, x, y) { } export function drawPointLegend(ctx, options, x, y, w) { - let type, xOffset, yOffset, size, cornerRadius, width; + let type, xOffset, yOffset, size, cornerRadius, width, xOffsetW, yOffsetW; const style = options.pointStyle; const rotation = options.rotation; const radius = options.radius; @@ -166,11 +166,12 @@ export function drawPointLegend(ctx, options, x, y, w) { ctx.closePath(); break; case 'triangle': - ctx.moveTo(x + Math.sin(rad) * radius, y - Math.cos(rad) * radius); + width = w ? w / 2 : radius; + ctx.moveTo(x + Math.sin(rad) * width, y - Math.cos(rad) * radius); rad += TWO_THIRDS_PI; - ctx.lineTo(x + Math.sin(rad) * radius, y - Math.cos(rad) * radius); + ctx.lineTo(x + Math.sin(rad) * width, y - Math.cos(rad) * radius); rad += TWO_THIRDS_PI; - ctx.lineTo(x + Math.sin(rad) * radius, y - Math.cos(rad) * radius); + ctx.lineTo(x + Math.sin(rad) * width, y - Math.cos(rad) * radius); ctx.closePath(); break; case 'rectRounded': @@ -184,11 +185,13 @@ export function drawPointLegend(ctx, options, x, y, w) { cornerRadius = radius * 0.516; size = radius - cornerRadius; xOffset = Math.cos(rad + QUARTER_PI) * size; + xOffsetW = Math.cos(rad + QUARTER_PI) * (w ? w / 2 - cornerRadius : size); yOffset = Math.sin(rad + QUARTER_PI) * size; - ctx.arc(x - xOffset, y - yOffset, cornerRadius, rad - PI, rad - HALF_PI); - ctx.arc(x + yOffset, y - xOffset, cornerRadius, rad - HALF_PI, rad); - ctx.arc(x + xOffset, y + yOffset, cornerRadius, rad, rad + HALF_PI); - ctx.arc(x - yOffset, y + xOffset, cornerRadius, rad + HALF_PI, rad + PI); + yOffsetW = Math.sin(rad + QUARTER_PI) * (w ? w / 2 - cornerRadius : size); + ctx.arc(x - xOffsetW, y - yOffset, cornerRadius, rad - PI, rad - HALF_PI); + ctx.arc(x + yOffsetW, y - xOffset, cornerRadius, rad - HALF_PI, rad); + ctx.arc(x + xOffsetW, y + yOffset, cornerRadius, rad, rad + HALF_PI); + ctx.arc(x - yOffsetW, y + xOffset, cornerRadius, rad + HALF_PI, rad + PI); ctx.closePath(); break; case 'rect': @@ -201,39 +204,47 @@ export function drawPointLegend(ctx, options, x, y, w) { rad += QUARTER_PI; /* falls through */ case 'rectRot': + xOffsetW = Math.cos(rad) * (w ? w / 2 : radius); xOffset = Math.cos(rad) * radius; yOffset = Math.sin(rad) * radius; - ctx.moveTo(x - xOffset, y - yOffset); - ctx.lineTo(x + yOffset, y - xOffset); - ctx.lineTo(x + xOffset, y + yOffset); - ctx.lineTo(x - yOffset, y + xOffset); + yOffsetW = Math.sin(rad) * (w ? w / 2 : radius); + ctx.moveTo(x - xOffsetW, y - yOffset); + ctx.lineTo(x + yOffsetW, y - xOffset); + ctx.lineTo(x + xOffsetW, y + yOffset); + ctx.lineTo(x - yOffsetW, y + xOffset); ctx.closePath(); break; case 'crossRot': rad += QUARTER_PI; /* falls through */ case 'cross': + xOffsetW = Math.cos(rad) * (w ? w / 2 : radius); xOffset = Math.cos(rad) * radius; yOffset = Math.sin(rad) * radius; - ctx.moveTo(x - xOffset, y - yOffset); - ctx.lineTo(x + xOffset, y + yOffset); - ctx.moveTo(x + yOffset, y - xOffset); - ctx.lineTo(x - yOffset, y + xOffset); + yOffsetW = Math.sin(rad) * (w ? w / 2 : radius); + ctx.moveTo(x - xOffsetW, y - yOffset); + ctx.lineTo(x + xOffsetW, y + yOffset); + ctx.moveTo(x + yOffsetW, y - xOffset); + ctx.lineTo(x - yOffsetW, y + xOffset); break; case 'star': + xOffsetW = Math.cos(rad) * (w ? w / 2 : radius); xOffset = Math.cos(rad) * radius; yOffset = Math.sin(rad) * radius; - ctx.moveTo(x - xOffset, y - yOffset); - ctx.lineTo(x + xOffset, y + yOffset); - ctx.moveTo(x + yOffset, y - xOffset); - ctx.lineTo(x - yOffset, y + xOffset); + yOffsetW = Math.sin(rad) * (w ? w / 2 : radius); + ctx.moveTo(x - xOffsetW, y - yOffset); + ctx.lineTo(x + xOffsetW, y + yOffset); + ctx.moveTo(x + yOffsetW, y - xOffset); + ctx.lineTo(x - yOffsetW, y + xOffset); rad += QUARTER_PI; + xOffsetW = Math.cos(rad) * (w ? w / 2 : radius); xOffset = Math.cos(rad) * radius; yOffset = Math.sin(rad) * radius; - ctx.moveTo(x - xOffset, y - yOffset); - ctx.lineTo(x + xOffset, y + yOffset); - ctx.moveTo(x + yOffset, y - xOffset); - ctx.lineTo(x - yOffset, y + xOffset); + yOffsetW = Math.sin(rad) * (w ? w / 2 : radius); + ctx.moveTo(x - xOffsetW, y - yOffset); + ctx.lineTo(x + xOffsetW, y + yOffset); + ctx.moveTo(x + yOffsetW, y - xOffset); + ctx.lineTo(x - yOffsetW, y + xOffset); break; case 'line': xOffset = w ? w / 2 : Math.cos(rad) * radius; @@ -243,7 +254,7 @@ export function drawPointLegend(ctx, options, x, y, w) { break; case 'dash': ctx.moveTo(x, y); - ctx.lineTo(x + Math.cos(rad) * radius, y + Math.sin(rad) * radius); + ctx.lineTo(x + Math.cos(rad) * (w ? w / 2 : radius), y + Math.sin(rad) * radius); break; } diff --git a/test/fixtures/plugin.legend/pointStyle-width/legend-pointStyle-width-default.json b/test/fixtures/plugin.legend/pointStyle-width/legend-pointStyle-width-default.json new file mode 100644 index 000000000..ad3c2c84e --- /dev/null +++ b/test/fixtures/plugin.legend/pointStyle-width/legend-pointStyle-width-default.json @@ -0,0 +1,111 @@ + { + "config": { + "type": "line", + "data": { + "labels": ["A", "B", "C"], + "datasets": [{ + "data": [10, 10, 10], + "backgroundColor": "#00ff00", + "borderColor": "#ff0000", + "borderWidth": 1, + "label": "", + "pointStyle": "line" + }, + { + "data": [15, 15, 15], + "backgroundColor": "#00ff00", + "borderColor": "#ff0000", + "borderWidth": 1, + "label": "", + "pointStyle": "triangle" + }, + { + "data": [20, 20, 20], + "backgroundColor": "#00ff00", + "borderColor": "#ff0000", + "borderWidth": 1, + "label": "", + "pointStyle": "rectRounded" + }, + { + "data": [30, 30, 30], + "backgroundColor": "#00ff00", + "borderColor": "#ff0000", + "borderWidth": 1, + "label": "" + }, + { + "data": [40, 40, 40], + "backgroundColor": "#00ff00", + "borderColor": "#ff0000", + "borderWidth": 1, + "label": "", + "pointStyle": "rect" + }, + { + "data": [25, 25, 25], + "backgroundColor": "#00ff00", + "borderColor": "#ff0000", + "borderWidth": 1, + "label": "", + "pointStyle": "rectRot" + }, + { + "data": [35, 35, 35], + "backgroundColor": "#00ff00", + "borderColor": "#ff0000", + "borderWidth": 1, + "label": "", + "pointStyle": "crossRot" + }, + { + "data": [45, 45, 45], + "backgroundColor": "#00ff00", + "borderColor": "#ff0000", + "borderWidth": 1, + "label": "", + "pointStyle": "cross" + }, + { + "data": [50, 50, 50], + "backgroundColor": "#00ff00", + "borderColor": "#ff0000", + "borderWidth": 1, + "label": "", + "pointStyle": "star" + }, + { + "data": [55, 55, 55], + "backgroundColor": "#00ff00", + "borderColor": "#ff0000", + "borderWidth": 1, + "label": "", + "pointStyle": "dash" + }] + }, + "options": { + "plugins": { + "legend": { + "display": true, + "labels": { + "usePointStyle": true + } + } + }, + "scales": { + "x": { + "display": false + }, + "y": { + "display": false + } + } + } + }, + "options": { + "canvas": { + "height": 512, + "width": 1024 + } + } +} \ No newline at end of file diff --git a/test/fixtures/plugin.legend/pointStyle-width/legend-pointStyle-width-default.png b/test/fixtures/plugin.legend/pointStyle-width/legend-pointStyle-width-default.png new file mode 100644 index 0000000000000000000000000000000000000000..d646921225fd5097e6f1ba2d95f56fd440efeb3e GIT binary patch literal 15327 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 SpF;rf&+@qSvC`jM|NKwc$@n7x literal 0 HcmV?d00001