cbvirtua 1.0.48 → 1.0.49
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/canvas-example-main/canvas-example-main/.github/workflows/main.yml +62 -0
- package/canvas-example-main/canvas-example-main/README.md +13 -0
- package/canvas-example-main/canvas-example-main/curved.html +52 -0
- package/canvas-example-main/canvas-example-main/eslint.config.js +30 -0
- package/canvas-example-main/canvas-example-main/index.html +13 -0
- package/canvas-example-main/canvas-example-main/package.json +51 -0
- package/canvas-example-main/canvas-example-main/pnpm-lock.yaml +4760 -0
- package/canvas-example-main/canvas-example-main/postcss.config.js +6 -0
- package/canvas-example-main/canvas-example-main/public/vite.svg +1 -0
- package/canvas-example-main/canvas-example-main/src/App.tsx +17 -0
- package/canvas-example-main/canvas-example-main/src/assets/github.svg +1 -0
- package/canvas-example-main/canvas-example-main/src/assets/react.svg +1 -0
- package/canvas-example-main/canvas-example-main/src/components/Iconfont/demo.css +539 -0
- package/canvas-example-main/canvas-example-main/src/components/Iconfont/demo_index.html +418 -0
- package/canvas-example-main/canvas-example-main/src/components/Iconfont/iconfont.css +55 -0
- package/canvas-example-main/canvas-example-main/src/components/Iconfont/iconfont.js +1 -0
- package/canvas-example-main/canvas-example-main/src/components/Iconfont/iconfont.json +79 -0
- package/canvas-example-main/canvas-example-main/src/components/Iconfont/iconfont.ttf +0 -0
- package/canvas-example-main/canvas-example-main/src/components/Iconfont/iconfont.woff +0 -0
- package/canvas-example-main/canvas-example-main/src/components/Iconfont/iconfont.woff2 +0 -0
- package/canvas-example-main/canvas-example-main/src/components/Iconfont/index.tsx +39 -0
- package/canvas-example-main/canvas-example-main/src/main.css +9 -0
- package/canvas-example-main/canvas-example-main/src/main.tsx +10 -0
- package/canvas-example-main/canvas-example-main/src/pages/2048/g2048.ts +14 -0
- package/canvas-example-main/canvas-example-main/src/pages/2048/index.tsx +21 -0
- package/canvas-example-main/canvas-example-main/src/pages/clock/index.tsx +103 -0
- package/canvas-example-main/canvas-example-main/src/pages/demo/index.tsx +21 -0
- package/canvas-example-main/canvas-example-main/src/pages/editor/components/editor/index.module.less +3 -0
- package/canvas-example-main/canvas-example-main/src/pages/editor/components/editor/index.tsx +99 -0
- package/canvas-example-main/canvas-example-main/src/pages/editor/components/header/index.module.less +5 -0
- package/canvas-example-main/canvas-example-main/src/pages/editor/components/header/index.tsx +5 -0
- package/canvas-example-main/canvas-example-main/src/pages/editor/components/material/index.module.less +59 -0
- package/canvas-example-main/canvas-example-main/src/pages/editor/components/material/index.tsx +85 -0
- package/canvas-example-main/canvas-example-main/src/pages/editor/components/setting/index.module.less +7 -0
- package/canvas-example-main/canvas-example-main/src/pages/editor/components/setting/index.tsx +5 -0
- package/canvas-example-main/canvas-example-main/src/pages/editor/core/application.ts +35 -0
- package/canvas-example-main/canvas-example-main/src/pages/editor/core/cmp/base.ts +17 -0
- package/canvas-example-main/canvas-example-main/src/pages/editor/core/cmp/factory.ts +14 -0
- package/canvas-example-main/canvas-example-main/src/pages/editor/core/cmp/shape.tsx +43 -0
- package/canvas-example-main/canvas-example-main/src/pages/editor/core/editor.ts +61 -0
- package/canvas-example-main/canvas-example-main/src/pages/editor/core/type.ts +6 -0
- package/canvas-example-main/canvas-example-main/src/pages/editor/index.module.less +7 -0
- package/canvas-example-main/canvas-example-main/src/pages/editor/index.tsx +32 -0
- package/canvas-example-main/canvas-example-main/src/pages/editor/store/component-config.ts +61 -0
- package/canvas-example-main/canvas-example-main/src/pages/editor/store/components.ts +43 -0
- package/canvas-example-main/canvas-example-main/src/pages/editor/store/layout.ts +40 -0
- package/canvas-example-main/canvas-example-main/src/pages/home/index.tsx +59 -0
- package/canvas-example-main/canvas-example-main/src/pages/jigsaw/index.tsx +3 -0
- package/canvas-example-main/canvas-example-main/src/pages/minesweeper/bomber.png +0 -0
- package/canvas-example-main/canvas-example-main/src/pages/minesweeper/index.tsx +138 -0
- package/canvas-example-main/canvas-example-main/src/pages/minesweeper/mark.png +0 -0
- package/canvas-example-main/canvas-example-main/src/pages/minesweeper/minesweeper.ts +345 -0
- package/canvas-example-main/canvas-example-main/src/pages/minesweeper/utils.ts +24 -0
- package/canvas-example-main/canvas-example-main/src/pages/pageflip/index.tsx +200 -0
- package/canvas-example-main/canvas-example-main/src/pages/pageflip/page1.jpg +0 -0
- package/canvas-example-main/canvas-example-main/src/pages/practice/draw/index.ts +367 -0
- package/canvas-example-main/canvas-example-main/src/pages/practice/index.module.less +26 -0
- package/canvas-example-main/canvas-example-main/src/pages/practice/index.tsx +54 -0
- package/canvas-example-main/canvas-example-main/src/pages/shape-editor/control.ts +174 -0
- package/canvas-example-main/canvas-example-main/src/pages/shape-editor/editor.ts +91 -0
- package/canvas-example-main/canvas-example-main/src/pages/shape-editor/index.raw.tsx +159 -0
- package/canvas-example-main/canvas-example-main/src/pages/shape-editor/index.tsx +36 -0
- package/canvas-example-main/canvas-example-main/src/pages/shape-editor/shape.ts +248 -0
- package/canvas-example-main/canvas-example-main/src/router.tsx +53 -0
- package/canvas-example-main/canvas-example-main/src/utils/storage.ts +48 -0
- package/canvas-example-main/canvas-example-main/src/vite-env.d.ts +1 -0
- package/canvas-example-main/canvas-example-main/tailwind.config.js +8 -0
- package/canvas-example-main/canvas-example-main/tsconfig.app.json +30 -0
- package/canvas-example-main/canvas-example-main/tsconfig.json +7 -0
- package/canvas-example-main/canvas-example-main/tsconfig.node.json +22 -0
- package/canvas-example-main/canvas-example-main/vite.config.ts +18 -0
- package/package.json +1 -1
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { useEffect, useRef } from 'react';
|
|
2
|
+
|
|
3
|
+
export default function Component() {
|
|
4
|
+
const canvasRef = useRef<HTMLCanvasElement>();
|
|
5
|
+
|
|
6
|
+
const draw = () => {
|
|
7
|
+
const canvas = canvasRef.current;
|
|
8
|
+
const ctx = canvasRef.current.getContext('2d');
|
|
9
|
+
console.log(canvas, ctx);
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
useEffect(() => {
|
|
13
|
+
draw();
|
|
14
|
+
}, []);
|
|
15
|
+
|
|
16
|
+
return (
|
|
17
|
+
<div className="w-[100vw] h-[100vh] flex items-center justify-center background-[#aaa] flex-col">
|
|
18
|
+
<canvas width={600} height={600} ref={canvasRef}></canvas>
|
|
19
|
+
</div>
|
|
20
|
+
);
|
|
21
|
+
}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { useEffect, useRef } from 'react';
|
|
2
|
+
|
|
3
|
+
export default function Clock() {
|
|
4
|
+
const canvasRef = useRef<HTMLCanvasElement>();
|
|
5
|
+
|
|
6
|
+
const draw = () => {
|
|
7
|
+
const canvas = canvasRef.current;
|
|
8
|
+
const ctx = canvasRef.current.getContext('2d');
|
|
9
|
+
|
|
10
|
+
function drawClock() {
|
|
11
|
+
const now = new Date();
|
|
12
|
+
const hours = now.getHours();
|
|
13
|
+
const minutes = now.getMinutes();
|
|
14
|
+
const seconds = now.getSeconds();
|
|
15
|
+
|
|
16
|
+
const centerX = canvas.width / 2;
|
|
17
|
+
const centerY = canvas.height / 2;
|
|
18
|
+
|
|
19
|
+
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
|
20
|
+
drawFace(ctx, centerX, centerY, 150);
|
|
21
|
+
drawNumbers(ctx, centerX, centerY, 150);
|
|
22
|
+
drawTime(ctx, centerX, centerY, hours, minutes, seconds);
|
|
23
|
+
drawTicks(ctx, centerX, centerY, 150);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function drawFace(ctx: CanvasRenderingContext2D, x, y, radius) {
|
|
27
|
+
ctx.beginPath();
|
|
28
|
+
ctx.lineWidth = 2;
|
|
29
|
+
ctx.fillStyle = 'black';
|
|
30
|
+
ctx.arc(x, y, radius, 0, Math.PI * 2);
|
|
31
|
+
ctx.stroke();
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function drawTicks(ctx, x, y, radius) {
|
|
35
|
+
for (let i = 0; i < 60; i++) {
|
|
36
|
+
const angle = i * (Math.PI / 30);
|
|
37
|
+
const isHour = i % 5 === 0;
|
|
38
|
+
const len = isHour ? 15 : 10;
|
|
39
|
+
if (isHour) {
|
|
40
|
+
ctx.lineWidth = 2;
|
|
41
|
+
} else {
|
|
42
|
+
ctx.lineWidth = 1;
|
|
43
|
+
}
|
|
44
|
+
const innerX = x + (radius - len) * Math.sin(angle);
|
|
45
|
+
const innerY = y - (radius - len) * Math.cos(angle);
|
|
46
|
+
const outerX = x + radius * Math.sin(angle);
|
|
47
|
+
const outerY = y - radius * Math.cos(angle);
|
|
48
|
+
|
|
49
|
+
ctx.beginPath();
|
|
50
|
+
ctx.moveTo(innerX, innerY);
|
|
51
|
+
ctx.lineTo(outerX, outerY);
|
|
52
|
+
ctx.stroke();
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function drawNumbers(ctx, x, y, radius) {
|
|
57
|
+
ctx.font = `${radius / 10}px Arial`;
|
|
58
|
+
ctx.textBaseline = 'middle';
|
|
59
|
+
ctx.textAlign = 'center';
|
|
60
|
+
|
|
61
|
+
for (let num = 1; num <= 12; num++) {
|
|
62
|
+
const angle = num * (Math.PI / 6);
|
|
63
|
+
const dx = x + radius * 0.8 * Math.sin(angle);
|
|
64
|
+
const dy = y - radius * 0.8 * Math.cos(angle);
|
|
65
|
+
ctx.fillText(num.toString(), dx, dy);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function drawTime(ctx, x, y, hours, minutes, seconds) {
|
|
70
|
+
hours = hours % 12;
|
|
71
|
+
hours = (hours * Math.PI) / 6 + (minutes * Math.PI) / 360;
|
|
72
|
+
drawHand(ctx, x, y, hours, 50, 6); // Hour hand
|
|
73
|
+
|
|
74
|
+
minutes = (minutes * Math.PI) / 30 + (seconds * Math.PI) / 1800;
|
|
75
|
+
drawHand(ctx, x, y, minutes, 70, 4); // Minute hand
|
|
76
|
+
|
|
77
|
+
seconds = (seconds * Math.PI) / 30;
|
|
78
|
+
drawHand(ctx, x, y, seconds, 90, 2); // Second hand
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function drawHand(ctx, x, y, angle, length, width) {
|
|
82
|
+
ctx.beginPath();
|
|
83
|
+
ctx.lineWidth = width;
|
|
84
|
+
ctx.lineCap = 'round';
|
|
85
|
+
ctx.moveTo(x, y);
|
|
86
|
+
ctx.lineTo(x + length * Math.sin(angle), y - length * Math.cos(angle));
|
|
87
|
+
ctx.stroke();
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
setInterval(drawClock, 1000);
|
|
91
|
+
drawClock();
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
useEffect(() => {
|
|
95
|
+
draw();
|
|
96
|
+
}, []);
|
|
97
|
+
|
|
98
|
+
return (
|
|
99
|
+
<div className="w-[100vw] h-[100vh] flex items-center justify-center background-[#aaa] flex-col">
|
|
100
|
+
<canvas width={600} height={600} ref={canvasRef}></canvas>
|
|
101
|
+
</div>
|
|
102
|
+
);
|
|
103
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { useEffect, useRef } from 'react';
|
|
2
|
+
|
|
3
|
+
export default function Component() {
|
|
4
|
+
const canvasRef = useRef<HTMLCanvasElement>();
|
|
5
|
+
|
|
6
|
+
const draw = () => {
|
|
7
|
+
const canvas = canvasRef.current;
|
|
8
|
+
const ctx = canvasRef.current.getContext('2d');
|
|
9
|
+
console.log(canvas, ctx);
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
useEffect(() => {
|
|
13
|
+
draw();
|
|
14
|
+
}, []);
|
|
15
|
+
|
|
16
|
+
return (
|
|
17
|
+
<div className="w-[100vw] h-[100vh] flex items-center justify-center background-[#aaa] flex-col">
|
|
18
|
+
<canvas width={600} height={600} ref={canvasRef}></canvas>
|
|
19
|
+
</div>
|
|
20
|
+
);
|
|
21
|
+
}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { useEffect, useRef, useState } from 'react';
|
|
2
|
+
import { createPortal } from 'react-dom';
|
|
3
|
+
import Editor from '../../core/editor';
|
|
4
|
+
import { useLayoutStore } from '../../store/layout';
|
|
5
|
+
import { useComponentStore } from '../../store/components';
|
|
6
|
+
|
|
7
|
+
import S from './index.module.less';
|
|
8
|
+
|
|
9
|
+
export default function EditorComponent() {
|
|
10
|
+
const { contentWidth, contentHeight } = useLayoutStore();
|
|
11
|
+
const { components, updateEditor } = useComponentStore();
|
|
12
|
+
const editorRef = useRef<Editor>();
|
|
13
|
+
|
|
14
|
+
useEffect(() => {
|
|
15
|
+
const id = 'editor-canvas-container';
|
|
16
|
+
|
|
17
|
+
const el = document.querySelector(`#${id}`);
|
|
18
|
+
|
|
19
|
+
let cancelContextMenuListener;
|
|
20
|
+
|
|
21
|
+
if (el) {
|
|
22
|
+
editorRef.current = new Editor({
|
|
23
|
+
width: contentWidth,
|
|
24
|
+
height: contentHeight,
|
|
25
|
+
frameHeight: 900,
|
|
26
|
+
frameWidth: 500,
|
|
27
|
+
view: id,
|
|
28
|
+
onMenuTap(event) {
|
|
29
|
+
console.log('event', event);
|
|
30
|
+
},
|
|
31
|
+
onSelect(event) {
|
|
32
|
+
// updateSelectCmp(event.value);
|
|
33
|
+
console.log(event);
|
|
34
|
+
},
|
|
35
|
+
onMove(event) {
|
|
36
|
+
console.log(event);
|
|
37
|
+
},
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
updateEditor(editorRef.current);
|
|
41
|
+
|
|
42
|
+
cancelContextMenuListener = document.addEventListener('click', () => {
|
|
43
|
+
setMenuPosition({ x: 0, y: 0 });
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
return () => {
|
|
48
|
+
if (editorRef.current) {
|
|
49
|
+
editorRef.current.destroy();
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
if (cancelContextMenuListener) {
|
|
53
|
+
document.removeEventListener('click', cancelContextMenuListener);
|
|
54
|
+
}
|
|
55
|
+
};
|
|
56
|
+
}, []);
|
|
57
|
+
|
|
58
|
+
useEffect(() => {
|
|
59
|
+
if (editorRef.current) {
|
|
60
|
+
editorRef.current.resize({ width: contentWidth, height: contentHeight });
|
|
61
|
+
}
|
|
62
|
+
}, [contentWidth, contentHeight]);
|
|
63
|
+
|
|
64
|
+
useEffect(() => {}, [components]);
|
|
65
|
+
|
|
66
|
+
const [menuPosition, setMenuPosition] = useState({ x: 0, y: 0 });
|
|
67
|
+
|
|
68
|
+
const Menu = ({ x, y }) => {
|
|
69
|
+
return createPortal(
|
|
70
|
+
<div
|
|
71
|
+
style={{
|
|
72
|
+
position: 'absolute',
|
|
73
|
+
left: x,
|
|
74
|
+
top: y,
|
|
75
|
+
background: '#f0f0f0',
|
|
76
|
+
padding: '5px',
|
|
77
|
+
border: '1px solid #ccc',
|
|
78
|
+
}}
|
|
79
|
+
>
|
|
80
|
+
<ul>
|
|
81
|
+
<li onClick={() => {}}>移除</li>
|
|
82
|
+
<li>置顶</li>
|
|
83
|
+
<li>置底</li>
|
|
84
|
+
</ul>
|
|
85
|
+
</div>,
|
|
86
|
+
document.body
|
|
87
|
+
);
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
return (
|
|
91
|
+
<main
|
|
92
|
+
className={S.editor}
|
|
93
|
+
style={{ width: contentWidth }}
|
|
94
|
+
id="editor-canvas-container"
|
|
95
|
+
>
|
|
96
|
+
{menuPosition.x !== 0 && <Menu x={menuPosition.x} y={menuPosition.y} />}
|
|
97
|
+
</main>
|
|
98
|
+
);
|
|
99
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
.material {
|
|
2
|
+
height: 100%;
|
|
3
|
+
background-color: white;
|
|
4
|
+
position: relative;
|
|
5
|
+
|
|
6
|
+
.content {
|
|
7
|
+
display: flex;
|
|
8
|
+
flex-direction: row;
|
|
9
|
+
height: 100%;
|
|
10
|
+
|
|
11
|
+
.list {
|
|
12
|
+
width: 60px;
|
|
13
|
+
display: flex;
|
|
14
|
+
flex-direction: column;
|
|
15
|
+
align-items: center;
|
|
16
|
+
gap: 15px;
|
|
17
|
+
|
|
18
|
+
border-right: 1px solid #dcdee2;
|
|
19
|
+
|
|
20
|
+
.item {
|
|
21
|
+
display: flex;
|
|
22
|
+
flex-direction: column;
|
|
23
|
+
align-items: center;
|
|
24
|
+
cursor: pointer;
|
|
25
|
+
width: 100%;
|
|
26
|
+
border-right: 2px solid transparent;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
.item-active {
|
|
30
|
+
border-right: 2px solid #2d8cf0;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
.aside {
|
|
35
|
+
width: 300px;
|
|
36
|
+
position: relative;
|
|
37
|
+
display: flex;
|
|
38
|
+
flex-direction: row;
|
|
39
|
+
flex-wrap: wrap;
|
|
40
|
+
gap: 10px;
|
|
41
|
+
padding: 10px;
|
|
42
|
+
|
|
43
|
+
.item {
|
|
44
|
+
cursor: pointer;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
.menu {
|
|
50
|
+
width: 30px;
|
|
51
|
+
height: 30px;
|
|
52
|
+
position: absolute;
|
|
53
|
+
right: -30px;
|
|
54
|
+
top: 50%;
|
|
55
|
+
transform: translate(0, -15px);
|
|
56
|
+
cursor: pointer;
|
|
57
|
+
z-index: 999999;
|
|
58
|
+
}
|
|
59
|
+
}
|
package/canvas-example-main/canvas-example-main/src/pages/editor/components/material/index.tsx
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { useMemo, useState } from 'react';
|
|
2
|
+
import classNames from 'classnames';
|
|
3
|
+
|
|
4
|
+
import Iconfont from '@/components/Iconfont';
|
|
5
|
+
import { useLayoutStore } from '../../store/layout';
|
|
6
|
+
|
|
7
|
+
import { useComponentStore } from '../../store/components';
|
|
8
|
+
import { useComponentConfigStore } from '../../store/component-config';
|
|
9
|
+
import S from './index.module.less';
|
|
10
|
+
|
|
11
|
+
export default function Material() {
|
|
12
|
+
const { componentConfig } = useComponentConfigStore();
|
|
13
|
+
|
|
14
|
+
const [activeType, setActiveType] = useState(componentConfig[0].type);
|
|
15
|
+
const { asideOpen, updateAsideOpen } = useLayoutStore();
|
|
16
|
+
const { addCmp } = useComponentStore();
|
|
17
|
+
|
|
18
|
+
const components = useMemo(() => {
|
|
19
|
+
const currentComponents = componentConfig.find(
|
|
20
|
+
(o) => o.type === activeType
|
|
21
|
+
);
|
|
22
|
+
return currentComponents.components;
|
|
23
|
+
}, [componentConfig, activeType]);
|
|
24
|
+
|
|
25
|
+
const Item = ({ item }) => {
|
|
26
|
+
return (
|
|
27
|
+
<div
|
|
28
|
+
className={classNames(
|
|
29
|
+
S.item,
|
|
30
|
+
item.type === activeType && S['item-active']
|
|
31
|
+
)}
|
|
32
|
+
onClick={() => {
|
|
33
|
+
setActiveType(item.type);
|
|
34
|
+
updateAsideOpen(true);
|
|
35
|
+
}}
|
|
36
|
+
>
|
|
37
|
+
<Iconfont name={item.icon} />
|
|
38
|
+
<span>{item.label}</span>
|
|
39
|
+
</div>
|
|
40
|
+
);
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
return (
|
|
44
|
+
<aside className={S.material}>
|
|
45
|
+
<div className={S.content}>
|
|
46
|
+
<div className={S.list}>
|
|
47
|
+
{componentConfig.map((item) => (
|
|
48
|
+
<Item item={item} key={item.type} />
|
|
49
|
+
))}
|
|
50
|
+
</div>
|
|
51
|
+
|
|
52
|
+
{asideOpen && (
|
|
53
|
+
<div className={S.aside}>
|
|
54
|
+
{components.map((cmp) => {
|
|
55
|
+
return (
|
|
56
|
+
<div
|
|
57
|
+
className={S.item}
|
|
58
|
+
onClick={() => {
|
|
59
|
+
addCmp(cmp.model as any);
|
|
60
|
+
}}
|
|
61
|
+
key={cmp.name}
|
|
62
|
+
>
|
|
63
|
+
{typeof cmp.icon === 'string' ? (
|
|
64
|
+
<Iconfont name={cmp.icon}></Iconfont>
|
|
65
|
+
) : (
|
|
66
|
+
cmp.icon()
|
|
67
|
+
)}
|
|
68
|
+
</div>
|
|
69
|
+
);
|
|
70
|
+
})}
|
|
71
|
+
</div>
|
|
72
|
+
)}
|
|
73
|
+
</div>
|
|
74
|
+
|
|
75
|
+
<div
|
|
76
|
+
className={S.menu}
|
|
77
|
+
onClick={() => {
|
|
78
|
+
updateAsideOpen(!asideOpen);
|
|
79
|
+
}}
|
|
80
|
+
>
|
|
81
|
+
{asideOpen ? <Iconfont name="jiantou1" /> : <Iconfont name="jiantou" />}
|
|
82
|
+
</div>
|
|
83
|
+
</aside>
|
|
84
|
+
);
|
|
85
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { App, Frame, IScreenSizeData } from 'leafer-ui';
|
|
2
|
+
|
|
3
|
+
export interface IApplicationConfig {
|
|
4
|
+
view: string;
|
|
5
|
+
width: number;
|
|
6
|
+
height: number;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export class Application {
|
|
10
|
+
config: IApplicationConfig;
|
|
11
|
+
app: App;
|
|
12
|
+
page: Frame;
|
|
13
|
+
|
|
14
|
+
constructor(config: IApplicationConfig) {
|
|
15
|
+
this.config = config;
|
|
16
|
+
const { view, width, height } = config;
|
|
17
|
+
this.app = new App({ view, width, height, editor: {} });
|
|
18
|
+
|
|
19
|
+
this.app.tree = this.app.addLeafer();
|
|
20
|
+
this.app.ground = this.app.addLeafer();
|
|
21
|
+
this.app.sky = this.app.addLeafer({ type: 'draw', usePartRender: false });
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
toJSON() {
|
|
25
|
+
return this.app.toJSON();
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
resize(sizeData: IScreenSizeData) {
|
|
29
|
+
this.app.resize(sizeData);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
destroy() {
|
|
33
|
+
this.app.destroy();
|
|
34
|
+
}
|
|
35
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { ComponentType } from '../type';
|
|
2
|
+
|
|
3
|
+
export interface BaseModel {
|
|
4
|
+
x: number;
|
|
5
|
+
y: number;
|
|
6
|
+
width?: number;
|
|
7
|
+
height?: number;
|
|
8
|
+
editable: boolean;
|
|
9
|
+
type?: ComponentType;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export const baseModel: BaseModel = {
|
|
13
|
+
x: 0,
|
|
14
|
+
y: 0,
|
|
15
|
+
editable: true,
|
|
16
|
+
type: ComponentType.Rect,
|
|
17
|
+
};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { Polygon, Rect } from 'leafer-ui';
|
|
2
|
+
import { BaseModel } from './base';
|
|
3
|
+
import { ComponentType } from '../type';
|
|
4
|
+
|
|
5
|
+
export function create(type: ComponentType, model: BaseModel) {
|
|
6
|
+
switch (type) {
|
|
7
|
+
case ComponentType.Rect:
|
|
8
|
+
return new Rect(model);
|
|
9
|
+
case ComponentType.Polygon:
|
|
10
|
+
return new Polygon(model);
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
return null;
|
|
14
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import Iconfont from '@/components/Iconfont';
|
|
2
|
+
import { Component } from '../../store/component-config';
|
|
3
|
+
import { ComponentType } from '../type';
|
|
4
|
+
import { baseModel } from './base';
|
|
5
|
+
|
|
6
|
+
const rect: Component = {
|
|
7
|
+
name: '矩形',
|
|
8
|
+
icon: () => <Iconfont size={28} name="xingzhuang-juxing"></Iconfont>,
|
|
9
|
+
model: {
|
|
10
|
+
...baseModel,
|
|
11
|
+
type: ComponentType.Rect,
|
|
12
|
+
width: 150,
|
|
13
|
+
height: 150,
|
|
14
|
+
fill: 'lime',
|
|
15
|
+
},
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
const triangle: Component = {
|
|
19
|
+
name: '三角形',
|
|
20
|
+
icon: () => <Iconfont size={28} name="xingzhuang-sanjiaoxing"></Iconfont>,
|
|
21
|
+
model: {
|
|
22
|
+
...baseModel,
|
|
23
|
+
type: ComponentType.Polygon,
|
|
24
|
+
width: 100,
|
|
25
|
+
height: 100,
|
|
26
|
+
sides: 3,
|
|
27
|
+
fill: 'lime',
|
|
28
|
+
},
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
const circle: Component = {
|
|
32
|
+
name: '圆',
|
|
33
|
+
icon: () => <Iconfont size={28} name="yuanhuan"></Iconfont>,
|
|
34
|
+
model: {
|
|
35
|
+
...baseModel,
|
|
36
|
+
type: ComponentType.Rect,
|
|
37
|
+
width: 150,
|
|
38
|
+
height: 150,
|
|
39
|
+
fill: 'lime',
|
|
40
|
+
},
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
export const shapeComponent = [rect, triangle, circle];
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Editor as LeaferEditor,
|
|
3
|
+
EditorEvent,
|
|
4
|
+
EditorMoveEvent,
|
|
5
|
+
} from '@leafer-in/editor';
|
|
6
|
+
|
|
7
|
+
import { Frame, PointerEvent } from 'leafer-ui';
|
|
8
|
+
import { Application, IApplicationConfig } from './application';
|
|
9
|
+
|
|
10
|
+
interface IEditorConfig extends IApplicationConfig {
|
|
11
|
+
frameWidth: number;
|
|
12
|
+
frameHeight: number;
|
|
13
|
+
onMenuTap?: (event) => void;
|
|
14
|
+
onSelect?: (event) => void;
|
|
15
|
+
onMove?: (event) => void;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export default class Editor extends Application {
|
|
19
|
+
declare config: IEditorConfig;
|
|
20
|
+
|
|
21
|
+
constructor(config: IEditorConfig) {
|
|
22
|
+
super(config);
|
|
23
|
+
this.config = config;
|
|
24
|
+
|
|
25
|
+
const { onMenuTap, onSelect, onMove } = config;
|
|
26
|
+
|
|
27
|
+
this.app.editor = new LeaferEditor({ continuousSelect: true });
|
|
28
|
+
this.app.sky.add(this.app.editor);
|
|
29
|
+
|
|
30
|
+
this.app.on(PointerEvent.MENU_TAP, onMenuTap);
|
|
31
|
+
this.app.editor.on(EditorEvent.SELECT, onSelect);
|
|
32
|
+
this.app.editor.on(EditorMoveEvent.MOVE, onMove);
|
|
33
|
+
|
|
34
|
+
this.initFrame();
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
initFrame() {
|
|
38
|
+
const { frameWidth, frameHeight } = this.config;
|
|
39
|
+
|
|
40
|
+
const centerX = this.app.width / 2 - frameWidth / 2;
|
|
41
|
+
const centerY = this.app.height / 2 - frameHeight / 2;
|
|
42
|
+
this.page = new Frame({
|
|
43
|
+
x: centerX,
|
|
44
|
+
y: centerY,
|
|
45
|
+
width: frameWidth,
|
|
46
|
+
height: frameHeight,
|
|
47
|
+
fill: 'white',
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
this.app.tree.add(this.page);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
addCmp(cmp: any) {
|
|
54
|
+
this.page.add(cmp);
|
|
55
|
+
return cmp;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
removeCmp() {}
|
|
59
|
+
|
|
60
|
+
updateCmp() {}
|
|
61
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { useEffect } from 'react';
|
|
2
|
+
|
|
3
|
+
import { useWindowSize } from 'react-use';
|
|
4
|
+
|
|
5
|
+
import Editor from './components/editor';
|
|
6
|
+
import Header from './components/header';
|
|
7
|
+
import Material from './components/material';
|
|
8
|
+
import Setting from './components/setting';
|
|
9
|
+
|
|
10
|
+
import { useLayoutStore } from './store/layout';
|
|
11
|
+
|
|
12
|
+
import S from './index.module.less';
|
|
13
|
+
|
|
14
|
+
export default function Component() {
|
|
15
|
+
const { updateContentWidth } = useLayoutStore();
|
|
16
|
+
const { width } = useWindowSize();
|
|
17
|
+
|
|
18
|
+
useEffect(() => {
|
|
19
|
+
updateContentWidth(width - 360);
|
|
20
|
+
}, [width]);
|
|
21
|
+
|
|
22
|
+
return (
|
|
23
|
+
<div className="bg-[#f2f3f5] h-[100vh] w-[100vw]">
|
|
24
|
+
<Header />
|
|
25
|
+
<div className={S.content}>
|
|
26
|
+
<Material />
|
|
27
|
+
<Editor />
|
|
28
|
+
<Setting />
|
|
29
|
+
</div>
|
|
30
|
+
</div>
|
|
31
|
+
);
|
|
32
|
+
}
|