canvas-react-easy 1.1.2 → 1.1.3
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.
|
@@ -1,30 +1,37 @@
|
|
|
1
|
-
import { jsx as _jsx } from "react/jsx-runtime";
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { useEffect, useRef } from "react";
|
|
3
3
|
import CanvasState from "../store/CanvasState";
|
|
4
4
|
import toolState from "../store/ToolState";
|
|
5
5
|
import { Brush } from "../tools/Brush";
|
|
6
6
|
import TextHoverTool from "../tools/TextHoverTool";
|
|
7
7
|
const Canvas = ({ userName = "Гость" }) => {
|
|
8
|
-
const
|
|
8
|
+
const mainRef = useRef(null);
|
|
9
|
+
const overlayRef = useRef(null);
|
|
9
10
|
useEffect(() => {
|
|
10
|
-
const
|
|
11
|
-
|
|
11
|
+
const mainCanvas = mainRef.current;
|
|
12
|
+
const overlayCanvas = overlayRef.current;
|
|
13
|
+
if (!mainCanvas || !overlayCanvas)
|
|
12
14
|
return;
|
|
13
|
-
CanvasState.setCanvas(
|
|
14
|
-
// По умолчанию кисть
|
|
15
|
-
const brush = new Brush(
|
|
15
|
+
CanvasState.setCanvas(mainCanvas);
|
|
16
|
+
// По умолчанию включаем кисть
|
|
17
|
+
const brush = new Brush(mainCanvas);
|
|
16
18
|
toolState.setTool(brush);
|
|
17
|
-
// Подключаем TextHoverTool
|
|
18
|
-
const
|
|
19
|
-
|
|
20
|
-
//
|
|
21
|
-
toolState.setTool(
|
|
19
|
+
// Подключаем TextHoverTool для отображения имени пользователя
|
|
20
|
+
const hover = new TextHoverTool(mainCanvas, overlayCanvas, userName);
|
|
21
|
+
hover.listen();
|
|
22
|
+
// Ставим hover tool как текущий инструмент (можно потом переключать через кнопки)
|
|
23
|
+
toolState.setTool(hover);
|
|
22
24
|
// Очистка при размонтировании
|
|
23
25
|
return () => {
|
|
24
|
-
hoverTool.clearEvents();
|
|
25
26
|
brush.clearEvents();
|
|
27
|
+
hover.clearEvents();
|
|
26
28
|
};
|
|
27
29
|
}, [userName]);
|
|
28
|
-
return (_jsx("canvas", { ref:
|
|
30
|
+
return (_jsxs("div", { style: { position: "relative" }, children: [_jsx("canvas", { ref: mainRef, width: 1600, height: 900, style: { border: "1px solid black", display: "block" } }), _jsx("canvas", { ref: overlayRef, width: 1600, height: 900, style: {
|
|
31
|
+
position: "absolute",
|
|
32
|
+
top: 0,
|
|
33
|
+
left: 0,
|
|
34
|
+
pointerEvents: "none",
|
|
35
|
+
} })] }));
|
|
29
36
|
};
|
|
30
37
|
export default Canvas;
|
|
@@ -1,43 +1,32 @@
|
|
|
1
1
|
import Tool from "./Tool";
|
|
2
|
-
export class TextHoverTool extends Tool {
|
|
3
|
-
constructor(canvas, userName) {
|
|
2
|
+
export default class TextHoverTool extends Tool {
|
|
3
|
+
constructor(canvas, overlayCanvas, userName) {
|
|
4
4
|
super(canvas);
|
|
5
5
|
this.fontSize = 18;
|
|
6
6
|
this.fontFamily = "Arial";
|
|
7
7
|
this.color = "black";
|
|
8
8
|
this.userName = userName;
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
this.
|
|
14
|
-
this.overlayCanvas.style.left = canvas.offsetLeft + "px";
|
|
15
|
-
this.overlayCanvas.style.top = canvas.offsetTop + "px";
|
|
16
|
-
this.overlayCanvas.style.pointerEvents = "none"; // мышь проходит через него
|
|
17
|
-
canvas.parentElement.appendChild(this.overlayCanvas);
|
|
18
|
-
this.overlayCtx = this.overlayCanvas.getContext("2d");
|
|
9
|
+
this.overlayCanvas = overlayCanvas;
|
|
10
|
+
const ctx = overlayCanvas.getContext("2d");
|
|
11
|
+
if (!ctx)
|
|
12
|
+
throw new Error("Cannot get 2D context for overlay");
|
|
13
|
+
this.overlayCtx = ctx;
|
|
19
14
|
}
|
|
20
15
|
listen() {
|
|
21
|
-
const moveHandler = (
|
|
22
|
-
|
|
23
|
-
// Очищаем overlay
|
|
16
|
+
const moveHandler = (e) => {
|
|
17
|
+
// очищаем overlay
|
|
24
18
|
this.overlayCtx.clearRect(0, 0, this.overlayCanvas.width, this.overlayCanvas.height);
|
|
25
|
-
// Координаты мыши относительно канваса
|
|
26
19
|
const x = e.pageX - this.canvas.offsetLeft;
|
|
27
20
|
const y = e.pageY - this.canvas.offsetTop;
|
|
28
|
-
// Рисуем имя чуть выше курсора
|
|
29
21
|
this.overlayCtx.font = `${this.fontSize}px ${this.fontFamily}`;
|
|
30
22
|
this.overlayCtx.fillStyle = this.color;
|
|
31
23
|
this.overlayCtx.fillText(this.userName, x, y - 20);
|
|
32
24
|
};
|
|
33
|
-
|
|
25
|
+
// Типизируем addEventListener как MouseEvent
|
|
26
|
+
this.overlayCanvas.addEventListener("mousemove", moveHandler);
|
|
34
27
|
}
|
|
35
28
|
clearEvents() {
|
|
36
29
|
super.clearEvents();
|
|
37
|
-
|
|
38
|
-
if (this.overlayCanvas.parentElement) {
|
|
39
|
-
this.overlayCanvas.parentElement.removeChild(this.overlayCanvas);
|
|
40
|
-
}
|
|
30
|
+
this.overlayCtx.clearRect(0, 0, this.overlayCanvas.width, this.overlayCanvas.height);
|
|
41
31
|
}
|
|
42
32
|
}
|
|
43
|
-
export default TextHoverTool;
|
|
@@ -1,13 +1,12 @@
|
|
|
1
1
|
import Tool from "./Tool";
|
|
2
|
-
export
|
|
2
|
+
export default class TextHoverTool extends Tool {
|
|
3
3
|
userName: string;
|
|
4
4
|
fontSize: number;
|
|
5
5
|
fontFamily: string;
|
|
6
6
|
color: string;
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
constructor(canvas: HTMLCanvasElement, userName: string);
|
|
7
|
+
overlayCanvas: HTMLCanvasElement;
|
|
8
|
+
overlayCtx: CanvasRenderingContext2D;
|
|
9
|
+
constructor(canvas: HTMLCanvasElement, overlayCanvas: HTMLCanvasElement, userName: string);
|
|
10
10
|
listen(): void;
|
|
11
11
|
clearEvents(): void;
|
|
12
12
|
}
|
|
13
|
-
export default TextHoverTool;
|
package/package.json
CHANGED
|
@@ -1,9 +1,6 @@
|
|
|
1
|
-
import React
|
|
1
|
+
import React from "react";
|
|
2
2
|
import Tools from "./Tools";
|
|
3
3
|
import Canvas from "./Canvas";
|
|
4
|
-
import toolState from "../store/ToolState";
|
|
5
|
-
import CanvasState from "../store/CanvasState";
|
|
6
|
-
import TextHoverTool from "../tools/TextHoverTool";
|
|
7
4
|
|
|
8
5
|
interface BorderProps {
|
|
9
6
|
userName?: string;
|
|
@@ -2,6 +2,10 @@ import React, { useEffect, useRef } from "react";
|
|
|
2
2
|
import CanvasState from "../store/CanvasState";
|
|
3
3
|
import toolState from "../store/ToolState";
|
|
4
4
|
import { Brush } from "../tools/Brush";
|
|
5
|
+
import { Rectangle } from "../tools/Rectangle";
|
|
6
|
+
import { Circle } from "../tools/Circle";
|
|
7
|
+
import { TextTool } from "../tools/Text";
|
|
8
|
+
import { ImageTool } from "../tools/ImageTool";
|
|
5
9
|
import TextHoverTool from "../tools/TextHoverTool";
|
|
6
10
|
|
|
7
11
|
interface CanvasProps {
|
|
@@ -9,39 +13,54 @@ interface CanvasProps {
|
|
|
9
13
|
}
|
|
10
14
|
|
|
11
15
|
const Canvas: React.FC<CanvasProps> = ({ userName = "Гость" }) => {
|
|
12
|
-
const
|
|
16
|
+
const mainRef = useRef<HTMLCanvasElement>(null);
|
|
17
|
+
const overlayRef = useRef<HTMLCanvasElement>(null);
|
|
13
18
|
|
|
14
19
|
useEffect(() => {
|
|
15
|
-
const
|
|
16
|
-
|
|
20
|
+
const mainCanvas = mainRef.current;
|
|
21
|
+
const overlayCanvas = overlayRef.current;
|
|
22
|
+
if (!mainCanvas || !overlayCanvas) return;
|
|
17
23
|
|
|
18
|
-
CanvasState.setCanvas(
|
|
24
|
+
CanvasState.setCanvas(mainCanvas);
|
|
19
25
|
|
|
20
|
-
// По умолчанию кисть
|
|
21
|
-
const brush = new Brush(
|
|
26
|
+
// По умолчанию включаем кисть
|
|
27
|
+
const brush = new Brush(mainCanvas);
|
|
22
28
|
toolState.setTool(brush);
|
|
23
29
|
|
|
24
|
-
// Подключаем TextHoverTool
|
|
25
|
-
const
|
|
26
|
-
|
|
30
|
+
// Подключаем TextHoverTool для отображения имени пользователя
|
|
31
|
+
const hover = new TextHoverTool(mainCanvas, overlayCanvas, userName);
|
|
32
|
+
hover.listen();
|
|
27
33
|
|
|
28
|
-
//
|
|
29
|
-
toolState.setTool(
|
|
34
|
+
// Ставим hover tool как текущий инструмент (можно потом переключать через кнопки)
|
|
35
|
+
toolState.setTool(hover);
|
|
30
36
|
|
|
31
37
|
// Очистка при размонтировании
|
|
32
38
|
return () => {
|
|
33
|
-
hoverTool.clearEvents();
|
|
34
39
|
brush.clearEvents();
|
|
40
|
+
hover.clearEvents();
|
|
35
41
|
};
|
|
36
42
|
}, [userName]);
|
|
37
43
|
|
|
38
44
|
return (
|
|
39
|
-
<
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
+
<div style={{ position: "relative" }}>
|
|
46
|
+
<canvas
|
|
47
|
+
ref={mainRef}
|
|
48
|
+
width={1600}
|
|
49
|
+
height={900}
|
|
50
|
+
style={{ border: "1px solid black", display: "block" }}
|
|
51
|
+
/>
|
|
52
|
+
<canvas
|
|
53
|
+
ref={overlayRef}
|
|
54
|
+
width={1600}
|
|
55
|
+
height={900}
|
|
56
|
+
style={{
|
|
57
|
+
position: "absolute",
|
|
58
|
+
top: 0,
|
|
59
|
+
left: 0,
|
|
60
|
+
pointerEvents: "none",
|
|
61
|
+
}}
|
|
62
|
+
/>
|
|
63
|
+
</div>
|
|
45
64
|
);
|
|
46
65
|
};
|
|
47
66
|
|
|
@@ -1,58 +1,51 @@
|
|
|
1
1
|
import Tool from "./Tool";
|
|
2
2
|
|
|
3
|
-
export class TextHoverTool extends Tool {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
// Удаляем overlay с DOM
|
|
52
|
-
if (this.overlayCanvas.parentElement) {
|
|
53
|
-
this.overlayCanvas.parentElement.removeChild(this.overlayCanvas);
|
|
54
|
-
}
|
|
55
|
-
}
|
|
3
|
+
export default class TextHoverTool extends Tool {
|
|
4
|
+
userName: string;
|
|
5
|
+
fontSize = 18;
|
|
6
|
+
fontFamily = "Arial";
|
|
7
|
+
color = "black";
|
|
8
|
+
|
|
9
|
+
overlayCanvas: HTMLCanvasElement;
|
|
10
|
+
overlayCtx: CanvasRenderingContext2D;
|
|
11
|
+
|
|
12
|
+
constructor(
|
|
13
|
+
canvas: HTMLCanvasElement,
|
|
14
|
+
overlayCanvas: HTMLCanvasElement,
|
|
15
|
+
userName: string
|
|
16
|
+
) {
|
|
17
|
+
super(canvas);
|
|
18
|
+
this.userName = userName;
|
|
19
|
+
this.overlayCanvas = overlayCanvas;
|
|
20
|
+
const ctx = overlayCanvas.getContext("2d");
|
|
21
|
+
if (!ctx) throw new Error("Cannot get 2D context for overlay");
|
|
22
|
+
this.overlayCtx = ctx;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
listen() {
|
|
26
|
+
const moveHandler = (e: MouseEvent) => {
|
|
27
|
+
// очищаем overlay
|
|
28
|
+
this.overlayCtx.clearRect(
|
|
29
|
+
0,
|
|
30
|
+
0,
|
|
31
|
+
this.overlayCanvas.width,
|
|
32
|
+
this.overlayCanvas.height
|
|
33
|
+
);
|
|
34
|
+
|
|
35
|
+
const x = e.pageX - this.canvas.offsetLeft;
|
|
36
|
+
const y = e.pageY - this.canvas.offsetTop;
|
|
37
|
+
|
|
38
|
+
this.overlayCtx.font = `${this.fontSize}px ${this.fontFamily}`;
|
|
39
|
+
this.overlayCtx.fillStyle = this.color;
|
|
40
|
+
this.overlayCtx.fillText(this.userName, x, y - 20);
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
// Типизируем addEventListener как MouseEvent
|
|
44
|
+
this.overlayCanvas.addEventListener("mousemove", moveHandler as EventListener);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
clearEvents() {
|
|
48
|
+
super.clearEvents();
|
|
49
|
+
this.overlayCtx.clearRect(0, 0, this.overlayCanvas.width, this.overlayCanvas.height);
|
|
50
|
+
}
|
|
56
51
|
}
|
|
57
|
-
|
|
58
|
-
export default TextHoverTool;
|