canvas-react-easy 1.0.9 → 1.1.0

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,8 +1,21 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { observer } from "mobx-react-lite";
2
+ import { useEffect } from "react";
3
3
  import Tools from "./Tools";
4
4
  import Canvas from "./Canvas";
5
- const Border = observer(() => {
6
- return (_jsxs("div", { children: [_jsx(Tools, {}), _jsx(Canvas, {})] }));
7
- });
5
+ import toolState from "../store/ToolState";
6
+ import CanvasState from "../store/CanvasState";
7
+ import { TextHoverTool } from "../tools/TextHoverTool";
8
+ const Border = ({ userName = "Гость" }) => {
9
+ useEffect(() => {
10
+ var _a;
11
+ // активируем инструмент "имя пользователя" сразу после монтирования
12
+ if (CanvasState.canvas) {
13
+ (_a = toolState.tool) === null || _a === void 0 ? void 0 : _a.clearEvents();
14
+ const tool = new TextHoverTool(CanvasState.canvas, userName);
15
+ tool.listen();
16
+ toolState.setTool(tool);
17
+ }
18
+ }, [userName]);
19
+ return (_jsxs("div", { style: { position: "relative" }, children: [_jsx(Tools, { userName: userName }), _jsx(Canvas, {})] }));
20
+ };
8
21
  export default Border;
@@ -6,7 +6,8 @@ import { Rectangle } from "../tools/Rectangle";
6
6
  import { Circle } from "../tools/Circle";
7
7
  import { TextTool } from "../tools/Text";
8
8
  import { ImageTool } from "../tools/ImageTool";
9
- const Tools = () => {
9
+ const Tools = ({ userName = "Гость" }) => {
10
+ // универсальный выбор инструмента
10
11
  const selectTool = (ToolClass) => {
11
12
  var _a, _b;
12
13
  if (!CanvasState.canvas)
@@ -18,6 +19,6 @@ const Tools = () => {
18
19
  (_b = tool.listen) === null || _b === void 0 ? void 0 : _b.call(tool); // если инструмент имеет метод listen
19
20
  toolState.setTool(tool);
20
21
  };
21
- return (_jsxs("div", { style: { marginBottom: "10px" }, children: [_jsx("button", { onClick: () => selectTool(Brush), children: "\u041A\u0438\u0441\u0442\u044C" }), _jsx("button", { onClick: () => selectTool(Rectangle), children: "\u041F\u0440\u044F\u043C\u043E\u0443\u0433\u043E\u043B\u044C\u043D\u0438\u043A" }), _jsx("button", { onClick: () => selectTool(Circle), children: "\u041A\u0440\u0443\u0433" }), _jsx("button", { onClick: () => selectTool(TextTool), children: "\u0422\u0435\u043A\u0441\u0442" }), _jsx("button", { onClick: () => selectTool(ImageTool), children: "\u0418\u0437\u043E\u0431\u0440\u0430\u0436\u0435\u043D\u0438\u0435" })] }));
22
+ return (_jsxs("div", { style: { marginBottom: "10px", display: "flex", gap: "5px" }, children: [_jsx("button", { onClick: () => selectTool(Brush), children: "\u041A\u0438\u0441\u0442\u044C" }), _jsx("button", { onClick: () => selectTool(Rectangle), children: "\u041F\u0440\u044F\u043C\u043E\u0443\u0433\u043E\u043B\u044C\u043D\u0438\u043A" }), _jsx("button", { onClick: () => selectTool(Circle), children: "\u041A\u0440\u0443\u0433" }), _jsx("button", { onClick: () => selectTool(TextTool), children: "\u0422\u0435\u043A\u0441\u0442" }), _jsx("button", { onClick: () => selectTool(ImageTool), children: "\u0418\u0437\u043E\u0431\u0440\u0430\u0436\u0435\u043D\u0438\u0435" })] }));
22
23
  };
23
24
  export default Tools;
@@ -2,19 +2,22 @@ import Tool from "./Tool";
2
2
  export class TextTool extends Tool {
3
3
  constructor(canvas) {
4
4
  super(canvas);
5
+ this.fontSize = 24; // размер шрифта в пикселях
6
+ this.fontFamily = "Arial"; // шрифт по умолчанию
5
7
  this.listen();
6
8
  }
7
9
  listen() {
8
10
  const handler = (e) => {
9
- const evt = e; // приводим Event к MouseEvent
11
+ const evt = e;
10
12
  const canvas = evt.target;
11
13
  const x = evt.pageX - canvas.offsetLeft;
12
14
  const y = evt.pageY - canvas.offsetTop;
13
15
  const text = prompt("Введите текст");
14
16
  if (text) {
17
+ // Устанавливаем шрифт перед рисованием
18
+ this.ctx.font = `${this.fontSize}px ${this.fontFamily}`;
15
19
  this.ctx.fillText(text, x, y);
16
20
  }
17
- // удаляем обработчик после первого использования
18
21
  this.clearEvents();
19
22
  };
20
23
  this.addListener("mousedown", handler);
@@ -0,0 +1,43 @@
1
+ import Tool from "./Tool";
2
+ export class TextHoverTool extends Tool {
3
+ constructor(canvas, userName) {
4
+ super(canvas);
5
+ this.fontSize = 18;
6
+ this.fontFamily = "Arial";
7
+ this.color = "black";
8
+ this.userName = userName;
9
+ // Создаём overlay-канвас поверх основного
10
+ this.overlayCanvas = document.createElement("canvas");
11
+ this.overlayCanvas.width = canvas.width;
12
+ this.overlayCanvas.height = canvas.height;
13
+ this.overlayCanvas.style.position = "absolute";
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");
19
+ }
20
+ listen() {
21
+ const moveHandler = (evt) => {
22
+ const e = evt; // кастим к MouseEvent
23
+ // Очищаем overlay
24
+ this.overlayCtx.clearRect(0, 0, this.overlayCanvas.width, this.overlayCanvas.height);
25
+ // Координаты мыши относительно канваса
26
+ const x = e.pageX - this.canvas.offsetLeft;
27
+ const y = e.pageY - this.canvas.offsetTop;
28
+ // Рисуем имя чуть выше курсора
29
+ this.overlayCtx.font = `${this.fontSize}px ${this.fontFamily}`;
30
+ this.overlayCtx.fillStyle = this.color;
31
+ this.overlayCtx.fillText(this.userName, x, y - 20);
32
+ };
33
+ this.addListener("mousemove", moveHandler);
34
+ }
35
+ clearEvents() {
36
+ super.clearEvents();
37
+ // Удаляем overlay с DOM
38
+ if (this.overlayCanvas.parentElement) {
39
+ this.overlayCanvas.parentElement.removeChild(this.overlayCanvas);
40
+ }
41
+ }
42
+ }
43
+ export default TextHoverTool;
@@ -1,4 +1,6 @@
1
- declare const Border: (() => import("react/jsx-runtime").JSX.Element) & {
2
- displayName: string;
3
- };
1
+ import React from "react";
2
+ interface BorderProps {
3
+ userName?: string;
4
+ }
5
+ declare const Border: React.FC<BorderProps>;
4
6
  export default Border;
@@ -1,2 +1,6 @@
1
- declare const Tools: () => import("react/jsx-runtime").JSX.Element;
1
+ import React from "react";
2
+ interface ToolsProps {
3
+ userName?: string;
4
+ }
5
+ declare const Tools: React.FC<ToolsProps>;
2
6
  export default Tools;
@@ -1,6 +1,8 @@
1
1
  import Tool from "./Tool";
2
2
  export declare class TextTool extends Tool {
3
3
  constructor(canvas: HTMLCanvasElement);
4
+ fontSize: number;
5
+ fontFamily: string;
4
6
  listen(): void;
5
7
  onClickHandler(e: MouseEvent): void;
6
8
  }
@@ -0,0 +1,13 @@
1
+ import Tool from "./Tool";
2
+ export declare class TextHoverTool extends Tool {
3
+ userName: string;
4
+ fontSize: number;
5
+ fontFamily: string;
6
+ color: string;
7
+ private overlayCanvas;
8
+ private overlayCtx;
9
+ constructor(canvas: HTMLCanvasElement, userName: string);
10
+ listen(): void;
11
+ clearEvents(): void;
12
+ }
13
+ export default TextHoverTool;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "canvas-react-easy",
3
- "version": "1.0.9",
3
+ "version": "1.1.0",
4
4
  "main": "dist/index.js",
5
5
  "types": "dist/types/index.d.ts",
6
6
  "license": "MIT",
@@ -1,14 +1,31 @@
1
- import { observer } from "mobx-react-lite";
1
+ import React, { useEffect } 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
+
8
+ interface BorderProps {
9
+ userName?: string;
10
+ }
11
+
12
+ const Border: React.FC<BorderProps> = ({ userName = "Гость" }) => {
13
+ useEffect(() => {
14
+ // активируем инструмент "имя пользователя" сразу после монтирования
15
+ if (CanvasState.canvas) {
16
+ toolState.tool?.clearEvents();
17
+ const tool = new TextHoverTool(CanvasState.canvas, userName);
18
+ tool.listen();
19
+ toolState.setTool(tool);
20
+ }
21
+ }, [userName]);
4
22
 
5
- const Border = observer(() => {
6
23
  return (
7
- <div>
8
- <Tools />
24
+ <div style={{ position: "relative" }}>
25
+ <Tools userName={userName} />
9
26
  <Canvas />
10
27
  </div>
11
28
  );
12
- });
29
+ };
13
30
 
14
31
  export default Border;
@@ -7,8 +7,12 @@ import { Circle } from "../tools/Circle";
7
7
  import { TextTool } from "../tools/Text";
8
8
  import { ImageTool } from "../tools/ImageTool";
9
9
 
10
- const Tools = () => {
10
+ interface ToolsProps {
11
+ userName?: string;
12
+ }
11
13
 
14
+ const Tools: React.FC<ToolsProps> = ({ userName = "Гость" }) => {
15
+ // универсальный выбор инструмента
12
16
  const selectTool = (ToolClass: any) => {
13
17
  if (!CanvasState.canvas) return;
14
18
 
@@ -19,17 +23,15 @@ const Tools = () => {
19
23
  const tool = new ToolClass(CanvasState.canvas);
20
24
  tool.listen?.(); // если инструмент имеет метод listen
21
25
  toolState.setTool(tool);
22
- };
26
+ };
23
27
 
24
-
25
28
  return (
26
- <div style={{ marginBottom: "10px" }}>
29
+ <div style={{ marginBottom: "10px", display: "flex", gap: "5px" }}>
27
30
  <button onClick={() => selectTool(Brush)}>Кисть</button>
28
31
  <button onClick={() => selectTool(Rectangle)}>Прямоугольник</button>
29
32
  <button onClick={() => selectTool(Circle)}>Круг</button>
30
33
  <button onClick={() => selectTool(TextTool)}>Текст</button>
31
34
  <button onClick={() => selectTool(ImageTool)}>Изображение</button>
32
-
33
35
  </div>
34
36
  );
35
37
  };
package/src/tools/Text.ts CHANGED
@@ -5,25 +5,28 @@ export class TextTool extends Tool {
5
5
  super(canvas);
6
6
  this.listen();
7
7
  }
8
+ fontSize: number = 24; // размер шрифта в пикселях
9
+ fontFamily: string = "Arial"; // шрифт по умолчанию
8
10
 
9
11
  listen() {
10
- const handler = (e: Event) => {
11
- const evt = e as MouseEvent; // приводим Event к MouseEvent
12
- const canvas = evt.target as HTMLCanvasElement;
13
- const x = evt.pageX - canvas.offsetLeft;
14
- const y = evt.pageY - canvas.offsetTop;
15
-
16
- const text = prompt("Введите текст");
17
- if (text) {
18
- this.ctx.fillText(text, x, y);
19
- }
20
-
21
- // удаляем обработчик после первого использования
22
- this.clearEvents();
23
- };
24
-
25
- this.addListener("mousedown", handler);
26
- }
12
+ const handler = (e: Event) => {
13
+ const evt = e as MouseEvent;
14
+ const canvas = evt.target as HTMLCanvasElement;
15
+ const x = evt.pageX - canvas.offsetLeft;
16
+ const y = evt.pageY - canvas.offsetTop;
17
+
18
+ const text = prompt("Введите текст");
19
+ if (text) {
20
+ // Устанавливаем шрифт перед рисованием
21
+ this.ctx.font = `${this.fontSize}px ${this.fontFamily}`;
22
+ this.ctx.fillText(text, x, y);
23
+ }
24
+
25
+ this.clearEvents();
26
+ };
27
+
28
+ this.addListener("mousedown", handler);
29
+ }
27
30
 
28
31
  onClickHandler(e: MouseEvent) {
29
32
  const target = e.target as HTMLCanvasElement;
@@ -0,0 +1,58 @@
1
+ import Tool from "./Tool";
2
+
3
+ export class TextHoverTool extends Tool {
4
+ userName: string;
5
+ fontSize: number = 18;
6
+ fontFamily: string = "Arial";
7
+ color: string = "black";
8
+
9
+ private overlayCanvas!: HTMLCanvasElement;
10
+ private overlayCtx!: CanvasRenderingContext2D;
11
+
12
+ constructor(canvas: HTMLCanvasElement, userName: string) {
13
+ super(canvas);
14
+ this.userName = userName;
15
+
16
+ // Создаём overlay-канвас поверх основного
17
+ this.overlayCanvas = document.createElement("canvas");
18
+ this.overlayCanvas.width = canvas.width;
19
+ this.overlayCanvas.height = canvas.height;
20
+ this.overlayCanvas.style.position = "absolute";
21
+ this.overlayCanvas.style.left = canvas.offsetLeft + "px";
22
+ this.overlayCanvas.style.top = canvas.offsetTop + "px";
23
+ this.overlayCanvas.style.pointerEvents = "none"; // мышь проходит через него
24
+ canvas.parentElement!.appendChild(this.overlayCanvas);
25
+
26
+ this.overlayCtx = this.overlayCanvas.getContext("2d")!;
27
+ }
28
+
29
+ listen() {
30
+ const moveHandler = (evt: Event) => {
31
+ const e = evt as MouseEvent; // кастим к MouseEvent
32
+
33
+ // Очищаем overlay
34
+ this.overlayCtx.clearRect(0, 0, this.overlayCanvas.width, this.overlayCanvas.height);
35
+
36
+ // Координаты мыши относительно канваса
37
+ const x = e.pageX - this.canvas.offsetLeft;
38
+ const y = e.pageY - this.canvas.offsetTop;
39
+
40
+ // Рисуем имя чуть выше курсора
41
+ this.overlayCtx.font = `${this.fontSize}px ${this.fontFamily}`;
42
+ this.overlayCtx.fillStyle = this.color;
43
+ this.overlayCtx.fillText(this.userName, x, y - 20);
44
+ };
45
+
46
+ this.addListener("mousemove", moveHandler);
47
+ }
48
+
49
+ clearEvents() {
50
+ super.clearEvents();
51
+ // Удаляем overlay с DOM
52
+ if (this.overlayCanvas.parentElement) {
53
+ this.overlayCanvas.parentElement.removeChild(this.overlayCanvas);
54
+ }
55
+ }
56
+ }
57
+
58
+ export default TextHoverTool;