Peter Millauer 3 дні тому
джерело
коміт
b22971ef35

+ 1
- 0
.gitignore Переглянути файл

@@ -11,6 +11,7 @@ node_modules
11 11
 dist
12 12
 dist-ssr
13 13
 *.local
14
+circles-pictures
14 15
 
15 16
 # Editor directories and files
16 17
 .vscode/*

+ 3
- 1
src/client/model/rpc-callbacks.ts Переглянути файл

@@ -1,3 +1,5 @@
1 1
 import { Stroke } from "./canvas-state";
2 2
 
3
-export type ListenCallbackParam = { strokeId: number, stroke: Stroke }
3
+export type StrokeStreamElement = { strokeId: number, stroke: Stroke }
4
+
5
+export type OnStrokeCallback = (state: StrokeStreamElement) => void

+ 5
- 15
src/client/services/draw/draw.client-service.ts Переглянути файл

@@ -23,29 +23,25 @@ export class ClientDrawService {
23 23
         private readonly densityValue = document.getElementById('densityValue')!,
24 24
 
25 25
         private readonly widthSlider = document.getElementById('widthSlider')!,
26
-        private readonly widthValue = document.getElementById('widthValue')!, 
26
+        private readonly widthValue = document.getElementById('widthValue')!,
27 27
 
28 28
         private readonly menuButton = document.getElementById('menuButton')!,
29 29
         private readonly drawer = document.getElementById('drawer')!,
30 30
         private readonly closeButton = document.getElementById('closeButton')!,
31 31
     ) {
32
-        this.resizeCanvas()
33 32
         this.setupCanvasEvents()
34
-        window.addEventListener("resize", () => this.resizeCanvas());
35
-        this.cctx = canvas.getContext("2d")!
36 33
         this.currentColor = colorPicker!.getAttribute('value')!
37 34
         this.currentDensity = Number(densitySlider!.getAttribute('value'))!
38 35
         this.currentWidth = Number(widthSlider!.getAttribute('value'))!
36
+
37
+        this.cctx = canvas.getContext("2d")!
39 38
     }
40 39
 
41 40
     draw() {
42
-
43
-            console.log("drawing")
44 41
         const strokes: Stroke[] = this.stateService.getStrokes()
45 42
 
46 43
         this.cctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
47
-        
48
-        this.cctx.globalAlpha = 1;
44
+
49 45
         strokes.forEach(stroke => {
50 46
             this.cctx.fillStyle = stroke.color;
51 47
             this.drawCurve(stroke.points, stroke.density, stroke.width)
@@ -122,7 +118,7 @@ export class ClientDrawService {
122 118
         });
123 119
 
124 120
         document.addEventListener('click', (e) => {
125
-            if(!e.target){
121
+            if (!e.target) {
126 122
                 return
127 123
             }
128 124
             if (!this.drawer.contains(e.target as Node) && !this.menuButton.contains(e.target as Node)) {
@@ -132,12 +128,6 @@ export class ClientDrawService {
132 128
 
133 129
     }
134 130
 
135
-    private resizeCanvas() {
136
-        const size = Math.min(window.innerWidth, window.innerHeight) * 0.9;
137
-        this.canvas.width = size;
138
-        this.canvas.height = size;
139
-    }
140
-
141 131
     private drawCurve(points: Point[], density: number, width: number) {
142 132
         if (points.length < 2) return;
143 133
 

+ 5
- 5
src/client/services/state/state.client-service.ts Переглянути файл

@@ -1,6 +1,6 @@
1 1
 import { RPCSocket } from "../../../../node_modules/rpclibrary/js/Index";
2 2
 import { CanvasState, Point, Stroke } from "../../model/canvas-state";
3
-import { ListenCallbackParam } from "../../model/rpc-callbacks";
3
+import { StrokeStreamElement } from "../../model/rpc-callbacks";
4 4
 import { ClientDrawService } from "../draw/draw.client-service";
5 5
 
6 6
 
@@ -14,11 +14,11 @@ export class ClientStateService {
14 14
         const sock = await new RPCSocket(8080, 'localhost').connect();
15 15
         this.remoteService = sock['StateService']
16 16
         this.canvasState = await this.getState()
17
-        await this.remoteService.listen((listenDto: ListenCallbackParam) => {
18
-            if(!this.canvasState.strokes[listenDto.strokeId]){
19
-                this.canvasState.strokes[listenDto.strokeId] = listenDto.stroke
17
+        await this.remoteService.onStroke((s: StrokeStreamElement) => {
18
+            if(!this.canvasState.strokes[s.strokeId]){
19
+                this.canvasState.strokes[s.strokeId] = s.stroke
20 20
             }else{
21
-                this.canvasState.strokes[listenDto.strokeId].points = [...this.canvasState.strokes[listenDto.strokeId].points, ...listenDto.stroke.points]
21
+                this.canvasState.strokes[s.strokeId].points = [...this.canvasState.strokes[s.strokeId].points, ...s.stroke.points]
22 22
             }
23 23
             drawService.draw()
24 24
         })

+ 11
- 1
src/server/services/express/express.service.ts Переглянути файл

@@ -13,6 +13,8 @@ export class ExpressService implements Initializable {
13 13
     @Inject(StateService)
14 14
     private stateService: StateService;
15 15
 
16
+    private connectionCount = 0;
17
+
16 18
     initialize() {
17 19
         const app = express();
18 20
         const PORT = 8080;
@@ -28,7 +30,15 @@ export class ExpressService implements Initializable {
28 30
         const rpcServer = new RPCServer([
29 31
             this.stateService,
30 32
 
31
-        ])
33
+        ], {
34
+            closeHandler: (socket) => {
35
+                this.connectionCount -= 1
36
+                if(this.connectionCount === 0){
37
+                    this.stateService.finalizePicture()
38
+                }
39
+            },
40
+            connectionHandler: (socket) => { this.connectionCount += 1 },
41
+        })
32 42
         rpcServer.attach(httpServer)
33 43
         rpcServer.listen(PORT)
34 44
 

+ 28
- 12
src/server/services/state/state.service.ts Переглянути файл

@@ -1,43 +1,59 @@
1 1
 import { Singleton, Initializable } from "depents";
2 2
 import { RPCExporter } from "rpclibrary";
3 3
 import { CanvasState, Point, Stroke } from "../../../client/model/canvas-state";
4
-import { ListenCallbackParam } from "../../../client/model/rpc-callbacks";
4
+import { OnStrokeCallback } from "../../../client/model/rpc-callbacks";
5
+import * as fs from "fs";
6
+import * as path from "path";
5 7
 
6 8
 @Singleton()
7 9
 export class StateService implements Initializable, RPCExporter {
8 10
     name = 'StateService' as const
9 11
 
10 12
     private canvasState: CanvasState = { strokes: [] }
11
-    private clients: Array<(param: ListenCallbackParam) => void> = []
13
+    private onStrokeCallbacks: Array<OnStrokeCallback> = []
12 14
 
13 15
     initialize() {
14 16
         this.canvasState = { strokes: [] }
15
-        this.clients = []
17
+        this.onStrokeCallbacks = []
16 18
     };
17 19
 
18 20
     beginStroke = async (stroke: Stroke) => {
19 21
         const strokeId = this.canvasState.strokes.length
20 22
         this.canvasState.strokes.push(stroke)
21
-        this.updateclients(strokeId, stroke)
23
+        this.updateStrokeListeners(strokeId, stroke)
22 24
         return strokeId
23 25
     }
24 26
 
25 27
     addPoint = async (strokeId: number, point: Point) => {
26 28
         this.canvasState.strokes[strokeId].points.push(point)
27
-        this.updateclients(strokeId, { ...this.canvasState.strokes[strokeId], points: [point] })
29
+        this.updateStrokeListeners(strokeId, { ...this.canvasState.strokes[strokeId], points: [point] })
28 30
     }
29 31
 
30
-    listen = async (callback: (state: any) => Promise<void>) => {
31
-        this.clients = [...this.clients, callback]
32
-        return this.canvasState
32
+    onStroke = async (callback: OnStrokeCallback) => {
33
+        this.onStrokeCallbacks = [...this.onStrokeCallbacks, callback]
34
+        return
33 35
     }
34 36
 
35 37
     getState = async (): Promise<CanvasState> => {
36 38
         return this.canvasState
37 39
     }
38 40
 
39
-    private updateclients = (strokeId: number, stroke: Stroke) => {
40
-        this.clients.forEach((client) => {
41
+    finalizePicture = () => {
42
+        const finalState = { ...this.canvasState }
43
+        this.canvasState = { strokes: [] }
44
+
45
+        const picturedir = path.join(__dirname, `../../../../circles-pictures/`);
46
+
47
+        if (!fs.existsSync(picturedir)) {
48
+            fs.mkdirSync(picturedir);
49
+        }
50
+
51
+        fs.writeFileSync(path.join(picturedir, `${Date.now()}.json`), JSON.stringify(finalState))
52
+        console.log(finalState)
53
+    }
54
+
55
+    private updateStrokeListeners = (strokeId: number, stroke: Stroke) => {
56
+        this.onStrokeCallbacks.forEach((client) => {
41 57
             client({ strokeId, stroke })
42 58
         })
43 59
     }
@@ -47,8 +63,8 @@ export class StateService implements Initializable, RPCExporter {
47 63
         this.addPoint,
48 64
         this.getState,
49 65
         {
50
-            name: 'listen' as const,
51
-            hook: (cb: any) => { this.listen(cb) }
66
+            name: 'onStroke' as const,
67
+            hook: this.onStroke,
52 68
         }
53 69
     ]
54 70
 

Завантаження…
Відмінити
Зберегти