face-api/src/draw/DrawTextField.ts

127 lines
4.0 KiB
TypeScript
Raw Normal View History

2020-12-23 17:26:55 +01:00
/* eslint-disable max-classes-per-file */
2020-12-19 17:46:41 +01:00
import { IDimensions, IPoint } from '../classes/index';
2020-08-18 13:54:53 +02:00
import { getContext2dOrThrow } from '../dom/getContext2dOrThrow';
import { resolveInput } from '../dom/resolveInput';
2020-12-23 17:26:55 +01:00
// eslint-disable-next-line no-shadow
2020-08-18 13:54:53 +02:00
export enum AnchorPosition {
2020-12-23 17:26:55 +01:00
// eslint-disable-next-line no-unused-vars
2020-08-18 13:54:53 +02:00
TOP_LEFT = 'TOP_LEFT',
2020-12-23 17:26:55 +01:00
// eslint-disable-next-line no-unused-vars
2020-08-18 13:54:53 +02:00
TOP_RIGHT = 'TOP_RIGHT',
2020-12-23 17:26:55 +01:00
// eslint-disable-next-line no-unused-vars
2020-08-18 13:54:53 +02:00
BOTTOM_LEFT = 'BOTTOM_LEFT',
2020-12-23 17:26:55 +01:00
// eslint-disable-next-line no-unused-vars
2020-08-18 13:54:53 +02:00
BOTTOM_RIGHT = 'BOTTOM_RIGHT'
}
export interface IDrawTextFieldOptions {
anchorPosition?: AnchorPosition
backgroundColor?: string
fontColor?: string
fontSize?: number
fontStyle?: string
padding?: number
}
export class DrawTextFieldOptions implements IDrawTextFieldOptions {
public anchorPosition: AnchorPosition
2020-12-23 17:26:55 +01:00
2020-08-18 13:54:53 +02:00
public backgroundColor: string
2020-12-23 17:26:55 +01:00
2020-08-18 13:54:53 +02:00
public fontColor: string
2020-12-23 17:26:55 +01:00
2020-08-18 13:54:53 +02:00
public fontSize: number
2020-12-23 17:26:55 +01:00
2020-08-18 13:54:53 +02:00
public fontStyle: string
2020-12-23 17:26:55 +01:00
2020-08-18 13:54:53 +02:00
public padding: number
constructor(options: IDrawTextFieldOptions = {}) {
2020-12-23 17:26:55 +01:00
const {
anchorPosition, backgroundColor, fontColor, fontSize, fontStyle, padding,
} = options;
this.anchorPosition = anchorPosition || AnchorPosition.TOP_LEFT;
this.backgroundColor = backgroundColor || 'rgba(0, 0, 0, 0.5)';
this.fontColor = fontColor || 'rgba(255, 255, 255, 1)';
this.fontSize = fontSize || 14;
this.fontStyle = fontStyle || 'Georgia';
this.padding = padding || 4;
2020-08-18 13:54:53 +02:00
}
}
export class DrawTextField {
public text: string[]
2020-12-23 17:26:55 +01:00
2020-08-18 13:54:53 +02:00
public anchor : IPoint
2020-12-23 17:26:55 +01:00
2020-08-18 13:54:53 +02:00
public options: DrawTextFieldOptions
constructor(
text: string | string[] | DrawTextField,
anchor: IPoint,
2020-12-23 17:26:55 +01:00
options: IDrawTextFieldOptions = {},
2020-08-18 13:54:53 +02:00
) {
2020-12-23 17:26:55 +01:00
// eslint-disable-next-line no-nested-ternary
2020-08-18 13:54:53 +02:00
this.text = typeof text === 'string'
? [text]
2020-12-23 17:26:55 +01:00
: (text instanceof DrawTextField ? text.text : text);
this.anchor = anchor;
this.options = new DrawTextFieldOptions(options);
2020-08-18 13:54:53 +02:00
}
measureWidth(ctx: CanvasRenderingContext2D): number {
2020-12-23 17:26:55 +01:00
const { padding } = this.options;
return this.text.map((l) => ctx.measureText(l).width).reduce((w0, w1) => (w0 < w1 ? w1 : w0), 0) + (2 * padding);
2020-08-18 13:54:53 +02:00
}
measureHeight(): number {
2020-12-23 17:26:55 +01:00
const { fontSize, padding } = this.options;
return this.text.length * fontSize + (2 * padding);
2020-08-18 13:54:53 +02:00
}
getUpperLeft(ctx: CanvasRenderingContext2D, canvasDims?: IDimensions): IPoint {
2020-12-23 17:26:55 +01:00
const { anchorPosition } = this.options;
const isShiftLeft = anchorPosition === AnchorPosition.BOTTOM_RIGHT || anchorPosition === AnchorPosition.TOP_RIGHT;
const isShiftTop = anchorPosition === AnchorPosition.BOTTOM_LEFT || anchorPosition === AnchorPosition.BOTTOM_RIGHT;
2020-08-18 13:54:53 +02:00
2020-12-23 17:26:55 +01:00
const textFieldWidth = this.measureWidth(ctx);
const textFieldHeight = this.measureHeight();
const x = (isShiftLeft ? this.anchor.x - textFieldWidth : this.anchor.x);
const y = isShiftTop ? this.anchor.y - textFieldHeight : this.anchor.y;
2020-08-18 13:54:53 +02:00
// adjust anchor if text box exceeds canvas borders
if (canvasDims) {
2020-12-23 17:26:55 +01:00
const { width, height } = canvasDims;
const newX = Math.max(Math.min(x, width - textFieldWidth), 0);
const newY = Math.max(Math.min(y, height - textFieldHeight), 0);
return { x: newX, y: newY };
2020-08-18 13:54:53 +02:00
}
2020-12-23 17:26:55 +01:00
return { x, y };
2020-08-18 13:54:53 +02:00
}
draw(canvasArg: string | HTMLCanvasElement | CanvasRenderingContext2D) {
2020-12-23 17:26:55 +01:00
const canvas = resolveInput(canvasArg);
const ctx = getContext2dOrThrow(canvas);
2020-08-18 13:54:53 +02:00
2020-12-23 17:26:55 +01:00
const {
backgroundColor, fontColor, fontSize, fontStyle, padding,
} = this.options;
2020-08-18 13:54:53 +02:00
2020-12-23 17:26:55 +01:00
ctx.font = `${fontSize}px ${fontStyle}`;
const maxTextWidth = this.measureWidth(ctx);
const textHeight = this.measureHeight();
2020-08-18 13:54:53 +02:00
2020-12-23 17:26:55 +01:00
ctx.fillStyle = backgroundColor;
const upperLeft = this.getUpperLeft(ctx, canvas);
ctx.fillRect(upperLeft.x, upperLeft.y, maxTextWidth, textHeight);
2020-08-18 13:54:53 +02:00
ctx.fillStyle = fontColor;
this.text.forEach((textLine, i) => {
2020-12-23 17:26:55 +01:00
const x = padding + upperLeft.x;
const y = padding + upperLeft.y + ((i + 1) * fontSize);
ctx.fillText(textLine, x, y);
});
2020-08-18 13:54:53 +02:00
}
2020-12-23 17:26:55 +01:00
}