diff --git a/.prettierrc.json b/.prettierrc.json index d0291bc..bbabebc 100644 --- a/.prettierrc.json +++ b/.prettierrc.json @@ -1,5 +1,3 @@ - - { "tabWidth": 2, "useTabs": false, @@ -7,5 +5,6 @@ "singleQuote": true, "semi": true, "trailingComma": "none", - "bracketSpacing": true -} \ No newline at end of file + "bracketSpacing": true, + "printWidth": 160 +} diff --git a/packages/types/src/lib/element.ts b/packages/types/src/lib/element.ts index 986b5c9..f5fa5e6 100644 --- a/packages/types/src/lib/element.ts +++ b/packages/types/src/lib/element.ts @@ -11,7 +11,25 @@ interface ElementRectDesc { borderRadius?: number; } -interface ElementEllipseDesc { +interface ElemenTextDesc { + text: string; + color: string; + fontSize: number; + lineHeight?: number; + fontWeight?: 'bold' | ''; + fontFamily?: string; + textAlign?: 'center' | 'left' | 'right'; + verticalAlign?: 'middle' | 'top' | 'bottom'; + bgColor?: string; + strokeColor?: string; + strokeWidth?: number; + textShadowColor?: string; + textShadowOffsetX?: number; + textShadowOffsetY?: number; + textShadowBlur?: number; +} + +interface ElementCircleDesc { radius: number; bgColor?: string; borderWidth?: number; @@ -19,7 +37,10 @@ interface ElementEllipseDesc { } interface ElementBaseDesc { - // TODO + shadowColor?: string; + shadowOffsetX?: number; + shadowOffsetY?: number; + shadowBlur?: number; } interface ElementHTMLDesc extends ElementBaseDesc { @@ -38,16 +59,14 @@ interface ElementSVGDesc extends ElementBaseDesc { interface ElementDescMap { rect: ElementRectDesc; - ellipse: ElementEllipseDesc; - polygon: ElementBaseDesc; // TODO - paint: ElementBaseDesc; // TODO - pen: ElementBaseDesc; // TODO + circle: ElementCircleDesc; + text: ElemenTextDesc; image: ElementImageDesc; html: ElementHTMLDesc; svg: ElementSVGDesc; } -export type ElementType = 'rect' | 'ellipse' | 'polygon' | 'paint' | 'pen' | 'image' | 'html' | 'svg'; // TODO +export type ElementType = 'text' | 'rect' | 'circle' | 'image' | 'svg' | 'html'; export interface ElementOperation { lock?: boolean; diff --git a/packages/util/__tests__/lib/loader.test.ts b/packages/util/__tests__/lib/loader.test.ts index 472ee89..e52fdac 100644 --- a/packages/util/__tests__/lib/loader.test.ts +++ b/packages/util/__tests__/lib/loader.test.ts @@ -1,5 +1,5 @@ import '../../../../__tests__/polyfill/image'; -import { loadHTML, loadImage, loadSVG } from '../../src/lib/loader'; +import { loadHTML, loadImage, loadSVG } from '../../src/lib/load'; import { parseHTMLToDataURL, parseSVGToDataURL } from '../../src/lib/parser'; describe('@idraw/util: lib/loader', () => { diff --git a/packages/util/src/index.ts b/packages/util/src/index.ts index d4442fa..db2dba0 100644 --- a/packages/util/src/index.ts +++ b/packages/util/src/index.ts @@ -1,48 +1,13 @@ -import { delay, compose, throttle } from './lib/time'; -import { downloadImageFromCanvas } from './lib/file'; -import { toColorHexStr, toColorHexNum, isColorStr } from './lib/color'; -import { createUUID } from './lib/uuid'; -import { deepClone } from './lib/data'; -import istype from './lib/istype'; -import { loadImage, loadSVG, loadHTML } from './lib/loader'; -import Context from './lib/context'; -import is from './lib/is'; -import check from './lib/check'; - -export { - is, - check, - delay, - compose, - throttle, - loadImage, - loadSVG, - loadHTML, - downloadImageFromCanvas, - toColorHexStr, - toColorHexNum, - isColorStr, - createUUID, - istype, - deepClone, - Context -}; - -export default { - is, - check, - delay, - compose, - throttle, - loadImage, - loadSVG, - loadHTML, - downloadImageFromCanvas, - toColorHexStr, - toColorHexNum, - isColorStr, - createUUID, - istype, - deepClone, - Context -}; +export { delay, compose, throttle } from './lib/time'; +export { downloadImageFromCanvas } from './lib/file'; +export { toColorHexStr, toColorHexNum, isColorStr } from './lib/color'; +export { createUUID } from './lib/uuid'; +export { deepClone } from './lib/data'; +export { istype } from './lib/istype'; +export { loadImage, loadSVG, loadHTML } from './lib/load'; +export { is } from './lib/is'; +export { check } from './lib/check'; +export { createBoardContexts, createContext2D, createOffscreenContext2D } from './lib/canvas'; +export { EventEmitter } from './lib/event'; +export { calcDistance, calcSpeed, equalPoint, equalTouchPoint, vaildPoint, vaildTouchPoint } from './lib/point'; +export { Store } from './lib/store'; diff --git a/packages/util/src/lib/canvas.ts b/packages/util/src/lib/canvas.ts new file mode 100644 index 0000000..10acabb --- /dev/null +++ b/packages/util/src/lib/canvas.ts @@ -0,0 +1,46 @@ +import type { ViewContent } from '@idraw/types'; + +export function createContext2D(opts: { + width: number; + height: number; +}): CanvasRenderingContext2D { + const { width, height } = opts; + const canvas: HTMLCanvasElement = document.createElement('canvas'); + canvas.width = width; + canvas.height = height; + const context: CanvasRenderingContext2D = canvas.getContext( + '2d' + ) as CanvasRenderingContext2D; + return context; +} + +export function createOffscreenContext2D(opts: { + width: number; + height: number; +}) { + const { width, height } = opts; + const offCanvas = new OffscreenCanvas(width, height); + const offRenderCtx = offCanvas.getContext('2d') as OffscreenRenderingContext; + const offCtx: CanvasRenderingContext2D | OffscreenRenderingContext = + offRenderCtx.canvas.getContext('2d') as + | CanvasRenderingContext2D + | OffscreenRenderingContext; + return offCtx; +} + +export function createBoardContexts( + ctx: CanvasRenderingContext2D +): ViewContent { + const opts = { + width: ctx.canvas.width, + height: ctx.canvas.height + }; + const viewContext = createContext2D(opts); + const helperContext = createContext2D(opts); + const content: ViewContent = { + viewContext, + helperContext, + boardContext: ctx + }; + return content; +} diff --git a/packages/util/src/lib/check.ts b/packages/util/src/lib/check.ts index 939d66e..a94461d 100644 --- a/packages/util/src/lib/check.ts +++ b/packages/util/src/lib/check.ts @@ -1,5 +1,5 @@ // import { DataElementAttrs } from '@idraw/types'; -import is from './is'; +import { is } from './is'; function attrs(attrs: any): boolean { const { x, y, w, h, angle } = attrs; @@ -125,7 +125,7 @@ function textDesc(desc: any): boolean { return true; } -const check = { +export const check = { attrs, textDesc, rectDesc, @@ -134,5 +134,3 @@ const check = { svgDesc, htmlDesc }; - -export default check; diff --git a/packages/util/src/lib/color.ts b/packages/util/src/lib/color.ts index baa61b1..eb2dee7 100644 --- a/packages/util/src/lib/color.ts +++ b/packages/util/src/lib/color.ts @@ -7,5 +7,8 @@ export function toColorHexStr(color: number): string { } export function isColorStr(color?: string): boolean { - return typeof color === 'string' && /^\#([0-9a-f]{3}|[0-9a-f]{6}|[0-9a-f]{8})$/i.test(color); -} \ No newline at end of file + return ( + typeof color === 'string' && + /^\#([0-9a-f]{3}|[0-9a-f]{6}|[0-9a-f]{8})$/i.test(color) + ); +} diff --git a/packages/util/src/lib/context.ts b/packages/util/src/lib/context.ts deleted file mode 100644 index 570a178..0000000 --- a/packages/util/src/lib/context.ts +++ /dev/null @@ -1,366 +0,0 @@ -import { IDrawContext, BoardSizeOptions } from '@idraw/types'; - -type Options = { - width: number; - height: number; - contextWidth: number; - contextHeight: number; - devicePixelRatio: number; -}; - -type Transform = { - scale?: number; - scrollX?: number; - scrollY?: number; -}; - -type PrivateTransform = { - scale: number; - scrollX: number; - scrollY: number; -}; - -class Context implements IDrawContext { - private _opts: Options; - private _ctx: CanvasRenderingContext2D; - private _transform: PrivateTransform; - - // private _scale: number; - // private _scrollX: number; - // private _scrollY: number; - - constructor(ctx: CanvasRenderingContext2D, opts: Options) { - this._opts = opts; - this._ctx = ctx; - this._transform = { - scale: 1, - scrollX: 0, - scrollY: 0 - }; - } - getContext(): CanvasRenderingContext2D { - return this._ctx; - } - - resetSize(opts: BoardSizeOptions) { - this._opts = { ...this._opts, ...opts }; - } - - calcDeviceNum(num: number): number { - return num * this._opts.devicePixelRatio; - } - - calcScreenNum(num: number): number { - return num / this._opts.devicePixelRatio; - } - - getSize() { - return { - width: this._opts.width, - height: this._opts.height, - contextWidth: this._opts.contextWidth, - contextHeight: this._opts.contextHeight, - devicePixelRatio: this._opts.devicePixelRatio - }; - } - - setTransform(config: Transform) { - this._transform = { ...this._transform, ...config }; - } - - getTransform() { - return { - scale: this._transform.scale, - scrollX: this._transform.scrollX, - scrollY: this._transform.scrollY - }; - } - - setFillStyle(color: string | CanvasPattern | CanvasGradient) { - this._ctx.fillStyle = color; - } - - fill(fillRule?: CanvasFillRule | undefined) { - return this._ctx.fill(fillRule || 'nonzero'); - } - - arc( - x: number, - y: number, - radius: number, - startAngle: number, - endAngle: number, - anticlockwise?: boolean | undefined - ): void { - return this._ctx.arc( - this._doSize(x), - this._doSize(y), - this._doSize(radius), - startAngle, - endAngle, - anticlockwise - ); - } - - rect(x: number, y: number, w: number, h: number) { - return this._ctx.rect( - this._doSize(x), - this._doSize(y), - this._doSize(w), - this._doSize(h) - ); - } - - fillRect(x: number, y: number, w: number, h: number) { - return this._ctx.fillRect( - this._doSize(x), - this._doSize(y), - this._doSize(w), - this._doSize(h) - ); - } - - clearRect(x: number, y: number, w: number, h: number) { - return this._ctx.clearRect( - this._doSize(x), - this._doSize(y), - this._doSize(w), - this._doSize(h) - ); - } - - beginPath() { - return this._ctx.beginPath(); - } - - closePath() { - return this._ctx.closePath(); - } - - lineTo(x: number, y: number) { - return this._ctx.lineTo(this._doSize(x), this._doSize(y)); - } - - moveTo(x: number, y: number) { - return this._ctx.moveTo(this._doSize(x), this._doSize(y)); - } - - arcTo(x1: number, y1: number, x2: number, y2: number, radius: number): void { - return this._ctx.arcTo( - this._doSize(x1), - this._doSize(y1), - this._doSize(x2), - this._doSize(y2), - this._doSize(radius) - ); - } - - setLineWidth(w: number) { - return (this._ctx.lineWidth = this._doSize(w)); - } - - setLineDash(nums: number[]) { - return this._ctx.setLineDash(nums.map((n) => this._doSize(n))); - } - - isPointInPath(x: number, y: number) { - return this._ctx.isPointInPath(this._doX(x), this._doY(y)); - } - - isPointInPathWithoutScroll(x: number, y: number) { - return this._ctx.isPointInPath(this._doSize(x), this._doSize(y)); - } - - setStrokeStyle(color: string) { - this._ctx.strokeStyle = color; - } - - stroke() { - return this._ctx.stroke(); - } - - translate(x: number, y: number) { - return this._ctx.translate(this._doSize(x), this._doSize(y)); - } - - rotate(angle: number) { - return this._ctx.rotate(angle); - } - - drawImage(...args: any[]) { - const image: CanvasImageSource = args[0]; - const sx: number = args[1]; - const sy: number = args[2]; - const sw: number = args[3]; - const sh: number = args[4]; - - const dx: number = args[args.length - 4]; - const dy: number = args[args.length - 3]; - const dw: number = args[args.length - 2]; - const dh: number = args[args.length - 1]; - - if (args.length === 9) { - return this._ctx.drawImage( - image, - this._doSize(sx), - this._doSize(sy), - this._doSize(sw), - this._doSize(sh), - this._doSize(dx), - this._doSize(dy), - this._doSize(dw), - this._doSize(dh) - ); - } else { - return this._ctx.drawImage( - image, - this._doSize(dx), - this._doSize(dy), - this._doSize(dw), - this._doSize(dh) - ); - } - } - - createPattern( - image: CanvasImageSource, - repetition: string | null - ): CanvasPattern | null { - return this._ctx.createPattern(image, repetition); - } - - measureText(text: string): TextMetrics { - return this._ctx.measureText(text); - } - - setTextAlign(align: CanvasTextAlign): void { - this._ctx.textAlign = align; - } - - fillText( - text: string, - x: number, - y: number, - maxWidth?: number | undefined - ): void { - if (maxWidth !== undefined) { - return this._ctx.fillText( - text, - this._doSize(x), - this._doSize(y), - this._doSize(maxWidth) - ); - } else { - return this._ctx.fillText(text, this._doSize(x), this._doSize(y)); - } - } - - strokeText( - text: string, - x: number, - y: number, - maxWidth?: number | undefined - ): void { - if (maxWidth !== undefined) { - return this._ctx.strokeText( - text, - this._doSize(x), - this._doSize(y), - this._doSize(maxWidth) - ); - } else { - return this._ctx.strokeText(text, this._doSize(x), this._doSize(y)); - } - } - - setFont(opts: { - fontSize: number; - fontFamily?: string; - fontWeight?: 'bold'; - }): void { - const strList: string[] = []; - if (opts.fontWeight === 'bold') { - strList.push(`${opts.fontWeight}`); - } - strList.push(`${this._doSize(opts.fontSize || 12)}px`); - strList.push(`${opts.fontFamily || 'sans-serif'}`); - this._ctx.font = `${strList.join(' ')}`; - // console.log('this._ctx.font =',this._ctx.font); - } - - setTextBaseline(baseline: CanvasTextBaseline): void { - this._ctx.textBaseline = baseline; - } - - setGlobalAlpha(alpha: number): void { - this._ctx.globalAlpha = alpha; - } - - save() { - this._ctx.save(); - } - - restore() { - this._ctx.restore(); - } - - scale(ratioX: number, ratioY: number) { - this._ctx.scale(ratioX, ratioY); - } - - setShadowColor(color: string): void { - this._ctx.shadowColor = color; - } - - setShadowOffsetX(offsetX: number): void { - this._ctx.shadowOffsetX = this._doSize(offsetX); - } - - setShadowOffsetY(offsetY: number): void { - this._ctx.shadowOffsetY = this._doSize(offsetY); - } - - setShadowBlur(blur: number): void { - this._ctx.shadowBlur = this._doSize(blur); - } - - ellipse( - x: number, - y: number, - radiusX: number, - radiusY: number, - rotation: number, - startAngle: number, - endAngle: number, - counterclockwise?: boolean | undefined - ) { - this._ctx.ellipse( - this._doSize(x), - this._doSize(y), - this._doSize(radiusX), - this._doSize(radiusY), - rotation, - startAngle, - endAngle, - counterclockwise - ); - } - - private _doSize(num: number) { - return this._opts.devicePixelRatio * num; - } - - private _doX(x: number) { - const { scale, scrollX } = this._transform; - const _x = (x - scrollX) / scale; - return this._doSize(_x); - } - - private _doY(y: number) { - const { scale, scrollY } = this._transform; - const _y = (y - scrollY) / scale; - return this._doSize(_y); - } -} - -export default Context; diff --git a/packages/util/src/lib/data.ts b/packages/util/src/lib/data.ts index 1442061..fa7fb36 100644 --- a/packages/util/src/lib/data.ts +++ b/packages/util/src/lib/data.ts @@ -1,8 +1,9 @@ - export function deepClone(target: any): any { function _clone(t: any) { const type = is(t); - if (['Null', 'Number', 'String', 'Boolean', 'Undefined'].indexOf(type) >= 0) { + if ( + ['Null', 'Number', 'String', 'Boolean', 'Undefined'].indexOf(type) >= 0 + ) { return t; } else if (type === 'Array') { const arr: any[] = []; @@ -11,7 +12,7 @@ export function deepClone(target: any): any { }); return arr; } else if (type === 'Object') { - const obj: {[key: string]: any} = {}; + const obj: { [key: string]: any } = {}; const keys = Object.keys(t); keys.forEach((key) => { obj[key] = _clone(t[key]); @@ -23,5 +24,8 @@ export function deepClone(target: any): any { } function is(data: any): string { - return Object.prototype.toString.call(data).replace(/[\]|\[]{1,1}/ig, '').split(' ')[1]; -} \ No newline at end of file + return Object.prototype.toString + .call(data) + .replace(/[\]|\[]{1,1}/gi, '') + .split(' ')[1]; +} diff --git a/packages/util/src/lib/event.ts b/packages/util/src/lib/event.ts new file mode 100644 index 0000000..0d88d59 --- /dev/null +++ b/packages/util/src/lib/event.ts @@ -0,0 +1,56 @@ +import type { UtilEventEmitter } from '@idraw/types'; + +export class EventEmitter> implements UtilEventEmitter { + private _listeners: Map void)[]>; + + constructor() { + this._listeners = new Map void)[]>(); + } + + on(eventKey: K, callback: (e: T[K]) => void) { + if (this._listeners.has(eventKey)) { + const callbacks: Array<(e: T[K]) => void> = this._listeners.get(eventKey) || []; + callbacks?.push(callback); + this._listeners.set(eventKey, callbacks); + } else { + this._listeners.set(eventKey, [callback]); + } + } + + off(eventKey: K, callback: (e: T[K]) => 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(eventKey: K, e: T[K]) { + const callbacks = this._listeners.get(eventKey); + if (Array.isArray(callbacks)) { + callbacks.forEach((cb) => { + cb(e); + }); + return true; + } else { + return false; + } + } + + has(name: K | string): boolean { + if (this._listeners.has(name)) { + const list: ((p: T[K]) => void)[] | undefined = this._listeners.get(name); + if (Array.isArray(list) && list.length > 0) { + return true; + } + } + return false; + } +} diff --git a/packages/util/src/lib/file.ts b/packages/util/src/lib/file.ts index b9d7069..3b21d68 100644 --- a/packages/util/src/lib/file.ts +++ b/packages/util/src/lib/file.ts @@ -1,9 +1,8 @@ - type ImageType = 'image/jpeg' | 'image/png'; -export function downloadImageFromCanvas ( - canvas: HTMLCanvasElement, - opts: { filename: string, type: ImageType } +export function downloadImageFromCanvas( + canvas: HTMLCanvasElement, + opts: { filename: string; type: ImageType } ): void { const { filename, type = 'image/jpeg' } = opts; const stream = canvas.toDataURL(type); @@ -13,4 +12,4 @@ export function downloadImageFromCanvas ( const downloadClickEvent = document.createEvent('MouseEvents'); downloadClickEvent.initEvent('click', true, false); downloadLink.dispatchEvent(downloadClickEvent); -} \ No newline at end of file +} diff --git a/packages/util/src/lib/is.ts b/packages/util/src/lib/is.ts index 1f4228a..0dd19c3 100644 --- a/packages/util/src/lib/is.ts +++ b/packages/util/src/lib/is.ts @@ -1,7 +1,7 @@ import { isColorStr } from './color'; function number(value: any) { - return (typeof value === 'number' && (value > 0 || value <= 0)); + return typeof value === 'number' && (value > 0 || value <= 0); } function x(value: any) { @@ -13,15 +13,15 @@ function y(value: any) { } function w(value: any) { - return (typeof value === 'number' && value >= 0); + return typeof value === 'number' && value >= 0; } function h(value: any) { - return (typeof value === 'number' && value >= 0); + return typeof value === 'number' && value >= 0; } function angle(value: any) { - return (typeof value === 'number' && value >= -360 && value <= 360); + return typeof value === 'number' && value >= -360 && value <= 360; } function borderWidth(value: any) { @@ -37,19 +37,26 @@ function color(value: any) { } function imageURL(value: any) { - return (typeof value === 'string' && /^(http:\/\/|https:\/\/|\.\/|\/)/.test(`${value}`)); + return ( + typeof value === 'string' && + /^(http:\/\/|https:\/\/|\.\/|\/)/.test(`${value}`) + ); } function imageBase64(value: any) { - return (typeof value === 'string' && /^(data:image\/)/.test(`${value}`)); + return typeof value === 'string' && /^(data:image\/)/.test(`${value}`); } function imageSrc(value: any) { - return (imageBase64(value) || imageURL(value)); + return imageBase64(value) || imageURL(value); } function svg(value: any) { - return (typeof value === 'string' && /^()/i.test(`${value}`.trim()) && /<\/[\s]{0,}svg>$/i.test(`${value}`.trim())); + return ( + typeof value === 'string' && + /^()/i.test(`${value}`.trim()) && + /<\/[\s]{0,}svg>$/i.test(`${value}`.trim()) + ); } function html(value: any) { @@ -93,13 +100,26 @@ function fontWeight(value: any) { return ['bold'].includes(value); } -const is = { - x, y, w, h, angle, number, - borderWidth, borderRadius, color, - imageSrc, imageURL, imageBase64, svg, html, - text, fontSize, lineHeight, textAlign, fontFamily, fontWeight, - strokeWidth, +export const is = { + x, + y, + w, + h, + angle, + number, + borderWidth, + borderRadius, + color, + imageSrc, + imageURL, + imageBase64, + svg, + html, + text, + fontSize, + lineHeight, + textAlign, + fontFamily, + fontWeight, + strokeWidth }; - - -export default is; diff --git a/packages/util/src/lib/istype.ts b/packages/util/src/lib/istype.ts index 9cf616e..3123697 100644 --- a/packages/util/src/lib/istype.ts +++ b/packages/util/src/lib/istype.ts @@ -1,50 +1,49 @@ -function parsePrototype (data: any): string { +function parsePrototype(data: any): string { const typeStr = Object.prototype.toString.call(data) || ''; - const result = typeStr.replace(/(\[object|\])/ig, '').trim(); + const result = typeStr.replace(/(\[object|\])/gi, '').trim(); return result; } -const istype = { - +export const istype = { type(data: any, lowerCase?: boolean): string { const result = parsePrototype(data); return lowerCase === true ? result.toLocaleLowerCase() : result; }, - array (data: any): boolean { + array(data: any): boolean { return parsePrototype(data) === 'Array'; }, - json (data: any): boolean { + json(data: any): boolean { return parsePrototype(data) === 'Object'; }, - function (data: any): boolean { + function(data: any): boolean { return parsePrototype(data) === 'Function'; }, - asyncFunction (data: any): boolean { + asyncFunction(data: any): boolean { return parsePrototype(data) === 'AsyncFunction'; }, - string (data: any): boolean { + string(data: any): boolean { return parsePrototype(data) === 'String'; }, - number (data: any): boolean { + number(data: any): boolean { return parsePrototype(data) === 'Number'; }, - undefined (data: any): boolean { + undefined(data: any): boolean { return parsePrototype(data) === 'Undefined'; }, - null (data: any): boolean { + null(data: any): boolean { return parsePrototype(data) === 'Null'; }, - promise (data: any): boolean { + promise(data: any): boolean { return parsePrototype(data) === 'Promise'; - }, + } // nodeList (data: any): boolean { // return parsePrototype(data) === 'NodeList'; @@ -53,7 +52,4 @@ const istype = { // imageData(data: any): boolean { // return parsePrototype(data) === 'ImageData'; // } - }; - -export default istype; \ No newline at end of file diff --git a/packages/util/src/lib/loader.ts b/packages/util/src/lib/load.ts similarity index 78% rename from packages/util/src/lib/loader.ts rename to packages/util/src/lib/load.ts index 740773b..fac7660 100644 --- a/packages/util/src/lib/loader.ts +++ b/packages/util/src/lib/load.ts @@ -3,10 +3,10 @@ const { Image } = window; export function loadImage(src: string): Promise { return new Promise((resolve, reject) => { - const img = new Image; + const img = new Image(); // img.setAttribute('crossOrigin', 'anonymous'); img.crossOrigin = 'anonymous'; - img.onload = function() { + img.onload = function () { resolve(img); }; img.onabort = reject; @@ -15,23 +15,22 @@ export function loadImage(src: string): Promise { }); } - export async function loadSVG(svg: string): Promise { const dataURL = await parseSVGToDataURL(svg); const image = await loadImage(dataURL); return image; } - function filterAmpersand(str: string): string { - return str.replace(/\&/ig, '&'); + return str.replace(/\&/gi, '&'); } -export async function loadHTML(html: string, opts: { width: number, height: number }): Promise { +export async function loadHTML( + html: string, + opts: { width: number; height: number } +): Promise { html = filterAmpersand(html); const dataURL = await parseHTMLToDataURL(html, opts); const image = await loadImage(dataURL); return image; } - - diff --git a/packages/util/src/lib/parser.ts b/packages/util/src/lib/parser.ts index 9e4a081..714854d 100644 --- a/packages/util/src/lib/parser.ts +++ b/packages/util/src/lib/parser.ts @@ -1,8 +1,14 @@ -export function parseHTMLToDataURL(html: string, opts: { width: number, height: number }): Promise { +export function parseHTMLToDataURL( + html: string, + opts: { width: number; height: number } +): Promise { const { width, height } = opts; return new Promise((resolve, reject) => { const _svg = ` - +
${html} @@ -10,31 +16,30 @@ export function parseHTMLToDataURL(html: string, opts: { width: number, height: `; - const blob = new Blob([_svg], { type: 'image/svg+xml;charset=utf-8'}); - const reader = new FileReader(); - reader.readAsDataURL(blob); - reader.onload = function (event: ProgressEvent) { - const base64: string = event?.target?.result as string; - resolve(base64) - }; - reader.onerror = function(err) { - reject(err); - }; - }); -} - - -export function parseSVGToDataURL(svg: string): Promise { - return new Promise((resolve, reject) => { - const _svg = svg; - const blob = new Blob([_svg], { type: 'image/svg+xml;charset=utf-8'}); + const blob = new Blob([_svg], { type: 'image/svg+xml;charset=utf-8' }); const reader = new FileReader(); reader.readAsDataURL(blob); reader.onload = function (event: ProgressEvent) { const base64: string = event?.target?.result as string; resolve(base64); }; - reader.onerror = function(err) { + reader.onerror = function (err) { + reject(err); + }; + }); +} + +export function parseSVGToDataURL(svg: string): Promise { + return new Promise((resolve, reject) => { + const _svg = svg; + const blob = new Blob([_svg], { type: 'image/svg+xml;charset=utf-8' }); + const reader = new FileReader(); + reader.readAsDataURL(blob); + reader.onload = function (event: ProgressEvent) { + const base64: string = event?.target?.result as string; + resolve(base64); + }; + reader.onerror = function (err) { reject(err); }; }); diff --git a/packages/util/src/lib/point.ts b/packages/util/src/lib/point.ts new file mode 100644 index 0000000..febc085 --- /dev/null +++ b/packages/util/src/lib/point.ts @@ -0,0 +1,32 @@ +import type { Point, TouchPoint } from '@idraw/types'; + +export function calcDistance(start: Point, end: Point) { + const distance = (start.x - end.x) * (start.x - end.x) + (start.y - end.y) * (start.y - end.y); + return distance === 0 ? distance : Math.sqrt(distance); +} + +export function calcSpeed(start: Point, end: Point) { + const distance = calcDistance(start, end); + const speed = distance / Math.abs(end.t - start.t); + return speed; +} + +export function equalPoint(p1: Point, p2: Point) { + return p1.x === p2.x && p1.y === p2.y && p1.t === p2.t; +} + +export function equalTouchPoint(p1: TouchPoint, p2: TouchPoint) { + return equalPoint(p1, p2) === true && p1.f === p2.f; +} + +function isNum(num: any): boolean { + return num >= 0 || num < 0; +} + +export function vaildPoint(p: Point) { + return isNum(p.x) && isNum(p.y) && p.t > 0; +} + +export function vaildTouchPoint(p: TouchPoint) { + return vaildPoint(p) === true && p.f >= 0; +} diff --git a/packages/util/src/lib/store.ts b/packages/util/src/lib/store.ts new file mode 100644 index 0000000..adb1ae1 --- /dev/null +++ b/packages/util/src/lib/store.ts @@ -0,0 +1,31 @@ +import { deepClone } from './data'; + +export class Store> { + private _temp: T; + private _backUpDefaultStorage: T; + + constructor(opts: { defaultStorage: T }) { + this._backUpDefaultStorage = deepClone(opts.defaultStorage); + this._temp = this._createTempStorage(); + } + + set(name: K, value: T[K]) { + this._temp[name] = value; + } + + get(name: K): T[K] { + return this._temp[name]; + } + + getSnapshot(): T { + return deepClone(this._temp); + } + + clear() { + this._temp = this._createTempStorage(); + } + + private _createTempStorage() { + return deepClone(this._backUpDefaultStorage); + } +}