mirror of
https://github.com/idrawjs/idraw
synced 2026-05-24 10:08:34 +00:00
chore: clear unuse code
This commit is contained in:
parent
88620b5f3a
commit
d8fb200f71
17 changed files with 10 additions and 1058 deletions
|
|
@ -1,6 +1,6 @@
|
|||
import {
|
||||
TypeScreenPosition, TypeScreenSize, TypeScreenContext, TypePoint, TypePointCursor,
|
||||
TypeBoardOptions, TypeBoardSizeOptions, InterfacePlugin, TypeContext,
|
||||
TypeBoardOptions, TypeBoardSizeOptions, TypeContext,
|
||||
} from '@idraw/types';
|
||||
import util from '@idraw/util';
|
||||
import { ScreenWatcher } from './lib/screen-watcher';
|
||||
|
|
@ -8,7 +8,7 @@ import { setStyle } from './lib/style';
|
|||
import { TypeBoardEventArgMap } from './lib/event';
|
||||
import { Scroller } from './lib/scroller';
|
||||
import { Screen } from './lib/screen';
|
||||
import { TempData } from './lib/temp';
|
||||
// import { TempData } from './lib/temp';
|
||||
import {
|
||||
_canvas, _displayCanvas, _mount, _opts, _hasRendered, _ctx,
|
||||
_watcher, _render, _parsePrivateOptions, _scroller, _helperCanvas, _helperCtx,
|
||||
|
|
@ -38,10 +38,10 @@ class Board {
|
|||
private [_watcher]: ScreenWatcher;
|
||||
private [_scroller]: Scroller;
|
||||
private [_screen]: Screen;
|
||||
private [_tempData]: TempData;
|
||||
// private [_tempData]: TempData;
|
||||
|
||||
constructor(mount: HTMLDivElement, opts: TypeBoardOptions) {
|
||||
this[_tempData] = new TempData(opts);
|
||||
// this[_tempData] = new TempData(opts);
|
||||
|
||||
this[_mount] = mount;
|
||||
this[_canvas] = document.createElement('canvas');
|
||||
|
|
@ -159,10 +159,6 @@ class Board {
|
|||
return { position, size };
|
||||
}
|
||||
|
||||
addPlugin(plugin: InterfacePlugin) {
|
||||
this[_tempData].get('plugins').push(plugin);
|
||||
}
|
||||
|
||||
clear() {
|
||||
const displayCtx = this[_displayCanvas].getContext('2d');
|
||||
displayCtx?.clearRect(0, 0, this[_displayCanvas].width, this[_displayCanvas].height);
|
||||
|
|
|
|||
|
|
@ -1,12 +1,10 @@
|
|||
import { InterfacePlugin, TypeBoardOptions, TypeContext } from '@idraw/types';
|
||||
import { TypeBoardOptions, TypeContext } from '@idraw/types';
|
||||
import util from '@idraw/util';
|
||||
|
||||
const Context = util.Context;
|
||||
|
||||
type TempDataDesc = {
|
||||
plugins: InterfacePlugin[],
|
||||
ctx: TypeContext,
|
||||
|
||||
}
|
||||
|
||||
function createDefaultData(opts: TypeBoardOptions) {
|
||||
|
|
|
|||
|
|
@ -1,77 +0,0 @@
|
|||
import { TypeContext, TypeElement, } from '@idraw/types';
|
||||
// import util from '@idraw/util'
|
||||
import { rotateElement } from './../transform';
|
||||
// import is from './../is';
|
||||
import { clearContext } from './base';
|
||||
|
||||
export function drawCircle(ctx: TypeContext, elem: TypeElement<'circle'>) {
|
||||
clearContext(ctx);
|
||||
rotateElement(ctx, elem, (ctx) => {
|
||||
const { x, y, w, h, desc } = elem;
|
||||
const {
|
||||
bgColor = '#000000',
|
||||
borderColor = '#000000',
|
||||
borderWidth = 0,
|
||||
} = desc;
|
||||
|
||||
const a = w / 2;
|
||||
const b = h / 2;
|
||||
const centerX = x + a;
|
||||
const centerY = y + b;
|
||||
|
||||
// draw border
|
||||
if (borderWidth && borderWidth > 0) {
|
||||
|
||||
const ba = borderWidth / 2 + a;
|
||||
const bb = borderWidth / 2 + b;
|
||||
ctx.beginPath();
|
||||
ctx.setStrokeStyle(borderColor);
|
||||
ctx.setLineWidth(borderWidth);
|
||||
ctx.ellipse(centerX, centerY, ba, bb, 0, 0, 2 * Math.PI)
|
||||
|
||||
ctx.closePath();
|
||||
ctx.stroke();
|
||||
}
|
||||
|
||||
// draw content
|
||||
ctx.beginPath();
|
||||
ctx.setFillStyle(bgColor);
|
||||
ctx.ellipse(centerX, centerY, a, b, 0, 0, 2 * Math.PI)
|
||||
ctx.closePath();
|
||||
ctx.fill();
|
||||
|
||||
// // draw shadow
|
||||
// clearContext(ctx);
|
||||
// if ((desc.shadowOffsetX !== undefined && is.number(desc.shadowOffsetX)) || desc.shadowOffsetY !== undefined && is.number(desc.shadowOffsetY)) {
|
||||
|
||||
// if (desc.shadowColor !== undefined && util.color.isColorStr(desc.shadowColor)) {
|
||||
// ctx.setShadowColor(desc.shadowColor);
|
||||
// }
|
||||
// if (desc.shadowOffsetX !== undefined && is.number(desc.shadowOffsetX)) {
|
||||
// ctx.setShadowOffsetX(desc.shadowOffsetX);
|
||||
// }
|
||||
// if (desc.shadowOffsetY !== undefined && is.number(desc.shadowOffsetY)) {
|
||||
// ctx.setShadowOffsetY(desc.shadowOffsetY);
|
||||
// }
|
||||
// if (desc.shadowBlur !== undefined && is.number(desc.shadowBlur)) {
|
||||
// ctx.setShadowBlur(desc.shadowBlur);
|
||||
// }
|
||||
|
||||
// const a = (w + borderWidth * 2) / 2;
|
||||
// const b = (h + borderWidth * 2) / 2;
|
||||
// const centerX = x + a - borderWidth;
|
||||
// const centerY = y + b - borderWidth;
|
||||
// const unit = (a > b) ? 1 / a : 1 / b;
|
||||
|
||||
// ctx.beginPath();
|
||||
// ctx.setFillStyle('#ffffff6a');
|
||||
// ctx.moveTo(centerX + a, centerY);
|
||||
// for(var i = 0; i < 2 * Math.PI; i += unit) {
|
||||
// ctx.lineTo(centerX + a * Math.cos(i), centerY + b * Math.sin(i));
|
||||
// }
|
||||
// ctx.closePath();
|
||||
// ctx.fill();
|
||||
// }
|
||||
|
||||
})
|
||||
}
|
||||
|
|
@ -1,20 +0,0 @@
|
|||
import {
|
||||
TypeContext,
|
||||
TypeElement,
|
||||
} from '@idraw/types';
|
||||
import { rotateElement } from '../transform';
|
||||
import Loader from '../loader';
|
||||
|
||||
|
||||
export function drawHTML(
|
||||
ctx: TypeContext,
|
||||
elem: TypeElement<'html'>,
|
||||
loader: Loader,
|
||||
) {
|
||||
const content = loader.getContent(elem.uuid);
|
||||
rotateElement(ctx, elem, () => {
|
||||
if (content) {
|
||||
ctx.drawImage(content, elem.x, elem.y, elem.w, elem.h);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
@ -1,53 +0,0 @@
|
|||
import {
|
||||
TypeContext,
|
||||
TypeElement,
|
||||
} from '@idraw/types';
|
||||
import { rotateElement } from '../transform';
|
||||
import Loader from '../loader';
|
||||
|
||||
|
||||
export function drawImage (
|
||||
ctx: TypeContext,
|
||||
elem: TypeElement<'image'>,
|
||||
loader: Loader,
|
||||
) {
|
||||
// const desc = elem.desc as TypeElemDesc['rect'];
|
||||
const content = loader.getContent(elem.uuid);
|
||||
rotateElement(ctx, elem, () => {
|
||||
// ctx.setFillStyle(desc.color);
|
||||
// ctx.fillRect(elem.x, elem.y, elem.w, elem.h);
|
||||
if (content) {
|
||||
// ctx.drawImage(content, 0, 0, elem.w, elem.h, elem.x, elem.y, elem.w, elem.h);
|
||||
ctx.drawImage(content, elem.x, elem.y, elem.w, elem.h);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
// import {
|
||||
// TypeContext,
|
||||
// TypeElement,
|
||||
// TypeHelperConfig,
|
||||
// TypeElemDesc,
|
||||
// } from '@idraw/types';
|
||||
// import Loader from '../loader';
|
||||
// import { drawBox } from './base';
|
||||
|
||||
// export function drawImage(
|
||||
// ctx: TypeContext,
|
||||
// elem: TypeElement<'image'>,
|
||||
// loader: Loader,
|
||||
// helperConfig: TypeHelperConfig
|
||||
// ) {
|
||||
// const content = loader.getPattern(elem, {
|
||||
// forceUpdate: helperConfig?.selectedElementWrapper?.uuid === elem.uuid
|
||||
// });
|
||||
// drawBox(ctx, elem, content);
|
||||
// }
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -1,81 +0,0 @@
|
|||
import {
|
||||
TypeContext,
|
||||
TypeData,
|
||||
TypeElement,
|
||||
TypeHelperConfig,
|
||||
// TypePoint,
|
||||
} from '@idraw/types';
|
||||
import util from '@idraw/util';
|
||||
import Loader from '../loader';
|
||||
import { clearContext, drawBgColor } from './base';
|
||||
import { drawRect } from './rect';
|
||||
import { drawImage } from './image';
|
||||
import { drawSVG } from './svg';
|
||||
import { drawHTML } from './html';
|
||||
import { drawText } from './text';
|
||||
import { drawCircle } from './circle';
|
||||
import {
|
||||
drawElementWrapper, drawAreaWrapper, drawElementListWrappers,
|
||||
} from './wrapper';
|
||||
|
||||
const { isColorStr } = util.color;
|
||||
|
||||
export function drawContext(
|
||||
ctx: TypeContext,
|
||||
data: TypeData,
|
||||
helperConfig: TypeHelperConfig,
|
||||
loader: Loader,
|
||||
): void {
|
||||
clearContext(ctx);
|
||||
const size = ctx.getSize();
|
||||
ctx.clearRect(0, 0, size.contextWidth, size.contextHeight);
|
||||
|
||||
if (typeof data.bgColor === 'string' && isColorStr(data.bgColor)) {
|
||||
drawBgColor(ctx, data.bgColor);
|
||||
}
|
||||
|
||||
if (!(data.elements.length > 0)) {
|
||||
return;
|
||||
}
|
||||
for (let i = 0; i < data.elements.length; i++) {
|
||||
const elem = data.elements[i];
|
||||
if (elem?.operation?.invisible === true) {
|
||||
continue;
|
||||
}
|
||||
switch (elem.type) {
|
||||
case 'rect': {
|
||||
drawRect(ctx, elem as TypeElement<'rect'>);
|
||||
break;
|
||||
}
|
||||
case 'text': {
|
||||
drawText(ctx, elem as TypeElement<'text'>, loader, helperConfig);
|
||||
break;
|
||||
}
|
||||
case 'image': {
|
||||
drawImage(ctx, elem as TypeElement<'image'>, loader);
|
||||
break;
|
||||
}
|
||||
case 'svg': {
|
||||
drawSVG(ctx, elem as TypeElement<'svg'>, loader);
|
||||
break;
|
||||
}
|
||||
case 'html': {
|
||||
drawHTML(ctx, elem as TypeElement<'html'>, loader);
|
||||
break;
|
||||
}
|
||||
case 'circle': {
|
||||
drawCircle(ctx, elem as TypeElement<'circle'>);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
// nothing
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
drawElementWrapper(ctx, helperConfig);
|
||||
drawAreaWrapper(ctx, helperConfig);
|
||||
drawElementListWrappers(ctx, helperConfig);
|
||||
}
|
||||
|
||||
|
|
@ -1,13 +0,0 @@
|
|||
import {
|
||||
TypeContext,
|
||||
TypeElement,
|
||||
} from '@idraw/types';
|
||||
import { drawBox } from './base';
|
||||
|
||||
export function drawRect(ctx: TypeContext, elem: TypeElement<'rect'>) {
|
||||
drawBox(ctx, elem, elem.desc.bgColor as string);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -1,47 +0,0 @@
|
|||
import {
|
||||
TypeContext,
|
||||
TypeElement,
|
||||
} from '@idraw/types';
|
||||
import { rotateElement } from '../transform';
|
||||
import Loader from '../loader';
|
||||
|
||||
|
||||
export function drawSVG (
|
||||
ctx: TypeContext,
|
||||
elem: TypeElement<'svg'>,
|
||||
loader: Loader,
|
||||
) {
|
||||
// const desc = elem.desc as TypeElemDesc['rect'];
|
||||
const content = loader.getContent(elem.uuid);
|
||||
rotateElement(ctx, elem, () => {
|
||||
// ctx.setFillStyle(desc.color);
|
||||
// ctx.fillRect(elem.x, elem.y, elem.w, elem.h);
|
||||
if (content) {
|
||||
// ctx.drawImage(content, 0, 0, elem.w, elem.h, elem.x, elem.y, elem.w, elem.h);
|
||||
ctx.drawImage(content, elem.x, elem.y, elem.w, elem.h);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// import {
|
||||
// TypeContext,
|
||||
// TypeElement,
|
||||
// TypeHelperConfig,
|
||||
// } from '@idraw/types';
|
||||
// import Loader from '../loader';
|
||||
// import { drawBox } from './base';
|
||||
|
||||
// export function drawSVG(
|
||||
// ctx: TypeContext,
|
||||
// elem: TypeElement<'svg'>,
|
||||
// loader: Loader,
|
||||
// helperConfig: TypeHelperConfig
|
||||
// ) {
|
||||
// const content = loader.getPattern(elem, {
|
||||
// forceUpdate: helperConfig?.selectedElementWrapper?.uuid === elem.uuid
|
||||
// });
|
||||
// drawBox(ctx, elem, content);
|
||||
// }
|
||||
|
||||
|
||||
|
||||
|
|
@ -1,143 +0,0 @@
|
|||
import {
|
||||
TypeContext,
|
||||
TypeElemDescText,
|
||||
TypeElement,
|
||||
TypeHelperConfig,
|
||||
} from '@idraw/types';
|
||||
import util from '@idraw/util';
|
||||
import Loader from '../loader';
|
||||
import { clearContext, drawBox } from './base';
|
||||
import { rotateElement } from './../transform';
|
||||
import is from './../is';
|
||||
|
||||
export function drawText(
|
||||
ctx: TypeContext,
|
||||
elem: TypeElement<'text'>,
|
||||
loader: Loader,
|
||||
helperConfig: TypeHelperConfig
|
||||
) {
|
||||
clearContext(ctx);
|
||||
drawBox(ctx, elem, elem.desc.bgColor || 'transparent');
|
||||
rotateElement(ctx, elem, () => {
|
||||
|
||||
const desc: TypeElemDescText = {
|
||||
...{
|
||||
fontSize: 12,
|
||||
fontFamily: 'sans-serif',
|
||||
textAlign: 'center',
|
||||
},
|
||||
...elem.desc
|
||||
};
|
||||
ctx.setFillStyle(elem.desc.color);
|
||||
ctx.setTextBaseline('top');
|
||||
ctx.setFont({
|
||||
fontWeight: desc.fontWeight,
|
||||
fontSize: desc.fontSize,
|
||||
fontFamily: desc.fontFamily
|
||||
});
|
||||
const descText = desc.text.replace(/\r\n/ig, '\n');
|
||||
const fontHeight = desc.lineHeight || desc.fontSize;
|
||||
const descTextList = descText.split('\n');
|
||||
const lines: {text: string, width: number}[] = [];
|
||||
|
||||
descTextList.forEach((tempText) => {
|
||||
let lineText = '';
|
||||
let lineNum = 0;
|
||||
for (let i = 0; i < tempText.length; i++) {
|
||||
if (ctx.measureText(lineText + (tempText[i] || '')).width < ctx.calcDeviceNum(elem.w)) {
|
||||
lineText += (tempText[i] || '');
|
||||
} else {
|
||||
lines.push({
|
||||
text: lineText,
|
||||
width: ctx.calcScreenNum(ctx.measureText(lineText).width),
|
||||
});
|
||||
lineText = (tempText[i] || '');
|
||||
lineNum ++;
|
||||
}
|
||||
if ((lineNum + 1) * fontHeight > elem.h) {
|
||||
break;
|
||||
}
|
||||
if (lineText && tempText.length - 1 === i) {
|
||||
if ((lineNum + 1) * fontHeight < elem.h) {
|
||||
lines.push({
|
||||
text: lineText,
|
||||
width: ctx.calcScreenNum(ctx.measureText(lineText).width),
|
||||
});
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// draw text lines
|
||||
{
|
||||
let _y = elem.y;
|
||||
if (lines.length * fontHeight < elem.h) {
|
||||
_y += ((elem.h - lines.length * fontHeight) / 2);
|
||||
}
|
||||
if (desc.textShadowColor !== undefined && util.color.isColorStr(desc.textShadowColor)) {
|
||||
ctx.setShadowColor(desc.textShadowColor);
|
||||
}
|
||||
if (desc.textShadowOffsetX !== undefined && is.number(desc.textShadowOffsetX)) {
|
||||
ctx.setShadowOffsetX(desc.textShadowOffsetX);
|
||||
}
|
||||
if (desc.textShadowOffsetY !== undefined && is.number(desc.textShadowOffsetY)) {
|
||||
ctx.setShadowOffsetY(desc.textShadowOffsetY);
|
||||
}
|
||||
if (desc.textShadowBlur !== undefined && is.number(desc.textShadowBlur)) {
|
||||
ctx.setShadowBlur(desc.textShadowBlur);
|
||||
}
|
||||
lines.forEach((line, i) => {
|
||||
let _x = elem.x;
|
||||
if (desc.textAlign === 'center') {
|
||||
_x = elem.x + (elem.w - line.width) / 2;
|
||||
} else if (desc.textAlign === 'right') {
|
||||
_x = elem.x + (elem.w - line.width);
|
||||
}
|
||||
ctx.fillText(line.text, _x, _y + fontHeight * i);
|
||||
});
|
||||
clearContext(ctx);
|
||||
}
|
||||
|
||||
// draw text stroke
|
||||
if (util.color.isColorStr(desc.strokeColor) && desc.strokeWidth !== undefined && desc.strokeWidth > 0) {
|
||||
let _y = elem.y;
|
||||
if (lines.length * fontHeight < elem.h) {
|
||||
_y += ((elem.h - lines.length * fontHeight) / 2);
|
||||
}
|
||||
lines.forEach((line, i) => {
|
||||
let _x = elem.x;
|
||||
if (desc.textAlign === 'center') {
|
||||
_x = elem.x + (elem.w - line.width) / 2;
|
||||
} else if (desc.textAlign === 'right') {
|
||||
_x = elem.x + (elem.w - line.width);
|
||||
}
|
||||
if (desc.strokeColor !== undefined) {
|
||||
ctx.setStrokeStyle(desc.strokeColor);
|
||||
}
|
||||
if (desc.strokeWidth !== undefined && desc.strokeWidth > 0) {
|
||||
ctx.setLineWidth(desc.strokeWidth);
|
||||
}
|
||||
ctx.strokeText(line.text, _x, _y + fontHeight * i);
|
||||
});
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
// export function createTextSVG(elem: TypeElement<'text'>): string {
|
||||
// const svg = `
|
||||
// <svg xmlns="http://www.w3.org/2000/svg" width="${elem.w}" height = "${elem.h}">
|
||||
// <foreignObject width="100%" height="100%">
|
||||
// <div xmlns = "http://www.w3.org/1999/xhtml" style="font-size: ${elem.desc.size}px; color:${elem.desc.color};">
|
||||
// <span>${elem.desc.text || ''}</span>
|
||||
// </div>
|
||||
// </foreignObject>
|
||||
// </svg>
|
||||
// `;
|
||||
// return svg;
|
||||
// }
|
||||
|
||||
|
||||
5
packages/core/src/lib/engine.ts
Normal file
5
packages/core/src/lib/engine.ts
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
export class Engine {
|
||||
constructor() {
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -1,4 +1,3 @@
|
|||
export * from './draw/index';
|
||||
export * from './calculate';
|
||||
export * from './check';
|
||||
export * from './config';
|
||||
|
|
@ -7,11 +6,8 @@ export * from './diff';
|
|||
export * from './element';
|
||||
export * from './helper';
|
||||
export * from './is';
|
||||
export * from './loader-event';
|
||||
export * from './loader';
|
||||
export * from './mapper';
|
||||
export * from './parse';
|
||||
export * from './renderer';
|
||||
export * from './temp';
|
||||
export * from './transform';
|
||||
export * from './value';
|
||||
|
|
|
|||
|
|
@ -1,83 +0,0 @@
|
|||
|
||||
|
||||
export type TypeLoadData = {
|
||||
[uuid: string]: {
|
||||
type: 'image' | 'svg' | 'html',
|
||||
status: 'null' | 'loaded' | 'fail',
|
||||
content: null | HTMLImageElement | HTMLCanvasElement,
|
||||
elemW: number;
|
||||
elemH: number;
|
||||
source: string,
|
||||
error?: any,
|
||||
}
|
||||
}
|
||||
|
||||
export type TypeLoaderEventArgMap = {
|
||||
'complete': undefined;
|
||||
'load': TypeLoadData[string];
|
||||
'error': TypeLoadData[string];
|
||||
}
|
||||
|
||||
export interface TypeLoaderEvent {
|
||||
on<T extends keyof TypeLoaderEventArgMap >(key: T, callback: (p: TypeLoaderEventArgMap[T]) => void): void
|
||||
off<T extends keyof TypeLoaderEventArgMap >(key: T, callback: (p: TypeLoaderEventArgMap[T]) => void): void
|
||||
trigger<T extends keyof TypeLoaderEventArgMap >(key: T, p: TypeLoaderEventArgMap[T]): void
|
||||
}
|
||||
|
||||
|
||||
export class LoaderEvent implements TypeLoaderEvent {
|
||||
|
||||
private _listeners: Map<string, ((p: any) => void)[]>;
|
||||
|
||||
constructor() {
|
||||
this._listeners = new Map();
|
||||
}
|
||||
|
||||
on<T extends keyof TypeLoaderEventArgMap >(eventKey: T, callback: (p: TypeLoaderEventArgMap[T]) => void) {
|
||||
if (this._listeners.has(eventKey)) {
|
||||
const callbacks = this._listeners.get(eventKey);
|
||||
callbacks?.push(callback);
|
||||
this._listeners.set(eventKey, callbacks || []);
|
||||
} else {
|
||||
this._listeners.set(eventKey, [callback]);
|
||||
}
|
||||
}
|
||||
|
||||
off<T extends keyof TypeLoaderEventArgMap >(eventKey: T, callback: (p: TypeLoaderEventArgMap[T]) => void) {
|
||||
if (this._listeners.has(eventKey)) {
|
||||
const callbacks = this._listeners.get(eventKey);
|
||||
if (Array.isArray(callbacks)) {
|
||||
for (let i = 0; i < callbacks?.length; i++) {
|
||||
if (callbacks[i] === callback) {
|
||||
callbacks.splice(i, 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
this._listeners.set(eventKey, callbacks || []);
|
||||
}
|
||||
}
|
||||
|
||||
trigger<T extends keyof TypeLoaderEventArgMap >(eventKey: T, arg: TypeLoaderEventArgMap[T]) {
|
||||
const callbacks = this._listeners.get(eventKey);
|
||||
if (Array.isArray(callbacks)) {
|
||||
callbacks.forEach((cb) => {
|
||||
cb(arg);
|
||||
});
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
has<T extends keyof TypeLoaderEventArgMap> (name: string) {
|
||||
if (this._listeners.has(name)) {
|
||||
const list: ((p: TypeLoaderEventArgMap[T]) => void)[] | undefined = this._listeners.get(name);
|
||||
if (Array.isArray(list) && list.length > 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,323 +0,0 @@
|
|||
import { TypeData, TypeElement } from '@idraw/types';
|
||||
import Board from '@idraw/board';
|
||||
import util from '@idraw/util';
|
||||
import { LoaderEvent, TypeLoadData, TypeLoaderEventArgMap } from './loader-event';
|
||||
import { filterScript } from './../util/filter';
|
||||
|
||||
const { loadImage, loadSVG, loadHTML } = util.loader;
|
||||
|
||||
type Options = {
|
||||
board: Board;
|
||||
maxParallelNum: number
|
||||
}
|
||||
|
||||
enum LoaderStatus {
|
||||
FREE = 'free',
|
||||
LOADING = 'loading',
|
||||
COMPLETE = 'complete',
|
||||
}
|
||||
|
||||
export default class Loader {
|
||||
|
||||
private _opts: Options;
|
||||
private _event: LoaderEvent;
|
||||
// private _patternMap: {[uuid: string]: CanvasPattern} = {}
|
||||
private _currentLoadData: TypeLoadData = {};
|
||||
private _currentUUIDQueue: string[] = [];
|
||||
private _storageLoadData: TypeLoadData = {};
|
||||
private _status: LoaderStatus = LoaderStatus.FREE;
|
||||
|
||||
private _waitingLoadQueue: Array<{
|
||||
uuidQueue: string[],
|
||||
loadData: TypeLoadData,
|
||||
}> = [];
|
||||
|
||||
constructor(opts: Options) {
|
||||
this._opts = opts;
|
||||
this._event = new LoaderEvent();
|
||||
this._waitingLoadQueue = [];
|
||||
}
|
||||
|
||||
load(data: TypeData, changeResourceUUIDs: string[]): void {
|
||||
const [uuidQueue, loadData] = this._resetLoadData(data, changeResourceUUIDs);
|
||||
if (this._status === LoaderStatus.FREE || this._status === LoaderStatus.COMPLETE) {
|
||||
this._currentUUIDQueue = uuidQueue;
|
||||
this._currentLoadData = loadData;
|
||||
this._loadTask();
|
||||
} else if (this._status === LoaderStatus.LOADING && uuidQueue.length > 0) {
|
||||
this._waitingLoadQueue.push({
|
||||
uuidQueue,
|
||||
loadData,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
on<T extends keyof TypeLoaderEventArgMap>(
|
||||
name: T,
|
||||
callback: (arg: TypeLoaderEventArgMap[T]
|
||||
) => void) {
|
||||
this._event.on(name, callback);
|
||||
}
|
||||
|
||||
off<T extends keyof TypeLoaderEventArgMap>(
|
||||
name: T,
|
||||
callback: (arg: TypeLoaderEventArgMap[T]
|
||||
) => void) {
|
||||
this._event.off(name, callback);
|
||||
}
|
||||
|
||||
isComplete() {
|
||||
return this._status === LoaderStatus.COMPLETE;
|
||||
}
|
||||
|
||||
getContent(uuid: string): null | HTMLImageElement | HTMLCanvasElement {
|
||||
if (this._storageLoadData[uuid]?.status === 'loaded') {
|
||||
return this._storageLoadData[uuid].content;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// getPattern(
|
||||
// elem: TypeElement<keyof TypeElemDesc>,
|
||||
// opts?: {
|
||||
// forceUpdate: boolean
|
||||
// }
|
||||
// ): null | CanvasPattern {
|
||||
// if (this._patternMap[elem.uuid] ) {
|
||||
// if (!(opts && opts.forceUpdate === true)) {
|
||||
// return this._patternMap[elem.uuid];
|
||||
// }
|
||||
// }
|
||||
// const item = this._currentLoadData[elem.uuid];
|
||||
// if (item?.status === 'loaded') {
|
||||
// const board = this._opts.board;
|
||||
// const tempCanvas = board.createCanvas();
|
||||
// const tempCtx = board.createContext(tempCanvas);
|
||||
// const image = this.getContent(elem.uuid);
|
||||
// tempCtx.drawImage(image, elem.x, elem.y, elem.w, elem.h);
|
||||
|
||||
// const canvas = board.createCanvas();
|
||||
// const ctx = board.createContext(canvas);
|
||||
// const pattern = ctx.createPattern(tempCanvas, 'no-repeat');
|
||||
// if (pattern) this._patternMap[elem.uuid] = pattern;
|
||||
// return pattern;
|
||||
// }
|
||||
// return null;
|
||||
// }
|
||||
|
||||
private _resetLoadData(data: TypeData, changeResourceUUIDs: string[]): [string[], TypeLoadData] {
|
||||
const loadData: TypeLoadData = {};
|
||||
const uuidQueue: string[] = [];
|
||||
|
||||
const storageLoadData = this._storageLoadData;
|
||||
|
||||
// add new load-data
|
||||
for (let i = data.elements.length - 1; i >= 0; i --) {
|
||||
const elem = data.elements[i] as TypeElement<'image' | 'svg' | 'html'>;
|
||||
if (['image', 'svg', 'html', ].includes(elem.type)) {
|
||||
if (!storageLoadData[elem.uuid]) {
|
||||
loadData[elem.uuid] = this._createEmptyLoadItem(elem);
|
||||
uuidQueue.push(elem.uuid);
|
||||
} else {
|
||||
if (changeResourceUUIDs.includes(elem.uuid)) {
|
||||
loadData[elem.uuid] = this._createEmptyLoadItem(elem);
|
||||
uuidQueue.push(elem.uuid);
|
||||
}
|
||||
// if (elem.type === 'image') {
|
||||
// const _ele = elem as TypeElement<'image'>;
|
||||
// if (_ele.desc.src !== storageLoadData[elem.uuid].source) {
|
||||
// loadData[elem.uuid] = this._createEmptyLoadItem(elem);
|
||||
// uuidQueue.push(elem.uuid);
|
||||
// }
|
||||
// } else if (elem.type === 'svg') {
|
||||
// const _ele = elem as TypeElement<'svg'>;
|
||||
// if (_ele.desc.svg !== storageLoadData[elem.uuid].source) {
|
||||
// loadData[elem.uuid] = this._createEmptyLoadItem(elem);
|
||||
// uuidQueue.push(elem.uuid);
|
||||
// }
|
||||
// } else if (elem.type === 'html') {
|
||||
// const _ele = elem as TypeElement<'html'>;
|
||||
// if (filterScript(_ele.desc.html) !== storageLoadData[elem.uuid].source) {
|
||||
// loadData[elem.uuid] = this._createEmptyLoadItem(elem);
|
||||
// uuidQueue.push(elem.uuid);
|
||||
// }
|
||||
// }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// // clear unuse load-data
|
||||
// const uuids = Object.keys(currentLoadData);
|
||||
// data.elements.forEach((elem) => {
|
||||
// if (uuids.includes(elem.uuid) !== true) {
|
||||
// delete loadData[elem.uuid];
|
||||
// }
|
||||
// });
|
||||
|
||||
return [uuidQueue, loadData];
|
||||
}
|
||||
|
||||
private _createEmptyLoadItem(elem: TypeElement<'image' | 'svg' | 'html'>): TypeLoadData[string] {
|
||||
let source = '';
|
||||
|
||||
const type: TypeLoadData[string]['type'] = elem.type as TypeLoadData[string]['type'];
|
||||
let elemW: number = elem.w;
|
||||
let elemH: number = elem.h;
|
||||
if (elem.type === 'image') {
|
||||
const _elem = elem as TypeElement<'image'>;
|
||||
source = _elem.desc.src || '';
|
||||
} else if (elem.type === 'svg') {
|
||||
const _elem = elem as TypeElement<'svg'>;
|
||||
source = _elem.desc.svg || '';
|
||||
} else if (elem.type === 'html') {
|
||||
const _elem = elem as TypeElement<'html'>;
|
||||
source = filterScript(_elem.desc.html || '');
|
||||
elemW = _elem.desc.width || elem.w;
|
||||
elemH = _elem.desc.height || elem.h;
|
||||
}
|
||||
return {
|
||||
type: type,
|
||||
status: 'null',
|
||||
content: null,
|
||||
source,
|
||||
elemW,
|
||||
elemH,
|
||||
};
|
||||
}
|
||||
|
||||
private _loadTask() {
|
||||
if (this._status === LoaderStatus.LOADING) {
|
||||
return;
|
||||
}
|
||||
this._status = LoaderStatus.LOADING;
|
||||
|
||||
if (this._currentUUIDQueue.length === 0) {
|
||||
if (this._waitingLoadQueue.length === 0) {
|
||||
this._status = LoaderStatus.COMPLETE;
|
||||
this._event.trigger('complete', undefined);
|
||||
return;
|
||||
} else {
|
||||
const waitingItem = this._waitingLoadQueue.shift();
|
||||
if (waitingItem) {
|
||||
const { uuidQueue, loadData } = waitingItem;
|
||||
this._currentLoadData = loadData;
|
||||
this._currentUUIDQueue = uuidQueue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const { maxParallelNum } = this._opts;
|
||||
const uuids = this._currentUUIDQueue.splice(0, maxParallelNum);
|
||||
const uuidMap: {[uuid: string]: number} = {};
|
||||
|
||||
uuids.forEach((url, i) => {
|
||||
uuidMap[url] = i;
|
||||
});
|
||||
const loadUUIDList: string[] = [];
|
||||
const _loadAction = () => {
|
||||
|
||||
if (loadUUIDList.length >= maxParallelNum) {
|
||||
return false;
|
||||
}
|
||||
if (uuids.length === 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
for (let i = loadUUIDList.length; i < maxParallelNum; i++) {
|
||||
const uuid = uuids.shift();
|
||||
if (uuid === undefined) {
|
||||
break;
|
||||
}
|
||||
loadUUIDList.push(uuid);
|
||||
|
||||
this._loadElementSource(this._currentLoadData[uuid]).then((image) => {
|
||||
loadUUIDList.splice(loadUUIDList.indexOf(uuid), 1);
|
||||
const status = _loadAction();
|
||||
|
||||
this._storageLoadData[uuid] = {
|
||||
type: this._currentLoadData[uuid].type,
|
||||
status: 'loaded',
|
||||
content: image,
|
||||
source: this._currentLoadData[uuid].source,
|
||||
elemW: this._currentLoadData[uuid].elemW,
|
||||
elemH: this._currentLoadData[uuid].elemH,
|
||||
};
|
||||
|
||||
if (loadUUIDList.length === 0 && uuids.length === 0 && status === true) {
|
||||
this._status = LoaderStatus.FREE;
|
||||
this._loadTask();
|
||||
}
|
||||
this._event.trigger('load', {
|
||||
type: this._storageLoadData[uuid].type,
|
||||
status: this._storageLoadData[uuid].status,
|
||||
content: this._storageLoadData[uuid].content,
|
||||
source: this._storageLoadData[uuid].source,
|
||||
elemW: this._storageLoadData[uuid].elemW,
|
||||
elemH: this._storageLoadData[uuid].elemH,
|
||||
});
|
||||
}).catch((err) => {
|
||||
console.warn(err);
|
||||
|
||||
loadUUIDList.splice(loadUUIDList.indexOf(uuid), 1);
|
||||
const status = _loadAction();
|
||||
|
||||
if (this._currentLoadData[uuid]) {
|
||||
this._storageLoadData[uuid] = {
|
||||
type: this._currentLoadData[uuid]?.type,
|
||||
status: 'fail',
|
||||
content: null,
|
||||
error: err,
|
||||
source: this._currentLoadData[uuid]?.source,
|
||||
elemW: this._currentLoadData[uuid]?.elemW,
|
||||
elemH: this._currentLoadData[uuid]?.elemH,
|
||||
};
|
||||
}
|
||||
|
||||
if (loadUUIDList.length === 0 && uuids.length === 0 && status === true) {
|
||||
this._status = LoaderStatus.FREE;
|
||||
this._loadTask();
|
||||
}
|
||||
|
||||
if (this._currentLoadData[uuid]) {
|
||||
this._event.trigger('error', {
|
||||
type: this._storageLoadData[uuid]?.type,
|
||||
status: this._storageLoadData[uuid]?.status,
|
||||
content: this._storageLoadData[uuid]?.content,
|
||||
source: this._storageLoadData[uuid]?.source,
|
||||
elemW: this._storageLoadData[uuid]?.elemW,
|
||||
elemH: this._storageLoadData[uuid]?.elemH,
|
||||
});
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
}
|
||||
return false;
|
||||
};
|
||||
_loadAction();
|
||||
}
|
||||
|
||||
private async _loadElementSource(
|
||||
params: TypeLoadData[string]
|
||||
): Promise<HTMLImageElement> {
|
||||
if (params && params.type === 'image') {
|
||||
const image = await loadImage(params.source);
|
||||
return image;
|
||||
} else if (params && params.type === 'svg') {
|
||||
const image = await loadSVG(
|
||||
params.source
|
||||
);
|
||||
return image;
|
||||
} else if (params && params.type === 'html') {
|
||||
const image = await loadHTML(
|
||||
params.source, {
|
||||
width: params.elemW, height: params.elemH
|
||||
}
|
||||
);
|
||||
return image;
|
||||
}
|
||||
throw Error('Element\'s source is not support!');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -1,69 +0,0 @@
|
|||
|
||||
export type TypeRendererEventArgMap = {
|
||||
'drawFrame': void;
|
||||
'drawFrameComplete': void;
|
||||
}
|
||||
|
||||
export interface TypeRendererEvent {
|
||||
on<T extends keyof TypeRendererEventArgMap >(key: T, callback: (p: TypeRendererEventArgMap[T]) => void): void
|
||||
off<T extends keyof TypeRendererEventArgMap >(key: T, callback: (p: TypeRendererEventArgMap[T]) => void): void
|
||||
trigger<T extends keyof TypeRendererEventArgMap >(key: T, p: TypeRendererEventArgMap[T]): void
|
||||
}
|
||||
|
||||
|
||||
export class RendererEvent implements TypeRendererEvent {
|
||||
|
||||
private _listeners: Map<string, ((p: any) => void)[]>;
|
||||
|
||||
constructor() {
|
||||
this._listeners = new Map();
|
||||
}
|
||||
|
||||
on<T extends keyof TypeRendererEventArgMap >(eventKey: T, callback: (p: TypeRendererEventArgMap[T]) => void) {
|
||||
if (this._listeners.has(eventKey)) {
|
||||
const callbacks = this._listeners.get(eventKey);
|
||||
callbacks?.push(callback);
|
||||
this._listeners.set(eventKey, callbacks || []);
|
||||
} else {
|
||||
this._listeners.set(eventKey, [callback]);
|
||||
}
|
||||
}
|
||||
|
||||
off<T extends keyof TypeRendererEventArgMap >(eventKey: T, callback: (p: TypeRendererEventArgMap[T]) => void) {
|
||||
if (this._listeners.has(eventKey)) {
|
||||
const callbacks = this._listeners.get(eventKey);
|
||||
if (Array.isArray(callbacks)) {
|
||||
for (let i = 0; i < callbacks?.length; i++) {
|
||||
if (callbacks[i] === callback) {
|
||||
callbacks.splice(i, 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
this._listeners.set(eventKey, callbacks || []);
|
||||
}
|
||||
}
|
||||
|
||||
trigger<T extends keyof TypeRendererEventArgMap >(eventKey: T, arg: TypeRendererEventArgMap[T]) {
|
||||
const callbacks = this._listeners.get(eventKey);
|
||||
if (Array.isArray(callbacks)) {
|
||||
callbacks.forEach((cb) => {
|
||||
cb(arg);
|
||||
});
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
has<T extends keyof TypeRendererEventArgMap> (name: string) {
|
||||
if (this._listeners.has(name)) {
|
||||
const list: ((p: TypeRendererEventArgMap[T]) => void)[] | undefined = this._listeners.get(name);
|
||||
if (Array.isArray(list) && list.length > 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,132 +0,0 @@
|
|||
import { TypeData, TypeHelperConfig, } from '@idraw/types';
|
||||
import util from '@idraw/util';
|
||||
import Board from '@idraw/board';
|
||||
import { drawContext } from './draw';
|
||||
import Loader from './loader';
|
||||
import { RendererEvent } from './renderer-event';
|
||||
|
||||
const { requestAnimationFrame } = window;
|
||||
const { deepClone } = util.data;
|
||||
|
||||
type QueueItem = { data: TypeData, helper: TypeHelperConfig };
|
||||
enum DrawStatus {
|
||||
NULL = 'null',
|
||||
FREE = 'free',
|
||||
DRAWING = 'drawing',
|
||||
FREEZE = 'freeze',
|
||||
// STOP = 'stop',
|
||||
}
|
||||
|
||||
export class Renderer extends RendererEvent {
|
||||
|
||||
private _queue: QueueItem[] = [];
|
||||
private _board: Board;
|
||||
private _status: DrawStatus = DrawStatus.NULL;
|
||||
private _loader: Loader;
|
||||
|
||||
constructor(board: Board) {
|
||||
super();
|
||||
this._board = board;
|
||||
this._loader = new Loader({
|
||||
board: board,
|
||||
maxParallelNum: 6
|
||||
});
|
||||
this._loader.on('load', (res) => {
|
||||
this._drawFrame();
|
||||
// console.log('Load: ', res);
|
||||
});
|
||||
this._loader.on('error', (res) => {
|
||||
console.log('Loader Error: ', res);
|
||||
});
|
||||
this._loader.on('complete', (res) => {
|
||||
// console.log('complete: ', res);
|
||||
});
|
||||
}
|
||||
|
||||
freeze() {
|
||||
this._status = DrawStatus.FREEZE;
|
||||
}
|
||||
|
||||
thaw() {
|
||||
this._status = DrawStatus.FREE;
|
||||
}
|
||||
|
||||
// stop() {
|
||||
// this._status = DrawStatus.STOP;
|
||||
// }
|
||||
|
||||
// restart() {
|
||||
// this._status = DrawStatus.NULL;
|
||||
// }
|
||||
|
||||
render(data: TypeData, helper: TypeHelperConfig, changeResourceUUIDs: string[]): void {
|
||||
// if ([DrawStatus.STOP, DrawStatus.FREEZE].includes(this._status)) {
|
||||
// return;
|
||||
// }
|
||||
if ([DrawStatus.FREEZE].includes(this._status)) {
|
||||
return;
|
||||
}
|
||||
const _data: QueueItem = deepClone({ data, helper }) as QueueItem;
|
||||
this._queue.push(_data);
|
||||
if (this._status !== DrawStatus.DRAWING) {
|
||||
this._status = DrawStatus.DRAWING;
|
||||
this._drawFrame();
|
||||
}
|
||||
this._loader.load(data, changeResourceUUIDs);
|
||||
}
|
||||
|
||||
private _drawFrame() {
|
||||
if (this._status === DrawStatus.FREEZE) {
|
||||
return;
|
||||
}
|
||||
requestAnimationFrame(() => {
|
||||
if (this._status === DrawStatus.FREEZE) {
|
||||
return;
|
||||
}
|
||||
const ctx = this._board.getContext();
|
||||
|
||||
let item: QueueItem | undefined = this._queue[0];
|
||||
let isLastFrame = false;
|
||||
if (this._queue.length > 1) {
|
||||
item = this._queue.shift();
|
||||
} else {
|
||||
isLastFrame = true;
|
||||
}
|
||||
if (this._loader.isComplete() !== true) {
|
||||
this._drawFrame();
|
||||
if (item) {
|
||||
drawContext(ctx, item.data, item.helper, this._loader);
|
||||
this._board.draw();
|
||||
}
|
||||
} else if (item) {
|
||||
drawContext(ctx, item.data, item.helper, this._loader);
|
||||
this._board.draw();
|
||||
this._retainQueueOneItem();
|
||||
if (!isLastFrame) {
|
||||
this._drawFrame();
|
||||
} else {
|
||||
this._status = DrawStatus.FREE;
|
||||
}
|
||||
} else {
|
||||
this._status = DrawStatus.FREE;
|
||||
}
|
||||
this.trigger('drawFrame', undefined)
|
||||
|
||||
if (this._loader.isComplete() === true && this._queue.length === 1 && this._status === DrawStatus.FREE) {
|
||||
this.trigger('drawFrameComplete', undefined);
|
||||
this.freeze();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private _retainQueueOneItem() {
|
||||
if (this._queue.length <= 1) {
|
||||
return;
|
||||
}
|
||||
const lastOne = deepClone(this._queue[this._queue.length - 1]);
|
||||
this._queue = [lastOne];
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -30,7 +30,6 @@ export class HelperPlugin implements Required<InterfaceHelperPlugin> {
|
|||
|
||||
}
|
||||
|
||||
|
||||
onMoveStart(detail: TypeHelperPluginEventDetail): void | TypeHelperPluginEventResult {
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
export * from './draw/index';
|
||||
export * from './diff';
|
||||
export * from './loader-event';
|
||||
export * from './loader';
|
||||
|
|
|
|||
Loading…
Reference in a new issue