diff --git a/lerna.json b/lerna.json index 3224f4e..9c83ee0 100644 --- a/lerna.json +++ b/lerna.json @@ -1,8 +1,8 @@ { "packages": [ "packages/types", - "packages/canvas", + "packages/board", "packages/idraw" ], - "version": "0.0.1" + "version": "0.0.3" } diff --git a/packages/canvas/api-extractor.json b/packages/board/api-extractor.json similarity index 100% rename from packages/canvas/api-extractor.json rename to packages/board/api-extractor.json diff --git a/packages/canvas/example/index.html b/packages/board/example/index.html similarity index 87% rename from packages/canvas/example/index.html rename to packages/board/example/index.html index d982bfb..8673c69 100644 --- a/packages/canvas/example/index.html +++ b/packages/board/example/index.html @@ -3,14 +3,14 @@ -
+
diff --git a/packages/board/example/main.js b/packages/board/example/main.js new file mode 100644 index 0000000..2e8c625 --- /dev/null +++ b/packages/board/example/main.js @@ -0,0 +1,9 @@ +const { Board } = window.iDraw; + +const mount = document.querySelector('#mount'); +const board = new Board(mount, { + width: 600, + height: 400, + devicePixelRatio: 4 +}); +board.render(); \ No newline at end of file diff --git a/packages/canvas/package.json b/packages/board/package.json similarity index 84% rename from packages/canvas/package.json rename to packages/board/package.json index 68b612a..58ec1d7 100644 --- a/packages/canvas/package.json +++ b/packages/board/package.json @@ -1,6 +1,6 @@ { - "name": "@idraw/canvas", - "version": "0.0.1", + "name": "@idraw/board", + "version": "0.0.3", "description": "", "main": "dist/index.cjs.js", "module": "dist/index.es.js", diff --git a/packages/board/src/index.ts b/packages/board/src/index.ts new file mode 100644 index 0000000..9a5b2bf --- /dev/null +++ b/packages/board/src/index.ts @@ -0,0 +1,64 @@ +// import { TypePoint } from '@idraw/types'; +import { setStyle } from './util/style'; +// import { Watcher } from './util/watcher'; + +type Options = { + width: number; + height: number; + devicePixelRatio?: number; +} + +type PrivateOptions = Options & { + devicePixelRatio: number +} + +class Drag { + private _canvas: HTMLCanvasElement; + private _mount: HTMLDivElement; + private _opts: PrivateOptions; + private _hasRendered: boolean = false; + // private _watcher: Watcher; + + constructor(mount: HTMLDivElement, opts: Options) { + this._mount = mount; + this._canvas = document.createElement('canvas'); + this._mount.appendChild(this._canvas); + this._opts = this._parsePrivateOptions(opts); + // this._watcher = new Watcher(this._canvas); + } + + render() { + if (this._hasRendered === true) { + return; + } + const { width, height, devicePixelRatio } = this._opts; + this._canvas.width = width * devicePixelRatio; + this._canvas.height = height * devicePixelRatio; + setStyle(this._canvas, { + width: `${width}px`, + height: `${height}px`, + }); + // this._watcher.onMove(this._onMove.bind(this)); + // this._watcher.onMoveStart(this._onMoveStart.bind(this)); + // this._watcher.onMoveEnd(this._onMoveEnd.bind(this)); + // this._hasRendered = true; + } + + draw() { + // TODO + } + + + + private _parsePrivateOptions(opts: Options): PrivateOptions { + const defaultOpts = { + devicePixelRatio: 1, + } + return { ...defaultOpts, ...opts } + } + + +} + +export default Drag; + diff --git a/packages/board/src/util/istype.ts b/packages/board/src/util/istype.ts new file mode 100644 index 0000000..0651aa1 --- /dev/null +++ b/packages/board/src/util/istype.ts @@ -0,0 +1,59 @@ +function parsePrototype (data: any) { + const typeStr = Object.prototype.toString.call(data) || ''; + const result = typeStr.replace(/(\[object|\])/ig, '').trim(); + return result; +}; +const istype = { + + type(data: any, lowerCase?: boolean) { + let result = parsePrototype(data); + return lowerCase === true ? result.toLocaleLowerCase() : result; + }, + + array (data: any) { + return parsePrototype(data) === 'Array'; + }, + + json (data: any) { + return parsePrototype(data) === 'Object'; + }, + + function (data: any) { + return parsePrototype(data) === 'Function'; + }, + + asyncFunction (data: any) { + return parsePrototype(data) === 'AsyncFunction'; + }, + + string (data: any) { + return parsePrototype(data) === 'String'; + }, + + number (data: any) { + return parsePrototype(data) === 'Number'; + }, + + undefined (data: any) { + return parsePrototype(data) === 'Undefined'; + }, + + null (data: any) { + return parsePrototype(data) === 'Null'; + }, + + promise (data: any) { + return parsePrototype(data) === 'Promise'; + }, + + nodeList (data: any) { + return parsePrototype(data) === 'NodeList'; + }, + + imageData(data: any) { + return parsePrototype(data) === 'ImageData'; + } + +}; + +export default istype; \ No newline at end of file diff --git a/packages/board/src/util/style.ts b/packages/board/src/util/style.ts new file mode 100644 index 0000000..9da4484 --- /dev/null +++ b/packages/board/src/util/style.ts @@ -0,0 +1,94 @@ +import istype from './istype'; + +export const mergeCSS2StyleAttr = function( + cssMap: {[key: string]: string} = {} +): string { + const cssList = []; + if (istype.json(cssMap) === true) { + for (const key in cssMap) { + let cssKey: string = `${key}`; + let cssVal: string = `${cssMap[key]}`; + cssKey = cssKey.trim(); + cssVal = cssVal.trim(); + cssList.push(`${cssKey}:${cssVal}`); + } + } + const styleAttr = cssList.join('; '); + return styleAttr; +} + + +export function setStyle( + dom: HTMLElement, + style: {[key: string]: string} ) { + const originStyle = getStyle(dom); + const _style = {...originStyle, ...style} + const keys: string[] = Object.keys(_style); + let styleStr = ''; + keys.forEach((key: string) => { + styleStr += `${key}:${_style[key] || ''};` + }); + dom.setAttribute('style', styleStr); +} + +export function getStyle(dom: HTMLElement): {[key: string]: string} { + const styleObj: {[key: string]: string} = {}; + const style = dom.getAttribute('style') || ''; + const styleList = style.split(';'); + styleList.forEach((item: string) => { + const dataList = item.split(':'); + if (dataList[0] && typeof dataList[0] === 'string') { + styleObj[dataList[0]] = dataList[1] || ''; + } + }) + + return styleObj; +} + +export function getDomTransform(dom: HTMLElement): { + scaleX: number; + skewY: number; + skewX: number; + scaleY: number; + translateX: number; + translateY: number; +} { + // transform: matrix( scaleX(), skewY(), skewX(), scaleY(), translateX(), translateY() ) + // matrix(1, 0, 0, 1, 0, 0) + const style = getComputedStyle(dom) || {}; + const { transform } = style; + const matrixStr = transform.replace(/^matrix\(|\)$/ig, ''); + const matrixList = matrixStr.split(',').map((str, i) => { + const val = parseFloat(str); + if ([0, 3].indexOf(i) >= 0) { + return isNaN(val) ? 1 : val; + } else { + return isNaN(val) ? 0 : val; + } + }); + const matrix = { + scaleX: matrixList[0], + skewY: matrixList[1] || 0, + skewX: matrixList[2] || 0, + scaleY: matrixList[3] || 1, + translateX: matrixList[4] || 0, + translateY: matrixList[5] || 0, + } + return matrix; +} + + +export function setDomTransform(dom: HTMLElement, matrix: { + scaleX: number; + skewY: number; + skewX: number; + scaleY: number; + translateX: number; + translateY: number; +}) { + // transform: matrix( scaleX(), skewY(), skewX(), scaleY(), translateX(), translateY() ) + // matrix(1, 2, -1, 1, 80, 80) + + const transform = `matrix(${matrix.scaleX}, ${matrix.skewY}, ${matrix.skewX}, ${matrix.scaleY}, ${matrix.translateX}, ${matrix.translateY})`; + dom.style.setProperty('transform', transform); +} diff --git a/packages/board/src/util/watcher.ts b/packages/board/src/util/watcher.ts new file mode 100644 index 0000000..571ff7e --- /dev/null +++ b/packages/board/src/util/watcher.ts @@ -0,0 +1,126 @@ +type TypeDataPosition = { + x: number, + y: number, + t: number, +} + +interface TypeWatcher { + onMove(callback: TypeWatchCallback): void, + onMoveEnd(callback: TypeWatchCallback): void, + onMoveEnd(callback: TypeWatchCallback): void, +} + + +type TypeWatchCallback = (p: TypeDataPosition) => void + +export class Watcher implements TypeWatcher { + + private _canvas: HTMLCanvasElement; + private _isPainting: boolean = false; + private _onMove?: TypeWatchCallback; + private _onMoveStart?: TypeWatchCallback; + private _onMoveEnd?: TypeWatchCallback; + + constructor(canvas: HTMLCanvasElement) { + this._canvas = canvas; + this._isPainting = false; + this._initEvent(); + } + + onMove(callback: TypeWatchCallback) { + this._onMove = callback; + } + + onMoveEnd(callback: TypeWatchCallback) { + this._onMoveEnd = callback; + } + + onMoveStart(callback: TypeWatchCallback) { + this._onMoveStart = callback; + } + + _initEvent() { + const canvas = this._canvas; + canvas.addEventListener('mousedown', this._listenStart.bind(this)); + canvas.addEventListener('mousemove', this._listenMove.bind(this)); + canvas.addEventListener('mouseup', this._listenEnd.bind(this)); + + canvas.addEventListener('touchstart', this._listenStart.bind(this)); + canvas.addEventListener('touchmove', this._listenMove.bind(this)); + canvas.addEventListener('touchend', this._listenEnd.bind(this)); + + const mouseupEvent = new MouseEvent('mouseup'); + document.querySelector('body')?.addEventListener('mousemove', (e) => { + // @ts-ignore + if (e && e.path && e.path[0] !== canvas) { + if (this._isPainting === true) { + canvas.dispatchEvent(mouseupEvent); + } + } + }, false) + } + + _listenStart(e: MouseEvent|TouchEvent) { + e.preventDefault(); + this._isPainting = true; + if (typeof this._onMoveStart === 'function') { + const p = this._getPosition(e); + if (this._isVaildPosition(p)) { + this._onMoveStart(p); + } + } + } + + _listenMove(e: MouseEvent|TouchEvent) { + e.preventDefault(); + e.stopPropagation(); + if (this._isPainting === true) { + if (typeof this._onMove === 'function') { + const p = this._getPosition(e); + if (this._isVaildPosition(p)) { + this._onMove(p); + } + } + } + } + + _listenEnd(e: MouseEvent|TouchEvent) { + e.preventDefault(); + this._isPainting = false; + if (typeof this._onMoveEnd === 'function') { + const p = this._getPosition(e); + if (this._isVaildPosition(p)) { + this._onMoveEnd(p); + } + } + } + + _getPosition(e: MouseEvent|TouchEvent) { + const canvas = this._canvas; + let x = 0; + let y = 0; + + if (e instanceof TouchEvent) { + const touch: Touch = e.touches[0]; + if (touch) { + x = touch.clientX; + y = touch.clientY; + } + } else { + x = e.clientX; + y = e.clientY; + } + + const p = { + x: x - canvas.getBoundingClientRect().left, + y: y - canvas.getBoundingClientRect().top, + t: Date.now(), + }; + return p; + } + + private _isVaildPosition(p: TypeDataPosition) { + return ( p.x > 0 && p.y > 0 && p.t > 0) + } + +} diff --git a/packages/canvas/example/main.js b/packages/canvas/example/main.js deleted file mode 100644 index c9cd42f..0000000 --- a/packages/canvas/example/main.js +++ /dev/null @@ -1 +0,0 @@ -console.log('hello world') \ No newline at end of file diff --git a/packages/canvas/src/index.ts b/packages/canvas/src/index.ts deleted file mode 100644 index a408936..0000000 --- a/packages/canvas/src/index.ts +++ /dev/null @@ -1,8 +0,0 @@ - -class Canvas { - render() { - console.log('hello world') - } -} - -export default Canvas; \ No newline at end of file diff --git a/packages/idraw/package.json b/packages/idraw/package.json index 68b612a..b844035 100644 --- a/packages/idraw/package.json +++ b/packages/idraw/package.json @@ -1,6 +1,6 @@ { - "name": "@idraw/canvas", - "version": "0.0.1", + "name": "idraw", + "version": "0.0.3", "description": "", "main": "dist/index.cjs.js", "module": "dist/index.es.js", diff --git a/packages/types/src/index.ts b/packages/types/src/index.ts index 22a79de..8f9a3e2 100644 --- a/packages/types/src/index.ts +++ b/packages/types/src/index.ts @@ -1 +1,2 @@ -export * from './lib/data'; \ No newline at end of file +export * from './lib/data'; +export * from './lib/board'; \ No newline at end of file diff --git a/packages/types/src/lib/board.ts b/packages/types/src/lib/board.ts new file mode 100644 index 0000000..ae0199f --- /dev/null +++ b/packages/types/src/lib/board.ts @@ -0,0 +1,8 @@ +type TypePoint = { + x: number; + y: number; +} + +export { + TypePoint +} \ No newline at end of file diff --git a/packages/types/src/lib/data.ts b/packages/types/src/lib/data.ts index 693da49..44f6b89 100644 --- a/packages/types/src/lib/data.ts +++ b/packages/types/src/lib/data.ts @@ -1 +1,3 @@ + + export {} \ No newline at end of file diff --git a/scripts/config.js b/scripts/config.js index c677aa4..df1fbcc 100644 --- a/scripts/config.js +++ b/scripts/config.js @@ -1,8 +1,8 @@ module.exports = { packages: [ { - dirName: 'canvas', - globalName: 'iDraw.Canvas', + dirName: 'board', + globalName: 'iDraw.Board', }, { dirName: 'idraw', diff --git a/scripts/rollup.config.js b/scripts/rollup.config.js index 0d02e80..25dda16 100644 --- a/scripts/rollup.config.js +++ b/scripts/rollup.config.js @@ -10,7 +10,7 @@ const resolveFile = function(names = []) { } const modules = []; -const external = [ '@idraw/idraw-types']; +const external = [ '@idraw/types']; for(let i = 0; i < packages.length; i++) { const pkg = packages[i];