From 197efaea0eb6be3c3f7c5701dc075af219ffc34b Mon Sep 17 00:00:00 2001 From: kkxxkk2019 Date: Tue, 15 Aug 2023 18:44:13 +0800 Subject: [PATCH] fix(vrender-components): label shoud omit automaticly when label's width exceeds item's width, relate https://github.com/VisActor/VChart/issues/505 --- .../__tests__/unit/legend/discrete.test.ts | 279 +++++++++++++++++- .../src/legend/discrete/discrete.ts | 35 ++- 2 files changed, 302 insertions(+), 12 deletions(-) diff --git a/packages/vrender-components/__tests__/unit/legend/discrete.test.ts b/packages/vrender-components/__tests__/unit/legend/discrete.test.ts index 0521f0e67..9e139357d 100644 --- a/packages/vrender-components/__tests__/unit/legend/discrete.test.ts +++ b/packages/vrender-components/__tests__/unit/legend/discrete.test.ts @@ -1,4 +1,5 @@ -import type { IGraphic, Stage } from '@visactor/vrender'; +import { expect } from 'vitest'; +import type { IGraphic, IGroup, IText, Stage } from '@visactor/vrender'; import { DiscreteLegend } from '../../../src'; import { createCanvas } from '../../util/dom'; import { createStage } from '../../util/vrender'; @@ -227,4 +228,280 @@ describe('DiscreteLegend', () => { expect(legend.AABBBounds.width()).toBe(76); }); + + it("should omit when label's width exceeds item's width", () => { + const legend = new DiscreteLegend({ + layout: 'vertical', + title: { + align: 'start', + space: 12, + textStyle: { + fontSize: 12, + fontWeight: 'bold', + fill: '#2C3542' + } + }, + item: { + spaceCol: 10, + spaceRow: 10, + shape: { + space: 4, + style: { + size: 10, + cursor: 'pointer' + }, + state: { + selectedHover: { + opacity: 0.85 + }, + unSelected: { + fill: '#D8D8D8', + fillOpacity: 0.5 + } + } + }, + label: { + space: 4, + style: { + fontSize: 12, + fill: '#89909D', + cursor: 'pointer' + }, + state: { + selectedHover: { + opacity: 0.85 + }, + unSelected: { + fill: '#D8D8D8', + fillOpacity: 0.5 + } + } + }, + value: { + alignRight: true, + style: { + fontSize: 10, + fill: '#333', + cursor: 'pointer', + fillOpacity: 0.8 + }, + state: { + selectedHover: { + opacity: 0.85 + }, + unSelected: { + fill: '#D8D8D8' + }, + unselected: { + fill: '#d8d8d8' + } + } + }, + background: { + style: { + cursor: 'pointer' + }, + state: { + selectedHover: { + fill: 'gray', + fillOpacity: 0.7 + }, + unSelectedHover: { + fill: 'gray', + fillOpacity: 0.2 + } + } + }, + focus: false, + focusIconStyle: { + size: 10, + symbolType: + 'M8 1C11.866 1 15 4.13401 15 8C15 11.866 11.866 15 8 15C4.13401 15 1 11.866 1 8C1 4.13401 4.13401 1 8 1ZM8.75044 2.55077L8.75 3.75H7.25L7.25006 2.5507C4.81247 2.88304 2.88304 4.81247 2.5507 7.25006L3.75 7.25V8.75L2.55077 8.75044C2.8833 11.1878 4.81264 13.117 7.25006 13.4493L7.25 12.25H8.75L8.75044 13.4492C11.1876 13.1167 13.1167 11.1876 13.4492 8.75044L12.25 8.75V7.25L13.4493 7.25006C13.117 4.81264 11.1878 2.8833 8.75044 2.55077ZM8 5.5C9.38071 5.5 10.5 6.61929 10.5 8C10.5 9.38071 9.38071 10.5 8 10.5C6.61929 10.5 5.5 9.38071 5.5 8C5.5 6.61929 6.61929 5.5 8 5.5ZM8 7C7.44772 7 7 7.44772 7 8C7 8.55228 7.44772 9 8 9C8.55228 9 9 8.55228 9 8C9 7.44772 8.55228 7 8 7Z', + fill: '#333', + cursor: 'pointer' + }, + visible: true, + padding: 2, + width: 121.95 + }, + autoPage: true, + pager: { + space: 12, + handler: { + style: { + size: 10 + }, + space: 4 + } + }, + hover: true, + select: true, + selectMode: 'multiple', + allowAllCanceled: false, + items: [ + { + label: 'OneOneOneOneOne', + shape: { + fill: '#1664FF', + symbolType: 'square', + stroke: null, + fillOpacity: 1, + strokeOpacity: 1, + opacity: 1, + texture: null, + texturePadding: null, + textureSize: null, + textureColor: null, + innerBorder: null, + outerBorder: null + }, + value: '26.32%', + id: 'OneOneOneOneOne', + index: 0 + }, + { + label: 'Two', + shape: { + fill: '#1AC6FF', + symbolType: 'square', + stroke: null, + fillOpacity: 1, + strokeOpacity: 1, + opacity: 1, + texture: null, + texturePadding: null, + textureSize: null, + textureColor: null, + innerBorder: null, + outerBorder: null + }, + value: '23.68%', + id: 'Two', + index: 1 + }, + { + label: 'Three', + shape: { + fill: '#FF8A00', + symbolType: 'square', + stroke: null, + fillOpacity: 1, + strokeOpacity: 1, + opacity: 1, + texture: null, + texturePadding: null, + textureSize: null, + textureColor: null, + innerBorder: null, + outerBorder: null + }, + value: '15.79%', + id: 'Three', + index: 2 + }, + { + label: 'Four', + shape: { + fill: '#3CC780', + symbolType: 'square', + stroke: null, + fillOpacity: 1, + strokeOpacity: 1, + opacity: 1, + texture: null, + texturePadding: null, + textureSize: null, + textureColor: null, + innerBorder: null, + outerBorder: null + }, + value: '13.16%', + id: 'Four', + index: 3 + }, + { + label: 'Five', + shape: { + fill: '#7442D4', + symbolType: 'square', + stroke: null, + fillOpacity: 1, + strokeOpacity: 1, + opacity: 1, + texture: null, + texturePadding: null, + textureSize: null, + textureColor: null, + innerBorder: null, + outerBorder: null + }, + value: '10.53%', + id: 'Five', + index: 4 + }, + { + label: 'Six', + shape: { + fill: '#FFC400', + symbolType: 'square', + stroke: null, + fillOpacity: 1, + strokeOpacity: 1, + opacity: 1, + texture: null, + texturePadding: null, + textureSize: null, + textureColor: null, + innerBorder: null, + outerBorder: null + }, + value: '7.89%', + id: 'Six', + index: 5 + }, + { + label: 'Seven', + shape: { + fill: '#304D77', + symbolType: 'square', + stroke: null, + fillOpacity: 1, + strokeOpacity: 1, + opacity: 1, + texture: null, + texturePadding: null, + textureSize: null, + textureColor: null, + innerBorder: null, + outerBorder: null + }, + value: '2.63%', + id: 'Seven', + index: 6 + } + ], + zIndex: 500, + maxWidth: 813, + maxHeight: 416, + defaultSelected: ['OneOneOneOneOne', 'Two', 'Three', 'Four', 'Five', 'Six', 'Seven'], + width: 147.6698455810547, + height: 186, + dx: 0, + dy: 0, + x: 100, + y: 42 + }); + + stage.defaultLayer.add(legend as unknown as IGraphic); + stage.render(); + + expect((legend.getElementsByName('legendItem')[0] as IGroup).AABBBounds.width()).toBe(121.95); + expect( + (legend.getElementsByName('legendItem')[0].getElementsByName('legendItemLabel')[0] as IText)._AABBBounds.width() + ).toBeCloseTo(57.143951416015625); + expect( + (legend.getElementsByName('legendItem')[0].getElementsByName('legendItemValue')[0] as IText).attribute + .maxLineWidth + ).toBeUndefined(); + }); }); diff --git a/packages/vrender-components/src/legend/discrete/discrete.ts b/packages/vrender-components/src/legend/discrete/discrete.ts index 9cd001bc9..749bfe9df 100644 --- a/packages/vrender-components/src/legend/discrete/discrete.ts +++ b/packages/vrender-components/src/legend/discrete/discrete.ts @@ -435,18 +435,31 @@ export class DiscreteLegend extends LegendBase { valueShape.addState(isSelected ? LegendStateValue.selected : LegendStateValue.unSelected); if (this._itemWidthByUser) { - valueShape.setAttribute( - 'maxLineWidth', + // 计算用来防止文本的宽度 + const layoutWidth = this._itemWidthByUser - - parsedPadding[1] - - parsedPadding[3] - - shapeSize - - shapeSpace - - labelShape.AABBBounds.width() - - labelSpace - - focusSpace - - valueSpace - ); + parsedPadding[1] - + parsedPadding[3] - + shapeSize - + shapeSpace - + labelSpace - + focusSpace - + valueSpace; + const valueBounds = valueShape.AABBBounds; + const labelBounds = labelShape.AABBBounds; + const valueWidth = valueBounds.width(); + const labelWidth = labelBounds.width(); + if (valueWidth + labelWidth > layoutWidth) { + if ((layoutWidth - valueWidth) / labelWidth > 0.4) { + // 设置一个值,如果剩余的宽度和 label 自身的比例不低于 0.4 的话,优先展示全 label + labelShape.setAttribute('maxLineWidth', layoutWidth - valueWidth); + } else { + valueShape.setAttribute('maxLineWidth', layoutWidth * 0.5); + labelShape.setAttribute('maxLineWidth', layoutWidth * 0.5); + } + } else { + valueShape.setAttribute('maxLineWidth', layoutWidth - labelWidth); + } if (valueAttr.alignRight) { valueShape.setAttributes({ // @ts-ignore