From d0003a455d21ef73019ef9780ba31d7a7829511b Mon Sep 17 00:00:00 2001 From: chenshenhai Date: Tue, 25 May 2021 18:16:28 +0800 Subject: [PATCH 1/6] feat: fix point at scale status --- packages/board/example/features/lib/action.js | 10 +++- packages/board/example/features/lib/draw.js | 2 + packages/board/example/features/lib/scale.js | 15 +++++- packages/board/example/features/lib/scroll.js | 19 ++++++-- packages/board/example/features/main.js | 16 ++++++- packages/board/src/index.ts | 15 ++++-- packages/board/src/util/context.ts | 48 ++++++++++++++++++- 7 files changed, 113 insertions(+), 12 deletions(-) diff --git a/packages/board/example/features/lib/action.js b/packages/board/example/features/lib/action.js index 473a0af15..9353d6599 100644 --- a/packages/board/example/features/lib/action.js +++ b/packages/board/example/features/lib/action.js @@ -1,5 +1,7 @@ import { getData } from "./data.js"; import { drawData } from './draw.js'; +import { getScale } from './scale.js'; +import opts from './opts.js' function isPointInElement(board, p = {x, y}) { const ctx = board.getContext(); @@ -13,6 +15,7 @@ function isPointInElement(board, p = {x, y}) { ctx.lineTo(ele.x + ele.w, ele.y + ele.h); ctx.lineTo(ele.x, ele.y + ele.h); ctx.closePath(); + if (ctx.isPointInPath(p.x, p.y)) { idx = i; break; @@ -23,9 +26,12 @@ function isPointInElement(board, p = {x, y}) { function moveElement(board, idx, moveX, moveY) { const data = getData(); + const scale = getScale(); if (data.elements[idx]) { - data.elements[idx].x += moveX; - data.elements[idx].y += moveY; + // data.elements[idx].x += (moveX * scale * opts.devicePixelRatio); + // data.elements[idx].y += (moveY * scale * opts.devicePixelRatio); + data.elements[idx].x += (moveX / scale); + data.elements[idx].y += (moveY / scale); } drawData(board) } diff --git a/packages/board/example/features/lib/draw.js b/packages/board/example/features/lib/draw.js index 8488196fa..28b15cbca 100644 --- a/packages/board/example/features/lib/draw.js +++ b/packages/board/example/features/lib/draw.js @@ -6,6 +6,8 @@ export function drawData(board) { const data = getData(); board.clear(); ctx.clearRect(0, 0, opts.width, opts.height); + ctx.setFillStyle('#ffffff'); + ctx.fillRect(0, 0, opts.width, opts.height); data.elements.forEach(ele => { ctx.setFillStyle(ele.desc.color); ctx.fillRect(ele.x, ele.y, ele.w, ele.h); diff --git a/packages/board/example/features/lib/scale.js b/packages/board/example/features/lib/scale.js index fa5bd6690..d2397890d 100644 --- a/packages/board/example/features/lib/scale.js +++ b/packages/board/example/features/lib/scale.js @@ -1,8 +1,13 @@ const input = document.querySelector('#scale'); let hasInited = false; -export function doScale(board) { +export function doScale(board, scale) { if (hasInited === true) return; + if (scale > 0) { + input.value = scale; + board.scale(scale); + board.draw(); + } input.addEventListener('change', () => { const val = input.value * 1; if (val > 0) { @@ -11,4 +16,12 @@ export function doScale(board) { } }); hasInited = true; +} + +export function getScale() { + let val = 1; + if (input.value * 1 > 0) { + val = input.value * 1; + } + return val; } \ No newline at end of file diff --git a/packages/board/example/features/lib/scroll.js b/packages/board/example/features/lib/scroll.js index 4b9d8101d..379164097 100644 --- a/packages/board/example/features/lib/scroll.js +++ b/packages/board/example/features/lib/scroll.js @@ -2,18 +2,31 @@ const inputX = document.querySelector('#scrollX'); const inputY = document.querySelector('#scrollY'); let hasInited = false; -export function doScroll(board) { +export function doScroll(board, conf = {}) { if (hasInited === true) return; + + if (conf.scrollX >= 0) { + inputX.value = conf.scrollX; + board.scrollX(conf.scrollX); + board.draw(); + } + + if (conf.scrollY >= 0) { + inputY.value = conf.scrollY; + board.scrollY(conf.scrollY); + board.draw(); + } + inputX.addEventListener('change', () => { const val = inputX.value * 1; - if (val > 0) { + if (val >= 0) { board.scrollX(val); board.draw(); } }); inputY.addEventListener('change', () => { const val = inputY.value * 1; - if (val > 0) { + if (val >= 0) { board.scrollY(val); board.draw(); } diff --git a/packages/board/example/features/main.js b/packages/board/example/features/main.js index fc25e1c4b..1049035f6 100644 --- a/packages/board/example/features/main.js +++ b/packages/board/example/features/main.js @@ -9,11 +9,23 @@ const { Board } = window.iDraw; const mount = document.querySelector('#mount'); const board = new Board(mount, opts); +const conf = { + scale: 0.5, + scrollX: 100, + scrollY: 200, +} + +// const conf = { +// scale: 1, +// scrollX: 0, +// scrollY: 0, +// } + drawData(board); initEvent(board); -doScale(board); -doScroll(board); +doScale(board, conf.scale); +doScroll(board, conf); // board.scale(2); diff --git a/packages/board/src/index.ts b/packages/board/src/index.ts index ac2ec577d..1bfb5430c 100644 --- a/packages/board/src/index.ts +++ b/packages/board/src/index.ts @@ -47,15 +47,24 @@ class Board { } scale(scaleRatio: number) { - if (scaleRatio > 0) this._scaleRatio = scaleRatio; + if (scaleRatio > 0) { + this._scaleRatio = scaleRatio; + this._ctx.setConfig({ scale: scaleRatio }); + } } scrollX(x: number) { - if (x > 0) this._scrollX = x; + if (x >= 0) { + this._scrollX = x; + this._ctx.setConfig({ scrollX: x }); + } } scrollY(y: number) { - if (y > 0) this._scrollY = y; + if (y >= 0) { + this._scrollY = y; + this._ctx.setConfig({ scrollY: y }); + } } draw() { diff --git a/packages/board/src/util/context.ts b/packages/board/src/util/context.ts index bea8e054d..69a3df56f 100644 --- a/packages/board/src/util/context.ts +++ b/packages/board/src/util/context.ts @@ -4,9 +4,22 @@ type Options = { devicePixelRatio: number; } +type Config = { + scale?: number; + scrollX?: number; + scrollY?: number; +} + +type PrivateConfig = { + scale: number; + scrollX: number; + scrollY: number; +} + class Context { private _opts: Options; private _ctx: CanvasRenderingContext2D; + private _conf: PrivateConfig; // private _scale: number; // private _scrollX: number; @@ -15,6 +28,15 @@ class Context { constructor(ctx: CanvasRenderingContext2D, opts: Options) { this._opts = opts; this._ctx = ctx; + this._conf = { + scale: 1, + scrollX: 0, + scrollY: 0, + } + } + + setConfig(config: Config) { + this._conf = {...this._conf, ...config}; } setFillStyle(color: string) { @@ -51,14 +73,38 @@ class Context { return this._ctx.lineTo(this._doSize(x), this._doSize(y)); } + setLineWidth(w: number) { + this._ctx.lineWidth = w; + } + isPointInPath(x: number, y: number) { - return this._ctx.isPointInPath(this._doSize(x), this._doSize(y)); + return this._ctx.isPointInPath(this._doX(x), this._doY(y)); + } + + setStrokeStyle(color: string) { + this._ctx.strokeStyle = color; + } + + stroke() { + return this._ctx.stroke(); } private _doSize(num: number) { return this._opts.devicePixelRatio * num; } + private _doX(x: number) { + const { scale, scrollX } = this._conf; + const _x = (x - scrollX * scale) / scale; + return this._doSize(_x); + } + + private _doY(y: number) { + const { scale, scrollY } = this._conf; + const _y = (y - scrollY * scale) / scale; + return this._doSize(_y); + } + } export default Context; \ No newline at end of file From d1696154630e9f779ae771a576a46dc834606068 Mon Sep 17 00:00:00 2001 From: chenshenhai Date: Tue, 25 May 2021 22:56:42 +0800 Subject: [PATCH 2/6] feat: add packages/core --- dev.md | 1 + lerna.json | 1 + packages/board/package.json | 2 +- packages/core/api-extractor.json | 7 ++++ packages/core/example/index.html | 39 +++++++++++++++++++++++ packages/core/example/lib/data.js | 53 +++++++++++++++++++++++++++++++ packages/core/example/main.js | 14 ++++++++ packages/core/package.json | 20 ++++++++++++ packages/core/src/index.ts | 51 +++++++++++++++++++++++++++++ packages/idraw/package.json | 5 ++- packages/idraw/src/index.ts | 18 +++++++++++ packages/types/package.json | 2 +- packages/types/src/lib/data.ts | 41 +++++++++++++++++++++++- scripts/config.js | 4 +++ scripts/rollup.config.js | 2 +- 15 files changed, 255 insertions(+), 5 deletions(-) create mode 100644 packages/core/api-extractor.json create mode 100644 packages/core/example/index.html create mode 100644 packages/core/example/lib/data.js create mode 100644 packages/core/example/main.js create mode 100644 packages/core/package.json create mode 100644 packages/core/src/index.ts diff --git a/dev.md b/dev.md index 13868d1cc..5b4cf68b4 100644 --- a/dev.md +++ b/dev.md @@ -1,4 +1,5 @@ ```sh lerna add @idraw/types --scope=idraw --dev +lerna add @idraw/board --scope=idraw ``` \ No newline at end of file diff --git a/lerna.json b/lerna.json index 9c83ee0a8..a81df0412 100644 --- a/lerna.json +++ b/lerna.json @@ -2,6 +2,7 @@ "packages": [ "packages/types", "packages/board", + "packages/core", "packages/idraw" ], "version": "0.0.3" diff --git a/packages/board/package.json b/packages/board/package.json index 126528cab..a2e0ee2fb 100644 --- a/packages/board/package.json +++ b/packages/board/package.json @@ -12,6 +12,6 @@ "author": "chenshenhai", "license": "MIT", "devDependencies": { - "@idraw/types": "^0.0.1" + "@idraw/types": "^0.0.3" } } diff --git a/packages/core/api-extractor.json b/packages/core/api-extractor.json new file mode 100644 index 000000000..7ae8ecaaf --- /dev/null +++ b/packages/core/api-extractor.json @@ -0,0 +1,7 @@ +{ + "extends": "../../api-extractor.json", + "mainEntryPointFilePath": "./dist/packages//src/index.d.ts", + "dtsRollup": { + "publicTrimmedFilePath": "./dist/index.d.ts" + } +} \ No newline at end of file diff --git a/packages/core/example/index.html b/packages/core/example/index.html new file mode 100644 index 000000000..e1f6b0ee1 --- /dev/null +++ b/packages/core/example/index.html @@ -0,0 +1,39 @@ + + + + + + + + +
+ +
+ scale + +
+
+ scrollX + +
+
+ scrollY + +
+ + + + + + \ No newline at end of file diff --git a/packages/core/example/lib/data.js b/packages/core/example/lib/data.js new file mode 100644 index 000000000..fef055963 --- /dev/null +++ b/packages/core/example/lib/data.js @@ -0,0 +1,53 @@ + +const data = { + elements: [ + { + x: 10, + y: 10, + w: 200, + h: 120, + type: 'rect', + desc: { + color: '#f0f0f0', + } + }, + { + x: 80, + y: 80, + w: 200, + h: 120, + type: 'rect', + desc: { + color: '#cccccc', + } + }, + { + x: 160, + y: 160, + w: 200, + h: 120, + type: 'rect', + desc: { + color: '#c0c0c0', + } + }, + { + x: 400 - 10, + y: 300 - 10, + w: 200, + h: 100, + type: 'rect', + desc: { + color: '#e0e0e0', + } + } + ] +} + +function getData() { + return data; +} + +export { + getData +}; \ No newline at end of file diff --git a/packages/core/example/main.js b/packages/core/example/main.js new file mode 100644 index 000000000..927b94ad7 --- /dev/null +++ b/packages/core/example/main.js @@ -0,0 +1,14 @@ +import { getData } from './lib/data.js'; +const { Core } = window.iDraw; + +const data = getData(); +const mount = document.querySelector('#mount'); +const core = new Core(mount, { + width: 600, + height: 400, + devicePixelRatio: 4 +}); +core.setData(data); +core.draw(); + +console.log('hello world =', Core); \ No newline at end of file diff --git a/packages/core/package.json b/packages/core/package.json new file mode 100644 index 000000000..8cba5fbf8 --- /dev/null +++ b/packages/core/package.json @@ -0,0 +1,20 @@ +{ + "name": "@idraw/core", + "version": "0.0.3", + "description": "", + "main": "dist/index.cjs.js", + "module": "dist/index.es.js", + "unpkg": "dist/index.global.js", + "types": "dist/index.d.ts", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "author": "chenshenhai", + "license": "MIT", + "devDependencies": { + "@idraw/types": "^0.0.3" + }, + "dependencies": { + "@idraw/board": "^0.0.3" + } +} diff --git a/packages/core/src/index.ts b/packages/core/src/index.ts new file mode 100644 index 000000000..6fc308c1e --- /dev/null +++ b/packages/core/src/index.ts @@ -0,0 +1,51 @@ +import { TypeData } from '@idraw/types'; +import Board from '@idraw/board'; + +type Options = { + width: number; + height: number; + devicePixelRatio: number; +} + +class Core { + + private _board: Board; + private _data: TypeData; + private _opts: Options; + + constructor(mount: HTMLDivElement, opts: Options) { + this._data = { elements: [] }; + this._opts = opts; + this._board = new Board(mount, this._opts); + } + + draw() { + const board = this._board; + const ctx = board.getContext(); + const data = this.getData(); + const { width, height } = this._opts; + board.clear(); + ctx.clearRect(0, 0, width, height); + ctx.setFillStyle('#ffffff'); + ctx.fillRect(0, 0, width, height); + data.elements.forEach(ele => { + // @ts-ignore + if (ele.type === 'rect' && typeof ele.desc.color === 'string') { + // @ts-ignore + ctx.setFillStyle(ele.desc.color); + } + ctx.fillRect(ele.x, ele.y, ele.w, ele.h); + }); + board.draw(); + } + + getData() { + return this._data; + } + + setData(data: TypeData) { + return this._data = data; + } +} + +export default Core; \ No newline at end of file diff --git a/packages/idraw/package.json b/packages/idraw/package.json index d738c0d9d..e98a73a11 100644 --- a/packages/idraw/package.json +++ b/packages/idraw/package.json @@ -12,6 +12,9 @@ "author": "chenshenhai", "license": "MIT", "devDependencies": { - "@idraw/types": "^0.0.1" + "@idraw/types": "^0.0.3" + }, + "dependencies": { + "@idraw/board": "^0.0.3" } } diff --git a/packages/idraw/src/index.ts b/packages/idraw/src/index.ts index d7fc2067d..62deb522b 100644 --- a/packages/idraw/src/index.ts +++ b/packages/idraw/src/index.ts @@ -1,3 +1,21 @@ +import { TypeData } from '@idraw/types'; + +const data: TypeData = { + elements: [ + { + x: 0, + y: 0, + w: 0, + h: 0, + type: 'circle', + desc: { + color: '#f0f0f0', + } + } + ] +} + +console.log('data =', data) class IDraw { render() { diff --git a/packages/types/package.json b/packages/types/package.json index b2a7f1b39..ecd1a3f9e 100644 --- a/packages/types/package.json +++ b/packages/types/package.json @@ -1,6 +1,6 @@ { "name": "@idraw/types", - "version": "0.0.1", + "version": "0.0.3", "description": "", "main": "src/index.ts", "types": "src/index.ts", diff --git a/packages/types/src/lib/data.ts b/packages/types/src/lib/data.ts index 44f6b8996..9badfcb85 100644 --- a/packages/types/src/lib/data.ts +++ b/packages/types/src/lib/data.ts @@ -1,3 +1,42 @@ -export {} \ No newline at end of file +type ElementsDescMap = { + text: { + size: number; + }, + rect: { + color: string; + }, + circle: { + color: string; + r: number; + x: number; + y: number; + }, + image: { + src: number; + }, + paint: { + + } +} + +type TypeDataElement = { + uuid?: string; + x: number; + y: number; + w: number; + h: number; + type: T; + desc: ElementsDescMap[T]; +} + +type TypeData = { + elements: TypeDataElement[] + selectedElements?: string[] // uuids +} + +export { + TypeDataElement, + TypeData +} \ No newline at end of file diff --git a/scripts/config.js b/scripts/config.js index df1fbccca..966311c80 100644 --- a/scripts/config.js +++ b/scripts/config.js @@ -4,6 +4,10 @@ module.exports = { dirName: 'board', globalName: 'iDraw.Board', }, + { + dirName: 'core', + globalName: 'iDraw.Core', + }, { dirName: 'idraw', globalName: 'iDraw.IDraw', diff --git a/scripts/rollup.config.js b/scripts/rollup.config.js index 25dda16d0..8b3bd51ce 100644 --- a/scripts/rollup.config.js +++ b/scripts/rollup.config.js @@ -10,7 +10,7 @@ const resolveFile = function(names = []) { } const modules = []; -const external = [ '@idraw/types']; +const external = [ '@idraw/types', '@idraw/board', '@idraw/core' ]; for(let i = 0; i < packages.length; i++) { const pkg = packages[i]; From 53935a884b40247564ddf31a3a35eb21266ae0e0 Mon Sep 17 00:00:00 2001 From: chenshenhai Date: Wed, 26 May 2021 11:06:16 +0800 Subject: [PATCH 3/6] feat: add types/elements --- packages/board/src/util/context.ts | 4 +++- packages/types/src/index.ts | 4 +++- packages/types/src/lib/board.ts | 21 ++++++++++++++++- packages/types/src/lib/data.ts | 29 ++++------------------- packages/types/src/lib/element.ts | 37 ++++++++++++++++++++++++++++++ packages/types/src/lib/paint.ts | 23 +++++++++++++++++++ 6 files changed, 90 insertions(+), 28 deletions(-) create mode 100644 packages/types/src/lib/element.ts create mode 100644 packages/types/src/lib/paint.ts diff --git a/packages/board/src/util/context.ts b/packages/board/src/util/context.ts index 69a3df56f..24186efd2 100644 --- a/packages/board/src/util/context.ts +++ b/packages/board/src/util/context.ts @@ -1,3 +1,5 @@ +import { TypeContext } from '@idraw/types'; + type Options = { width: number; height: number; @@ -16,7 +18,7 @@ type PrivateConfig = { scrollY: number; } -class Context { +class Context implements TypeContext { private _opts: Options; private _ctx: CanvasRenderingContext2D; private _conf: PrivateConfig; diff --git a/packages/types/src/index.ts b/packages/types/src/index.ts index 8f9a3e2c6..56adeca91 100644 --- a/packages/types/src/index.ts +++ b/packages/types/src/index.ts @@ -1,2 +1,4 @@ export * from './lib/data'; -export * from './lib/board'; \ No newline at end of file +export * from './lib/board'; +export * from './lib/paint'; +export * from './lib/element'; \ No newline at end of file diff --git a/packages/types/src/lib/board.ts b/packages/types/src/lib/board.ts index ae0199fb6..81920aedd 100644 --- a/packages/types/src/lib/board.ts +++ b/packages/types/src/lib/board.ts @@ -3,6 +3,25 @@ type TypePoint = { y: number; } +interface TypeContext { + setConfig(config: { + scale?: number; + scrollX?: number; + scrollY?: number; + }): void; + setFillStyle(color: string): void; + fillRect(x: number, y: number, w: number, h: number): void; + clearRect(x: number, y: number, w: number, h: number): void; + beginPath(): void; + closePath(): void; + lineTo(x: number, y: number): void; + setLineWidth(w: number): void; + isPointInPath(x: number, y: number): boolean; + setStrokeStyle(color: string): void; + stroke(): void; +} + export { - TypePoint + TypePoint, + TypeContext } \ No newline at end of file diff --git a/packages/types/src/lib/data.ts b/packages/types/src/lib/data.ts index 9badfcb85..0ae7f18ae 100644 --- a/packages/types/src/lib/data.ts +++ b/packages/types/src/lib/data.ts @@ -1,38 +1,17 @@ +import { TypeElementsDesc } from './element'; - -type ElementsDescMap = { - text: { - size: number; - }, - rect: { - color: string; - }, - circle: { - color: string; - r: number; - x: number; - y: number; - }, - image: { - src: number; - }, - paint: { - - } -} - -type TypeDataElement = { +type TypeDataElement = { uuid?: string; x: number; y: number; w: number; h: number; type: T; - desc: ElementsDescMap[T]; + desc: TypeElementsDesc[T]; } type TypeData = { - elements: TypeDataElement[] + elements: TypeDataElement[] selectedElements?: string[] // uuids } diff --git a/packages/types/src/lib/element.ts b/packages/types/src/lib/element.ts new file mode 100644 index 000000000..b3ac80994 --- /dev/null +++ b/packages/types/src/lib/element.ts @@ -0,0 +1,37 @@ +import { TypePaintData } from './paint'; + +type TypeElementsDesc = { + text: TypeElemDescText, + rect: TypeElemDescRect, + circle: TypeElemDescCircle, + image: TypeElemDescImage, + paint: TypeElemDescPaint +} + +type TypeElemDescRect = { + color: string; +} + +type TypeElemDescText = { + size: number; + color: number; +} + +type TypeElemDescCircle = { + r: number; + x: number; + y: number; +} + +type TypeElemDescImage = { + src: number; +} + +type TypeElemDescPaint = TypePaintData + +export { + TypeElemDescText, + TypeElemDescRect, + TypeElemDescCircle, + TypeElementsDesc, +} \ No newline at end of file diff --git a/packages/types/src/lib/paint.ts b/packages/types/src/lib/paint.ts new file mode 100644 index 000000000..d18f0c805 --- /dev/null +++ b/packages/types/src/lib/paint.ts @@ -0,0 +1,23 @@ +export type TypePaintData = { + brushMap: {[name: string]: TypePaintBrush}, + paths: TypePaintPath[], +} + +export type TypePaintBrush = { + name: string; + src: string; +} + +export type TypePaintPath = { + brush: string, + size: number; + positions: TypePaintPosition[], + color: string; + pressure: number; +} + +export type TypePaintPosition = { + x: number, + y: number, + t: number, +} From d04cc215b4010fd2d5072084a80bc2e0ef8feb57 Mon Sep 17 00:00:00 2001 From: chenshenhai Date: Wed, 26 May 2021 14:23:30 +0800 Subject: [PATCH 4/6] feat: init core render --- package.json | 3 ++- packages/core/example/main.js | 4 +-- packages/core/src/index.ts | 21 +++------------ packages/core/src/lib/draw.ts | 22 ++++++++++++++++ packages/core/src/lib/renderer.ts | 21 +++++++++++++++ packages/core/src/util/color.ts | 7 +++++ packages/core/src/util/file.ts | 16 +++++++++++ packages/core/src/util/index.ts | 22 ++++++++++++++++ packages/core/src/util/loader.ts | 13 +++++++++ packages/core/src/util/time.ts | 44 +++++++++++++++++++++++++++++++ packages/types/src/lib/data.ts | 15 +++-------- packages/types/src/lib/element.ts | 15 +++++++++-- 12 files changed, 168 insertions(+), 35 deletions(-) create mode 100644 packages/core/src/lib/draw.ts create mode 100644 packages/core/src/lib/renderer.ts create mode 100644 packages/core/src/util/color.ts create mode 100644 packages/core/src/util/file.ts create mode 100644 packages/core/src/util/index.ts create mode 100644 packages/core/src/util/loader.ts create mode 100644 packages/core/src/util/time.ts diff --git a/package.json b/package.json index f106af1b5..22d24f51a 100644 --- a/package.json +++ b/package.json @@ -9,7 +9,8 @@ "init": "lerna bootstrap --npm-client=cnpm", "clear": "rm -rf ./packages/*/dist/ & rm -rf ./packages/*/node_modules/", "jest": "jest --config jest.config.js", - "test": "lerna bootstrap --no-ci && npm run build && npm run jest && npm run e2e" + "test": "lerna bootstrap --no-ci && npm run build && npm run jest && npm run e2e", + "serve": "http-server ./" }, "devDependencies": { "@babel/core": "^7.13.14", diff --git a/packages/core/example/main.js b/packages/core/example/main.js index 927b94ad7..f0ebb7b24 100644 --- a/packages/core/example/main.js +++ b/packages/core/example/main.js @@ -9,6 +9,4 @@ const core = new Core(mount, { devicePixelRatio: 4 }); core.setData(data); -core.draw(); - -console.log('hello world =', Core); \ No newline at end of file +core.draw(); \ No newline at end of file diff --git a/packages/core/src/index.ts b/packages/core/src/index.ts index 6fc308c1e..9654cf850 100644 --- a/packages/core/src/index.ts +++ b/packages/core/src/index.ts @@ -1,5 +1,6 @@ import { TypeData } from '@idraw/types'; import Board from '@idraw/board'; +import Renderer from './lib/renderer'; type Options = { width: number; @@ -12,31 +13,17 @@ class Core { private _board: Board; private _data: TypeData; private _opts: Options; + private _renderer: Renderer; constructor(mount: HTMLDivElement, opts: Options) { this._data = { elements: [] }; this._opts = opts; this._board = new Board(mount, this._opts); + this._renderer = new Renderer(this._board); } draw() { - const board = this._board; - const ctx = board.getContext(); - const data = this.getData(); - const { width, height } = this._opts; - board.clear(); - ctx.clearRect(0, 0, width, height); - ctx.setFillStyle('#ffffff'); - ctx.fillRect(0, 0, width, height); - data.elements.forEach(ele => { - // @ts-ignore - if (ele.type === 'rect' && typeof ele.desc.color === 'string') { - // @ts-ignore - ctx.setFillStyle(ele.desc.color); - } - ctx.fillRect(ele.x, ele.y, ele.w, ele.h); - }); - board.draw(); + this._renderer.render(this._data); } getData() { diff --git a/packages/core/src/lib/draw.ts b/packages/core/src/lib/draw.ts new file mode 100644 index 000000000..1bcdef3f8 --- /dev/null +++ b/packages/core/src/lib/draw.ts @@ -0,0 +1,22 @@ +import { TypeContext, TypeData, TypeElement, TypeElemDesc } from '@idraw/types'; + +export function drawContext(ctx: TypeContext, data: TypeData) { + for (let i = 0; i < data.elements.length; i++) { + const ele = data.elements[i]; + switch (ele.type) { + case 'rect': { + drawRect<'rect'>(ctx, ele as TypeElement<'rect'>); + }; + default: { + // nothing + } + } + } +} + + +function drawRect(ctx: TypeContext, ele: TypeElement) { + const desc = ele.desc as TypeElemDesc['rect']; + ctx.setFillStyle(desc.color); + ctx.fillRect(ele.x, ele.y, ele.w, ele.h); +} \ No newline at end of file diff --git a/packages/core/src/lib/renderer.ts b/packages/core/src/lib/renderer.ts new file mode 100644 index 000000000..535417efd --- /dev/null +++ b/packages/core/src/lib/renderer.ts @@ -0,0 +1,21 @@ +import { TypeContext, TypeData } from '@idraw/types'; +import { drawContext } from './draw'; +import Board from '@idraw/board'; + +export default class Renderer { + + private _board: Board; + private _ctx: TypeContext; + private _data: TypeData = { elements: [] }; + + constructor(board: Board) { + this._board = board; + this._ctx = this._board.getContext(); + } + + render(data: TypeData) { + this._data = data; + drawContext(this._ctx, this._data); + this._board.draw(); + } +} \ No newline at end of file diff --git a/packages/core/src/util/color.ts b/packages/core/src/util/color.ts new file mode 100644 index 000000000..4de9f98d2 --- /dev/null +++ b/packages/core/src/util/color.ts @@ -0,0 +1,7 @@ +export function toColorHexNum(color: string): number { + return parseInt(color.replace(/^\#/, '0x')); +} + +export function toColorHexStr(color: number): string { + return '#' + color.toString(16); +} \ No newline at end of file diff --git a/packages/core/src/util/file.ts b/packages/core/src/util/file.ts new file mode 100644 index 000000000..30b4ce5c4 --- /dev/null +++ b/packages/core/src/util/file.ts @@ -0,0 +1,16 @@ + +type ImageType = 'image/jpeg' | 'image/png'; + +export function downloadImageFromCanvas ( + canvas: HTMLCanvasElement, + opts: { filename: string, type: ImageType } +) { + const { filename, type = 'image/jpeg' } = opts; + const stream = canvas.toDataURL(type); + const downloadLink = document.createElement('a'); + downloadLink.href = stream; + downloadLink.download = filename; + const downloadClickEvent = document.createEvent('MouseEvents'); + downloadClickEvent.initEvent('click', true, false); + downloadLink.dispatchEvent(downloadClickEvent); +} \ No newline at end of file diff --git a/packages/core/src/util/index.ts b/packages/core/src/util/index.ts new file mode 100644 index 000000000..b99a113d2 --- /dev/null +++ b/packages/core/src/util/index.ts @@ -0,0 +1,22 @@ +import { loadImage } from './loader'; +import { delay, compose, throttle } from './time'; +import { downloadImageFromCanvas } from './file'; +import { toColorHexStr, toColorHexNum } from './color'; + +export default { + time: { + delay, + compose, + throttle, + }, + loader: { + loadImage + }, + file: { + downloadImageFromCanvas, + }, + color: { + toColorHexStr, + toColorHexNum, + } +} \ No newline at end of file diff --git a/packages/core/src/util/loader.ts b/packages/core/src/util/loader.ts new file mode 100644 index 000000000..7eedec1e7 --- /dev/null +++ b/packages/core/src/util/loader.ts @@ -0,0 +1,13 @@ + + +export function loadImage(src: string): Promise { + return new Promise((resolve, reject) => { + const img = new Image; + img.onload = function() { + resolve(img); + }; + img.onabort = reject; + img.onerror = reject; + img.src = src; + }); +} \ No newline at end of file diff --git a/packages/core/src/util/time.ts b/packages/core/src/util/time.ts new file mode 100644 index 000000000..8ec52e67e --- /dev/null +++ b/packages/core/src/util/time.ts @@ -0,0 +1,44 @@ + +export function compose (middleware: Function[]) { + return function (context: any, next?: Function) { + // let index = -1; + return dispatch(0); + + function dispatch (i: number): Promise { + // index = i + let fn = middleware[i] + if (i === middleware.length && next) { + fn = next; + } + if (!fn) return Promise.resolve() + try { + return Promise.resolve(fn(context, dispatch.bind(null, i + 1))); + } catch (err) { + return Promise.reject(err) + } + } + } +} + + +export function delay(time: number): Promise { + return new Promise((resolve) => { + setTimeout(() => { + resolve(); + }, time); + }) +} + +export function throttle(fn: Function, timeout: number) { + let timer: any = -1; + return function(...args: any[]) { + if (timer > 0) { + return; + } + timer = setTimeout(() => { + fn(...args); + timer = -1; + }, timeout) + } +} + diff --git a/packages/types/src/lib/data.ts b/packages/types/src/lib/data.ts index 0ae7f18ae..9bc0144d1 100644 --- a/packages/types/src/lib/data.ts +++ b/packages/types/src/lib/data.ts @@ -1,21 +1,12 @@ -import { TypeElementsDesc } from './element'; +import { TypeElemDesc, TypeElement } from './element'; + -type TypeDataElement = { - uuid?: string; - x: number; - y: number; - w: number; - h: number; - type: T; - desc: TypeElementsDesc[T]; -} type TypeData = { - elements: TypeDataElement[] + elements: TypeElement[] selectedElements?: string[] // uuids } export { - TypeDataElement, TypeData } \ No newline at end of file diff --git a/packages/types/src/lib/element.ts b/packages/types/src/lib/element.ts index b3ac80994..b9ce72287 100644 --- a/packages/types/src/lib/element.ts +++ b/packages/types/src/lib/element.ts @@ -1,6 +1,16 @@ import { TypePaintData } from './paint'; -type TypeElementsDesc = { +type TypeElement = { + uuid?: string; + x: number; + y: number; + w: number; + h: number; + type: T; + desc: TypeElemDesc[T]; +} + +type TypeElemDesc = { text: TypeElemDescText, rect: TypeElemDescRect, circle: TypeElemDescCircle, @@ -33,5 +43,6 @@ export { TypeElemDescText, TypeElemDescRect, TypeElemDescCircle, - TypeElementsDesc, + TypeElemDesc, + TypeElement, } \ No newline at end of file From 8d78fc3219e7bfa98e178d1625c07b2a46e91120 Mon Sep 17 00:00:00 2001 From: chenshenhai Date: Wed, 26 May 2021 15:21:27 +0800 Subject: [PATCH 5/6] chore: update core/example --- docs/features/core.md | 1 + docs/features/idraw.md | 0 packages/core/example/index.html | 24 +++++++++++--------- packages/core/example/lib/scale.js | 27 ++++++++++++++++++++++ packages/core/example/lib/scroll.js | 35 +++++++++++++++++++++++++++++ packages/core/example/main.js | 12 +++++++++- packages/core/src/index.ts | 32 ++++++++++++++++++++++++++ packages/core/src/lib/element.ts | 28 +++++++++++++++++++++++ 8 files changed, 147 insertions(+), 12 deletions(-) create mode 100644 docs/features/core.md create mode 100644 docs/features/idraw.md create mode 100644 packages/core/example/lib/scale.js create mode 100644 packages/core/example/lib/scroll.js create mode 100644 packages/core/src/lib/element.ts diff --git a/docs/features/core.md b/docs/features/core.md new file mode 100644 index 000000000..aeda8b2f0 --- /dev/null +++ b/docs/features/core.md @@ -0,0 +1 @@ +- [x] \ No newline at end of file diff --git a/docs/features/idraw.md b/docs/features/idraw.md new file mode 100644 index 000000000..e69de29bb diff --git a/packages/core/example/index.html b/packages/core/example/index.html index e1f6b0ee1..48374d504 100644 --- a/packages/core/example/index.html +++ b/packages/core/example/index.html @@ -19,17 +19,19 @@
-
- scale - -
-
- scrollX - -
-
- scrollY - +
+
+ scale + +
+
+ scrollX + +
+
+ scrollY + +
diff --git a/packages/core/example/lib/scale.js b/packages/core/example/lib/scale.js new file mode 100644 index 000000000..a271ef638 --- /dev/null +++ b/packages/core/example/lib/scale.js @@ -0,0 +1,27 @@ +const input = document.querySelector('#scale'); +let hasInited = false; + +export function doScale(core, scale) { + if (hasInited === true) return; + if (scale > 0) { + input.value = scale; + core.scale(scale); + core.draw(); + } + input.addEventListener('change', () => { + const val = input.value * 1; + if (val > 0) { + core.scale(val); + core.draw(); + } + }); + hasInited = true; +} + +export function getScale() { + let val = 1; + if (input.value * 1 > 0) { + val = input.value * 1; + } + return val; +} \ No newline at end of file diff --git a/packages/core/example/lib/scroll.js b/packages/core/example/lib/scroll.js new file mode 100644 index 000000000..3a1c1a79f --- /dev/null +++ b/packages/core/example/lib/scroll.js @@ -0,0 +1,35 @@ +const inputX = document.querySelector('#scrollX'); +const inputY = document.querySelector('#scrollY'); +let hasInited = false; + +export function doScroll(core, conf = {}) { + if (hasInited === true) return; + + if (conf.scrollX >= 0) { + inputX.value = conf.scrollX; + core.scrollX(conf.scrollX); + core.draw(); + } + + if (conf.scrollY >= 0) { + inputY.value = conf.scrollY; + core.scrollY(conf.scrollY); + core.draw(); + } + + inputX.addEventListener('change', () => { + const val = inputX.value * 1; + if (val >= 0) { + core.scrollX(val); + core.draw(); + } + }); + inputY.addEventListener('change', () => { + const val = inputY.value * 1; + if (val >= 0) { + core.scrollY(val); + core.draw(); + } + }); + hasInited = true; +} \ No newline at end of file diff --git a/packages/core/example/main.js b/packages/core/example/main.js index f0ebb7b24..9bc0b45a2 100644 --- a/packages/core/example/main.js +++ b/packages/core/example/main.js @@ -1,12 +1,22 @@ import { getData } from './lib/data.js'; +import { doScale } from './lib/scale.js'; +import { doScroll } from './lib/scroll.js'; + const { Core } = window.iDraw; const data = getData(); const mount = document.querySelector('#mount'); +const defaultConf = { + scale: 0.5, + scrollX: 100, + scrollY: 200, +} const core = new Core(mount, { width: 600, height: 400, devicePixelRatio: 4 }); core.setData(data); -core.draw(); \ No newline at end of file +doScale(core, defaultConf.scale); +doScroll(core, defaultConf); + diff --git a/packages/core/src/index.ts b/packages/core/src/index.ts index 9654cf850..ddd4971a0 100644 --- a/packages/core/src/index.ts +++ b/packages/core/src/index.ts @@ -1,6 +1,7 @@ import { TypeData } from '@idraw/types'; import Board from '@idraw/board'; import Renderer from './lib/renderer'; +import { Element } from './lib/element'; type Options = { width: number; @@ -14,25 +15,56 @@ class Core { private _data: TypeData; private _opts: Options; private _renderer: Renderer; + private _element: Element; + private _hasInited: boolean = false; constructor(mount: HTMLDivElement, opts: Options) { this._data = { elements: [] }; this._opts = opts; this._board = new Board(mount, this._opts); this._renderer = new Renderer(this._board); + this._element = new Element(this._board.getContext()); + this._initEvent(); + this._hasInited = true; } draw() { this._renderer.render(this._data); } + selectElement(index: number) { + console.log('index'); + } + getData() { return this._data; } + scale(ratio: number) { + this._board.scale(ratio); + } + + scrollX(x: number) { + this._board.scrollX(x); + } + + scrollY(y: number) { + this._board.scrollY(y); + } + setData(data: TypeData) { return this._data = data; } + + private _initEvent() { + if (this._hasInited === true) { + return; + } + this._board.on('point', (p) => { + const idx = this._element.isPointInElement(p, this._data); + console.log('idx ====', idx); + }); + } } export default Core; \ No newline at end of file diff --git a/packages/core/src/lib/element.ts b/packages/core/src/lib/element.ts new file mode 100644 index 000000000..9b72ffe7a --- /dev/null +++ b/packages/core/src/lib/element.ts @@ -0,0 +1,28 @@ +import { TypeContext, TypePoint, TypeData } from '@idraw/types'; + +export class Element { + private _ctx: TypeContext; + + constructor(ctx: TypeContext) { + this._ctx = ctx; + } + + isPointInElement(p: TypePoint, data: TypeData) { + const ctx = this._ctx; + let idx = -1; + for (let i = data.elements.length - 1; i >= 0; i--) { + const ele = data.elements[i]; + ctx.beginPath(); + ctx.lineTo(ele.x, ele.y); + ctx.lineTo(ele.x + ele.w, ele.y); + ctx.lineTo(ele.x + ele.w, ele.y + ele.h); + ctx.lineTo(ele.x, ele.y + ele.h); + ctx.closePath(); + if (ctx.isPointInPath(p.x, p.y)) { + idx = i; + break; + } + } + return idx; + } +} From f3324106a5020cd2fbbbe9e4e59da8327e10ca5a Mon Sep 17 00:00:00 2001 From: chenshenhai Date: Wed, 26 May 2021 15:29:26 +0800 Subject: [PATCH 6/6] docs: add features --- docs/features/core.md | 13 ++++++++++++- docs/features/idraw.md | 3 +++ packages/core/example/lib/data.js | 8 ++------ packages/core/example/main.js | 3 +-- 4 files changed, 18 insertions(+), 9 deletions(-) diff --git a/docs/features/core.md b/docs/features/core.md index aeda8b2f0..f0e77d9a0 100644 --- a/docs/features/core.md +++ b/docs/features/core.md @@ -1 +1,12 @@ -- [x] \ No newline at end of file +- [x] Scale canvas +- [x] Scroll canvas +- [] Render data's elements + - [] Text + - [] Rect + - [] Circle + - [] Image + - [] Point +- [] Drag elements +- [] Move elements' index +- [] Transform elements's size +- [] Undo action record \ No newline at end of file diff --git a/docs/features/idraw.md b/docs/features/idraw.md index e69de29bb..593f526a5 100644 --- a/docs/features/idraw.md +++ b/docs/features/idraw.md @@ -0,0 +1,3 @@ +- [] Dashboard +- [] Data input +- [] Result export \ No newline at end of file diff --git a/packages/core/example/lib/data.js b/packages/core/example/lib/data.js index fef055963..6027f5dd4 100644 --- a/packages/core/example/lib/data.js +++ b/packages/core/example/lib/data.js @@ -44,10 +44,6 @@ const data = { ] } -function getData() { - return data; -} -export { - getData -}; \ No newline at end of file + +export default data; \ No newline at end of file diff --git a/packages/core/example/main.js b/packages/core/example/main.js index 9bc0b45a2..7e1d58fff 100644 --- a/packages/core/example/main.js +++ b/packages/core/example/main.js @@ -1,10 +1,9 @@ -import { getData } from './lib/data.js'; +import data from './lib/data.js'; import { doScale } from './lib/scale.js'; import { doScroll } from './lib/scroll.js'; const { Core } = window.iDraw; -const data = getData(); const mount = document.querySelector('#mount'); const defaultConf = { scale: 0.5,