From f28200656b6756132dd490faa54d61b5f6866266 Mon Sep 17 00:00:00 2001 From: Stanislaw Malinowski Date: Thu, 25 Jul 2024 12:10:33 +0100 Subject: [PATCH] with colors --- plotting-preview/package-lock.json | 89 ++++++++++++++- plotting-preview/package.json | 2 + .../src/components/ColorsChart.tsx | 105 ++++++++++++++++++ plotting-preview/src/components/Konva.tsx | 37 ++++++ src/plotting_server/start.py | 48 ++++++++ 5 files changed, 278 insertions(+), 3 deletions(-) create mode 100644 plotting-preview/src/components/ColorsChart.tsx create mode 100644 plotting-preview/src/components/Konva.tsx diff --git a/plotting-preview/package-lock.json b/plotting-preview/package-lock.json index ec724a8..b6cfacd 100644 --- a/plotting-preview/package-lock.json +++ b/plotting-preview/package-lock.json @@ -8,8 +8,10 @@ "name": "plotting-preview", "version": "0.0.0", "dependencies": { + "konva": "^9.3.14", "react": "^18.3.1", "react-dom": "^18.3.1", + "react-konva": "^18.2.10", "recharts": "^2.12.7" }, "devDependencies": { @@ -1312,14 +1314,12 @@ "node_modules/@types/prop-types": { "version": "15.7.12", "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.12.tgz", - "integrity": "sha512-5zvhXYtRNRluoE/jAp4GVsSduVUzNWKkOZrCDBWYtE7biZywwdC2AcEzg+cSMLFRfVgeAFqpfNabiPjxFddV1Q==", - "dev": true + "integrity": "sha512-5zvhXYtRNRluoE/jAp4GVsSduVUzNWKkOZrCDBWYtE7biZywwdC2AcEzg+cSMLFRfVgeAFqpfNabiPjxFddV1Q==" }, "node_modules/@types/react": { "version": "18.3.3", "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.3.tgz", "integrity": "sha512-hti/R0pS0q1/xx+TsI73XIqk26eBsISZ2R0wUijXIngRK9R/e7Xw/cXVxQK7R5JjW+SV4zGcn5hXjudkN/pLIw==", - "dev": true, "dependencies": { "@types/prop-types": "*", "csstype": "^3.0.2" @@ -1334,6 +1334,14 @@ "@types/react": "*" } }, + "node_modules/@types/react-reconciler": { + "version": "0.28.8", + "resolved": "https://registry.npmjs.org/@types/react-reconciler/-/react-reconciler-0.28.8.tgz", + "integrity": "sha512-SN9c4kxXZonFhbX4hJrZy37yw9e7EIxcpHCxQv5JUS18wDE5ovkQKlqQEkufdJCCMfuI9BnjUJvhYeJ9x5Ra7g==", + "dependencies": { + "@types/react": "*" + } + }, "node_modules/@typescript-eslint/eslint-plugin": { "version": "7.17.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.17.0.tgz", @@ -2648,6 +2656,17 @@ "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", "dev": true }, + "node_modules/its-fine": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/its-fine/-/its-fine-1.2.5.tgz", + "integrity": "sha512-fXtDA0X0t0eBYAGLVM5YsgJGsJ5jEmqZEPrGbzdf5awjv0xE7nqv3TVnvtUF060Tkes15DbDAKW/I48vsb6SyA==", + "dependencies": { + "@types/react-reconciler": "^0.28.0" + }, + "peerDependencies": { + "react": ">=18.0" + } + }, "node_modules/js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", @@ -2716,6 +2735,25 @@ "json-buffer": "3.0.1" } }, + "node_modules/konva": { + "version": "9.3.14", + "resolved": "https://registry.npmjs.org/konva/-/konva-9.3.14.tgz", + "integrity": "sha512-Gmm5lyikGYJyogKQA7Fy6dKkfNh350V6DwfZkid0RVrGYP2cfCsxuMxgF5etKeCv7NjXYpJxKqi1dYkIkX/dcA==", + "funding": [ + { + "type": "patreon", + "url": "https://www.patreon.com/lavrton" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/konva" + }, + { + "type": "github", + "url": "https://github.com/sponsors/lavrton" + } + ] + }, "node_modules/levn": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", @@ -3082,6 +3120,51 @@ "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" }, + "node_modules/react-konva": { + "version": "18.2.10", + "resolved": "https://registry.npmjs.org/react-konva/-/react-konva-18.2.10.tgz", + "integrity": "sha512-ohcX1BJINL43m4ynjZ24MxFI1syjBdrXhqVxYVDw2rKgr3yuS0x/6m1Y2Z4sl4T/gKhfreBx8KHisd0XC6OT1g==", + "funding": [ + { + "type": "patreon", + "url": "https://www.patreon.com/lavrton" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/konva" + }, + { + "type": "github", + "url": "https://github.com/sponsors/lavrton" + } + ], + "dependencies": { + "@types/react-reconciler": "^0.28.2", + "its-fine": "^1.1.1", + "react-reconciler": "~0.29.0", + "scheduler": "^0.23.0" + }, + "peerDependencies": { + "konva": "^8.0.1 || ^7.2.5 || ^9.0.0", + "react": ">=18.0.0", + "react-dom": ">=18.0.0" + } + }, + "node_modules/react-reconciler": { + "version": "0.29.2", + "resolved": "https://registry.npmjs.org/react-reconciler/-/react-reconciler-0.29.2.tgz", + "integrity": "sha512-zZQqIiYgDCTP/f1N/mAR10nJGrPD2ZR+jDSEsKWJHYC7Cm2wodlwbR3upZRdC3cjIjSlTLNVyO7Iu0Yy7t2AYg==", + "dependencies": { + "loose-envify": "^1.1.0", + "scheduler": "^0.23.2" + }, + "engines": { + "node": ">=0.10.0" + }, + "peerDependencies": { + "react": "^18.3.1" + } + }, "node_modules/react-refresh": { "version": "0.14.2", "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.14.2.tgz", diff --git a/plotting-preview/package.json b/plotting-preview/package.json index e849615..82e338e 100644 --- a/plotting-preview/package.json +++ b/plotting-preview/package.json @@ -10,8 +10,10 @@ "preview": "vite preview" }, "dependencies": { + "konva": "^9.3.14", "react": "^18.3.1", "react-dom": "^18.3.1", + "react-konva": "^18.2.10", "recharts": "^2.12.7" }, "devDependencies": { diff --git a/plotting-preview/src/components/ColorsChart.tsx b/plotting-preview/src/components/ColorsChart.tsx new file mode 100644 index 0000000..3a27b27 --- /dev/null +++ b/plotting-preview/src/components/ColorsChart.tsx @@ -0,0 +1,105 @@ +import { useEffect, useRef, useState } from 'react'; +import { Layer, Rect, Stage } from 'react-konva'; + +type Colors = 'r' | 'g' | 'b' | 't'; + +type ColorEvent = { + c: Colors, + i: number +} + +const intensityClosure = (name: Colors) => { + let getHex = (intensity: number) => "#000000"; + switch (name) { + case 'r': + getHex = (intensity: number) => `#${intensity.toString(16).padStart(2, '0')}0000`; + break; + case 'g': + getHex = (intensity: number) => `#00${intensity.toString(16).padStart(2, '0')}00`; + break; + case 'b': + getHex = (intensity: number) => `#0000${intensity.toString(16).padStart(2, '0')}`; + break; + case 't': + getHex = (intensity: number) => { + const hexIntensity = intensity.toString(16).padStart(2, '0'); + return `#${hexIntensity}${hexIntensity}${hexIntensity}`; + } + break; + default: + getHex = (intensity: number) => "#000000"; + break; + } + return getHex; +}; + + +interface OneColorCanvasProps { + name: Colors, +} + +export function OneColorCanvas({ name }: OneColorCanvasProps) { + const [data, setData] = useState([]); + const ws = useRef(null); + + useEffect(() => { + // Establish WebSocket connection + ws.current = new WebSocket('/ws/colors'); + console.log(ws.current); + ws.current.onmessage = (event) => { + const parsedData: ColorEvent = JSON.parse(event.data); + if (parsedData.c == name) { + setData(prevData => { + const newData = [...prevData, parsedData.i]; + return newData + }); + } + }; + + // Cleanup WebSocket connection on component unmount + return () => { + if (ws.current) { + ws.current.close(); + } + }; + }, []); + const getHex = intensityClosure(name); + + return ( +
+
On color {name} stuffs
+ + + {data.map((intensity, index) => { + const color = getHex(intensity); + + })} + + +
+ ) +} + + + +function ColorsChart() { + return ( +
+

Colors Data

+ + + + +
+ ); +} + +export default ColorsChart; diff --git a/plotting-preview/src/components/Konva.tsx b/plotting-preview/src/components/Konva.tsx new file mode 100644 index 0000000..9da5f99 --- /dev/null +++ b/plotting-preview/src/components/Konva.tsx @@ -0,0 +1,37 @@ +import React, { useState } from 'react'; +import { render } from 'react-dom'; +import { Stage, Layer, Rect, Text } from 'react-konva'; +import Konva from 'konva'; + +const ColoredRect = () => { + const [color, setColor] = useState('green'); + + const handleClick = () => { + setColor(Konva.Util.getRandomColor()); + }; + + return ( + + ); +}; + +const App = () => { + return ( + + + + + + + ); +}; + +render(, document.getElementById('root')); \ No newline at end of file diff --git a/src/plotting_server/start.py b/src/plotting_server/start.py index ff1fa45..21ac312 100644 --- a/src/plotting_server/start.py +++ b/src/plotting_server/start.py @@ -1,4 +1,5 @@ import random +import numpy as np import time from fastapi import FastAPI, Response, WebSocket from fastapi.middleware.cors import CORSMiddleware @@ -53,3 +54,50 @@ async def websocket_endpoint(websocket: WebSocket): print(f"Error: {e}") finally: await websocket.close() + + + +# Generate 10,000 random integers between 0 and 255 +def generate_rgb_array(size=10000): + return np.random.randint(0, 256, size=size, dtype=np.uint8) + +# Initialize RGB arrays +r_array = generate_rgb_array() +g_array = generate_rgb_array() +b_array = generate_rgb_array() + +@app.websocket("/ws/colors") +async def colors_websocket_endpoint(websocket: WebSocket): + await websocket.accept() + try: + while True: + # Simulate data generation + now = time.time() + # Compute total of RGB values + r_total = np.sum(r_array) + g_total = np.sum(g_array) + b_total = np.sum(b_array) + total = r_total + g_total + b_total + + # Generate intensity value as a random 8-bit integer + intensity = random.randint(0, 255) + + # Create JSON data format + # todo decide if 1 message parsed on the frontend or 3 different messages + data = { + "c": { + "r": r_total, + "g": g_total, + "b": b_total, + "total": total + }, + "i": intensity + } + + # Send JSON data + await websocket.send_json(data) + await asyncio.sleep(0.1) # Emit every 100 ms (10 Hz) + except Exception as e: + print(f"Error: {e}") + finally: + await websocket.close()