init
This commit is contained in:
commit
db749b97e3
24
.gitignore
vendored
Normal file
24
.gitignore
vendored
Normal file
@ -0,0 +1,24 @@
|
||||
# Logs
|
||||
logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
pnpm-debug.log*
|
||||
lerna-debug.log*
|
||||
|
||||
node_modules
|
||||
dist
|
||||
dist-ssr
|
||||
*.local
|
||||
|
||||
# Editor directories and files
|
||||
.vscode/*
|
||||
!.vscode/extensions.json
|
||||
.idea
|
||||
.DS_Store
|
||||
*.suo
|
||||
*.ntvs*
|
||||
*.njsproj
|
||||
*.sln
|
||||
*.sw?
|
||||
3
.vscode/extensions.json
vendored
Normal file
3
.vscode/extensions.json
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
{
|
||||
"recommendations": ["Vue.volar"]
|
||||
}
|
||||
5
README.md
Normal file
5
README.md
Normal file
@ -0,0 +1,5 @@
|
||||
# Vue 3 + TypeScript + Vite
|
||||
|
||||
This template should help get you started developing with Vue 3 and TypeScript in Vite. The template uses Vue 3 `<script setup>` SFCs, check out the [script setup docs](https://v3.vuejs.org/api/sfc-script-setup.html#sfc-script-setup) to learn more.
|
||||
|
||||
Learn more about the recommended Project Setup and IDE Support in the [Vue Docs TypeScript Guide](https://vuejs.org/guide/typescript/overview.html#project-setup).
|
||||
232
bun.lock
Normal file
232
bun.lock
Normal file
@ -0,0 +1,232 @@
|
||||
{
|
||||
"lockfileVersion": 1,
|
||||
"workspaces": {
|
||||
"": {
|
||||
"name": "mag-rl-optimization",
|
||||
"dependencies": {
|
||||
"@types/three": "^0.179.0",
|
||||
"echarts": "^6.0.0",
|
||||
"three": "^0.179.1",
|
||||
"vue": "^3.5.18",
|
||||
},
|
||||
"devDependencies": {
|
||||
"@vitejs/plugin-vue": "^6.0.1",
|
||||
"@vue/tsconfig": "^0.7.0",
|
||||
"typescript": "~5.8.3",
|
||||
"vite": "^7.1.2",
|
||||
"vue-tsc": "^3.0.5",
|
||||
},
|
||||
},
|
||||
},
|
||||
"packages": {
|
||||
"@babel/helper-string-parser": ["@babel/helper-string-parser@7.27.1", "", {}, "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA=="],
|
||||
|
||||
"@babel/helper-validator-identifier": ["@babel/helper-validator-identifier@7.27.1", "", {}, "sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow=="],
|
||||
|
||||
"@babel/parser": ["@babel/parser@7.28.0", "", { "dependencies": { "@babel/types": "^7.28.0" }, "bin": "./bin/babel-parser.js" }, "sha512-jVZGvOxOuNSsuQuLRTh13nU0AogFlw32w/MT+LV6D3sP5WdbW61E77RnkbaO2dUvmPAYrBDJXGn5gGS6tH4j8g=="],
|
||||
|
||||
"@babel/types": ["@babel/types@7.28.2", "", { "dependencies": { "@babel/helper-string-parser": "^7.27.1", "@babel/helper-validator-identifier": "^7.27.1" } }, "sha512-ruv7Ae4J5dUYULmeXw1gmb7rYRz57OWCPM57pHojnLq/3Z1CK2lNSLTCVjxVk1F/TZHwOZZrOWi0ur95BbLxNQ=="],
|
||||
|
||||
"@dimforge/rapier3d-compat": ["@dimforge/rapier3d-compat@0.12.0", "", {}, "sha512-uekIGetywIgopfD97oDL5PfeezkFpNhwlzlaEYNOA0N6ghdsOvh/HYjSMek5Q2O1PYvRSDFcqFVJl4r4ZBwOow=="],
|
||||
|
||||
"@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.25.8", "", { "os": "aix", "cpu": "ppc64" }, "sha512-urAvrUedIqEiFR3FYSLTWQgLu5tb+m0qZw0NBEasUeo6wuqatkMDaRT+1uABiGXEu5vqgPd7FGE1BhsAIy9QVA=="],
|
||||
|
||||
"@esbuild/android-arm": ["@esbuild/android-arm@0.25.8", "", { "os": "android", "cpu": "arm" }, "sha512-RONsAvGCz5oWyePVnLdZY/HHwA++nxYWIX1atInlaW6SEkwq6XkP3+cb825EUcRs5Vss/lGh/2YxAb5xqc07Uw=="],
|
||||
|
||||
"@esbuild/android-arm64": ["@esbuild/android-arm64@0.25.8", "", { "os": "android", "cpu": "arm64" }, "sha512-OD3p7LYzWpLhZEyATcTSJ67qB5D+20vbtr6vHlHWSQYhKtzUYrETuWThmzFpZtFsBIxRvhO07+UgVA9m0i/O1w=="],
|
||||
|
||||
"@esbuild/android-x64": ["@esbuild/android-x64@0.25.8", "", { "os": "android", "cpu": "x64" }, "sha512-yJAVPklM5+4+9dTeKwHOaA+LQkmrKFX96BM0A/2zQrbS6ENCmxc4OVoBs5dPkCCak2roAD+jKCdnmOqKszPkjA=="],
|
||||
|
||||
"@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.25.8", "", { "os": "darwin", "cpu": "arm64" }, "sha512-Jw0mxgIaYX6R8ODrdkLLPwBqHTtYHJSmzzd+QeytSugzQ0Vg4c5rDky5VgkoowbZQahCbsv1rT1KW72MPIkevw=="],
|
||||
|
||||
"@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.25.8", "", { "os": "darwin", "cpu": "x64" }, "sha512-Vh2gLxxHnuoQ+GjPNvDSDRpoBCUzY4Pu0kBqMBDlK4fuWbKgGtmDIeEC081xi26PPjn+1tct+Bh8FjyLlw1Zlg=="],
|
||||
|
||||
"@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.25.8", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-YPJ7hDQ9DnNe5vxOm6jaie9QsTwcKedPvizTVlqWG9GBSq+BuyWEDazlGaDTC5NGU4QJd666V0yqCBL2oWKPfA=="],
|
||||
|
||||
"@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.25.8", "", { "os": "freebsd", "cpu": "x64" }, "sha512-MmaEXxQRdXNFsRN/KcIimLnSJrk2r5H8v+WVafRWz5xdSVmWLoITZQXcgehI2ZE6gioE6HirAEToM/RvFBeuhw=="],
|
||||
|
||||
"@esbuild/linux-arm": ["@esbuild/linux-arm@0.25.8", "", { "os": "linux", "cpu": "arm" }, "sha512-FuzEP9BixzZohl1kLf76KEVOsxtIBFwCaLupVuk4eFVnOZfU+Wsn+x5Ryam7nILV2pkq2TqQM9EZPsOBuMC+kg=="],
|
||||
|
||||
"@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.25.8", "", { "os": "linux", "cpu": "arm64" }, "sha512-WIgg00ARWv/uYLU7lsuDK00d/hHSfES5BzdWAdAig1ioV5kaFNrtK8EqGcUBJhYqotlUByUKz5Qo6u8tt7iD/w=="],
|
||||
|
||||
"@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.25.8", "", { "os": "linux", "cpu": "ia32" }, "sha512-A1D9YzRX1i+1AJZuFFUMP1E9fMaYY+GnSQil9Tlw05utlE86EKTUA7RjwHDkEitmLYiFsRd9HwKBPEftNdBfjg=="],
|
||||
|
||||
"@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.25.8", "", { "os": "linux", "cpu": "none" }, "sha512-O7k1J/dwHkY1RMVvglFHl1HzutGEFFZ3kNiDMSOyUrB7WcoHGf96Sh+64nTRT26l3GMbCW01Ekh/ThKM5iI7hQ=="],
|
||||
|
||||
"@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.25.8", "", { "os": "linux", "cpu": "none" }, "sha512-uv+dqfRazte3BzfMp8PAQXmdGHQt2oC/y2ovwpTteqrMx2lwaksiFZ/bdkXJC19ttTvNXBuWH53zy/aTj1FgGw=="],
|
||||
|
||||
"@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.25.8", "", { "os": "linux", "cpu": "ppc64" }, "sha512-GyG0KcMi1GBavP5JgAkkstMGyMholMDybAf8wF5A70CALlDM2p/f7YFE7H92eDeH/VBtFJA5MT4nRPDGg4JuzQ=="],
|
||||
|
||||
"@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.25.8", "", { "os": "linux", "cpu": "none" }, "sha512-rAqDYFv3yzMrq7GIcen3XP7TUEG/4LK86LUPMIz6RT8A6pRIDn0sDcvjudVZBiiTcZCY9y2SgYX2lgK3AF+1eg=="],
|
||||
|
||||
"@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.25.8", "", { "os": "linux", "cpu": "s390x" }, "sha512-Xutvh6VjlbcHpsIIbwY8GVRbwoviWT19tFhgdA7DlenLGC/mbc3lBoVb7jxj9Z+eyGqvcnSyIltYUrkKzWqSvg=="],
|
||||
|
||||
"@esbuild/linux-x64": ["@esbuild/linux-x64@0.25.8", "", { "os": "linux", "cpu": "x64" }, "sha512-ASFQhgY4ElXh3nDcOMTkQero4b1lgubskNlhIfJrsH5OKZXDpUAKBlNS0Kx81jwOBp+HCeZqmoJuihTv57/jvQ=="],
|
||||
|
||||
"@esbuild/netbsd-arm64": ["@esbuild/netbsd-arm64@0.25.8", "", { "os": "none", "cpu": "arm64" }, "sha512-d1KfruIeohqAi6SA+gENMuObDbEjn22olAR7egqnkCD9DGBG0wsEARotkLgXDu6c4ncgWTZJtN5vcgxzWRMzcw=="],
|
||||
|
||||
"@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.25.8", "", { "os": "none", "cpu": "x64" }, "sha512-nVDCkrvx2ua+XQNyfrujIG38+YGyuy2Ru9kKVNyh5jAys6n+l44tTtToqHjino2My8VAY6Lw9H7RI73XFi66Cg=="],
|
||||
|
||||
"@esbuild/openbsd-arm64": ["@esbuild/openbsd-arm64@0.25.8", "", { "os": "openbsd", "cpu": "arm64" }, "sha512-j8HgrDuSJFAujkivSMSfPQSAa5Fxbvk4rgNAS5i3K+r8s1X0p1uOO2Hl2xNsGFppOeHOLAVgYwDVlmxhq5h+SQ=="],
|
||||
|
||||
"@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.25.8", "", { "os": "openbsd", "cpu": "x64" }, "sha512-1h8MUAwa0VhNCDp6Af0HToI2TJFAn1uqT9Al6DJVzdIBAd21m/G0Yfc77KDM3uF3T/YaOgQq3qTJHPbTOInaIQ=="],
|
||||
|
||||
"@esbuild/openharmony-arm64": ["@esbuild/openharmony-arm64@0.25.8", "", { "os": "none", "cpu": "arm64" }, "sha512-r2nVa5SIK9tSWd0kJd9HCffnDHKchTGikb//9c7HX+r+wHYCpQrSgxhlY6KWV1nFo1l4KFbsMlHk+L6fekLsUg=="],
|
||||
|
||||
"@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.25.8", "", { "os": "sunos", "cpu": "x64" }, "sha512-zUlaP2S12YhQ2UzUfcCuMDHQFJyKABkAjvO5YSndMiIkMimPmxA+BYSBikWgsRpvyxuRnow4nS5NPnf9fpv41w=="],
|
||||
|
||||
"@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.25.8", "", { "os": "win32", "cpu": "arm64" }, "sha512-YEGFFWESlPva8hGL+zvj2z/SaK+pH0SwOM0Nc/d+rVnW7GSTFlLBGzZkuSU9kFIGIo8q9X3ucpZhu8PDN5A2sQ=="],
|
||||
|
||||
"@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.25.8", "", { "os": "win32", "cpu": "ia32" }, "sha512-hiGgGC6KZ5LZz58OL/+qVVoZiuZlUYlYHNAmczOm7bs2oE1XriPFi5ZHHrS8ACpV5EjySrnoCKmcbQMN+ojnHg=="],
|
||||
|
||||
"@esbuild/win32-x64": ["@esbuild/win32-x64@0.25.8", "", { "os": "win32", "cpu": "x64" }, "sha512-cn3Yr7+OaaZq1c+2pe+8yxC8E144SReCQjN6/2ynubzYjvyqZjTXfQJpAcQpsdJq3My7XADANiYGHoFC69pLQw=="],
|
||||
|
||||
"@jridgewell/sourcemap-codec": ["@jridgewell/sourcemap-codec@1.5.5", "", {}, "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og=="],
|
||||
|
||||
"@rolldown/pluginutils": ["@rolldown/pluginutils@1.0.0-beta.29", "", {}, "sha512-NIJgOsMjbxAXvoGq/X0gD7VPMQ8j9g0BiDaNjVNVjvl+iKXxL3Jre0v31RmBYeLEmkbj2s02v8vFTbUXi5XS2Q=="],
|
||||
|
||||
"@rollup/rollup-android-arm-eabi": ["@rollup/rollup-android-arm-eabi@4.46.2", "", { "os": "android", "cpu": "arm" }, "sha512-Zj3Hl6sN34xJtMv7Anwb5Gu01yujyE/cLBDB2gnHTAHaWS1Z38L7kuSG+oAh0giZMqG060f/YBStXtMH6FvPMA=="],
|
||||
|
||||
"@rollup/rollup-android-arm64": ["@rollup/rollup-android-arm64@4.46.2", "", { "os": "android", "cpu": "arm64" }, "sha512-nTeCWY83kN64oQ5MGz3CgtPx8NSOhC5lWtsjTs+8JAJNLcP3QbLCtDDgUKQc/Ro/frpMq4SHUaHN6AMltcEoLQ=="],
|
||||
|
||||
"@rollup/rollup-darwin-arm64": ["@rollup/rollup-darwin-arm64@4.46.2", "", { "os": "darwin", "cpu": "arm64" }, "sha512-HV7bW2Fb/F5KPdM/9bApunQh68YVDU8sO8BvcW9OngQVN3HHHkw99wFupuUJfGR9pYLLAjcAOA6iO+evsbBaPQ=="],
|
||||
|
||||
"@rollup/rollup-darwin-x64": ["@rollup/rollup-darwin-x64@4.46.2", "", { "os": "darwin", "cpu": "x64" }, "sha512-SSj8TlYV5nJixSsm/y3QXfhspSiLYP11zpfwp6G/YDXctf3Xkdnk4woJIF5VQe0of2OjzTt8EsxnJDCdHd2xMA=="],
|
||||
|
||||
"@rollup/rollup-freebsd-arm64": ["@rollup/rollup-freebsd-arm64@4.46.2", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-ZyrsG4TIT9xnOlLsSSi9w/X29tCbK1yegE49RYm3tu3wF1L/B6LVMqnEWyDB26d9Ecx9zrmXCiPmIabVuLmNSg=="],
|
||||
|
||||
"@rollup/rollup-freebsd-x64": ["@rollup/rollup-freebsd-x64@4.46.2", "", { "os": "freebsd", "cpu": "x64" }, "sha512-pCgHFoOECwVCJ5GFq8+gR8SBKnMO+xe5UEqbemxBpCKYQddRQMgomv1104RnLSg7nNvgKy05sLsY51+OVRyiVw=="],
|
||||
|
||||
"@rollup/rollup-linux-arm-gnueabihf": ["@rollup/rollup-linux-arm-gnueabihf@4.46.2", "", { "os": "linux", "cpu": "arm" }, "sha512-EtP8aquZ0xQg0ETFcxUbU71MZlHaw9MChwrQzatiE8U/bvi5uv/oChExXC4mWhjiqK7azGJBqU0tt5H123SzVA=="],
|
||||
|
||||
"@rollup/rollup-linux-arm-musleabihf": ["@rollup/rollup-linux-arm-musleabihf@4.46.2", "", { "os": "linux", "cpu": "arm" }, "sha512-qO7F7U3u1nfxYRPM8HqFtLd+raev2K137dsV08q/LRKRLEc7RsiDWihUnrINdsWQxPR9jqZ8DIIZ1zJJAm5PjQ=="],
|
||||
|
||||
"@rollup/rollup-linux-arm64-gnu": ["@rollup/rollup-linux-arm64-gnu@4.46.2", "", { "os": "linux", "cpu": "arm64" }, "sha512-3dRaqLfcOXYsfvw5xMrxAk9Lb1f395gkoBYzSFcc/scgRFptRXL9DOaDpMiehf9CO8ZDRJW2z45b6fpU5nwjng=="],
|
||||
|
||||
"@rollup/rollup-linux-arm64-musl": ["@rollup/rollup-linux-arm64-musl@4.46.2", "", { "os": "linux", "cpu": "arm64" }, "sha512-fhHFTutA7SM+IrR6lIfiHskxmpmPTJUXpWIsBXpeEwNgZzZZSg/q4i6FU4J8qOGyJ0TR+wXBwx/L7Ho9z0+uDg=="],
|
||||
|
||||
"@rollup/rollup-linux-loongarch64-gnu": ["@rollup/rollup-linux-loongarch64-gnu@4.46.2", "", { "os": "linux", "cpu": "none" }, "sha512-i7wfGFXu8x4+FRqPymzjD+Hyav8l95UIZ773j7J7zRYc3Xsxy2wIn4x+llpunexXe6laaO72iEjeeGyUFmjKeA=="],
|
||||
|
||||
"@rollup/rollup-linux-ppc64-gnu": ["@rollup/rollup-linux-ppc64-gnu@4.46.2", "", { "os": "linux", "cpu": "ppc64" }, "sha512-B/l0dFcHVUnqcGZWKcWBSV2PF01YUt0Rvlurci5P+neqY/yMKchGU8ullZvIv5e8Y1C6wOn+U03mrDylP5q9Yw=="],
|
||||
|
||||
"@rollup/rollup-linux-riscv64-gnu": ["@rollup/rollup-linux-riscv64-gnu@4.46.2", "", { "os": "linux", "cpu": "none" }, "sha512-32k4ENb5ygtkMwPMucAb8MtV8olkPT03oiTxJbgkJa7lJ7dZMr0GCFJlyvy+K8iq7F/iuOr41ZdUHaOiqyR3iQ=="],
|
||||
|
||||
"@rollup/rollup-linux-riscv64-musl": ["@rollup/rollup-linux-riscv64-musl@4.46.2", "", { "os": "linux", "cpu": "none" }, "sha512-t5B2loThlFEauloaQkZg9gxV05BYeITLvLkWOkRXogP4qHXLkWSbSHKM9S6H1schf/0YGP/qNKtiISlxvfmmZw=="],
|
||||
|
||||
"@rollup/rollup-linux-s390x-gnu": ["@rollup/rollup-linux-s390x-gnu@4.46.2", "", { "os": "linux", "cpu": "s390x" }, "sha512-YKjekwTEKgbB7n17gmODSmJVUIvj8CX7q5442/CK80L8nqOUbMtf8b01QkG3jOqyr1rotrAnW6B/qiHwfcuWQA=="],
|
||||
|
||||
"@rollup/rollup-linux-x64-gnu": ["@rollup/rollup-linux-x64-gnu@4.46.2", "", { "os": "linux", "cpu": "x64" }, "sha512-Jj5a9RUoe5ra+MEyERkDKLwTXVu6s3aACP51nkfnK9wJTraCC8IMe3snOfALkrjTYd2G1ViE1hICj0fZ7ALBPA=="],
|
||||
|
||||
"@rollup/rollup-linux-x64-musl": ["@rollup/rollup-linux-x64-musl@4.46.2", "", { "os": "linux", "cpu": "x64" }, "sha512-7kX69DIrBeD7yNp4A5b81izs8BqoZkCIaxQaOpumcJ1S/kmqNFjPhDu1LHeVXv0SexfHQv5cqHsxLOjETuqDuA=="],
|
||||
|
||||
"@rollup/rollup-win32-arm64-msvc": ["@rollup/rollup-win32-arm64-msvc@4.46.2", "", { "os": "win32", "cpu": "arm64" }, "sha512-wiJWMIpeaak/jsbaq2HMh/rzZxHVW1rU6coyeNNpMwk5isiPjSTx0a4YLSlYDwBH/WBvLz+EtsNqQScZTLJy3g=="],
|
||||
|
||||
"@rollup/rollup-win32-ia32-msvc": ["@rollup/rollup-win32-ia32-msvc@4.46.2", "", { "os": "win32", "cpu": "ia32" }, "sha512-gBgaUDESVzMgWZhcyjfs9QFK16D8K6QZpwAaVNJxYDLHWayOta4ZMjGm/vsAEy3hvlS2GosVFlBlP9/Wb85DqQ=="],
|
||||
|
||||
"@rollup/rollup-win32-x64-msvc": ["@rollup/rollup-win32-x64-msvc@4.46.2", "", { "os": "win32", "cpu": "x64" }, "sha512-CvUo2ixeIQGtF6WvuB87XWqPQkoFAFqW+HUo/WzHwuHDvIwZCtjdWXoYCcr06iKGydiqTclC4jU/TNObC/xKZg=="],
|
||||
|
||||
"@tweenjs/tween.js": ["@tweenjs/tween.js@23.1.3", "", {}, "sha512-vJmvvwFxYuGnF2axRtPYocag6Clbb5YS7kLL+SO/TeVFzHqDIWrNKYtcsPMibjDx9O+bu+psAy9NKfWklassUA=="],
|
||||
|
||||
"@types/estree": ["@types/estree@1.0.8", "", {}, "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w=="],
|
||||
|
||||
"@types/stats.js": ["@types/stats.js@0.17.4", "", {}, "sha512-jIBvWWShCvlBqBNIZt0KAshWpvSjhkwkEu4ZUcASoAvhmrgAUI2t1dXrjSL4xXVLB4FznPrIsX3nKXFl/Dt4vA=="],
|
||||
|
||||
"@types/three": ["@types/three@0.179.0", "", { "dependencies": { "@dimforge/rapier3d-compat": "~0.12.0", "@tweenjs/tween.js": "~23.1.3", "@types/stats.js": "*", "@types/webxr": "*", "@webgpu/types": "*", "fflate": "~0.8.2", "meshoptimizer": "~0.22.0" } }, "sha512-VgbFG2Pgsm84BqdegZzr7w2aKbQxmgzIu4Dy7/75ygiD/0P68LKmp5ie08KMPNqGTQwIge8s6D1guZf1RnZE0A=="],
|
||||
|
||||
"@types/webxr": ["@types/webxr@0.5.22", "", {}, "sha512-Vr6Stjv5jPRqH690f5I5GLjVk8GSsoQSYJ2FVd/3jJF7KaqfwPi3ehfBS96mlQ2kPCwZaX6U0rG2+NGHBKkA/A=="],
|
||||
|
||||
"@vitejs/plugin-vue": ["@vitejs/plugin-vue@6.0.1", "", { "dependencies": { "@rolldown/pluginutils": "1.0.0-beta.29" }, "peerDependencies": { "vite": "^5.0.0 || ^6.0.0 || ^7.0.0", "vue": "^3.2.25" } }, "sha512-+MaE752hU0wfPFJEUAIxqw18+20euHHdxVtMvbFcOEpjEyfqXH/5DCoTHiVJ0J29EhTJdoTkjEv5YBKU9dnoTw=="],
|
||||
|
||||
"@volar/language-core": ["@volar/language-core@2.4.22", "", { "dependencies": { "@volar/source-map": "2.4.22" } }, "sha512-gp4M7Di5KgNyIyO903wTClYBavRt6UyFNpc5LWfyZr1lBsTUY+QrVZfmbNF2aCyfklBOVk9YC4p+zkwoyT7ECg=="],
|
||||
|
||||
"@volar/source-map": ["@volar/source-map@2.4.22", "", {}, "sha512-L2nVr/1vei0xKRgO2tYVXtJYd09HTRjaZi418e85Q+QdbbqA8h7bBjfNyPPSsjnrOO4l4kaAo78c8SQUAdHvgA=="],
|
||||
|
||||
"@volar/typescript": ["@volar/typescript@2.4.22", "", { "dependencies": { "@volar/language-core": "2.4.22", "path-browserify": "^1.0.1", "vscode-uri": "^3.0.8" } }, "sha512-6ZczlJW1/GWTrNnkmZxJp4qyBt/SGVlcTuCWpI5zLrdPdCZsj66Aff9ZsfFaT3TyjG8zVYgBMYPuCm/eRkpcpQ=="],
|
||||
|
||||
"@vue/compiler-core": ["@vue/compiler-core@3.5.18", "", { "dependencies": { "@babel/parser": "^7.28.0", "@vue/shared": "3.5.18", "entities": "^4.5.0", "estree-walker": "^2.0.2", "source-map-js": "^1.2.1" } }, "sha512-3slwjQrrV1TO8MoXgy3aynDQ7lslj5UqDxuHnrzHtpON5CBinhWjJETciPngpin/T3OuW3tXUf86tEurusnztw=="],
|
||||
|
||||
"@vue/compiler-dom": ["@vue/compiler-dom@3.5.18", "", { "dependencies": { "@vue/compiler-core": "3.5.18", "@vue/shared": "3.5.18" } }, "sha512-RMbU6NTU70++B1JyVJbNbeFkK+A+Q7y9XKE2EM4NLGm2WFR8x9MbAtWxPPLdm0wUkuZv9trpwfSlL6tjdIa1+A=="],
|
||||
|
||||
"@vue/compiler-sfc": ["@vue/compiler-sfc@3.5.18", "", { "dependencies": { "@babel/parser": "^7.28.0", "@vue/compiler-core": "3.5.18", "@vue/compiler-dom": "3.5.18", "@vue/compiler-ssr": "3.5.18", "@vue/shared": "3.5.18", "estree-walker": "^2.0.2", "magic-string": "^0.30.17", "postcss": "^8.5.6", "source-map-js": "^1.2.1" } }, "sha512-5aBjvGqsWs+MoxswZPoTB9nSDb3dhd1x30xrrltKujlCxo48j8HGDNj3QPhF4VIS0VQDUrA1xUfp2hEa+FNyXA=="],
|
||||
|
||||
"@vue/compiler-ssr": ["@vue/compiler-ssr@3.5.18", "", { "dependencies": { "@vue/compiler-dom": "3.5.18", "@vue/shared": "3.5.18" } }, "sha512-xM16Ak7rSWHkM3m22NlmcdIM+K4BMyFARAfV9hYFl+SFuRzrZ3uGMNW05kA5pmeMa0X9X963Kgou7ufdbpOP9g=="],
|
||||
|
||||
"@vue/compiler-vue2": ["@vue/compiler-vue2@2.7.16", "", { "dependencies": { "de-indent": "^1.0.2", "he": "^1.2.0" } }, "sha512-qYC3Psj9S/mfu9uVi5WvNZIzq+xnXMhOwbTFKKDD7b1lhpnn71jXSFdTQ+WsIEk0ONCd7VV2IMm7ONl6tbQ86A=="],
|
||||
|
||||
"@vue/language-core": ["@vue/language-core@3.0.5", "", { "dependencies": { "@volar/language-core": "2.4.22", "@vue/compiler-dom": "^3.5.0", "@vue/compiler-vue2": "^2.7.16", "@vue/shared": "^3.5.0", "alien-signals": "^2.0.5", "muggle-string": "^0.4.1", "path-browserify": "^1.0.1", "picomatch": "^4.0.2" }, "peerDependencies": { "typescript": "*" }, "optionalPeers": ["typescript"] }, "sha512-gCEjn9Ik7I/seHVNIEipOm8W+f3/kg60e8s1IgIkMYma2wu9ZGUTMv3mSL2bX+Md2L8fslceJ4SU8j1fgSRoiw=="],
|
||||
|
||||
"@vue/reactivity": ["@vue/reactivity@3.5.18", "", { "dependencies": { "@vue/shared": "3.5.18" } }, "sha512-x0vPO5Imw+3sChLM5Y+B6G1zPjwdOri9e8V21NnTnlEvkxatHEH5B5KEAJcjuzQ7BsjGrKtfzuQ5eQwXh8HXBg=="],
|
||||
|
||||
"@vue/runtime-core": ["@vue/runtime-core@3.5.18", "", { "dependencies": { "@vue/reactivity": "3.5.18", "@vue/shared": "3.5.18" } }, "sha512-DUpHa1HpeOQEt6+3nheUfqVXRog2kivkXHUhoqJiKR33SO4x+a5uNOMkV487WPerQkL0vUuRvq/7JhRgLW3S+w=="],
|
||||
|
||||
"@vue/runtime-dom": ["@vue/runtime-dom@3.5.18", "", { "dependencies": { "@vue/reactivity": "3.5.18", "@vue/runtime-core": "3.5.18", "@vue/shared": "3.5.18", "csstype": "^3.1.3" } }, "sha512-YwDj71iV05j4RnzZnZtGaXwPoUWeRsqinblgVJwR8XTXYZ9D5PbahHQgsbmzUvCWNF6x7siQ89HgnX5eWkr3mw=="],
|
||||
|
||||
"@vue/server-renderer": ["@vue/server-renderer@3.5.18", "", { "dependencies": { "@vue/compiler-ssr": "3.5.18", "@vue/shared": "3.5.18" }, "peerDependencies": { "vue": "3.5.18" } }, "sha512-PvIHLUoWgSbDG7zLHqSqaCoZvHi6NNmfVFOqO+OnwvqMz/tqQr3FuGWS8ufluNddk7ZLBJYMrjcw1c6XzR12mA=="],
|
||||
|
||||
"@vue/shared": ["@vue/shared@3.5.18", "", {}, "sha512-cZy8Dq+uuIXbxCZpuLd2GJdeSO/lIzIspC2WtkqIpje5QyFbvLaI5wZtdUjLHjGZrlVX6GilejatWwVYYRc8tA=="],
|
||||
|
||||
"@vue/tsconfig": ["@vue/tsconfig@0.7.0", "", { "peerDependencies": { "typescript": "5.x", "vue": "^3.4.0" }, "optionalPeers": ["typescript", "vue"] }, "sha512-ku2uNz5MaZ9IerPPUyOHzyjhXoX2kVJaVf7hL315DC17vS6IiZRmmCPfggNbU16QTvM80+uYYy3eYJB59WCtvg=="],
|
||||
|
||||
"@webgpu/types": ["@webgpu/types@0.1.64", "", {}, "sha512-84kRIAGV46LJTlJZWxShiOrNL30A+9KokD7RB3dRCIqODFjodS5tCD5yyiZ8kIReGVZSDfA3XkkwyyOIF6K62A=="],
|
||||
|
||||
"alien-signals": ["alien-signals@2.0.6", "", {}, "sha512-P3TxJSe31bUHBiblg59oU1PpaWPtmxF9GhJ/cB7OkgJ0qN/ifFSKUI25/v8ZhsT+lIG6ac8DpTOplXxORX6F3Q=="],
|
||||
|
||||
"csstype": ["csstype@3.1.3", "", {}, "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw=="],
|
||||
|
||||
"de-indent": ["de-indent@1.0.2", "", {}, "sha512-e/1zu3xH5MQryN2zdVaF0OrdNLUbvWxzMbi+iNA6Bky7l1RoP8a2fIbRocyHclXt/arDrrR6lL3TqFD9pMQTsg=="],
|
||||
|
||||
"echarts": ["echarts@6.0.0", "", { "dependencies": { "tslib": "2.3.0", "zrender": "6.0.0" } }, "sha512-Tte/grDQRiETQP4xz3iZWSvoHrkCQtwqd6hs+mifXcjrCuo2iKWbajFObuLJVBlDIJlOzgQPd1hsaKt/3+OMkQ=="],
|
||||
|
||||
"entities": ["entities@4.5.0", "", {}, "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw=="],
|
||||
|
||||
"esbuild": ["esbuild@0.25.8", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.25.8", "@esbuild/android-arm": "0.25.8", "@esbuild/android-arm64": "0.25.8", "@esbuild/android-x64": "0.25.8", "@esbuild/darwin-arm64": "0.25.8", "@esbuild/darwin-x64": "0.25.8", "@esbuild/freebsd-arm64": "0.25.8", "@esbuild/freebsd-x64": "0.25.8", "@esbuild/linux-arm": "0.25.8", "@esbuild/linux-arm64": "0.25.8", "@esbuild/linux-ia32": "0.25.8", "@esbuild/linux-loong64": "0.25.8", "@esbuild/linux-mips64el": "0.25.8", "@esbuild/linux-ppc64": "0.25.8", "@esbuild/linux-riscv64": "0.25.8", "@esbuild/linux-s390x": "0.25.8", "@esbuild/linux-x64": "0.25.8", "@esbuild/netbsd-arm64": "0.25.8", "@esbuild/netbsd-x64": "0.25.8", "@esbuild/openbsd-arm64": "0.25.8", "@esbuild/openbsd-x64": "0.25.8", "@esbuild/openharmony-arm64": "0.25.8", "@esbuild/sunos-x64": "0.25.8", "@esbuild/win32-arm64": "0.25.8", "@esbuild/win32-ia32": "0.25.8", "@esbuild/win32-x64": "0.25.8" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-vVC0USHGtMi8+R4Kz8rt6JhEWLxsv9Rnu/lGYbPR8u47B+DCBksq9JarW0zOO7bs37hyOK1l2/oqtbciutL5+Q=="],
|
||||
|
||||
"estree-walker": ["estree-walker@2.0.2", "", {}, "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w=="],
|
||||
|
||||
"fdir": ["fdir@6.4.6", "", { "peerDependencies": { "picomatch": "^3 || ^4" }, "optionalPeers": ["picomatch"] }, "sha512-hiFoqpyZcfNm1yc4u8oWCf9A2c4D3QjCrks3zmoVKVxpQRzmPNar1hUJcBG2RQHvEVGDN+Jm81ZheVLAQMK6+w=="],
|
||||
|
||||
"fflate": ["fflate@0.8.2", "", {}, "sha512-cPJU47OaAoCbg0pBvzsgpTPhmhqI5eJjh/JIu8tPj5q+T7iLvW/JAYUqmE7KOB4R1ZyEhzBaIQpQpardBF5z8A=="],
|
||||
|
||||
"fsevents": ["fsevents@2.3.3", "", { "os": "darwin" }, "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw=="],
|
||||
|
||||
"he": ["he@1.2.0", "", { "bin": { "he": "bin/he" } }, "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw=="],
|
||||
|
||||
"magic-string": ["magic-string@0.30.17", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.0" } }, "sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA=="],
|
||||
|
||||
"meshoptimizer": ["meshoptimizer@0.22.0", "", {}, "sha512-IebiK79sqIy+E4EgOr+CAw+Ke8hAspXKzBd0JdgEmPHiAwmvEj2S4h1rfvo+o/BnfEYd/jAOg5IeeIjzlzSnDg=="],
|
||||
|
||||
"muggle-string": ["muggle-string@0.4.1", "", {}, "sha512-VNTrAak/KhO2i8dqqnqnAHOa3cYBwXEZe9h+D5h/1ZqFSTEFHdM65lR7RoIqq3tBBYavsOXV84NoHXZ0AkPyqQ=="],
|
||||
|
||||
"nanoid": ["nanoid@3.3.11", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w=="],
|
||||
|
||||
"path-browserify": ["path-browserify@1.0.1", "", {}, "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g=="],
|
||||
|
||||
"picocolors": ["picocolors@1.1.1", "", {}, "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA=="],
|
||||
|
||||
"picomatch": ["picomatch@4.0.3", "", {}, "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q=="],
|
||||
|
||||
"postcss": ["postcss@8.5.6", "", { "dependencies": { "nanoid": "^3.3.11", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" } }, "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg=="],
|
||||
|
||||
"rollup": ["rollup@4.46.2", "", { "dependencies": { "@types/estree": "1.0.8" }, "optionalDependencies": { "@rollup/rollup-android-arm-eabi": "4.46.2", "@rollup/rollup-android-arm64": "4.46.2", "@rollup/rollup-darwin-arm64": "4.46.2", "@rollup/rollup-darwin-x64": "4.46.2", "@rollup/rollup-freebsd-arm64": "4.46.2", "@rollup/rollup-freebsd-x64": "4.46.2", "@rollup/rollup-linux-arm-gnueabihf": "4.46.2", "@rollup/rollup-linux-arm-musleabihf": "4.46.2", "@rollup/rollup-linux-arm64-gnu": "4.46.2", "@rollup/rollup-linux-arm64-musl": "4.46.2", "@rollup/rollup-linux-loongarch64-gnu": "4.46.2", "@rollup/rollup-linux-ppc64-gnu": "4.46.2", "@rollup/rollup-linux-riscv64-gnu": "4.46.2", "@rollup/rollup-linux-riscv64-musl": "4.46.2", "@rollup/rollup-linux-s390x-gnu": "4.46.2", "@rollup/rollup-linux-x64-gnu": "4.46.2", "@rollup/rollup-linux-x64-musl": "4.46.2", "@rollup/rollup-win32-arm64-msvc": "4.46.2", "@rollup/rollup-win32-ia32-msvc": "4.46.2", "@rollup/rollup-win32-x64-msvc": "4.46.2", "fsevents": "~2.3.2" }, "bin": { "rollup": "dist/bin/rollup" } }, "sha512-WMmLFI+Boh6xbop+OAGo9cQ3OgX9MIg7xOQjn+pTCwOkk+FNDAeAemXkJ3HzDJrVXleLOFVa1ipuc1AmEx1Dwg=="],
|
||||
|
||||
"source-map-js": ["source-map-js@1.2.1", "", {}, "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA=="],
|
||||
|
||||
"three": ["three@0.179.1", "", {}, "sha512-5y/elSIQbrvKOISxpwXCR4sQqHtGiOI+MKLc3SsBdDXA2hz3Mdp3X59aUp8DyybMa34aeBwbFTpdoLJaUDEWSw=="],
|
||||
|
||||
"tinyglobby": ["tinyglobby@0.2.14", "", { "dependencies": { "fdir": "^6.4.4", "picomatch": "^4.0.2" } }, "sha512-tX5e7OM1HnYr2+a2C/4V0htOcSQcoSTH9KgJnVvNm5zm/cyEWKJ7j7YutsH9CxMdtOkkLFy2AHrMci9IM8IPZQ=="],
|
||||
|
||||
"tslib": ["tslib@2.3.0", "", {}, "sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg=="],
|
||||
|
||||
"typescript": ["typescript@5.8.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ=="],
|
||||
|
||||
"vite": ["vite@7.1.2", "", { "dependencies": { "esbuild": "^0.25.0", "fdir": "^6.4.6", "picomatch": "^4.0.3", "postcss": "^8.5.6", "rollup": "^4.43.0", "tinyglobby": "^0.2.14" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^20.19.0 || >=22.12.0", "jiti": ">=1.21.0", "less": "^4.0.0", "lightningcss": "^1.21.0", "sass": "^1.70.0", "sass-embedded": "^1.70.0", "stylus": ">=0.54.8", "sugarss": "^5.0.0", "terser": "^5.16.0", "tsx": "^4.8.1", "yaml": "^2.4.2" }, "optionalPeers": ["@types/node", "jiti", "less", "lightningcss", "sass", "sass-embedded", "stylus", "sugarss", "terser", "tsx", "yaml"], "bin": { "vite": "bin/vite.js" } }, "sha512-J0SQBPlQiEXAF7tajiH+rUooJPo0l8KQgyg4/aMunNtrOa7bwuZJsJbDWzeljqQpgftxuq5yNJxQ91O9ts29UQ=="],
|
||||
|
||||
"vscode-uri": ["vscode-uri@3.1.0", "", {}, "sha512-/BpdSx+yCQGnCvecbyXdxHDkuk55/G3xwnC0GqY4gmQ3j+A+g8kzzgB4Nk/SINjqn6+waqw3EgbVF2QKExkRxQ=="],
|
||||
|
||||
"vue": ["vue@3.5.18", "", { "dependencies": { "@vue/compiler-dom": "3.5.18", "@vue/compiler-sfc": "3.5.18", "@vue/runtime-dom": "3.5.18", "@vue/server-renderer": "3.5.18", "@vue/shared": "3.5.18" }, "peerDependencies": { "typescript": "*" }, "optionalPeers": ["typescript"] }, "sha512-7W4Y4ZbMiQ3SEo+m9lnoNpV9xG7QVMLa+/0RFwwiAVkeYoyGXqWE85jabU4pllJNUzqfLShJ5YLptewhCWUgNA=="],
|
||||
|
||||
"vue-tsc": ["vue-tsc@3.0.5", "", { "dependencies": { "@volar/typescript": "2.4.22", "@vue/language-core": "3.0.5" }, "peerDependencies": { "typescript": ">=5.0.0" }, "bin": { "vue-tsc": "./bin/vue-tsc.js" } }, "sha512-PsTFN9lo1HJCrZw9NoqjYcAbYDXY0cOKyuW2E7naX5jcaVyWpqEsZOHN9Dws5890E8e5SDAD4L4Zam3dxG3/Cw=="],
|
||||
|
||||
"zrender": ["zrender@6.0.0", "", { "dependencies": { "tslib": "2.3.0" } }, "sha512-41dFXEEXuJpNecuUQq6JlbybmnHaqqpGlbH1yxnA5V9MMP4SbohSVZsJIwz+zdjQXSSlR1Vc34EgH1zxyTDvhg=="],
|
||||
}
|
||||
}
|
||||
13
index.html
Normal file
13
index.html
Normal file
@ -0,0 +1,13 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>EM Induction Lab</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
<script type="module" src="/src/main.ts"></script>
|
||||
</body>
|
||||
</html>
|
||||
24
package.json
Normal file
24
package.json
Normal file
@ -0,0 +1,24 @@
|
||||
{
|
||||
"name": "mag-rl-optimization",
|
||||
"private": true,
|
||||
"version": "0.0.0",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"build": "vue-tsc -b && vite build",
|
||||
"preview": "vite preview"
|
||||
},
|
||||
"dependencies": {
|
||||
"@types/three": "^0.179.0",
|
||||
"echarts": "^6.0.0",
|
||||
"three": "^0.179.1",
|
||||
"vue": "^3.5.18"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@vitejs/plugin-vue": "^6.0.1",
|
||||
"@vue/tsconfig": "^0.7.0",
|
||||
"typescript": "~5.8.3",
|
||||
"vite": "^7.1.2",
|
||||
"vue-tsc": "^3.0.5"
|
||||
}
|
||||
}
|
||||
1
public/vite.svg
Normal file
1
public/vite.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="31.88" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 257"><defs><linearGradient id="IconifyId1813088fe1fbc01fb466" x1="-.828%" x2="57.636%" y1="7.652%" y2="78.411%"><stop offset="0%" stop-color="#41D1FF"></stop><stop offset="100%" stop-color="#BD34FE"></stop></linearGradient><linearGradient id="IconifyId1813088fe1fbc01fb467" x1="43.376%" x2="50.316%" y1="2.242%" y2="89.03%"><stop offset="0%" stop-color="#FFEA83"></stop><stop offset="8.333%" stop-color="#FFDD35"></stop><stop offset="100%" stop-color="#FFA800"></stop></linearGradient></defs><path fill="url(#IconifyId1813088fe1fbc01fb466)" d="M255.153 37.938L134.897 252.976c-2.483 4.44-8.862 4.466-11.382.048L.875 37.958c-2.746-4.814 1.371-10.646 6.827-9.67l120.385 21.517a6.537 6.537 0 0 0 2.322-.004l117.867-21.483c5.438-.991 9.574 4.796 6.877 9.62Z"></path><path fill="url(#IconifyId1813088fe1fbc01fb467)" d="M185.432.063L96.44 17.501a3.268 3.268 0 0 0-2.634 3.014l-5.474 92.456a3.268 3.268 0 0 0 3.997 3.378l24.777-5.718c2.318-.535 4.413 1.507 3.936 3.838l-7.361 36.047c-.495 2.426 1.782 4.5 4.151 3.78l15.304-4.649c2.372-.72 4.652 1.36 4.15 3.788l-11.698 56.621c-.732 3.542 3.979 5.473 5.943 2.437l1.313-2.028l72.516-144.72c1.215-2.423-.88-5.186-3.54-4.672l-25.505 4.922c-2.396.462-4.435-1.77-3.759-4.114l16.646-57.705c.677-2.35-1.37-4.583-3.769-4.113Z"></path></svg>
|
||||
|
After Width: | Height: | Size: 1.5 KiB |
26
src/App.vue
Normal file
26
src/App.vue
Normal file
@ -0,0 +1,26 @@
|
||||
<script setup lang="ts">
|
||||
import ExperimentLiveDashboard from './components/ExperimentLiveDashboard.vue';
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<ExperimentLiveDashboard />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.logo {
|
||||
height: 6em;
|
||||
padding: 1.5em;
|
||||
will-change: filter;
|
||||
transition: filter 300ms;
|
||||
}
|
||||
|
||||
.logo:hover {
|
||||
filter: drop-shadow(0 0 2em #646cffaa);
|
||||
}
|
||||
|
||||
.logo.vue:hover {
|
||||
filter: drop-shadow(0 0 2em #42b883aa);
|
||||
}
|
||||
</style>
|
||||
1
src/assets/vue.svg
Normal file
1
src/assets/vue.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="37.07" height="36" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 198"><path fill="#41B883" d="M204.8 0H256L128 220.8L0 0h97.92L128 51.2L157.44 0h47.36Z"></path><path fill="#41B883" d="m0 0l128 220.8L256 0h-51.2L128 132.48L50.56 0H0Z"></path><path fill="#35495E" d="M50.56 0L128 133.12L204.8 0h-47.36L128 51.2L97.92 0H50.56Z"></path></svg>
|
||||
|
After Width: | Height: | Size: 496 B |
671
src/components/ExperimentLiveDashboard.vue
Normal file
671
src/components/ExperimentLiveDashboard.vue
Normal file
@ -0,0 +1,671 @@
|
||||
<template>
|
||||
<div class="page">
|
||||
<header class="header glass">
|
||||
<div class="title">
|
||||
<h1>EM Induction Lab — Live Monitor</h1>
|
||||
<p>气垫导轨 · 单线圈 · 可编程电源 · 实验状态实时演示</p>
|
||||
</div>
|
||||
<div class="badges">
|
||||
<span class="pill" :class="statusClass">{{ statusText }}</span>
|
||||
<span class="pill alt">Mode: {{ mode }}</span>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<section class="metrics-grid">
|
||||
<div class="card glass metric">
|
||||
<div class="label">当前回合</div>
|
||||
<div class="value xl">{{ state.round }}</div>
|
||||
</div>
|
||||
<div class="card glass metric">
|
||||
<div class="label">回合时间</div>
|
||||
<div class="value">{{ formattedTime }}</div>
|
||||
</div>
|
||||
<div class="card glass metric">
|
||||
<div class="label">末速度 v_out</div>
|
||||
<div class="value">{{ fmt(state.metrics.v_out) }} m/s</div>
|
||||
</div>
|
||||
<div class="card glass metric">
|
||||
<div class="label">能耗 E</div>
|
||||
<div class="value">{{ fmt(state.metrics.energy) }} J</div>
|
||||
</div>
|
||||
<div class="card glass metric">
|
||||
<div class="label">峰值电流</div>
|
||||
<div class="value">{{ fmt(state.metrics.I_pk) }} A</div>
|
||||
</div>
|
||||
<div class="card glass metric">
|
||||
<div class="label">线圈温度</div>
|
||||
<div class="value">{{ state.metrics.temp.toFixed(1) }} ℃</div>
|
||||
</div>
|
||||
<div class="card glass metric">
|
||||
<div class="label">本回合得分</div>
|
||||
<div class="value">{{ state.metrics.score.toFixed(2) }}</div>
|
||||
</div>
|
||||
<div class="card glass metric">
|
||||
<div class="label">脉冲参数</div>
|
||||
<div class="value">
|
||||
δ={{ (state.params.delta*1000).toFixed(1) }}ms ·
|
||||
τ={{ (state.params.tau*1000).toFixed(1) }}ms ·
|
||||
A={{ (state.params.amp*100).toFixed(0) }}%
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="main-grid">
|
||||
<div class="card glass three-wrap">
|
||||
<div class="card-title">装置实时 3D 状态</div>
|
||||
<canvas ref="threeCanvas" class="three"></canvas>
|
||||
<div class="legend">
|
||||
<span class="dot coil"></span>线圈
|
||||
<span class="dot cart"></span>滑块
|
||||
<span class="dot track"></span>导轨
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card glass chart" ref="chartVIP">
|
||||
<div class="card-title">实时:电压 / 电流 / 功率</div>
|
||||
<div class="sub">{{ nowStr }}</div>
|
||||
<div class="chart-host"></div>
|
||||
</div>
|
||||
|
||||
<div class="card glass chart" ref="chartEnergy">
|
||||
<div class="card-title">累计能量(积分)</div>
|
||||
<div class="chart-host"></div>
|
||||
</div>
|
||||
|
||||
<div class="card glass chart" ref="chartXV">
|
||||
<div class="card-title">实时:位置 / 速度</div>
|
||||
<div class="chart-host"></div>
|
||||
</div>
|
||||
|
||||
<div class="card glass chart" ref="chartScores">
|
||||
<div class="card-title">回合表现(得分、v_out、I_pk)</div>
|
||||
<div class="chart-host"></div>
|
||||
</div>
|
||||
|
||||
<div class="card glass chart" ref="chartParams">
|
||||
<div class="card-title">参数历史(δ/τ/A)</div>
|
||||
<div class="chart-host"></div>
|
||||
</div>
|
||||
|
||||
<div class="card glass side">
|
||||
<div class="card-title">控制</div>
|
||||
<div class="controls">
|
||||
<button class="btn" @click="toggleRun">
|
||||
{{ running ? '终止实验' : '继续实验' }}
|
||||
</button>
|
||||
<button class="btn alt" @click="nextRound">进入下一回合</button>
|
||||
</div>
|
||||
<div class="divider"></div>
|
||||
<div class="card-title">阈值 / 设定</div>
|
||||
<ul class="kv">
|
||||
<li><span>I 限流</span><b>{{ limits.I_max }} A</b></li>
|
||||
<li><span>温度上限</span><b>{{ limits.T_max }} ℃</b></li>
|
||||
<li><span>脉冲最宽</span><b>{{ (limits.tau_max*1000).toFixed(0) }} ms</b></li>
|
||||
<li><span>采样周期</span><b>{{ (dt*1000).toFixed(0) }} ms</b></li>
|
||||
</ul>
|
||||
|
||||
<div class="divider"></div>
|
||||
<div class="card-title">最近事件</div>
|
||||
<ul class="log">
|
||||
<li v-for="(e,i) in events.slice(-6).reverse()" :key="i">
|
||||
<span class="ts">{{ e.t }}</span>
|
||||
<span :class="['tag', e.type]">{{ e.type }}</span>
|
||||
<span class="msg">{{ e.msg }}</span>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { onMounted, onBeforeUnmount, ref, reactive, computed } from 'vue'
|
||||
import * as echarts from 'echarts'
|
||||
import * as THREE from 'three'
|
||||
|
||||
// ---------- 基础状态 ----------
|
||||
const running = ref(true)
|
||||
const mode = ref<'ACCEL' | 'BRAKE'>('ACCEL')
|
||||
const dt = 0.02 // 采样周期(秒),演示用
|
||||
const state = reactive({
|
||||
round: 1,
|
||||
t: 0, // 当前回合时间
|
||||
params: {
|
||||
delta: 0.010, // s
|
||||
tau: 0.018, // s
|
||||
amp: 0.7 // 0..1
|
||||
},
|
||||
metrics: {
|
||||
v_out: 0,
|
||||
energy: 0,
|
||||
I_pk: 0,
|
||||
temp: 31.2,
|
||||
score: 0
|
||||
}
|
||||
})
|
||||
const limits = reactive({
|
||||
I_max: 4.0,
|
||||
T_max: 70,
|
||||
tau_max: 0.050
|
||||
})
|
||||
const events = reactive<{t:string,type:string,msg:string}[]>([])
|
||||
|
||||
const statusText = computed(()=> running.value ? 'RUNNING' : 'PAUSED')
|
||||
const statusClass = computed(()=> running.value ? 'ok' : 'warn')
|
||||
const formattedTime = computed(()=>{
|
||||
const s = Math.floor(state.t)
|
||||
const ms = Math.floor((state.t - s)*1000)
|
||||
return `${String(s).padStart(2,'0')}.${String(ms).padStart(3,'0')} s`
|
||||
})
|
||||
const nowStr = computed(()=>{
|
||||
const d = new Date()
|
||||
const pad = (n:number,l=2)=>String(n).padStart(l,'0')
|
||||
return `${pad(d.getHours())}:${pad(d.getMinutes())}:${pad(d.getSeconds())}`
|
||||
})
|
||||
const fmt = (v:number)=> v>=10? v.toFixed(2) : v>=1? v.toFixed(3) : v.toFixed(4)
|
||||
|
||||
// ---------- three.js 场景 ----------
|
||||
const threeCanvas = ref<HTMLCanvasElement|null>(null)
|
||||
let renderer: THREE.WebGLRenderer | null = null
|
||||
let scene: THREE.Scene
|
||||
let camera: THREE.PerspectiveCamera
|
||||
let cart: THREE.Mesh
|
||||
let coil: THREE.Mesh
|
||||
let rafId = 0
|
||||
|
||||
function initThree() {
|
||||
if (!threeCanvas.value) return
|
||||
|
||||
// 等待 DOM 渲染完成后再获取尺寸
|
||||
setTimeout(() => {
|
||||
if (!threeCanvas.value) return
|
||||
const rect = threeCanvas.value.getBoundingClientRect()
|
||||
const w = rect.width
|
||||
const h = rect.height
|
||||
|
||||
scene = new THREE.Scene()
|
||||
scene.background = new THREE.Color('#0a0f1b')
|
||||
|
||||
camera = new THREE.PerspectiveCamera(45, w/h, 0.1, 100)
|
||||
camera.position.set(2.8, 1.6, 3.2)
|
||||
camera.lookAt(0,0,0)
|
||||
|
||||
renderer = new THREE.WebGLRenderer({ canvas: threeCanvas.value, antialias: true })
|
||||
renderer.setSize(w, h, false) // 添加 false 参数避免设置 canvas 样式
|
||||
renderer.setPixelRatio(Math.min(2, window.devicePixelRatio || 1))
|
||||
|
||||
const light = new THREE.DirectionalLight('#ffffff', 1.0)
|
||||
light.position.set(2,3,4)
|
||||
scene.add(light)
|
||||
scene.add(new THREE.AmbientLight('#88a', 0.4))
|
||||
|
||||
// 导轨
|
||||
const trackGeo = new THREE.BoxGeometry(3.0, 0.05, 0.25)
|
||||
const trackMat = new THREE.MeshStandardMaterial({ color: '#4a6fa5', metalness: 0.5, roughness: 0.4 })
|
||||
const track = new THREE.Mesh(trackGeo, trackMat)
|
||||
track.position.set(0, -0.025, 0)
|
||||
scene.add(track)
|
||||
|
||||
// 线圈(中间)
|
||||
const coilGeo = new THREE.TorusGeometry(0.18, 0.04, 16, 64)
|
||||
const coilMat = new THREE.MeshStandardMaterial({ color: '#00eaff', emissive: '#003344', emissiveIntensity: 0.8, metalness: 0.6, roughness: 0.3 })
|
||||
coil = new THREE.Mesh(coilGeo, coilMat)
|
||||
coil.rotation.x = 0 // 竖起来,不再倒在地上
|
||||
coil.rotation.z = Math.PI / 2 // 旋转到水平
|
||||
coil.rotation.y = Math.PI / 2 // 旋转到正面
|
||||
scene.add(coil)
|
||||
|
||||
// 滑块
|
||||
const cartGeo = new THREE.BoxGeometry(0.18, 0.08, 0.18)
|
||||
const cartMat = new THREE.MeshStandardMaterial({ color: '#ffd166', metalness: 0.4, roughness: 0.5, emissive: '#664400', emissiveIntensity: 0.3 })
|
||||
cart = new THREE.Mesh(cartGeo, cartMat)
|
||||
cart.position.set(-1.2, 0.04, 0)
|
||||
scene.add(cart)
|
||||
|
||||
// 地面微光
|
||||
const grid = new THREE.GridHelper(10, 20, '#224466', '#112233')
|
||||
grid.position.y = -0.025
|
||||
scene.add(grid)
|
||||
|
||||
const animate = ()=>{
|
||||
// 根据演示中的位置(-1.2 -> 1.2)更新滑块
|
||||
const x = -1.2 + 2.4 * normPos // normPos in [0..1]
|
||||
cart.position.x = x
|
||||
|
||||
// 线圈亮度与瞬时电流关联(演示)
|
||||
const em = 0.3 + 0.7*Math.min(1, lastI/limits.I_max)
|
||||
;(coil.material as THREE.MeshStandardMaterial).emissiveIntensity = em
|
||||
|
||||
renderer!.render(scene, camera)
|
||||
rafId = requestAnimationFrame(animate)
|
||||
}
|
||||
animate()
|
||||
|
||||
window.addEventListener('resize', onResize)
|
||||
function onResize() {
|
||||
if (!renderer || !threeCanvas.value) return
|
||||
const rect = threeCanvas.value.getBoundingClientRect()
|
||||
const w = rect.width
|
||||
const h = rect.height
|
||||
camera.aspect = w/h
|
||||
camera.updateProjectionMatrix()
|
||||
renderer.setSize(w, h, false) // 添加 false 参数
|
||||
}
|
||||
}, 100) // 延迟 100ms 确保 DOM 已渲染
|
||||
}
|
||||
|
||||
// ---------- 图表 ----------
|
||||
const chartVIP = ref<HTMLDivElement|null>(null)
|
||||
const chartEnergy = ref<HTMLDivElement|null>(null)
|
||||
const chartXV = ref<HTMLDivElement|null>(null)
|
||||
const chartScores = ref<HTMLDivElement|null>(null)
|
||||
const chartParams = ref<HTMLDivElement|null>(null)
|
||||
|
||||
let vipChart: echarts.ECharts
|
||||
let energyChart: echarts.ECharts
|
||||
let xvChart: echarts.ECharts
|
||||
let scoresChart: echarts.ECharts
|
||||
let paramsChart: echarts.ECharts
|
||||
|
||||
// 数据缓冲
|
||||
const maxPts = 120
|
||||
const series = reactive({
|
||||
t: [] as number[],
|
||||
U: [] as number[],
|
||||
I: [] as number[],
|
||||
P: [] as number[],
|
||||
E: [] as number[],
|
||||
x: [] as number[],
|
||||
v: [] as number[],
|
||||
})
|
||||
const history = reactive({
|
||||
rounds: [] as number[],
|
||||
score: [] as number[],
|
||||
vout: [] as number[],
|
||||
Ipk: [] as number[],
|
||||
delta: [] as number[],
|
||||
tau: [] as number[],
|
||||
amp: [] as number[],
|
||||
})
|
||||
|
||||
function initCharts(){
|
||||
// 通用主题
|
||||
const base = {
|
||||
backgroundColor: 'transparent',
|
||||
textStyle: { color: '#cfe5ff' },
|
||||
grid: { left: 48, right: 20, top: 40, bottom: 40 },
|
||||
tooltip: { trigger: 'axis' },
|
||||
animation: false
|
||||
}
|
||||
// VIP
|
||||
vipChart = echarts.init(chartVIP.value!.querySelector('.chart-host') as HTMLDivElement)
|
||||
vipChart.setOption({
|
||||
...base,
|
||||
legend: { data: ['U (V)','I (A)','P (W)'], top: 4, textStyle: { color: '#a9c3ff' } },
|
||||
xAxis: { type:'category', boundaryGap:false, axisLine:{lineStyle:{color:'#335'}}, axisLabel:{color:'#89a'}},
|
||||
yAxis: [
|
||||
{ type:'value', name:'U/I', position:'left', axisLabel:{color:'#89a'} },
|
||||
{ type:'value', name:'P', position:'right', axisLabel:{color:'#89a'} }
|
||||
],
|
||||
series: [
|
||||
{ name:'U (V)', type:'line', smooth:true, showSymbol:false, data:[] },
|
||||
{ name:'I (A)', type:'line', smooth:true, showSymbol:false, data:[] },
|
||||
{ name:'P (W)', type:'line', smooth:true, yAxisIndex:1, showSymbol:false, areaStyle:{}, data:[] },
|
||||
]
|
||||
})
|
||||
|
||||
// Energy
|
||||
energyChart = echarts.init(chartEnergy.value!.querySelector('.chart-host') as HTMLDivElement)
|
||||
energyChart.setOption({
|
||||
...base,
|
||||
xAxis: { type:'category', boundaryGap:false, axisLabel:{color:'#89a'} },
|
||||
yAxis: { type:'value', name:'E (J)', axisLabel:{color:'#89a'} },
|
||||
series: [{ type:'line', smooth:true, showSymbol:false, areaStyle:{}, data:[] }]
|
||||
})
|
||||
|
||||
// XV
|
||||
xvChart = echarts.init(chartXV.value!.querySelector('.chart-host') as HTMLDivElement)
|
||||
xvChart.setOption({
|
||||
...base,
|
||||
legend: { data:['x (m)','v (m/s)'], top: 4, textStyle: { color:'#a9c3ff' } },
|
||||
xAxis: { type:'category', boundaryGap:false, axisLabel:{color:'#89a'} },
|
||||
yAxis: [
|
||||
{ type:'value', name:'x', position:'left', axisLabel:{color:'#89a'} },
|
||||
{ type:'value', name:'v', position:'right', axisLabel:{color:'#89a'} }
|
||||
],
|
||||
series: [
|
||||
{ name:'x (m)', type:'line', smooth:true, showSymbol:false, data:[] },
|
||||
{ name:'v (m/s)', type:'line', smooth:true, showSymbol:false, yAxisIndex:1, data:[] },
|
||||
]
|
||||
})
|
||||
|
||||
// Scores
|
||||
scoresChart = echarts.init(chartScores.value!.querySelector('.chart-host') as HTMLDivElement)
|
||||
scoresChart.setOption({
|
||||
...base,
|
||||
xAxis: { type:'category', axisLabel:{color:'#89a'}, data:[] },
|
||||
yAxis: [{ type:'value', axisLabel:{color:'#89a'}, name:'Score / v_out / I_pk'}],
|
||||
legend: { data:['Score','v_out','I_pk'], top: 4, textStyle: { color:'#a9c3ff' } },
|
||||
series: [
|
||||
{ name:'Score', type:'bar', data:[], itemStyle:{opacity:0.9}},
|
||||
{ name:'v_out', type:'line', smooth:true, showSymbol:true, data:[] },
|
||||
{ name:'I_pk', type:'line', smooth:true, showSymbol:true, data:[] },
|
||||
]
|
||||
})
|
||||
|
||||
// Params
|
||||
paramsChart = echarts.init(chartParams.value!.querySelector('.chart-host') as HTMLDivElement)
|
||||
paramsChart.setOption({
|
||||
...base,
|
||||
legend: { data:['δ(ms)','τ(ms)','A(%)'], top: 4, textStyle: { color:'#a9c3ff' } },
|
||||
xAxis: { type:'category', axisLabel:{color:'#89a'}, data:[] },
|
||||
yAxis: { type:'value', axisLabel:{color:'#89a'} },
|
||||
series: [
|
||||
{ name:'δ(ms)', type:'line', smooth:true, showSymbol:true, data:[] },
|
||||
{ name:'τ(ms)', type:'line', smooth:true, showSymbol:true, data:[] },
|
||||
{ name:'A(%)', type:'line', smooth:true, showSymbol:true, data:[] },
|
||||
]
|
||||
})
|
||||
}
|
||||
|
||||
function updateCharts(){
|
||||
// 为实时图表使用时间标签作为 X 轴
|
||||
const timeLabels = series.t.map(t => t.toFixed(1))
|
||||
|
||||
vipChart.setOption({
|
||||
xAxis: { data: timeLabels },
|
||||
series: [
|
||||
{ data: series.U },
|
||||
{ data: series.I },
|
||||
{ data: series.P },
|
||||
]
|
||||
})
|
||||
|
||||
energyChart.setOption({
|
||||
xAxis: { data: timeLabels },
|
||||
series: [{ data: series.E }]
|
||||
})
|
||||
|
||||
xvChart.setOption({
|
||||
xAxis: { data: timeLabels },
|
||||
series: [
|
||||
{ data: series.x },
|
||||
{ data: series.v }
|
||||
]
|
||||
})
|
||||
|
||||
// 历史图表使用回合数作为 X 轴
|
||||
scoresChart.setOption({
|
||||
xAxis: { data: history.rounds.map(r=>`#${r}`) },
|
||||
series: [
|
||||
{ data: history.score },
|
||||
{ data: history.vout },
|
||||
{ data: history.Ipk },
|
||||
]
|
||||
})
|
||||
|
||||
paramsChart.setOption({
|
||||
xAxis: { data: history.rounds.map(r=>`#${r}`) },
|
||||
series: [
|
||||
{ data: history.delta.map(d=> (d*1000).toFixed(1)) },
|
||||
{ data: history.tau.map(d=> (d*1000).toFixed(1)) },
|
||||
{ data: history.amp.map(a=> (a*100).toFixed(0)) },
|
||||
]
|
||||
})
|
||||
}
|
||||
|
||||
// ---------- 演示数据生成 ----------
|
||||
let ticker: number | null = null
|
||||
let roundTimer: number | null = null
|
||||
let lastI = 0
|
||||
let normPos = 0 // 0..1 for three.js
|
||||
|
||||
function resetSeries(){
|
||||
series.t.length = 0
|
||||
series.U.length = 0
|
||||
series.I.length = 0
|
||||
series.P.length = 0
|
||||
series.E.length = 0
|
||||
series.x.length = 0
|
||||
series.v.length = 0
|
||||
state.t = 0
|
||||
normPos = 0
|
||||
}
|
||||
|
||||
function clamp(n:number,min:number,max:number){ return Math.max(min, Math.min(max, n)) }
|
||||
|
||||
function pushDataPoint(){
|
||||
// 一个简单的“单脉冲穿越线圈”波形模型(仅为演示)
|
||||
state.t += dt
|
||||
const t = state.t
|
||||
const { delta, tau, amp } = state.params
|
||||
|
||||
// 位置/速度:先加速后缓出
|
||||
const total = 1.6 // 回合时长(s)
|
||||
const progress = clamp(t/total, 0, 1)
|
||||
const x = 1.2*progress // 0..1.2m
|
||||
const v = 1.2/total + 0.4*Math.sin(progress*Math.PI) // m/s 粗略
|
||||
normPos = progress
|
||||
// 电压/电流脉冲(在中心附近)
|
||||
const pulseCenter = 0.8 // s
|
||||
const t0 = pulseCenter - delta
|
||||
const inPulse = t>=t0 && t<=t0+tau
|
||||
const U = inPulse ? 8*amp + 0.2*Math.sin(t*20) : 0.1+0.05*Math.sin(t*6)
|
||||
const I = inPulse ? clamp(2.5*amp + 0.5*Math.sin(t*30), 0, limits.I_max) : 0.05+0.02*Math.sin(t*10)
|
||||
const P = U*I
|
||||
lastI = I
|
||||
|
||||
const E = ((series.E.length ? series.E[series.E.length - 1] : 0) || 0) + P*dt
|
||||
|
||||
series.t.push(t)
|
||||
series.U.push(Number(U.toFixed(3)))
|
||||
series.I.push(Number(I.toFixed(3)))
|
||||
series.P.push(Number(P.toFixed(3)))
|
||||
series.E.push(Number(E.toFixed(3)))
|
||||
series.x.push(Number((x).toFixed(3)))
|
||||
series.v.push(Number((v).toFixed(3)))
|
||||
|
||||
if (series.t.length>maxPts){
|
||||
Object.values(series).forEach(arr => (arr as number[]).shift())
|
||||
}
|
||||
|
||||
// metrics(这里用最后一点近似)
|
||||
state.metrics.energy = E
|
||||
state.metrics.I_pk = Math.max(state.metrics.I_pk, I)
|
||||
state.metrics.v_out = v
|
||||
state.metrics.temp = clamp(state.metrics.temp + (inPulse? 0.05: -0.02), 25, 80)
|
||||
|
||||
// 事件:过流/高温警告(演示)
|
||||
if (I > limits.I_max*0.95){
|
||||
events.push({t: nowStr.value, type:'warn', msg:`接近限流:${I.toFixed(2)} A`})
|
||||
}
|
||||
}
|
||||
|
||||
function finishRound(){
|
||||
// 计算得分
|
||||
const score = state.metrics.v_out - 0.4*state.metrics.energy - 0.2*state.metrics.I_pk - 0.02*(state.metrics.temp-25)
|
||||
state.metrics.score = Number(score.toFixed(3))
|
||||
|
||||
history.rounds.push(state.round)
|
||||
history.score.push(Number(state.metrics.score.toFixed(3)))
|
||||
history.vout.push(Number(state.metrics.v_out.toFixed(3)))
|
||||
history.Ipk.push(Number(state.metrics.I_pk.toFixed(3)))
|
||||
history.delta.push(state.params.delta)
|
||||
history.tau.push(state.params.tau)
|
||||
history.amp.push(state.params.amp)
|
||||
|
||||
// 下一回合参数微调(模拟优化)
|
||||
state.round += 1
|
||||
state.params.delta = clamp(state.params.delta + (Math.random()-0.5)*0.004, 0.004, 0.020)
|
||||
state.params.tau = clamp(state.params.tau + (Math.random()-0.5)*0.006, 0.008, limits.tau_max)
|
||||
state.params.amp = clamp(state.params.amp + (Math.random()-0.5)*0.08, 0.25, 1.0)
|
||||
|
||||
events.push({t: nowStr.value, type:'info', msg:`回合结束:Score=${state.metrics.score.toFixed(2)} v_out=${state.metrics.v_out.toFixed(2)} Ipk=${state.metrics.I_pk.toFixed(2)}`})
|
||||
|
||||
// 重置
|
||||
resetSeries()
|
||||
state.metrics.I_pk = 0
|
||||
state.metrics.energy = 0
|
||||
}
|
||||
|
||||
function startDemo(){
|
||||
if (ticker) return
|
||||
resetSeries()
|
||||
ticker = window.setInterval(()=>{
|
||||
if (!running.value) return
|
||||
pushDataPoint()
|
||||
updateCharts()
|
||||
|
||||
// 演示一个回合 1.6s
|
||||
if (state.t >= 1.6){
|
||||
finishRound()
|
||||
updateCharts()
|
||||
}
|
||||
}, dt*1000)
|
||||
|
||||
// 每5秒补一个“系统事件”
|
||||
if (!roundTimer){
|
||||
roundTimer = window.setInterval(()=>{
|
||||
events.push({t: nowStr.value, type:'sys', msg:'系统检查通过'})
|
||||
if (events.length>100) events.splice(0, events.length-100)
|
||||
}, 5000)
|
||||
}
|
||||
}
|
||||
|
||||
function stopDemo(){
|
||||
if (ticker){ clearInterval(ticker); ticker = null }
|
||||
if (roundTimer){ clearInterval(roundTimer); roundTimer = null }
|
||||
}
|
||||
|
||||
function toggleRun(){ running.value = !running.value }
|
||||
function nextRound(){ if (running.value){ finishRound(); updateCharts() } }
|
||||
|
||||
onMounted(()=>{
|
||||
initThree()
|
||||
initCharts()
|
||||
startDemo()
|
||||
})
|
||||
onBeforeUnmount(()=>{
|
||||
stopDemo()
|
||||
if (renderer){ renderer.dispose(); renderer = null }
|
||||
cancelAnimationFrame(rafId)
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
* { box-sizing: border-box; }
|
||||
.page{
|
||||
min-height: 100vh;
|
||||
background:
|
||||
radial-gradient(1200px 600px at 10% -10%, rgba(0,234,255,0.1), transparent),
|
||||
radial-gradient(1200px 600px at 90% 110%, rgba(255,209,102,0.08), transparent),
|
||||
linear-gradient(180deg, #050914 0%, #090f1e 100%);
|
||||
color: var(--text);
|
||||
padding: 24px;
|
||||
font-family: ui-sans-serif, system-ui, -apple-system, Segoe UI, Roboto, "Helvetica Neue", Arial;
|
||||
}
|
||||
.header{
|
||||
display:flex; align-items:center; justify-content:space-between;
|
||||
padding:16px 20px; border:1px solid var(--border); border-radius:16px; margin-bottom: 18px;
|
||||
}
|
||||
.header .title h1{ margin:0; letter-spacing:0.4px; font-weight:700; }
|
||||
.header .title p{ margin:4px 0 0; color:var(--muted); font-size:13px; }
|
||||
.badges{ display:flex; gap:10px; }
|
||||
.pill{
|
||||
padding:6px 12px; border-radius:999px; font-size:12px;
|
||||
background: linear-gradient(180deg, rgba(0,234,255,0.2), rgba(0,234,255,0.06));
|
||||
color:#baf6ff; border:1px solid rgba(0,234,255,0.25);
|
||||
text-shadow: 0 0 8px rgba(0,234,255,0.4);
|
||||
}
|
||||
.pill.ok{ background: linear-gradient(180deg, rgba(16,212,138,0.25), rgba(16,212,138,0.07));
|
||||
color:#c9ffe9; border-color: rgba(16,212,138,0.35); text-shadow:0 0 8px rgba(16,212,138,0.4);}
|
||||
.pill.warn{ background: linear-gradient(180deg, rgba(255,157,87,0.25), rgba(255,157,87,0.07));
|
||||
color:#ffe6d2; border-color: rgba(255,157,87,0.35); text-shadow:0 0 8px rgba(255,157,87,0.4);}
|
||||
.pill.alt{ background: linear-gradient(180deg, rgba(140,160,255,0.18), rgba(140,160,255,0.06)); color:#e0e6ff; border-color:rgba(140,160,255,0.3); }
|
||||
|
||||
.metrics-grid{
|
||||
display:grid; gap:12px; grid-template-columns: repeat(8, minmax(0,1fr)); margin-bottom: 14px;
|
||||
}
|
||||
.metric .label{ color: var(--muted); font-size:12px; }
|
||||
.metric .value{ font-size:18px; font-weight:700; margin-top:6px; }
|
||||
.metric .value.xl{ font-size:28px; letter-spacing: 0.5px; }
|
||||
|
||||
.main-grid{
|
||||
display:grid; grid-template-columns: 1.6fr 1.6fr 1.6fr 1fr; grid-auto-rows: 320px; gap:14px;
|
||||
}
|
||||
.card{
|
||||
position:relative; border:1px solid var(--border); border-radius:16px; padding:12px;
|
||||
}
|
||||
.glass{
|
||||
background: var(--card);
|
||||
backdrop-filter: blur(8px) saturate(120%);
|
||||
box-shadow: 0 12px 40px rgba(0,0,0,0.25), inset 0 0 0 1px rgba(255,255,255,0.02);
|
||||
}
|
||||
.card-title{
|
||||
font-weight:700; color:#e6f2ff; margin:4px 2px 10px; letter-spacing:0.3px;
|
||||
}
|
||||
.chart .chart-host{ position:absolute; inset: 48px 8px 8px 8px; }
|
||||
.sub{ position:absolute; right:14px; top:10px; color:#8fb3ff; font-size:12px; }
|
||||
|
||||
.three-wrap{
|
||||
grid-column: span 2;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
.three{
|
||||
width: 100%;
|
||||
height: calc(100% - 40px); /* 减去卡片标题和内边距 */
|
||||
max-width: 100%;
|
||||
max-height: calc(100% - 40px);
|
||||
border-radius: 12px;
|
||||
outline: 1px solid rgba(0,234,255,0.08);
|
||||
display: block;
|
||||
}
|
||||
.legend{
|
||||
position:absolute; left:12px; bottom:10px; display:flex; gap:14px; align-items:center; font-size:12px; color:#a9c3ff;
|
||||
}
|
||||
.legend .dot{ width:10px; height:10px; border-radius:50%; display:inline-block; margin-right:6px; }
|
||||
.legend .dot.coil{ background:#00eaff; box-shadow:0 0 10px #00eaff; }
|
||||
.legend .dot.cart{ background:#ffd166; box-shadow:0 0 10px #ffd166; }
|
||||
.legend .dot.track{ background:#1b2a4a; }
|
||||
|
||||
.side{ grid-row: span 2; display:flex; flex-direction:column; }
|
||||
.controls{ display:flex; gap:8px; }
|
||||
.btn{
|
||||
background: linear-gradient(180deg, rgba(0,234,255,0.2), rgba(0,109,169,0.2));
|
||||
color:#dff8ff; border:1px solid rgba(0,234,255,0.35); padding:8px 12px; border-radius:10px;
|
||||
cursor:pointer; font-weight:700; letter-spacing:0.2px;
|
||||
}
|
||||
.btn:hover{ filter: brightness(1.1); }
|
||||
.btn.alt{ background: linear-gradient(180deg, rgba(255,209,102,0.25), rgba(255,145,0,0.18)); border-color: rgba(255,209,102,0.45); color:#1b1200; }
|
||||
.divider{ height:1px; background: linear-gradient(90deg, transparent, rgba(255,255,255,0.12), transparent); margin:12px 0; }
|
||||
.kv{ list-style:none; padding:0; margin:6px 0 0; }
|
||||
.kv li{ display:flex; justify-content:space-between; padding:6px 2px; color:var(--muted); }
|
||||
.kv b{ color:var(--text); }
|
||||
.log{ list-style:none; padding:0; margin:8px 0 0; display:flex; flex-direction:column; gap:8px; max-height: 180px; overflow:auto; }
|
||||
.log .ts{ color:#89a; font-size:12px; margin-right:6px; }
|
||||
.log .msg{ color:#ddecff; }
|
||||
.tag{
|
||||
font-size:11px; padding:2px 8px; border-radius:999px; margin-right:6px;
|
||||
background: rgba(140,160,255,0.18); border:1px solid rgba(140,160,255,0.3); color:#dee5ff;
|
||||
}
|
||||
.tag.warn{ background: rgba(255,157,87,0.2); border-color: rgba(255,157,87,0.35); color:#fff0e5;}
|
||||
.tag.info{ background: rgba(0,234,255,0.18); border-color: rgba(0,234,255,0.35); color:#e2fbff;}
|
||||
.tag.sys{ background: rgba(16,212,138,0.2); border-color: rgba(16,212,138,0.35); color:#e5fff6;}
|
||||
|
||||
.footer{ text-align:center; color:#7fa5ff; margin-top: 16px; font-size:12px; }
|
||||
|
||||
/* 响应式 */
|
||||
@media (max-width: 1200px){
|
||||
.main-grid{ grid-template-columns: 1fr 1fr; grid-auto-rows: 300px; }
|
||||
.three-wrap{ grid-column: span 2; }
|
||||
.side{ grid-row: auto; }
|
||||
.metrics-grid{ grid-template-columns: repeat(4, 1fr); }
|
||||
}
|
||||
@media (max-width: 700px){
|
||||
.metrics-grid{ grid-template-columns: repeat(2, 1fr); }
|
||||
.main-grid{ grid-template-columns: 1fr; }
|
||||
.three-wrap{ grid-column: span 1; }
|
||||
}
|
||||
</style>
|
||||
5
src/main.ts
Normal file
5
src/main.ts
Normal file
@ -0,0 +1,5 @@
|
||||
import { createApp } from 'vue'
|
||||
import './style.css'
|
||||
import App from './App.vue'
|
||||
|
||||
createApp(App).mount('#app')
|
||||
16
src/style.css
Normal file
16
src/style.css
Normal file
@ -0,0 +1,16 @@
|
||||
|
||||
:root{
|
||||
--bg: #060a14;
|
||||
--card: rgba(16,24,44,0.6);
|
||||
--border: rgba(255,255,255,0.08);
|
||||
--text: #dce9ff;
|
||||
--muted: #9ab0d6;
|
||||
--accent: #00eaff;
|
||||
--accent2: #ffd166;
|
||||
--ok: #10d48a;
|
||||
--warn: #ff9d57;
|
||||
}
|
||||
|
||||
body{
|
||||
margin: 0;
|
||||
}
|
||||
1
src/vite-env.d.ts
vendored
Normal file
1
src/vite-env.d.ts
vendored
Normal file
@ -0,0 +1 @@
|
||||
/// <reference types="vite/client" />
|
||||
15
tsconfig.app.json
Normal file
15
tsconfig.app.json
Normal file
@ -0,0 +1,15 @@
|
||||
{
|
||||
"extends": "@vue/tsconfig/tsconfig.dom.json",
|
||||
"compilerOptions": {
|
||||
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
|
||||
|
||||
/* Linting */
|
||||
"strict": true,
|
||||
"noUnusedLocals": true,
|
||||
"noUnusedParameters": true,
|
||||
"erasableSyntaxOnly": true,
|
||||
"noFallthroughCasesInSwitch": true,
|
||||
"noUncheckedSideEffectImports": true
|
||||
},
|
||||
"include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.vue"]
|
||||
}
|
||||
7
tsconfig.json
Normal file
7
tsconfig.json
Normal file
@ -0,0 +1,7 @@
|
||||
{
|
||||
"files": [],
|
||||
"references": [
|
||||
{ "path": "./tsconfig.app.json" },
|
||||
{ "path": "./tsconfig.node.json" }
|
||||
]
|
||||
}
|
||||
25
tsconfig.node.json
Normal file
25
tsconfig.node.json
Normal file
@ -0,0 +1,25 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo",
|
||||
"target": "ES2023",
|
||||
"lib": ["ES2023"],
|
||||
"module": "ESNext",
|
||||
"skipLibCheck": true,
|
||||
|
||||
/* Bundler mode */
|
||||
"moduleResolution": "bundler",
|
||||
"allowImportingTsExtensions": true,
|
||||
"verbatimModuleSyntax": true,
|
||||
"moduleDetection": "force",
|
||||
"noEmit": true,
|
||||
|
||||
/* Linting */
|
||||
"strict": true,
|
||||
"noUnusedLocals": true,
|
||||
"noUnusedParameters": true,
|
||||
"erasableSyntaxOnly": true,
|
||||
"noFallthroughCasesInSwitch": true,
|
||||
"noUncheckedSideEffectImports": true
|
||||
},
|
||||
"include": ["vite.config.ts"]
|
||||
}
|
||||
7
vite.config.ts
Normal file
7
vite.config.ts
Normal file
@ -0,0 +1,7 @@
|
||||
import { defineConfig } from 'vite'
|
||||
import vue from '@vitejs/plugin-vue'
|
||||
|
||||
// https://vite.dev/config/
|
||||
export default defineConfig({
|
||||
plugins: [vue()],
|
||||
})
|
||||
Loading…
x
Reference in New Issue
Block a user