mirror of
https://github.com/motajs/template.git
synced 2026-11-05 00:34:34 +08:00
init: 2.B
This commit is contained in:
commit
6bf32174d8
610 files changed
+151444
No files matched your search
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"name": "@motajs/render-elements",
|
||||
"dependencies": {
|
||||
"@motajs/common": "workspace:*",
|
||||
"@motajs/render-core": "workspace:*",
|
||||
"@motajs/render-style": "workspace:*"
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,2 @@
|
||||
export * from './graphics';
|
||||
export * from './misc';
|
||||
@@ -0,0 +1,227 @@
|
||||
import {
|
||||
ERenderItemEvent,
|
||||
RenderItem,
|
||||
RenderItemPosition,
|
||||
Transform,
|
||||
MotaOffscreenCanvas2D
|
||||
} from '@motajs/render-core';
|
||||
import { Font } from '@motajs/render-style';
|
||||
|
||||
/** 文字的安全填充,会填充在文字的上侧和下侧,防止削顶和削底 */
|
||||
const SAFE_PAD = 1;
|
||||
|
||||
type CanvasStyle = string | CanvasGradient | CanvasPattern;
|
||||
|
||||
export interface ETextEvent extends ERenderItemEvent {
|
||||
setText: [text: string, width: number, height: number];
|
||||
}
|
||||
|
||||
export class Text extends RenderItem<ETextEvent> {
|
||||
text: string;
|
||||
|
||||
fillStyle?: CanvasStyle = '#fff';
|
||||
strokeStyle?: CanvasStyle;
|
||||
font: Font = new Font();
|
||||
strokeWidth: number = 1;
|
||||
|
||||
private length: number = 0;
|
||||
private descent: number = 0;
|
||||
|
||||
private static measureCanvas = new MotaOffscreenCanvas2D();
|
||||
|
||||
constructor(text: string = '', type: RenderItemPosition = 'static') {
|
||||
super(type, false);
|
||||
|
||||
this.text = text;
|
||||
if (text.length > 0) {
|
||||
this.requestBeforeFrame(() => {
|
||||
this.calBox();
|
||||
this.emit('setText', text, this.width, this.height);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
protected render(
|
||||
canvas: MotaOffscreenCanvas2D,
|
||||
_transform: Transform
|
||||
): void {
|
||||
const ctx = canvas.ctx;
|
||||
const stroke = this.strokeWidth;
|
||||
ctx.textBaseline = 'bottom';
|
||||
ctx.fillStyle = this.fillStyle ?? 'transparent';
|
||||
ctx.strokeStyle = this.strokeStyle ?? 'transparent';
|
||||
ctx.font = this.font.string();
|
||||
ctx.lineWidth = this.strokeWidth;
|
||||
ctx.lineJoin = 'round';
|
||||
|
||||
if (this.strokeStyle) {
|
||||
ctx.strokeText(this.text, stroke, this.descent + stroke + SAFE_PAD);
|
||||
}
|
||||
if (this.fillStyle) {
|
||||
ctx.fillText(this.text, stroke, this.descent + stroke + SAFE_PAD);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取文字的长度
|
||||
*/
|
||||
measure() {
|
||||
const ctx = Text.measureCanvas.ctx;
|
||||
ctx.textBaseline = 'bottom';
|
||||
ctx.font = this.font.string();
|
||||
const res = ctx.measureText(this.text);
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置显示文字
|
||||
* @param text 显示的文字
|
||||
*/
|
||||
setText(text: string) {
|
||||
this.text = text;
|
||||
this.calBox();
|
||||
this.update(this);
|
||||
this.emit('setText', text, this.width, this.height);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置使用的字体
|
||||
* @param font 字体
|
||||
*/
|
||||
setFont(font: Font) {
|
||||
this.font = font;
|
||||
this.calBox();
|
||||
this.update(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置字体样式
|
||||
* @param fill 填充样式
|
||||
* @param stroke 描边样式
|
||||
*/
|
||||
setStyle(fill?: CanvasStyle, stroke?: CanvasStyle) {
|
||||
this.fillStyle = fill;
|
||||
this.strokeStyle = stroke;
|
||||
this.update();
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置描边宽度
|
||||
* @param width 宽度
|
||||
*/
|
||||
setStrokeWidth(width: number) {
|
||||
const before = this.strokeWidth;
|
||||
this.strokeWidth = width;
|
||||
const dw = width - before;
|
||||
this.size(this.width + dw * 2, this.height + dw * 2);
|
||||
this.update();
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算字体所占空间,从而确定这个元素的大小
|
||||
*/
|
||||
calBox() {
|
||||
const { width, actualBoundingBoxAscent, actualBoundingBoxDescent } =
|
||||
this.measure();
|
||||
this.length = width;
|
||||
this.descent = actualBoundingBoxAscent;
|
||||
const height = actualBoundingBoxAscent + actualBoundingBoxDescent;
|
||||
const stroke = this.strokeWidth * 2;
|
||||
this.size(width + stroke, height + stroke + SAFE_PAD * 2);
|
||||
}
|
||||
|
||||
protected handleProps(
|
||||
key: string,
|
||||
_prevValue: any,
|
||||
nextValue: any
|
||||
): boolean {
|
||||
switch (key) {
|
||||
case 'text':
|
||||
if (!this.assertType(nextValue, 'string', key)) return false;
|
||||
this.setText(nextValue);
|
||||
return true;
|
||||
case 'fillStyle':
|
||||
this.setStyle(nextValue, this.strokeStyle);
|
||||
return true;
|
||||
case 'strokeStyle':
|
||||
this.setStyle(this.fillStyle, nextValue);
|
||||
return true;
|
||||
case 'font':
|
||||
if (!this.assertType(nextValue, Font, key)) return false;
|
||||
this.setFont(nextValue);
|
||||
return true;
|
||||
case 'strokeWidth':
|
||||
this.setStrokeWidth(nextValue);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
export interface EImageEvent extends ERenderItemEvent {}
|
||||
|
||||
export class Image extends RenderItem<EImageEvent> {
|
||||
image: CanvasImageSource;
|
||||
|
||||
constructor(image: CanvasImageSource, type: RenderItemPosition = 'static') {
|
||||
super(type, false);
|
||||
this.image = image;
|
||||
if (image instanceof VideoFrame || image instanceof SVGElement) {
|
||||
this.size(200, 200);
|
||||
} else {
|
||||
this.size(image.width, image.height);
|
||||
}
|
||||
}
|
||||
|
||||
protected render(
|
||||
canvas: MotaOffscreenCanvas2D,
|
||||
_transform: Transform
|
||||
): void {
|
||||
const ctx = canvas.ctx;
|
||||
ctx.drawImage(this.image, 0, 0, this.width, this.height);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置图片资源
|
||||
* @param image 图片资源
|
||||
*/
|
||||
setImage(image: CanvasImageSource) {
|
||||
this.image = image;
|
||||
this.update();
|
||||
}
|
||||
|
||||
protected handleProps(
|
||||
key: string,
|
||||
_prevValue: any,
|
||||
nextValue: any
|
||||
): boolean {
|
||||
switch (key) {
|
||||
case 'image':
|
||||
this.setImage(nextValue);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
export class Comment extends RenderItem {
|
||||
readonly isComment: boolean = true;
|
||||
|
||||
constructor(public text: string = '') {
|
||||
super('static', false, false);
|
||||
this.hide();
|
||||
}
|
||||
|
||||
getBoundingRect(): DOMRectReadOnly {
|
||||
return new DOMRectReadOnly(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
protected render(
|
||||
_canvas: MotaOffscreenCanvas2D,
|
||||
_transform: Transform
|
||||
): void {}
|
||||
|
||||
protected handleProps(): boolean {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user