Merge pull request #351 from idrawjs/dev-v0.4

refactor: refactor @idraw/renderer and migrate @idraw/board to @idraw/core
This commit is contained in:
Deepsea 2025-04-13 17:01:31 +08:00 committed by GitHub
commit 342948b9a5
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
75 changed files with 3615 additions and 6284 deletions

View file

@ -31,9 +31,6 @@ jobs:
- run: npm publish --provenance --access public -w ./packages/renderer
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
- run: npm publish --provenance --access public -w ./packages/board
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
- run: npm publish --provenance --access public -w ./packages/core
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}

View file

@ -1,6 +1,6 @@
{
"private": false,
"version": "0.4.0-beta.39",
"version": "0.4.0-beta.40",
"workspaces": [
"packages/*"
],
@ -30,47 +30,47 @@
"upgrade:version": "npm run version:reset && pnpm i"
},
"devDependencies": {
"@babel/core": "^7.25.2",
"@babel/preset-env": "^7.25.3",
"@babel/preset-typescript": "^7.24.7",
"@babel/core": "^7.26.10",
"@babel/preset-env": "^7.26.9",
"@babel/preset-typescript": "^7.27.0",
"@rollup/plugin-json": "^6.1.0",
"@types/glob": "^8.1.0",
"@types/jest": "^29.5.12",
"@types/jest": "^29.5.14",
"@types/koa-compose": "^3.2.8",
"@types/node": "^22.1.0",
"@types/node": "^22.14.1",
"@types/serve-handler": "^6.1.4",
"@typescript-eslint/eslint-plugin": "^8.0.0",
"@typescript-eslint/parser": "^8.0.0",
"@vitejs/plugin-react": "^4.3.1",
"@typescript-eslint/eslint-plugin": "^8.29.1",
"@typescript-eslint/parser": "^8.29.1",
"@vitejs/plugin-react": "^4.3.4",
"babel-jest": "^29.7.0",
"chalk": "^5.3.0",
"dotenv": "^16.4.5",
"chalk": "^5.4.1",
"dotenv": "^16.5.0",
"enquirer": "^2.4.1",
"esbuild": "^0.23.0",
"eslint": "^9.8.0",
"execa": "^9.3.0",
"fs-extra": "^11.2.0",
"glob": "^11.0.0",
"esbuild": "^0.25.2",
"eslint": "^9.24.0",
"execa": "^9.5.2",
"fs-extra": "^11.3.0",
"glob": "^11.0.1",
"http-server": "^14.1.1",
"husky": "^9.1.4",
"husky": "^9.1.7",
"jest": "^29.7.0",
"jest-canvas-mock": "^2.5.2",
"jest-environment-jsdom": "^29.7.0",
"jimp": "^0.22.12",
"jimp": "^1.6.0",
"koa-compose": "^4.1.0",
"less": "^4.2.0",
"pixelmatch": "^6.0.0",
"less": "^4.3.0",
"pixelmatch": "^7.1.0",
"pngjs": "^7.0.0",
"puppeteer": "^22.6.4",
"rollup": "^4.20.0",
"rollup-plugin-dts": "^6.1.1",
"rollup-plugin-esbuild": "^6.1.1",
"serve-handler": "^6.1.5",
"terser": "^5.31.3",
"ts-morph": "^23.0.0",
"puppeteer": "^24.6.1",
"rollup": "^4.40.0",
"rollup-plugin-dts": "^6.2.1",
"rollup-plugin-esbuild": "^6.2.1",
"serve-handler": "^6.1.6",
"terser": "^5.39.0",
"ts-morph": "^25.0.1",
"ts-node": "^10.9.2",
"tslib": "^2.6.3",
"typescript": "^5.5.4",
"vite": "^5.3.5"
"tslib": "^2.8.1",
"typescript": "^5.8.3",
"vite": "^6.2.6"
}
}

View file

@ -1,3 +0,0 @@
# @idraw/board
[![Node.js CI](https://github.com/idrawjs/idraw/actions/workflows/node.js.yml/badge.svg?branch=main)](https://github.com/idrawjs/idraw/actions/workflows/node.js.yml)

View file

@ -1,197 +0,0 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`@idraw/board context 1`] = `
[
{
"props": {
"height": 1600,
"width": 2400,
"x": 0,
"y": 0,
},
"transform": [
1,
0,
0,
1,
0,
0,
],
"type": "clearRect",
},
{
"props": {
"height": 1600,
"width": 2400,
"x": 0,
"y": 0,
},
"transform": [
1,
0,
0,
1,
0,
0,
],
"type": "fillRect",
},
{
"props": {
"height": 480,
"width": 800,
"x": 40,
"y": 40,
},
"transform": [
1,
0,
0,
1,
0,
0,
],
"type": "fillRect",
},
{
"props": {
"height": 480,
"width": 800,
"x": 320,
"y": 320,
},
"transform": [
1,
0,
0,
1,
0,
0,
],
"type": "fillRect",
},
{
"props": {
"height": 480,
"width": 800,
"x": 640,
"y": 640,
},
"transform": [
1,
0,
0,
1,
0,
0,
],
"type": "fillRect",
},
{
"props": {
"height": 400,
"width": 800,
"x": 1560,
"y": 1160,
},
"transform": [
1,
0,
0,
1,
0,
0,
],
"type": "fillRect",
},
]
`;
exports[`@idraw/board context 2`] = `
[
{
"props": {
"height": 1600,
"width": 2400,
"x": 0,
"y": 0,
},
"transform": [
1,
0,
0,
1,
0,
0,
],
"type": "clearRect",
},
{
"props": {
"height": 1600,
"width": 2400,
"x": 0,
"y": 0,
},
"transform": [
1,
0,
0,
1,
0,
0,
],
"type": "clearRect",
},
{
"props": {
"dHeight": 3600,
"dWidth": 4000,
"dx": 0,
"dy": 0,
"img": <canvas
height="3600"
width="4000"
/>,
"sHeight": 3600,
"sWidth": 4000,
"sx": 0,
"sy": 0,
},
"transform": [
1,
0,
0,
1,
0,
0,
],
"type": "drawImage",
},
{
"props": {
"dHeight": 3600,
"dWidth": 4000,
"dx": 0,
"dy": 0,
"img": <canvas
height="3600"
width="4000"
/>,
"sHeight": 3600,
"sWidth": 4000,
"sx": 0,
"sy": 0,
},
"transform": [
1,
0,
0,
1,
0,
0,
],
"type": "drawImage",
},
]
`;

View file

@ -1,197 +0,0 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`@idraw/board getTransform 1`] = `
[
{
"props": {
"height": 1600,
"width": 2400,
"x": 0,
"y": 0,
},
"transform": [
1,
0,
0,
1,
0,
0,
],
"type": "clearRect",
},
{
"props": {
"height": 1600,
"width": 2400,
"x": 0,
"y": 0,
},
"transform": [
1,
0,
0,
1,
0,
0,
],
"type": "fillRect",
},
{
"props": {
"height": 480,
"width": 800,
"x": 40,
"y": 40,
},
"transform": [
1,
0,
0,
1,
0,
0,
],
"type": "fillRect",
},
{
"props": {
"height": 480,
"width": 800,
"x": 320,
"y": 320,
},
"transform": [
1,
0,
0,
1,
0,
0,
],
"type": "fillRect",
},
{
"props": {
"height": 480,
"width": 800,
"x": 640,
"y": 640,
},
"transform": [
1,
0,
0,
1,
0,
0,
],
"type": "fillRect",
},
{
"props": {
"height": 400,
"width": 800,
"x": 1560,
"y": 1160,
},
"transform": [
1,
0,
0,
1,
0,
0,
],
"type": "fillRect",
},
]
`;
exports[`@idraw/board getTransform 2`] = `
[
{
"props": {
"height": 1600,
"width": 2400,
"x": 0,
"y": 0,
},
"transform": [
1,
0,
0,
1,
0,
0,
],
"type": "clearRect",
},
{
"props": {
"height": 1600,
"width": 2400,
"x": 0,
"y": 0,
},
"transform": [
1,
0,
0,
1,
0,
0,
],
"type": "clearRect",
},
{
"props": {
"dHeight": 1600,
"dWidth": 2400,
"dx": -2400,
"dy": -1600,
"img": <canvas
height="1600"
width="2400"
/>,
"sHeight": 1600,
"sWidth": 2400,
"sx": 0,
"sy": 0,
},
"transform": [
1,
0,
0,
1,
0,
0,
],
"type": "drawImage",
},
{
"props": {
"dHeight": 1600,
"dWidth": 2400,
"dx": -2400,
"dy": -1600,
"img": <canvas
height="1600"
width="2400"
/>,
"sHeight": 1600,
"sWidth": 2400,
"sx": 0,
"sy": 0,
},
"transform": [
1,
0,
0,
1,
0,
0,
],
"type": "drawImage",
},
]
`;

View file

@ -1,785 +0,0 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`@idraw/board scale 001 1`] = `
[
{
"props": {
"height": 1600,
"width": 2400,
"x": 0,
"y": 0,
},
"transform": [
1,
0,
0,
1,
0,
0,
],
"type": "clearRect",
},
{
"props": {
"height": 1600,
"width": 2400,
"x": 0,
"y": 0,
},
"transform": [
1,
0,
0,
1,
0,
0,
],
"type": "fillRect",
},
{
"props": {
"height": 480,
"width": 800,
"x": 40,
"y": 40,
},
"transform": [
1,
0,
0,
1,
0,
0,
],
"type": "fillRect",
},
{
"props": {
"height": 480,
"width": 800,
"x": 320,
"y": 320,
},
"transform": [
1,
0,
0,
1,
0,
0,
],
"type": "fillRect",
},
{
"props": {
"height": 480,
"width": 800,
"x": 640,
"y": 640,
},
"transform": [
1,
0,
0,
1,
0,
0,
],
"type": "fillRect",
},
{
"props": {
"height": 400,
"width": 800,
"x": 1560,
"y": 1160,
},
"transform": [
1,
0,
0,
1,
0,
0,
],
"type": "fillRect",
},
]
`;
exports[`@idraw/board scale 001 2`] = `
[
{
"props": {
"height": 1600,
"width": 2400,
"x": 0,
"y": 0,
},
"transform": [
1,
0,
0,
1,
0,
0,
],
"type": "clearRect",
},
{
"props": {
"height": 1600,
"width": 2400,
"x": 0,
"y": 0,
},
"transform": [
1,
0,
0,
1,
0,
0,
],
"type": "clearRect",
},
{
"props": {
"dHeight": 3600,
"dWidth": 4000,
"dx": 200,
"dy": 0,
"img": <canvas
height="3600"
width="4000"
/>,
"sHeight": 3600,
"sWidth": 4000,
"sx": 0,
"sy": 0,
},
"transform": [
1,
0,
0,
1,
0,
0,
],
"type": "drawImage",
},
{
"props": {
"dHeight": 3600,
"dWidth": 4000,
"dx": 200,
"dy": 0,
"img": <canvas
height="3600"
width="4000"
/>,
"sHeight": 3600,
"sWidth": 4000,
"sx": 0,
"sy": 0,
},
"transform": [
1,
0,
0,
1,
0,
0,
],
"type": "drawImage",
},
]
`;
exports[`@idraw/board scale 002 1`] = `
[
{
"props": {
"height": 1600,
"width": 2400,
"x": 0,
"y": 0,
},
"transform": [
1,
0,
0,
1,
0,
0,
],
"type": "clearRect",
},
{
"props": {
"height": 1600,
"width": 2400,
"x": 0,
"y": 0,
},
"transform": [
1,
0,
0,
1,
0,
0,
],
"type": "fillRect",
},
{
"props": {
"height": 480,
"width": 800,
"x": 40,
"y": 40,
},
"transform": [
1,
0,
0,
1,
0,
0,
],
"type": "fillRect",
},
{
"props": {
"height": 480,
"width": 800,
"x": 320,
"y": 320,
},
"transform": [
1,
0,
0,
1,
0,
0,
],
"type": "fillRect",
},
{
"props": {
"height": 480,
"width": 800,
"x": 640,
"y": 640,
},
"transform": [
1,
0,
0,
1,
0,
0,
],
"type": "fillRect",
},
{
"props": {
"height": 400,
"width": 800,
"x": 1560,
"y": 1160,
},
"transform": [
1,
0,
0,
1,
0,
0,
],
"type": "fillRect",
},
]
`;
exports[`@idraw/board scale 002 2`] = `
[
{
"props": {
"height": 1600,
"width": 2400,
"x": 0,
"y": 0,
},
"transform": [
1,
0,
0,
1,
0,
0,
],
"type": "clearRect",
},
{
"props": {
"height": 1600,
"width": 2400,
"x": 0,
"y": 0,
},
"transform": [
1,
0,
0,
1,
0,
0,
],
"type": "clearRect",
},
{
"props": {
"dHeight": 2400,
"dWidth": 4800,
"dx": 0,
"dy": 200,
"img": <canvas
height="2400"
width="4800"
/>,
"sHeight": 2400,
"sWidth": 4800,
"sx": 0,
"sy": 0,
},
"transform": [
1,
0,
0,
1,
0,
0,
],
"type": "drawImage",
},
{
"props": {
"dHeight": 2400,
"dWidth": 4800,
"dx": 0,
"dy": 200,
"img": <canvas
height="2400"
width="4800"
/>,
"sHeight": 2400,
"sWidth": 4800,
"sx": 0,
"sy": 0,
},
"transform": [
1,
0,
0,
1,
0,
0,
],
"type": "drawImage",
},
]
`;
exports[`@idraw/board scale 003 1`] = `
[
{
"props": {
"height": 1600,
"width": 2400,
"x": 0,
"y": 0,
},
"transform": [
1,
0,
0,
1,
0,
0,
],
"type": "clearRect",
},
{
"props": {
"height": 1600,
"width": 2400,
"x": 0,
"y": 0,
},
"transform": [
1,
0,
0,
1,
0,
0,
],
"type": "fillRect",
},
{
"props": {
"height": 480,
"width": 800,
"x": 40,
"y": 40,
},
"transform": [
1,
0,
0,
1,
0,
0,
],
"type": "fillRect",
},
{
"props": {
"height": 480,
"width": 800,
"x": 320,
"y": 320,
},
"transform": [
1,
0,
0,
1,
0,
0,
],
"type": "fillRect",
},
{
"props": {
"height": 480,
"width": 800,
"x": 640,
"y": 640,
},
"transform": [
1,
0,
0,
1,
0,
0,
],
"type": "fillRect",
},
{
"props": {
"height": 400,
"width": 800,
"x": 1560,
"y": 1160,
},
"transform": [
1,
0,
0,
1,
0,
0,
],
"type": "fillRect",
},
]
`;
exports[`@idraw/board scale 003 2`] = `
[
{
"props": {
"height": 1600,
"width": 2400,
"x": 0,
"y": 0,
},
"transform": [
1,
0,
0,
1,
0,
0,
],
"type": "clearRect",
},
{
"props": {
"height": 1600,
"width": 2400,
"x": 0,
"y": 0,
},
"transform": [
1,
0,
0,
1,
0,
0,
],
"type": "clearRect",
},
{
"props": {
"dHeight": 2400,
"dWidth": 4000,
"dx": 0,
"dy": 0,
"img": <canvas
height="2400"
width="4000"
/>,
"sHeight": 2400,
"sWidth": 4000,
"sx": 0,
"sy": 0,
},
"transform": [
1,
0,
0,
1,
0,
0,
],
"type": "drawImage",
},
{
"props": {
"dHeight": 2400,
"dWidth": 4000,
"dx": 0,
"dy": 0,
"img": <canvas
height="2400"
width="4000"
/>,
"sHeight": 2400,
"sWidth": 4000,
"sx": 0,
"sy": 0,
},
"transform": [
1,
0,
0,
1,
0,
0,
],
"type": "drawImage",
},
]
`;
exports[`@idraw/board scale 1`] = `
[
{
"props": {
"height": 1600,
"width": 2400,
"x": 0,
"y": 0,
},
"transform": [
1,
0,
0,
1,
0,
0,
],
"type": "clearRect",
},
{
"props": {
"height": 1600,
"width": 2400,
"x": 0,
"y": 0,
},
"transform": [
1,
0,
0,
1,
0,
0,
],
"type": "fillRect",
},
{
"props": {
"height": 480,
"width": 800,
"x": 40,
"y": 40,
},
"transform": [
1,
0,
0,
1,
0,
0,
],
"type": "fillRect",
},
{
"props": {
"height": 480,
"width": 800,
"x": 320,
"y": 320,
},
"transform": [
1,
0,
0,
1,
0,
0,
],
"type": "fillRect",
},
{
"props": {
"height": 480,
"width": 800,
"x": 640,
"y": 640,
},
"transform": [
1,
0,
0,
1,
0,
0,
],
"type": "fillRect",
},
{
"props": {
"height": 400,
"width": 800,
"x": 1560,
"y": 1160,
},
"transform": [
1,
0,
0,
1,
0,
0,
],
"type": "fillRect",
},
]
`;
exports[`@idraw/board scale 2`] = `
[
{
"props": {
"height": 1600,
"width": 2400,
"x": 0,
"y": 0,
},
"transform": [
1,
0,
0,
1,
0,
0,
],
"type": "clearRect",
},
{
"props": {
"height": 1600,
"width": 2400,
"x": 0,
"y": 0,
},
"transform": [
1,
0,
0,
1,
0,
0,
],
"type": "clearRect",
},
{
"props": {
"dHeight": 1600,
"dWidth": 2400,
"dx": 600,
"dy": 400,
"img": <canvas
height="1600"
width="2400"
/>,
"sHeight": 1600,
"sWidth": 2400,
"sx": 0,
"sy": 0,
},
"transform": [
1,
0,
0,
1,
0,
0,
],
"type": "drawImage",
},
{
"props": {
"dHeight": 1600,
"dWidth": 2400,
"dx": 600,
"dy": 400,
"img": <canvas
height="1600"
width="2400"
/>,
"sHeight": 1600,
"sWidth": 2400,
"sx": 0,
"sy": 0,
},
"transform": [
1,
0,
0,
1,
0,
0,
],
"type": "drawImage",
},
]
`;

View file

@ -1,197 +0,0 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`@idraw/board scroll 1`] = `
[
{
"props": {
"height": 1600,
"width": 2400,
"x": 0,
"y": 0,
},
"transform": [
1,
0,
0,
1,
0,
0,
],
"type": "clearRect",
},
{
"props": {
"height": 1600,
"width": 2400,
"x": 0,
"y": 0,
},
"transform": [
1,
0,
0,
1,
0,
0,
],
"type": "fillRect",
},
{
"props": {
"height": 480,
"width": 800,
"x": 40,
"y": 40,
},
"transform": [
1,
0,
0,
1,
0,
0,
],
"type": "fillRect",
},
{
"props": {
"height": 480,
"width": 800,
"x": 320,
"y": 320,
},
"transform": [
1,
0,
0,
1,
0,
0,
],
"type": "fillRect",
},
{
"props": {
"height": 480,
"width": 800,
"x": 640,
"y": 640,
},
"transform": [
1,
0,
0,
1,
0,
0,
],
"type": "fillRect",
},
{
"props": {
"height": 400,
"width": 800,
"x": 1560,
"y": 1160,
},
"transform": [
1,
0,
0,
1,
0,
0,
],
"type": "fillRect",
},
]
`;
exports[`@idraw/board scroll 2`] = `
[
{
"props": {
"height": 1600,
"width": 2400,
"x": 0,
"y": 0,
},
"transform": [
1,
0,
0,
1,
0,
0,
],
"type": "clearRect",
},
{
"props": {
"height": 1600,
"width": 2400,
"x": 0,
"y": 0,
},
"transform": [
1,
0,
0,
1,
0,
0,
],
"type": "clearRect",
},
{
"props": {
"dHeight": 1600,
"dWidth": 2400,
"dx": -2400,
"dy": -1600,
"img": <canvas
height="1600"
width="2400"
/>,
"sHeight": 1600,
"sWidth": 2400,
"sx": 0,
"sy": 0,
},
"transform": [
1,
0,
0,
1,
0,
0,
],
"type": "drawImage",
},
{
"props": {
"dHeight": 1600,
"dWidth": 2400,
"dx": -2400,
"dy": -1600,
"img": <canvas
height="1600"
width="2400"
/>,
"sHeight": 1600,
"sWidth": 2400,
"sx": 0,
"sy": 0,
},
"transform": [
1,
0,
0,
1,
0,
0,
],
"type": "drawImage",
},
]
`;

View file

@ -1,737 +0,0 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`@idraw/board scroll 1`] = `
[
{
"props": {
"height": 1600,
"width": 2400,
"x": 0,
"y": 0,
},
"transform": [
1,
0,
0,
1,
0,
0,
],
"type": "clearRect",
},
{
"props": {
"height": 1600,
"width": 2400,
"x": 0,
"y": 0,
},
"transform": [
1,
0,
0,
1,
0,
0,
],
"type": "fillRect",
},
{
"props": {
"height": 480,
"width": 800,
"x": 40,
"y": 40,
},
"transform": [
1,
0,
0,
1,
0,
0,
],
"type": "fillRect",
},
{
"props": {
"height": 480,
"width": 800,
"x": 320,
"y": 320,
},
"transform": [
1,
0,
0,
1,
0,
0,
],
"type": "fillRect",
},
{
"props": {
"height": 480,
"width": 800,
"x": 640,
"y": 640,
},
"transform": [
1,
0,
0,
1,
0,
0,
],
"type": "fillRect",
},
{
"props": {
"height": 400,
"width": 800,
"x": 1560,
"y": 1160,
},
"transform": [
1,
0,
0,
1,
0,
0,
],
"type": "fillRect",
},
]
`;
exports[`@idraw/board scroll 2`] = `
[
{
"props": {
"height": 1600,
"width": 2400,
"x": 0,
"y": 0,
},
"transform": [
1,
0,
0,
1,
0,
0,
],
"type": "clearRect",
},
{
"props": {
"height": 1600,
"width": 2400,
"x": 0,
"y": 0,
},
"transform": [
1,
0,
0,
1,
0,
0,
],
"type": "clearRect",
},
{
"props": {
"dHeight": 1600,
"dWidth": 2400,
"dx": -2400,
"dy": -1600,
"img": <canvas
height="1600"
width="2400"
/>,
"sHeight": 1600,
"sWidth": 2400,
"sx": 0,
"sy": 0,
},
"transform": [
1,
0,
0,
1,
0,
0,
],
"type": "drawImage",
},
{
"props": {
"dHeight": 1600,
"dWidth": 2400,
"dx": -2400,
"dy": -1600,
"img": <canvas
height="1600"
width="2400"
/>,
"sHeight": 1600,
"sWidth": 2400,
"sx": 0,
"sy": 0,
},
"transform": [
1,
0,
0,
1,
0,
0,
],
"type": "drawImage",
},
{
"props": {
"height": 80,
"width": 2400,
"x": 0,
"y": 1520,
},
"transform": [
1,
0,
0,
1,
0,
0,
],
"type": "fillRect",
},
{
"props": {
"fillRule": "nonzero",
"path": [
{
"props": {},
"transform": [
1,
0,
0,
1,
0,
0,
],
"type": "beginPath",
},
{
"props": {
"x": 2220,
"y": 1541,
},
"transform": [
1,
0,
0,
1,
0,
0,
],
"type": "moveTo",
},
{
"props": {
"cpx1": 2400,
"cpx2": 2400,
"cpy1": 1541,
"cpy2": 1581,
"radius": 20,
},
"transform": [
1,
0,
0,
1,
0,
0,
],
"type": "arcTo",
},
{
"props": {
"cpx1": 2400,
"cpx2": 2200,
"cpy1": 1581,
"cpy2": 1581,
"radius": 20,
},
"transform": [
1,
0,
0,
1,
0,
0,
],
"type": "arcTo",
},
{
"props": {
"cpx1": 2200,
"cpx2": 2200,
"cpy1": 1581,
"cpy2": 1541,
"radius": 20,
},
"transform": [
1,
0,
0,
1,
0,
0,
],
"type": "arcTo",
},
{
"props": {
"cpx1": 2200,
"cpx2": 2400,
"cpy1": 1541,
"cpy2": 1541,
"radius": 20,
},
"transform": [
1,
0,
0,
1,
0,
0,
],
"type": "arcTo",
},
{
"props": {},
"transform": [
1,
0,
0,
1,
0,
0,
],
"type": "closePath",
},
],
},
"transform": [
1,
0,
0,
1,
0,
0,
],
"type": "fill",
},
{
"props": {
"path": [
{
"props": {},
"transform": [
1,
0,
0,
1,
0,
0,
],
"type": "beginPath",
},
{
"props": {
"x": 2220,
"y": 1541,
},
"transform": [
1,
0,
0,
1,
0,
0,
],
"type": "moveTo",
},
{
"props": {
"cpx1": 2400,
"cpx2": 2400,
"cpy1": 1541,
"cpy2": 1581,
"radius": 20,
},
"transform": [
1,
0,
0,
1,
0,
0,
],
"type": "arcTo",
},
{
"props": {
"cpx1": 2400,
"cpx2": 2200,
"cpy1": 1581,
"cpy2": 1581,
"radius": 20,
},
"transform": [
1,
0,
0,
1,
0,
0,
],
"type": "arcTo",
},
{
"props": {
"cpx1": 2200,
"cpx2": 2200,
"cpy1": 1581,
"cpy2": 1541,
"radius": 20,
},
"transform": [
1,
0,
0,
1,
0,
0,
],
"type": "arcTo",
},
{
"props": {
"cpx1": 2200,
"cpx2": 2400,
"cpy1": 1541,
"cpy2": 1541,
"radius": 20,
},
"transform": [
1,
0,
0,
1,
0,
0,
],
"type": "arcTo",
},
{
"props": {},
"transform": [
1,
0,
0,
1,
0,
0,
],
"type": "closePath",
},
],
},
"transform": [
1,
0,
0,
1,
0,
0,
],
"type": "stroke",
},
{
"props": {
"height": 1600,
"width": 80,
"x": 2320,
"y": 0,
},
"transform": [
1,
0,
0,
1,
0,
0,
],
"type": "fillRect",
},
{
"props": {
"fillRule": "nonzero",
"path": [
{
"props": {},
"transform": [
1,
0,
0,
1,
0,
0,
],
"type": "beginPath",
},
{
"props": {
"x": 2361,
"y": 1400,
},
"transform": [
1,
0,
0,
1,
0,
0,
],
"type": "moveTo",
},
{
"props": {
"cpx1": 2381,
"cpx2": 2381,
"cpy1": 1400,
"cpy2": 1600,
"radius": 20,
},
"transform": [
1,
0,
0,
1,
0,
0,
],
"type": "arcTo",
},
{
"props": {
"cpx1": 2381,
"cpx2": 2341,
"cpy1": 1600,
"cpy2": 1600,
"radius": 20,
},
"transform": [
1,
0,
0,
1,
0,
0,
],
"type": "arcTo",
},
{
"props": {
"cpx1": 2341,
"cpx2": 2341,
"cpy1": 1600,
"cpy2": 1400,
"radius": 20,
},
"transform": [
1,
0,
0,
1,
0,
0,
],
"type": "arcTo",
},
{
"props": {
"cpx1": 2341,
"cpx2": 2381,
"cpy1": 1400,
"cpy2": 1400,
"radius": 20,
},
"transform": [
1,
0,
0,
1,
0,
0,
],
"type": "arcTo",
},
{
"props": {},
"transform": [
1,
0,
0,
1,
0,
0,
],
"type": "closePath",
},
],
},
"transform": [
1,
0,
0,
1,
0,
0,
],
"type": "fill",
},
{
"props": {
"path": [
{
"props": {},
"transform": [
1,
0,
0,
1,
0,
0,
],
"type": "beginPath",
},
{
"props": {
"x": 2361,
"y": 1400,
},
"transform": [
1,
0,
0,
1,
0,
0,
],
"type": "moveTo",
},
{
"props": {
"cpx1": 2381,
"cpx2": 2381,
"cpy1": 1400,
"cpy2": 1600,
"radius": 20,
},
"transform": [
1,
0,
0,
1,
0,
0,
],
"type": "arcTo",
},
{
"props": {
"cpx1": 2381,
"cpx2": 2341,
"cpy1": 1600,
"cpy2": 1600,
"radius": 20,
},
"transform": [
1,
0,
0,
1,
0,
0,
],
"type": "arcTo",
},
{
"props": {
"cpx1": 2341,
"cpx2": 2341,
"cpy1": 1600,
"cpy2": 1400,
"radius": 20,
},
"transform": [
1,
0,
0,
1,
0,
0,
],
"type": "arcTo",
},
{
"props": {
"cpx1": 2341,
"cpx2": 2381,
"cpy1": 1400,
"cpy2": 1400,
"radius": 20,
},
"transform": [
1,
0,
0,
1,
0,
0,
],
"type": "arcTo",
},
{
"props": {},
"transform": [
1,
0,
0,
1,
0,
0,
],
"type": "closePath",
},
],
},
"transform": [
1,
0,
0,
1,
0,
0,
],
"type": "stroke",
},
]
`;

View file

@ -1,47 +0,0 @@
export function getData() {
const data = {
elements: [
{
x: 10,
y: 10,
w: 200,
h: 120,
type: 'rect',
detail: {
color: '#f0f0f0'
}
},
{
x: 80,
y: 80,
w: 200,
h: 120,
type: 'rect',
detail: {
color: '#cccccc'
}
},
{
x: 160,
y: 160,
w: 200,
h: 120,
type: 'rect',
detail: {
color: '#c0c0c0'
}
},
{
x: 400 - 10,
y: 300 - 10,
w: 200,
h: 100,
type: 'rect',
detail: {
color: '#e0e0e0'
}
}
]
};
return data;
}

View file

@ -1,42 +0,0 @@
import Board from './../src';
import { getData } from './data';
describe('@idraw/board', () => {
test('context', async () => {
document.body.innerHTML = `
<div id="mount"></div>
`;
const opts = {
width: 600,
height: 400,
contextWidth: 1000,
contextHeight: 900,
devicePixelRatio: 4
};
const mount = document.querySelector('#mount') as HTMLDivElement;
const board = new Board(mount, opts);
const ctx = board.getContext();
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);
});
board.draw();
const originCtx = board.getOriginContext2D();
// @ts-ignore;
const originCalls = originCtx.__getDrawCalls();
expect(originCalls).toMatchSnapshot();
const displayCtx = board.getDisplayContext2D();
// @ts-ignore;
const displayCalls = displayCtx.__getDrawCalls();
expect(displayCalls).toMatchSnapshot();
});
});

View file

@ -1,22 +0,0 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`@idraw/board: src/lib/style getStyle 1`] = `
{
"height": "20px",
"margin-top": "123px",
"overflow": "auto",
"width": "12px",
}
`;
exports[`@idraw/board: src/lib/style setDomTransform 1`] = `
<div
style="transform: matrix(1, 2, -1, 1, 80, 90);"
/>
`;
exports[`@idraw/board: src/lib/style setStyle 1`] = `
<div
style="width:12px;height:20px;overflow:auto;margin-top:123px;"
/>
`;

View file

@ -1,108 +0,0 @@
import { TypePoint } from '@idraw/types';
import { BoardEvent } from './../../src/lib/event';
describe('@idraw/board: src/lib/event', () => {
// 'doubleClick': TypePoint;
// 'hover': TypePoint;
// 'leave': void;
// 'point': TypePoint;
// 'move': TypePoint;
// 'moveStart': TypePoint;
// 'moveEnd': TypePoint;
// 'wheelX': number;
// 'wheelY': number;
test('BoardEvent event:off', async () => {
const event = new BoardEvent();
const point = { x: 123, y: 456 }
const callback = (p: TypePoint) => {
expect(p).toStrictEqual(point);
}
event.on('doubleClick', callback);
event.trigger('doubleClick', point)
event.off('doubleClick', callback);
});
test('BoardEvent event:doubleClick', async () => {
const event = new BoardEvent();
const point = { x: 123, y: 456 }
event.on('doubleClick', (p) => {
expect(p).toStrictEqual(point);
});
event.trigger('doubleClick', point)
});
test('BoardEvent event:hover', async () => {
const event = new BoardEvent();
const point = { x: 123, y: 456 }
event.on('hover', (p) => {
expect(p).toStrictEqual(point);
});
event.trigger('hover', point)
});
test('BoardEvent event:leave', async () => {
const event = new BoardEvent();
event.on('leave', (e) => {
expect(e).toStrictEqual(undefined);
});
event.trigger('leave', undefined)
});
test('BoardEvent event:point', async () => {
const event = new BoardEvent();
const point = { x: 123, y: 456 }
event.on('point', (p) => {
expect(p).toStrictEqual(point);
});
event.trigger('point', point)
});
test('BoardEvent event:move', async () => {
const event = new BoardEvent();
const point = { x: 123, y: 456 }
event.on('move', (p) => {
expect(p).toStrictEqual(point);
});
event.trigger('move', point)
});
test('BoardEvent event:moveStart', async () => {
const event = new BoardEvent();
const point = { x: 123, y: 456 }
event.on('moveStart', (p) => {
expect(p).toStrictEqual(point);
});
event.trigger('moveStart', point)
});
test('BoardEvent event:moveEnd', async () => {
const event = new BoardEvent();
const point = { x: 123, y: 456 }
event.on('moveEnd', (p) => {
expect(p).toStrictEqual(point);
});
event.trigger('moveEnd', point)
});
test('BoardEvent event:wheelX', async () => {
const event = new BoardEvent();
const num = 123
event.on('wheelX', (e) => {
expect(e).toStrictEqual(num);
});
event.trigger('wheelX', num)
});
test('BoardEvent event:wheelY', async () => {
const event = new BoardEvent();
const num = 123
event.on('wheelY', (e) => {
expect(e).toStrictEqual(num);
});
event.trigger('wheelY', num)
});
});

View file

@ -1,81 +0,0 @@
import {
mergeCSS2StyleAttr, setStyle, getStyle, getDomTransform,
setDomTransform,
} from './../../src/lib/style';
describe('@idraw/board: src/lib/style', () => {
test('mergeCSS2StyleAttr', () => {
const str = mergeCSS2StyleAttr({
'width': '12px',
'height': '20px',
'overflow': 'auto',
'margin-top': '123px',
});
expect(str).toStrictEqual('width:12px; height:20px; overflow:auto; margin-top:123px;');
});
test('setStyle', () => {
const div = document.createElement('div');
setStyle(div, {
'width': '12px',
'height': '20px',
'overflow': 'auto',
'margin-top': '123px',
});
expect(div).toMatchSnapshot();
});
test('getStyle', () => {
const div = document.createElement('div');
setStyle(div, {
'width': '12px',
'height': '20px',
'overflow': 'auto',
'margin-top': '123px',
});
expect(getStyle(div)).toMatchSnapshot({
'width': '12px',
'height': '20px',
'overflow': 'auto',
'margin-top': '123px',
});
});
test('setDomTransform', () => {
// transform: matrix( scaleX(), skewY(), skewX(), scaleY(), translateX(), translateY() )
// matrix(1, 2, -1, 1, 80, 80)
const div = document.createElement('div');
setDomTransform(div, {
scaleX: 1,
skewY: 2,
skewX: -1,
scaleY: 1,
translateX: 80,
translateY: 90,
});
expect(div).toMatchSnapshot();
})
test('getDomTransform', () => {
// transform: matrix( scaleX(), skewY(), skewX(), scaleY(), translateX(), translateY() )
// matrix(1, 2, -1, 1, 80, 80)
const div = document.createElement('div');
setDomTransform(div, {
scaleX: 1,
skewY: 2,
skewX: -1,
scaleY: 1,
translateX: 80,
translateY: 90,
});
expect(getDomTransform(div)).toStrictEqual({
scaleX: 1,
skewY: 2,
skewX: -1,
scaleY: 1,
translateX: 80,
translateY: 90,
});
})
})

View file

@ -1,63 +0,0 @@
import Board from '../src';
import { getData } from './data';
describe('@idraw/board', () => {
document.body.innerHTML = `
<div id="mount"></div>
`;
const opts = {
width: 600,
height: 400,
contextWidth: 600,
contextHeight: 400,
devicePixelRatio: 4
};
const mount = document.querySelector('#mount') as HTMLDivElement;
const board = new Board(mount, opts);
const ctx = board.getContext();
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);
});
test('getTransform', async () => {
const resultScale = board.scale(2);
expect(resultScale).toStrictEqual({
position: { top: 0, bottom: -400, left: 0, right: -600 },
size: { x: 0, y: 0, w: 1200, h: 800 }
});
const resultX = board.scrollX(-600);
expect(resultX).toStrictEqual({
position: { top: 0, bottom: -400, left: -600, right: 0 },
size: { x: -1200, y: 0, w: 1200, h: 800 }
});
const resultY = board.scrollY(-400);
expect(resultY).toStrictEqual({
position: { top: -400, bottom: 0, left: -600, right: 0 },
size: { x: -1200, y: -800, w: 1200, h: 800 }
});
board.draw();
const originCtx = board.getOriginContext2D();
// @ts-ignore;
const originCalls = originCtx.__getDrawCalls();
expect(originCalls).toMatchSnapshot();
const displayCtx = board.getDisplayContext2D();
// @ts-ignore;
const displayCalls = displayCtx.__getDrawCalls();
expect(displayCalls).toMatchSnapshot();
const transform = board.getTransform();
expect(transform).toStrictEqual({ scale: 2, scrollX: -600, scrollY: -400 });
});
});

View file

@ -1,38 +0,0 @@
import Board from '../src';
describe('@idraw/board', () => {
document.body.innerHTML = `
<div id="mount"></div>
`;
const opts = {
width: 800,
height: 600,
contextWidth: 600,
contextHeight: 400,
devicePixelRatio: 4,
canScroll: true
};
const transform = {
scale: 2,
scrollX: -200,
scrollY: -100
};
const mount = document.querySelector('#mount') as HTMLDivElement;
const board = new Board(mount, opts);
board.scale(transform.scale);
board.scrollX(transform.scrollX);
board.scrollY(transform.scrollY);
board.draw();
const p1 = { x: 400, y: 300 };
const p2 = { x: 300, y: 200 };
test('pointScreenToContext', async () => {
expect(board.pointScreenToContext(p1)).toStrictEqual(p2);
});
test('pointContextToScreen', async () => {
expect(board.pointContextToScreen(p2)).toStrictEqual(p1);
});
});

View file

@ -1,184 +0,0 @@
import Board from '../src';
import { getData } from './data';
describe('@idraw/board', () => {
test('scale', async () => {
document.body.innerHTML = `
<div id="mount"></div>
`;
const opts = {
width: 600,
height: 400,
contextWidth: 600,
contextHeight: 400,
devicePixelRatio: 4
};
const mount = document.querySelector('#mount') as HTMLDivElement;
const board = new Board(mount, opts);
const ctx = board.getContext();
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);
});
const result = board.scale(0.5);
expect(result).toStrictEqual({
position: { top: 100, bottom: 100, left: 150, right: 150 },
size: { x: 75, y: 50, w: 300, h: 200 }
});
board.draw();
const originCtx = board.getOriginContext2D();
// @ts-ignore;
const originCalls = originCtx.__getDrawCalls();
expect(originCalls).toMatchSnapshot();
const displayCtx = board.getDisplayContext2D();
// @ts-ignore;
const displayCalls = displayCtx.__getDrawCalls();
expect(displayCalls).toMatchSnapshot();
});
test('scale 001', async () => {
document.body.innerHTML = `
<div id="mount-001"></div>
`;
const opts = {
width: 600,
height: 400,
contextWidth: 1000,
contextHeight: 900,
devicePixelRatio: 4
};
const mount = document.querySelector('#mount-001') as HTMLDivElement;
const board = new Board(mount, opts);
const ctx = board.getContext();
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);
});
const result = board.scale(0.5);
expect(result).toStrictEqual({
position: { top: 0, bottom: -50, left: 50, right: 50 },
size: { x: 25, y: 0, w: 500, h: 450 }
});
board.draw();
const originCtx = board.getOriginContext2D();
// @ts-ignore;
const originCalls = originCtx.__getDrawCalls();
expect(originCalls).toMatchSnapshot();
const displayCtx = board.getDisplayContext2D();
// @ts-ignore;
const displayCalls = displayCtx.__getDrawCalls();
expect(displayCalls).toMatchSnapshot();
});
test('scale 002', async () => {
document.body.innerHTML = `
<div id="mount-002"></div>
`;
const opts = {
width: 600,
height: 400,
contextWidth: 1200,
contextHeight: 600,
devicePixelRatio: 4
};
const mount = document.querySelector('#mount-002') as HTMLDivElement;
const board = new Board(mount, opts);
const ctx = board.getContext();
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);
});
board.scrollX(-600);
board.scrollY(-400);
const result = board.scale(0.5);
expect(result).toStrictEqual({
position: { top: 50, bottom: 50, left: 0, right: 0 },
size: { x: 0, y: 25, w: 600, h: 300 }
});
board.draw();
const originCtx = board.getOriginContext2D();
// @ts-ignore;
const originCalls = originCtx.__getDrawCalls();
expect(originCalls).toMatchSnapshot();
const displayCtx = board.getDisplayContext2D();
// @ts-ignore;
const displayCalls = displayCtx.__getDrawCalls();
expect(displayCalls).toMatchSnapshot();
});
test('scale 003', async () => {
document.body.innerHTML = `
<div id="mount-003"></div>
`;
const opts = {
width: 600,
height: 400,
contextWidth: 1000,
contextHeight: 600,
devicePixelRatio: 4
};
const mount = document.querySelector('#mount-003') as HTMLDivElement;
const board = new Board(mount, opts);
const ctx = board.getContext();
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);
});
board.scrollX(400);
board.scrollY(400);
const result = board.scale(0.8);
expect(result).toStrictEqual({
position: { top: 0, bottom: -80, left: 0, right: -200 },
size: { x: 0, y: 0, w: 800, h: 480 }
});
board.draw();
const originCtx = board.getOriginContext2D();
// @ts-ignore;
const originCalls = originCtx.__getDrawCalls();
expect(originCalls).toMatchSnapshot();
const displayCtx = board.getDisplayContext2D();
// @ts-ignore;
const displayCalls = displayCtx.__getDrawCalls();
expect(displayCalls).toMatchSnapshot();
});
});

View file

@ -1,74 +0,0 @@
import Board from '../src';
import { getData } from './data';
describe('@idraw/board', () => {
document.body.innerHTML = `
<div id="mount"></div>
`;
const opts = {
width: 600,
height: 400,
contextWidth: 600,
contextHeight: 400,
devicePixelRatio: 4
};
const mount = document.querySelector('#mount') as HTMLDivElement;
const board = new Board(mount, opts);
const ctx = board.getContext();
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);
});
test('scroll', async () => {
const resultScale = board.scale(2);
expect(resultScale).toStrictEqual({
position: { top: 0, bottom: -400, left: 0, right: -600 },
size: { x: 0, y: 0, w: 1200, h: 800 }
});
const resultX = board.scrollX(-600);
expect(resultX).toStrictEqual({
position: { top: 0, bottom: -400, left: -600, right: 0 },
size: { x: -1200, y: 0, w: 1200, h: 800 }
});
const resultY = board.scrollY(-400);
expect(resultY).toStrictEqual({
position: { top: -400, bottom: 0, left: -600, right: 0 },
size: { x: -1200, y: -800, w: 1200, h: 800 }
});
board.draw();
const originCtx = board.getOriginContext2D();
// @ts-ignore;
const originCalls = originCtx.__getDrawCalls();
expect(originCalls).toMatchSnapshot();
const displayCtx = board.getDisplayContext2D();
// @ts-ignore;
const displayCalls = displayCtx.__getDrawCalls();
expect(displayCalls).toMatchSnapshot();
const screenInfo = board.getScreenInfo();
expect(screenInfo).toStrictEqual({
size: { x: -1200, y: -800, w: 1200, h: 800 },
position: { top: -400, bottom: 0, left: -600, right: 0 },
deviceSize: { x: -2400, y: -1600, w: 4800, h: 3200 },
width: 600,
height: 400,
devicePixelRatio: 4,
canScrollXNext: true,
canScrollXPrev: true,
canScrollYNext: true,
canScrollYPrev: true
});
});
});

View file

@ -1,69 +0,0 @@
/* eslint-disable @typescript-eslint/ban-ts-comment */
import Board from '../src';
import { getData } from './data';
describe('@idraw/board', () => {
test('scroll', async () => {
document.body.innerHTML = `
<div id="mount"></div>
`;
const opts = {
width: 600,
height: 400,
contextWidth: 600,
contextHeight: 400,
devicePixelRatio: 4,
canScroll: true,
scrollConfig: {
width: 20,
color: '#666666'
}
};
const mount = document.querySelector('#mount') as HTMLDivElement;
const board = new Board(mount, opts);
const ctx = board.getContext();
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);
});
const resultScale = board.scale(2);
expect(resultScale).toStrictEqual({
position: { top: 0, bottom: -400, left: 0, right: -600 },
size: { x: 0, y: 0, w: 1200, h: 800 }
});
const resultX = board.scrollX(-600);
expect(resultX).toStrictEqual({
position: { top: 0, bottom: -400, left: -600, right: 0 },
size: { x: -1200, y: 0, w: 1200, h: 800 }
});
const resultY = board.scrollY(-400);
expect(resultY).toStrictEqual({
position: { top: -400, bottom: 0, left: -600, right: 0 },
size: { x: -1200, y: -800, w: 1200, h: 800 }
});
board.draw();
const originCtx = board.getOriginContext2D();
// @ts-ignore;
const originCalls = originCtx.__getDrawCalls();
expect(originCalls).toMatchSnapshot();
const displayCtx = board.getDisplayContext2D();
// @ts-ignore;
const displayCalls = displayCtx.__getDrawCalls();
expect(displayCalls).toMatchSnapshot();
const scrollLineWidth = board.getScrollLineWidth();
expect(scrollLineWidth).toStrictEqual(opts.scrollConfig.width);
});
});

View file

@ -1,195 +0,0 @@
import type { Data } from '@idraw/types';
import { createUUID, parseSVGPath } from '@idraw/util';
const data: Data = {
elements: [
// {
// uuid: createUUID(),
// type: 'image',
// x: 100,
// y: 100,
// w: 100,
// h: 100,
// angle: 30,
// detail: {
// // src: '/public/images/lena.png?t=002'
// src: '@assets/0ee02fb0-ec43-6b9a-9ab4-55be5816ca4a'
// },
// operations: {
// limitRatio: true
// }
// },
{
uuid: createUUID(),
x: 2,
y: 2,
w: 100,
h: 100,
type: 'circle',
detail: {
background: '#f44336'
}
},
{
uuid: createUUID(),
type: 'rect',
x: 50,
y: 50,
w: 100,
h: 100,
detail: {
background: '#8bc34a'
}
},
// {
// uuid: createUUID(),
// type: 'image',
// x: 250,
// y: 250,
// w: 100,
// h: 100,
// detail: {
// // src: '/public/images/github.png?t=003'
// src: '@assets/25a0e630-a958-a522-29a4-5dccf04985da'
// }
// },
// {
// uuid: createUUID(),
// type: 'group',
// x: 250,
// y: 250,
// w: 100,
// h: 100,
// detail: {
// children: [
// {
// uuid: createUUID(),
// type: 'image',
// x: 0,
// y: 0,
// w: 100,
// h: 100,
// detail: {
// // src: '/public/images/github.png?t=003'
// src: '@assets/489c64d2-f642-3855-7bd6-cb40624b62c3'
// }
// }
// ],
// // assets: {
// // '@assets/489c64d2-f642-3855-7bd6-cb40624b62c3': {
// // type: 'image',
// // value: '/public/images/github.png?t=003'
// // }
// // }
// }
// },
{
uuid: createUUID(),
x: 0,
y: 300,
w: 100,
h: 100,
type: 'circle',
detail: {
background: '#009688'
}
},
{
uuid: createUUID(),
x: 300,
y: 300,
w: 100,
h: 100,
type: 'circle',
detail: {
background: '#673ab7'
}
},
{
uuid: createUUID(),
x: 300,
y: 0,
w: 100,
h: 100,
type: 'circle',
detail: {
background: '#ffc107'
}
},
{
uuid: createUUID(),
x: 150,
y: 150,
w: 100,
h: 100,
// angle: 30,
type: 'rect',
detail: {
background: '#4caf50',
clipPath: {
commands: parseSVGPath(`
M 10,30
A 20,20 0,0,1 50,30
A 20,20 0,0,1 90,30
Q 90,60 50,90
Q 10,60 10,30 z`),
// fill: '#ff0000',
originX: 10,
originY: 10,
originH: 80,
originW: 80
// background: '#0000002A'
}
}
},
{
uuid: createUUID(),
x: 100,
y: 10,
w: 80,
h: 80,
// angle: 30,
type: 'path',
detail: {
commands: parseSVGPath(`
M 10,30
A 20,20 0,0,1 50,30
A 20,20 0,0,1 90,30
Q 90,60 50,90
Q 10,60 10,30 z`),
fill: 'red',
originX: 10,
originY: 10,
originH: 80,
originW: 80,
background: '#0000002A'
// clipPath: {
// commands: parseSVGPath(`
// M 10,30
// A 20,20 0,0,1 50,30
// A 20,20 0,0,1 90,30
// Q 90,60 50,90
// Q 10,60 10,30 z`),
// fill: '#ff0000',
// originX: 10,
// originY: 10,
// originH: 80,
// originW: 80
// }
}
}
]
// assets: {
// '@assets/0ee02fb0-ec43-6b9a-9ab4-55be5816ca4a': {
// type: 'image',
// value: '/public/images/lena.png?t=003'
// },
// '@assets/25a0e630-a958-a522-29a4-5dccf04985da': {
// type: 'image',
// value: '/public/images/github.png?t=002'
// }
// }
};
export default data;

View file

@ -1,37 +0,0 @@
<html>
<head>
<style></style>
<meta name="viewport" content="width=device-width,minimum-scale=1.0,maximum-scale=1.0,user-scalable=no">
<style>
html, body {
margin: 0; padding: 0;
background: #f0f0f088;
}
#mount {
/* margin-top: 50px;
margin-left: 60px; */
}
#mount canvas {
border-right: 1px solid #aaaaaa40;
border-bottom: 1px solid #aaaaaa40;
background-image:
linear-gradient(#aaaaaa40 1px, transparent 0),
linear-gradient(90deg, #aaaaaa40 1px, transparent 0),
linear-gradient(#aaa 1px, transparent 0),
linear-gradient(90deg, #aaa 1px, transparent 0);
background-size: 10px 10px, 10px 10px, 50px 50px, 50px 50px;
background-color: #ffffff;
}
</style>
</head>
<body>
<div id="mount">
<canvas id="canvas"></canvas>
</div>
<script type="module" src="./main.ts"></script>
</body>
</html>

View file

@ -1,38 +0,0 @@
import { createBoardContent, deepClone } from '../../util/src';
import { Board } from '../src';
import { MiddlewareSelector, MiddlewareScroller, MiddlewareScaler } from '../../core/src';
import data from './data';
const devicePixelRatio = window.devicePixelRatio;
// const width = window.innerWidth;
// const height = window.innerHeight;
const width = 800;
const height = 600;
const canvas = document.querySelector('#canvas') as HTMLCanvasElement;
canvas.width = width * devicePixelRatio;
canvas.height = height * devicePixelRatio;
canvas.style.width = `${width}px`;
canvas.style.height = `${height}px`;
// const ctx1 = canvas.getContext('2d') as CanvasRenderingContext2D;
const boardContent1 = createBoardContent(canvas, { width, height, devicePixelRatio });
const board = new Board({ boardContent: boardContent1 });
const sharer1 = board.getSharer();
sharer1.setActiveViewSizeInfo({
devicePixelRatio,
width,
height,
contextWidth: width,
contextHeight: height
});
const data1 = deepClone(data);
board.resize(sharer1.getActiveViewSizeInfo());
board.setData(data1);
board.use(MiddlewareSelector);
board.use(MiddlewareScroller);
board.use(MiddlewareScaler);
// board.scale(2);
// board.scrollX(-50);
// board.scrollY(-50);

View file

@ -1,35 +0,0 @@
{
"name": "@idraw/board",
"version": "0.4.0-beta.39",
"description": "",
"main": "dist/esm/index.js",
"module": "dist/esm/index.js",
"unpkg": "dist/index.global.js",
"types": "dist/esm/index.d.ts",
"files": [
"dist/**/*.ts",
"dist/**/*.js"
],
"repository": {
"type": "git",
"url": "git+https://github.com/idrawjs/idraw.git"
},
"bugs": {
"url": "https://github.com/idrawjs/idraw/issues"
},
"homepage": "https://github.com/idrawjs/idraw#readme",
"author": "chenshenhai",
"license": "MIT",
"devDependencies": {
"@idraw/types": "workspace:^0.4.0-beta.39"
},
"dependencies": {},
"peerDependencies": {
"@idraw/util": "workspace:^0.4.0-beta.39",
"@idraw/renderer": "workspace:^0.4.0-beta.39"
},
"publishConfig": {
"access": "public",
"provenance": true
}
}

View file

@ -1,6 +1,6 @@
{
"name": "@idraw/core",
"version": "0.4.0-beta.39",
"version": "0.4.0-beta.40",
"description": "",
"main": "dist/esm/index.js",
"module": "dist/esm/index.js",
@ -18,16 +18,15 @@
"url": "https://github.com/idrawjs/idraw/issues"
},
"homepage": "https://github.com/idrawjs/idraw#readme",
"author": "chenshenhai",
"author": "idrawjs",
"license": "MIT",
"devDependencies": {
"@idraw/types": "workspace:^0.4.0-beta.39"
"@idraw/types": "workspace:^0.4.0-beta.40"
},
"dependencies": {},
"peerDependencies": {
"@idraw/board": "workspace:^0.4.0-beta.39",
"@idraw/renderer": "workspace:^0.4.0-beta.39",
"@idraw/util": "workspace:^0.4.0-beta.39"
"@idraw/renderer": "workspace:^0.4.0-beta.40",
"@idraw/util": "workspace:^0.4.0-beta.40"
},
"publishConfig": {
"access": "public",

View file

@ -1,4 +1,4 @@
import { Renderer } from '@idraw/renderer';
import { Renderer, Calculator } from '@idraw/renderer';
import {
// throttle,
calcElementsContextSize,
@ -16,10 +16,9 @@ import type {
UtilEventEmitter,
ModifyOptions
} from '@idraw/types';
import { Calculator } from './lib/calculator';
import { BoardWatcher } from './lib/watcher';
import { Sharer } from './lib/sharer';
import { Viewer } from './lib/viewer';
import { BoardWatcher } from './watcher';
import { Sharer } from './sharer';
import { Viewer } from './viewer';
// const throttleTime = 10; // ms
@ -44,16 +43,17 @@ export class Board<T extends BoardExtendEventMap = BoardExtendEventMap> {
constructor(opts: BoardOptions) {
const { boardContent } = opts;
const sharer = new Sharer();
const calculator = new Calculator({ viewContext: boardContent.viewContext });
const watcher = new BoardWatcher({
boardContent,
sharer
});
const renderer = new Renderer({
viewContext: boardContent.viewContext,
sharer,
calculator
tempContext: boardContent.tempContext,
sharer
});
const calculator = renderer.getCalculator();
this.#opts = opts;
this.#sharer = sharer;
@ -331,12 +331,12 @@ export class Board<T extends BoardExtendEventMap = BoardExtendEventMap> {
extend: true
});
if (modifiedOptions) {
this.#viewer.resetViewVisibleInfoMap(data, {
this.#viewer.resetVirtualFlatItemMap(data, {
viewSizeInfo,
viewScaleInfo
});
} else {
this.#viewer.resetViewVisibleInfoMap(data, {
this.#viewer.resetVirtualFlatItemMap(data, {
viewSizeInfo,
viewScaleInfo
});
@ -374,7 +374,10 @@ export class Board<T extends BoardExtendEventMap = BoardExtendEventMap> {
const calculator = this.#calculator;
const eventHub = this.#eventHub;
const obj = middleware({ boardContent, sharer, viewer, calculator, eventHub: eventHub as UtilEventEmitter<any>, container }, config);
const obj = middleware(
{ boardContent, sharer, viewer, calculator, eventHub: eventHub as UtilEventEmitter<any>, container },
config
);
obj.use?.();
this.#middlewares.push(middleware);
this.#activeMiddlewareObjs.push(obj);

View file

@ -45,7 +45,18 @@ export class Viewer extends EventEmitter<BoardViewerEventMap> implements BoardVi
const { renderer, boardContent, beforeDrawFrame, afterDrawFrame } = this.#opts;
if (snapshot) {
const { scale, offsetTop, offsetBottom, offsetLeft, offsetRight, width, height, contextHeight, contextWidth, devicePixelRatio } = snapshot.activeStore;
const {
scale,
offsetTop,
offsetBottom,
offsetLeft,
offsetRight,
width,
height,
contextHeight,
contextWidth,
devicePixelRatio
} = snapshot.activeStore;
const viewScaleInfo: ViewScaleInfo = {
scale,
@ -86,7 +97,7 @@ export class Viewer extends EventEmitter<BoardViewerEventMap> implements BoardVi
}
}
resetViewVisibleInfoMap(
resetVirtualFlatItemMap(
data: Data,
opts: {
viewScaleInfo: ViewScaleInfo;
@ -94,7 +105,7 @@ export class Viewer extends EventEmitter<BoardViewerEventMap> implements BoardVi
}
): void {
if (data) {
this.#opts.calculator.resetViewVisibleInfoMap(data, opts);
this.#opts.calculator.resetVirtualFlatItemMap(data, opts);
}
}
@ -111,7 +122,10 @@ export class Viewer extends EventEmitter<BoardViewerEventMap> implements BoardVi
this.#drawAnimationFrame();
}
scale(opts: { scale: number; point: PointSize; ignoreUpdateVisibleStatus?: boolean }): { moveX: number; moveY: number } {
scale(opts: { scale: number; point: PointSize; ignoreUpdateVisibleStatus?: boolean }): {
moveX: number;
moveY: number;
} {
const { scale, point, ignoreUpdateVisibleStatus } = opts;
const { sharer } = this.#opts;
const { moveX, moveY } = viewScale({

View file

@ -1,4 +1,12 @@
import type { Point, BoardWatcherEventMap, Data, Element, ElementType, BoardWatcherOptions, BoardWatcherStore } from '@idraw/types';
import type {
Point,
BoardWatcherEventMap,
Data,
Element,
ElementType,
BoardWatcherOptions,
BoardWatcherStore
} from '@idraw/types';
import { EventEmitter, Store } from '@idraw/util';
function isBoardAvailableNum(num: any): boolean {
@ -11,7 +19,9 @@ export class BoardWatcher extends EventEmitter<BoardWatcherEventMap> {
#hasDestroyed: boolean = false;
constructor(opts: BoardWatcherOptions) {
super();
const store = new Store<BoardWatcherStore>({ defaultStorage: { hasPointDown: false, prevClickPoint: null, inCanvas: true } });
const store = new Store<BoardWatcherStore>({
defaultStorage: { hasPointDown: false, prevClickPoint: null, inCanvas: true }
});
this.#store = store;
this.#opts = opts;
this.#init();
@ -25,25 +35,27 @@ export class BoardWatcher extends EventEmitter<BoardWatcherEventMap> {
if (this.#hasDestroyed) {
return;
}
const canvas = this.#opts.boardContent.boardContext.canvas;
const container = window;
container.addEventListener('mousemove', this.#onHover);
container.addEventListener('mousedown', this.#onPointStart);
container.addEventListener('mousemove', this.#onPointMove);
container.addEventListener('mouseup', this.#onPointEnd);
// container.addEventListener('mouseleave', this.#onPointLeave);
container.addEventListener('wheel', this.#onWheel, { passive: false });
canvas.addEventListener('wheel', this.#onWheel, { passive: false });
container.addEventListener('click', this.#onClick);
container.addEventListener('contextmenu', this.#onContextMenu);
}
offEvents() {
const container = window;
const canvas = this.#opts.boardContent.boardContext.canvas;
container.removeEventListener('mousemove', this.#onHover);
container.removeEventListener('mousedown', this.#onPointStart);
container.removeEventListener('mousemove', this.#onPointMove);
container.removeEventListener('mouseup', this.#onPointEnd);
container.removeEventListener('mouseleave', this.#onPointLeave);
container.removeEventListener('wheel', this.#onWheel);
canvas.removeEventListener('wheel', this.#onWheel);
container.removeEventListener('click', this.#onClick);
container.removeEventListener('contextmenu', this.#onContextMenu);
}
@ -101,7 +113,12 @@ export class BoardWatcher extends EventEmitter<BoardWatcherEventMap> {
const maxLimitTime = 500;
const t = Date.now();
const preClickPoint = this.#store.get('prevClickPoint');
if (preClickPoint && t - preClickPoint.t <= maxLimitTime && Math.abs(preClickPoint.x - point.x) <= 5 && Math.abs(preClickPoint.y - point.y) <= 5) {
if (
preClickPoint &&
t - preClickPoint.t <= maxLimitTime &&
Math.abs(preClickPoint.x - point.x) <= 5 &&
Math.abs(preClickPoint.y - point.y) <= 5
) {
this.trigger('doubleClick', { point });
} else {
this.#store.set('prevClickPoint', point);

View file

@ -3,6 +3,7 @@ export const EVENT_KEY_CURSOR = 'cursor';
export const EVENT_KEY_RULER = 'ruler';
export const EVENT_KEY_SCALE = 'scale';
export const EVENT_KEY_SELECT = 'select';
export const EVENT_KEY_SELECT_LAYOUT = 'selectLayout';
export const EVENT_KEY_CLEAR_SELECT = 'clearSelect';
export const EVENT_KEY_TEXT_EDIT = 'textEdit';
export const EVENT_KEY_TEXT_CHANGE = 'textChange';
@ -16,6 +17,7 @@ export type CoreEventKeys = {
RULER: typeof EVENT_KEY_RULER;
SCALE: typeof EVENT_KEY_SCALE;
SELECT: typeof EVENT_KEY_SELECT;
SELECT_LAYOUT: typeof EVENT_KEY_SELECT_LAYOUT;
CLEAR_SELECT: typeof EVENT_KEY_CLEAR_SELECT;
TEXT_EDIT: typeof EVENT_KEY_TEXT_EDIT;
TEXT_CHANGE: typeof EVENT_KEY_TEXT_CHANGE;
@ -29,6 +31,7 @@ const innerEventKeys: CoreEventKeys = {
CHANGE: EVENT_KEY_CHANGE,
RULER: EVENT_KEY_RULER,
SCALE: EVENT_KEY_SCALE,
SELECT_LAYOUT: EVENT_KEY_SELECT_LAYOUT,
SELECT: EVENT_KEY_SELECT,
CLEAR_SELECT: EVENT_KEY_CLEAR_SELECT,
TEXT_EDIT: EVENT_KEY_TEXT_EDIT,

View file

@ -1,10 +1,22 @@
import type { Data, PointSize, CoreOptions, BoardMiddleware, ViewSizeInfo, CoreEventMap, ViewScaleInfo, LoadItemMap, ModifyOptions } from '@idraw/types';
import { Board } from '@idraw/board';
import type {
Data,
PointSize,
CoreOptions,
BoardMiddleware,
ViewSizeInfo,
CoreEventMap,
ViewScaleInfo,
LoadItemMap,
ModifyOptions
} from '@idraw/types';
import { Board, Sharer, Calculator } from './board';
import { createBoardContent, validateElements } from '@idraw/util';
import { Cursor } from './lib/cursor';
export { coreEventKeys } from './config';
export type { CoreEventKeys } from './config';
export { Board, Sharer, Calculator };
// export { MiddlewareSelector } from './middleware/selector';
export { MiddlewareSelector } from './middleware/selector';
export { MiddlewareScroller } from './middleware/scroller';
@ -23,7 +35,7 @@ export class Core<E extends CoreEventMap = CoreEventMap> {
#container: HTMLDivElement;
constructor(container: HTMLDivElement, opts: CoreOptions) {
const { devicePixelRatio = 1, width, height, createCustomContext2D } = opts;
const { devicePixelRatio = 1, width, height } = opts;
// this.#opts = opts;
this.#container = container;
@ -33,7 +45,7 @@ export class Core<E extends CoreEventMap = CoreEventMap> {
this.#initContainer();
container.appendChild(canvas);
const boardContent = createBoardContent(canvas, { width, height, devicePixelRatio, offscreen: true, createCustomContext2D });
const boardContent = createBoardContent(canvas, { width, height, devicePixelRatio });
const board = new Board<E>({ boardContent, container });
const sharer = board.getSharer();
sharer.setActiveViewSizeInfo({

View file

@ -1,5 +1,11 @@
import type { BoardMiddleware, ElementSize, Point, MiddlewareLayoutSelectorConfig, CoreEventMap } from '@idraw/types';
import { calcLayoutSizeController, isViewPointInVertexes, getViewScaleInfoFromSnapshot, isViewPointInElementSize, calcViewElementSize } from '@idraw/util';
import {
calcLayoutSizeController,
isViewPointInVertexes,
getViewScaleInfoFromSnapshot,
isViewPointInElementSize,
calcViewElementSize
} from '@idraw/util';
import type { LayoutSelectorSharedStorage, ControlType } from './types';
import {
keyLayoutActionType,
@ -21,7 +27,11 @@ import { coreEventKeys } from '../../config';
export { keyLayoutIsSelected, keyLayoutIsBusyMoving };
export const MiddlewareLayoutSelector: BoardMiddleware<LayoutSelectorSharedStorage, CoreEventMap, MiddlewareLayoutSelectorConfig> = (opts, config) => {
export const MiddlewareLayoutSelector: BoardMiddleware<
LayoutSelectorSharedStorage,
CoreEventMap,
MiddlewareLayoutSelectorConfig
> = (opts, config) => {
const { sharer, boardContent, calculator, viewer, eventHub } = opts;
const { overlayContext } = boardContent;
let innerConfig = {
@ -242,6 +252,7 @@ export const MiddlewareLayoutSelector: BoardMiddleware<LayoutSelectorSharedStora
if (sharer.getSharedStorage(keyLayoutIsSelected) === true && !prevIsSelected) {
viewer.drawFrame();
eventHub.trigger(coreEventKeys.SELECT_LAYOUT);
}
prevIsSelected = sharer.getSharedStorage(keyLayoutIsSelected);
@ -349,11 +360,14 @@ export const MiddlewareLayoutSelector: BoardMiddleware<LayoutSelectorSharedStora
const data = sharer.getActiveStorage('data');
if (data && layoutActionType === 'resize' && layoutControlType) {
eventHub.trigger(coreEventKeys.CHANGE, {
type: 'changeLayout',
type: 'dragLayout',
data
});
}
sharer.setSharedStorage(keyLayoutActionType, null);
sharer.setSharedStorage(keyLayoutControlType, null);
if (sharer.getSharedStorage(keyLayoutIsHoverController) === true) {
return false;
}

View file

@ -1,6 +1,22 @@
import type { Point, BoardViewerFrameSnapshot, ViewScaleInfo, ViewSizeInfo, ViewContext2D, ElementSize, MiddlewareScrollerStyle } from '@idraw/types';
import type {
Point,
BoardViewerFrameSnapshot,
ViewScaleInfo,
ViewSizeInfo,
ViewContext2D,
ElementSize,
MiddlewareScrollerStyle
} from '@idraw/types';
import { getViewScaleInfoFromSnapshot, getViewSizeInfoFromSnapshot } from '@idraw/util';
import { keyActivePoint, keyActiveThumbType, keyPrevPoint, keyXThumbRect, keyYThumbRect, keyHoverXThumbRect, keyHoverYThumbRect } from './config';
import {
keyActivePoint,
keyActiveThumbType,
keyPrevPoint,
keyXThumbRect,
keyYThumbRect,
keyHoverXThumbRect,
keyHoverYThumbRect
} from './config';
const scrollerLineWidth = 16;
const minThumbLength = scrollerLineWidth * 2.5;
@ -153,7 +169,8 @@ function drawScrollerThumb(
borderColor: string;
}
): void {
let { x, y, h, w, background, borderColor } = opts;
let { x, y, h, w } = opts;
const { background, borderColor } = opts;
ctx.save();
ctx.shadowColor = '#FFFFFF';
@ -203,7 +220,12 @@ function drawScrollerThumb(
function drawScrollerInfo(
overlayContext: ViewContext2D,
opts: { viewScaleInfo: ViewScaleInfo; viewSizeInfo: ViewSizeInfo; scrollInfo: ScrollInfo; style: MiddlewareScrollerStyle }
opts: {
viewScaleInfo: ViewScaleInfo;
viewSizeInfo: ViewSizeInfo;
scrollInfo: ScrollInfo;
style: MiddlewareScrollerStyle;
}
) {
const ctx = overlayContext;
const { viewScaleInfo, viewSizeInfo, scrollInfo, style } = opts;
@ -261,7 +283,10 @@ function drawScrollerInfo(
};
}
export function drawScroller(ctx: ViewContext2D, opts: { snapshot: BoardViewerFrameSnapshot; style: MiddlewareScrollerStyle }) {
export function drawScroller(
ctx: ViewContext2D,
opts: { snapshot: BoardViewerFrameSnapshot; style: MiddlewareScrollerStyle }
) {
const { snapshot, style } = opts;
const viewSizeInfo = getViewSizeInfoFromSnapshot(snapshot);
const viewScaleInfo = getViewScaleInfoFromSnapshot(snapshot);

View file

@ -173,7 +173,10 @@ export const MiddlewareSelector: BoardMiddleware<
sharer.setSharedStorage(keySelectedElementList, list);
if (list.length === 1) {
updateSelectedElemenetController();
sharer.setSharedStorage(keySelectedElementPosition, getElementPositionFromList(list[0].uuid, sharer.getActiveStorage('data')?.elements || []));
sharer.setSharedStorage(
keySelectedElementPosition,
getElementPositionFromList(list[0].uuid, sharer.getActiveStorage('data')?.elements || [])
);
} else {
sharer.setSharedStorage(keySelectedElementController, null);
sharer.setSharedStorage(keySelectedElementPosition, []);
@ -183,7 +186,11 @@ export const MiddlewareSelector: BoardMiddleware<
const uuids = list.map((elem) => elem.uuid);
const data = sharer.getActiveStorage('data');
const positionMap = getElementPositionMapFromList(uuids, data?.elements || []);
eventHub.trigger(coreEventKeys.SELECT, { uuids, positions: list.map((elem) => [...positionMap[elem.uuid]]) });
eventHub.trigger(coreEventKeys.SELECT, {
type: 'clickCanvas',
uuids,
positions: list.map((elem) => [...positionMap[elem.uuid]])
});
}
};
@ -515,7 +522,14 @@ export const MiddlewareSelector: BoardMiddleware<
eventHub.trigger(MIDDLEWARE_INTERNAL_EVENT_SHOW_INFO_ANGLE, { show: false });
if (data && elems?.length === 1 && moveOriginalStartElementSize && originalStart && end && elems[0]?.operations?.locked !== true) {
if (
data &&
elems?.length === 1 &&
moveOriginalStartElementSize &&
originalStart &&
end &&
elems[0]?.operations?.locked !== true
) {
const { moveX, moveY } = calcPointMoveElementInGroup(originalStart, end, groupQueue);
let totalMoveX = calculator.toGridNum(moveX / scale);
@ -547,7 +561,7 @@ export const MiddlewareSelector: BoardMiddleware<
elems[0].x = calculator.toGridNum(moveOriginalStartElementSize.x + totalMoveX);
elems[0].y = calculator.toGridNum(moveOriginalStartElementSize.y + totalMoveY);
updateSelectedElementList([elems[0]]);
calculator.modifyViewVisibleInfoMap(data, {
calculator.modifyVirtualFlatItemMap(data, {
modifyOptions: {
type: 'updateElement',
content: {
@ -571,7 +585,7 @@ export const MiddlewareSelector: BoardMiddleware<
elem.x = calculator.toGridNum(elem.x + moveX);
elem.y = calculator.toGridNum(elem.y + moveY);
calculator.modifyViewVisibleInfoMap(data, {
calculator.modifyVirtualFlatItemMap(data, {
modifyOptions: {
type: 'updateElement',
content: {
@ -589,7 +603,13 @@ export const MiddlewareSelector: BoardMiddleware<
}
viewer.drawFrame();
} else if (actionType === 'resize') {
if (data && elems?.length === 1 && originalStart && moveOriginalStartElementSize && resizeType?.startsWith('resize-')) {
if (
data &&
elems?.length === 1 &&
originalStart &&
moveOriginalStartElementSize &&
resizeType?.startsWith('resize-')
) {
hasChangedData = true;
inBusyMode = 'resize';
const pointGroupQueue: Element<'group'>[] = [];
@ -612,7 +632,9 @@ export const MiddlewareSelector: BoardMiddleware<
resizeEnd = rotatePointInGroup(end, pointGroupQueue);
}
if (resizeType === 'resize-rotate') {
const controller: ElementSizeController = sharer.getSharedStorage(keySelectedElementController) as ElementSizeController;
const controller: ElementSizeController = sharer.getSharedStorage(
keySelectedElementController
) as ElementSizeController;
const viewVertexes: ViewRectVertexes = [
controller.topLeft.center,
controller.topRight.center,
@ -633,7 +655,10 @@ export const MiddlewareSelector: BoardMiddleware<
elems[0].angle = calculator.toGridNum(resizedElemSize.angle || 0);
} else {
const resizedElemSize = resizeElement(moveOriginalStartElementSize, { scale, start: resizeStart, end: resizeEnd, resizeType, sharer });
const resizedElemSize = resizeElement(
{ ...moveOriginalStartElementSize, operations: elems[0].operations },
{ scale, start: resizeStart, end: resizeEnd, resizeType, sharer }
);
const calcOpts = { ignore: !!moveOriginalStartElementSize.angle };
elems[0].x = calculator.toGridNum(resizedElemSize.x, calcOpts);
elems[0].y = calculator.toGridNum(resizedElemSize.y, calcOpts);
@ -649,7 +674,7 @@ export const MiddlewareSelector: BoardMiddleware<
}
updateSelectedElementList([elems[0]]);
calculator.modifyViewVisibleInfoMap(data, {
calculator.modifyVirtualFlatItemMap(data, {
modifyOptions: {
type: 'updateElement',
content: {
@ -788,11 +813,18 @@ export const MiddlewareSelector: BoardMiddleware<
viewer.drawFrame();
return;
}
} else if (target.elements.length === 1 && target.elements[0]?.type === 'text' && !target.elements[0]?.operations?.invisible) {
} else if (
target.elements.length === 1 &&
target.elements[0]?.type === 'text' &&
!target.elements[0]?.operations?.invisible
) {
eventHub.trigger(coreEventKeys.TEXT_EDIT, {
element: target.elements[0] as Element<'text'>,
groupQueue: sharer.getSharedStorage(keyGroupQueue) || [],
position: getElementPositionFromList(target.elements[0]?.uuid, sharer.getActiveStorage('data')?.elements || []),
position: getElementPositionFromList(
target.elements[0]?.uuid,
sharer.getActiveStorage('data')?.elements || []
),
viewScaleInfo: sharer.getActiveViewScaleInfo()
});
}
@ -858,7 +890,18 @@ export const MiddlewareSelector: BoardMiddleware<
const style = { activeColor, activeAreaColor, lockedColor, referenceColor };
const { activeStore, sharedStore } = snapshot;
const { scale, offsetLeft, offsetTop, offsetRight, offsetBottom, width, height, contextHeight, contextWidth, devicePixelRatio } = activeStore;
const {
scale,
offsetLeft,
offsetTop,
offsetRight,
offsetBottom,
width,
height,
contextHeight,
contextWidth,
devicePixelRatio
} = activeStore;
if (rotateControllerPattern.fill !== activeColor) {
rotateControllerPattern = createRotateControllerPattern({
fill: innerConfig.activeColor,

View file

@ -11,7 +11,14 @@ import {
limitAngle,
calcRadian
} from '@idraw/util';
import type { ViewRectVertexes, ElementSizeController, StoreSharer, ViewScaleInfo, ViewSizeInfo } from '@idraw/types';
import type {
ViewRectVertexes,
ElementSizeController,
StoreSharer,
ViewScaleInfo,
ViewSizeInfo,
ElementOperations
} from '@idraw/types';
import type {
Data,
Element,
@ -65,7 +72,12 @@ export function isPointInViewActiveVertexes(
export function isPointInViewActiveGroup(
p: PointSize,
opts: { ctx: ViewContext2D; viewScaleInfo: ViewScaleInfo; viewSizeInfo: ViewSizeInfo; groupQueue: Element<'group'>[] | null }
opts: {
ctx: ViewContext2D;
viewScaleInfo: ViewScaleInfo;
viewSizeInfo: ViewSizeInfo;
groupQueue: Element<'group'>[] | null;
}
): boolean {
const { ctx, viewScaleInfo, viewSizeInfo, groupQueue } = opts;
if (!groupQueue || !(groupQueue?.length > 0)) {
@ -100,7 +112,17 @@ export function getPointTarget(
groupQueue: [],
groupQueueVertexesList: []
};
const { ctx, data, calculator, selectedElements, viewScaleInfo, viewSizeInfo, areaSize, groupQueue, selectedElementController } = opts;
const {
ctx,
data,
calculator,
selectedElements,
viewScaleInfo,
viewSizeInfo,
areaSize,
groupQueue,
selectedElementController
} = opts;
// resize
if (selectedElementController) {
@ -174,7 +196,7 @@ export function getPointTarget(
}
export function resizeElement(
elem: ElementSize,
elem: ElementSize & { operations?: ElementOperations },
opts: {
start: PointSize;
end: PointSize;
@ -260,7 +282,9 @@ export function resizeElement(
const maxHorizontalDist = Math.max(Math.abs(moveHorizontalX), Math.abs(moveHorizontalY));
moveHorizontalX = (moveHorizontalX >= 0 ? 1 : -1) * maxHorizontalDist;
moveHorizontalY = (((moveHorizontalY >= 0 ? 1 : -1) * maxHorizontalDist) / elem.w) * elem.h;
} else if (['resize-top-left', 'resize-top-right', 'resize-bottom-left', 'resize-bottom-right'].includes(resizeType)) {
} else if (
['resize-top-left', 'resize-top-right', 'resize-bottom-left', 'resize-bottom-right'].includes(resizeType)
) {
{
// const maxDist = Math.max(Math.abs(moveX), Math.abs(moveY));
const maxDist = Math.abs(moveX);
@ -533,7 +557,8 @@ export function resizeElement(
if (angle < 90) {
moveVerticalDist = 0 - changeMoveDistDirect(moveVerticalDist, moveVerticalY);
moveHorizontalDist = 0 - changeMoveDistDirect(moveHorizontalDist, limitRatio ? 0 - moveVerticalDist : moveHorizontalX);
moveHorizontalDist =
0 - changeMoveDistDirect(moveHorizontalDist, limitRatio ? 0 - moveVerticalDist : moveHorizontalX);
const centerMoveVerticalDist = moveVerticalDist / 2;
centerX = centerX + centerMoveVerticalDist * Math.sin(radian);
@ -544,7 +569,10 @@ export function resizeElement(
centerY = centerY - centerMoveHorizontalDist * Math.sin(radian);
} else if (angle < 180) {
moveVerticalDist = changeMoveDistDirect(moveVerticalDist, moveVerticalX);
moveHorizontalDist = changeMoveDistDirect(moveHorizontalDist, limitRatio ? moveVerticalDist : moveHorizontalX);
moveHorizontalDist = changeMoveDistDirect(
moveHorizontalDist,
limitRatio ? moveVerticalDist : moveHorizontalX
);
const radian = parseRadian(angle - 90);
const centerMoveVerticalDist = moveVerticalDist / 2;
@ -556,7 +584,10 @@ export function resizeElement(
centerY = centerY - centerMoveDist * Math.cos(radian);
} else if (angle < 270) {
moveVerticalDist = changeMoveDistDirect(moveVerticalDist, moveVerticalY);
moveHorizontalDist = changeMoveDistDirect(moveHorizontalDist, limitRatio ? moveVerticalDist : moveHorizontalY);
moveHorizontalDist = changeMoveDistDirect(
moveHorizontalDist,
limitRatio ? moveVerticalDist : moveHorizontalY
);
const radian = parseRadian(angle - 180);
const centerMoveVerticalDist = moveVerticalDist / 2;
@ -568,7 +599,10 @@ export function resizeElement(
centerY = centerY + centerMoveHorizontalDist * Math.sin(radian);
} else if (angle < 360) {
moveVerticalDist = 0 - changeMoveDistDirect(moveVerticalDist, moveVerticalX);
moveHorizontalDist = changeMoveDistDirect(moveHorizontalDist, limitRatio ? moveVerticalDist : moveHorizontalY);
moveHorizontalDist = changeMoveDistDirect(
moveHorizontalDist,
limitRatio ? moveVerticalDist : moveHorizontalY
);
const radian = parseRadian(angle - 270);
const centerMoveVerticalDist = moveVerticalDist / 2;
@ -604,7 +638,10 @@ export function resizeElement(
let centerY = elemCenter.y;
if (angle < 90) {
moveVerticalDist = 0 - changeMoveDistDirect(moveVerticalDist, moveVerticalY);
moveHorizontalDist = changeMoveDistDirect(moveHorizontalDist, limitRatio ? moveVerticalDist : moveHorizontalY);
moveHorizontalDist = changeMoveDistDirect(
moveHorizontalDist,
limitRatio ? moveVerticalDist : moveHorizontalY
);
const radian = parseRadian(angle);
const centerMoveVerticalDist = moveVerticalDist / 2;
@ -616,7 +653,10 @@ export function resizeElement(
centerY = centerY + centerMoveHorizontalDist * Math.sin(radian);
} else if (angle < 180) {
moveVerticalDist = changeMoveDistDirect(moveVerticalDist, moveVerticalX);
moveHorizontalDist = changeMoveDistDirect(moveHorizontalDist, limitRatio ? moveVerticalDist : moveHorizontalY);
moveHorizontalDist = changeMoveDistDirect(
moveHorizontalDist,
limitRatio ? moveVerticalDist : moveHorizontalY
);
const radian = parseRadian(angle - 90);
const centerMoveVerticalDist = moveVerticalDist / 2;
@ -629,7 +669,10 @@ export function resizeElement(
} else if (angle < 270) {
const radian = parseRadian(angle - 180);
moveVerticalDist = changeMoveDistDirect(moveVerticalDist, moveVerticalY);
moveHorizontalDist = changeMoveDistDirect(moveHorizontalDist, limitRatio ? moveVerticalDist : 0 - moveHorizontalX);
moveHorizontalDist = changeMoveDistDirect(
moveHorizontalDist,
limitRatio ? moveVerticalDist : 0 - moveHorizontalX
);
const centerMoveVerticalDist = moveVerticalDist / 2;
centerX = centerX - centerMoveVerticalDist * Math.sin(radian);
centerY = centerY + centerMoveVerticalDist * Math.cos(radian);
@ -639,7 +682,10 @@ export function resizeElement(
centerY = centerY - centerMoveHorizontalDist * Math.sin(radian);
} else if (angle < 360) {
moveVerticalDist = 0 - changeMoveDistDirect(moveVerticalDist, moveVerticalX);
moveHorizontalDist = changeMoveDistDirect(moveHorizontalDist, limitRatio ? moveVerticalDist : moveHorizontalX);
moveHorizontalDist = changeMoveDistDirect(
moveHorizontalDist,
limitRatio ? moveVerticalDist : moveHorizontalX
);
const radian = parseRadian(angle - 270);
const centerMoveVerticalDist = moveVerticalDist / 2;
@ -675,7 +721,8 @@ export function resizeElement(
let centerY = elemCenter.y;
if (angle < 90) {
moveVerticalDist = changeMoveDistDirect(moveVerticalDist, moveVerticalY);
moveHorizontalDist = 0 - changeMoveDistDirect(moveHorizontalDist, limitRatio ? 0 - moveVerticalDist : moveHorizontalX);
moveHorizontalDist =
0 - changeMoveDistDirect(moveHorizontalDist, limitRatio ? 0 - moveVerticalDist : moveHorizontalX);
const radian = parseRadian(angle);
const centerMoveVerticalDist = moveVerticalDist / 2;
@ -687,7 +734,10 @@ export function resizeElement(
centerY = centerY - centerMoveHorizontalDist * Math.sin(radian);
} else if (angle < 180) {
moveVerticalDist = 0 - changeMoveDistDirect(moveVerticalDist, moveVerticalX);
moveHorizontalDist = changeMoveDistDirect(moveHorizontalDist, limitRatio ? moveVerticalDist : moveHorizontalX);
moveHorizontalDist = changeMoveDistDirect(
moveHorizontalDist,
limitRatio ? moveVerticalDist : moveHorizontalX
);
const radian = parseRadian(angle - 90);
const centerMoveVerticalDist = moveVerticalDist / 2;
@ -699,7 +749,10 @@ export function resizeElement(
centerY = centerY - centerMoveDist * Math.cos(radian);
} else if (angle < 270) {
moveVerticalDist = changeMoveDistDirect(moveVerticalDist, moveVerticalX);
moveHorizontalDist = changeMoveDistDirect(moveHorizontalDist, limitRatio ? moveVerticalDist : moveHorizontalY);
moveHorizontalDist = changeMoveDistDirect(
moveHorizontalDist,
limitRatio ? moveVerticalDist : moveHorizontalY
);
const radian = parseRadian(angle - 180);
const centerMoveVerticalDist = moveVerticalDist / 2;
@ -711,7 +764,10 @@ export function resizeElement(
centerY = centerY + centerMoveHorizontalDist * Math.sin(radian);
} else if (angle < 360) {
moveVerticalDist = changeMoveDistDirect(moveVerticalDist, moveVerticalX);
moveHorizontalDist = changeMoveDistDirect(moveHorizontalDist, limitRatio ? moveVerticalDist : moveHorizontalY);
moveHorizontalDist = changeMoveDistDirect(
moveHorizontalDist,
limitRatio ? moveVerticalDist : moveHorizontalY
);
const radian = parseRadian(angle - 270);
const centerMoveDist = moveVerticalDist / 2;
centerX = centerX + centerMoveDist * Math.cos(radian);
@ -745,7 +801,10 @@ export function resizeElement(
let centerY = elemCenter.y;
if (angle < 90) {
moveVerticalDist = changeMoveDistDirect(moveVerticalDist, moveVerticalY);
moveHorizontalDist = changeMoveDistDirect(moveHorizontalDist, limitRatio ? moveVerticalDist : moveHorizontalY);
moveHorizontalDist = changeMoveDistDirect(
moveHorizontalDist,
limitRatio ? moveVerticalDist : moveHorizontalY
);
const radian = parseRadian(angle);
const centerMoveVerticalDist = moveVerticalDist / 2;
@ -769,7 +828,10 @@ export function resizeElement(
centerY = centerY + centerMoveHorizontalDist * Math.cos(radian);
} else if (angle < 270) {
moveVerticalDist = changeMoveDistDirect(moveVerticalDist, moveVerticalX);
moveHorizontalDist = changeMoveDistDirect(moveHorizontalDist, limitRatio ? moveVerticalDist : 0 - moveHorizontalY);
moveHorizontalDist = changeMoveDistDirect(
moveHorizontalDist,
limitRatio ? moveVerticalDist : 0 - moveHorizontalY
);
const radian = parseRadian(angle - 180);
const centerMoveVerticalDist = moveVerticalDist / 2;
@ -781,7 +843,10 @@ export function resizeElement(
centerY = centerY - centerMoveHorizontalDist * Math.sin(radian);
} else if (angle < 360) {
moveVerticalDist = changeMoveDistDirect(moveVerticalDist, moveVerticalX);
moveHorizontalDist = changeMoveDistDirect(moveHorizontalDist, limitRatio ? moveVerticalDist : moveHorizontalX);
moveHorizontalDist = changeMoveDistDirect(
moveHorizontalDist,
limitRatio ? moveVerticalDist : moveHorizontalX
);
const radian = parseRadian(angle - 270);
const centerMoveDist = moveVerticalDist / 2;
@ -865,7 +930,7 @@ export function getSelectedListArea(
const indexes: number[] = [];
const uuids: string[] = [];
const elements: Element<ElementType>[] = [];
const { viewScaleInfo, viewSizeInfo, start, end } = opts;
const { viewScaleInfo, start, end } = opts;
if (!(Array.isArray(data.elements) && start && end)) {
return { indexes, uuids, elements };

View file

@ -1,6 +1,6 @@
{
"name": "@idraw/figma",
"version": "0.4.0-beta.39",
"version": "0.4.0-beta.40",
"description": "",
"main": "dist/esm/index.js",
"module": "dist/esm/index.js",
@ -11,8 +11,8 @@
"dist/**/*.js"
],
"dependencies": {
"@idraw/types": "workspace:^0.4.0-beta.39",
"@idraw/util": "workspace:^0.4.0-beta.39",
"@idraw/types": "workspace:^0.4.0-beta.40",
"@idraw/util": "workspace:^0.4.0-beta.40",
"kiwi-schema": "^0.5.0",
"matrix-inverse": "^2.0.0",
"pako": "^2.1.0",
@ -20,7 +20,7 @@
},
"devDependencies": {
"@types/pako": "^2.0.3",
"@idraw/types": "workspace:^0.4.0-beta.39"
"@idraw/types": "workspace:^0.4.0-beta.40"
},
"repository": {
"type": "git",
@ -30,7 +30,7 @@
"url": "https://github.com/idrawjs/idraw/issues"
},
"homepage": "https://github.com/idrawjs/idraw#readme",
"author": "chenshenhai",
"author": "idrawjs",
"license": "MIT",
"publishConfig": {
"access": "public",

View file

@ -1,6 +1,6 @@
{
"name": "idraw",
"version": "0.4.0-beta.39",
"version": "0.4.0-beta.40",
"description": "",
"main": "dist/esm/index.js",
"module": "dist/esm/index.js",
@ -18,15 +18,14 @@
"url": "https://github.com/idrawjs/idraw/issues"
},
"homepage": "https://github.com/idrawjs/idraw#readme",
"author": "chenshenhai",
"author": "idrawjs",
"license": "MIT",
"devDependencies": {},
"dependencies": {
"@idraw/board": "workspace:^0.4.0-beta.39",
"@idraw/core": "workspace:^0.4.0-beta.39",
"@idraw/renderer": "workspace:^0.4.0-beta.39",
"@idraw/types": "workspace:^0.4.0-beta.39",
"@idraw/util": "workspace:^0.4.0-beta.39"
"@idraw/core": "workspace:^0.4.0-beta.40",
"@idraw/renderer": "workspace:^0.4.0-beta.40",
"@idraw/types": "workspace:^0.4.0-beta.40",
"@idraw/util": "workspace:^0.4.0-beta.40"
},
"publishConfig": {
"access": "public",

View file

@ -1,5 +1,4 @@
import { Renderer } from '@idraw/renderer';
import { Calculator } from '@idraw/board';
import { createOffscreenContext2D } from '@idraw/util';
import type { Data, LoadItemMap, ViewContext2D, ViewScaleInfo, ViewSizeInfo } from '@idraw/types';
@ -26,10 +25,9 @@ export type ExportImageFileResult = {
export async function exportImageFileBlobURL(opts: ExportImageFileOptions): Promise<ExportImageFileResult> {
const { data, width, height, devicePixelRatio, viewScaleInfo, viewSizeInfo, loadItemMap } = opts;
let viewContext: ViewContext2D | null = createOffscreenContext2D({ width, height, devicePixelRatio });
let calculator: Calculator | null = new Calculator({ viewContext });
// let calculator: Calculator | null = new Calculator({ viewContext });
let renderer: Renderer | null = new Renderer({
viewContext,
calculator
viewContext
});
renderer.setLoadItemMap(loadItemMap);
renderer.drawData(data, {
@ -46,7 +44,6 @@ export async function exportImageFileBlobURL(opts: ExportImageFileOptions): Prom
offScreenCanvas = null;
viewContext = null;
calculator = null;
renderer = null;
return {

View file

@ -12,7 +12,8 @@ import type {
Element,
RecursivePartial,
ElementPosition,
IDrawStorage
IDrawStorage,
DataLayout
} from '@idraw/types';
import {
createElement,
@ -25,9 +26,17 @@ import {
filterCompactData,
calcViewCenterContent,
calcViewCenter,
Store
Store,
merge
} from '@idraw/util';
import { defaultSettings, getDefaultStorage, defaultMode, parseStyles, parseSettings } from './setting/config';
import {
defaultSettings,
defaultOptions,
getDefaultStorage,
defaultMode,
parseStyles,
parseSettings
} from './setting/config';
import { exportImageFileBlobURL } from './file';
import type { ExportImageFileBaseOptions, ExportImageFileResult } from './file';
import type { IDrawEvent } from './event';
@ -42,10 +51,10 @@ export class iDraw {
});
constructor(mount: HTMLDivElement, options: IDrawOptions) {
const opts = { ...defaultSettings, ...options };
const opts = { ...defaultSettings, ...defaultOptions, ...options };
this.#store.set('middlewareStyles', parseStyles(opts));
const { width, height, devicePixelRatio, createCustomContext2D } = opts;
const core = new Core<IDrawEvent>(mount, { width, height, devicePixelRatio, createCustomContext2D });
const { width, height, devicePixelRatio } = opts;
const core = new Core<IDrawEvent>(mount, { width, height, devicePixelRatio });
this.#core = core;
this.#opts = opts;
this.#init();
@ -85,7 +94,7 @@ export class iDraw {
const store = this.#store;
const { mode, styles } = parseSettings(opts);
let needFresh = false;
let newOpts: IDrawSettings = {};
const newOpts: IDrawSettings = {};
store.clear();
if (mode) {
changeMode(mode, core, store);
@ -181,20 +190,20 @@ export class iDraw {
this.#core.trigger(name, e as IDrawEvent[T]);
}
selectElement(uuid: string) {
this.selectElements([uuid]);
selectElement(uuid: string, opts?: { type?: string }) {
this.trigger(coreEventKeys.SELECT, { uuids: [uuid], type: opts?.type || 'selectElement' });
}
selectElements(uuids: string[]) {
this.trigger(coreEventKeys.SELECT, { uuids });
selectElements(uuids: string[], opts?: { type?: string }) {
this.trigger(coreEventKeys.SELECT, { uuids, type: opts?.type || 'selectElements' });
}
selectElementByPosition(position: ElementPosition) {
this.selectElementsByPositions([position]);
selectElementByPosition(position: ElementPosition, opts?: { type?: string }) {
this.trigger(coreEventKeys.SELECT, { positions: [position], type: opts?.type || 'selectElementByPosition' });
}
selectElementsByPositions(positions: ElementPosition[]) {
this.trigger(coreEventKeys.SELECT, { positions });
selectElementsByPositions(positions: ElementPosition[], opts?: { type?: string }) {
this.trigger(coreEventKeys.SELECT, { positions, type: opts?.type || 'selectElementsByPositions' });
}
cancelElements() {
@ -230,6 +239,14 @@ export class iDraw {
core.trigger(coreEventKeys.CHANGE, { data, type: 'updateElement' });
}
updateElementName(uuid: string, name: string) {
const core = this.#core;
const data: Data = core.getData() || { elements: [] };
updateElementInList(uuid, { name }, data.elements);
core.setData(data);
core.trigger(coreEventKeys.CHANGE, { data, type: 'updateElementName' });
}
addElement(
element: Element,
opts?: {
@ -241,7 +258,7 @@ export class iDraw {
if (!opts || !opts?.position?.length) {
data.elements.push(element);
} else if (opts?.position) {
const position = [...opts?.position];
const position = [...(opts?.position || [])];
insertElementToListByPosition(element, position, data.elements);
}
core.setData(data);
@ -270,6 +287,15 @@ export class iDraw {
core.trigger(coreEventKeys.CHANGE, { data, type: 'moveElement' });
}
updateLayout(layout: Partial<DataLayout>) {
const core = this.#core;
const data: Data = core.getData() || { elements: [] };
data.layout = merge(data.layout || {}, layout) as DataLayout;
core.setData(data);
core.refresh();
core.trigger(coreEventKeys.CHANGE, { data, type: 'updateLayout' });
}
async getImageBlobURL(opts?: ExportImageFileBaseOptions): Promise<ExportImageFileResult> {
const data = this.getData() || { elements: [] };
const { devicePixelRatio } = opts || { devicePixelRatio: 1 };

View file

@ -1,6 +1,15 @@
export type * from '@idraw/types';
export { Core, MiddlewareSelector, MiddlewareScroller, MiddlewareScaler, MiddlewareRuler, MiddlewareTextEditor, coreEventKeys } from '@idraw/core';
export { Sharer, Calculator } from '@idraw/board';
export {
Sharer,
Calculator,
Core,
MiddlewareSelector,
MiddlewareScroller,
MiddlewareScaler,
MiddlewareRuler,
MiddlewareTextEditor,
coreEventKeys
} from '@idraw/core';
export { Renderer } from '@idraw/renderer';
export {
delay,
@ -23,6 +32,7 @@ export {
isAssetId,
createAssetId,
deepClone,
deepCloneData,
sortDataAsserts,
istype,
loadImage,
@ -111,10 +121,10 @@ export {
modifyElement,
calcElementViewRectInfo,
calcElementOriginRectInfo,
calcElementViewRectInfoMap,
sortElementsViewVisiableInfoMap,
flatElementList,
calcPointMoveElementInGroup
calcPointMoveElementInGroup,
merge,
omit
} from '@idraw/util';
export { iDraw } from './idraw';
export { eventKeys } from './event';

View file

@ -1,4 +1,4 @@
import type { IDrawSettings, IDrawStorage, IDrawMode } from '@idraw/types';
import type { IDrawSettings, IDrawOptions, IDrawStorage, IDrawMode } from '@idraw/types';
import { istype } from '@idraw/util';
export const defaultMode: IDrawMode = 'select';
@ -7,6 +7,10 @@ export const defaultSettings: Required<Pick<IDrawSettings, 'mode'>> = {
mode: defaultMode
};
export const defaultOptions: Required<Pick<IDrawOptions, 'devicePixelRatio'>> = {
devicePixelRatio: window.devicePixelRatio
};
export function getDefaultStorage(): IDrawStorage {
const storage: IDrawStorage = {
mode: defaultMode,

View file

@ -1,6 +1,6 @@
{
"name": "@idraw/renderer",
"version": "0.4.0-beta.39",
"version": "0.4.0-beta.40",
"description": "",
"main": "dist/esm/index.js",
"module": "dist/esm/index.js",
@ -18,14 +18,14 @@
"url": "https://github.com/idrawjs/idraw/issues"
},
"homepage": "https://github.com/idrawjs/idraw#readme",
"author": "chenshenhai",
"author": "idrawjs",
"license": "MIT",
"devDependencies": {
"@idraw/types": "workspace:^0.4.0-beta.39"
"@idraw/types": "workspace:^0.4.0-beta.40"
},
"dependencies": {},
"peerDependencies": {
"@idraw/util": "workspace:^0.4.0-beta.39"
"@idraw/util": "workspace:^0.4.0-beta.40"
},
"publishConfig": {
"access": "public",

View file

@ -7,34 +7,34 @@ import type {
ViewCalculatorOptions,
ViewScaleInfo,
ViewSizeInfo,
ViewCalculatorStorage,
VirtualFlatStorage,
ViewRectInfo,
ModifyOptions,
ViewVisibleInfo
VirtualFlatItem
} from '@idraw/types';
import {
is,
isViewPointInElement,
getViewPointAtElement,
Store,
sortElementsViewVisiableInfoMap,
updateViewVisibleInfoMapStatus,
calcViewPointSize,
findElementFromListByPosition,
getGroupQueueByElementPosition,
calcElementOriginRectInfo,
originRectInfoToRangeRectInfo
// elementToBoxInfo
} from '@idraw/util';
import { sortElementsViewVisiableInfoMap, updateVirtualFlatItemMapStatus } from './view-visible';
import { calcVirtualFlatDetail } from './virtual-flat';
export class Calculator implements ViewCalculator {
#opts: ViewCalculatorOptions;
#store: Store<ViewCalculatorStorage>;
#store: Store<VirtualFlatStorage>;
constructor(opts: ViewCalculatorOptions) {
this.#opts = opts;
this.#store = new Store<ViewCalculatorStorage>({
this.#store = new Store<VirtualFlatStorage>({
defaultStorage: {
viewVisibleInfoMap: {},
virtualFlatItemMap: {},
visibleCount: 0,
invisibleCount: 0
}
@ -55,36 +55,23 @@ export class Calculator implements ViewCalculator {
}
needRender(elem: Element<ElementType>): boolean {
const viewVisibleInfoMap = this.#store.get('viewVisibleInfoMap');
const info = viewVisibleInfoMap[elem.uuid];
const virtualFlatItemMap = this.#store.get('virtualFlatItemMap');
const info = virtualFlatItemMap[elem.uuid];
if (!info) {
return true;
}
return info.isVisibleInView;
}
/**
* @deprecated
*/
isPointInElement(p: Point, elem: Element<ElementType>, viewScaleInfo: ViewScaleInfo, viewSizeInfo: ViewSizeInfo): boolean {
const context2d = this.#opts.viewContext;
return isViewPointInElement(p, {
context2d,
element: elem,
viewScaleInfo,
viewSizeInfo
});
}
getPointElement(
p: Point,
opts: { data: Data; viewScaleInfo: ViewScaleInfo; viewSizeInfo: ViewSizeInfo }
): { index: number; element: null | Element<ElementType>; groupQueueIndex: number } {
const context2d = this.#opts.viewContext;
const context2d = this.#opts.tempContext;
return getViewPointAtElement(p, { ...opts, ...{ context2d } });
}
resetViewVisibleInfoMap(
resetVirtualFlatItemMap(
data: Data,
opts: {
viewScaleInfo: ViewScaleInfo;
@ -92,16 +79,24 @@ export class Calculator implements ViewCalculator {
}
): void {
if (data) {
const { viewVisibleInfoMap, invisibleCount, visibleCount } = sortElementsViewVisiableInfoMap(data.elements, opts);
this.#store.set('viewVisibleInfoMap', viewVisibleInfoMap);
const { virtualFlatItemMap, invisibleCount, visibleCount } = sortElementsViewVisiableInfoMap(data.elements, {
...opts,
...{
tempContext: this.#opts.tempContext
}
});
this.#store.set('virtualFlatItemMap', virtualFlatItemMap);
this.#store.set('invisibleCount', invisibleCount);
this.#store.set('visibleCount', visibleCount);
}
}
updateVisiableStatus(opts: { viewScaleInfo: ViewScaleInfo; viewSizeInfo: ViewSizeInfo }) {
const { viewVisibleInfoMap, invisibleCount, visibleCount } = updateViewVisibleInfoMapStatus(this.#store.get('viewVisibleInfoMap'), opts);
this.#store.set('viewVisibleInfoMap', viewVisibleInfoMap);
const { virtualFlatItemMap, invisibleCount, visibleCount } = updateVirtualFlatItemMapStatus(
this.#store.get('virtualFlatItemMap'),
opts
);
this.#store.set('virtualFlatItemMap', virtualFlatItemMap);
this.#store.set('invisibleCount', invisibleCount);
this.#store.set('visibleCount', visibleCount);
}
@ -114,7 +109,7 @@ export class Calculator implements ViewCalculator {
viewSizeInfo: ViewSizeInfo;
}
): ViewRectInfo | null {
const infoData = this.#store.get('viewVisibleInfoMap')[uuid];
const infoData = this.#store.get('virtualFlatItemMap')[uuid];
if (!infoData?.originRectInfo) {
return null;
}
@ -148,7 +143,7 @@ export class Calculator implements ViewCalculator {
viewSizeInfo: ViewSizeInfo;
}
): ViewRectInfo | null {
const infoData = this.#store.get('viewVisibleInfoMap')[uuid];
const infoData = this.#store.get('virtualFlatItemMap')[uuid];
if (!infoData?.originRectInfo) {
return null;
}
@ -174,7 +169,7 @@ export class Calculator implements ViewCalculator {
return viewRectInfo;
}
modifyViewVisibleInfoMap(
modifyVirtualFlatItemMap(
data: Data,
opts: {
modifyOptions: ModifyOptions; // TODO
@ -185,7 +180,7 @@ export class Calculator implements ViewCalculator {
const { modifyOptions, viewScaleInfo, viewSizeInfo } = opts;
const { type, content } = modifyOptions;
const list = data.elements;
const viewVisibleInfoMap = this.#store.get('viewVisibleInfoMap');
const virtualFlatItemMap = this.#store.get('virtualFlatItemMap');
if (type === 'deleteElement') {
const { element } = content as ModifyOptions<'deleteElement'>['content'];
const uuids: string[] = [];
@ -199,13 +194,13 @@ export class Calculator implements ViewCalculator {
};
_walk(element);
uuids.forEach((uuid) => {
delete viewVisibleInfoMap[uuid];
delete virtualFlatItemMap[uuid];
});
this.#store.set('viewVisibleInfoMap', viewVisibleInfoMap);
this.#store.set('virtualFlatItemMap', virtualFlatItemMap);
}
// else if (type === 'updateElement') {
// // TODO
// this.resetViewVisibleInfoMap(data, { viewScaleInfo, viewSizeInfo });
// this.resetVirtualFlatItemMap(data, { viewScaleInfo, viewSizeInfo });
// }
else if (type === 'addElement' || type === 'updateElement') {
const { position } = content as ModifyOptions<'addElement'>['content'];
@ -214,27 +209,35 @@ export class Calculator implements ViewCalculator {
if (element) {
if (type === 'updateElement' && element.type === 'group') {
// TODO
this.resetViewVisibleInfoMap(data, { viewScaleInfo, viewSizeInfo });
this.resetVirtualFlatItemMap(data, { viewScaleInfo, viewSizeInfo });
} else {
const originRectInfo = calcElementOriginRectInfo(element, {
groupQueue: groupQueue || []
});
const newViewVisibleInfo: ViewVisibleInfo = {
const newVirtualFlatItem: VirtualFlatItem = {
type: element.type,
originRectInfo,
rangeRectInfo: is.angle(element.angle) ? originRectInfoToRangeRectInfo(originRectInfo) : originRectInfo,
isVisibleInView: true,
isGroup: element?.type === 'group',
position: [...position]
position: [...position],
...calcVirtualFlatDetail(element, {
tempContext: this.#opts.tempContext
})
};
viewVisibleInfoMap[element.uuid] = newViewVisibleInfo;
this.#store.set('viewVisibleInfoMap', viewVisibleInfoMap);
virtualFlatItemMap[element.uuid] = newVirtualFlatItem;
this.#store.set('virtualFlatItemMap', virtualFlatItemMap);
if (type === 'updateElement') {
this.updateVisiableStatus({ viewScaleInfo, viewSizeInfo });
}
}
}
} else if (type === 'moveElement') {
this.resetViewVisibleInfoMap(data, { viewScaleInfo, viewSizeInfo });
this.resetVirtualFlatItemMap(data, { viewScaleInfo, viewSizeInfo });
}
}
getVirtualFlatItem(uuid: string): VirtualFlatItem | null {
const itemMap = this.#store.get('virtualFlatItemMap');
return itemMap[uuid] || null;
}
}

View file

@ -1,5 +1,25 @@
import { ViewContext2D, Element, ElementType, ElementSize, ViewScaleInfo, ViewSizeInfo, TransformAction } from '@idraw/types';
import { istype, isColorStr, generateSVGPath, rotateElement, is, getDefaultElementDetailConfig, calcViewBoxSize } from '@idraw/util';
import {
ViewContext2D,
Element,
ElementType,
ElementSize,
ViewScaleInfo,
ViewSizeInfo,
TransformAction
// PointSize
} from '@idraw/types';
import {
istype,
isColorStr,
generateSVGPath,
rotateElement,
is,
getDefaultElementDetailConfig,
calcViewBoxSize
// elementToBoxInfo,
// calcViewPointSize
} from '@idraw/util';
import { Calculator } from '../calculator';
import { createColorStyle } from './color';
const defaultElemConfig = getDefaultElementDetailConfig();
@ -35,7 +55,7 @@ export function drawBox(
ctx.globalAlpha = opacity;
drawBoxBackground(ctx, viewElem, { pattern, viewScaleInfo, viewSizeInfo });
renderContent?.();
drawBoxBorder(ctx, viewElem, { viewScaleInfo, viewSizeInfo });
drawBoxBorder(ctx, viewElem, { originElem, viewScaleInfo, viewSizeInfo });
ctx.globalAlpha = parentOpacity;
};
if (clipPath) {
@ -122,7 +142,14 @@ function drawClipPathStroke(
const { renderContent, originElem, calcElemSize, viewSizeInfo, parentOpacity } = opts;
const totalScale = viewSizeInfo.devicePixelRatio;
const { clipPath, clipPathStrokeColor, clipPathStrokeWidth } = originElem?.detail || {};
if (clipPath && calcElemSize && clipPath.commands && typeof clipPathStrokeWidth === 'number' && clipPathStrokeWidth > 0 && clipPathStrokeColor) {
if (
clipPath &&
calcElemSize &&
clipPath.commands &&
typeof clipPathStrokeWidth === 'number' &&
clipPathStrokeWidth > 0 &&
clipPathStrokeColor
) {
const { x, y, w, h } = calcElemSize;
const { originW, originH, originX, originY } = clipPath;
const scaleW = w / originW;
@ -217,7 +244,11 @@ export function drawBoxBackground(
}
}
export function drawBoxBorder(ctx: ViewContext2D, viewElem: Element<ElementType>, opts: { viewScaleInfo: ViewScaleInfo; viewSizeInfo: ViewSizeInfo }): void {
export function drawBoxBorder(
ctx: ViewContext2D,
viewElem: Element<ElementType>,
opts: { originElem: Element; viewScaleInfo: ViewScaleInfo; viewSizeInfo: ViewSizeInfo; calculator?: Calculator }
): void {
if (viewElem.detail.borderWidth === 0) {
return;
}
@ -230,12 +261,18 @@ export function drawBoxBorder(ctx: ViewContext2D, viewElem: Element<ElementType>
if (isColorStr(viewElem.detail.borderColor) === true) {
borderColor = viewElem.detail.borderColor as string;
}
const { borderWidth, borderRadius, borderDash, boxSizing = defaultElemConfig.boxSizing } = viewElem.detail;
let bw: number = 0;
if (typeof borderWidth === 'number') {
bw = borderWidth || 1;
const { borderDash, borderWidth, borderRadius, boxSizing = defaultElemConfig.boxSizing } = viewElem.detail;
let viewBorderDash: number[] = [];
if (Array.isArray(borderDash) && borderDash.length > 0) {
viewBorderDash = borderDash.map((num) => Math.ceil(num * scale));
}
bw = bw * scale;
if (viewBorderDash.length > 0) {
ctx.lineCap = 'butt';
} else {
ctx.lineCap = 'square';
}
let radiusList: [number, number, number, number] = [0, 0, 0, 0];
if (typeof borderRadius === 'number') {
const br = borderRadius * scale;
@ -243,11 +280,75 @@ export function drawBoxBorder(ctx: ViewContext2D, viewElem: Element<ElementType>
} else if (Array.isArray(borderRadius) && borderRadius?.length === 4) {
radiusList = [borderRadius[0] * scale, borderRadius[1] * scale, borderRadius[2] * scale, borderRadius[3] * scale];
}
ctx.strokeStyle = borderColor;
let viewBorderDash: number[] = [];
if (Array.isArray(borderDash) && borderDash.length > 0) {
viewBorderDash = borderDash.map((num) => Math.ceil(num * scale));
// // TODO
// const boxInfo = elementToBoxInfo(opts.originElem);
// const calcViewOpts = { viewScaleInfo, viewSizeInfo: opts.viewSizeInfo };
// const op0: PointSize = calcViewPointSize(boxInfo.op0, calcViewOpts);
// const op1: PointSize = calcViewPointSize(boxInfo.op1, calcViewOpts);
// const op2: PointSize = calcViewPointSize(boxInfo.op2, calcViewOpts);
// const op3: PointSize = calcViewPointSize(boxInfo.op3, calcViewOpts);
// const op0s: PointSize = calcViewPointSize(boxInfo.op0s, calcViewOpts);
// const op0e: PointSize = calcViewPointSize(boxInfo.op0e, calcViewOpts);
// const op1s: PointSize = calcViewPointSize(boxInfo.op1s, calcViewOpts);
// const op1e: PointSize = calcViewPointSize(boxInfo.op1e, calcViewOpts);
// const op2s: PointSize = calcViewPointSize(boxInfo.op2s, calcViewOpts);
// const op2e: PointSize = calcViewPointSize(boxInfo.op2e, calcViewOpts);
// const op3s: PointSize = calcViewPointSize(boxInfo.op3s, calcViewOpts);
// const op3e: PointSize = calcViewPointSize(boxInfo.op3e, calcViewOpts);
// const ip0: PointSize = calcViewPointSize(boxInfo.ip0, calcViewOpts);
// const ip1: PointSize = calcViewPointSize(boxInfo.ip1, calcViewOpts);
// const ip2: PointSize = calcViewPointSize(boxInfo.ip2, calcViewOpts);
// const ip3: PointSize = calcViewPointSize(boxInfo.ip3, calcViewOpts);
// const ip0s: PointSize = calcViewPointSize(boxInfo.ip0s, calcViewOpts);
// const ip0e: PointSize = calcViewPointSize(boxInfo.ip0e, calcViewOpts);
// const ip1s: PointSize = calcViewPointSize(boxInfo.ip1s, calcViewOpts);
// const ip1e: PointSize = calcViewPointSize(boxInfo.ip1e, calcViewOpts);
// const ip2s: PointSize = calcViewPointSize(boxInfo.ip2s, calcViewOpts);
// const ip2e: PointSize = calcViewPointSize(boxInfo.ip2e, calcViewOpts);
// const ip3s: PointSize = calcViewPointSize(boxInfo.ip3s, calcViewOpts);
// const ip3e: PointSize = calcViewPointSize(boxInfo.ip3e, calcViewOpts);
// ctx.fillStyle = borderColor;
// ctx.beginPath();
// ctx.moveTo(op0s.x, op0s.y);
// ctx.quadraticCurveTo(op0.x, op0.y, op0e.x, op0e.y);
// ctx.lineTo(op1s.x, op1s.y);
// ctx.quadraticCurveTo(op1.x, op1.y, op1e.x, op1e.y);
// ctx.lineTo(op2s.x, op2s.y);
// ctx.quadraticCurveTo(op2.x, op2.y, op2e.x, op2e.y);
// ctx.lineTo(op3s.x, op3s.y);
// ctx.quadraticCurveTo(op3.x, op3.y, op3e.x, op3e.y);
// ctx.lineTo(op0s.x, op0s.y);
// ctx.closePath();
// ctx.fill();
// ctx.fillStyle = '#000000';
// ctx.globalCompositeOperation = 'destination-out';
// ctx.beginPath();
// ctx.moveTo(ip0s.x, ip0s.y);
// ctx.quadraticCurveTo(ip0.x, ip0.y, ip0e.x, ip0e.y);
// ctx.lineTo(ip1s.x, ip1s.y);
// ctx.quadraticCurveTo(ip1.x, ip1.y, ip1e.x, ip1e.y);
// ctx.lineTo(ip2s.x, ip2s.y);
// ctx.quadraticCurveTo(ip2.x, ip2.y, ip2e.x, ip2e.y);
// ctx.lineTo(ip3s.x, ip3s.y);
// ctx.quadraticCurveTo(ip3.x, ip3.y, ip3e.x, ip3e.y);
// ctx.lineTo(ip0s.x, ip0s.y);
// ctx.closePath();
// ctx.fill();
// ctx.globalCompositeOperation = 'source-over';
// return;
// // TODO
let bw: number = 0;
if (typeof borderWidth === 'number') {
bw = borderWidth || 1;
}
bw = bw * scale;
ctx.strokeStyle = borderColor;
let borderTop = 0;
let borderRight = 0;
@ -338,11 +439,6 @@ export function drawBoxBorder(ctx: ViewContext2D, viewElem: Element<ElementType>
// if (r < w / 2 && r < h / 2) {
// r = r + bw / 2;
// }
if (viewBorderDash.length > 0) {
ctx.lineCap = 'butt';
} else {
ctx.lineCap = 'square';
}
// TODO
w = Math.max(w, 1);

View file

@ -33,8 +33,8 @@ export function drawCircle(ctx: ViewContext2D, elem: Element<'circle'>, opts: Re
const radiusB = b;
if (bw > 0) {
if (boxSizing === 'content-box') {
a = a;
b = b;
// a = a;
// b = b;
} else if (boxSizing === 'center-line') {
a = a - bw / 2;
b = b - bw / 2;

View file

@ -72,13 +72,15 @@ export function drawElement(ctx: ViewContext2D, elem: Element<ElementType>, opts
}
}
} catch (err) {
// eslint-disable-next-line no-console
console.error(err);
}
}
export function drawGroup(ctx: ViewContext2D, elem: Element<'group'>, opts: RendererDrawElementOptions) {
const { viewScaleInfo, viewSizeInfo, parentOpacity } = opts;
const { x, y, w, h, angle } = calcViewElementSize({ x: elem.x, y: elem.y, w: elem.w, h: elem.h, angle: elem.angle }, { viewScaleInfo }) || elem;
const { x, y, w, h, angle } =
calcViewElementSize({ x: elem.x, y: elem.y, w: elem.w, h: elem.h, angle: elem.angle }, { viewScaleInfo }) || elem;
const viewElem = { ...elem, ...{ x, y, w, h, angle } };
rotateElement(ctx, { x, y, w, h, angle }, () => {
ctx.globalAlpha = getOpacity(elem) * parentOpacity;
@ -141,6 +143,7 @@ export function drawGroup(ctx: ViewContext2D, elem: Element<'group'>, opts: Rend
try {
drawElement(ctx, child, { ...opts, ...{ parentOpacity: parentOpacity * getOpacity(elem) } });
} catch (err) {
// eslint-disable-next-line no-console
console.error(err);
}
}

View file

@ -2,7 +2,12 @@ import type { RendererDrawElementOptions, ViewContext2D, DataLayout, Element } f
import { calcViewElementSize, calcViewBoxSize } from '@idraw/util';
import { drawBoxShadow, drawBoxBackground, drawBoxBorder } from './box';
export function drawLayout(ctx: ViewContext2D, layout: DataLayout, opts: RendererDrawElementOptions, renderContent: (ctx: ViewContext2D) => void) {
export function drawLayout(
ctx: ViewContext2D,
layout: DataLayout,
opts: RendererDrawElementOptions,
renderContent: (ctx: ViewContext2D) => void
) {
const { viewScaleInfo, viewSizeInfo, parentOpacity } = opts;
const elem: Element = { uuid: 'layout', type: 'group', ...layout } as Element;
const { x, y, w, h } = calcViewElementSize(elem, { viewScaleInfo }) || elem;
@ -46,6 +51,6 @@ export function drawLayout(ctx: ViewContext2D, layout: DataLayout, opts: Rendere
ctx.restore();
}
drawBoxBorder(ctx, viewElem, { viewScaleInfo, viewSizeInfo });
drawBoxBorder(ctx, viewElem, { originElem: elem, viewScaleInfo, viewSizeInfo });
ctx.globalAlpha = parentOpacity;
}

View file

@ -5,18 +5,8 @@ import { drawBox, drawBoxShadow } from './box';
const detailConfig = getDefaultElementDetailConfig();
// TODO
function isTextWidthWithinErrorRange(w0: number, w1: number, scale: number): boolean {
if (scale < 0.5) {
if (w0 < w1 && (w0 - w1) / w0 > -0.15) {
return true;
}
}
return w0 >= w1;
}
export function drawText(ctx: ViewContext2D, elem: Element<'text'>, opts: RendererDrawElementOptions) {
const { viewScaleInfo, viewSizeInfo, parentOpacity } = opts;
const { viewScaleInfo, viewSizeInfo, parentOpacity, calculator } = opts;
const { x, y, w, h, angle } = calcViewElementSize(elem, { viewScaleInfo }) || elem;
const viewElem = { ...elem, ...{ x, y, w, h, angle } };
rotateElement(ctx, { x, y, w, h, angle }, () => {
@ -45,9 +35,6 @@ export function drawText(ctx: ViewContext2D, elem: Element<'text'>, opts: Render
return;
}
const originLineHeight = detail.lineHeight || originFontSize;
const lineHeight = originLineHeight * viewScaleInfo.scale;
ctx.fillStyle = elem.detail.color || detailConfig.color;
ctx.textBaseline = 'top';
ctx.$setFont({
@ -55,143 +42,28 @@ export function drawText(ctx: ViewContext2D, elem: Element<'text'>, opts: Render
fontSize: fontSize,
fontFamily: enhanceFontFamliy(detail.fontFamily)
});
let detailText = detail.text.replace(/\r\n/gi, '\n');
if (detail.textTransform === 'lowercase') {
detailText = detailText.toLowerCase();
} else if (detail.textTransform === 'uppercase') {
detailText = detailText.toUpperCase();
}
const fontHeight = lineHeight;
const detailTextList = detailText.split('\n');
const lines: { text: string; width: number }[] = [];
let lineNum = 0;
detailTextList.forEach((itemText: string, idx: number) => {
if (detail.minInlineSize === 'maxContent') {
lines.push({
text: itemText,
width: ctx.$undoPixelRatio(ctx.measureText(itemText).width)
});
} else {
let lineText = '';
let splitStr = '';
let tempStrList: string[] = itemText.split(splitStr);
if (detail.wordBreak === 'normal') {
const splitStr = ' ';
const wordList = itemText.split(splitStr);
tempStrList = [];
wordList.forEach((word: string, idx: number) => {
tempStrList.push(word);
if (idx < wordList.length - 1) {
tempStrList.push(splitStr);
}
});
}
if (tempStrList.length === 1 && detail.overflow === 'visible') {
lines.push({
text: tempStrList[0],
width: ctx.$undoPixelRatio(ctx.measureText(tempStrList[0]).width)
});
} else if (tempStrList.length > 0) {
for (let i = 0; i < tempStrList.length; i++) {
if (isTextWidthWithinErrorRange(ctx.$doPixelRatio(w), ctx.measureText(lineText + tempStrList[i]).width, viewScaleInfo.scale)) {
lineText += tempStrList[i] || '';
} else {
lines.push({
text: lineText,
width: ctx.$undoPixelRatio(ctx.measureText(lineText).width)
});
lineText = tempStrList[i] || '';
lineNum++;
}
if ((lineNum + 1) * fontHeight > h && detail.overflow === 'hidden') {
break;
}
if (tempStrList.length - 1 === i) {
if ((lineNum + 1) * fontHeight <= h) {
lines.push({
text: lineText,
width: ctx.$undoPixelRatio(ctx.measureText(lineText).width)
});
if (idx < detailTextList.length - 1) {
lineNum++;
}
break;
}
}
}
} else {
lines.push({
text: '',
width: 0
});
}
}
});
let startY = 0;
let eachLineStartY = 0;
if (fontHeight > fontSize) {
eachLineStartY = (fontHeight - fontSize) / 2;
}
if (lines.length * fontHeight < h) {
if (elem.detail.verticalAlign === 'top') {
startY = 0;
} else if (elem.detail.verticalAlign === 'bottom') {
startY += h - lines.length * fontHeight;
} else {
// middle and default
startY += (h - lines.length * fontHeight) / 2;
}
}
// draw text lines
{
const _y = y + startY;
if (detail.textShadowColor !== undefined && isColorStr(detail.textShadowColor)) {
ctx.shadowColor = detail.textShadowColor;
}
if (detail.textShadowOffsetX !== undefined && is.number(detail.textShadowOffsetX)) {
ctx.shadowOffsetX = detail.textShadowOffsetX;
}
if (detail.textShadowOffsetY !== undefined && is.number(detail.textShadowOffsetY)) {
ctx.shadowOffsetY = detail.textShadowOffsetY;
}
if (detail.textShadowBlur !== undefined && is.number(detail.textShadowBlur)) {
ctx.shadowBlur = detail.textShadowBlur;
}
lines.forEach((line, i) => {
let _x = x;
if (detail.textAlign === 'center') {
_x = x + (w - line.width) / 2;
} else if (detail.textAlign === 'right') {
_x = x + (w - line.width);
const virtualTextDetail = calculator.getVirtualFlatItem(elem.uuid);
if (Array.isArray(virtualTextDetail?.textLines) && virtualTextDetail?.textLines?.length > 0) {
if (detail.textShadowColor !== undefined && isColorStr(detail.textShadowColor)) {
ctx.shadowColor = detail.textShadowColor;
}
if (detail.textShadowOffsetX !== undefined && is.number(detail.textShadowOffsetX)) {
ctx.shadowOffsetX = detail.textShadowOffsetX;
}
if (detail.textShadowOffsetY !== undefined && is.number(detail.textShadowOffsetY)) {
ctx.shadowOffsetY = detail.textShadowOffsetY;
}
if (detail.textShadowBlur !== undefined && is.number(detail.textShadowBlur)) {
ctx.shadowBlur = detail.textShadowBlur;
}
ctx.fillText(line.text, _x, _y + fontHeight * i + eachLineStartY);
});
}
// // draw text stroke
// if (isColorStr(detail.strokeColor) && detail.strokeWidth !== undefined && detail.strokeWidth > 0) {
// const _y = y + startY;
// lines.forEach((line, i) => {
// let _x = x;
// if (detail.textAlign === 'center') {
// _x = x + (w - line.width) / 2;
// } else if (detail.textAlign === 'right') {
// _x = x + (w - line.width);
// }
// if (detail.strokeColor !== undefined) {
// ctx.strokeStyle = detail.strokeColor;
// }
// if (detail.strokeWidth !== undefined && detail.strokeWidth > 0) {
// ctx.lineWidth = detail.strokeWidth;
// }
// ctx.strokeText(line.text, _x, _y + fontHeight * i);
// });
// }
virtualTextDetail?.textLines?.forEach((line) => {
ctx.fillText(line.text, x + line.x * viewScaleInfo.scale, y + line.y * viewScaleInfo.scale);
});
}
}
}
});
}

View file

@ -3,15 +3,21 @@ import type { DataLayout, LoadItemMap } from '@idraw/types';
import { drawElementList, drawLayout, drawGlobalBackground } from './draw/index';
import { Loader } from './loader';
import type { Data, BoardRenderer, RendererOptions, RendererEventMap, RendererDrawOptions } from '@idraw/types';
import { Calculator } from './calculator';
export { Calculator };
export class Renderer extends EventEmitter<RendererEventMap> implements BoardRenderer {
#opts: RendererOptions;
#loader: Loader = new Loader();
#calculator: Calculator;
#hasDestroyed: boolean = false;
constructor(opts: RendererOptions) {
super();
this.#opts = opts;
this.#calculator = new Calculator({
tempContext: opts.tempContext
});
this.#init();
}
@ -45,7 +51,8 @@ export class Renderer extends EventEmitter<RendererEventMap> implements BoardRen
drawData(data: Data, opts: RendererDrawOptions) {
const loader = this.#loader;
const { calculator, sharer } = this.#opts;
const calculator = this.#calculator;
const { sharer } = this.#opts;
const viewContext = this.#opts.viewContext;
viewContext.clearRect(0, 0, viewContext.canvas.width, viewContext.canvas.height);
const parentElementSize = {
@ -88,8 +95,18 @@ export class Renderer extends EventEmitter<RendererEventMap> implements BoardRen
// TODO
return;
}
const { data, offsetTop, offsetBottom, offsetLeft, offsetRight, width, height, contextHeight, contextWidth, devicePixelRatio } =
sharer.getActiveStoreSnapshot();
const {
data,
offsetTop,
offsetBottom,
offsetLeft,
offsetRight,
width,
height,
contextHeight,
contextWidth,
devicePixelRatio
} = sharer.getActiveStoreSnapshot();
if (data) {
this.drawData(data, {
viewScaleInfo: {
@ -121,6 +138,10 @@ export class Renderer extends EventEmitter<RendererEventMap> implements BoardRen
getLoader(): Loader {
return this.#loader;
}
getCalculator(): Calculator {
return this.#calculator;
}
}
export {

View file

@ -1,61 +1,22 @@
import { Element, ElementPosition, Elements, ViewScaleInfo, ViewSizeInfo, ViewRectInfo, ViewVisibleInfoMap, ViewVisibleInfo } from '@idraw/types';
import { calcElementOriginRectInfo, originRectInfoToRangeRectInfo } from './view-calc';
import { getGroupQueueByElementPosition } from './element';
import { calcElementCenter } from './rotate';
import { is } from './is';
import { Elements, ViewScaleInfo, ViewSizeInfo, ViewRectInfo, VirtualFlatItemMap, ViewContext2D } from '@idraw/types';
import { calcElementCenter } from '@idraw/util';
import { elementsToVirtualFlatMap } from '../virtual-flat';
export function sortElementsViewVisiableInfoMap(
elements: Elements,
opts: {
viewScaleInfo: ViewScaleInfo;
viewSizeInfo: ViewSizeInfo;
tempContext: ViewContext2D;
}
): {
viewVisibleInfoMap: ViewVisibleInfoMap;
virtualFlatItemMap: VirtualFlatItemMap;
visibleCount: number;
invisibleCount: number;
} {
const visibleInfoMap: ViewVisibleInfoMap = {};
const currentPosition: ElementPosition = [];
const _walk = (elem: Element) => {
const baseInfo: Omit<ViewVisibleInfo, 'originRectInfo' | 'rangeRectInfo'> = {
isVisibleInView: true,
isGroup: elem.type === 'group',
position: [...currentPosition]
};
let originRectInfo: ViewRectInfo | null = null;
const groupQueue = getGroupQueueByElementPosition(elements, currentPosition);
originRectInfo = calcElementOriginRectInfo(elem, {
groupQueue: groupQueue || []
});
visibleInfoMap[elem.uuid] = {
...baseInfo,
...{
originRectInfo: originRectInfo as ViewRectInfo,
rangeRectInfo: is.angle(elem.angle) ? originRectInfoToRangeRectInfo(originRectInfo as ViewRectInfo) : originRectInfo
}
};
if (elem.type === 'group') {
(elem as Element<'group'>).detail.children.forEach((ele, i) => {
currentPosition.push(i);
_walk(ele);
currentPosition.pop();
});
}
};
elements.forEach((elem, index) => {
currentPosition.push(index);
_walk(elem);
currentPosition.pop();
});
return updateViewVisibleInfoMapStatus(visibleInfoMap, opts);
const { viewScaleInfo, viewSizeInfo, tempContext } = opts;
const visibleInfoMap: VirtualFlatItemMap = elementsToVirtualFlatMap(elements, { tempContext });
return updateVirtualFlatItemMapStatus(visibleInfoMap, { viewScaleInfo, viewSizeInfo });
}
function isRangeRectInfoCollide(info1: ViewRectInfo, info2: ViewRectInfo): boolean {
@ -79,10 +40,10 @@ function isRangeRectInfoCollide(info1: ViewRectInfo, info2: ViewRectInfo): boole
return false;
}
// function logViewVisibleInfoMapStatus(viewVisibleInfoMap: ViewVisibleInfoMap) {
// function logVirtualFlatItemMapStatus(virtualFlatItemMap: VirtualFlatItemMap) {
// console.log('------------------------------------------------');
// Object.keys(viewVisibleInfoMap).forEach((uuid) => {
// const item = viewVisibleInfoMap[uuid];
// Object.keys(virtualFlatItemMap).forEach((uuid) => {
// const item = virtualFlatItemMap[uuid];
// const info = item.originRectInfo;
// const rect = {
// x: info.topLeft.x,
@ -94,31 +55,34 @@ function isRangeRectInfoCollide(info1: ViewRectInfo, info2: ViewRectInfo): boole
// });
// }
export function updateViewVisibleInfoMapStatus(
viewVisibleInfoMap: ViewVisibleInfoMap,
export function updateVirtualFlatItemMapStatus(
virtualFlatItemMap: VirtualFlatItemMap,
opts: { viewScaleInfo: ViewScaleInfo; viewSizeInfo: ViewSizeInfo }
): {
viewVisibleInfoMap: ViewVisibleInfoMap;
virtualFlatItemMap: VirtualFlatItemMap;
visibleCount: number;
invisibleCount: number;
} {
const canvasRectInfo = calcVisibleOriginCanvasRectInfo(opts);
let visibleCount = 0;
let invisibleCount = 0;
Object.keys(viewVisibleInfoMap).forEach((uuid) => {
const info = viewVisibleInfoMap[uuid];
Object.keys(virtualFlatItemMap).forEach((uuid) => {
const info = virtualFlatItemMap[uuid];
info.isVisibleInView = isRangeRectInfoCollide(info.rangeRectInfo, canvasRectInfo);
// eslint-disable-next-line @typescript-eslint/no-unused-expressions
info.isVisibleInView ? visibleCount++ : invisibleCount++;
});
// logViewVisibleInfoMapStatus(viewVisibleInfoMap);
// logVirtualFlatItemMapStatus(virtualFlatItemMap);
return { viewVisibleInfoMap, visibleCount, invisibleCount };
return { virtualFlatItemMap, visibleCount, invisibleCount };
}
export function calcVisibleOriginCanvasRectInfo(opts: { viewScaleInfo: ViewScaleInfo; viewSizeInfo: ViewSizeInfo }): ViewRectInfo {
export function calcVisibleOriginCanvasRectInfo(opts: {
viewScaleInfo: ViewScaleInfo;
viewSizeInfo: ViewSizeInfo;
}): ViewRectInfo {
const { viewScaleInfo, viewSizeInfo } = opts;
// console.log('xxx ===== ', viewScaleInfo, viewSizeInfo);
const { scale, offsetTop, offsetLeft } = viewScaleInfo;
const { width, height } = viewSizeInfo;

View file

@ -0,0 +1,75 @@
import {
Element,
ElementPosition,
Elements,
ViewRectInfo,
VirtualFlatItemMap,
VirtualFlatItem,
VirtualFlatDetail,
ViewContext2D
} from '@idraw/types';
import {
is,
getGroupQueueByElementPosition,
calcElementOriginRectInfo,
originRectInfoToRangeRectInfo
} from '@idraw/util';
import { calcVirtualTextDetail } from './text';
export function calcVirtualFlatDetail(elem: Element, opts: { tempContext: ViewContext2D }): VirtualFlatDetail {
let virtualDetail: VirtualFlatDetail = {};
if (elem.type === 'text') {
virtualDetail = calcVirtualTextDetail(elem as Element<'text'>, opts);
}
return virtualDetail;
}
export function elementsToVirtualFlatMap(elements: Elements, opts: { tempContext: ViewContext2D }): VirtualFlatItemMap {
const virtualFlatMap: VirtualFlatItemMap = {};
const currentPosition: ElementPosition = [];
const _walk = (elem: Element) => {
const baseInfo: Omit<VirtualFlatItem, 'originRectInfo' | 'rangeRectInfo'> = {
type: elem.type,
isVisibleInView: true,
position: [...currentPosition]
};
let originRectInfo: ViewRectInfo | null = null;
const groupQueue = getGroupQueueByElementPosition(elements, currentPosition);
originRectInfo = calcElementOriginRectInfo(elem, {
groupQueue: groupQueue || []
});
const virtualItem: VirtualFlatItem = {
...baseInfo,
...{
originRectInfo: originRectInfo as ViewRectInfo,
rangeRectInfo: is.angle(elem.angle)
? originRectInfoToRangeRectInfo(originRectInfo as ViewRectInfo)
: originRectInfo
},
...calcVirtualFlatDetail(elem, opts)
};
virtualFlatMap[elem.uuid] = virtualItem;
if (elem.type === 'group') {
(elem as Element<'group'>).detail.children.forEach((ele, i) => {
currentPosition.push(i);
_walk(ele);
currentPosition.pop();
});
}
};
elements.forEach((elem, index) => {
currentPosition.push(index);
_walk(elem);
currentPosition.pop();
});
return virtualFlatMap;
}

View file

@ -0,0 +1,163 @@
import type { Element, CalcVirtualDetailOptions, VirtualFlatTextDetail, VirtualFlatTextLine } from '@idraw/types';
import { enhanceFontFamliy, getDefaultElementDetailConfig } from '@idraw/util';
const detailConfig = getDefaultElementDetailConfig();
// TODO
function isTextWidthWithinErrorRange(w0: number, w1: number, scale: number): boolean {
if (scale < 0.5) {
if (w0 < w1 && (w0 - w1) / w0 > -0.15) {
return true;
}
}
return w0 >= w1;
}
export function calcVirtualTextDetail(elem: Element<'text'>, opts: CalcVirtualDetailOptions): VirtualFlatTextDetail {
const { w, h } = elem;
const x = 0;
const y = 0;
const ctx = opts.tempContext;
const lines: VirtualFlatTextLine[] = [];
const detail: Element<'text'>['detail'] = {
...detailConfig,
...elem.detail
};
const originFontSize = detail.fontSize || detailConfig.fontSize;
const fontSize = originFontSize;
if (fontSize < 2) {
return {};
}
const originLineHeight = detail.lineHeight || originFontSize;
const lineHeight = originLineHeight;
ctx.textBaseline = 'top';
ctx.$setFont({
fontWeight: detail.fontWeight,
fontSize: fontSize,
fontFamily: enhanceFontFamliy(detail.fontFamily)
});
let detailText = detail.text.replace(/\r\n/gi, '\n');
if (detail.textTransform === 'lowercase') {
detailText = detailText.toLowerCase();
} else if (detail.textTransform === 'uppercase') {
detailText = detailText.toUpperCase();
}
const fontHeight = lineHeight;
const detailTextList = detailText.split('\n');
let lineNum = 0;
detailTextList.forEach((itemText: string, idx: number) => {
if (detail.minInlineSize === 'maxContent') {
lines.push({
x,
y: 0, // TODO
text: itemText,
width: ctx.$undoPixelRatio(ctx.measureText(itemText).width)
});
} else {
let lineText = '';
let splitStr = '';
let tempStrList: string[] = itemText.split(splitStr);
if (detail.wordBreak === 'normal') {
splitStr = ' ';
const wordList = itemText.split(splitStr);
tempStrList = [];
wordList.forEach((word: string, idx: number) => {
tempStrList.push(word);
if (idx < wordList.length - 1) {
tempStrList.push(splitStr);
}
});
}
if (tempStrList.length === 1 && detail.overflow === 'visible') {
lines.push({
x,
y: 0, // TODO
text: tempStrList[0],
width: ctx.$undoPixelRatio(ctx.measureText(tempStrList[0]).width)
});
} else if (tempStrList.length > 0) {
for (let i = 0; i < tempStrList.length; i++) {
if (isTextWidthWithinErrorRange(ctx.$doPixelRatio(w), ctx.measureText(lineText + tempStrList[i]).width, 1)) {
lineText += tempStrList[i] || '';
} else {
lines.push({
x,
y: 0, // TODO
text: lineText,
width: ctx.$undoPixelRatio(ctx.measureText(lineText).width)
});
lineText = tempStrList[i] || '';
lineNum++;
}
if ((lineNum + 1) * fontHeight > h && detail.overflow === 'hidden') {
break;
}
if (tempStrList.length - 1 === i) {
if ((lineNum + 1) * fontHeight <= h) {
lines.push({
x,
y: 0, // TODO
text: lineText,
width: ctx.$undoPixelRatio(ctx.measureText(lineText).width)
});
if (idx < detailTextList.length - 1) {
lineNum++;
}
break;
}
}
}
} else {
lines.push({
x,
y: 0, // TODO
text: '',
width: 0
});
}
}
});
let startY = 0;
let eachLineStartY = 0;
if (fontHeight > fontSize) {
eachLineStartY = (fontHeight - fontSize) / 2;
}
if (lines.length * fontHeight < h) {
if (elem.detail.verticalAlign === 'top') {
startY = 0;
} else if (elem.detail.verticalAlign === 'bottom') {
startY += h - lines.length * fontHeight;
} else {
// middle and default
startY += (h - lines.length * fontHeight) / 2;
}
}
// draw text lines
{
const _y = y + startY;
lines.forEach((line, i) => {
let _x = x;
if (detail.textAlign === 'center') {
_x = x + (w - line.width) / 2;
} else if (detail.textAlign === 'right') {
_x = x + (w - line.width);
}
lines[i].x = _x;
lines[i].y = _y + fontHeight * i + eachLineStartY;
});
}
const virtualTextDetail: VirtualFlatTextDetail = {
textLines: lines
};
return virtualTextDetail;
}

View file

@ -1,11 +1,11 @@
{
"name": "@idraw/types",
"version": "0.4.0-beta.39",
"version": "0.4.0-beta.40",
"description": "",
"main": "src/index.ts",
"types": "src/index.ts",
"scripts": {},
"author": "chenshenhai",
"author": "idrawjs",
"license": "MIT",
"files": [
"src/**/*.ts",

View file

@ -1,5 +1,6 @@
export * from './lib/util';
export * from './lib/point';
export * from './lib/box';
export * from './lib/data';
export * from './lib/element';
export * from './lib/view';
@ -17,3 +18,4 @@ export * from './lib/html';
export * from './lib/svg-path';
export * from './lib/config';
export * from './lib/modify';
export * from './lib/virtual-flat';

View file

@ -88,7 +88,10 @@ export interface BoardMiddlewareObject<S extends Record<any | symbol, any> = any
clear?(e: BoardWatcherEventMap<S>['clear']): void | boolean;
}
export interface BoardMiddlewareOptions<S extends Record<any | symbol, any> = Record<any | symbol, any>, E extends BoardExtendEventMap = BoardExtendEventMap> {
export interface BoardMiddlewareOptions<
S extends Record<any | symbol, any> = Record<any | symbol, any>,
E extends BoardExtendEventMap = BoardExtendEventMap
> {
boardContent: BoardContent;
sharer: StoreSharer<S>;
viewer: BoardViewer;
@ -98,10 +101,11 @@ export interface BoardMiddlewareOptions<S extends Record<any | symbol, any> = Re
canvas?: HTMLCanvasElement;
}
export type BoardMiddleware<S extends Record<any | symbol, any> = any, E extends BoardExtendEventMap = BoardExtendEventMap, C extends any = undefined> = (
opts: BoardMiddlewareOptions<S, E>,
config?: C
) => BoardMiddlewareObject<S, C>;
export type BoardMiddleware<
S extends Record<any | symbol, any> = any,
E extends BoardExtendEventMap = BoardExtendEventMap,
C extends any = undefined
> = (opts: BoardMiddlewareOptions<S, E>, config?: C) => BoardMiddlewareObject<S, C>;
export interface BoardOptions {
boardContent: BoardContent;
@ -114,8 +118,7 @@ export interface BoardViewerFrameSnapshot<S extends Record<any | symbol, any> =
}
export interface BoardViewerEventMap {
// eslint-disable-next-line @typescript-eslint/ban-types
drawFrame: {};
drawFrame: object;
}
export interface BoardViewerOptions {
@ -128,24 +131,27 @@ export interface BoardViewerOptions {
}
// export interface BoardViewerStorage {
// viewVisibleInfoMap: ViewVisibleInfoMap;
// virtualFlatItemMap: VirtualFlatItemMap;
// }
export interface BoardViewer extends UtilEventEmitter<BoardViewerEventMap> {
drawFrame(): void;
scale(opts: { scale: number; point: PointSize; ignoreUpdateVisibleStatus?: boolean }): { moveX: number; moveY: number };
scale(opts: { scale: number; point: PointSize; ignoreUpdateVisibleStatus?: boolean }): {
moveX: number;
moveY: number;
};
scroll(opts: { moveX?: number; moveY?: number; ignoreUpdateVisibleStatus?: boolean }): ViewScaleInfo;
resize(viewSize: Partial<ViewSizeInfo>, opts?: { ignoreUpdateVisibleStatus?: boolean }): ViewSizeInfo;
updateViewScaleInfo(opts: { scale: number; offsetX: number; offsetY: number }): ViewScaleInfo;
// resetViewVisibleInfoMap(
// resetVirtualFlatItemMap(
// data: Data,
// opts: {
// viewScaleInfo: ViewScaleInfo;
// viewSizeInfo: ViewSizeInfo;
// }
// ): void;
// modifyViewVisibleInfoMap(
// modifyVirtualFlatItemMap(
// data: Data,
// opts: {
// modifyOptions: ModifyOptions;

View file

@ -0,0 +1,56 @@
import type { PointSize } from './point';
export type BoxInfo = {
// p0: PointSize; // top-left
// p1: PointSize; // top-right
// p2: PointSize; // bottom-right
// p3: PointSize; // bottom-left
btw: number; // border-top-width
brw: number; // border-right-width
bbw: number; // border-bottom-width
blw: number; // border-left-width
btlr: number; // border-top-left-radius
btrr: number; // border-top-right-radius
bblr: number; // border-bottom-left-radius
bbrr: number; // border-bottom-right-radius
p0: PointSize; // pointer border-top-left
p1: PointSize; // pointer border-top-right
p2: PointSize; // pointer border-bottom-right
p3: PointSize; // pointer border-bottom-left
p0s: PointSize; // pointer border-top-left start
p0e: PointSize; // pointer border-top-left end
p1s: PointSize; // pointer border-top-right start
p1e: PointSize; // pointer border-top-right start
p2s: PointSize; // pointer border-bottom-right start
p2e: PointSize; // pointer border-bottom-right end
p3s: PointSize; // pointer border-bottom-left start
p3e: PointSize; // pointer border-bottom-left end
op0: PointSize; // outer pointer border-top-left
op1: PointSize; // outer pointer border-top-right
op2: PointSize; // outer pointer border-bottom-right
op3: PointSize; // outer pointer border-bottom-left
op0s: PointSize; // outer pointer border-top-left start
op0e: PointSize; // outer pointer border-top-left end
op1s: PointSize; // outer pointer border-top-right start
op1e: PointSize; // outer pointer border-top-right start
op2s: PointSize; // outer pointer border-bottom-right start
op2e: PointSize; // outer pointer border-bottom-right end
op3s: PointSize; // outer pointer border-bottom-left start
op3e: PointSize; // outer pointer border-bottom-left end
ip0: PointSize; // inner pointer border-top-left
ip1: PointSize; // inner pointer border-top-right
ip2: PointSize; // inner pointer border-bottom-right
ip3: PointSize; // inner pointer border-bottom-left
ip0s: PointSize; // inner pointer border-top-left start
ip0e: PointSize; // inner pointer border-top-left end
ip1s: PointSize; // inner pointer border-top-right start
ip1e: PointSize; // inner pointer border-top-right start
ip2s: PointSize; // inner pointer border-bottom-right start
ip2e: PointSize; // inner pointer border-bottom-right end
ip3s: PointSize; // inner pointer border-bottom-left start
ip3e: PointSize; // inner pointer border-bottom-left end
};

View file

@ -31,6 +31,8 @@ export interface ViewContext2D {
moveTo(x: number, y: number): void;
lineTo(x: number, y: number): void;
arcTo(x1: number, y1: number, x2: number, y2: number, radius: number): void;
bezierCurveTo(cp1x: number, cp1y: number, cp2x: number, cp2y: number, x: number, y: number): void;
quadraticCurveTo(cpx: number, cpy: number, x: number, y: number): void;
lineWidth: number;
getLineDash(): number[];
setLineDash(segments: number[]): void;
@ -49,7 +51,17 @@ export interface ViewContext2D {
scale(x: number, y: number): void;
drawImage(image: CanvasImageSource, dx: number, dy: number): void;
drawImage(image: CanvasImageSource, dx: number, dy: number, dw: number, dh: number): void;
drawImage(image: CanvasImageSource, sx: number, sy: number, sw: number, sh: number, dx: number, dy: number, dw: number, dh: number): void;
drawImage(
image: CanvasImageSource,
sx: number,
sy: number,
sw: number,
sh: number,
dx: number,
dy: number,
dw: number,
dh: number
): void;
createPattern(image: CanvasImageSource, repetition: string | null): CanvasPattern | null;
globalAlpha: number;
globalCompositeOperation: GlobalCompositeOperation;
@ -57,7 +69,16 @@ export interface ViewContext2D {
shadowColor: string;
shadowOffsetX: number;
shadowOffsetY: number;
circle(x: number, y: number, radiusX: number, radiusY: number, rotation: number, startAngle: number, endAngle: number, counterclockwise?: boolean): void;
circle(
x: number,
y: number,
radiusX: number,
radiusY: number,
rotation: number,
startAngle: number,
endAngle: number,
counterclockwise?: boolean
): void;
isPointInPath(x: number, y: number, fillRule?: CanvasFillRule): boolean;
clip(fillRule?: CanvasFillRule): void;
clip(path: Path2D, fillRule?: CanvasFillRule): void;

View file

@ -1,14 +1,12 @@
import type { Element, ElementSize, ElementType, ElementPosition } from './element';
import type { ViewScaleInfo } from './view';
import type { Data } from './data';
import type { ViewContext2D } from './context2d';
import type { BoardBaseEventMap } from './board';
export interface CoreOptions {
width: number;
height: number;
devicePixelRatio?: number;
createCustomContext2D?: (opts: { width: number; height: number; devicePixelRatio: number }) => ViewContext2D;
}
export type CursorType =
@ -46,7 +44,9 @@ export interface CoreEventChange {
| 'setData'
| 'undo'
| 'redo'
| 'changeLayout' // TODO
| 'dragLayout'
| 'updateLayout'
| 'updateElementName'
| 'other';
selectedElements?: Element[] | null;
hoverElement?: Element | null;
@ -82,7 +82,19 @@ export type CoreEventMap = BoardBaseEventMap & {
change: CoreEventChange;
ruler: { show: boolean; showGrid: boolean };
scale: { scale: number };
select: { uuids?: string[]; positions?: ElementPosition[] };
select: {
uuids?: string[];
positions?: ElementPosition[];
type?:
| 'clickCanvas'
| 'selectElement'
| 'selectElements'
| 'selectElementByPosition'
| 'selectElementsByPositions'
| 'other'
| string;
};
selectLayout: void; // TODO
clearSelect: { uuids?: string[] } | void;
textEdit: CoreEventTextEdit;
textChange: CoreEventTextChange;

View file

@ -1,20 +1,34 @@
import type { Element, ElementType, ElementAssets, ElementSize, ElementGroupDetail, ElementGlobalDetail } from './element';
import type { Element, ElementType, ElementAssets, ElementSize, ElementGroupDetail } from './element';
export type DataLayout = Pick<ElementSize, 'x' | 'y' | 'w' | 'h'> & {
detail: Pick<
ElementGroupDetail,
'background' | 'borderWidth' | 'overflow' | 'borderColor' | 'borderDash' | 'borderRadius' | 'shadowBlur' | 'shadowColor' | 'shadowOffsetX' | 'shadowOffsetY'
| 'background'
| 'borderWidth'
| 'overflow'
| 'borderColor'
| 'borderDash'
| 'borderRadius'
| 'shadowBlur'
| 'shadowColor'
| 'shadowOffsetX'
| 'shadowOffsetY'
>;
operations?: {
position?: 'absolute' | 'relative';
};
};
export interface DataGlobalDetail {
background?: string;
}
export type Data<E extends Record<string, any> = Record<string, any>> = {
name?: string;
elements: Element<ElementType, E>[];
assets?: ElementAssets;
layout?: DataLayout;
global?: ElementGlobalDetail;
global?: DataGlobalDetail;
};
export type Matrix = [

View file

@ -44,7 +44,7 @@ export interface TransformScale {
export type TransformAction = TransformMatrix | TransformTranslate | TransformRotate | TransformScale;
export interface GradientStop {
offset: number;
offset: number; // [0, 1] eg. 0.5
color: string;
}
@ -92,7 +92,7 @@ export interface ElementBaseDetail {
// // background?: string;
// }
export interface ElementRectDetail extends ElementBaseDetail {}
export type ElementRectDetail = ElementBaseDetail;
export interface ElementTextDetail extends ElementBaseDetail {
text: string;
@ -182,14 +182,15 @@ export interface ElementGlobalDetail {
background?: string;
}
export interface Element<T extends ElementType = ElementType, E extends Record<string, any> = Record<string, any>> extends ElementSize {
export interface Element<T extends ElementType = ElementType, E extends Record<string, any> = Record<string, any>>
extends ElementSize {
uuid: string;
name?: string;
type: T;
detail: ElementDetailMap[T];
operations?: ElementOperations;
extends?: E;
global?: ElementGlobalDetail;
// global?: ElementGlobalDetail;
}
export type Elements = Element<ElementType>[];

View file

@ -7,8 +7,8 @@ import { ViewContext2D } from '@idraw/types';
export interface RendererOptions {
viewContext: ViewContext2D;
tempContext: ViewContext2D;
sharer?: StoreSharer;
calculator?: ViewCalculator;
}
export interface RendererEvent {
@ -37,7 +37,7 @@ export interface RendererDrawOptions {
export interface RendererDrawElementOptions extends RendererDrawOptions {
loader: RendererLoader;
calculator?: ViewCalculator;
calculator: ViewCalculator;
viewScaleInfo: ViewScaleInfo;
viewSizeInfo: ViewSizeInfo;
parentElementSize: ElementSize;

View file

@ -1,8 +1,10 @@
import type { Element, ElementType, ElementPosition } from './element';
import type { Element, ElementType } from './element';
import type { Point, PointSize } from './point';
import type { Data } from './data';
import type { ViewContext2D } from './context2d';
import type { ModifyOptions } from './modify';
import { VirtualFlatItem } from './virtual-flat';
// import type { BoxInfo } from './box';
export interface ViewScaleInfo {
scale: number;
@ -28,31 +30,22 @@ export interface BoardContent {
viewContext: ViewContext2D;
overlayContext: ViewContext2D;
underlayContext: ViewContext2D;
tempContext: ViewContext2D;
drawView: () => void;
}
export interface ViewCalculatorOptions {
// boardContent?: BoardContent;
viewContext: ViewContext2D;
}
export interface ViewCalculatorStorage {
viewVisibleInfoMap: ViewVisibleInfoMap;
visibleCount: number;
invisibleCount: number;
tempContext: ViewContext2D;
}
export interface ViewCalculator {
/**
* @deprecated
*/
isPointInElement(p: Point, elem: Element<ElementType>, viewScaleInfo: ViewScaleInfo, viewSize: ViewSizeInfo): boolean;
needRender(elem: Element<ElementType>): boolean;
getPointElement(
p: Point,
opts: { data: Data; viewScaleInfo: ViewScaleInfo; viewSizeInfo: ViewSizeInfo; groupQueue?: Element<'group'>[] }
): { index: number; element: null | Element<ElementType>; groupQueueIndex: number };
resetViewVisibleInfoMap(
resetVirtualFlatItemMap(
data: Data,
opts: {
viewScaleInfo: ViewScaleInfo;
@ -76,7 +69,7 @@ export interface ViewCalculator {
viewSizeInfo: ViewSizeInfo;
}
): ViewRectInfo | null;
modifyViewVisibleInfoMap(
modifyVirtualFlatItemMap(
data: Data,
opts: {
modifyOptions: ModifyOptions;
@ -86,6 +79,7 @@ export interface ViewCalculator {
): void;
toGridNum(num: number, opts?: { ignore?: boolean }): number;
getVirtualFlatItem: (uuid: string) => VirtualFlatItem | null;
}
export type ViewRectVertexes = [PointSize, PointSize, PointSize, PointSize];
@ -109,18 +103,3 @@ export type ViewRectInfo = {
left: PointSize;
center: PointSize;
};
export type ViewRectInfoMap = {
originRectInfo: ViewRectInfo;
rangeRectInfo: ViewRectInfo;
};
export type ViewVisibleInfo = ViewRectInfoMap & {
isVisibleInView: boolean;
isGroup: boolean;
position: ElementPosition;
};
export type ViewVisibleInfoMap = {
[uuid: string]: ViewVisibleInfo;
};

View file

@ -0,0 +1,39 @@
import type { ViewRectInfo } from './view';
import type { ElementPosition, ElementType } from './element';
import type { ViewContext2D } from './context2d';
export type CalcVirtualDetailOptions = {
tempContext: ViewContext2D;
};
export type VirtualFlatTextLine = {
x: number;
y: number;
width: number;
text: string;
};
export type VirtualFlatTextDetail = {
textLines?: Array<VirtualFlatTextLine>;
};
export type VirtualFlatDetail = VirtualFlatTextDetail & {
// TODO
};
export type VirtualFlatItem = {
type: ElementType;
position: ElementPosition;
originRectInfo: ViewRectInfo;
rangeRectInfo: ViewRectInfo;
isVisibleInView: boolean;
} & VirtualFlatDetail;
export type VirtualFlatItemMap = {
[uuid: string]: VirtualFlatItem;
};
export interface VirtualFlatStorage {
virtualFlatItemMap: VirtualFlatItemMap;
visibleCount: number;
invisibleCount: number;
}

View file

@ -1,6 +1,6 @@
{
"name": "@idraw/util",
"version": "0.4.0-beta.39",
"version": "0.4.0-beta.40",
"description": "",
"main": "dist/esm/index.js",
"module": "dist/esm/index.js",
@ -18,7 +18,7 @@
"url": "https://github.com/idrawjs/idraw/issues"
},
"homepage": "https://github.com/idrawjs/idraw#readme",
"author": "chenshenhai",
"author": "idrawjs",
"license": "MIT",
"devDependencies": {
"@idraw/types": "^0.4.0-alpha.0"

View file

@ -1,15 +1,37 @@
export { delay, compose, throttle, debounce } from './lib/time';
export { downloadImageFromCanvas, parseFileToBase64, pickFile, parseFileToText, downloadFileFromText } from './lib/file';
export { toColorHexStr, toColorHexNum, isColorStr, colorNameToHex, colorToCSS, colorToLinearGradientCSS, mergeHexColorAlpha } from './lib/color';
export {
downloadImageFromCanvas,
parseFileToBase64,
pickFile,
parseFileToText,
downloadFileFromText
} from './lib/file';
export {
toColorHexStr,
toColorHexNum,
isColorStr,
colorNameToHex,
colorToCSS,
colorToLinearGradientCSS,
mergeHexColorAlpha
} from './lib/color';
export { createUUID, isAssetId, createAssetId } from './lib/uuid';
export { deepClone, sortDataAsserts, deepCloneElement, filterCompactData } from './lib/data';
export { deepClone, sortDataAsserts, deepCloneElement, deepCloneData, filterCompactData } 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 { createBoardContent, createContext2D, createOffscreenContext2D } from './lib/canvas';
export { EventEmitter } from './lib/event';
export { calcDistance, calcSpeed, equalPoint, equalTouchPoint, vaildPoint, vaildTouchPoint, getCenterFromTwoPoints } from './lib/point';
export {
calcDistance,
calcSpeed,
equalPoint,
equalTouchPoint,
vaildPoint,
vaildTouchPoint,
getCenterFromTwoPoints
} from './lib/point';
export { Store } from './lib/store';
export { getViewScaleInfoFromSnapshot, getViewSizeInfoFromSnapshot } from './lib/middleware';
export { Context2D } from './lib/context2d';
@ -60,14 +82,17 @@ export {
calcViewScaleInfo,
calcElementViewRectInfo,
calcElementOriginRectInfo,
calcElementViewRectInfoMap,
originRectInfoToRangeRectInfo,
isViewPointInElementSize,
isViewPointInVertexes
} from './lib/view-calc';
export { sortElementsViewVisiableInfoMap, calcVisibleOriginCanvasRectInfo, updateViewVisibleInfoMapStatus } from './lib/view-visible';
export { rotatePoint, rotateVertexes, rotateByCenter } from './lib/rotate';
export { getElementVertexes, calcElementVertexesInGroup, calcElementVertexesQueueInGroup, calcElementQueueVertexesQueueInGroup } from './lib/vertex';
export {
getElementVertexes,
calcElementVertexesInGroup,
calcElementVertexesQueueInGroup,
calcElementQueueVertexesQueueInGroup
} from './lib/vertex';
export { calcElementSizeController, calcLayoutSizeController } from './lib/controller';
export { generateSVGPath, parseSVGPath } from './lib/svg-path';
export { generateHTML, parseHTML } from './lib/html';
@ -93,3 +118,6 @@ export { enhanceFontFamliy } from './lib/text';
export { flatElementList } from './lib/flat';
export { groupElementsByPosition, ungroupElementsByPosition } from './lib/group';
export { calcPointMoveElementInGroup } from './lib/point-move-element';
export { merge } from './lib/merge';
export { omit } from './lib/omit';
export { elementToBoxInfo } from './lib/box';

View file

@ -0,0 +1,186 @@
import type { BoxInfo, Element, PointSize } from '@idraw/types';
import { is } from './is';
export function elementToBoxInfo(elem: Element): BoxInfo {
const { x, y, w, h, detail } = elem;
const { borderWidth, borderRadius, boxSizing } = detail;
let btw: number = 0; // border-top-width
let brw: number = 0; // border-right-width
let bbw: number = 0; // border-bottom-width
let blw: number = 0; // border-left-width
let btlr: number = 0; // border-top-left-radius
let btrr: number = 0; // border-top-right-radius
let bblr: number = 0; // border-bottom-left-radius
let bbrr: number = 0; // border-bottom-right-radius
if (typeof borderWidth === 'number' && borderWidth > 0) {
btw = borderWidth;
brw = borderWidth;
bbw = borderWidth;
blw = borderWidth;
} else if (Array.isArray(borderWidth)) {
btw = is.positiveNum(borderWidth[0]) ? borderWidth[0] : 0;
brw = is.positiveNum(borderWidth[1]) ? borderWidth[0] : 0;
bbw = is.positiveNum(borderWidth[2]) ? borderWidth[0] : 0;
blw = is.positiveNum(borderWidth[3]) ? borderWidth[0] : 0;
}
if (typeof borderRadius === 'number' && borderRadius > 0) {
btlr = borderRadius;
btrr = borderRadius;
bblr = borderRadius;
bbrr = borderRadius;
} else if (Array.isArray(borderRadius)) {
btlr = is.positiveNum(borderRadius[0]) ? borderRadius[0] : 0;
btrr = is.positiveNum(borderRadius[0]) ? borderRadius[0] : 0;
bblr = is.positiveNum(borderRadius[0]) ? borderRadius[0] : 0;
bbrr = is.positiveNum(borderRadius[0]) ? borderRadius[0] : 0;
}
const p0: PointSize = { x: x, y: y }; // pointer border-top-left
const p1: PointSize = { x: x + w, y: y }; // pointer border-top-right
const p2: PointSize = { x: x + w, y: y + h }; // pointer border-bottom-right
const p3: PointSize = { x: x, y: y + h }; // pointer border-bottom-left
const p0s: PointSize = { x: x, y: y + btlr }; // pointer border-top-left start
const p0e: PointSize = { x: x + btlr, y: y }; // pointer border-top-left end
const p1s: PointSize = { x: x + w - btrr, y: y }; // pointer border-top-right start
const p1e: PointSize = { x: x + w, y: y + btrr }; // pointer border-top-right start
const p2s: PointSize = { x: x + w, y: y + h - bbrr }; // pointer border-bottom-right start
const p2e: PointSize = { x: x + w - bbrr, y: y + h }; // pointer border-bottom-right end
const p3s: PointSize = { x: x + bblr, y: y + h }; // pointer border-bottom-left start
const p3e: PointSize = { x: x, y: y + h - bblr }; // pointer border-bottom-left end
let op0: PointSize = { ...p0 }; // outer pointer border-top-left
let op1: PointSize = { ...p1 }; // outer pointer border-top-right
let op2: PointSize = { ...p2 }; // outer pointer border-bottom-right
let op3: PointSize = { ...p3 }; // outer pointer border-bottom-left
let op0s: PointSize = { ...p0s }; // outer pointer border-top-left start
let op0e: PointSize = { ...p0e }; // outer pointer border-top-left end
let op1s: PointSize = { ...p1s }; // outer pointer border-top-right start
let op1e: PointSize = { ...p1e }; // outer pointer border-top-right start
let op2s: PointSize = { ...p2s }; // outer pointer border-bottom-right start
let op2e: PointSize = { ...p2e }; // outer pointer border-bottom-right end
let op3s: PointSize = { ...p3s }; // outer pointer border-bottom-left start
let op3e: PointSize = { ...p3e }; // outer pointer border-bottom-left end
let ip0: PointSize = { ...p0 }; // inner pointer border-top-left
let ip1: PointSize = { ...p1 }; // inner pointer border-top-right
let ip2: PointSize = { ...p2 }; // inner pointer border-bottom-right
let ip3: PointSize = { ...p3 }; // inner pointer border-bottom-left
let ip0s: PointSize = { ...p0s }; // inner pointer border-top-left start
let ip0e: PointSize = { ...p0e }; // inner pointer border-top-left end
let ip1s: PointSize = { ...p1s }; // inner pointer border-top-right start
let ip1e: PointSize = { ...p1e }; // inner pointer border-top-right start
let ip2s: PointSize = { ...p2s }; // inner pointer border-bottom-right start
let ip2e: PointSize = { ...p2e }; // inner pointer border-bottom-right end
let ip3s: PointSize = { ...p3s }; // inner pointer border-bottom-left start
let ip3e: PointSize = { ...p3e }; // inner pointer border-bottom-left end
if (boxSizing === 'border-box') {
ip0 = { x: ip0.x + blw, y: ip0.y + btw };
ip1 = { x: ip1.x - brw, y: ip1.y + btw };
ip2 = { x: ip2.x - brw, y: ip2.y - bbw };
ip3 = { x: ip3.x + blw, y: ip3.y - bbw };
ip0s = { x: ip0s.x + blw, y: ip0s.y + btw };
ip0e = { x: ip0e.x + blw, y: ip0e.y + btw };
ip1s = { x: ip1s.x - brw, y: ip1s.y + btw };
ip1e = { x: ip1e.x - brw, y: ip1e.y + btw };
ip2s = { x: ip2s.x - brw, y: ip2s.y - bbw };
ip2e = { x: ip2e.x - brw, y: ip2e.y - bbw };
ip3s = { x: ip3s.x + blw, y: ip3s.y - bbw };
ip3e = { x: ip3e.x + blw, y: ip3e.y - bbw };
} else if (boxSizing === 'content-box') {
op0 = { x: op0.x - blw, y: op0.y - btw };
op1 = { x: op1.x + brw, y: op1.y - btw };
op2 = { x: op2.x + brw, y: op2.y + bbw };
op3 = { x: op3.x - blw, y: op3.y + bbw };
op0s = { x: op0s.x - blw, y: op0s.y - btw };
op0e = { x: op0e.x - blw, y: op0e.y - btw };
op1s = { x: op1s.x + brw, y: op1s.y - btw };
op1e = { x: op1e.x + brw, y: op1e.y - btw };
op2s = { x: op2s.x + brw, y: op2s.y + bbw };
op2e = { x: op2e.x + brw, y: op2e.y + bbw };
op3s = { x: op3s.x - blw, y: op3s.y + bbw };
op3e = { x: op3e.x - blw, y: op3e.y + bbw };
} else {
ip0 = { x: ip0.x + blw / 2, y: ip0.y + btw / 2 };
ip1 = { x: ip1.x - brw / 2, y: ip1.y + btw / 2 };
ip2 = { x: ip2.x - brw / 2, y: ip2.y - bbw / 2 };
ip3 = { x: ip3.x + blw / 2, y: ip3.y - bbw / 2 };
ip0s = { x: ip0s.x + blw / 2, y: ip0s.y + btw / 2 };
ip0e = { x: ip0e.x + blw / 2, y: ip0e.y + btw / 2 };
ip1s = { x: ip1s.x - brw / 2, y: ip1s.y + btw / 2 };
ip1e = { x: ip1e.x - brw / 2, y: ip1e.y + btw / 2 };
ip2s = { x: ip2s.x - brw / 2, y: ip2s.y - bbw / 2 };
ip2e = { x: ip2e.x - brw / 2, y: ip2e.y - bbw / 2 };
ip3s = { x: ip3s.x + blw / 2, y: ip3s.y - bbw / 2 };
ip3e = { x: ip3e.x + blw / 2, y: ip3e.y - bbw / 2 };
op0 = { x: op0.x - blw / 2, y: op0.y - btw / 2 };
op1 = { x: op1.x + brw / 2, y: op1.y - btw / 2 };
op2 = { x: op2.x + brw / 2, y: op2.y + bbw / 2 };
op3 = { x: op3.x - blw / 2, y: op3.y + bbw / 2 };
op0s = { x: op0s.x - blw / 2, y: op0s.y - btw / 2 };
op0e = { x: op0e.x - blw / 2, y: op0e.y - btw / 2 };
op1s = { x: op1s.x + brw / 2, y: op1s.y - btw / 2 };
op1e = { x: op1e.x + brw / 2, y: op1e.y - btw / 2 };
op2s = { x: op2s.x + brw / 2, y: op2s.y + bbw / 2 };
op2e = { x: op2e.x + brw / 2, y: op2e.y + bbw / 2 };
op3s = { x: op3s.x - blw / 2, y: op3s.y + bbw / 2 };
op3e = { x: op3e.x - blw / 2, y: op3e.y + bbw / 2 };
}
return {
btw,
brw,
bbw,
blw,
btlr,
btrr,
bblr,
bbrr,
p0,
p1,
p2,
p3,
p0s,
p0e,
p1s,
p1e,
p2s,
p2e,
p3s,
p3e,
op0,
op1,
op2,
op3,
op0s,
op0e,
op1s,
op1e,
op2s,
op2e,
op3s,
op3e,
ip0,
ip1,
ip2,
ip3,
ip0s,
ip0e,
ip1s,
ip1e,
ip2s,
ip2e,
ip3s,
ip3e
};
}

View file

@ -1,7 +1,12 @@
import type { BoardContent, ViewContext2D } from '@idraw/types';
import type { BoardContent } from '@idraw/types';
import { Context2D } from './context2d';
export function createContext2D(opts: { ctx?: CanvasRenderingContext2D; width: number; height: number; devicePixelRatio: number }): Context2D {
export function createContext2D(opts: {
ctx?: CanvasRenderingContext2D;
width: number;
height: number;
devicePixelRatio: number;
}): Context2D {
const { width, height, ctx, devicePixelRatio } = opts;
let context: CanvasRenderingContext2D | undefined = ctx;
if (!context) {
@ -34,11 +39,9 @@ export function createBoardContent(
width: number;
height: number;
devicePixelRatio: number;
offscreen?: boolean;
createCustomContext2D?: (opts: { width: number; height: number; devicePixelRatio: number }) => ViewContext2D;
}
): BoardContent {
const { width, height, devicePixelRatio, offscreen, createCustomContext2D } = opts;
const { width, height, devicePixelRatio } = opts;
const ctxOpts = {
width,
height,
@ -47,86 +50,32 @@ export function createBoardContent(
const ctx = canvas.getContext('2d') as CanvasRenderingContext2D;
if (createCustomContext2D) {
// TODO
const viewContext = createCustomContext2D(ctxOpts);
const overlayContext = createCustomContext2D(ctxOpts);
const underlayContext = createCustomContext2D(ctxOpts);
const boardContext = createContext2D({ ctx, ...ctxOpts });
// const ctx = canvas.getContext('2d') as CanvasRenderingContext2D;
const viewContext = createOffscreenContext2D(ctxOpts);
const overlayContext = createOffscreenContext2D(ctxOpts);
const underlayContext = createOffscreenContext2D(ctxOpts);
const boardContext = createContext2D({ ctx, ...ctxOpts });
const tempContext = createOffscreenContext2D(ctxOpts);
const drawView = () => {
const { width: w, height: h } = viewContext.$getSize();
const drawView = () => {
const { width: w, height: h } = viewContext.$getSize();
boardContext.clearRect(0, 0, w, h);
boardContext.drawImage(underlayContext.canvas, 0, 0, w, h);
boardContext.drawImage(viewContext.canvas, 0, 0, w, h);
boardContext.drawImage(overlayContext.canvas, 0, 0, w, h);
underlayContext.clearRect(0, 0, w, h);
viewContext.clearRect(0, 0, w, h);
overlayContext.clearRect(0, 0, w, h);
};
boardContext.clearRect(0, 0, w, h);
boardContext.drawImage(underlayContext.canvas, 0, 0, w, h);
boardContext.drawImage(viewContext.canvas, 0, 0, w, h);
boardContext.drawImage(overlayContext.canvas, 0, 0, w, h);
underlayContext.clearRect(0, 0, w, h);
viewContext.clearRect(0, 0, w, h);
overlayContext.clearRect(0, 0, w, h);
};
const content: BoardContent = {
underlayContext,
viewContext,
overlayContext,
boardContext,
drawView
};
return content;
}
if (offscreen === true) {
// const ctx = canvas.getContext('2d') as CanvasRenderingContext2D;
const viewContext = createOffscreenContext2D(ctxOpts);
const overlayContext = createOffscreenContext2D(ctxOpts);
const underlayContext = createOffscreenContext2D(ctxOpts);
const boardContext = createContext2D({ ctx, ...ctxOpts });
const drawView = () => {
const { width: w, height: h } = viewContext.$getSize();
boardContext.clearRect(0, 0, w, h);
boardContext.drawImage(underlayContext.canvas, 0, 0, w, h);
boardContext.drawImage(viewContext.canvas, 0, 0, w, h);
boardContext.drawImage(overlayContext.canvas, 0, 0, w, h);
underlayContext.clearRect(0, 0, w, h);
viewContext.clearRect(0, 0, w, h);
overlayContext.clearRect(0, 0, w, h);
};
const content: BoardContent = {
underlayContext,
viewContext,
overlayContext,
boardContext,
drawView
};
return content;
} else {
// const ctx = canvas.getContext('2d') as CanvasRenderingContext2D;
const viewContext = createContext2D(ctxOpts);
const overlayContext = createContext2D(ctxOpts);
const underlayContext = createContext2D(ctxOpts);
const boardContext = createContext2D({ ctx, ...ctxOpts });
const drawView = () => {
boardContext.clearRect(0, 0, width, height);
boardContext.drawImage(underlayContext.canvas, 0, 0, width, height);
boardContext.drawImage(viewContext.canvas, 0, 0, width, height);
boardContext.drawImage(overlayContext.canvas, 0, 0, width, height);
underlayContext.clearRect(0, 0, width, height);
viewContext.clearRect(0, 0, width, height);
overlayContext.clearRect(0, 0, width, height);
};
const content: BoardContent = {
underlayContext,
viewContext,
overlayContext,
boardContext,
drawView
};
return content;
}
const content: BoardContent = {
underlayContext,
viewContext,
overlayContext,
boardContext,
tempContext,
drawView
};
return content;
}

View file

@ -1,7 +1,7 @@
import type { LinearGradientColor, RadialGradientColor } from '@idraw/types';
export function toColorHexNum(color: string): number {
return parseInt(color.replace(/^\#/, '0x'));
return parseInt(color.replace(/^#/, '0x'));
}
export function toColorHexStr(color: number): string {
@ -9,7 +9,9 @@ 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) || /^[a-z]{1,}$/i.test(color));
return (
typeof color === 'string' && (/^#([0-9a-f]{3}|[0-9a-f]{6}|[0-9a-f]{8})$/i.test(color) || /^[a-z]{1,}$/i.test(color))
);
}
// https://stackoverflow.com/questions/1573053/javascript-function-to-convert-color-names-to-hex-codes
@ -170,6 +172,8 @@ export function colorToCSS(color?: string | LinearGradientColor | RadialGradient
let css = 'transparent';
if (typeof color === 'string') {
css = color;
} else if (color?.stops.length === 1) {
css = color.stops[0].color;
} else if (color?.type === 'linear-gradient') {
const items: string[] = [];
if (typeof color.angle === 'number') {
@ -220,13 +224,13 @@ export function mergeHexColorAlpha(hex: string, alpha: number): string {
return hex;
}
let hexAlpha = 1;
const regHex1 = /^\#[0-9a-f]{6,6}$/i;
const regHex2 = /^\#[0-9a-f]{8,8}$/i;
const regHex1 = /^#[0-9a-f]{6,6}$/i;
const regHex2 = /^#[0-9a-f]{8,8}$/i;
let result = hex;
if (regHex1.test(hex)) {
hexAlpha = parseInt(hex.substring(5, 7).replace(/^\#/, '0x'));
hexAlpha = parseInt(hex.substring(5, 7).replace(/^#/, '0x'));
} else if (regHex2.test(hex)) {
hexAlpha = parseInt(hex.substring(7, 9).replace(/^\#/, '0x'));
hexAlpha = parseInt(hex.substring(7, 9).replace(/^#/, '0x'));
result = hex.substring(0, 7);
}
hexAlpha = hexAlpha * alpha;

View file

@ -175,8 +175,22 @@ export class Context2D implements ViewContext2D {
return this.#ctx.fill(...(args as [path: Path2D, fillRule?: CanvasFillRule | undefined]));
}
arc(x: number, y: number, radius: number, startAngle: number, endAngle: number, anticlockwise?: boolean | undefined): void {
return this.#ctx.arc(this.$doPixelRatio(x), this.$doPixelRatio(y), this.$doPixelRatio(radius), startAngle, endAngle, anticlockwise);
arc(
x: number,
y: number,
radius: number,
startAngle: number,
endAngle: number,
anticlockwise?: boolean | undefined
): void {
return this.#ctx.arc(
this.$doPixelRatio(x),
this.$doPixelRatio(y),
this.$doPixelRatio(radius),
startAngle,
endAngle,
anticlockwise
);
}
rect(x: number, y: number, w: number, h: number) {
@ -184,11 +198,21 @@ export class Context2D implements ViewContext2D {
}
fillRect(x: number, y: number, w: number, h: number) {
return this.#ctx.fillRect(this.$doPixelRatio(x), this.$doPixelRatio(y), this.$doPixelRatio(w), this.$doPixelRatio(h));
return this.#ctx.fillRect(
this.$doPixelRatio(x),
this.$doPixelRatio(y),
this.$doPixelRatio(w),
this.$doPixelRatio(h)
);
}
clearRect(x: number, y: number, w: number, h: number) {
return this.#ctx.clearRect(this.$doPixelRatio(x), this.$doPixelRatio(y), this.$doPixelRatio(w), this.$doPixelRatio(h));
return this.#ctx.clearRect(
this.$doPixelRatio(x),
this.$doPixelRatio(y),
this.$doPixelRatio(w),
this.$doPixelRatio(h)
);
}
beginPath() {
@ -208,7 +232,32 @@ export class Context2D implements ViewContext2D {
}
arcTo(x1: number, y1: number, x2: number, y2: number, radius: number): void {
return this.#ctx.arcTo(this.$doPixelRatio(x1), this.$doPixelRatio(y1), this.$doPixelRatio(x2), this.$doPixelRatio(y2), this.$doPixelRatio(radius));
return this.#ctx.arcTo(
this.$doPixelRatio(x1),
this.$doPixelRatio(y1),
this.$doPixelRatio(x2),
this.$doPixelRatio(y2),
this.$doPixelRatio(radius)
);
}
bezierCurveTo(cp1x: number, cp1y: number, cp2x: number, cp2y: number, x: number, y: number): void {
return this.#ctx.bezierCurveTo(
this.$doPixelRatio(cp1x),
this.$doPixelRatio(cp1y),
this.$doPixelRatio(cp2x),
this.$doPixelRatio(cp2y),
this.$doPixelRatio(x),
this.$doPixelRatio(y)
);
}
quadraticCurveTo(cpx: number, cpy: number, x: number, y: number): void {
return this.#ctx.quadraticCurveTo(
this.$doPixelRatio(cpx),
this.$doPixelRatio(cpy),
this.$doPixelRatio(x),
this.$doPixelRatio(y)
);
}
getLineDash() {
@ -257,7 +306,13 @@ export class Context2D implements ViewContext2D {
this.$doPixelRatio(dh)
);
} else {
return this.#ctx.drawImage(image, this.$doPixelRatio(dx), this.$doPixelRatio(dy), this.$doPixelRatio(dw), this.$doPixelRatio(dh));
return this.#ctx.drawImage(
image,
this.$doPixelRatio(dx),
this.$doPixelRatio(dy),
this.$doPixelRatio(dw),
this.$doPixelRatio(dh)
);
}
}
@ -338,7 +393,12 @@ export class Context2D implements ViewContext2D {
}
createLinearGradient(x0: number, y0: number, x1: number, y1: number): CanvasGradient {
return this.#ctx.createLinearGradient(this.$doPixelRatio(x0), this.$doPixelRatio(y0), this.$doPixelRatio(x1), this.$doPixelRatio(y1));
return this.#ctx.createLinearGradient(
this.$doPixelRatio(x0),
this.$doPixelRatio(y0),
this.$doPixelRatio(x1),
this.$doPixelRatio(y1)
);
}
createRadialGradient(x0: number, y0: number, r0: number, x1: number, y1: number, r1: number): CanvasGradient {
return this.#ctx.createRadialGradient(

View file

@ -42,11 +42,24 @@ export function deepCloneElement<T extends Element = Element>(element: T): T {
return elem;
}
export function deepCloneData(data: Data): Data {
const { elements, ...restData } = data;
return {
...deepClone(restData),
...{
elements: elements.map((elem) => deepCloneElement(elem))
}
};
}
function is(target: any): string {
return Object.prototype.toString
.call(target)
.replace(/[\]|\[]{1,1}/gi, '')
.split(' ')[1];
return (
Object.prototype.toString
.call(target)
// eslint-disable-next-line no-useless-escape
.replace(/[\]|\[]{1,1}/gi, '')
.split(' ')[1]
);
}
export function sortDataAsserts(data: Data, opts?: { clone?: boolean }): Data {

View file

@ -1,5 +1,9 @@
import { isColorStr } from './color';
function positiveNum(value: any) {
return typeof value === 'number' && value >= 0;
}
function number(value: any) {
return typeof value === 'number' && (value > 0 || value <= 0);
}
@ -13,11 +17,11 @@ function y(value: any) {
}
function w(value: any) {
return typeof value === 'number' && value >= 0;
return positiveNum(value);
}
function h(value: any) {
return typeof value === 'number' && value >= 0;
return positiveNum(value);
}
function angle(value: any) {
@ -25,11 +29,25 @@ function angle(value: any) {
}
function borderWidth(value: any) {
return w(value);
return (
positiveNum(value) ||
(Array.isArray(value) &&
positiveNum(value[0]) &&
positiveNum(value[1]) &&
positiveNum(value[2]) &&
positiveNum(value[3]))
);
}
function borderRadius(value: any) {
return number(value) && value >= 0;
return (
positiveNum(value) ||
(Array.isArray(value) &&
positiveNum(value[0]) &&
positiveNum(value[1]) &&
positiveNum(value[2]) &&
positiveNum(value[3]))
);
}
function color(value: any) {
@ -49,7 +67,11 @@ function imageSrc(value: any) {
}
function svg(value: any) {
return typeof value === 'string' && /^(<svg[\s]{1,}|<svg>)/i.test(`${value}`.trim()) && /<\/[\s]{0,}svg>$/i.test(`${value}`.trim());
return (
typeof value === 'string' &&
/^(<svg[\s]{1,}|<svg>)/i.test(`${value}`.trim()) &&
/<\/[\s]{0,}svg>$/i.test(`${value}`.trim())
);
}
function html(value: any) {
@ -98,6 +120,7 @@ function numberStr(value: any): boolean {
}
export const is = {
positiveNum,
x,
y,
w,

View file

@ -0,0 +1,22 @@
export function merge<T extends Record<string, any> = any, U extends Record<string, any> = any>(
target: T,
source: U
): T & U {
type Result = T & U;
const result: Result = target as Result;
for (const key in source) {
if (Object.prototype.hasOwnProperty.call(source, key)) {
if (
typeof source[key] === 'object' &&
source[key] !== null &&
typeof result[key] === 'object' &&
result[key] !== null
) {
result[key] = merge(result[key] as object, source[key] as object) as any;
} else {
result[key] = source[key] as any;
}
}
}
return target as T & U;
}

View file

@ -0,0 +1,11 @@
export function omit<T extends Record<string, any>, K extends keyof T>(obj: T, keys: K[]): Omit<T, K> {
// Create a shallow copy of the object
const result = { ...obj };
// Remove the specified keys
for (const key of keys) {
delete result[key];
}
return result;
}

View file

@ -2,10 +2,14 @@ import type { Element, ViewScaleInfo, ViewSizeInfo, ViewBoxSize } from '@idraw/t
import { getDefaultElementDetailConfig } from './config';
const defaultElemConfig = getDefaultElementDetailConfig();
export function calcViewBoxSize(viewElem: Element, opts: { viewScaleInfo: ViewScaleInfo; viewSizeInfo: ViewSizeInfo }): ViewBoxSize {
export function calcViewBoxSize(
viewElem: Element,
opts: { viewScaleInfo: ViewScaleInfo; viewSizeInfo: ViewSizeInfo }
): ViewBoxSize {
const { viewScaleInfo } = opts;
const { scale } = viewScaleInfo;
let { borderRadius, borderDash } = viewElem.detail;
let { borderRadius } = viewElem.detail;
const { borderDash } = viewElem.detail;
const hasBorderDash = Array.isArray(borderDash) && borderDash.length > 0;
const { boxSizing = defaultElemConfig.boxSizing, borderWidth } = viewElem.detail;

View file

@ -9,15 +9,17 @@ import {
ElementSize,
ViewContext2D,
ViewRectVertexes,
ViewRectInfo,
ViewRectInfoMap
ViewRectInfo
} from '@idraw/types';
import { rotateElementVertexes } from './rotate';
import { checkRectIntersect } from './rect';
import { calcElementVertexesInGroup, calcElementVertexes } from './vertex';
import { getCenterFromTwoPoints } from './point';
export function calcViewScaleInfo(info: { scale: number; offsetX: number; offsetY: number }, opts: { viewSizeInfo: ViewSizeInfo }): ViewScaleInfo {
export function calcViewScaleInfo(
info: { scale: number; offsetX: number; offsetY: number },
opts: { viewSizeInfo: ViewSizeInfo }
): ViewScaleInfo {
const { scale, offsetX, offsetY } = info;
const { viewSizeInfo } = opts;
const { width, height, contextWidth, contextHeight } = viewSizeInfo;
@ -38,7 +40,12 @@ export function calcViewScaleInfo(info: { scale: number; offsetX: number; offset
return newScaleInfo;
}
export function viewScale(opts: { scale: number; point: PointSize; viewScaleInfo: ViewScaleInfo; viewSizeInfo: ViewSizeInfo }): {
export function viewScale(opts: {
scale: number;
point: PointSize;
viewScaleInfo: ViewScaleInfo;
viewSizeInfo: ViewSizeInfo;
}): {
moveX: number;
moveY: number;
} {
@ -55,7 +62,12 @@ export function viewScale(opts: { scale: number; point: PointSize; viewScaleInfo
};
}
export function viewScroll(opts: { moveX?: number; moveY?: number; viewScaleInfo: ViewScaleInfo; viewSizeInfo: ViewSizeInfo }): ViewScaleInfo {
export function viewScroll(opts: {
moveX?: number;
moveY?: number;
viewScaleInfo: ViewScaleInfo;
viewSizeInfo: ViewSizeInfo;
}): ViewScaleInfo {
const { moveX = 0, moveY = 0, viewScaleInfo, viewSizeInfo } = opts;
const { scale } = viewScaleInfo;
@ -110,7 +122,10 @@ export function calcViewPointSize(size: PointSize, opts: { viewScaleInfo: ViewSc
return newSize;
}
export function calcViewVertexes(vertexes: ViewRectVertexes, opts: { viewScaleInfo: ViewScaleInfo; viewSizeInfo: ViewSizeInfo }): ViewRectVertexes {
export function calcViewVertexes(
vertexes: ViewRectVertexes,
opts: { viewScaleInfo: ViewScaleInfo; viewSizeInfo: ViewSizeInfo }
): ViewRectVertexes {
return [
calcViewPointSize(vertexes[0], opts),
calcViewPointSize(vertexes[1], opts),
@ -264,7 +279,10 @@ export function getViewPointAtElement(
/**
* @deprecated
*/
export function isElementInView(elem: ElementSize, opts: { viewScaleInfo: ViewScaleInfo; viewSizeInfo: ViewSizeInfo }): boolean {
export function isElementInView(
elem: ElementSize,
opts: { viewScaleInfo: ViewScaleInfo; viewSizeInfo: ViewSizeInfo }
): boolean {
const { viewSizeInfo, viewScaleInfo } = opts;
const { width, height } = viewSizeInfo;
const { angle } = elem;
@ -325,10 +343,30 @@ export function calcElementOriginRectInfo(
}
export function originRectInfoToRangeRectInfo(originRectInfo: ViewRectInfo): ViewRectInfo {
const rangeMaxX = Math.max(originRectInfo.topLeft.x, originRectInfo.topRight.x, originRectInfo.bottomRight.x, originRectInfo.bottomLeft.x);
const rangeMaxY = Math.max(originRectInfo.topLeft.y, originRectInfo.topRight.y, originRectInfo.bottomRight.y, originRectInfo.bottomLeft.y);
const rangeMinX = Math.min(originRectInfo.topLeft.x, originRectInfo.topRight.x, originRectInfo.bottomRight.x, originRectInfo.bottomLeft.x);
const rangeMinY = Math.min(originRectInfo.topLeft.y, originRectInfo.topRight.y, originRectInfo.bottomRight.y, originRectInfo.bottomLeft.y);
const rangeMaxX = Math.max(
originRectInfo.topLeft.x,
originRectInfo.topRight.x,
originRectInfo.bottomRight.x,
originRectInfo.bottomLeft.x
);
const rangeMaxY = Math.max(
originRectInfo.topLeft.y,
originRectInfo.topRight.y,
originRectInfo.bottomRight.y,
originRectInfo.bottomLeft.y
);
const rangeMinX = Math.min(
originRectInfo.topLeft.x,
originRectInfo.topRight.x,
originRectInfo.bottomRight.x,
originRectInfo.bottomLeft.x
);
const rangeMinY = Math.min(
originRectInfo.topLeft.y,
originRectInfo.topRight.y,
originRectInfo.bottomRight.y,
originRectInfo.bottomLeft.y
);
const rangeCenter = { x: originRectInfo.center.x, y: originRectInfo.center.y };
const rangeTopLeft = { x: rangeMinX, y: rangeMinY };
@ -384,10 +422,30 @@ export function calcElementViewRectInfo(
if (range === true) {
// Range RectInfo
const viewMaxX = Math.max(viewRectInfo.topLeft.x, viewRectInfo.topRight.x, viewRectInfo.bottomRight.x, viewRectInfo.bottomLeft.x);
const viewMaxY = Math.max(viewRectInfo.topLeft.y, viewRectInfo.topRight.y, viewRectInfo.bottomRight.y, viewRectInfo.bottomLeft.y);
const viewMinX = Math.min(viewRectInfo.topLeft.x, viewRectInfo.topRight.x, viewRectInfo.bottomRight.x, viewRectInfo.bottomLeft.x);
const viewMinY = Math.min(viewRectInfo.topLeft.y, viewRectInfo.topRight.y, viewRectInfo.bottomRight.y, viewRectInfo.bottomLeft.y);
const viewMaxX = Math.max(
viewRectInfo.topLeft.x,
viewRectInfo.topRight.x,
viewRectInfo.bottomRight.x,
viewRectInfo.bottomLeft.x
);
const viewMaxY = Math.max(
viewRectInfo.topLeft.y,
viewRectInfo.topRight.y,
viewRectInfo.bottomRight.y,
viewRectInfo.bottomLeft.y
);
const viewMinX = Math.min(
viewRectInfo.topLeft.x,
viewRectInfo.topRight.x,
viewRectInfo.bottomRight.x,
viewRectInfo.bottomLeft.x
);
const viewMinY = Math.min(
viewRectInfo.topLeft.y,
viewRectInfo.topRight.y,
viewRectInfo.bottomRight.y,
viewRectInfo.bottomLeft.y
);
const rangeCenter = { x: viewRectInfo.center.x, y: viewRectInfo.center.y };
const rangeTopLeft = { x: viewMinX, y: viewMinY };
@ -416,65 +474,3 @@ export function calcElementViewRectInfo(
return viewRectInfo;
}
export function calcElementViewRectInfoMap(
elemSize: ElementSize,
opts: {
groupQueue: Element<'group'>[];
viewScaleInfo: ViewScaleInfo;
}
): ViewRectInfoMap {
const { groupQueue, viewScaleInfo } = opts;
// Original RectInfo
const originRectInfo = calcElementOriginRectInfo(elemSize, { groupQueue });
const { center, top, bottom, left, right, topLeft, topRight, bottomLeft, bottomRight } = originRectInfo;
// View RectInfo
const viewRectInfo: ViewRectInfo = {
center: calcViewPointSize(center, { viewScaleInfo }),
topLeft: calcViewPointSize(topLeft, { viewScaleInfo }),
topRight: calcViewPointSize(topRight, { viewScaleInfo }),
bottomLeft: calcViewPointSize(bottomLeft, { viewScaleInfo }),
bottomRight: calcViewPointSize(bottomRight, { viewScaleInfo }),
top: calcViewPointSize(top, { viewScaleInfo }),
right: calcViewPointSize(right, { viewScaleInfo }),
left: calcViewPointSize(left, { viewScaleInfo }),
bottom: calcViewPointSize(bottom, { viewScaleInfo })
};
// Range RectInfo
const viewMaxX = Math.max(viewRectInfo.topLeft.x, viewRectInfo.topRight.x, viewRectInfo.bottomRight.x, viewRectInfo.bottomLeft.x);
const viewMaxY = Math.max(viewRectInfo.topLeft.y, viewRectInfo.topRight.y, viewRectInfo.bottomRight.y, viewRectInfo.bottomLeft.y);
const viewMinX = Math.min(viewRectInfo.topLeft.x, viewRectInfo.topRight.x, viewRectInfo.bottomRight.x, viewRectInfo.bottomLeft.x);
const viewMinY = Math.min(viewRectInfo.topLeft.y, viewRectInfo.topRight.y, viewRectInfo.bottomRight.y, viewRectInfo.bottomLeft.y);
const rangeCenter = { x: viewRectInfo.center.x, y: viewRectInfo.center.y };
const rangeTopLeft = { x: viewMinX, y: viewMinY };
const rangeTopRight = { x: viewMaxX, y: viewMinY };
const rangeBottomRight = { x: viewMaxX, y: viewMaxY };
const rangeBottomLeft = { x: viewMinX, y: viewMaxY };
const rangeTop = getCenterFromTwoPoints(rangeTopLeft, rangeTopRight);
const rangeBottom = getCenterFromTwoPoints(rangeBottomLeft, rangeBottomRight);
const rangeLeft = getCenterFromTwoPoints(rangeTopLeft, rangeBottomLeft);
const rangeRight = getCenterFromTwoPoints(rangeTopRight, rangeBottomRight);
const rangeRectInfo: ViewRectInfo = {
center: rangeCenter,
topLeft: rangeTopLeft,
topRight: rangeTopRight,
bottomLeft: rangeBottomLeft,
bottomRight: rangeBottomRight,
top: rangeTop,
right: rangeRight,
left: rangeLeft,
bottom: rangeBottom
};
return {
originRectInfo,
// viewRectInfo,
rangeRectInfo
};
}

File diff suppressed because it is too large Load diff

View file

@ -5,10 +5,6 @@ const packages = [
dirName: 'util',
globalName: 'iDrawUtil'
},
{
dirName: 'board',
globalName: 'iDrawBoard'
},
{
dirName: 'renderer',
globalName: 'iDrawRenderer'