diff --git a/package-lock.json b/package-lock.json index 8837735..61712d5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,6 +12,7 @@ "@types/lodash": "^4.17.16", "@vueuse/core": "^13.5.0", "async-mutex": "^0.5.0", + "echarts": "^5.6.0", "highlight.js": "^11.11.1", "konva": "^9.3.20", "lodash": "^4.17.21", @@ -24,6 +25,7 @@ "ts-log": "^2.2.7", "ts-results-es": "^5.0.1", "vue": "^3.5.13", + "vue-echarts": "^7.0.3", "vue-konva": "^3.2.1", "vue-router": "4", "yocto-queue": "^1.2.1", @@ -2618,6 +2620,22 @@ "node": ">=8" } }, + "node_modules/echarts": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/echarts/-/echarts-5.6.0.tgz", + "integrity": "sha512-oTbVTsXfKuEhxftHqL5xprgLoc0k7uScAwtryCgWF6hPYFLRwOUHiFmHGCBKP5NPFNkDVopOieyUqYGH8Fa3kA==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "2.3.0", + "zrender": "5.6.1" + } + }, + "node_modules/echarts/node_modules/tslib": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.0.tgz", + "integrity": "sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg==", + "license": "0BSD" + }, "node_modules/electron-to-chromium": { "version": "1.5.140", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.140.tgz", @@ -4660,6 +4678,51 @@ } } }, + "node_modules/vue-demi": { + "version": "0.13.11", + "resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.13.11.tgz", + "integrity": "sha512-IR8HoEEGM65YY3ZJYAjMlKygDQn25D5ajNFNoKh9RSDMQtlzCxtfQjdQgv9jjK+m3377SsJXY8ysq8kLCZL25A==", + "hasInstallScript": true, + "license": "MIT", + "bin": { + "vue-demi-fix": "bin/vue-demi-fix.js", + "vue-demi-switch": "bin/vue-demi-switch.js" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + }, + "peerDependencies": { + "@vue/composition-api": "^1.0.0-rc.1", + "vue": "^3.0.0-0 || ^2.6.0" + }, + "peerDependenciesMeta": { + "@vue/composition-api": { + "optional": true + } + } + }, + "node_modules/vue-echarts": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/vue-echarts/-/vue-echarts-7.0.3.tgz", + "integrity": "sha512-/jSxNwOsw5+dYAUcwSfkLwKPuzTQ0Cepz1LxCOpj2QcHrrmUa/Ql0eQqMmc1rTPQVrh2JQ29n2dhq75ZcHvRDw==", + "license": "MIT", + "dependencies": { + "vue-demi": "^0.13.11" + }, + "peerDependencies": { + "@vue/runtime-core": "^3.0.0", + "echarts": "^5.5.1", + "vue": "^2.7.0 || ^3.1.1" + }, + "peerDependenciesMeta": { + "@vue/runtime-core": { + "optional": true + } + } + }, "node_modules/vue-konva": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/vue-konva/-/vue-konva-3.2.1.tgz", @@ -4788,6 +4851,21 @@ "funding": { "url": "https://github.com/sponsors/colinhacks" } + }, + "node_modules/zrender": { + "version": "5.6.1", + "resolved": "https://registry.npmjs.org/zrender/-/zrender-5.6.1.tgz", + "integrity": "sha512-OFXkDJKcrlx5su2XbzJvj/34Q3m6PvyCZkVPHGYpcCJ52ek4U/ymZyfuV1nKE23AyBJ51E/6Yr0mhZ7xGTO4ag==", + "license": "BSD-3-Clause", + "dependencies": { + "tslib": "2.3.0" + } + }, + "node_modules/zrender/node_modules/tslib": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.0.tgz", + "integrity": "sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg==", + "license": "0BSD" } } } diff --git a/package.json b/package.json index 25ddf1a..c989293 100644 --- a/package.json +++ b/package.json @@ -18,6 +18,7 @@ "@types/lodash": "^4.17.16", "@vueuse/core": "^13.5.0", "async-mutex": "^0.5.0", + "echarts": "^5.6.0", "highlight.js": "^11.11.1", "konva": "^9.3.20", "lodash": "^4.17.21", @@ -30,6 +31,7 @@ "ts-log": "^2.2.7", "ts-results-es": "^5.0.1", "vue": "^3.5.13", + "vue-echarts": "^7.0.3", "vue-konva": "^3.2.1", "vue-router": "4", "yocto-queue": "^1.2.1", diff --git a/src/components/Alert/Alert.vue b/src/components/Alert/Alert.vue new file mode 100644 index 0000000..e69de29 diff --git a/src/components/Alert/index.ts b/src/components/Alert/index.ts new file mode 100644 index 0000000..e69de29 diff --git a/src/components/Oscilloscope/WaveformDisplay.vue b/src/components/Oscilloscope/WaveformDisplay.vue new file mode 100644 index 0000000..4841334 --- /dev/null +++ b/src/components/Oscilloscope/WaveformDisplay.vue @@ -0,0 +1,172 @@ + + + diff --git a/src/components/Oscilloscope/index.ts b/src/components/Oscilloscope/index.ts new file mode 100644 index 0000000..a06dd05 --- /dev/null +++ b/src/components/Oscilloscope/index.ts @@ -0,0 +1,26 @@ +import WaveformDisplay from "./WaveformDisplay.vue"; + +// Test data generator +const generateTestData = () => { + const sampleRate = 1000; // 1kHz + const duration = 0.1; // 10ms + const points = Math.floor(sampleRate * duration); + + const x = Array.from({ length: points }, (_, i) => i / sampleRate * 1000); // time in ms + + // Generate multiple channels with different waveforms + const y = [ + // Channel 1: Sine wave 50Hz + Array.from({ length: points }, (_, i) => Math.sin(2 * Math.PI * 50 * i / sampleRate) * 3.3), + // Channel 2: Square wave 25Hz + Array.from({ length: points }, (_, i) => Math.sign(Math.sin(2 * Math.PI * 25 * i / sampleRate)) * 5), + // Channel 3: Sawtooth wave 33Hz + Array.from({ length: points }, (_, i) => (2 * ((33 * i / sampleRate) % 1) - 1) * 2.5), + // Channel 4: Noise + DC offset + Array.from({ length: points }, () => Math.random() * 0.5 + 1.5) + ]; + + return { x, y }; +}; + +export { WaveformDisplay, generateTestData }; diff --git a/src/router/index.ts b/src/router/index.ts index c36ca1b..f9761e5 100644 --- a/src/router/index.ts +++ b/src/router/index.ts @@ -1,23 +1,27 @@ -import { createRouter, createWebHistory } from 'vue-router' -import HomeView from '../views/HomeView.vue' -import LoginView from '../views/LoginView.vue' -import LabView from '../views/LabView.vue' -import ProjectView from '../views/ProjectView.vue' -import TestView from '../views/TestView.vue' -import UserView from '../views/UserView.vue' -import AdminView from '../views/AdminView.vue' -import VideoStreamView from '../views/VideoStreamView.vue' +import { createRouter, createWebHistory } from "vue-router"; +import HomeView from "../views/HomeView.vue"; +import LoginView from "../views/LoginView.vue"; +import LabView from "../views/LabView.vue"; +import ProjectView from "../views/ProjectView.vue"; +import TestView from "../views/TestView.vue"; +import UserView from "../views/UserView.vue"; +import AdminView from "../views/AdminView.vue"; +import VideoStreamView from "../views/VideoStreamView.vue"; +import OscilloscopeView from "@/views/OscilloscopeView.vue"; const router = createRouter({ history: createWebHistory(import.meta.env.BASE_URL), routes: [ - {path: '/', name: 'home', component: HomeView}, - {path: '/login', name: 'login', component: LoginView}, - {path: '/lab/:id',name: 'lab', component: LabView}, - {path: '/project',name: 'project',component: ProjectView}, - {path: '/test', name: 'test', component: TestView}, - {path: '/user', name: 'user', component: UserView}, - {path: '/admin', name: 'admin', component: AdminView}, {path: '/video-stream',name: 'video-stream',component: VideoStreamView}] -}) + { path: "/", name: "home", component: HomeView }, + { path: "/login", name: "login", component: LoginView }, + { path: "/lab/:id", name: "lab", component: LabView }, + { path: "/project", name: "project", component: ProjectView }, + { path: "/test", name: "test", component: TestView }, + { path: "/user", name: "user", component: UserView }, + { path: "/admin", name: "admin", component: AdminView }, + { path: "/video-stream", name: "videoStream", component: VideoStreamView }, + { path: "/oscilloscope", name: "oscilloscope", component: OscilloscopeView }, + ], +}); -export default router +export default router; diff --git a/src/views/OscilloscopeView.vue b/src/views/OscilloscopeView.vue new file mode 100644 index 0000000..a3c6857 --- /dev/null +++ b/src/views/OscilloscopeView.vue @@ -0,0 +1,224 @@ + + +