Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Add pipeline and separate basic layer from basic operation tool #429

Open
wants to merge 44 commits into
base: feat/pipeline
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
a49e51a
ci: Support beta version release
Jan 30, 2024
3f020d8
feat: NLP tool
lixinghua123 Jan 24, 2024
ab3299f
feat: Annotation core func in NLP
Jan 25, 2024
ef8ba08
fix: Fix cover problem
Jan 25, 2024
3165abf
feat: Support highlight in nlp tool
Jan 25, 2024
24f1d20
feat: Support clear result in nlp tool
Jan 25, 2024
dbfdf82
feat: NLPTool: Support delete in siderbar
Jan 26, 2024
7e566c2
feat: Support lock and uncheck attr in nlp tool
Jan 29, 2024
61266ed
feat: NLP tool view
lixinghua123 Jan 29, 2024
14ac2a8
feat: NLP tool support remark
lixinghua123 Jan 29, 2024
f760487
feat: NLP tool type
lixinghua123 Jan 29, 2024
4ba510c
feat: NLP tool sidebar and hotkey
lixinghua123 Jan 29, 2024
443733f
feat: NLP tool support indicatorDetermine
lixinghua123 Jan 29, 2024
a6d0c8f
feat: Type deal with
lixinghua123 Jan 29, 2024
f222ab8
feat: Code adjustment
lixinghua123 Jan 30, 2024
d3bbfed
feat: Code review
lixinghua123 Jan 30, 2024
58d4476
feat(nlp): Hide attribute list on checkMode
Jan 30, 2024
a11eecf
feat(nlp): Remove warning on annotation page
Jan 30, 2024
6810792
feat(nlp): Remove useless shortcut
Jan 30, 2024
f250096
feat(nlp): Remove dbl default event on nlp conatiner
Jan 30, 2024
c79bcbe
feat: Code review
lixinghua123 Jan 30, 2024
6807e21
feat: Hide option icon in header
lixinghua123 Jan 30, 2024
1006f96
feat: Hover delete icon
lixinghua123 Jan 30, 2024
1eae95e
feat: Copywriting and style adjustment
lixinghua123 Jan 30, 2024
94b8e70
feat: NLP hide set validity
lixinghua123 Jan 30, 2024
d70bcc6
fix: NLP tool view mode cannot delete annotations
lixinghua123 Jan 31, 2024
92b50df
feat: Code review
lixinghua123 Jan 31, 2024
521483b
fix: NLP tool hides comment lines
lixinghua123 Jan 31, 2024
38ff360
fix: NLP tool does not produce results when labeling some
lixinghua123 Jan 31, 2024
7f49aa0
fix: NLP tool indicators determine data anomalies
lixinghua123 Jan 31, 2024
5413448
fix: NLP Tools Switch Panel Hide Annotations
lixinghua123 Jan 31, 2024
cab7cfc
fix: NLP indicator judgment to obtain data
lixinghua123 Feb 1, 2024
e5c5217
feat: Add pipeline: get basic result
Jan 24, 2024
9a296d4
feat: Pipeline v1-temp
Jan 30, 2024
8ccfeae
feat: Separation of basic layer from basic operation tool
Jan 31, 2024
2c9d8e1
chore: Remove Chinese comments
Feb 1, 2024
cdccc42
fix: Resolve comments
Feb 1, 2024
8ceafeb
feat: Support the render of reference data
Feb 22, 2024
a0154c6
fix: Lint problems
Feb 22, 2024
715f7a9
fix: Resolve comments
Feb 26, 2024
267235f
feat: Add hiddenTextSwitch and highlightBadge in rect tool
Mar 13, 2024
097a2bf
chore: Fix conflict
Mar 13, 2024
3fd7fab
feat: Add basicLayer in annotationView
Mar 19, 2024
6b8eb9b
feat: Add errorboundary
Apr 30, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions packages/lb-annotation/src/constant/keyCode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ enum EKeyCode {
L = 76,
R = 82,
Z = 90,
V = 86,
W = 87,
X = 88,
Y = 89,
Expand Down
381 changes: 381 additions & 0 deletions packages/lb-annotation/src/core/basicLayer.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,381 @@
/**
* @file render layer of basic results, should be initialized in annotationEngine
* @Author wanghaiqing [email protected]
* @Date 2024-01-31
*/

import { EToolName, THybridToolName } from '@/constant/tool';
import CanvasUtils from '@/utils/tool/CanvasUtils';
import DrawUtils from '@/utils/tool/DrawUtils';
import AxisUtils, { CoordinateUtils } from '@/utils/tool/AxisUtils';
import { HybridToolUtils } from '@/core/scheduler';
import EventListener from '@/core/toolOperation/eventListener';
import { IPolygonConfig } from '@/types/tool/polygon';
import { IPolygonData, toolStyleConverter } from '@labelbee/lb-utils';
import CommonToolUtils from '@/utils/tool/CommonToolUtils';
import { styleString } from '@/constant/style';
import StyleUtils from '@/utils/tool/StyleUtils';
import { ICommonProps } from './index';

type IReferenceConfig = IRectConfig | IPolygonConfig | ILineConfig | IPointToolConfig;

export interface IReferenceInfoProps {
referenceConfig: IReferenceConfig;
referenceResult: any;
referenceToolName: EToolName;
}

interface IBasicLayerProps extends ICommonProps {
container: HTMLElement;
size: ISize;
toolName?: THybridToolName;
imgNode?: HTMLImageElement; // dom node of image
config?: string; // config of annotation task
style?: any;
forbidBasicResultRender?: boolean;
}

export default class BasicLayer extends EventListener {
public container: HTMLElement; // external dom node

public config: any;

public style: any;

public size: ISize;

public imgNode?: HTMLImageElement;

public basicCanvas!: HTMLCanvasElement; // dom for basic layer

public basicResult?: any; // data of depended tool

public referenceInfo?: IReferenceInfoProps;

public dependToolName?: EToolName;

public forbidBasicResultRender: boolean; // disable rendering of basic result

public zoom: number;

public currentPos: ICoordinate; // store real-time offset position

public coordUtils?: CoordinateUtils;

public basicImgInfo: any; // store info of current image

public imgInfo?: ISize;

private hiddenImg: boolean;

private _imgAttribute?: any;

private currentPosStorage?: ICoordinate; // store the current clicked translation position

constructor(props: IBasicLayerProps) {
super();
this.container = props.container;
this.config = CommonToolUtils.jsonParser(props.config);
this.style = props.style ?? CommonToolUtils.jsonParser(styleString);

this.size = props.size;
this.zoom = props.zoom ?? 1;
this.currentPos = props.currentPos ?? { x: 0, y: 0 };
this.basicImgInfo = props.basicImgInfo;
this.coordUtils = props.coordUtils;
this._imgAttribute = props.imgAttribute ?? {};

this.imgNode = props.imgNode;
this.hiddenImg = props.toolName ? !HybridToolUtils.isSingleTool(props.toolName) : false;
this.forbidBasicResultRender = props.forbidBasicResultRender ?? false;

this.destroyBasicCanvas();
this.createBasicCanvas(props.size);
}

// getters
get basicCtx() {
return this.basicCanvas?.getContext('2d');
}

public get pixelRatio() {
return CanvasUtils.getPixelRatio(this.basicCanvas?.getContext('2d'));
}

get rotate() {
return this.basicImgInfo?.rotate ?? 0;
}

// setters
public setZoom(zoom: number) {
this.zoom = zoom;
}

public setCurrentPos(currentPos: ICoordinate) {
this.currentPos = currentPos;
this.currentPosStorage = currentPos;
}

public setBasicImgInfo(basicImgInfo: any) {
this.basicImgInfo = basicImgInfo;
}

public setImgAttribute(imgAttribute: IImageAttribute) {
this._imgAttribute = imgAttribute;
this.renderBasicCanvas();
}

public setImgInfo(size?: ISize) {
this.imgInfo = size;
}

public setDependName(dependToolName?: EToolName, dependToolConfig?: IRectConfig | IPolygonConfig) {
this.dependToolName = dependToolName;
this.coordUtils?.setDependInfo(dependToolName, dependToolConfig);
}

public setBasicResult(basicResult: any) {
this.basicResult = basicResult;
this.coordUtils?.setBasicResult(basicResult);
}

public setReferenceInfo(referenceInfo: IReferenceInfoProps) {
this.referenceInfo = referenceInfo;
}

/**
* Synchronize common information such as currentPos, zoom, etc
*/
public syncCommonInfo(info: ICommonProps) {
this.setZoom(info?.zoom ?? this.zoom);
this.setCurrentPos(info?.currentPos ?? this.currentPos);
this.setBasicImgInfo(info?.basicImgInfo ?? this.basicImgInfo);
this.setImgInfo(info?.imgInfo ?? this.imgInfo);
}

/**
* Resize the current canvas and reinitialize
* @param size
*/
public setSize(size: ISize) {
this.size = size;
if (this.container.contains(this.basicCanvas)) {
this.destroyBasicCanvas();
this.createBasicCanvas(size);
this.renderBasicCanvas();
}
}

/** Get the current property color */
public getColor(attribute = '', config = this.config) {
return toolStyleConverter.getColorByConfig({ attribute, config, style: this.style });
}

/**
* Notice. It needs to set the default imgInfo. Because it will needs to create info when it doesn't have
* @param imgNode
* @param basicImgInfo
*/
public setImgNode(imgNode: HTMLImageElement, basicImgInfo: Partial<{ valid: boolean; rotate: number }> = {}) {
this.imgNode = imgNode;

this.setBasicImgInfo({
width: imgNode.width,
height: imgNode.height,
valid: true,
rotate: 0,
...basicImgInfo,
});

this.renderBasicCanvas();
}

public createBasicCanvas(size: ISize) {
const basicCanvas = document.createElement('canvas');
basicCanvas.className = 'bee-basic-layer';
this.updateCanvasBasicStyle(basicCanvas, size, 0);
this.basicCanvas = basicCanvas;
if (this.container.hasChildNodes()) {
this.container.insertBefore(basicCanvas, this.container.childNodes[0]);
} else {
this.container.appendChild(basicCanvas);
}
this.basicCtx?.scale(this.pixelRatio, this.pixelRatio);
}

public updateCanvasBasicStyle(canvas: HTMLCanvasElement, size: ISize, zIndex: number) {
const pixel = this.pixelRatio;
canvas.style.position = 'absolute';
canvas.width = size.width * pixel;
canvas.height = size.height * pixel;
canvas.style.width = `${size.width}px`;
canvas.style.height = `${size.height}px`;
canvas.style.left = '0';
canvas.style.top = '0';
canvas.style.zIndex = `${zIndex} `;
}

public drawImg = () => {
if (!this.imgNode || this.hiddenImg === true) return;

DrawUtils.drawImg(this.basicCanvas, this.imgNode, {
zoom: this.zoom,
currentPos: this.currentPos,
rotate: this.rotate,
imgAttribute: this._imgAttribute,
});
};

public destroyBasicCanvas() {
if (this.basicCanvas && this.container.contains(this.basicCanvas)) {
this.container.removeChild(this.basicCanvas);
}
}

public clearBasicCanvas() {
this.basicCtx?.clearRect(0, 0, this.size.width, this.size.height);
}

public renderBasicCanvas() {
if (!this.basicCanvas) {
return;
}

this.clearBasicCanvas();
this.drawImg();

const thickness = 2;

if (this.basicResult && this.dependToolName && !this.forbidBasicResultRender) {
switch (this.dependToolName) {
case EToolName.Rect: {
DrawUtils.drawRect(
this.basicCanvas,
AxisUtils.changeRectByZoom(this.basicResult, this.zoom, this.currentPos),
{
color: 'rgba(204,204,204,1.00)',
thickness,
},
);
break;
}

case EToolName.Polygon: {
DrawUtils.drawPolygonWithFillAndLine(
this.basicCanvas,
AxisUtils.changePointListByZoom(this.basicResult.pointList, this.zoom, this.currentPos),
{
fillColor: 'transparent',
strokeColor: 'rgba(204,204,204,1.00)',
isClose: true,
thickness,
},
);

break;
}

case EToolName.Line: {
DrawUtils.drawLineWithPointList(
this.basicCanvas,
AxisUtils.changePointListByZoom(this.basicResult.pointList, this.zoom, this.currentPos),
{
color: 'rgba(204,204,204,1.00)',
thickness,
},
);

break;
}

default: {
//
}
}
}

this.renderReference();
}

public renderReference() {
const thickness = 2;

if (this.referenceInfo) {
const { referenceResult, referenceToolName, referenceConfig } = this.referenceInfo;
switch (referenceToolName) {
case EToolName.RectTrack:
case EToolName.Rect: {
const rectList = referenceResult;
rectList.forEach((rect: IRect) => {
const toolColor = this.getColor(rect.attribute, referenceConfig);
const toolData = StyleUtils.getStrokeAndFill(toolColor, rect.valid);
DrawUtils.drawRect(this.basicCanvas, AxisUtils.changeRectByZoom(rect, this.zoom, this.currentPos), {
color: toolData.stroke,
thickness,
lineDash: [24],
});
});
break;
}

case EToolName.Point: {
const pointList = referenceResult;
pointList.forEach((point: IPointUnit) => {
const toolColor = this.getColor(point.attribute, referenceConfig);
const toolData = StyleUtils.getStrokeAndFill(toolColor, point.valid);
DrawUtils.drawCircle(this.basicCanvas, AxisUtils.changePointByZoom(point, this.zoom, this.currentPos), 5, {
color: toolData.stroke,
fill: toolData.fill,
});
});
break;
}

case EToolName.Polygon: {
const polygonList = referenceResult;
polygonList.forEach((polygon: IPolygonData) => {
const toolColor = this.getColor(polygon.attribute, referenceConfig);
const toolData = StyleUtils.getStrokeAndFill(toolColor, polygon.valid);

DrawUtils.drawPolygonWithFillAndLine(
this.basicCanvas,
AxisUtils.changePointListByZoom(polygon.pointList, this.zoom, this.currentPos),
{
fillColor: toolData.fill,
strokeColor: toolData.stroke,
isClose: true,
thickness,
},
);
});

break;
}

case EToolName.LineMarker:
case EToolName.Line: {
const lineList = referenceResult;
lineList.forEach((line: any) => {
const toolColor = this.getColor(line.attribute, referenceConfig);
const toolData = StyleUtils.getStrokeAndFill(toolColor, line.valid);

DrawUtils.drawLineWithPointList(
this.basicCanvas,
AxisUtils.changePointListByZoom(line.pointList, this.zoom, this.currentPos),
{
color: toolData.stroke,
thickness,
},
);
});

break;
}

default: {
//
}
}
}
}
}
Loading