From 1c21c061dc165aa95103fcc3cfc1949aae753571 Mon Sep 17 00:00:00 2001 From: laoluo Date: Tue, 21 Dec 2021 23:19:40 +0800 Subject: [PATCH] feat: AnnotationView add text annotation dispaly --- packages/lb-annotation/src/constant/tool.ts | 5 ++ .../src/core/toolOperation/ViewOperation.ts | 77 +++++++++++++++++- packages/lb-annotation/src/utils/MathUtils.ts | 80 ++++++++++++++++++- .../lb-annotation/src/utils/tool/DrawUtils.ts | 8 +- packages/lb-components/docs/annotationView.md | 13 +++ .../docs/annotationView_en-US.md | 13 +++ packages/lb-demo/src/mock/index.js | 31 +++++-- 7 files changed, 216 insertions(+), 11 deletions(-) diff --git a/packages/lb-annotation/src/constant/tool.ts b/packages/lb-annotation/src/constant/tool.ts index 0ed89c3b8..eb639e5e4 100644 --- a/packages/lb-annotation/src/constant/tool.ts +++ b/packages/lb-annotation/src/constant/tool.ts @@ -190,6 +190,11 @@ export const TEXT_ATTRIBUTE_MAX_LENGTH = 1000; /** 文本标注的文本高度 */ export const TEXT_ATTRIBUTE_LINE_HEIGHT = 16; +/** 文本默认的最大宽度 */ +export const DEFAULT_TEXT_MAX_WIDTH = 300; + +export const DEFAULT_FONT = 'normal normal 500 14px Arial'; + /** 缩略图下的模式 */ export enum EThumbnailOption { ImgList = 1000, diff --git a/packages/lb-annotation/src/core/toolOperation/ViewOperation.ts b/packages/lb-annotation/src/core/toolOperation/ViewOperation.ts index 8b1f556a5..11b8a83d8 100644 --- a/packages/lb-annotation/src/core/toolOperation/ViewOperation.ts +++ b/packages/lb-annotation/src/core/toolOperation/ViewOperation.ts @@ -9,6 +9,8 @@ import AxisUtils from '@/utils/tool/AxisUtils'; import RectUtils from '@/utils/tool/RectUtils'; import PolygonUtils from '@/utils/tool/PolygonUtils'; import { BasicToolOperation, IBasicToolOperationProps } from './basicToolOperation'; +import MathUtils from '@/utils/MathUtils'; +import { DEFAULT_FONT } from '@/constant/tool'; const newScope = 3; @@ -19,8 +21,8 @@ interface IBasicStyle { } interface IAnnotationData { - type: 'rect' | 'polygon' | 'line' | 'point'; - annotation: IBasicRect & IBasicPolygon & IBasicLine & IPoint; + type: 'rect' | 'polygon' | 'line' | 'point' | 'text'; + annotation: IBasicRect & IBasicPolygon & IBasicLine & IPoint & IBasicText; } interface IBasicRect extends IBasicStyle { @@ -38,6 +40,18 @@ interface IBasicPolygon extends IBasicStyle { type IBasicLine = IBasicPolygon; +interface IBasicText { + x: number; + y: number; + text: string; // Use \n for line feed + textMaxWidth?: number; + + color?: string; + background?: string; + lineHeight?: number; + font?: string; // canvas-font https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/font +} + interface IPoint extends IBasicStyle { x: number; y: number; @@ -238,6 +252,65 @@ export default class ViewOperation extends BasicToolOperation { break; } + case 'text': { + const textAnnotation = annotation.annotation; + const { + text, + x, + y, + textMaxWidth, + color = 'white', + background = 'rgba(0, 0, 0, 0.6)', + lineHeight = 25, + font = DEFAULT_FONT, + } = textAnnotation; + const renderPoint = AxisUtils.changePointByZoom({ x, y }, this.zoom, this.currentPos); + + const { + width, + height, + fontHeight = 0, + } = MathUtils.getTextArea(this.canvas, textAnnotation.text, textMaxWidth, font, lineHeight); + + const paddingTB = 10; + const paddingLR = 10; + + // 字体背景 + DrawUtils.drawRectWithFill( + this.canvas, + { + x: renderPoint.x, + y: renderPoint.y, + width: width + paddingLR * 2, + height: height + paddingTB * 2, + id: '', + sourceID: '', + valid: true, + textAttribute: '', + attribute: '', + }, + { + color: background, + }, + ); + + DrawUtils.drawText( + this.canvas, + { + x: renderPoint.x + paddingLR, + y: renderPoint.y + fontHeight + paddingTB, + }, + text, + { + color, + lineHeight, + font, + textMaxWidth, + }, + ); + break; + } + default: { // } diff --git a/packages/lb-annotation/src/utils/MathUtils.ts b/packages/lb-annotation/src/utils/MathUtils.ts index 37a1e4e82..4e221b627 100644 --- a/packages/lb-annotation/src/utils/MathUtils.ts +++ b/packages/lb-annotation/src/utils/MathUtils.ts @@ -2,7 +2,7 @@ * 各类的数学运算 */ -import { SEGMENT_NUMBER } from '@/constant/tool'; +import { DEFAULT_FONT, DEFAULT_TEXT_MAX_WIDTH, SEGMENT_NUMBER } from '@/constant/tool'; import { createSmoothCurvePointsFromPointList } from './tool/polygonTool'; export default class MathUtils { @@ -172,4 +172,82 @@ export default class MathUtils { length, }; }; + + /** + * 获取当前文本的背景面积 + * @param canvas + * @param text + * @param maxWidth + * @param lineHeight + * @returns + */ + public static getTextArea( + canvas: HTMLCanvasElement, + text: string, + maxWidth: number = DEFAULT_TEXT_MAX_WIDTH, + font = DEFAULT_FONT, + lineHeight?: number, + ) { + if (typeof text !== 'string') { + return { + width: 0, + height: 0, + }; + } + + const context: CanvasRenderingContext2D = canvas.getContext('2d')!; + context.font = font; + + let height = 0; + + if (typeof lineHeight === 'undefined') { + lineHeight = + (canvas && parseInt(window.getComputedStyle(canvas).lineHeight, 10)) || + parseInt(window.getComputedStyle(document.body).lineHeight, 10); + } + + const fontHeight: number = + (canvas && parseInt(window.getComputedStyle(canvas).fontSize, 10)) || + parseInt(window.getComputedStyle(document.body).fontSize, 10) || + 0; + + const arrParagraph = text.split('\n'); + + let lineWidth = 0; // 最大长度定位 + + for (let i = 0; i < arrParagraph.length; i++) { + // 字符分隔为数组 + const arrText = arrParagraph[i].split(''); + let line = ''; + + for (let n = 0; n < arrText.length; n++) { + const testLine = line + arrText[n]; + const metrics = context.measureText(testLine); + const textWidth = metrics.width; + + if (textWidth > maxWidth && n > 0) { + line = arrText[n]; + height += lineHeight; + lineWidth = maxWidth; + } else { + line = testLine; + + if (textWidth > lineWidth) { + lineWidth = textWidth; + } + } + } + + if (i !== arrParagraph.length - 1) { + height += lineHeight; + } + } + + return { + width: lineWidth, + height: height + fontHeight, + lineHeight, + fontHeight, + }; + } } diff --git a/packages/lb-annotation/src/utils/tool/DrawUtils.ts b/packages/lb-annotation/src/utils/tool/DrawUtils.ts index 344ff9514..c2116f144 100644 --- a/packages/lb-annotation/src/utils/tool/DrawUtils.ts +++ b/packages/lb-annotation/src/utils/tool/DrawUtils.ts @@ -1,4 +1,4 @@ -import { ELineTypes, SEGMENT_NUMBER } from '../../constant/tool'; +import { DEFAULT_FONT, ELineTypes, SEGMENT_NUMBER } from '../../constant/tool'; import { IPolygonPoint } from '../../types/tool/polygon'; import PolygonUtils from './PolygonUtils'; import UnitUtils from './UnitUtils'; @@ -401,6 +401,7 @@ export default class DrawUtils { offsetX: number; offsetY: number; textAlign: 'start' | 'center' | 'end' | 'left' | 'right'; + lineHeight: number; }> = {}, ): void { if (!text) { @@ -410,7 +411,7 @@ export default class DrawUtils { const ctx: CanvasRenderingContext2D = canvas.getContext('2d')!; const { color = DEFAULT_COLOR, - font = 'normal normal 500 14px Arial', + font = DEFAULT_FONT, shadowColor = '', shadowBlur = 0, shadowOffsetX = 0, @@ -419,6 +420,7 @@ export default class DrawUtils { offsetX = 0, offsetY = 0, textAlign = 'start', + lineHeight, } = options; ctx.save(); @@ -429,7 +431,7 @@ export default class DrawUtils { ctx.shadowOffsetX = shadowOffsetX; ctx.shadowOffsetY = shadowOffsetY; ctx.shadowBlur = shadowBlur; - this.wrapText(canvas, `${text}`, startPoint.x + offsetX, startPoint.y + offsetY, textMaxWidth); + this.wrapText(canvas, `${text}`, startPoint.x + offsetX, startPoint.y + offsetY, textMaxWidth, lineHeight); ctx.restore(); } diff --git a/packages/lb-components/docs/annotationView.md b/packages/lb-components/docs/annotationView.md index 1921fc810..0c2f93c11 100644 --- a/packages/lb-components/docs/annotationView.md +++ b/packages/lb-components/docs/annotationView.md @@ -77,4 +77,17 @@ interface IPoint extends IBasicStyle { y: number; radius?: number; } + +interface IBasicText { + x: number; + y: number; + text: string; // 使用 \n 进行换行 + textMaxWidth?: number; + + color?: string; + background?: string; + lineHeight?: number; + font?: string; // canvas-font https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/font +} + ``` \ No newline at end of file diff --git a/packages/lb-components/docs/annotationView_en-US.md b/packages/lb-components/docs/annotationView_en-US.md index 2dfd0804e..edff3cc5e 100644 --- a/packages/lb-components/docs/annotationView_en-US.md +++ b/packages/lb-components/docs/annotationView_en-US.md @@ -76,4 +76,17 @@ interface IPoint extends IBasicStyle { y: number; radius?: number; } + +interface IBasicText { + x: number; + y: number; + text: string; // Use \n for line feed + textMaxWidth?: number; + + color?: string; + background?: string; + lineHeight?: number; + font?: string; // canvas-font https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/font +} + ``` \ No newline at end of file diff --git a/packages/lb-demo/src/mock/index.js b/packages/lb-demo/src/mock/index.js index f3b3154bc..0f98c01e8 100644 --- a/packages/lb-demo/src/mock/index.js +++ b/packages/lb-demo/src/mock/index.js @@ -85,7 +85,7 @@ export const DEFAULT_ANNOTATIONS = [ { type: 'rect', annotation: { - id: 123123, + id: '123123', x: 123, y: 23, width: 100, @@ -97,7 +97,7 @@ export const DEFAULT_ANNOTATIONS = [ { type: 'polygon', annotation: { - id: 3, + id: '3', // thickness: 10, color: 'green', pointList: [ @@ -121,7 +121,7 @@ export const DEFAULT_ANNOTATIONS = [ annotation: { color: 'yellow', thickness: 5, - id: 4, + id: '4', pointList: [ { @@ -142,7 +142,7 @@ export const DEFAULT_ANNOTATIONS = [ { type: 'point', annotation: { - id: 5, + id: '5', x: 10, y: 10, fill: 'green', @@ -154,11 +154,32 @@ export const DEFAULT_ANNOTATIONS = [ { type: 'rect', annotation: { - id: 10, + id: '10', x: 13, y: 3, width: 1020, height: 100, }, }, + { + type: 'text', + annotation: { + id: '11', + x: 223, + y: 23, + textMaxWidth: 300, + text: '标签1: 测试1 \n标签2: 测试2' + } + }, + { + type: 'text', + annotation: { + id: '12', + x: 12, + y: 123, + textMaxWidth: 500, + lineHeight: 25, + text: 'Key: Loooooooooooooooooooooooooooooooooog value\nSecond One: short value' + } + } ];